aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/ath/ath5k/mac80211-ops.c
diff options
context:
space:
mode:
authorBruno Randolf <br1@einfach.org>2010-12-22 05:20:32 -0500
committerJohn W. Linville <linville@tuxdriver.com>2011-01-04 14:35:11 -0500
commitcd2c5486526b744fb505e18c9d981b35feaf283a (patch)
tree6d9a11b28b6da7a0a593f06a4da3cbaead71ec49 /drivers/net/wireless/ath/ath5k/mac80211-ops.c
parent0511af9e9a43c64dd7e23e642c9087710688768c (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.c774
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
49extern int modparam_nohwcrypt;
50
51/* functions used from base.c */
52void set_beacon_filter(struct ieee80211_hw *hw, bool enable);
53bool ath_any_vif_assoc(struct ath5k_softc *sc);
54int ath5k_tx_queue(struct ieee80211_hw *hw, struct sk_buff *skb,
55 struct ath5k_txq *txq);
56int ath5k_init_hw(struct ath5k_softc *sc);
57int ath5k_stop_hw(struct ath5k_softc *sc);
58void ath5k_mode_setup(struct ath5k_softc *sc, struct ieee80211_vif *vif);
59void ath5k_update_bssid_mask_and_opmode(struct ath5k_softc *sc,
60 struct ieee80211_vif *vif);
61int ath5k_chan_set(struct ath5k_softc *sc, struct ieee80211_channel *chan);
62void ath5k_beacon_update_timers(struct ath5k_softc *sc, u64 bc_tsf);
63int ath5k_beacon_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
64void ath5k_beacon_config(struct ath5k_softc *sc);
65void ath5k_txbuf_free_skb(struct ath5k_softc *sc, struct ath5k_buf *bf);
66void ath5k_rxbuf_free_skb(struct ath5k_softc *sc, struct ath5k_buf *bf);
67
68/********************\
69* Mac80211 functions *
70\********************/
71
72static int
73ath5k_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
87static int
88ath5k_start(struct ieee80211_hw *hw)
89{
90 return ath5k_init_hw(hw->priv);
91}
92
93
94static void
95ath5k_stop(struct ieee80211_hw *hw)
96{
97 ath5k_stop_hw(hw->priv);
98}
99
100
101static int
102ath5k_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;
181end:
182 mutex_unlock(&sc->lock);
183 return ret;
184}
185
186
187static void
188ath5k_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 */
222static int
223ath5k_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
265unlock:
266 mutex_unlock(&sc->lock);
267 return ret;
268}
269
270
271static void
272ath5k_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
332static u64
333ath5k_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 */
380static void
381ath5k_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
478static int
479ath5k_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
534static void
535ath5k_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
543static void
544ath5k_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
552static int
553ath5k_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
570static int
571ath5k_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
610static u64
611ath5k_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
619static void
620ath5k_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
628static void
629ath5k_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
644static int
645ath5k_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 */
691static void
692ath5k_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
702static int
703ath5k_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
719static int
720ath5k_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
736const 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};