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); | |
e8c58e7a | 180 | sbands->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_16K; |
dad0d04f FF |
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 | ||
686a2541 JM |
343 | /** |
344 | * rsi_channel_change() - This function is a performs the checks | |
345 | * required for changing a channel and sets | |
346 | * the channel accordingly. | |
347 | * @hw: Pointer to the ieee80211_hw structure. | |
348 | * | |
349 | * Return: 0 on success, negative error code on failure. | |
350 | */ | |
351 | static int rsi_channel_change(struct ieee80211_hw *hw) | |
352 | { | |
353 | struct rsi_hw *adapter = hw->priv; | |
354 | struct rsi_common *common = adapter->priv; | |
355 | int status = -EOPNOTSUPP; | |
356 | struct ieee80211_channel *curchan = hw->conf.chandef.chan; | |
357 | u16 channel = curchan->hw_value; | |
358 | struct ieee80211_bss_conf *bss = &adapter->vifs[0]->bss_conf; | |
359 | ||
360 | rsi_dbg(INFO_ZONE, | |
361 | "%s: Set channel: %d MHz type: %d channel_no %d\n", | |
362 | __func__, curchan->center_freq, | |
363 | curchan->flags, channel); | |
364 | ||
365 | if (bss->assoc) { | |
366 | if (!common->hw_data_qs_blocked && | |
367 | (rsi_get_connected_channel(adapter) != channel)) { | |
368 | rsi_dbg(INFO_ZONE, "blk data q %d\n", channel); | |
369 | if (!rsi_send_block_unblock_frame(common, true)) | |
370 | common->hw_data_qs_blocked = true; | |
371 | } | |
372 | } | |
373 | ||
374 | status = rsi_band_check(common); | |
375 | if (!status) | |
376 | status = rsi_set_channel(adapter->priv, channel); | |
377 | ||
378 | if (bss->assoc) { | |
379 | if (common->hw_data_qs_blocked && | |
380 | (rsi_get_connected_channel(adapter) == channel)) { | |
381 | rsi_dbg(INFO_ZONE, "unblk data q %d\n", channel); | |
382 | if (!rsi_send_block_unblock_frame(common, false)) | |
383 | common->hw_data_qs_blocked = false; | |
384 | } | |
385 | } else { | |
386 | if (common->hw_data_qs_blocked) { | |
387 | rsi_dbg(INFO_ZONE, "unblk data q %d\n", channel); | |
388 | if (!rsi_send_block_unblock_frame(common, false)) | |
389 | common->hw_data_qs_blocked = false; | |
390 | } | |
391 | } | |
392 | ||
393 | return status; | |
394 | } | |
395 | ||
dad0d04f FF |
396 | /** |
397 | * rsi_mac80211_config() - This function is a handler for configuration | |
398 | * requests. The stack calls this function to | |
399 | * change hardware configuration, e.g., channel. | |
400 | * @hw: Pointer to the ieee80211_hw structure. | |
401 | * @changed: Changed flags set. | |
402 | * | |
403 | * Return: 0 on success, negative error code on failure. | |
404 | */ | |
405 | static int rsi_mac80211_config(struct ieee80211_hw *hw, | |
406 | u32 changed) | |
407 | { | |
408 | struct rsi_hw *adapter = hw->priv; | |
409 | struct rsi_common *common = adapter->priv; | |
410 | int status = -EOPNOTSUPP; | |
411 | ||
412 | mutex_lock(&common->mutex); | |
686a2541 JM |
413 | |
414 | if (changed & IEEE80211_CONF_CHANGE_CHANNEL) | |
415 | status = rsi_channel_change(hw); | |
416 | ||
dad0d04f FF |
417 | mutex_unlock(&common->mutex); |
418 | ||
419 | return status; | |
420 | } | |
421 | ||
422 | /** | |
423 | * rsi_get_connected_channel() - This function is used to get the current | |
424 | * connected channel number. | |
425 | * @adapter: Pointer to the adapter structure. | |
426 | * | |
427 | * Return: Current connected AP's channel number is returned. | |
428 | */ | |
429 | u16 rsi_get_connected_channel(struct rsi_hw *adapter) | |
430 | { | |
431 | struct ieee80211_vif *vif = adapter->vifs[0]; | |
432 | if (vif) { | |
433 | struct ieee80211_bss_conf *bss = &vif->bss_conf; | |
434 | struct ieee80211_channel *channel = bss->chandef.chan; | |
435 | return channel->hw_value; | |
436 | } | |
437 | ||
438 | return 0; | |
439 | } | |
440 | ||
441 | /** | |
442 | * rsi_mac80211_bss_info_changed() - This function is a handler for config | |
443 | * requests related to BSS parameters that | |
444 | * may vary during BSS's lifespan. | |
445 | * @hw: Pointer to the ieee80211_hw structure. | |
446 | * @vif: Pointer to the ieee80211_vif structure. | |
447 | * @bss_conf: Pointer to the ieee80211_bss_conf structure. | |
448 | * @changed: Changed flags set. | |
449 | * | |
450 | * Return: None. | |
451 | */ | |
452 | static void rsi_mac80211_bss_info_changed(struct ieee80211_hw *hw, | |
453 | struct ieee80211_vif *vif, | |
454 | struct ieee80211_bss_conf *bss_conf, | |
455 | u32 changed) | |
456 | { | |
457 | struct rsi_hw *adapter = hw->priv; | |
458 | struct rsi_common *common = adapter->priv; | |
459 | ||
460 | mutex_lock(&common->mutex); | |
461 | if (changed & BSS_CHANGED_ASSOC) { | |
462 | rsi_dbg(INFO_ZONE, "%s: Changed Association status: %d\n", | |
463 | __func__, bss_conf->assoc); | |
464 | rsi_inform_bss_status(common, | |
465 | bss_conf->assoc, | |
466 | bss_conf->bssid, | |
467 | bss_conf->qos, | |
468 | bss_conf->aid); | |
469 | } | |
686a2541 JM |
470 | |
471 | if (changed & BSS_CHANGED_CQM) { | |
472 | common->cqm_info.last_cqm_event_rssi = 0; | |
473 | common->cqm_info.rssi_thold = bss_conf->cqm_rssi_thold; | |
474 | common->cqm_info.rssi_hyst = bss_conf->cqm_rssi_hyst; | |
475 | rsi_dbg(INFO_ZONE, "RSSI throld & hysteresis are: %d %d\n", | |
476 | common->cqm_info.rssi_thold, | |
477 | common->cqm_info.rssi_hyst); | |
478 | } | |
dad0d04f FF |
479 | mutex_unlock(&common->mutex); |
480 | } | |
481 | ||
482 | /** | |
483 | * rsi_mac80211_conf_filter() - This function configure the device's RX filter. | |
484 | * @hw: Pointer to the ieee80211_hw structure. | |
485 | * @changed: Changed flags set. | |
486 | * @total_flags: Total initial flags set. | |
487 | * @multicast: Multicast. | |
488 | * | |
489 | * Return: None. | |
490 | */ | |
491 | static void rsi_mac80211_conf_filter(struct ieee80211_hw *hw, | |
492 | u32 changed_flags, | |
493 | u32 *total_flags, | |
494 | u64 multicast) | |
495 | { | |
496 | /* Not doing much here as of now */ | |
497 | *total_flags &= RSI_SUPP_FILTERS; | |
498 | } | |
499 | ||
500 | /** | |
501 | * rsi_mac80211_conf_tx() - This function configures TX queue parameters | |
502 | * (EDCF (aifs, cw_min, cw_max), bursting) | |
503 | * for a hardware TX queue. | |
504 | * @hw: Pointer to the ieee80211_hw structure | |
505 | * @vif: Pointer to the ieee80211_vif structure. | |
506 | * @queue: Queue number. | |
507 | * @params: Pointer to ieee80211_tx_queue_params structure. | |
508 | * | |
509 | * Return: 0 on success, negative error code on failure. | |
510 | */ | |
511 | static int rsi_mac80211_conf_tx(struct ieee80211_hw *hw, | |
512 | struct ieee80211_vif *vif, u16 queue, | |
513 | const struct ieee80211_tx_queue_params *params) | |
514 | { | |
515 | struct rsi_hw *adapter = hw->priv; | |
516 | struct rsi_common *common = adapter->priv; | |
517 | u8 idx = 0; | |
518 | ||
519 | if (queue >= IEEE80211_NUM_ACS) | |
520 | return 0; | |
521 | ||
522 | rsi_dbg(INFO_ZONE, | |
523 | "%s: Conf queue %d, aifs: %d, cwmin: %d cwmax: %d, txop: %d\n", | |
524 | __func__, queue, params->aifs, | |
525 | params->cw_min, params->cw_max, params->txop); | |
526 | ||
527 | mutex_lock(&common->mutex); | |
528 | /* Map into the way the f/w expects */ | |
529 | switch (queue) { | |
530 | case IEEE80211_AC_VO: | |
531 | idx = VO_Q; | |
532 | break; | |
533 | case IEEE80211_AC_VI: | |
534 | idx = VI_Q; | |
535 | break; | |
536 | case IEEE80211_AC_BE: | |
537 | idx = BE_Q; | |
538 | break; | |
539 | case IEEE80211_AC_BK: | |
540 | idx = BK_Q; | |
541 | break; | |
542 | default: | |
543 | idx = BE_Q; | |
544 | break; | |
545 | } | |
546 | ||
547 | memcpy(&common->edca_params[idx], | |
548 | params, | |
549 | sizeof(struct ieee80211_tx_queue_params)); | |
550 | mutex_unlock(&common->mutex); | |
551 | ||
552 | return 0; | |
553 | } | |
554 | ||
555 | /** | |
556 | * rsi_hal_key_config() - This function loads the keys into the firmware. | |
557 | * @hw: Pointer to the ieee80211_hw structure. | |
558 | * @vif: Pointer to the ieee80211_vif structure. | |
559 | * @key: Pointer to the ieee80211_key_conf structure. | |
560 | * | |
561 | * Return: status: 0 on success, -1 on failure. | |
562 | */ | |
563 | static int rsi_hal_key_config(struct ieee80211_hw *hw, | |
564 | struct ieee80211_vif *vif, | |
565 | struct ieee80211_key_conf *key) | |
566 | { | |
567 | struct rsi_hw *adapter = hw->priv; | |
568 | int status; | |
569 | u8 key_type; | |
570 | ||
571 | if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) | |
572 | key_type = RSI_PAIRWISE_KEY; | |
573 | else | |
574 | key_type = RSI_GROUP_KEY; | |
575 | ||
576 | rsi_dbg(ERR_ZONE, "%s: Cipher 0x%x key_type: %d key_len: %d\n", | |
577 | __func__, key->cipher, key_type, key->keylen); | |
578 | ||
579 | if ((key->cipher == WLAN_CIPHER_SUITE_WEP104) || | |
580 | (key->cipher == WLAN_CIPHER_SUITE_WEP40)) { | |
581 | status = rsi_hal_load_key(adapter->priv, | |
582 | key->key, | |
583 | key->keylen, | |
584 | RSI_PAIRWISE_KEY, | |
585 | key->keyidx, | |
586 | key->cipher); | |
587 | if (status) | |
588 | return status; | |
589 | } | |
590 | return rsi_hal_load_key(adapter->priv, | |
591 | key->key, | |
592 | key->keylen, | |
593 | key_type, | |
594 | key->keyidx, | |
595 | key->cipher); | |
596 | } | |
597 | ||
598 | /** | |
599 | * rsi_mac80211_set_key() - This function sets type of key to be loaded. | |
600 | * @hw: Pointer to the ieee80211_hw structure. | |
601 | * @cmd: enum set_key_cmd. | |
602 | * @vif: Pointer to the ieee80211_vif structure. | |
603 | * @sta: Pointer to the ieee80211_sta structure. | |
604 | * @key: Pointer to the ieee80211_key_conf structure. | |
605 | * | |
606 | * Return: status: 0 on success, negative error code on failure. | |
607 | */ | |
608 | static int rsi_mac80211_set_key(struct ieee80211_hw *hw, | |
609 | enum set_key_cmd cmd, | |
610 | struct ieee80211_vif *vif, | |
611 | struct ieee80211_sta *sta, | |
612 | struct ieee80211_key_conf *key) | |
613 | { | |
614 | struct rsi_hw *adapter = hw->priv; | |
615 | struct rsi_common *common = adapter->priv; | |
616 | struct security_info *secinfo = &common->secinfo; | |
617 | int status; | |
618 | ||
619 | mutex_lock(&common->mutex); | |
620 | switch (cmd) { | |
621 | case SET_KEY: | |
622 | secinfo->security_enable = true; | |
623 | status = rsi_hal_key_config(hw, vif, key); | |
624 | if (status) { | |
625 | mutex_unlock(&common->mutex); | |
626 | return status; | |
627 | } | |
628 | ||
629 | if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) | |
630 | secinfo->ptk_cipher = key->cipher; | |
631 | else | |
632 | secinfo->gtk_cipher = key->cipher; | |
633 | ||
634 | key->hw_key_idx = key->keyidx; | |
635 | key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; | |
636 | ||
637 | rsi_dbg(ERR_ZONE, "%s: RSI set_key\n", __func__); | |
638 | break; | |
639 | ||
640 | case DISABLE_KEY: | |
641 | secinfo->security_enable = false; | |
642 | rsi_dbg(ERR_ZONE, "%s: RSI del key\n", __func__); | |
643 | memset(key, 0, sizeof(struct ieee80211_key_conf)); | |
644 | status = rsi_hal_key_config(hw, vif, key); | |
645 | break; | |
646 | ||
647 | default: | |
648 | status = -EOPNOTSUPP; | |
649 | break; | |
650 | } | |
651 | ||
652 | mutex_unlock(&common->mutex); | |
653 | return status; | |
654 | } | |
655 | ||
656 | /** | |
657 | * rsi_mac80211_ampdu_action() - This function selects the AMPDU action for | |
658 | * the corresponding mlme_action flag and | |
659 | * informs the f/w regarding this. | |
660 | * @hw: Pointer to the ieee80211_hw structure. | |
661 | * @vif: Pointer to the ieee80211_vif structure. | |
662 | * @action: ieee80211_ampdu_mlme_action enum. | |
663 | * @sta: Pointer to the ieee80211_sta structure. | |
664 | * @tid: Traffic identifier. | |
665 | * @ssn: Pointer to ssn value. | |
666 | * @buf_size: Buffer size (for kernel version > 2.6.38). | |
667 | * | |
668 | * Return: status: 0 on success, negative error code on failure. | |
669 | */ | |
670 | static int rsi_mac80211_ampdu_action(struct ieee80211_hw *hw, | |
671 | struct ieee80211_vif *vif, | |
672 | enum ieee80211_ampdu_mlme_action action, | |
673 | struct ieee80211_sta *sta, | |
674 | unsigned short tid, | |
675 | unsigned short *ssn, | |
676 | unsigned char buf_size) | |
677 | { | |
678 | int status = -EOPNOTSUPP; | |
679 | struct rsi_hw *adapter = hw->priv; | |
680 | struct rsi_common *common = adapter->priv; | |
681 | u16 seq_no = 0; | |
682 | u8 ii = 0; | |
683 | ||
684 | for (ii = 0; ii < RSI_MAX_VIFS; ii++) { | |
685 | if (vif == adapter->vifs[ii]) | |
686 | break; | |
687 | } | |
688 | ||
689 | mutex_lock(&common->mutex); | |
690 | rsi_dbg(INFO_ZONE, "%s: AMPDU action %d called\n", __func__, action); | |
691 | if (ssn != NULL) | |
692 | seq_no = *ssn; | |
693 | ||
694 | switch (action) { | |
695 | case IEEE80211_AMPDU_RX_START: | |
696 | status = rsi_send_aggregation_params_frame(common, | |
697 | tid, | |
698 | seq_no, | |
699 | buf_size, | |
700 | STA_RX_ADDBA_DONE); | |
701 | break; | |
702 | ||
703 | case IEEE80211_AMPDU_RX_STOP: | |
704 | status = rsi_send_aggregation_params_frame(common, | |
705 | tid, | |
706 | 0, | |
707 | buf_size, | |
708 | STA_RX_DELBA); | |
709 | break; | |
710 | ||
711 | case IEEE80211_AMPDU_TX_START: | |
712 | common->vif_info[ii].seq_start = seq_no; | |
713 | ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); | |
5f407acb | 714 | status = 0; |
dad0d04f FF |
715 | break; |
716 | ||
717 | case IEEE80211_AMPDU_TX_STOP_CONT: | |
718 | case IEEE80211_AMPDU_TX_STOP_FLUSH: | |
719 | case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: | |
720 | status = rsi_send_aggregation_params_frame(common, | |
721 | tid, | |
722 | seq_no, | |
723 | buf_size, | |
724 | STA_TX_DELBA); | |
725 | if (!status) | |
726 | ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); | |
727 | break; | |
728 | ||
729 | case IEEE80211_AMPDU_TX_OPERATIONAL: | |
730 | status = rsi_send_aggregation_params_frame(common, | |
731 | tid, | |
732 | common->vif_info[ii] | |
733 | .seq_start, | |
734 | buf_size, | |
735 | STA_TX_ADDBA_DONE); | |
736 | break; | |
737 | ||
738 | default: | |
739 | rsi_dbg(ERR_ZONE, "%s: Uknown AMPDU action\n", __func__); | |
740 | break; | |
741 | } | |
742 | ||
743 | mutex_unlock(&common->mutex); | |
744 | return status; | |
745 | } | |
746 | ||
747 | /** | |
748 | * rsi_mac80211_set_rts_threshold() - This function sets rts threshold value. | |
749 | * @hw: Pointer to the ieee80211_hw structure. | |
750 | * @value: Rts threshold value. | |
751 | * | |
752 | * Return: 0 on success. | |
753 | */ | |
754 | static int rsi_mac80211_set_rts_threshold(struct ieee80211_hw *hw, | |
755 | u32 value) | |
756 | { | |
757 | struct rsi_hw *adapter = hw->priv; | |
758 | struct rsi_common *common = adapter->priv; | |
759 | ||
760 | mutex_lock(&common->mutex); | |
761 | common->rts_threshold = value; | |
762 | mutex_unlock(&common->mutex); | |
763 | ||
764 | return 0; | |
765 | } | |
766 | ||
767 | /** | |
768 | * rsi_mac80211_set_rate_mask() - This function sets bitrate_mask to be used. | |
769 | * @hw: Pointer to the ieee80211_hw structure | |
770 | * @vif: Pointer to the ieee80211_vif structure. | |
771 | * @mask: Pointer to the cfg80211_bitrate_mask structure. | |
772 | * | |
773 | * Return: 0 on success. | |
774 | */ | |
775 | static int rsi_mac80211_set_rate_mask(struct ieee80211_hw *hw, | |
776 | struct ieee80211_vif *vif, | |
777 | const struct cfg80211_bitrate_mask *mask) | |
778 | { | |
779 | struct rsi_hw *adapter = hw->priv; | |
780 | struct rsi_common *common = adapter->priv; | |
85af5bf8 | 781 | enum ieee80211_band band = hw->conf.chandef.chan->band; |
dad0d04f FF |
782 | |
783 | mutex_lock(&common->mutex); | |
85af5bf8 | 784 | common->fixedrate_mask[band] = 0; |
dad0d04f | 785 | |
85af5bf8 JM |
786 | if (mask->control[band].legacy == 0xfff) { |
787 | common->fixedrate_mask[band] = | |
788 | (mask->control[band].ht_mcs[0] << 12); | |
dad0d04f | 789 | } else { |
85af5bf8 JM |
790 | common->fixedrate_mask[band] = |
791 | mask->control[band].legacy; | |
dad0d04f FF |
792 | } |
793 | mutex_unlock(&common->mutex); | |
794 | ||
795 | return 0; | |
796 | } | |
797 | ||
686a2541 JM |
798 | /** |
799 | * rsi_perform_cqm() - This function performs cqm. | |
800 | * @common: Pointer to the driver private structure. | |
801 | * @bssid: pointer to the bssid. | |
802 | * @rssi: RSSI value. | |
803 | */ | |
804 | static void rsi_perform_cqm(struct rsi_common *common, | |
805 | u8 *bssid, | |
806 | s8 rssi) | |
807 | { | |
808 | struct rsi_hw *adapter = common->priv; | |
809 | s8 last_event = common->cqm_info.last_cqm_event_rssi; | |
810 | int thold = common->cqm_info.rssi_thold; | |
811 | u32 hyst = common->cqm_info.rssi_hyst; | |
812 | enum nl80211_cqm_rssi_threshold_event event; | |
813 | ||
814 | if (rssi < thold && (last_event == 0 || rssi < (last_event - hyst))) | |
815 | event = NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW; | |
816 | else if (rssi > thold && | |
817 | (last_event == 0 || rssi > (last_event + hyst))) | |
818 | event = NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH; | |
819 | else | |
820 | return; | |
821 | ||
822 | common->cqm_info.last_cqm_event_rssi = rssi; | |
823 | rsi_dbg(INFO_ZONE, "CQM: Notifying event: %d\n", event); | |
824 | ieee80211_cqm_rssi_notify(adapter->vifs[0], event, GFP_KERNEL); | |
825 | ||
826 | return; | |
827 | } | |
828 | ||
dad0d04f FF |
829 | /** |
830 | * rsi_fill_rx_status() - This function fills rx status in | |
831 | * ieee80211_rx_status structure. | |
832 | * @hw: Pointer to the ieee80211_hw structure. | |
833 | * @skb: Pointer to the socket buffer structure. | |
834 | * @common: Pointer to the driver private structure. | |
835 | * @rxs: Pointer to the ieee80211_rx_status structure. | |
836 | * | |
837 | * Return: None. | |
838 | */ | |
839 | static void rsi_fill_rx_status(struct ieee80211_hw *hw, | |
840 | struct sk_buff *skb, | |
841 | struct rsi_common *common, | |
842 | struct ieee80211_rx_status *rxs) | |
843 | { | |
686a2541 | 844 | struct ieee80211_bss_conf *bss = &common->priv->vifs[0]->bss_conf; |
dad0d04f FF |
845 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
846 | struct skb_info *rx_params = (struct skb_info *)info->driver_data; | |
847 | struct ieee80211_hdr *hdr; | |
848 | char rssi = rx_params->rssi; | |
849 | u8 hdrlen = 0; | |
850 | u8 channel = rx_params->channel; | |
851 | s32 freq; | |
852 | ||
853 | hdr = ((struct ieee80211_hdr *)(skb->data)); | |
854 | hdrlen = ieee80211_hdrlen(hdr->frame_control); | |
855 | ||
856 | memset(info, 0, sizeof(struct ieee80211_tx_info)); | |
857 | ||
858 | rxs->signal = -(rssi); | |
859 | ||
aabd3ad4 | 860 | rxs->band = common->band; |
dad0d04f FF |
861 | |
862 | freq = ieee80211_channel_to_frequency(channel, rxs->band); | |
863 | ||
864 | if (freq) | |
865 | rxs->freq = freq; | |
866 | ||
867 | if (ieee80211_has_protected(hdr->frame_control)) { | |
868 | if (rsi_is_cipher_wep(common)) { | |
869 | memmove(skb->data + 4, skb->data, hdrlen); | |
870 | skb_pull(skb, 4); | |
871 | } else { | |
872 | memmove(skb->data + 8, skb->data, hdrlen); | |
873 | skb_pull(skb, 8); | |
874 | rxs->flag |= RX_FLAG_MMIC_STRIPPED; | |
875 | } | |
876 | rxs->flag |= RX_FLAG_DECRYPTED; | |
877 | rxs->flag |= RX_FLAG_IV_STRIPPED; | |
878 | } | |
686a2541 JM |
879 | |
880 | /* CQM only for connected AP beacons, the RSSI is a weighted avg */ | |
881 | if (bss->assoc && !(memcmp(bss->bssid, hdr->addr2, ETH_ALEN))) { | |
882 | if (ieee80211_is_beacon(hdr->frame_control)) | |
883 | rsi_perform_cqm(common, hdr->addr2, rxs->signal); | |
884 | } | |
885 | ||
886 | return; | |
dad0d04f FF |
887 | } |
888 | ||
889 | /** | |
890 | * rsi_indicate_pkt_to_os() - This function sends recieved packet to mac80211. | |
891 | * @common: Pointer to the driver private structure. | |
892 | * @skb: Pointer to the socket buffer structure. | |
893 | * | |
894 | * Return: None. | |
895 | */ | |
896 | void rsi_indicate_pkt_to_os(struct rsi_common *common, | |
897 | struct sk_buff *skb) | |
898 | { | |
899 | struct rsi_hw *adapter = common->priv; | |
900 | struct ieee80211_hw *hw = adapter->hw; | |
901 | struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb); | |
902 | ||
903 | if ((common->iface_down) || (!adapter->sc_nvifs)) { | |
904 | dev_kfree_skb(skb); | |
905 | return; | |
906 | } | |
907 | ||
908 | /* filling in the ieee80211_rx_status flags */ | |
909 | rsi_fill_rx_status(hw, skb, common, rx_status); | |
910 | ||
911 | ieee80211_rx_irqsafe(hw, skb); | |
912 | } | |
913 | ||
914 | static void rsi_set_min_rate(struct ieee80211_hw *hw, | |
915 | struct ieee80211_sta *sta, | |
916 | struct rsi_common *common) | |
917 | { | |
918 | u8 band = hw->conf.chandef.chan->band; | |
919 | u8 ii; | |
920 | u32 rate_bitmap; | |
921 | bool matched = false; | |
922 | ||
923 | common->bitrate_mask[band] = sta->supp_rates[band]; | |
924 | ||
925 | rate_bitmap = (common->fixedrate_mask[band] & sta->supp_rates[band]); | |
926 | ||
927 | if (rate_bitmap & 0xfff) { | |
928 | /* Find out the min rate */ | |
929 | for (ii = 0; ii < ARRAY_SIZE(rsi_rates); ii++) { | |
930 | if (rate_bitmap & BIT(ii)) { | |
931 | common->min_rate = rsi_rates[ii].hw_value; | |
932 | matched = true; | |
933 | break; | |
934 | } | |
935 | } | |
936 | } | |
937 | ||
938 | common->vif_info[0].is_ht = sta->ht_cap.ht_supported; | |
939 | ||
940 | if ((common->vif_info[0].is_ht) && (rate_bitmap >> 12)) { | |
941 | for (ii = 0; ii < ARRAY_SIZE(rsi_mcsrates); ii++) { | |
942 | if ((rate_bitmap >> 12) & BIT(ii)) { | |
943 | common->min_rate = rsi_mcsrates[ii]; | |
944 | matched = true; | |
945 | break; | |
946 | } | |
947 | } | |
948 | } | |
949 | ||
950 | if (!matched) | |
951 | common->min_rate = 0xffff; | |
952 | } | |
953 | ||
954 | /** | |
955 | * rsi_mac80211_sta_add() - This function notifies driver about a peer getting | |
956 | * connected. | |
957 | * @hw: pointer to the ieee80211_hw structure. | |
958 | * @vif: Pointer to the ieee80211_vif structure. | |
959 | * @sta: Pointer to the ieee80211_sta structure. | |
960 | * | |
961 | * Return: 0 on success, -1 on failure. | |
962 | */ | |
963 | static int rsi_mac80211_sta_add(struct ieee80211_hw *hw, | |
964 | struct ieee80211_vif *vif, | |
965 | struct ieee80211_sta *sta) | |
966 | { | |
967 | struct rsi_hw *adapter = hw->priv; | |
968 | struct rsi_common *common = adapter->priv; | |
969 | ||
970 | mutex_lock(&common->mutex); | |
971 | ||
972 | rsi_set_min_rate(hw, sta, common); | |
973 | ||
974 | if ((sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) || | |
975 | (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40)) { | |
976 | common->vif_info[0].sgi = true; | |
977 | } | |
978 | ||
979 | if (sta->ht_cap.ht_supported) | |
980 | ieee80211_start_tx_ba_session(sta, 0, 0); | |
981 | ||
982 | mutex_unlock(&common->mutex); | |
983 | ||
984 | return 0; | |
985 | } | |
986 | ||
987 | /** | |
988 | * rsi_mac80211_sta_remove() - This function notifies driver about a peer | |
989 | * getting disconnected. | |
990 | * @hw: Pointer to the ieee80211_hw structure. | |
991 | * @vif: Pointer to the ieee80211_vif structure. | |
992 | * @sta: Pointer to the ieee80211_sta structure. | |
993 | * | |
994 | * Return: 0 on success, -1 on failure. | |
995 | */ | |
996 | static int rsi_mac80211_sta_remove(struct ieee80211_hw *hw, | |
997 | struct ieee80211_vif *vif, | |
998 | struct ieee80211_sta *sta) | |
999 | { | |
1000 | struct rsi_hw *adapter = hw->priv; | |
1001 | struct rsi_common *common = adapter->priv; | |
1002 | ||
1003 | mutex_lock(&common->mutex); | |
1004 | /* Resetting all the fields to default values */ | |
1005 | common->bitrate_mask[IEEE80211_BAND_2GHZ] = 0; | |
1006 | common->bitrate_mask[IEEE80211_BAND_5GHZ] = 0; | |
1007 | common->min_rate = 0xffff; | |
1008 | common->vif_info[0].is_ht = false; | |
1009 | common->vif_info[0].sgi = false; | |
1010 | common->vif_info[0].seq_start = 0; | |
1011 | common->secinfo.ptk_cipher = 0; | |
1012 | common->secinfo.gtk_cipher = 0; | |
1013 | mutex_unlock(&common->mutex); | |
1014 | ||
1015 | return 0; | |
1016 | } | |
1017 | ||
1018 | static struct ieee80211_ops mac80211_ops = { | |
1019 | .tx = rsi_mac80211_tx, | |
1020 | .start = rsi_mac80211_start, | |
1021 | .stop = rsi_mac80211_stop, | |
1022 | .add_interface = rsi_mac80211_add_interface, | |
1023 | .remove_interface = rsi_mac80211_remove_interface, | |
1024 | .config = rsi_mac80211_config, | |
1025 | .bss_info_changed = rsi_mac80211_bss_info_changed, | |
1026 | .conf_tx = rsi_mac80211_conf_tx, | |
1027 | .configure_filter = rsi_mac80211_conf_filter, | |
1028 | .set_key = rsi_mac80211_set_key, | |
1029 | .set_rts_threshold = rsi_mac80211_set_rts_threshold, | |
1030 | .set_bitrate_mask = rsi_mac80211_set_rate_mask, | |
1031 | .ampdu_action = rsi_mac80211_ampdu_action, | |
1032 | .sta_add = rsi_mac80211_sta_add, | |
1033 | .sta_remove = rsi_mac80211_sta_remove, | |
1034 | }; | |
1035 | ||
1036 | /** | |
1037 | * rsi_mac80211_attach() - This function is used to initialize Mac80211 stack. | |
1038 | * @common: Pointer to the driver private structure. | |
1039 | * | |
1040 | * Return: 0 on success, -1 on failure. | |
1041 | */ | |
1042 | int rsi_mac80211_attach(struct rsi_common *common) | |
1043 | { | |
1044 | int status = 0; | |
1045 | struct ieee80211_hw *hw = NULL; | |
1046 | struct wiphy *wiphy = NULL; | |
1047 | struct rsi_hw *adapter = common->priv; | |
1048 | u8 addr_mask[ETH_ALEN] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x3}; | |
1049 | ||
1050 | rsi_dbg(INIT_ZONE, "%s: Performing mac80211 attach\n", __func__); | |
1051 | ||
1052 | hw = ieee80211_alloc_hw(sizeof(struct rsi_hw), &mac80211_ops); | |
1053 | if (!hw) { | |
1054 | rsi_dbg(ERR_ZONE, "%s: ieee80211 hw alloc failed\n", __func__); | |
1055 | return -ENOMEM; | |
1056 | } | |
1057 | ||
1058 | wiphy = hw->wiphy; | |
1059 | ||
1060 | SET_IEEE80211_DEV(hw, adapter->device); | |
1061 | ||
1062 | hw->priv = adapter; | |
1063 | adapter->hw = hw; | |
1064 | ||
1065 | hw->flags = IEEE80211_HW_SIGNAL_DBM | | |
1066 | IEEE80211_HW_HAS_RATE_CONTROL | | |
1067 | IEEE80211_HW_AMPDU_AGGREGATION | | |
1068 | 0; | |
1069 | ||
1070 | hw->queues = MAX_HW_QUEUES; | |
1071 | hw->extra_tx_headroom = RSI_NEEDED_HEADROOM; | |
1072 | ||
1073 | hw->max_rates = 1; | |
1074 | hw->max_rate_tries = MAX_RETRIES; | |
1075 | ||
1076 | hw->max_tx_aggregation_subframes = 6; | |
1077 | rsi_register_rates_channels(adapter, IEEE80211_BAND_2GHZ); | |
85af5bf8 | 1078 | rsi_register_rates_channels(adapter, IEEE80211_BAND_5GHZ); |
dad0d04f FF |
1079 | hw->rate_control_algorithm = "AARF"; |
1080 | ||
1081 | SET_IEEE80211_PERM_ADDR(hw, common->mac_addr); | |
1082 | ether_addr_copy(hw->wiphy->addr_mask, addr_mask); | |
1083 | ||
1084 | wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); | |
1085 | wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; | |
1086 | wiphy->retry_short = RETRY_SHORT; | |
1087 | wiphy->retry_long = RETRY_LONG; | |
1088 | wiphy->frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD; | |
1089 | wiphy->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD; | |
1090 | wiphy->flags = 0; | |
1091 | ||
1092 | wiphy->available_antennas_rx = 1; | |
1093 | wiphy->available_antennas_tx = 1; | |
1094 | wiphy->bands[IEEE80211_BAND_2GHZ] = | |
1095 | &adapter->sbands[IEEE80211_BAND_2GHZ]; | |
85af5bf8 JM |
1096 | wiphy->bands[IEEE80211_BAND_5GHZ] = |
1097 | &adapter->sbands[IEEE80211_BAND_5GHZ]; | |
dad0d04f FF |
1098 | |
1099 | status = ieee80211_register_hw(hw); | |
1100 | if (status) | |
1101 | return status; | |
1102 | ||
1103 | return rsi_init_dbgfs(adapter); | |
1104 | } |