diff options
author | Bruno Randolf <br1@einfach.org> | 2010-12-22 05:20:32 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2011-01-04 14:35:11 -0500 |
commit | cd2c5486526b744fb505e18c9d981b35feaf283a (patch) | |
tree | 6d9a11b28b6da7a0a593f06a4da3cbaead71ec49 /drivers/net/wireless/ath/ath5k/mac80211-ops.c | |
parent | 0511af9e9a43c64dd7e23e642c9087710688768c (diff) |
ath5k: Move mac80211 functions into new file
Move mac80211 functions into new file mac80211-ops.c to have a better
separation and to make base.c smaller.
Signed-off-by: Bruno Randolf <br1@einfach.org>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/ath/ath5k/mac80211-ops.c')
-rw-r--r-- | drivers/net/wireless/ath/ath5k/mac80211-ops.c | 774 |
1 files changed, 774 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..de257a3430be --- /dev/null +++ b/drivers/net/wireless/ath/ath5k/mac80211-ops.c | |||
@@ -0,0 +1,774 @@ | |||
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 modparam_nohwcrypt; | ||
50 | |||
51 | /* functions used from base.c */ | ||
52 | void set_beacon_filter(struct ieee80211_hw *hw, bool enable); | ||
53 | bool ath_any_vif_assoc(struct ath5k_softc *sc); | ||
54 | int ath5k_tx_queue(struct ieee80211_hw *hw, struct sk_buff *skb, | ||
55 | struct ath5k_txq *txq); | ||
56 | int ath5k_init_hw(struct ath5k_softc *sc); | ||
57 | int ath5k_stop_hw(struct ath5k_softc *sc); | ||
58 | void ath5k_mode_setup(struct ath5k_softc *sc, struct ieee80211_vif *vif); | ||
59 | void ath5k_update_bssid_mask_and_opmode(struct ath5k_softc *sc, | ||
60 | struct ieee80211_vif *vif); | ||
61 | int ath5k_chan_set(struct ath5k_softc *sc, struct ieee80211_channel *chan); | ||
62 | void ath5k_beacon_update_timers(struct ath5k_softc *sc, u64 bc_tsf); | ||
63 | int ath5k_beacon_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif); | ||
64 | void ath5k_beacon_config(struct ath5k_softc *sc); | ||
65 | void ath5k_txbuf_free_skb(struct ath5k_softc *sc, struct ath5k_buf *bf); | ||
66 | void ath5k_rxbuf_free_skb(struct ath5k_softc *sc, struct ath5k_buf *bf); | ||
67 | |||
68 | /********************\ | ||
69 | * Mac80211 functions * | ||
70 | \********************/ | ||
71 | |||
72 | static int | ||
73 | ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb) | ||
74 | { | ||
75 | struct ath5k_softc *sc = hw->priv; | ||
76 | u16 qnum = skb_get_queue_mapping(skb); | ||
77 | |||
78 | if (WARN_ON(qnum >= sc->ah->ah_capabilities.cap_queues.q_tx_num)) { | ||
79 | dev_kfree_skb_any(skb); | ||
80 | return 0; | ||
81 | } | ||
82 | |||
83 | return ath5k_tx_queue(hw, skb, &sc->txqs[qnum]); | ||
84 | } | ||
85 | |||
86 | |||
87 | static int | ||
88 | ath5k_start(struct ieee80211_hw *hw) | ||
89 | { | ||
90 | return ath5k_init_hw(hw->priv); | ||
91 | } | ||
92 | |||
93 | |||
94 | static void | ||
95 | ath5k_stop(struct ieee80211_hw *hw) | ||
96 | { | ||
97 | ath5k_stop_hw(hw->priv); | ||
98 | } | ||
99 | |||
100 | |||
101 | static int | ||
102 | ath5k_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) | ||
103 | { | ||
104 | struct ath5k_softc *sc = hw->priv; | ||
105 | int ret; | ||
106 | struct ath5k_vif *avf = (void *)vif->drv_priv; | ||
107 | |||
108 | mutex_lock(&sc->lock); | ||
109 | |||
110 | if ((vif->type == NL80211_IFTYPE_AP || | ||
111 | vif->type == NL80211_IFTYPE_ADHOC) | ||
112 | && (sc->num_ap_vifs + sc->num_adhoc_vifs) >= ATH_BCBUF) { | ||
113 | ret = -ELNRNG; | ||
114 | goto end; | ||
115 | } | ||
116 | |||
117 | /* Don't allow other interfaces if one ad-hoc is configured. | ||
118 | * TODO: Fix the problems with ad-hoc and multiple other interfaces. | ||
119 | * We would need to operate the HW in ad-hoc mode to allow TSF updates | ||
120 | * for the IBSS, but this breaks with additional AP or STA interfaces | ||
121 | * at the moment. */ | ||
122 | if (sc->num_adhoc_vifs || | ||
123 | (sc->nvifs && vif->type == NL80211_IFTYPE_ADHOC)) { | ||
124 | ATH5K_ERR(sc, "Only one single ad-hoc interface is allowed.\n"); | ||
125 | ret = -ELNRNG; | ||
126 | goto end; | ||
127 | } | ||
128 | |||
129 | switch (vif->type) { | ||
130 | case NL80211_IFTYPE_AP: | ||
131 | case NL80211_IFTYPE_STATION: | ||
132 | case NL80211_IFTYPE_ADHOC: | ||
133 | case NL80211_IFTYPE_MESH_POINT: | ||
134 | avf->opmode = vif->type; | ||
135 | break; | ||
136 | default: | ||
137 | ret = -EOPNOTSUPP; | ||
138 | goto end; | ||
139 | } | ||
140 | |||
141 | sc->nvifs++; | ||
142 | ATH5K_DBG(sc, ATH5K_DEBUG_MODE, "add interface mode %d\n", avf->opmode); | ||
143 | |||
144 | /* Assign the vap/adhoc to a beacon xmit slot. */ | ||
145 | if ((avf->opmode == NL80211_IFTYPE_AP) || | ||
146 | (avf->opmode == NL80211_IFTYPE_ADHOC) || | ||
147 | (avf->opmode == NL80211_IFTYPE_MESH_POINT)) { | ||
148 | int slot; | ||
149 | |||
150 | WARN_ON(list_empty(&sc->bcbuf)); | ||
151 | avf->bbuf = list_first_entry(&sc->bcbuf, struct ath5k_buf, | ||
152 | list); | ||
153 | list_del(&avf->bbuf->list); | ||
154 | |||
155 | avf->bslot = 0; | ||
156 | for (slot = 0; slot < ATH_BCBUF; slot++) { | ||
157 | if (!sc->bslot[slot]) { | ||
158 | avf->bslot = slot; | ||
159 | break; | ||
160 | } | ||
161 | } | ||
162 | BUG_ON(sc->bslot[avf->bslot] != NULL); | ||
163 | sc->bslot[avf->bslot] = vif; | ||
164 | if (avf->opmode == NL80211_IFTYPE_AP) | ||
165 | sc->num_ap_vifs++; | ||
166 | else if (avf->opmode == NL80211_IFTYPE_ADHOC) | ||
167 | sc->num_adhoc_vifs++; | ||
168 | } | ||
169 | |||
170 | /* Any MAC address is fine, all others are included through the | ||
171 | * filter. | ||
172 | */ | ||
173 | memcpy(&sc->lladdr, vif->addr, ETH_ALEN); | ||
174 | ath5k_hw_set_lladdr(sc->ah, vif->addr); | ||
175 | |||
176 | memcpy(&avf->lladdr, vif->addr, ETH_ALEN); | ||
177 | |||
178 | ath5k_mode_setup(sc, vif); | ||
179 | |||
180 | ret = 0; | ||
181 | end: | ||
182 | mutex_unlock(&sc->lock); | ||
183 | return ret; | ||
184 | } | ||
185 | |||
186 | |||
187 | static void | ||
188 | ath5k_remove_interface(struct ieee80211_hw *hw, | ||
189 | struct ieee80211_vif *vif) | ||
190 | { | ||
191 | struct ath5k_softc *sc = hw->priv; | ||
192 | struct ath5k_vif *avf = (void *)vif->drv_priv; | ||
193 | unsigned int i; | ||
194 | |||
195 | mutex_lock(&sc->lock); | ||
196 | sc->nvifs--; | ||
197 | |||
198 | if (avf->bbuf) { | ||
199 | ath5k_txbuf_free_skb(sc, avf->bbuf); | ||
200 | list_add_tail(&avf->bbuf->list, &sc->bcbuf); | ||
201 | for (i = 0; i < ATH_BCBUF; i++) { | ||
202 | if (sc->bslot[i] == vif) { | ||
203 | sc->bslot[i] = NULL; | ||
204 | break; | ||
205 | } | ||
206 | } | ||
207 | avf->bbuf = NULL; | ||
208 | } | ||
209 | if (avf->opmode == NL80211_IFTYPE_AP) | ||
210 | sc->num_ap_vifs--; | ||
211 | else if (avf->opmode == NL80211_IFTYPE_ADHOC) | ||
212 | sc->num_adhoc_vifs--; | ||
213 | |||
214 | ath5k_update_bssid_mask_and_opmode(sc, NULL); | ||
215 | mutex_unlock(&sc->lock); | ||
216 | } | ||
217 | |||
218 | |||
219 | /* | ||
220 | * TODO: Phy disable/diversity etc | ||
221 | */ | ||
222 | static int | ||
223 | ath5k_config(struct ieee80211_hw *hw, u32 changed) | ||
224 | { | ||
225 | struct ath5k_softc *sc = hw->priv; | ||
226 | struct ath5k_hw *ah = sc->ah; | ||
227 | struct ieee80211_conf *conf = &hw->conf; | ||
228 | int ret = 0; | ||
229 | |||
230 | mutex_lock(&sc->lock); | ||
231 | |||
232 | if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { | ||
233 | ret = ath5k_chan_set(sc, conf->channel); | ||
234 | if (ret < 0) | ||
235 | goto unlock; | ||
236 | } | ||
237 | |||
238 | if ((changed & IEEE80211_CONF_CHANGE_POWER) && | ||
239 | (sc->power_level != conf->power_level)) { | ||
240 | sc->power_level = conf->power_level; | ||
241 | |||
242 | /* Half dB steps */ | ||
243 | ath5k_hw_set_txpower_limit(ah, (conf->power_level * 2)); | ||
244 | } | ||
245 | |||
246 | /* TODO: | ||
247 | * 1) Move this on config_interface and handle each case | ||
248 | * separately eg. when we have only one STA vif, use | ||
249 | * AR5K_ANTMODE_SINGLE_AP | ||
250 | * | ||
251 | * 2) Allow the user to change antenna mode eg. when only | ||
252 | * one antenna is present | ||
253 | * | ||
254 | * 3) Allow the user to set default/tx antenna when possible | ||
255 | * | ||
256 | * 4) Default mode should handle 90% of the cases, together | ||
257 | * with fixed a/b and single AP modes we should be able to | ||
258 | * handle 99%. Sectored modes are extreme cases and i still | ||
259 | * haven't found a usage for them. If we decide to support them, | ||
260 | * then we must allow the user to set how many tx antennas we | ||
261 | * have available | ||
262 | */ | ||
263 | ath5k_hw_set_antenna_mode(ah, ah->ah_ant_mode); | ||
264 | |||
265 | unlock: | ||
266 | mutex_unlock(&sc->lock); | ||
267 | return ret; | ||
268 | } | ||
269 | |||
270 | |||
271 | static void | ||
272 | ath5k_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, | ||
273 | struct ieee80211_bss_conf *bss_conf, u32 changes) | ||
274 | { | ||
275 | struct ath5k_vif *avf = (void *)vif->drv_priv; | ||
276 | struct ath5k_softc *sc = hw->priv; | ||
277 | struct ath5k_hw *ah = sc->ah; | ||
278 | struct ath_common *common = ath5k_hw_common(ah); | ||
279 | unsigned long flags; | ||
280 | |||
281 | mutex_lock(&sc->lock); | ||
282 | |||
283 | if (changes & BSS_CHANGED_BSSID) { | ||
284 | /* Cache for later use during resets */ | ||
285 | memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN); | ||
286 | common->curaid = 0; | ||
287 | ath5k_hw_set_bssid(ah); | ||
288 | mmiowb(); | ||
289 | } | ||
290 | |||
291 | if (changes & BSS_CHANGED_BEACON_INT) | ||
292 | sc->bintval = bss_conf->beacon_int; | ||
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 | |||
393 | mutex_lock(&sc->lock); | ||
394 | |||
395 | mfilt[0] = multicast; | ||
396 | mfilt[1] = multicast >> 32; | ||
397 | |||
398 | /* Only deal with supported flags */ | ||
399 | changed_flags &= SUPPORTED_FIF_FLAGS; | ||
400 | *new_flags &= SUPPORTED_FIF_FLAGS; | ||
401 | |||
402 | /* If HW detects any phy or radar errors, leave those filters on. | ||
403 | * Also, always enable Unicast, Broadcasts and Multicast | ||
404 | * XXX: move unicast, bssid broadcasts and multicast to mac80211 */ | ||
405 | rfilt = (ath5k_hw_get_rx_filter(ah) & (AR5K_RX_FILTER_PHYERR)) | | ||
406 | (AR5K_RX_FILTER_UCAST | AR5K_RX_FILTER_BCAST | | ||
407 | AR5K_RX_FILTER_MCAST); | ||
408 | |||
409 | if (changed_flags & (FIF_PROMISC_IN_BSS | FIF_OTHER_BSS)) { | ||
410 | if (*new_flags & FIF_PROMISC_IN_BSS) | ||
411 | __set_bit(ATH_STAT_PROMISC, sc->status); | ||
412 | else | ||
413 | __clear_bit(ATH_STAT_PROMISC, sc->status); | ||
414 | } | ||
415 | |||
416 | if (test_bit(ATH_STAT_PROMISC, sc->status)) | ||
417 | rfilt |= AR5K_RX_FILTER_PROM; | ||
418 | |||
419 | /* Note, AR5K_RX_FILTER_MCAST is already enabled */ | ||
420 | if (*new_flags & FIF_ALLMULTI) { | ||
421 | mfilt[0] = ~0; | ||
422 | mfilt[1] = ~0; | ||
423 | } | ||
424 | |||
425 | /* This is the best we can do */ | ||
426 | if (*new_flags & (FIF_FCSFAIL | FIF_PLCPFAIL)) | ||
427 | rfilt |= AR5K_RX_FILTER_PHYERR; | ||
428 | |||
429 | /* FIF_BCN_PRBRESP_PROMISC really means to enable beacons | ||
430 | * and probes for any BSSID */ | ||
431 | if ((*new_flags & FIF_BCN_PRBRESP_PROMISC) || (sc->nvifs > 1)) | ||
432 | rfilt |= AR5K_RX_FILTER_BEACON; | ||
433 | |||
434 | /* FIF_CONTROL doc says that if FIF_PROMISC_IN_BSS is not | ||
435 | * set we should only pass on control frames for this | ||
436 | * station. This needs testing. I believe right now this | ||
437 | * enables *all* control frames, which is OK.. but | ||
438 | * but we should see if we can improve on granularity */ | ||
439 | if (*new_flags & FIF_CONTROL) | ||
440 | rfilt |= AR5K_RX_FILTER_CONTROL; | ||
441 | |||
442 | /* Additional settings per mode -- this is per ath5k */ | ||
443 | |||
444 | /* XXX move these to mac80211, and add a beacon IFF flag to mac80211 */ | ||
445 | |||
446 | switch (sc->opmode) { | ||
447 | case NL80211_IFTYPE_MESH_POINT: | ||
448 | rfilt |= AR5K_RX_FILTER_CONTROL | | ||
449 | AR5K_RX_FILTER_BEACON | | ||
450 | AR5K_RX_FILTER_PROBEREQ | | ||
451 | AR5K_RX_FILTER_PROM; | ||
452 | break; | ||
453 | case NL80211_IFTYPE_AP: | ||
454 | case NL80211_IFTYPE_ADHOC: | ||
455 | rfilt |= AR5K_RX_FILTER_PROBEREQ | | ||
456 | AR5K_RX_FILTER_BEACON; | ||
457 | break; | ||
458 | case NL80211_IFTYPE_STATION: | ||
459 | if (sc->assoc) | ||
460 | rfilt |= AR5K_RX_FILTER_BEACON; | ||
461 | default: | ||
462 | break; | ||
463 | } | ||
464 | |||
465 | /* Set filters */ | ||
466 | ath5k_hw_set_rx_filter(ah, rfilt); | ||
467 | |||
468 | /* Set multicast bits */ | ||
469 | ath5k_hw_set_mcast_filter(ah, mfilt[0], mfilt[1]); | ||
470 | /* Set the cached hw filter flags, this will later actually | ||
471 | * be set in HW */ | ||
472 | sc->filter_flags = rfilt; | ||
473 | |||
474 | mutex_unlock(&sc->lock); | ||
475 | } | ||
476 | |||
477 | |||
478 | static int | ||
479 | ath5k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, | ||
480 | struct ieee80211_vif *vif, struct ieee80211_sta *sta, | ||
481 | struct ieee80211_key_conf *key) | ||
482 | { | ||
483 | struct ath5k_softc *sc = hw->priv; | ||
484 | struct ath5k_hw *ah = sc->ah; | ||
485 | struct ath_common *common = ath5k_hw_common(ah); | ||
486 | int ret = 0; | ||
487 | |||
488 | if (modparam_nohwcrypt) | ||
489 | return -EOPNOTSUPP; | ||
490 | |||
491 | switch (key->cipher) { | ||
492 | case WLAN_CIPHER_SUITE_WEP40: | ||
493 | case WLAN_CIPHER_SUITE_WEP104: | ||
494 | case WLAN_CIPHER_SUITE_TKIP: | ||
495 | break; | ||
496 | case WLAN_CIPHER_SUITE_CCMP: | ||
497 | if (common->crypt_caps & ATH_CRYPT_CAP_CIPHER_AESCCM) | ||
498 | break; | ||
499 | return -EOPNOTSUPP; | ||
500 | default: | ||
501 | WARN_ON(1); | ||
502 | return -EINVAL; | ||
503 | } | ||
504 | |||
505 | mutex_lock(&sc->lock); | ||
506 | |||
507 | switch (cmd) { | ||
508 | case SET_KEY: | ||
509 | ret = ath_key_config(common, vif, sta, key); | ||
510 | if (ret >= 0) { | ||
511 | key->hw_key_idx = ret; | ||
512 | /* push IV and Michael MIC generation to stack */ | ||
513 | key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; | ||
514 | if (key->cipher == WLAN_CIPHER_SUITE_TKIP) | ||
515 | key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC; | ||
516 | if (key->cipher == WLAN_CIPHER_SUITE_CCMP) | ||
517 | key->flags |= IEEE80211_KEY_FLAG_SW_MGMT; | ||
518 | ret = 0; | ||
519 | } | ||
520 | break; | ||
521 | case DISABLE_KEY: | ||
522 | ath_key_delete(common, key); | ||
523 | break; | ||
524 | default: | ||
525 | ret = -EINVAL; | ||
526 | } | ||
527 | |||
528 | mmiowb(); | ||
529 | mutex_unlock(&sc->lock); | ||
530 | return ret; | ||
531 | } | ||
532 | |||
533 | |||
534 | static void | ||
535 | ath5k_sw_scan_start(struct ieee80211_hw *hw) | ||
536 | { | ||
537 | struct ath5k_softc *sc = hw->priv; | ||
538 | if (!sc->assoc) | ||
539 | ath5k_hw_set_ledstate(sc->ah, AR5K_LED_SCAN); | ||
540 | } | ||
541 | |||
542 | |||
543 | static void | ||
544 | ath5k_sw_scan_complete(struct ieee80211_hw *hw) | ||
545 | { | ||
546 | struct ath5k_softc *sc = hw->priv; | ||
547 | ath5k_hw_set_ledstate(sc->ah, sc->assoc ? | ||
548 | AR5K_LED_ASSOC : AR5K_LED_INIT); | ||
549 | } | ||
550 | |||
551 | |||
552 | static int | ||
553 | ath5k_get_stats(struct ieee80211_hw *hw, | ||
554 | struct ieee80211_low_level_stats *stats) | ||
555 | { | ||
556 | struct ath5k_softc *sc = hw->priv; | ||
557 | |||
558 | /* Force update */ | ||
559 | ath5k_hw_update_mib_counters(sc->ah); | ||
560 | |||
561 | stats->dot11ACKFailureCount = sc->stats.ack_fail; | ||
562 | stats->dot11RTSFailureCount = sc->stats.rts_fail; | ||
563 | stats->dot11RTSSuccessCount = sc->stats.rts_ok; | ||
564 | stats->dot11FCSErrorCount = sc->stats.fcs_error; | ||
565 | |||
566 | return 0; | ||
567 | } | ||
568 | |||
569 | |||
570 | static int | ||
571 | ath5k_conf_tx(struct ieee80211_hw *hw, u16 queue, | ||
572 | const struct ieee80211_tx_queue_params *params) | ||
573 | { | ||
574 | struct ath5k_softc *sc = hw->priv; | ||
575 | struct ath5k_hw *ah = sc->ah; | ||
576 | struct ath5k_txq_info qi; | ||
577 | int ret = 0; | ||
578 | |||
579 | if (queue >= ah->ah_capabilities.cap_queues.q_tx_num) | ||
580 | return 0; | ||
581 | |||
582 | mutex_lock(&sc->lock); | ||
583 | |||
584 | ath5k_hw_get_tx_queueprops(ah, queue, &qi); | ||
585 | |||
586 | qi.tqi_aifs = params->aifs; | ||
587 | qi.tqi_cw_min = params->cw_min; | ||
588 | qi.tqi_cw_max = params->cw_max; | ||
589 | qi.tqi_burst_time = params->txop; | ||
590 | |||
591 | ATH5K_DBG(sc, ATH5K_DEBUG_ANY, | ||
592 | "Configure tx [queue %d], " | ||
593 | "aifs: %d, cw_min: %d, cw_max: %d, txop: %d\n", | ||
594 | queue, params->aifs, params->cw_min, | ||
595 | params->cw_max, params->txop); | ||
596 | |||
597 | if (ath5k_hw_set_tx_queueprops(ah, queue, &qi)) { | ||
598 | ATH5K_ERR(sc, | ||
599 | "Unable to update hardware queue %u!\n", queue); | ||
600 | ret = -EIO; | ||
601 | } else | ||
602 | ath5k_hw_reset_tx_queue(ah, queue); | ||
603 | |||
604 | mutex_unlock(&sc->lock); | ||
605 | |||
606 | return ret; | ||
607 | } | ||
608 | |||
609 | |||
610 | static u64 | ||
611 | ath5k_get_tsf(struct ieee80211_hw *hw) | ||
612 | { | ||
613 | struct ath5k_softc *sc = hw->priv; | ||
614 | |||
615 | return ath5k_hw_get_tsf64(sc->ah); | ||
616 | } | ||
617 | |||
618 | |||
619 | static void | ||
620 | ath5k_set_tsf(struct ieee80211_hw *hw, u64 tsf) | ||
621 | { | ||
622 | struct ath5k_softc *sc = hw->priv; | ||
623 | |||
624 | ath5k_hw_set_tsf64(sc->ah, tsf); | ||
625 | } | ||
626 | |||
627 | |||
628 | static void | ||
629 | ath5k_reset_tsf(struct ieee80211_hw *hw) | ||
630 | { | ||
631 | struct ath5k_softc *sc = hw->priv; | ||
632 | |||
633 | /* | ||
634 | * in IBSS mode we need to update the beacon timers too. | ||
635 | * this will also reset the TSF if we call it with 0 | ||
636 | */ | ||
637 | if (sc->opmode == NL80211_IFTYPE_ADHOC) | ||
638 | ath5k_beacon_update_timers(sc, 0); | ||
639 | else | ||
640 | ath5k_hw_reset_tsf(sc->ah); | ||
641 | } | ||
642 | |||
643 | |||
644 | static int | ||
645 | ath5k_get_survey(struct ieee80211_hw *hw, int idx, struct survey_info *survey) | ||
646 | { | ||
647 | struct ath5k_softc *sc = hw->priv; | ||
648 | struct ieee80211_conf *conf = &hw->conf; | ||
649 | struct ath_common *common = ath5k_hw_common(sc->ah); | ||
650 | struct ath_cycle_counters *cc = &common->cc_survey; | ||
651 | unsigned int div = common->clockrate * 1000; | ||
652 | |||
653 | if (idx != 0) | ||
654 | return -ENOENT; | ||
655 | |||
656 | spin_lock_bh(&common->cc_lock); | ||
657 | ath_hw_cycle_counters_update(common); | ||
658 | if (cc->cycles > 0) { | ||
659 | sc->survey.channel_time += cc->cycles / div; | ||
660 | sc->survey.channel_time_busy += cc->rx_busy / div; | ||
661 | sc->survey.channel_time_rx += cc->rx_frame / div; | ||
662 | sc->survey.channel_time_tx += cc->tx_frame / div; | ||
663 | } | ||
664 | memset(cc, 0, sizeof(*cc)); | ||
665 | spin_unlock_bh(&common->cc_lock); | ||
666 | |||
667 | memcpy(survey, &sc->survey, sizeof(*survey)); | ||
668 | |||
669 | survey->channel = conf->channel; | ||
670 | survey->noise = sc->ah->ah_noise_floor; | ||
671 | survey->filled = SURVEY_INFO_NOISE_DBM | | ||
672 | SURVEY_INFO_CHANNEL_TIME | | ||
673 | SURVEY_INFO_CHANNEL_TIME_BUSY | | ||
674 | SURVEY_INFO_CHANNEL_TIME_RX | | ||
675 | SURVEY_INFO_CHANNEL_TIME_TX; | ||
676 | |||
677 | return 0; | ||
678 | } | ||
679 | |||
680 | |||
681 | /** | ||
682 | * ath5k_set_coverage_class - Set IEEE 802.11 coverage class | ||
683 | * | ||
684 | * @hw: struct ieee80211_hw pointer | ||
685 | * @coverage_class: IEEE 802.11 coverage class number | ||
686 | * | ||
687 | * Mac80211 callback. Sets slot time, ACK timeout and CTS timeout for given | ||
688 | * coverage class. The values are persistent, they are restored after device | ||
689 | * reset. | ||
690 | */ | ||
691 | static void | ||
692 | ath5k_set_coverage_class(struct ieee80211_hw *hw, u8 coverage_class) | ||
693 | { | ||
694 | struct ath5k_softc *sc = hw->priv; | ||
695 | |||
696 | mutex_lock(&sc->lock); | ||
697 | ath5k_hw_set_coverage_class(sc->ah, coverage_class); | ||
698 | mutex_unlock(&sc->lock); | ||
699 | } | ||
700 | |||
701 | |||
702 | static int | ||
703 | ath5k_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) | ||
704 | { | ||
705 | struct ath5k_softc *sc = hw->priv; | ||
706 | |||
707 | if (tx_ant == 1 && rx_ant == 1) | ||
708 | ath5k_hw_set_antenna_mode(sc->ah, AR5K_ANTMODE_FIXED_A); | ||
709 | else if (tx_ant == 2 && rx_ant == 2) | ||
710 | ath5k_hw_set_antenna_mode(sc->ah, AR5K_ANTMODE_FIXED_B); | ||
711 | else if ((tx_ant & 3) == 3 && (rx_ant & 3) == 3) | ||
712 | ath5k_hw_set_antenna_mode(sc->ah, AR5K_ANTMODE_DEFAULT); | ||
713 | else | ||
714 | return -EINVAL; | ||
715 | return 0; | ||
716 | } | ||
717 | |||
718 | |||
719 | static int | ||
720 | ath5k_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant) | ||
721 | { | ||
722 | struct ath5k_softc *sc = hw->priv; | ||
723 | |||
724 | switch (sc->ah->ah_ant_mode) { | ||
725 | case AR5K_ANTMODE_FIXED_A: | ||
726 | *tx_ant = 1; *rx_ant = 1; break; | ||
727 | case AR5K_ANTMODE_FIXED_B: | ||
728 | *tx_ant = 2; *rx_ant = 2; break; | ||
729 | case AR5K_ANTMODE_DEFAULT: | ||
730 | *tx_ant = 3; *rx_ant = 3; break; | ||
731 | } | ||
732 | return 0; | ||
733 | } | ||
734 | |||
735 | |||
736 | const struct ieee80211_ops ath5k_hw_ops = { | ||
737 | .tx = ath5k_tx, | ||
738 | .start = ath5k_start, | ||
739 | .stop = ath5k_stop, | ||
740 | .add_interface = ath5k_add_interface, | ||
741 | /* .change_interface = not implemented */ | ||
742 | .remove_interface = ath5k_remove_interface, | ||
743 | .config = ath5k_config, | ||
744 | .bss_info_changed = ath5k_bss_info_changed, | ||
745 | .prepare_multicast = ath5k_prepare_multicast, | ||
746 | .configure_filter = ath5k_configure_filter, | ||
747 | /* .set_tim = not implemented */ | ||
748 | .set_key = ath5k_set_key, | ||
749 | /* .update_tkip_key = not implemented */ | ||
750 | /* .hw_scan = not implemented */ | ||
751 | .sw_scan_start = ath5k_sw_scan_start, | ||
752 | .sw_scan_complete = ath5k_sw_scan_complete, | ||
753 | .get_stats = ath5k_get_stats, | ||
754 | /* .get_tkip_seq = not implemented */ | ||
755 | /* .set_frag_threshold = not implemented */ | ||
756 | /* .set_rts_threshold = not implemented */ | ||
757 | /* .sta_add = not implemented */ | ||
758 | /* .sta_remove = not implemented */ | ||
759 | /* .sta_notify = not implemented */ | ||
760 | .conf_tx = ath5k_conf_tx, | ||
761 | .get_tsf = ath5k_get_tsf, | ||
762 | .set_tsf = ath5k_set_tsf, | ||
763 | .reset_tsf = ath5k_reset_tsf, | ||
764 | /* .tx_last_beacon = not implemented */ | ||
765 | /* .ampdu_action = not needed */ | ||
766 | .get_survey = ath5k_get_survey, | ||
767 | .set_coverage_class = ath5k_set_coverage_class, | ||
768 | /* .rfkill_poll = not implemented */ | ||
769 | /* .flush = not implemented */ | ||
770 | /* .channel_switch = not implemented */ | ||
771 | /* .napi_poll = not implemented */ | ||
772 | .set_antenna = ath5k_set_antenna, | ||
773 | .get_antenna = ath5k_get_antenna, | ||
774 | }; | ||