Back to home page

OSCL-LXR

 
 

    


0001 /*-
0002  * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting
0003  * Copyright (c) 2004-2005 Atheros Communications, Inc.
0004  * Copyright (c) 2006 Devicescape Software, Inc.
0005  * Copyright (c) 2007 Jiri Slaby <jirislaby@gmail.com>
0006  * Copyright (c) 2007 Luis R. Rodriguez <mcgrof@winlab.rutgers.edu>
0007  * Copyright (c) 2010 Bruno Randolf <br1@einfach.org>
0008  *
0009  * All rights reserved.
0010  *
0011  * Redistribution and use in source and binary forms, with or without
0012  * modification, are permitted provided that the following conditions
0013  * are met:
0014  * 1. Redistributions of source code must retain the above copyright
0015  *    notice, this list of conditions and the following disclaimer,
0016  *    without modification.
0017  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
0018  *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
0019  *    redistribution must be conditioned upon including a substantially
0020  *    similar Disclaimer requirement for further binary redistribution.
0021  * 3. Neither the names of the above-listed copyright holders nor the names
0022  *    of any contributors may be used to endorse or promote products derived
0023  *    from this software without specific prior written permission.
0024  *
0025  * Alternatively, this software may be distributed under the terms of the
0026  * GNU General Public License ("GPL") version 2 as published by the Free
0027  * Software Foundation.
0028  *
0029  * NO WARRANTY
0030  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
0031  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
0032  * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
0033  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
0034  * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
0035  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0036  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0037  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
0038  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0039  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
0040  * THE POSSIBILITY OF SUCH DAMAGES.
0041  *
0042  */
0043 
0044 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0045 
0046 #include <net/mac80211.h>
0047 #include <asm/unaligned.h>
0048 
0049 #include "ath5k.h"
0050 #include "base.h"
0051 #include "reg.h"
0052 
0053 /********************\
0054 * Mac80211 functions *
0055 \********************/
0056 
0057 static void
0058 ath5k_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control,
0059      struct sk_buff *skb)
0060 {
0061     struct ath5k_hw *ah = hw->priv;
0062     u16 qnum = skb_get_queue_mapping(skb);
0063 
0064     if (WARN_ON(qnum >= ah->ah_capabilities.cap_queues.q_tx_num)) {
0065         ieee80211_free_txskb(hw, skb);
0066         return;
0067     }
0068 
0069     ath5k_tx_queue(hw, skb, &ah->txqs[qnum], control);
0070 }
0071 
0072 
0073 static int
0074 ath5k_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
0075 {
0076     struct ath5k_hw *ah = hw->priv;
0077     int ret;
0078     struct ath5k_vif *avf = (void *)vif->drv_priv;
0079 
0080     mutex_lock(&ah->lock);
0081 
0082     if ((vif->type == NL80211_IFTYPE_AP ||
0083          vif->type == NL80211_IFTYPE_ADHOC)
0084         && (ah->num_ap_vifs + ah->num_adhoc_vifs) >= ATH_BCBUF) {
0085         ret = -ELNRNG;
0086         goto end;
0087     }
0088 
0089     /* Don't allow other interfaces if one ad-hoc is configured.
0090      * TODO: Fix the problems with ad-hoc and multiple other interfaces.
0091      * We would need to operate the HW in ad-hoc mode to allow TSF updates
0092      * for the IBSS, but this breaks with additional AP or STA interfaces
0093      * at the moment. */
0094     if (ah->num_adhoc_vifs ||
0095         (ah->nvifs && vif->type == NL80211_IFTYPE_ADHOC)) {
0096         ATH5K_ERR(ah, "Only one single ad-hoc interface is allowed.\n");
0097         ret = -ELNRNG;
0098         goto end;
0099     }
0100 
0101     switch (vif->type) {
0102     case NL80211_IFTYPE_AP:
0103     case NL80211_IFTYPE_STATION:
0104     case NL80211_IFTYPE_ADHOC:
0105     case NL80211_IFTYPE_MESH_POINT:
0106         avf->opmode = vif->type;
0107         break;
0108     default:
0109         ret = -EOPNOTSUPP;
0110         goto end;
0111     }
0112 
0113     ah->nvifs++;
0114     ATH5K_DBG(ah, ATH5K_DEBUG_MODE, "add interface mode %d\n", avf->opmode);
0115 
0116     /* Assign the vap/adhoc to a beacon xmit slot. */
0117     if ((avf->opmode == NL80211_IFTYPE_AP) ||
0118         (avf->opmode == NL80211_IFTYPE_ADHOC) ||
0119         (avf->opmode == NL80211_IFTYPE_MESH_POINT)) {
0120         int slot;
0121 
0122         WARN_ON(list_empty(&ah->bcbuf));
0123         avf->bbuf = list_first_entry(&ah->bcbuf, struct ath5k_buf,
0124                          list);
0125         list_del(&avf->bbuf->list);
0126 
0127         avf->bslot = 0;
0128         for (slot = 0; slot < ATH_BCBUF; slot++) {
0129             if (!ah->bslot[slot]) {
0130                 avf->bslot = slot;
0131                 break;
0132             }
0133         }
0134         BUG_ON(ah->bslot[avf->bslot] != NULL);
0135         ah->bslot[avf->bslot] = vif;
0136         if (avf->opmode == NL80211_IFTYPE_AP)
0137             ah->num_ap_vifs++;
0138         else if (avf->opmode == NL80211_IFTYPE_ADHOC)
0139             ah->num_adhoc_vifs++;
0140         else if (avf->opmode == NL80211_IFTYPE_MESH_POINT)
0141             ah->num_mesh_vifs++;
0142     }
0143 
0144     /* Any MAC address is fine, all others are included through the
0145      * filter.
0146      */
0147     ath5k_hw_set_lladdr(ah, vif->addr);
0148 
0149     ath5k_update_bssid_mask_and_opmode(ah, vif);
0150     ret = 0;
0151 end:
0152     mutex_unlock(&ah->lock);
0153     return ret;
0154 }
0155 
0156 
0157 static void
0158 ath5k_remove_interface(struct ieee80211_hw *hw,
0159                struct ieee80211_vif *vif)
0160 {
0161     struct ath5k_hw *ah = hw->priv;
0162     struct ath5k_vif *avf = (void *)vif->drv_priv;
0163     unsigned int i;
0164 
0165     mutex_lock(&ah->lock);
0166     ah->nvifs--;
0167 
0168     if (avf->bbuf) {
0169         ath5k_txbuf_free_skb(ah, avf->bbuf);
0170         list_add_tail(&avf->bbuf->list, &ah->bcbuf);
0171         for (i = 0; i < ATH_BCBUF; i++) {
0172             if (ah->bslot[i] == vif) {
0173                 ah->bslot[i] = NULL;
0174                 break;
0175             }
0176         }
0177         avf->bbuf = NULL;
0178     }
0179     if (avf->opmode == NL80211_IFTYPE_AP)
0180         ah->num_ap_vifs--;
0181     else if (avf->opmode == NL80211_IFTYPE_ADHOC)
0182         ah->num_adhoc_vifs--;
0183     else if (avf->opmode == NL80211_IFTYPE_MESH_POINT)
0184         ah->num_mesh_vifs--;
0185 
0186     ath5k_update_bssid_mask_and_opmode(ah, NULL);
0187     mutex_unlock(&ah->lock);
0188 }
0189 
0190 
0191 /*
0192  * TODO: Phy disable/diversity etc
0193  */
0194 static int
0195 ath5k_config(struct ieee80211_hw *hw, u32 changed)
0196 {
0197     struct ath5k_hw *ah = hw->priv;
0198     struct ieee80211_conf *conf = &hw->conf;
0199     int ret = 0;
0200     int i;
0201 
0202     mutex_lock(&ah->lock);
0203 
0204     if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
0205         ret = ath5k_chan_set(ah, &conf->chandef);
0206         if (ret < 0)
0207             goto unlock;
0208     }
0209 
0210     if ((changed & IEEE80211_CONF_CHANGE_POWER) &&
0211     (ah->ah_txpower.txp_requested != conf->power_level)) {
0212         ah->ah_txpower.txp_requested = conf->power_level;
0213 
0214         /* Half dB steps */
0215         ath5k_hw_set_txpower_limit(ah, (conf->power_level * 2));
0216     }
0217 
0218     if (changed & IEEE80211_CONF_CHANGE_RETRY_LIMITS) {
0219         ah->ah_retry_long = conf->long_frame_max_tx_count;
0220         ah->ah_retry_short = conf->short_frame_max_tx_count;
0221 
0222         for (i = 0; i < ah->ah_capabilities.cap_queues.q_tx_num; i++)
0223             ath5k_hw_set_tx_retry_limits(ah, i);
0224     }
0225 
0226     /* TODO:
0227      * 1) Move this on config_interface and handle each case
0228      * separately eg. when we have only one STA vif, use
0229      * AR5K_ANTMODE_SINGLE_AP
0230      *
0231      * 2) Allow the user to change antenna mode eg. when only
0232      * one antenna is present
0233      *
0234      * 3) Allow the user to set default/tx antenna when possible
0235      *
0236      * 4) Default mode should handle 90% of the cases, together
0237      * with fixed a/b and single AP modes we should be able to
0238      * handle 99%. Sectored modes are extreme cases and i still
0239      * haven't found a usage for them. If we decide to support them,
0240      * then we must allow the user to set how many tx antennas we
0241      * have available
0242      */
0243     ath5k_hw_set_antenna_mode(ah, ah->ah_ant_mode);
0244 
0245 unlock:
0246     mutex_unlock(&ah->lock);
0247     return ret;
0248 }
0249 
0250 
0251 static void
0252 ath5k_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
0253                struct ieee80211_bss_conf *bss_conf, u64 changes)
0254 {
0255     struct ath5k_vif *avf = (void *)vif->drv_priv;
0256     struct ath5k_hw *ah = hw->priv;
0257     struct ath_common *common = ath5k_hw_common(ah);
0258 
0259     mutex_lock(&ah->lock);
0260 
0261     if (changes & BSS_CHANGED_BSSID) {
0262         /* Cache for later use during resets */
0263         memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN);
0264         common->curaid = 0;
0265         ath5k_hw_set_bssid(ah);
0266     }
0267 
0268     if (changes & BSS_CHANGED_BEACON_INT)
0269         ah->bintval = bss_conf->beacon_int;
0270 
0271     if (changes & BSS_CHANGED_ERP_SLOT) {
0272         int slot_time;
0273 
0274         ah->ah_short_slot = bss_conf->use_short_slot;
0275         slot_time = ath5k_hw_get_default_slottime(ah) +
0276                 3 * ah->ah_coverage_class;
0277         ath5k_hw_set_ifs_intervals(ah, slot_time);
0278     }
0279 
0280     if (changes & BSS_CHANGED_ASSOC) {
0281         avf->assoc = vif->cfg.assoc;
0282         if (vif->cfg.assoc)
0283             ah->assoc = vif->cfg.assoc;
0284         else
0285             ah->assoc = ath5k_any_vif_assoc(ah);
0286 
0287         if (ah->opmode == NL80211_IFTYPE_STATION)
0288             ath5k_set_beacon_filter(hw, ah->assoc);
0289         ath5k_hw_set_ledstate(ah, ah->assoc ?
0290             AR5K_LED_ASSOC : AR5K_LED_INIT);
0291         if (vif->cfg.assoc) {
0292             ATH5K_DBG(ah, ATH5K_DEBUG_ANY,
0293                   "Bss Info ASSOC %d, bssid: %pM\n",
0294                   vif->cfg.aid, common->curbssid);
0295             common->curaid = vif->cfg.aid;
0296             ath5k_hw_set_bssid(ah);
0297             /* Once ANI is available you would start it here */
0298         }
0299     }
0300 
0301     if (changes & BSS_CHANGED_BEACON) {
0302         spin_lock_bh(&ah->block);
0303         ath5k_beacon_update(hw, vif);
0304         spin_unlock_bh(&ah->block);
0305     }
0306 
0307     if (changes & BSS_CHANGED_BEACON_ENABLED)
0308         ah->enable_beacon = bss_conf->enable_beacon;
0309 
0310     if (changes & (BSS_CHANGED_BEACON | BSS_CHANGED_BEACON_ENABLED |
0311                BSS_CHANGED_BEACON_INT))
0312         ath5k_beacon_config(ah);
0313 
0314     mutex_unlock(&ah->lock);
0315 }
0316 
0317 
0318 static u64
0319 ath5k_prepare_multicast(struct ieee80211_hw *hw,
0320             struct netdev_hw_addr_list *mc_list)
0321 {
0322     u32 mfilt[2], val;
0323     u8 pos;
0324     struct netdev_hw_addr *ha;
0325 
0326     mfilt[0] = 0;
0327     mfilt[1] = 0;
0328 
0329     netdev_hw_addr_list_for_each(ha, mc_list) {
0330         /* calculate XOR of eight 6-bit values */
0331         val = get_unaligned_le32(ha->addr + 0);
0332         pos = (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val;
0333         val = get_unaligned_le32(ha->addr + 3);
0334         pos ^= (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val;
0335         pos &= 0x3f;
0336         mfilt[pos / 32] |= (1 << (pos % 32));
0337         /* XXX: we might be able to just do this instead,
0338         * but not sure, needs testing, if we do use this we'd
0339         * need to inform below not to reset the mcast */
0340         /* ath5k_hw_set_mcast_filterindex(ah,
0341          *      ha->addr[5]); */
0342     }
0343 
0344     return ((u64)(mfilt[1]) << 32) | mfilt[0];
0345 }
0346 
0347 
0348 /*
0349  * o always accept unicast, broadcast, and multicast traffic
0350  * o multicast traffic for all BSSIDs will be enabled if mac80211
0351  *   says it should be
0352  * o maintain current state of phy ofdm or phy cck error reception.
0353  *   If the hardware detects any of these type of errors then
0354  *   ath5k_hw_get_rx_filter() will pass to us the respective
0355  *   hardware filters to be able to receive these type of frames.
0356  * o probe request frames are accepted only when operating in
0357  *   hostap, adhoc, or monitor modes
0358  * o enable promiscuous mode according to the interface state
0359  * o accept beacons:
0360  *   - when operating in adhoc mode so the 802.11 layer creates
0361  *     node table entries for peers,
0362  *   - when operating in station mode for collecting rssi data when
0363  *     the station is otherwise quiet, or
0364  *   - when scanning
0365  */
0366 static void
0367 ath5k_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags,
0368                unsigned int *new_flags, u64 multicast)
0369 {
0370 #define SUPPORTED_FIF_FLAGS \
0371     (FIF_ALLMULTI | FIF_FCSFAIL | \
0372     FIF_PLCPFAIL | FIF_CONTROL | FIF_OTHER_BSS | \
0373     FIF_BCN_PRBRESP_PROMISC)
0374 
0375     struct ath5k_hw *ah = hw->priv;
0376     u32 mfilt[2], rfilt;
0377     struct ath5k_vif_iter_data iter_data; /* to count STA interfaces */
0378 
0379     mutex_lock(&ah->lock);
0380 
0381     mfilt[0] = multicast;
0382     mfilt[1] = multicast >> 32;
0383 
0384     /* Only deal with supported flags */
0385     changed_flags &= SUPPORTED_FIF_FLAGS;
0386     *new_flags &= SUPPORTED_FIF_FLAGS;
0387 
0388     /* If HW detects any phy or radar errors, leave those filters on.
0389      * Also, always enable Unicast, Broadcasts and Multicast
0390      * XXX: move unicast, bssid broadcasts and multicast to mac80211 */
0391     rfilt = (ath5k_hw_get_rx_filter(ah) & (AR5K_RX_FILTER_PHYERR)) |
0392         (AR5K_RX_FILTER_UCAST | AR5K_RX_FILTER_BCAST |
0393         AR5K_RX_FILTER_MCAST);
0394 
0395     /* Note, AR5K_RX_FILTER_MCAST is already enabled */
0396     if (*new_flags & FIF_ALLMULTI) {
0397         mfilt[0] =  ~0;
0398         mfilt[1] =  ~0;
0399     }
0400 
0401     /* This is the best we can do */
0402     if (*new_flags & (FIF_FCSFAIL | FIF_PLCPFAIL))
0403         rfilt |= AR5K_RX_FILTER_PHYERR;
0404 
0405     /* FIF_BCN_PRBRESP_PROMISC really means to enable beacons
0406     * and probes for any BSSID */
0407     if ((*new_flags & FIF_BCN_PRBRESP_PROMISC) || (ah->nvifs > 1))
0408         rfilt |= AR5K_RX_FILTER_BEACON;
0409 
0410     /* FIF_CONTROL doc says we should only pass on control frames for this
0411      * station. This needs testing. I believe right now this
0412      * enables *all* control frames, which is OK.. but
0413      * we should see if we can improve on granularity */
0414     if (*new_flags & FIF_CONTROL)
0415         rfilt |= AR5K_RX_FILTER_CONTROL;
0416 
0417     /* Additional settings per mode -- this is per ath5k */
0418 
0419     /* XXX move these to mac80211, and add a beacon IFF flag to mac80211 */
0420 
0421     switch (ah->opmode) {
0422     case NL80211_IFTYPE_MESH_POINT:
0423         rfilt |= AR5K_RX_FILTER_CONTROL |
0424              AR5K_RX_FILTER_BEACON |
0425              AR5K_RX_FILTER_PROBEREQ |
0426              AR5K_RX_FILTER_PROM;
0427         break;
0428     case NL80211_IFTYPE_AP:
0429     case NL80211_IFTYPE_ADHOC:
0430         rfilt |= AR5K_RX_FILTER_PROBEREQ |
0431              AR5K_RX_FILTER_BEACON;
0432         break;
0433     case NL80211_IFTYPE_STATION:
0434         if (ah->assoc)
0435             rfilt |= AR5K_RX_FILTER_BEACON;
0436         break;
0437     default:
0438         break;
0439     }
0440 
0441     iter_data.hw_macaddr = NULL;
0442     iter_data.n_stas = 0;
0443     iter_data.need_set_hw_addr = false;
0444     ieee80211_iterate_active_interfaces_atomic(
0445         ah->hw, IEEE80211_IFACE_ITER_RESUME_ALL,
0446         ath5k_vif_iter, &iter_data);
0447 
0448     /* Set up RX Filter */
0449     if (iter_data.n_stas > 1) {
0450         /* If you have multiple STA interfaces connected to
0451          * different APs, ARPs are not received (most of the time?)
0452          * Enabling PROMISC appears to fix that problem.
0453          */
0454         rfilt |= AR5K_RX_FILTER_PROM;
0455     }
0456 
0457     /* Set filters */
0458     ath5k_hw_set_rx_filter(ah, rfilt);
0459 
0460     /* Set multicast bits */
0461     ath5k_hw_set_mcast_filter(ah, mfilt[0], mfilt[1]);
0462     /* Set the cached hw filter flags, this will later actually
0463      * be set in HW */
0464     ah->filter_flags = rfilt;
0465     /* Store current FIF filter flags */
0466     ah->fif_filter_flags = *new_flags;
0467 
0468     mutex_unlock(&ah->lock);
0469 }
0470 
0471 
0472 static int
0473 ath5k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
0474           struct ieee80211_vif *vif, struct ieee80211_sta *sta,
0475           struct ieee80211_key_conf *key)
0476 {
0477     struct ath5k_hw *ah = hw->priv;
0478     struct ath_common *common = ath5k_hw_common(ah);
0479     int ret = 0;
0480 
0481     if (ath5k_modparam_nohwcrypt)
0482         return -EOPNOTSUPP;
0483 
0484     if (key->flags & IEEE80211_KEY_FLAG_RX_MGMT)
0485         return -EOPNOTSUPP;
0486 
0487     if (vif->type == NL80211_IFTYPE_ADHOC &&
0488         (key->cipher == WLAN_CIPHER_SUITE_TKIP ||
0489          key->cipher == WLAN_CIPHER_SUITE_CCMP) &&
0490         !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) {
0491         /* don't program group keys when using IBSS_RSN */
0492         return -EOPNOTSUPP;
0493     }
0494 
0495     switch (key->cipher) {
0496     case WLAN_CIPHER_SUITE_WEP40:
0497     case WLAN_CIPHER_SUITE_WEP104:
0498     case WLAN_CIPHER_SUITE_TKIP:
0499         break;
0500     case WLAN_CIPHER_SUITE_CCMP:
0501         if (common->crypt_caps & ATH_CRYPT_CAP_CIPHER_AESCCM)
0502             break;
0503         return -EOPNOTSUPP;
0504     default:
0505         return -EOPNOTSUPP;
0506     }
0507 
0508     mutex_lock(&ah->lock);
0509 
0510     switch (cmd) {
0511     case SET_KEY:
0512         ret = ath_key_config(common, vif, sta, key);
0513         if (ret >= 0) {
0514             key->hw_key_idx = ret;
0515             /* push IV and Michael MIC generation to stack */
0516             key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
0517             if (key->cipher == WLAN_CIPHER_SUITE_TKIP)
0518                 key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
0519             if (key->cipher == WLAN_CIPHER_SUITE_CCMP)
0520                 key->flags |= IEEE80211_KEY_FLAG_SW_MGMT_TX;
0521             ret = 0;
0522         }
0523         break;
0524     case DISABLE_KEY:
0525         ath_key_delete(common, key->hw_key_idx);
0526         break;
0527     default:
0528         ret = -EINVAL;
0529     }
0530 
0531     mutex_unlock(&ah->lock);
0532     return ret;
0533 }
0534 
0535 
0536 static void
0537 ath5k_sw_scan_start(struct ieee80211_hw *hw,
0538             struct ieee80211_vif *vif,
0539             const u8 *mac_addr)
0540 {
0541     struct ath5k_hw *ah = hw->priv;
0542     if (!ah->assoc)
0543         ath5k_hw_set_ledstate(ah, AR5K_LED_SCAN);
0544 }
0545 
0546 
0547 static void
0548 ath5k_sw_scan_complete(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
0549 {
0550     struct ath5k_hw *ah = hw->priv;
0551     ath5k_hw_set_ledstate(ah, ah->assoc ?
0552         AR5K_LED_ASSOC : AR5K_LED_INIT);
0553 }
0554 
0555 
0556 static int
0557 ath5k_get_stats(struct ieee80211_hw *hw,
0558         struct ieee80211_low_level_stats *stats)
0559 {
0560     struct ath5k_hw *ah = hw->priv;
0561 
0562     /* Force update */
0563     ath5k_hw_update_mib_counters(ah);
0564 
0565     stats->dot11ACKFailureCount = ah->stats.ack_fail;
0566     stats->dot11RTSFailureCount = ah->stats.rts_fail;
0567     stats->dot11RTSSuccessCount = ah->stats.rts_ok;
0568     stats->dot11FCSErrorCount = ah->stats.fcs_error;
0569 
0570     return 0;
0571 }
0572 
0573 
0574 static int
0575 ath5k_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
0576           unsigned int link_id, u16 queue,
0577           const struct ieee80211_tx_queue_params *params)
0578 {
0579     struct ath5k_hw *ah = hw->priv;
0580     struct ath5k_txq_info qi;
0581     int ret = 0;
0582 
0583     if (queue >= ah->ah_capabilities.cap_queues.q_tx_num)
0584         return 0;
0585 
0586     mutex_lock(&ah->lock);
0587 
0588     ath5k_hw_get_tx_queueprops(ah, queue, &qi);
0589 
0590     qi.tqi_aifs = params->aifs;
0591     qi.tqi_cw_min = params->cw_min;
0592     qi.tqi_cw_max = params->cw_max;
0593     qi.tqi_burst_time = params->txop * 32;
0594 
0595     ATH5K_DBG(ah, ATH5K_DEBUG_ANY,
0596           "Configure tx [queue %d],  "
0597           "aifs: %d, cw_min: %d, cw_max: %d, txop: %d\n",
0598           queue, params->aifs, params->cw_min,
0599           params->cw_max, params->txop);
0600 
0601     if (ath5k_hw_set_tx_queueprops(ah, queue, &qi)) {
0602         ATH5K_ERR(ah,
0603               "Unable to update hardware queue %u!\n", queue);
0604         ret = -EIO;
0605     } else
0606         ath5k_hw_reset_tx_queue(ah, queue);
0607 
0608     mutex_unlock(&ah->lock);
0609 
0610     return ret;
0611 }
0612 
0613 
0614 static u64
0615 ath5k_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
0616 {
0617     struct ath5k_hw *ah = hw->priv;
0618 
0619     return ath5k_hw_get_tsf64(ah);
0620 }
0621 
0622 
0623 static void
0624 ath5k_set_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u64 tsf)
0625 {
0626     struct ath5k_hw *ah = hw->priv;
0627 
0628     ath5k_hw_set_tsf64(ah, tsf);
0629 }
0630 
0631 
0632 static void
0633 ath5k_reset_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
0634 {
0635     struct ath5k_hw *ah = hw->priv;
0636 
0637     /*
0638      * in IBSS mode we need to update the beacon timers too.
0639      * this will also reset the TSF if we call it with 0
0640      */
0641     if (ah->opmode == NL80211_IFTYPE_ADHOC)
0642         ath5k_beacon_update_timers(ah, 0);
0643     else
0644         ath5k_hw_reset_tsf(ah);
0645 }
0646 
0647 
0648 static int
0649 ath5k_get_survey(struct ieee80211_hw *hw, int idx, struct survey_info *survey)
0650 {
0651     struct ath5k_hw *ah = hw->priv;
0652     struct ieee80211_conf *conf = &hw->conf;
0653     struct ath_common *common = ath5k_hw_common(ah);
0654     struct ath_cycle_counters *cc = &common->cc_survey;
0655     unsigned int div = common->clockrate * 1000;
0656 
0657     if (idx != 0)
0658         return -ENOENT;
0659 
0660     spin_lock_bh(&common->cc_lock);
0661     ath_hw_cycle_counters_update(common);
0662     if (cc->cycles > 0) {
0663         ah->survey.time += cc->cycles / div;
0664         ah->survey.time_busy += cc->rx_busy / div;
0665         ah->survey.time_rx += cc->rx_frame / div;
0666         ah->survey.time_tx += cc->tx_frame / div;
0667     }
0668     memset(cc, 0, sizeof(*cc));
0669     spin_unlock_bh(&common->cc_lock);
0670 
0671     memcpy(survey, &ah->survey, sizeof(*survey));
0672 
0673     survey->channel = conf->chandef.chan;
0674     survey->noise = ah->ah_noise_floor;
0675     survey->filled = SURVEY_INFO_NOISE_DBM |
0676             SURVEY_INFO_IN_USE |
0677             SURVEY_INFO_TIME |
0678             SURVEY_INFO_TIME_BUSY |
0679             SURVEY_INFO_TIME_RX |
0680             SURVEY_INFO_TIME_TX;
0681 
0682     return 0;
0683 }
0684 
0685 
0686 /**
0687  * ath5k_set_coverage_class - Set IEEE 802.11 coverage class
0688  *
0689  * @hw: struct ieee80211_hw pointer
0690  * @coverage_class: IEEE 802.11 coverage class number
0691  *
0692  * Mac80211 callback. Sets slot time, ACK timeout and CTS timeout for given
0693  * coverage class. The values are persistent, they are restored after device
0694  * reset.
0695  */
0696 static void
0697 ath5k_set_coverage_class(struct ieee80211_hw *hw, s16 coverage_class)
0698 {
0699     struct ath5k_hw *ah = hw->priv;
0700 
0701     mutex_lock(&ah->lock);
0702     ath5k_hw_set_coverage_class(ah, coverage_class);
0703     mutex_unlock(&ah->lock);
0704 }
0705 
0706 
0707 static int
0708 ath5k_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant)
0709 {
0710     struct ath5k_hw *ah = hw->priv;
0711 
0712     if (tx_ant == 1 && rx_ant == 1)
0713         ath5k_hw_set_antenna_mode(ah, AR5K_ANTMODE_FIXED_A);
0714     else if (tx_ant == 2 && rx_ant == 2)
0715         ath5k_hw_set_antenna_mode(ah, AR5K_ANTMODE_FIXED_B);
0716     else if ((tx_ant & 3) == 3 && (rx_ant & 3) == 3)
0717         ath5k_hw_set_antenna_mode(ah, AR5K_ANTMODE_DEFAULT);
0718     else
0719         return -EINVAL;
0720     return 0;
0721 }
0722 
0723 
0724 static int
0725 ath5k_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant)
0726 {
0727     struct ath5k_hw *ah = hw->priv;
0728 
0729     switch (ah->ah_ant_mode) {
0730     case AR5K_ANTMODE_FIXED_A:
0731         *tx_ant = 1; *rx_ant = 1; break;
0732     case AR5K_ANTMODE_FIXED_B:
0733         *tx_ant = 2; *rx_ant = 2; break;
0734     case AR5K_ANTMODE_DEFAULT:
0735         *tx_ant = 3; *rx_ant = 3; break;
0736     }
0737     return 0;
0738 }
0739 
0740 
0741 static void ath5k_get_ringparam(struct ieee80211_hw *hw,
0742                 u32 *tx, u32 *tx_max, u32 *rx, u32 *rx_max)
0743 {
0744     struct ath5k_hw *ah = hw->priv;
0745 
0746     *tx = ah->txqs[AR5K_TX_QUEUE_ID_DATA_MIN].txq_max;
0747 
0748     *tx_max = ATH5K_TXQ_LEN_MAX;
0749     *rx = *rx_max = ATH_RXBUF;
0750 }
0751 
0752 
0753 static int ath5k_set_ringparam(struct ieee80211_hw *hw, u32 tx, u32 rx)
0754 {
0755     struct ath5k_hw *ah = hw->priv;
0756     u16 qnum;
0757 
0758     /* only support setting tx ring size for now */
0759     if (rx != ATH_RXBUF)
0760         return -EINVAL;
0761 
0762     /* restrict tx ring size min/max */
0763     if (!tx || tx > ATH5K_TXQ_LEN_MAX)
0764         return -EINVAL;
0765 
0766     for (qnum = 0; qnum < ARRAY_SIZE(ah->txqs); qnum++) {
0767         if (!ah->txqs[qnum].setup)
0768             continue;
0769         if (ah->txqs[qnum].qnum < AR5K_TX_QUEUE_ID_DATA_MIN ||
0770             ah->txqs[qnum].qnum > AR5K_TX_QUEUE_ID_DATA_MAX)
0771             continue;
0772 
0773         ah->txqs[qnum].txq_max = tx;
0774         if (ah->txqs[qnum].txq_len >= ah->txqs[qnum].txq_max)
0775             ieee80211_stop_queue(hw, ah->txqs[qnum].qnum);
0776     }
0777 
0778     return 0;
0779 }
0780 
0781 
0782 const struct ieee80211_ops ath5k_hw_ops = {
0783     .tx         = ath5k_tx,
0784     .start          = ath5k_start,
0785     .stop           = ath5k_stop,
0786     .add_interface      = ath5k_add_interface,
0787     /* .change_interface    = not implemented */
0788     .remove_interface   = ath5k_remove_interface,
0789     .config         = ath5k_config,
0790     .bss_info_changed   = ath5k_bss_info_changed,
0791     .prepare_multicast  = ath5k_prepare_multicast,
0792     .configure_filter   = ath5k_configure_filter,
0793     /* .set_tim     = not implemented */
0794     .set_key        = ath5k_set_key,
0795     /* .update_tkip_key = not implemented */
0796     /* .hw_scan     = not implemented */
0797     .sw_scan_start      = ath5k_sw_scan_start,
0798     .sw_scan_complete   = ath5k_sw_scan_complete,
0799     .get_stats      = ath5k_get_stats,
0800     /* .set_frag_threshold  = not implemented */
0801     /* .set_rts_threshold   = not implemented */
0802     /* .sta_add     = not implemented */
0803     /* .sta_remove      = not implemented */
0804     /* .sta_notify      = not implemented */
0805     .conf_tx        = ath5k_conf_tx,
0806     .get_tsf        = ath5k_get_tsf,
0807     .set_tsf        = ath5k_set_tsf,
0808     .reset_tsf      = ath5k_reset_tsf,
0809     /* .tx_last_beacon  = not implemented */
0810     /* .ampdu_action    = not needed */
0811     .get_survey     = ath5k_get_survey,
0812     .set_coverage_class = ath5k_set_coverage_class,
0813     /* .rfkill_poll     = not implemented */
0814     /* .flush       = not implemented */
0815     /* .channel_switch  = not implemented */
0816     /* .napi_poll       = not implemented */
0817     .set_antenna        = ath5k_set_antenna,
0818     .get_antenna        = ath5k_get_antenna,
0819     .set_ringparam      = ath5k_set_ringparam,
0820     .get_ringparam      = ath5k_get_ringparam,
0821 };