linux/drivers/net/wireless/ath/ath5k/mac80211-ops.c
<<
>>
Prefs
   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
  57static void
  58ath5k_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]);
  70}
  71
  72
  73static int
  74ath5k_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;
 151end:
 152        mutex_unlock(&ah->lock);
 153        return ret;
 154}
 155
 156
 157static void
 158ath5k_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 */
 194static int
 195ath5k_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.chan);
 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
 245unlock:
 246        mutex_unlock(&ah->lock);
 247        return ret;
 248}
 249
 250
 251static void
 252ath5k_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                mmiowb();
 267        }
 268
 269        if (changes & BSS_CHANGED_BEACON_INT)
 270                ah->bintval = bss_conf->beacon_int;
 271
 272        if (changes & BSS_CHANGED_ERP_SLOT) {
 273                int slot_time;
 274
 275                ah->ah_short_slot = bss_conf->use_short_slot;
 276                slot_time = ath5k_hw_get_default_slottime(ah) +
 277                            3 * ah->ah_coverage_class;
 278                ath5k_hw_set_ifs_intervals(ah, slot_time);
 279        }
 280
 281        if (changes & BSS_CHANGED_ASSOC) {
 282                avf->assoc = bss_conf->assoc;
 283                if (bss_conf->assoc)
 284                        ah->assoc = bss_conf->assoc;
 285                else
 286                        ah->assoc = ath5k_any_vif_assoc(ah);
 287
 288                if (ah->opmode == NL80211_IFTYPE_STATION)
 289                        ath5k_set_beacon_filter(hw, ah->assoc);
 290                ath5k_hw_set_ledstate(ah, ah->assoc ?
 291                        AR5K_LED_ASSOC : AR5K_LED_INIT);
 292                if (bss_conf->assoc) {
 293                        ATH5K_DBG(ah, ATH5K_DEBUG_ANY,
 294                                  "Bss Info ASSOC %d, bssid: %pM\n",
 295                                  bss_conf->aid, common->curbssid);
 296                        common->curaid = bss_conf->aid;
 297                        ath5k_hw_set_bssid(ah);
 298                        /* Once ANI is available you would start it here */
 299                }
 300        }
 301
 302        if (changes & BSS_CHANGED_BEACON) {
 303                spin_lock_bh(&ah->block);
 304                ath5k_beacon_update(hw, vif);
 305                spin_unlock_bh(&ah->block);
 306        }
 307
 308        if (changes & BSS_CHANGED_BEACON_ENABLED)
 309                ah->enable_beacon = bss_conf->enable_beacon;
 310
 311        if (changes & (BSS_CHANGED_BEACON | BSS_CHANGED_BEACON_ENABLED |
 312                       BSS_CHANGED_BEACON_INT))
 313                ath5k_beacon_config(ah);
 314
 315        mutex_unlock(&ah->lock);
 316}
 317
 318
 319static u64
 320ath5k_prepare_multicast(struct ieee80211_hw *hw,
 321                        struct netdev_hw_addr_list *mc_list)
 322{
 323        u32 mfilt[2], val;
 324        u8 pos;
 325        struct netdev_hw_addr *ha;
 326
 327        mfilt[0] = 0;
 328        mfilt[1] = 1;
 329
 330        netdev_hw_addr_list_for_each(ha, mc_list) {
 331                /* calculate XOR of eight 6-bit values */
 332                val = get_unaligned_le32(ha->addr + 0);
 333                pos = (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val;
 334                val = get_unaligned_le32(ha->addr + 3);
 335                pos ^= (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val;
 336                pos &= 0x3f;
 337                mfilt[pos / 32] |= (1 << (pos % 32));
 338                /* XXX: we might be able to just do this instead,
 339                * but not sure, needs testing, if we do use this we'd
 340                * need to inform below not to reset the mcast */
 341                /* ath5k_hw_set_mcast_filterindex(ah,
 342                 *      ha->addr[5]); */
 343        }
 344
 345        return ((u64)(mfilt[1]) << 32) | mfilt[0];
 346}
 347
 348
 349/*
 350 * o always accept unicast, broadcast, and multicast traffic
 351 * o multicast traffic for all BSSIDs will be enabled if mac80211
 352 *   says it should be
 353 * o maintain current state of phy ofdm or phy cck error reception.
 354 *   If the hardware detects any of these type of errors then
 355 *   ath5k_hw_get_rx_filter() will pass to us the respective
 356 *   hardware filters to be able to receive these type of frames.
 357 * o probe request frames are accepted only when operating in
 358 *   hostap, adhoc, or monitor modes
 359 * o enable promiscuous mode according to the interface state
 360 * o accept beacons:
 361 *   - when operating in adhoc mode so the 802.11 layer creates
 362 *     node table entries for peers,
 363 *   - when operating in station mode for collecting rssi data when
 364 *     the station is otherwise quiet, or
 365 *   - when scanning
 366 */
 367static void
 368ath5k_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags,
 369                       unsigned int *new_flags, u64 multicast)
 370{
 371#define SUPPORTED_FIF_FLAGS \
 372        (FIF_PROMISC_IN_BSS |  FIF_ALLMULTI | FIF_FCSFAIL | \
 373        FIF_PLCPFAIL | FIF_CONTROL | FIF_OTHER_BSS | \
 374        FIF_BCN_PRBRESP_PROMISC)
 375
 376        struct ath5k_hw *ah = hw->priv;
 377        u32 mfilt[2], rfilt;
 378        struct ath5k_vif_iter_data iter_data; /* to count STA interfaces */
 379
 380        mutex_lock(&ah->lock);
 381
 382        mfilt[0] = multicast;
 383        mfilt[1] = multicast >> 32;
 384
 385        /* Only deal with supported flags */
 386        changed_flags &= SUPPORTED_FIF_FLAGS;
 387        *new_flags &= SUPPORTED_FIF_FLAGS;
 388
 389        /* If HW detects any phy or radar errors, leave those filters on.
 390         * Also, always enable Unicast, Broadcasts and Multicast
 391         * XXX: move unicast, bssid broadcasts and multicast to mac80211 */
 392        rfilt = (ath5k_hw_get_rx_filter(ah) & (AR5K_RX_FILTER_PHYERR)) |
 393                (AR5K_RX_FILTER_UCAST | AR5K_RX_FILTER_BCAST |
 394                AR5K_RX_FILTER_MCAST);
 395
 396        if (changed_flags & (FIF_PROMISC_IN_BSS | FIF_OTHER_BSS)) {
 397                if (*new_flags & FIF_PROMISC_IN_BSS)
 398                        __set_bit(ATH_STAT_PROMISC, ah->status);
 399                else
 400                        __clear_bit(ATH_STAT_PROMISC, ah->status);
 401        }
 402
 403        if (test_bit(ATH_STAT_PROMISC, ah->status))
 404                rfilt |= AR5K_RX_FILTER_PROM;
 405
 406        /* Note, AR5K_RX_FILTER_MCAST is already enabled */
 407        if (*new_flags & FIF_ALLMULTI) {
 408                mfilt[0] =  ~0;
 409                mfilt[1] =  ~0;
 410        }
 411
 412        /* This is the best we can do */
 413        if (*new_flags & (FIF_FCSFAIL | FIF_PLCPFAIL))
 414                rfilt |= AR5K_RX_FILTER_PHYERR;
 415
 416        /* FIF_BCN_PRBRESP_PROMISC really means to enable beacons
 417        * and probes for any BSSID */
 418        if ((*new_flags & FIF_BCN_PRBRESP_PROMISC) || (ah->nvifs > 1))
 419                rfilt |= AR5K_RX_FILTER_BEACON;
 420
 421        /* FIF_CONTROL doc says that if FIF_PROMISC_IN_BSS is not
 422         * set we should only pass on control frames for this
 423         * station. This needs testing. I believe right now this
 424         * enables *all* control frames, which is OK.. but
 425         * but we should see if we can improve on granularity */
 426        if (*new_flags & FIF_CONTROL)
 427                rfilt |= AR5K_RX_FILTER_CONTROL;
 428
 429        /* Additional settings per mode -- this is per ath5k */
 430
 431        /* XXX move these to mac80211, and add a beacon IFF flag to mac80211 */
 432
 433        switch (ah->opmode) {
 434        case NL80211_IFTYPE_MESH_POINT:
 435                rfilt |= AR5K_RX_FILTER_CONTROL |
 436                         AR5K_RX_FILTER_BEACON |
 437                         AR5K_RX_FILTER_PROBEREQ |
 438                         AR5K_RX_FILTER_PROM;
 439                break;
 440        case NL80211_IFTYPE_AP:
 441        case NL80211_IFTYPE_ADHOC:
 442                rfilt |= AR5K_RX_FILTER_PROBEREQ |
 443                         AR5K_RX_FILTER_BEACON;
 444                break;
 445        case NL80211_IFTYPE_STATION:
 446                if (ah->assoc)
 447                        rfilt |= AR5K_RX_FILTER_BEACON;
 448        default:
 449                break;
 450        }
 451
 452        iter_data.hw_macaddr = NULL;
 453        iter_data.n_stas = 0;
 454        iter_data.need_set_hw_addr = false;
 455        ieee80211_iterate_active_interfaces_atomic(
 456                ah->hw, IEEE80211_IFACE_ITER_RESUME_ALL,
 457                ath5k_vif_iter, &iter_data);
 458
 459        /* Set up RX Filter */
 460        if (iter_data.n_stas > 1) {
 461                /* If you have multiple STA interfaces connected to
 462                 * different APs, ARPs are not received (most of the time?)
 463                 * Enabling PROMISC appears to fix that problem.
 464                 */
 465                rfilt |= AR5K_RX_FILTER_PROM;
 466        }
 467
 468        /* Set filters */
 469        ath5k_hw_set_rx_filter(ah, rfilt);
 470
 471        /* Set multicast bits */
 472        ath5k_hw_set_mcast_filter(ah, mfilt[0], mfilt[1]);
 473        /* Set the cached hw filter flags, this will later actually
 474         * be set in HW */
 475        ah->filter_flags = rfilt;
 476
 477        mutex_unlock(&ah->lock);
 478}
 479
 480
 481static int
 482ath5k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
 483              struct ieee80211_vif *vif, struct ieee80211_sta *sta,
 484              struct ieee80211_key_conf *key)
 485{
 486        struct ath5k_hw *ah = hw->priv;
 487        struct ath_common *common = ath5k_hw_common(ah);
 488        int ret = 0;
 489
 490        if (ath5k_modparam_nohwcrypt)
 491                return -EOPNOTSUPP;
 492
 493        if (key->flags & IEEE80211_KEY_FLAG_RX_MGMT)
 494                return -EOPNOTSUPP;
 495
 496        if (vif->type == NL80211_IFTYPE_ADHOC &&
 497            (key->cipher == WLAN_CIPHER_SUITE_TKIP ||
 498             key->cipher == WLAN_CIPHER_SUITE_CCMP) &&
 499            !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) {
 500                /* don't program group keys when using IBSS_RSN */
 501                return -EOPNOTSUPP;
 502        }
 503
 504        switch (key->cipher) {
 505        case WLAN_CIPHER_SUITE_WEP40:
 506        case WLAN_CIPHER_SUITE_WEP104:
 507        case WLAN_CIPHER_SUITE_TKIP:
 508                break;
 509        case WLAN_CIPHER_SUITE_CCMP:
 510                if (common->crypt_caps & ATH_CRYPT_CAP_CIPHER_AESCCM)
 511                        break;
 512                return -EOPNOTSUPP;
 513        default:
 514                WARN_ON(1);
 515                return -EINVAL;
 516        }
 517
 518        mutex_lock(&ah->lock);
 519
 520        switch (cmd) {
 521        case SET_KEY:
 522                ret = ath_key_config(common, vif, sta, key);
 523                if (ret >= 0) {
 524                        key->hw_key_idx = ret;
 525                        /* push IV and Michael MIC generation to stack */
 526                        key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
 527                        if (key->cipher == WLAN_CIPHER_SUITE_TKIP)
 528                                key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
 529                        if (key->cipher == WLAN_CIPHER_SUITE_CCMP)
 530                                key->flags |= IEEE80211_KEY_FLAG_SW_MGMT_TX;
 531                        ret = 0;
 532                }
 533                break;
 534        case DISABLE_KEY:
 535                ath_key_delete(common, key);
 536                break;
 537        default:
 538                ret = -EINVAL;
 539        }
 540
 541        mmiowb();
 542        mutex_unlock(&ah->lock);
 543        return ret;
 544}
 545
 546
 547static void
 548ath5k_sw_scan_start(struct ieee80211_hw *hw)
 549{
 550        struct ath5k_hw *ah = hw->priv;
 551        if (!ah->assoc)
 552                ath5k_hw_set_ledstate(ah, AR5K_LED_SCAN);
 553}
 554
 555
 556static void
 557ath5k_sw_scan_complete(struct ieee80211_hw *hw)
 558{
 559        struct ath5k_hw *ah = hw->priv;
 560        ath5k_hw_set_ledstate(ah, ah->assoc ?
 561                AR5K_LED_ASSOC : AR5K_LED_INIT);
 562}
 563
 564
 565static int
 566ath5k_get_stats(struct ieee80211_hw *hw,
 567                struct ieee80211_low_level_stats *stats)
 568{
 569        struct ath5k_hw *ah = hw->priv;
 570
 571        /* Force update */
 572        ath5k_hw_update_mib_counters(ah);
 573
 574        stats->dot11ACKFailureCount = ah->stats.ack_fail;
 575        stats->dot11RTSFailureCount = ah->stats.rts_fail;
 576        stats->dot11RTSSuccessCount = ah->stats.rts_ok;
 577        stats->dot11FCSErrorCount = ah->stats.fcs_error;
 578
 579        return 0;
 580}
 581
 582
 583static int
 584ath5k_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u16 queue,
 585              const struct ieee80211_tx_queue_params *params)
 586{
 587        struct ath5k_hw *ah = hw->priv;
 588        struct ath5k_txq_info qi;
 589        int ret = 0;
 590
 591        if (queue >= ah->ah_capabilities.cap_queues.q_tx_num)
 592                return 0;
 593
 594        mutex_lock(&ah->lock);
 595
 596        ath5k_hw_get_tx_queueprops(ah, queue, &qi);
 597
 598        qi.tqi_aifs = params->aifs;
 599        qi.tqi_cw_min = params->cw_min;
 600        qi.tqi_cw_max = params->cw_max;
 601        qi.tqi_burst_time = params->txop * 32;
 602
 603        ATH5K_DBG(ah, ATH5K_DEBUG_ANY,
 604                  "Configure tx [queue %d],  "
 605                  "aifs: %d, cw_min: %d, cw_max: %d, txop: %d\n",
 606                  queue, params->aifs, params->cw_min,
 607                  params->cw_max, params->txop);
 608
 609        if (ath5k_hw_set_tx_queueprops(ah, queue, &qi)) {
 610                ATH5K_ERR(ah,
 611                          "Unable to update hardware queue %u!\n", queue);
 612                ret = -EIO;
 613        } else
 614                ath5k_hw_reset_tx_queue(ah, queue);
 615
 616        mutex_unlock(&ah->lock);
 617
 618        return ret;
 619}
 620
 621
 622static u64
 623ath5k_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
 624{
 625        struct ath5k_hw *ah = hw->priv;
 626
 627        return ath5k_hw_get_tsf64(ah);
 628}
 629
 630
 631static void
 632ath5k_set_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u64 tsf)
 633{
 634        struct ath5k_hw *ah = hw->priv;
 635
 636        ath5k_hw_set_tsf64(ah, tsf);
 637}
 638
 639
 640static void
 641ath5k_reset_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
 642{
 643        struct ath5k_hw *ah = hw->priv;
 644
 645        /*
 646         * in IBSS mode we need to update the beacon timers too.
 647         * this will also reset the TSF if we call it with 0
 648         */
 649        if (ah->opmode == NL80211_IFTYPE_ADHOC)
 650                ath5k_beacon_update_timers(ah, 0);
 651        else
 652                ath5k_hw_reset_tsf(ah);
 653}
 654
 655
 656static int
 657ath5k_get_survey(struct ieee80211_hw *hw, int idx, struct survey_info *survey)
 658{
 659        struct ath5k_hw *ah = hw->priv;
 660        struct ieee80211_conf *conf = &hw->conf;
 661        struct ath_common *common = ath5k_hw_common(ah);
 662        struct ath_cycle_counters *cc = &common->cc_survey;
 663        unsigned int div = common->clockrate * 1000;
 664
 665        if (idx != 0)
 666                return -ENOENT;
 667
 668        spin_lock_bh(&common->cc_lock);
 669        ath_hw_cycle_counters_update(common);
 670        if (cc->cycles > 0) {
 671                ah->survey.channel_time += cc->cycles / div;
 672                ah->survey.channel_time_busy += cc->rx_busy / div;
 673                ah->survey.channel_time_rx += cc->rx_frame / div;
 674                ah->survey.channel_time_tx += cc->tx_frame / div;
 675        }
 676        memset(cc, 0, sizeof(*cc));
 677        spin_unlock_bh(&common->cc_lock);
 678
 679        memcpy(survey, &ah->survey, sizeof(*survey));
 680
 681        survey->channel = conf->chandef.chan;
 682        survey->noise = ah->ah_noise_floor;
 683        survey->filled = SURVEY_INFO_NOISE_DBM |
 684                        SURVEY_INFO_CHANNEL_TIME |
 685                        SURVEY_INFO_CHANNEL_TIME_BUSY |
 686                        SURVEY_INFO_CHANNEL_TIME_RX |
 687                        SURVEY_INFO_CHANNEL_TIME_TX;
 688
 689        return 0;
 690}
 691
 692
 693/**
 694 * ath5k_set_coverage_class - Set IEEE 802.11 coverage class
 695 *
 696 * @hw: struct ieee80211_hw pointer
 697 * @coverage_class: IEEE 802.11 coverage class number
 698 *
 699 * Mac80211 callback. Sets slot time, ACK timeout and CTS timeout for given
 700 * coverage class. The values are persistent, they are restored after device
 701 * reset.
 702 */
 703static void
 704ath5k_set_coverage_class(struct ieee80211_hw *hw, u8 coverage_class)
 705{
 706        struct ath5k_hw *ah = hw->priv;
 707
 708        mutex_lock(&ah->lock);
 709        ath5k_hw_set_coverage_class(ah, coverage_class);
 710        mutex_unlock(&ah->lock);
 711}
 712
 713
 714static int
 715ath5k_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant)
 716{
 717        struct ath5k_hw *ah = hw->priv;
 718
 719        if (tx_ant == 1 && rx_ant == 1)
 720                ath5k_hw_set_antenna_mode(ah, AR5K_ANTMODE_FIXED_A);
 721        else if (tx_ant == 2 && rx_ant == 2)
 722                ath5k_hw_set_antenna_mode(ah, AR5K_ANTMODE_FIXED_B);
 723        else if ((tx_ant & 3) == 3 && (rx_ant & 3) == 3)
 724                ath5k_hw_set_antenna_mode(ah, AR5K_ANTMODE_DEFAULT);
 725        else
 726                return -EINVAL;
 727        return 0;
 728}
 729
 730
 731static int
 732ath5k_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant)
 733{
 734        struct ath5k_hw *ah = hw->priv;
 735
 736        switch (ah->ah_ant_mode) {
 737        case AR5K_ANTMODE_FIXED_A:
 738                *tx_ant = 1; *rx_ant = 1; break;
 739        case AR5K_ANTMODE_FIXED_B:
 740                *tx_ant = 2; *rx_ant = 2; break;
 741        case AR5K_ANTMODE_DEFAULT:
 742                *tx_ant = 3; *rx_ant = 3; break;
 743        }
 744        return 0;
 745}
 746
 747
 748static void ath5k_get_ringparam(struct ieee80211_hw *hw,
 749                                u32 *tx, u32 *tx_max, u32 *rx, u32 *rx_max)
 750{
 751        struct ath5k_hw *ah = hw->priv;
 752
 753        *tx = ah->txqs[AR5K_TX_QUEUE_ID_DATA_MIN].txq_max;
 754
 755        *tx_max = ATH5K_TXQ_LEN_MAX;
 756        *rx = *rx_max = ATH_RXBUF;
 757}
 758
 759
 760static int ath5k_set_ringparam(struct ieee80211_hw *hw, u32 tx, u32 rx)
 761{
 762        struct ath5k_hw *ah = hw->priv;
 763        u16 qnum;
 764
 765        /* only support setting tx ring size for now */
 766        if (rx != ATH_RXBUF)
 767                return -EINVAL;
 768
 769        /* restrict tx ring size min/max */
 770        if (!tx || tx > ATH5K_TXQ_LEN_MAX)
 771                return -EINVAL;
 772
 773        for (qnum = 0; qnum < ARRAY_SIZE(ah->txqs); qnum++) {
 774                if (!ah->txqs[qnum].setup)
 775                        continue;
 776                if (ah->txqs[qnum].qnum < AR5K_TX_QUEUE_ID_DATA_MIN ||
 777                    ah->txqs[qnum].qnum > AR5K_TX_QUEUE_ID_DATA_MAX)
 778                        continue;
 779
 780                ah->txqs[qnum].txq_max = tx;
 781                if (ah->txqs[qnum].txq_len >= ah->txqs[qnum].txq_max)
 782                        ieee80211_stop_queue(hw, ah->txqs[qnum].qnum);
 783        }
 784
 785        return 0;
 786}
 787
 788
 789const struct ieee80211_ops ath5k_hw_ops = {
 790        .tx                     = ath5k_tx,
 791        .start                  = ath5k_start,
 792        .stop                   = ath5k_stop,
 793        .add_interface          = ath5k_add_interface,
 794        /* .change_interface    = not implemented */
 795        .remove_interface       = ath5k_remove_interface,
 796        .config                 = ath5k_config,
 797        .bss_info_changed       = ath5k_bss_info_changed,
 798        .prepare_multicast      = ath5k_prepare_multicast,
 799        .configure_filter       = ath5k_configure_filter,
 800        /* .set_tim             = not implemented */
 801        .set_key                = ath5k_set_key,
 802        /* .update_tkip_key     = not implemented */
 803        /* .hw_scan             = not implemented */
 804        .sw_scan_start          = ath5k_sw_scan_start,
 805        .sw_scan_complete       = ath5k_sw_scan_complete,
 806        .get_stats              = ath5k_get_stats,
 807        /* .get_tkip_seq        = not implemented */
 808        /* .set_frag_threshold  = not implemented */
 809        /* .set_rts_threshold   = not implemented */
 810        /* .sta_add             = not implemented */
 811        /* .sta_remove          = not implemented */
 812        /* .sta_notify          = not implemented */
 813        .conf_tx                = ath5k_conf_tx,
 814        .get_tsf                = ath5k_get_tsf,
 815        .set_tsf                = ath5k_set_tsf,
 816        .reset_tsf              = ath5k_reset_tsf,
 817        /* .tx_last_beacon      = not implemented */
 818        /* .ampdu_action        = not needed */
 819        .get_survey             = ath5k_get_survey,
 820        .set_coverage_class     = ath5k_set_coverage_class,
 821        /* .rfkill_poll         = not implemented */
 822        /* .flush               = not implemented */
 823        /* .channel_switch      = not implemented */
 824        /* .napi_poll           = not implemented */
 825        .set_antenna            = ath5k_set_antenna,
 826        .get_antenna            = ath5k_get_antenna,
 827        .set_ringparam          = ath5k_set_ringparam,
 828        .get_ringparam          = ath5k_get_ringparam,
 829};
 830