diff options
author | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
---|---|---|
committer | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
commit | c71c03bda1e86c9d5198c5d83f712e695c4f2a1e (patch) | |
tree | ecb166cb3e2b7e2adb3b5e292245fefd23381ac8 /drivers/net/wireless/ath/ath5k/mac80211-ops.c | |
parent | ea53c912f8a86a8567697115b6a0d8152beee5c8 (diff) | |
parent | 6a00f206debf8a5c8899055726ad127dbeeed098 (diff) |
Merge branch 'mpi-master' into wip-k-fmlpwip-k-fmlp
Conflicts:
litmus/sched_cedf.c
Diffstat (limited to 'drivers/net/wireless/ath/ath5k/mac80211-ops.c')
-rw-r--r-- | drivers/net/wireless/ath/ath5k/mac80211-ops.c | 833 |
1 files changed, 833 insertions, 0 deletions
diff --git a/drivers/net/wireless/ath/ath5k/mac80211-ops.c b/drivers/net/wireless/ath/ath5k/mac80211-ops.c new file mode 100644 index 000000000000..807bd6440169 --- /dev/null +++ b/drivers/net/wireless/ath/ath5k/mac80211-ops.c | |||
@@ -0,0 +1,833 @@ | |||
1 | /*- | ||
2 | * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting | ||
3 | * Copyright (c) 2004-2005 Atheros Communications, Inc. | ||
4 | * Copyright (c) 2006 Devicescape Software, Inc. | ||
5 | * Copyright (c) 2007 Jiri Slaby <jirislaby@gmail.com> | ||
6 | * Copyright (c) 2007 Luis R. Rodriguez <mcgrof@winlab.rutgers.edu> | ||
7 | * Copyright (c) 2010 Bruno Randolf <br1@einfach.org> | ||
8 | * | ||
9 | * All rights reserved. | ||
10 | * | ||
11 | * Redistribution and use in source and binary forms, with or without | ||
12 | * modification, are permitted provided that the following conditions | ||
13 | * are met: | ||
14 | * 1. Redistributions of source code must retain the above copyright | ||
15 | * notice, this list of conditions and the following disclaimer, | ||
16 | * without modification. | ||
17 | * 2. Redistributions in binary form must reproduce at minimum a disclaimer | ||
18 | * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any | ||
19 | * redistribution must be conditioned upon including a substantially | ||
20 | * similar Disclaimer requirement for further binary redistribution. | ||
21 | * 3. Neither the names of the above-listed copyright holders nor the names | ||
22 | * of any contributors may be used to endorse or promote products derived | ||
23 | * from this software without specific prior written permission. | ||
24 | * | ||
25 | * Alternatively, this software may be distributed under the terms of the | ||
26 | * GNU General Public License ("GPL") version 2 as published by the Free | ||
27 | * Software Foundation. | ||
28 | * | ||
29 | * NO WARRANTY | ||
30 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
31 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
32 | * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY | ||
33 | * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL | ||
34 | * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, | ||
35 | * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
36 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | ||
37 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER | ||
38 | * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
39 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF | ||
40 | * THE POSSIBILITY OF SUCH DAMAGES. | ||
41 | * | ||
42 | */ | ||
43 | |||
44 | #include <asm/unaligned.h> | ||
45 | |||
46 | #include "base.h" | ||
47 | #include "reg.h" | ||
48 | |||
49 | extern int ath5k_modparam_nohwcrypt; | ||
50 | |||
51 | /********************\ | ||
52 | * Mac80211 functions * | ||
53 | \********************/ | ||
54 | |||
55 | static void | ||
56 | ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb) | ||
57 | { | ||
58 | struct ath5k_softc *sc = hw->priv; | ||
59 | u16 qnum = skb_get_queue_mapping(skb); | ||
60 | |||
61 | if (WARN_ON(qnum >= sc->ah->ah_capabilities.cap_queues.q_tx_num)) { | ||
62 | dev_kfree_skb_any(skb); | ||
63 | return; | ||
64 | } | ||
65 | |||
66 | ath5k_tx_queue(hw, skb, &sc->txqs[qnum]); | ||
67 | } | ||
68 | |||
69 | |||
70 | static int | ||
71 | ath5k_start(struct ieee80211_hw *hw) | ||
72 | { | ||
73 | return ath5k_init_hw(hw->priv); | ||
74 | } | ||
75 | |||
76 | |||
77 | static void | ||
78 | ath5k_stop(struct ieee80211_hw *hw) | ||
79 | { | ||
80 | ath5k_stop_hw(hw->priv); | ||
81 | } | ||
82 | |||
83 | |||
84 | static int | ||
85 | ath5k_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) | ||
86 | { | ||
87 | struct ath5k_softc *sc = hw->priv; | ||
88 | int ret; | ||
89 | struct ath5k_vif *avf = (void *)vif->drv_priv; | ||
90 | |||
91 | mutex_lock(&sc->lock); | ||
92 | |||
93 | if ((vif->type == NL80211_IFTYPE_AP || | ||
94 | vif->type == NL80211_IFTYPE_ADHOC) | ||
95 | && (sc->num_ap_vifs + sc->num_adhoc_vifs) >= ATH_BCBUF) { | ||
96 | ret = -ELNRNG; | ||
97 | goto end; | ||
98 | } | ||
99 | |||
100 | /* Don't allow other interfaces if one ad-hoc is configured. | ||
101 | * TODO: Fix the problems with ad-hoc and multiple other interfaces. | ||
102 | * We would need to operate the HW in ad-hoc mode to allow TSF updates | ||
103 | * for the IBSS, but this breaks with additional AP or STA interfaces | ||
104 | * at the moment. */ | ||
105 | if (sc->num_adhoc_vifs || | ||
106 | (sc->nvifs && vif->type == NL80211_IFTYPE_ADHOC)) { | ||
107 | ATH5K_ERR(sc, "Only one single ad-hoc interface is allowed.\n"); | ||
108 | ret = -ELNRNG; | ||
109 | goto end; | ||
110 | } | ||
111 | |||
112 | switch (vif->type) { | ||
113 | case NL80211_IFTYPE_AP: | ||
114 | case NL80211_IFTYPE_STATION: | ||
115 | case NL80211_IFTYPE_ADHOC: | ||
116 | case NL80211_IFTYPE_MESH_POINT: | ||
117 | avf->opmode = vif->type; | ||
118 | break; | ||
119 | default: | ||
120 | ret = -EOPNOTSUPP; | ||
121 | goto end; | ||
122 | } | ||
123 | |||
124 | sc->nvifs++; | ||
125 | ATH5K_DBG(sc, ATH5K_DEBUG_MODE, "add interface mode %d\n", avf->opmode); | ||
126 | |||
127 | /* Assign the vap/adhoc to a beacon xmit slot. */ | ||
128 | if ((avf->opmode == NL80211_IFTYPE_AP) || | ||
129 | (avf->opmode == NL80211_IFTYPE_ADHOC) || | ||
130 | (avf->opmode == NL80211_IFTYPE_MESH_POINT)) { | ||
131 | int slot; | ||
132 | |||
133 | WARN_ON(list_empty(&sc->bcbuf)); | ||
134 | avf->bbuf = list_first_entry(&sc->bcbuf, struct ath5k_buf, | ||
135 | list); | ||
136 | list_del(&avf->bbuf->list); | ||
137 | |||
138 | avf->bslot = 0; | ||
139 | for (slot = 0; slot < ATH_BCBUF; slot++) { | ||
140 | if (!sc->bslot[slot]) { | ||
141 | avf->bslot = slot; | ||
142 | break; | ||
143 | } | ||
144 | } | ||
145 | BUG_ON(sc->bslot[avf->bslot] != NULL); | ||
146 | sc->bslot[avf->bslot] = vif; | ||
147 | if (avf->opmode == NL80211_IFTYPE_AP) | ||
148 | sc->num_ap_vifs++; | ||
149 | else if (avf->opmode == NL80211_IFTYPE_ADHOC) | ||
150 | sc->num_adhoc_vifs++; | ||
151 | } | ||
152 | |||
153 | /* Any MAC address is fine, all others are included through the | ||
154 | * filter. | ||
155 | */ | ||
156 | memcpy(&sc->lladdr, vif->addr, ETH_ALEN); | ||
157 | ath5k_hw_set_lladdr(sc->ah, vif->addr); | ||
158 | |||
159 | memcpy(&avf->lladdr, vif->addr, ETH_ALEN); | ||
160 | |||
161 | ath5k_update_bssid_mask_and_opmode(sc, vif); | ||
162 | ret = 0; | ||
163 | end: | ||
164 | mutex_unlock(&sc->lock); | ||
165 | return ret; | ||
166 | } | ||
167 | |||
168 | |||
169 | static void | ||
170 | ath5k_remove_interface(struct ieee80211_hw *hw, | ||
171 | struct ieee80211_vif *vif) | ||
172 | { | ||
173 | struct ath5k_softc *sc = hw->priv; | ||
174 | struct ath5k_vif *avf = (void *)vif->drv_priv; | ||
175 | unsigned int i; | ||
176 | |||
177 | mutex_lock(&sc->lock); | ||
178 | sc->nvifs--; | ||
179 | |||
180 | if (avf->bbuf) { | ||
181 | ath5k_txbuf_free_skb(sc, avf->bbuf); | ||
182 | list_add_tail(&avf->bbuf->list, &sc->bcbuf); | ||
183 | for (i = 0; i < ATH_BCBUF; i++) { | ||
184 | if (sc->bslot[i] == vif) { | ||
185 | sc->bslot[i] = NULL; | ||
186 | break; | ||
187 | } | ||
188 | } | ||
189 | avf->bbuf = NULL; | ||
190 | } | ||
191 | if (avf->opmode == NL80211_IFTYPE_AP) | ||
192 | sc->num_ap_vifs--; | ||
193 | else if (avf->opmode == NL80211_IFTYPE_ADHOC) | ||
194 | sc->num_adhoc_vifs--; | ||
195 | |||
196 | ath5k_update_bssid_mask_and_opmode(sc, NULL); | ||
197 | mutex_unlock(&sc->lock); | ||
198 | } | ||
199 | |||
200 | |||
201 | /* | ||
202 | * TODO: Phy disable/diversity etc | ||
203 | */ | ||
204 | static int | ||
205 | ath5k_config(struct ieee80211_hw *hw, u32 changed) | ||
206 | { | ||
207 | struct ath5k_softc *sc = hw->priv; | ||
208 | struct ath5k_hw *ah = sc->ah; | ||
209 | struct ieee80211_conf *conf = &hw->conf; | ||
210 | int ret = 0; | ||
211 | int i; | ||
212 | |||
213 | mutex_lock(&sc->lock); | ||
214 | |||
215 | if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { | ||
216 | ret = ath5k_chan_set(sc, conf->channel); | ||
217 | if (ret < 0) | ||
218 | goto unlock; | ||
219 | } | ||
220 | |||
221 | if ((changed & IEEE80211_CONF_CHANGE_POWER) && | ||
222 | (sc->power_level != conf->power_level)) { | ||
223 | sc->power_level = conf->power_level; | ||
224 | |||
225 | /* Half dB steps */ | ||
226 | ath5k_hw_set_txpower_limit(ah, (conf->power_level * 2)); | ||
227 | } | ||
228 | |||
229 | if (changed & IEEE80211_CONF_CHANGE_RETRY_LIMITS) { | ||
230 | ah->ah_retry_long = conf->long_frame_max_tx_count; | ||
231 | ah->ah_retry_short = conf->short_frame_max_tx_count; | ||
232 | |||
233 | for (i = 0; i < ah->ah_capabilities.cap_queues.q_tx_num; i++) | ||
234 | ath5k_hw_set_tx_retry_limits(ah, i); | ||
235 | } | ||
236 | |||
237 | /* TODO: | ||
238 | * 1) Move this on config_interface and handle each case | ||
239 | * separately eg. when we have only one STA vif, use | ||
240 | * AR5K_ANTMODE_SINGLE_AP | ||
241 | * | ||
242 | * 2) Allow the user to change antenna mode eg. when only | ||
243 | * one antenna is present | ||
244 | * | ||
245 | * 3) Allow the user to set default/tx antenna when possible | ||
246 | * | ||
247 | * 4) Default mode should handle 90% of the cases, together | ||
248 | * with fixed a/b and single AP modes we should be able to | ||
249 | * handle 99%. Sectored modes are extreme cases and i still | ||
250 | * haven't found a usage for them. If we decide to support them, | ||
251 | * then we must allow the user to set how many tx antennas we | ||
252 | * have available | ||
253 | */ | ||
254 | ath5k_hw_set_antenna_mode(ah, ah->ah_ant_mode); | ||
255 | |||
256 | unlock: | ||
257 | mutex_unlock(&sc->lock); | ||
258 | return ret; | ||
259 | } | ||
260 | |||
261 | |||
262 | static void | ||
263 | ath5k_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, | ||
264 | struct ieee80211_bss_conf *bss_conf, u32 changes) | ||
265 | { | ||
266 | struct ath5k_vif *avf = (void *)vif->drv_priv; | ||
267 | struct ath5k_softc *sc = hw->priv; | ||
268 | struct ath5k_hw *ah = sc->ah; | ||
269 | struct ath_common *common = ath5k_hw_common(ah); | ||
270 | unsigned long flags; | ||
271 | |||
272 | mutex_lock(&sc->lock); | ||
273 | |||
274 | if (changes & BSS_CHANGED_BSSID) { | ||
275 | /* Cache for later use during resets */ | ||
276 | memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN); | ||
277 | common->curaid = 0; | ||
278 | ath5k_hw_set_bssid(ah); | ||
279 | mmiowb(); | ||
280 | } | ||
281 | |||
282 | if (changes & BSS_CHANGED_BEACON_INT) | ||
283 | sc->bintval = bss_conf->beacon_int; | ||
284 | |||
285 | if (changes & BSS_CHANGED_ERP_SLOT) { | ||
286 | int slot_time; | ||
287 | |||
288 | ah->ah_short_slot = bss_conf->use_short_slot; | ||
289 | slot_time = ath5k_hw_get_default_slottime(ah) + | ||
290 | 3 * ah->ah_coverage_class; | ||
291 | ath5k_hw_set_ifs_intervals(ah, slot_time); | ||
292 | } | ||
293 | |||
294 | if (changes & BSS_CHANGED_ASSOC) { | ||
295 | avf->assoc = bss_conf->assoc; | ||
296 | if (bss_conf->assoc) | ||
297 | sc->assoc = bss_conf->assoc; | ||
298 | else | ||
299 | sc->assoc = ath_any_vif_assoc(sc); | ||
300 | |||
301 | if (sc->opmode == NL80211_IFTYPE_STATION) | ||
302 | set_beacon_filter(hw, sc->assoc); | ||
303 | ath5k_hw_set_ledstate(sc->ah, sc->assoc ? | ||
304 | AR5K_LED_ASSOC : AR5K_LED_INIT); | ||
305 | if (bss_conf->assoc) { | ||
306 | ATH5K_DBG(sc, ATH5K_DEBUG_ANY, | ||
307 | "Bss Info ASSOC %d, bssid: %pM\n", | ||
308 | bss_conf->aid, common->curbssid); | ||
309 | common->curaid = bss_conf->aid; | ||
310 | ath5k_hw_set_bssid(ah); | ||
311 | /* Once ANI is available you would start it here */ | ||
312 | } | ||
313 | } | ||
314 | |||
315 | if (changes & BSS_CHANGED_BEACON) { | ||
316 | spin_lock_irqsave(&sc->block, flags); | ||
317 | ath5k_beacon_update(hw, vif); | ||
318 | spin_unlock_irqrestore(&sc->block, flags); | ||
319 | } | ||
320 | |||
321 | if (changes & BSS_CHANGED_BEACON_ENABLED) | ||
322 | sc->enable_beacon = bss_conf->enable_beacon; | ||
323 | |||
324 | if (changes & (BSS_CHANGED_BEACON | BSS_CHANGED_BEACON_ENABLED | | ||
325 | BSS_CHANGED_BEACON_INT)) | ||
326 | ath5k_beacon_config(sc); | ||
327 | |||
328 | mutex_unlock(&sc->lock); | ||
329 | } | ||
330 | |||
331 | |||
332 | static u64 | ||
333 | ath5k_prepare_multicast(struct ieee80211_hw *hw, | ||
334 | struct netdev_hw_addr_list *mc_list) | ||
335 | { | ||
336 | u32 mfilt[2], val; | ||
337 | u8 pos; | ||
338 | struct netdev_hw_addr *ha; | ||
339 | |||
340 | mfilt[0] = 0; | ||
341 | mfilt[1] = 1; | ||
342 | |||
343 | netdev_hw_addr_list_for_each(ha, mc_list) { | ||
344 | /* calculate XOR of eight 6-bit values */ | ||
345 | val = get_unaligned_le32(ha->addr + 0); | ||
346 | pos = (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val; | ||
347 | val = get_unaligned_le32(ha->addr + 3); | ||
348 | pos ^= (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val; | ||
349 | pos &= 0x3f; | ||
350 | mfilt[pos / 32] |= (1 << (pos % 32)); | ||
351 | /* XXX: we might be able to just do this instead, | ||
352 | * but not sure, needs testing, if we do use this we'd | ||
353 | * neet to inform below to not reset the mcast */ | ||
354 | /* ath5k_hw_set_mcast_filterindex(ah, | ||
355 | * ha->addr[5]); */ | ||
356 | } | ||
357 | |||
358 | return ((u64)(mfilt[1]) << 32) | mfilt[0]; | ||
359 | } | ||
360 | |||
361 | |||
362 | /* | ||
363 | * o always accept unicast, broadcast, and multicast traffic | ||
364 | * o multicast traffic for all BSSIDs will be enabled if mac80211 | ||
365 | * says it should be | ||
366 | * o maintain current state of phy ofdm or phy cck error reception. | ||
367 | * If the hardware detects any of these type of errors then | ||
368 | * ath5k_hw_get_rx_filter() will pass to us the respective | ||
369 | * hardware filters to be able to receive these type of frames. | ||
370 | * o probe request frames are accepted only when operating in | ||
371 | * hostap, adhoc, or monitor modes | ||
372 | * o enable promiscuous mode according to the interface state | ||
373 | * o accept beacons: | ||
374 | * - when operating in adhoc mode so the 802.11 layer creates | ||
375 | * node table entries for peers, | ||
376 | * - when operating in station mode for collecting rssi data when | ||
377 | * the station is otherwise quiet, or | ||
378 | * - when scanning | ||
379 | */ | ||
380 | static void | ||
381 | ath5k_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, | ||
382 | unsigned int *new_flags, u64 multicast) | ||
383 | { | ||
384 | #define SUPPORTED_FIF_FLAGS \ | ||
385 | (FIF_PROMISC_IN_BSS | FIF_ALLMULTI | FIF_FCSFAIL | \ | ||
386 | FIF_PLCPFAIL | FIF_CONTROL | FIF_OTHER_BSS | \ | ||
387 | FIF_BCN_PRBRESP_PROMISC) | ||
388 | |||
389 | struct ath5k_softc *sc = hw->priv; | ||
390 | struct ath5k_hw *ah = sc->ah; | ||
391 | u32 mfilt[2], rfilt; | ||
392 | struct ath5k_vif_iter_data iter_data; /* to count STA interfaces */ | ||
393 | |||
394 | mutex_lock(&sc->lock); | ||
395 | |||
396 | mfilt[0] = multicast; | ||
397 | mfilt[1] = multicast >> 32; | ||
398 | |||
399 | /* Only deal with supported flags */ | ||
400 | changed_flags &= SUPPORTED_FIF_FLAGS; | ||
401 | *new_flags &= SUPPORTED_FIF_FLAGS; | ||
402 | |||
403 | /* If HW detects any phy or radar errors, leave those filters on. | ||
404 | * Also, always enable Unicast, Broadcasts and Multicast | ||
405 | * XXX: move unicast, bssid broadcasts and multicast to mac80211 */ | ||
406 | rfilt = (ath5k_hw_get_rx_filter(ah) & (AR5K_RX_FILTER_PHYERR)) | | ||
407 | (AR5K_RX_FILTER_UCAST | AR5K_RX_FILTER_BCAST | | ||
408 | AR5K_RX_FILTER_MCAST); | ||
409 | |||
410 | if (changed_flags & (FIF_PROMISC_IN_BSS | FIF_OTHER_BSS)) { | ||
411 | if (*new_flags & FIF_PROMISC_IN_BSS) | ||
412 | __set_bit(ATH_STAT_PROMISC, sc->status); | ||
413 | else | ||
414 | __clear_bit(ATH_STAT_PROMISC, sc->status); | ||
415 | } | ||
416 | |||
417 | if (test_bit(ATH_STAT_PROMISC, sc->status)) | ||
418 | rfilt |= AR5K_RX_FILTER_PROM; | ||
419 | |||
420 | /* Note, AR5K_RX_FILTER_MCAST is already enabled */ | ||
421 | if (*new_flags & FIF_ALLMULTI) { | ||
422 | mfilt[0] = ~0; | ||
423 | mfilt[1] = ~0; | ||
424 | } | ||
425 | |||
426 | /* This is the best we can do */ | ||
427 | if (*new_flags & (FIF_FCSFAIL | FIF_PLCPFAIL)) | ||
428 | rfilt |= AR5K_RX_FILTER_PHYERR; | ||
429 | |||
430 | /* FIF_BCN_PRBRESP_PROMISC really means to enable beacons | ||
431 | * and probes for any BSSID */ | ||
432 | if ((*new_flags & FIF_BCN_PRBRESP_PROMISC) || (sc->nvifs > 1)) | ||
433 | rfilt |= AR5K_RX_FILTER_BEACON; | ||
434 | |||
435 | /* FIF_CONTROL doc says that if FIF_PROMISC_IN_BSS is not | ||
436 | * set we should only pass on control frames for this | ||
437 | * station. This needs testing. I believe right now this | ||
438 | * enables *all* control frames, which is OK.. but | ||
439 | * but we should see if we can improve on granularity */ | ||
440 | if (*new_flags & FIF_CONTROL) | ||
441 | rfilt |= AR5K_RX_FILTER_CONTROL; | ||
442 | |||
443 | /* Additional settings per mode -- this is per ath5k */ | ||
444 | |||
445 | /* XXX move these to mac80211, and add a beacon IFF flag to mac80211 */ | ||
446 | |||
447 | switch (sc->opmode) { | ||
448 | case NL80211_IFTYPE_MESH_POINT: | ||
449 | rfilt |= AR5K_RX_FILTER_CONTROL | | ||
450 | AR5K_RX_FILTER_BEACON | | ||
451 | AR5K_RX_FILTER_PROBEREQ | | ||
452 | AR5K_RX_FILTER_PROM; | ||
453 | break; | ||
454 | case NL80211_IFTYPE_AP: | ||
455 | case NL80211_IFTYPE_ADHOC: | ||
456 | rfilt |= AR5K_RX_FILTER_PROBEREQ | | ||
457 | AR5K_RX_FILTER_BEACON; | ||
458 | break; | ||
459 | case NL80211_IFTYPE_STATION: | ||
460 | if (sc->assoc) | ||
461 | rfilt |= AR5K_RX_FILTER_BEACON; | ||
462 | default: | ||
463 | break; | ||
464 | } | ||
465 | |||
466 | iter_data.hw_macaddr = NULL; | ||
467 | iter_data.n_stas = 0; | ||
468 | iter_data.need_set_hw_addr = false; | ||
469 | ieee80211_iterate_active_interfaces_atomic(sc->hw, ath5k_vif_iter, | ||
470 | &iter_data); | ||
471 | |||
472 | /* Set up RX Filter */ | ||
473 | if (iter_data.n_stas > 1) { | ||
474 | /* If you have multiple STA interfaces connected to | ||
475 | * different APs, ARPs are not received (most of the time?) | ||
476 | * Enabling PROMISC appears to fix that probem. | ||
477 | */ | ||
478 | rfilt |= AR5K_RX_FILTER_PROM; | ||
479 | } | ||
480 | |||
481 | /* Set filters */ | ||
482 | ath5k_hw_set_rx_filter(ah, rfilt); | ||
483 | |||
484 | /* Set multicast bits */ | ||
485 | ath5k_hw_set_mcast_filter(ah, mfilt[0], mfilt[1]); | ||
486 | /* Set the cached hw filter flags, this will later actually | ||
487 | * be set in HW */ | ||
488 | sc->filter_flags = rfilt; | ||
489 | |||
490 | mutex_unlock(&sc->lock); | ||
491 | } | ||
492 | |||
493 | |||
494 | static int | ||
495 | ath5k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, | ||
496 | struct ieee80211_vif *vif, struct ieee80211_sta *sta, | ||
497 | struct ieee80211_key_conf *key) | ||
498 | { | ||
499 | struct ath5k_softc *sc = hw->priv; | ||
500 | struct ath5k_hw *ah = sc->ah; | ||
501 | struct ath_common *common = ath5k_hw_common(ah); | ||
502 | int ret = 0; | ||
503 | |||
504 | if (ath5k_modparam_nohwcrypt) | ||
505 | return -EOPNOTSUPP; | ||
506 | |||
507 | switch (key->cipher) { | ||
508 | case WLAN_CIPHER_SUITE_WEP40: | ||
509 | case WLAN_CIPHER_SUITE_WEP104: | ||
510 | case WLAN_CIPHER_SUITE_TKIP: | ||
511 | break; | ||
512 | case WLAN_CIPHER_SUITE_CCMP: | ||
513 | if (common->crypt_caps & ATH_CRYPT_CAP_CIPHER_AESCCM) | ||
514 | break; | ||
515 | return -EOPNOTSUPP; | ||
516 | default: | ||
517 | WARN_ON(1); | ||
518 | return -EINVAL; | ||
519 | } | ||
520 | |||
521 | mutex_lock(&sc->lock); | ||
522 | |||
523 | switch (cmd) { | ||
524 | case SET_KEY: | ||
525 | ret = ath_key_config(common, vif, sta, key); | ||
526 | if (ret >= 0) { | ||
527 | key->hw_key_idx = ret; | ||
528 | /* push IV and Michael MIC generation to stack */ | ||
529 | key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; | ||
530 | if (key->cipher == WLAN_CIPHER_SUITE_TKIP) | ||
531 | key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC; | ||
532 | if (key->cipher == WLAN_CIPHER_SUITE_CCMP) | ||
533 | key->flags |= IEEE80211_KEY_FLAG_SW_MGMT; | ||
534 | ret = 0; | ||
535 | } | ||
536 | break; | ||
537 | case DISABLE_KEY: | ||
538 | ath_key_delete(common, key); | ||
539 | break; | ||
540 | default: | ||
541 | ret = -EINVAL; | ||
542 | } | ||
543 | |||
544 | mmiowb(); | ||
545 | mutex_unlock(&sc->lock); | ||
546 | return ret; | ||
547 | } | ||
548 | |||
549 | |||
550 | static void | ||
551 | ath5k_sw_scan_start(struct ieee80211_hw *hw) | ||
552 | { | ||
553 | struct ath5k_softc *sc = hw->priv; | ||
554 | if (!sc->assoc) | ||
555 | ath5k_hw_set_ledstate(sc->ah, AR5K_LED_SCAN); | ||
556 | } | ||
557 | |||
558 | |||
559 | static void | ||
560 | ath5k_sw_scan_complete(struct ieee80211_hw *hw) | ||
561 | { | ||
562 | struct ath5k_softc *sc = hw->priv; | ||
563 | ath5k_hw_set_ledstate(sc->ah, sc->assoc ? | ||
564 | AR5K_LED_ASSOC : AR5K_LED_INIT); | ||
565 | } | ||
566 | |||
567 | |||
568 | static int | ||
569 | ath5k_get_stats(struct ieee80211_hw *hw, | ||
570 | struct ieee80211_low_level_stats *stats) | ||
571 | { | ||
572 | struct ath5k_softc *sc = hw->priv; | ||
573 | |||
574 | /* Force update */ | ||
575 | ath5k_hw_update_mib_counters(sc->ah); | ||
576 | |||
577 | stats->dot11ACKFailureCount = sc->stats.ack_fail; | ||
578 | stats->dot11RTSFailureCount = sc->stats.rts_fail; | ||
579 | stats->dot11RTSSuccessCount = sc->stats.rts_ok; | ||
580 | stats->dot11FCSErrorCount = sc->stats.fcs_error; | ||
581 | |||
582 | return 0; | ||
583 | } | ||
584 | |||
585 | |||
586 | static int | ||
587 | ath5k_conf_tx(struct ieee80211_hw *hw, u16 queue, | ||
588 | const struct ieee80211_tx_queue_params *params) | ||
589 | { | ||
590 | struct ath5k_softc *sc = hw->priv; | ||
591 | struct ath5k_hw *ah = sc->ah; | ||
592 | struct ath5k_txq_info qi; | ||
593 | int ret = 0; | ||
594 | |||
595 | if (queue >= ah->ah_capabilities.cap_queues.q_tx_num) | ||
596 | return 0; | ||
597 | |||
598 | mutex_lock(&sc->lock); | ||
599 | |||
600 | ath5k_hw_get_tx_queueprops(ah, queue, &qi); | ||
601 | |||
602 | qi.tqi_aifs = params->aifs; | ||
603 | qi.tqi_cw_min = params->cw_min; | ||
604 | qi.tqi_cw_max = params->cw_max; | ||
605 | qi.tqi_burst_time = params->txop; | ||
606 | |||
607 | ATH5K_DBG(sc, ATH5K_DEBUG_ANY, | ||
608 | "Configure tx [queue %d], " | ||
609 | "aifs: %d, cw_min: %d, cw_max: %d, txop: %d\n", | ||
610 | queue, params->aifs, params->cw_min, | ||
611 | params->cw_max, params->txop); | ||
612 | |||
613 | if (ath5k_hw_set_tx_queueprops(ah, queue, &qi)) { | ||
614 | ATH5K_ERR(sc, | ||
615 | "Unable to update hardware queue %u!\n", queue); | ||
616 | ret = -EIO; | ||
617 | } else | ||
618 | ath5k_hw_reset_tx_queue(ah, queue); | ||
619 | |||
620 | mutex_unlock(&sc->lock); | ||
621 | |||
622 | return ret; | ||
623 | } | ||
624 | |||
625 | |||
626 | static u64 | ||
627 | ath5k_get_tsf(struct ieee80211_hw *hw) | ||
628 | { | ||
629 | struct ath5k_softc *sc = hw->priv; | ||
630 | |||
631 | return ath5k_hw_get_tsf64(sc->ah); | ||
632 | } | ||
633 | |||
634 | |||
635 | static void | ||
636 | ath5k_set_tsf(struct ieee80211_hw *hw, u64 tsf) | ||
637 | { | ||
638 | struct ath5k_softc *sc = hw->priv; | ||
639 | |||
640 | ath5k_hw_set_tsf64(sc->ah, tsf); | ||
641 | } | ||
642 | |||
643 | |||
644 | static void | ||
645 | ath5k_reset_tsf(struct ieee80211_hw *hw) | ||
646 | { | ||
647 | struct ath5k_softc *sc = hw->priv; | ||
648 | |||
649 | /* | ||
650 | * in IBSS mode we need to update the beacon timers too. | ||
651 | * this will also reset the TSF if we call it with 0 | ||
652 | */ | ||
653 | if (sc->opmode == NL80211_IFTYPE_ADHOC) | ||
654 | ath5k_beacon_update_timers(sc, 0); | ||
655 | else | ||
656 | ath5k_hw_reset_tsf(sc->ah); | ||
657 | } | ||
658 | |||
659 | |||
660 | static int | ||
661 | ath5k_get_survey(struct ieee80211_hw *hw, int idx, struct survey_info *survey) | ||
662 | { | ||
663 | struct ath5k_softc *sc = hw->priv; | ||
664 | struct ieee80211_conf *conf = &hw->conf; | ||
665 | struct ath_common *common = ath5k_hw_common(sc->ah); | ||
666 | struct ath_cycle_counters *cc = &common->cc_survey; | ||
667 | unsigned int div = common->clockrate * 1000; | ||
668 | |||
669 | if (idx != 0) | ||
670 | return -ENOENT; | ||
671 | |||
672 | spin_lock_bh(&common->cc_lock); | ||
673 | ath_hw_cycle_counters_update(common); | ||
674 | if (cc->cycles > 0) { | ||
675 | sc->survey.channel_time += cc->cycles / div; | ||
676 | sc->survey.channel_time_busy += cc->rx_busy / div; | ||
677 | sc->survey.channel_time_rx += cc->rx_frame / div; | ||
678 | sc->survey.channel_time_tx += cc->tx_frame / div; | ||
679 | } | ||
680 | memset(cc, 0, sizeof(*cc)); | ||
681 | spin_unlock_bh(&common->cc_lock); | ||
682 | |||
683 | memcpy(survey, &sc->survey, sizeof(*survey)); | ||
684 | |||
685 | survey->channel = conf->channel; | ||
686 | survey->noise = sc->ah->ah_noise_floor; | ||
687 | survey->filled = SURVEY_INFO_NOISE_DBM | | ||
688 | SURVEY_INFO_CHANNEL_TIME | | ||
689 | SURVEY_INFO_CHANNEL_TIME_BUSY | | ||
690 | SURVEY_INFO_CHANNEL_TIME_RX | | ||
691 | SURVEY_INFO_CHANNEL_TIME_TX; | ||
692 | |||
693 | return 0; | ||
694 | } | ||
695 | |||
696 | |||
697 | /** | ||
698 | * ath5k_set_coverage_class - Set IEEE 802.11 coverage class | ||
699 | * | ||
700 | * @hw: struct ieee80211_hw pointer | ||
701 | * @coverage_class: IEEE 802.11 coverage class number | ||
702 | * | ||
703 | * Mac80211 callback. Sets slot time, ACK timeout and CTS timeout for given | ||
704 | * coverage class. The values are persistent, they are restored after device | ||
705 | * reset. | ||
706 | */ | ||
707 | static void | ||
708 | ath5k_set_coverage_class(struct ieee80211_hw *hw, u8 coverage_class) | ||
709 | { | ||
710 | struct ath5k_softc *sc = hw->priv; | ||
711 | |||
712 | mutex_lock(&sc->lock); | ||
713 | ath5k_hw_set_coverage_class(sc->ah, coverage_class); | ||
714 | mutex_unlock(&sc->lock); | ||
715 | } | ||
716 | |||
717 | |||
718 | static int | ||
719 | ath5k_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) | ||
720 | { | ||
721 | struct ath5k_softc *sc = hw->priv; | ||
722 | |||
723 | if (tx_ant == 1 && rx_ant == 1) | ||
724 | ath5k_hw_set_antenna_mode(sc->ah, AR5K_ANTMODE_FIXED_A); | ||
725 | else if (tx_ant == 2 && rx_ant == 2) | ||
726 | ath5k_hw_set_antenna_mode(sc->ah, AR5K_ANTMODE_FIXED_B); | ||
727 | else if ((tx_ant & 3) == 3 && (rx_ant & 3) == 3) | ||
728 | ath5k_hw_set_antenna_mode(sc->ah, AR5K_ANTMODE_DEFAULT); | ||
729 | else | ||
730 | return -EINVAL; | ||
731 | return 0; | ||
732 | } | ||
733 | |||
734 | |||
735 | static int | ||
736 | ath5k_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant) | ||
737 | { | ||
738 | struct ath5k_softc *sc = hw->priv; | ||
739 | |||
740 | switch (sc->ah->ah_ant_mode) { | ||
741 | case AR5K_ANTMODE_FIXED_A: | ||
742 | *tx_ant = 1; *rx_ant = 1; break; | ||
743 | case AR5K_ANTMODE_FIXED_B: | ||
744 | *tx_ant = 2; *rx_ant = 2; break; | ||
745 | case AR5K_ANTMODE_DEFAULT: | ||
746 | *tx_ant = 3; *rx_ant = 3; break; | ||
747 | } | ||
748 | return 0; | ||
749 | } | ||
750 | |||
751 | |||
752 | static void ath5k_get_ringparam(struct ieee80211_hw *hw, | ||
753 | u32 *tx, u32 *tx_max, u32 *rx, u32 *rx_max) | ||
754 | { | ||
755 | struct ath5k_softc *sc = hw->priv; | ||
756 | |||
757 | *tx = sc->txqs[AR5K_TX_QUEUE_ID_DATA_MIN].txq_max; | ||
758 | |||
759 | *tx_max = ATH5K_TXQ_LEN_MAX; | ||
760 | *rx = *rx_max = ATH_RXBUF; | ||
761 | } | ||
762 | |||
763 | |||
764 | static int ath5k_set_ringparam(struct ieee80211_hw *hw, u32 tx, u32 rx) | ||
765 | { | ||
766 | struct ath5k_softc *sc = hw->priv; | ||
767 | u16 qnum; | ||
768 | |||
769 | /* only support setting tx ring size for now */ | ||
770 | if (rx != ATH_RXBUF) | ||
771 | return -EINVAL; | ||
772 | |||
773 | /* restrict tx ring size min/max */ | ||
774 | if (!tx || tx > ATH5K_TXQ_LEN_MAX) | ||
775 | return -EINVAL; | ||
776 | |||
777 | for (qnum = 0; qnum < ARRAY_SIZE(sc->txqs); qnum++) { | ||
778 | if (!sc->txqs[qnum].setup) | ||
779 | continue; | ||
780 | if (sc->txqs[qnum].qnum < AR5K_TX_QUEUE_ID_DATA_MIN || | ||
781 | sc->txqs[qnum].qnum > AR5K_TX_QUEUE_ID_DATA_MAX) | ||
782 | continue; | ||
783 | |||
784 | sc->txqs[qnum].txq_max = tx; | ||
785 | if (sc->txqs[qnum].txq_len >= sc->txqs[qnum].txq_max) | ||
786 | ieee80211_stop_queue(hw, sc->txqs[qnum].qnum); | ||
787 | } | ||
788 | |||
789 | return 0; | ||
790 | } | ||
791 | |||
792 | |||
793 | const struct ieee80211_ops ath5k_hw_ops = { | ||
794 | .tx = ath5k_tx, | ||
795 | .start = ath5k_start, | ||
796 | .stop = ath5k_stop, | ||
797 | .add_interface = ath5k_add_interface, | ||
798 | /* .change_interface = not implemented */ | ||
799 | .remove_interface = ath5k_remove_interface, | ||
800 | .config = ath5k_config, | ||
801 | .bss_info_changed = ath5k_bss_info_changed, | ||
802 | .prepare_multicast = ath5k_prepare_multicast, | ||
803 | .configure_filter = ath5k_configure_filter, | ||
804 | /* .set_tim = not implemented */ | ||
805 | .set_key = ath5k_set_key, | ||
806 | /* .update_tkip_key = not implemented */ | ||
807 | /* .hw_scan = not implemented */ | ||
808 | .sw_scan_start = ath5k_sw_scan_start, | ||
809 | .sw_scan_complete = ath5k_sw_scan_complete, | ||
810 | .get_stats = ath5k_get_stats, | ||
811 | /* .get_tkip_seq = not implemented */ | ||
812 | /* .set_frag_threshold = not implemented */ | ||
813 | /* .set_rts_threshold = not implemented */ | ||
814 | /* .sta_add = not implemented */ | ||
815 | /* .sta_remove = not implemented */ | ||
816 | /* .sta_notify = not implemented */ | ||
817 | .conf_tx = ath5k_conf_tx, | ||
818 | .get_tsf = ath5k_get_tsf, | ||
819 | .set_tsf = ath5k_set_tsf, | ||
820 | .reset_tsf = ath5k_reset_tsf, | ||
821 | /* .tx_last_beacon = not implemented */ | ||
822 | /* .ampdu_action = not needed */ | ||
823 | .get_survey = ath5k_get_survey, | ||
824 | .set_coverage_class = ath5k_set_coverage_class, | ||
825 | /* .rfkill_poll = not implemented */ | ||
826 | /* .flush = not implemented */ | ||
827 | /* .channel_switch = not implemented */ | ||
828 | /* .napi_poll = not implemented */ | ||
829 | .set_antenna = ath5k_set_antenna, | ||
830 | .get_antenna = ath5k_get_antenna, | ||
831 | .set_ringparam = ath5k_set_ringparam, | ||
832 | .get_ringparam = ath5k_get_ringparam, | ||
833 | }; | ||