root/drivers/net/wireless/ath/ath5k/mac80211-ops.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ath5k_tx
  2. ath5k_add_interface
  3. ath5k_remove_interface
  4. ath5k_config
  5. ath5k_bss_info_changed
  6. ath5k_prepare_multicast
  7. ath5k_configure_filter
  8. ath5k_set_key
  9. ath5k_sw_scan_start
  10. ath5k_sw_scan_complete
  11. ath5k_get_stats
  12. ath5k_conf_tx
  13. ath5k_get_tsf
  14. ath5k_set_tsf
  15. ath5k_reset_tsf
  16. ath5k_get_survey
  17. ath5k_set_coverage_class
  18. ath5k_set_antenna
  19. ath5k_get_antenna
  20. ath5k_get_ringparam
  21. ath5k_set_ringparam

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

/* [<][>][^][v][top][bottom][index][help] */