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], control);
  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);
 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] = 0;
 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_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        /* Note, AR5K_RX_FILTER_MCAST is already enabled */
 397        if (*new_flags & FIF_ALLMULTI) {
 398                mfilt[0] =  ~0;
 399                mfilt[1] =  ~0;
 400        }
 401
 402        /* This is the best we can do */
 403        if (*new_flags & (FIF_FCSFAIL | FIF_PLCPFAIL))
 404                rfilt |= AR5K_RX_FILTER_PHYERR;
 405
 406        /* FIF_BCN_PRBRESP_PROMISC really means to enable beacons
 407        * and probes for any BSSID */
 408        if ((*new_flags & FIF_BCN_PRBRESP_PROMISC) || (ah->nvifs > 1))
 409                rfilt |= AR5K_RX_FILTER_BEACON;
 410
 411        /* FIF_CONTROL doc says we should only pass on control frames for this
 412         * station. This needs testing. I believe right now this
 413         * enables *all* control frames, which is OK.. but
 414         * but we should see if we can improve on granularity */
 415        if (*new_flags & FIF_CONTROL)
 416                rfilt |= AR5K_RX_FILTER_CONTROL;
 417
 418        /* Additional settings per mode -- this is per ath5k */
 419
 420        /* XXX move these to mac80211, and add a beacon IFF flag to mac80211 */
 421
 422        switch (ah->opmode) {
 423        case NL80211_IFTYPE_MESH_POINT:
 424                rfilt |= AR5K_RX_FILTER_CONTROL |
 425                         AR5K_RX_FILTER_BEACON |
 426                         AR5K_RX_FILTER_PROBEREQ |
 427                         AR5K_RX_FILTER_PROM;
 428                break;
 429        case NL80211_IFTYPE_AP:
 430        case NL80211_IFTYPE_ADHOC:
 431                rfilt |= AR5K_RX_FILTER_PROBEREQ |
 432                         AR5K_RX_FILTER_BEACON;
 433                break;
 434        case NL80211_IFTYPE_STATION:
 435                if (ah->assoc)
 436                        rfilt |= AR5K_RX_FILTER_BEACON;
 437        default:
 438                break;
 439        }
 440
 441        iter_data.hw_macaddr = NULL;
 442        iter_data.n_stas = 0;
 443        iter_data.need_set_hw_addr = false;
 444        ieee80211_iterate_active_interfaces_atomic(
 445                ah->hw, IEEE80211_IFACE_ITER_RESUME_ALL,
 446                ath5k_vif_iter, &iter_data);
 447
 448        /* Set up RX Filter */
 449        if (iter_data.n_stas > 1) {
 450                /* If you have multiple STA interfaces connected to
 451                 * different APs, ARPs are not received (most of the time?)
 452                 * Enabling PROMISC appears to fix that problem.
 453                 */
 454                rfilt |= AR5K_RX_FILTER_PROM;
 455        }
 456
 457        /* Set filters */
 458        ath5k_hw_set_rx_filter(ah, rfilt);
 459
 460        /* Set multicast bits */
 461        ath5k_hw_set_mcast_filter(ah, mfilt[0], mfilt[1]);
 462        /* Set the cached hw filter flags, this will later actually
 463         * be set in HW */
 464        ah->filter_flags = rfilt;
 465        /* Store current FIF filter flags */
 466        ah->fif_filter_flags = *new_flags;
 467
 468        mutex_unlock(&ah->lock);
 469}
 470
 471
 472static int
 473ath5k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
 474              struct ieee80211_vif *vif, struct ieee80211_sta *sta,
 475              struct ieee80211_key_conf *key)
 476{
 477        struct ath5k_hw *ah = hw->priv;
 478        struct ath_common *common = ath5k_hw_common(ah);
 479        int ret = 0;
 480
 481        if (ath5k_modparam_nohwcrypt)
 482                return -EOPNOTSUPP;
 483
 484        if (key->flags & IEEE80211_KEY_FLAG_RX_MGMT)
 485                return -EOPNOTSUPP;
 486
 487        if (vif->type == NL80211_IFTYPE_ADHOC &&
 488            (key->cipher == WLAN_CIPHER_SUITE_TKIP ||
 489             key->cipher == WLAN_CIPHER_SUITE_CCMP) &&
 490            !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) {
 491                /* don't program group keys when using IBSS_RSN */
 492                return -EOPNOTSUPP;
 493        }
 494
 495        switch (key->cipher) {
 496        case WLAN_CIPHER_SUITE_WEP40:
 497        case WLAN_CIPHER_SUITE_WEP104:
 498        case WLAN_CIPHER_SUITE_TKIP:
 499                break;
 500        case WLAN_CIPHER_SUITE_CCMP:
 501                if (common->crypt_caps & ATH_CRYPT_CAP_CIPHER_AESCCM)
 502                        break;
 503                return -EOPNOTSUPP;
 504        default:
 505                WARN_ON(1);
 506                return -EINVAL;
 507        }
 508
 509        mutex_lock(&ah->lock);
 510
 511        switch (cmd) {
 512        case SET_KEY:
 513                ret = ath_key_config(common, vif, sta, key);
 514                if (ret >= 0) {
 515                        key->hw_key_idx = ret;
 516                        /* push IV and Michael MIC generation to stack */
 517                        key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
 518                        if (key->cipher == WLAN_CIPHER_SUITE_TKIP)
 519                                key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
 520                        if (key->cipher == WLAN_CIPHER_SUITE_CCMP)
 521                                key->flags |= IEEE80211_KEY_FLAG_SW_MGMT_TX;
 522                        ret = 0;
 523                }
 524                break;
 525        case DISABLE_KEY:
 526                ath_key_delete(common, key);
 527                break;
 528        default:
 529                ret = -EINVAL;
 530        }
 531
 532        mmiowb();
 533        mutex_unlock(&ah->lock);
 534        return ret;
 535}
 536
 537
 538static void
 539ath5k_sw_scan_start(struct ieee80211_hw *hw,
 540                    struct ieee80211_vif *vif,
 541                    const u8 *mac_addr)
 542{
 543        struct ath5k_hw *ah = hw->priv;
 544        if (!ah->assoc)
 545                ath5k_hw_set_ledstate(ah, AR5K_LED_SCAN);
 546}
 547
 548
 549static void
 550ath5k_sw_scan_complete(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
 551{
 552        struct ath5k_hw *ah = hw->priv;
 553        ath5k_hw_set_ledstate(ah, ah->assoc ?
 554                AR5K_LED_ASSOC : AR5K_LED_INIT);
 555}
 556
 557
 558static int
 559ath5k_get_stats(struct ieee80211_hw *hw,
 560                struct ieee80211_low_level_stats *stats)
 561{
 562        struct ath5k_hw *ah = hw->priv;
 563
 564        /* Force update */
 565        ath5k_hw_update_mib_counters(ah);
 566
 567        stats->dot11ACKFailureCount = ah->stats.ack_fail;
 568        stats->dot11RTSFailureCount = ah->stats.rts_fail;
 569        stats->dot11RTSSuccessCount = ah->stats.rts_ok;
 570        stats->dot11FCSErrorCount = ah->stats.fcs_error;
 571
 572        return 0;
 573}
 574
 575
 576static int
 577ath5k_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u16 queue,
 578              const struct ieee80211_tx_queue_params *params)
 579{
 580        struct ath5k_hw *ah = hw->priv;
 581        struct ath5k_txq_info qi;
 582        int ret = 0;
 583
 584        if (queue >= ah->ah_capabilities.cap_queues.q_tx_num)
 585                return 0;
 586
 587        mutex_lock(&ah->lock);
 588
 589        ath5k_hw_get_tx_queueprops(ah, queue, &qi);
 590
 591        qi.tqi_aifs = params->aifs;
 592        qi.tqi_cw_min = params->cw_min;
 593        qi.tqi_cw_max = params->cw_max;
 594        qi.tqi_burst_time = params->txop * 32;
 595
 596        ATH5K_DBG(ah, ATH5K_DEBUG_ANY,
 597                  "Configure tx [queue %d],  "
 598                  "aifs: %d, cw_min: %d, cw_max: %d, txop: %d\n",
 599                  queue, params->aifs, params->cw_min,
 600                  params->cw_max, params->txop);
 601
 602        if (ath5k_hw_set_tx_queueprops(ah, queue, &qi)) {
 603                ATH5K_ERR(ah,
 604                          "Unable to update hardware queue %u!\n", queue);
 605                ret = -EIO;
 606        } else
 607                ath5k_hw_reset_tx_queue(ah, queue);
 608
 609        mutex_unlock(&ah->lock);
 610
 611        return ret;
 612}
 613
 614
 615static u64
 616ath5k_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
 617{
 618        struct ath5k_hw *ah = hw->priv;
 619
 620        return ath5k_hw_get_tsf64(ah);
 621}
 622
 623
 624static void
 625ath5k_set_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u64 tsf)
 626{
 627        struct ath5k_hw *ah = hw->priv;
 628
 629        ath5k_hw_set_tsf64(ah, tsf);
 630}
 631
 632
 633static void
 634ath5k_reset_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
 635{
 636        struct ath5k_hw *ah = hw->priv;
 637
 638        /*
 639         * in IBSS mode we need to update the beacon timers too.
 640         * this will also reset the TSF if we call it with 0
 641         */
 642        if (ah->opmode == NL80211_IFTYPE_ADHOC)
 643                ath5k_beacon_update_timers(ah, 0);
 644        else
 645                ath5k_hw_reset_tsf(ah);
 646}
 647
 648
 649static int
 650ath5k_get_survey(struct ieee80211_hw *hw, int idx, struct survey_info *survey)
 651{
 652        struct ath5k_hw *ah = hw->priv;
 653        struct ieee80211_conf *conf = &hw->conf;
 654        struct ath_common *common = ath5k_hw_common(ah);
 655        struct ath_cycle_counters *cc = &common->cc_survey;
 656        unsigned int div = common->clockrate * 1000;
 657
 658        if (idx != 0)
 659                return -ENOENT;
 660
 661        spin_lock_bh(&common->cc_lock);
 662        ath_hw_cycle_counters_update(common);
 663        if (cc->cycles > 0) {
 664                ah->survey.time += cc->cycles / div;
 665                ah->survey.time_busy += cc->rx_busy / div;
 666                ah->survey.time_rx += cc->rx_frame / div;
 667                ah->survey.time_tx += cc->tx_frame / div;
 668        }
 669        memset(cc, 0, sizeof(*cc));
 670        spin_unlock_bh(&common->cc_lock);
 671
 672        memcpy(survey, &ah->survey, sizeof(*survey));
 673
 674        survey->channel = conf->chandef.chan;
 675        survey->noise = ah->ah_noise_floor;
 676        survey->filled = SURVEY_INFO_NOISE_DBM |
 677                        SURVEY_INFO_IN_USE |
 678                        SURVEY_INFO_TIME |
 679                        SURVEY_INFO_TIME_BUSY |
 680                        SURVEY_INFO_TIME_RX |
 681                        SURVEY_INFO_TIME_TX;
 682
 683        return 0;
 684}
 685
 686
 687/**
 688 * ath5k_set_coverage_class - Set IEEE 802.11 coverage class
 689 *
 690 * @hw: struct ieee80211_hw pointer
 691 * @coverage_class: IEEE 802.11 coverage class number
 692 *
 693 * Mac80211 callback. Sets slot time, ACK timeout and CTS timeout for given
 694 * coverage class. The values are persistent, they are restored after device
 695 * reset.
 696 */
 697static void
 698ath5k_set_coverage_class(struct ieee80211_hw *hw, s16 coverage_class)
 699{
 700        struct ath5k_hw *ah = hw->priv;
 701
 702        mutex_lock(&ah->lock);
 703        ath5k_hw_set_coverage_class(ah, coverage_class);
 704        mutex_unlock(&ah->lock);
 705}
 706
 707
 708static int
 709ath5k_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant)
 710{
 711        struct ath5k_hw *ah = hw->priv;
 712
 713        if (tx_ant == 1 && rx_ant == 1)
 714                ath5k_hw_set_antenna_mode(ah, AR5K_ANTMODE_FIXED_A);
 715        else if (tx_ant == 2 && rx_ant == 2)
 716                ath5k_hw_set_antenna_mode(ah, AR5K_ANTMODE_FIXED_B);
 717        else if ((tx_ant & 3) == 3 && (rx_ant & 3) == 3)
 718                ath5k_hw_set_antenna_mode(ah, AR5K_ANTMODE_DEFAULT);
 719        else
 720                return -EINVAL;
 721        return 0;
 722}
 723
 724
 725static int
 726ath5k_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant)
 727{
 728        struct ath5k_hw *ah = hw->priv;
 729
 730        switch (ah->ah_ant_mode) {
 731        case AR5K_ANTMODE_FIXED_A:
 732                *tx_ant = 1; *rx_ant = 1; break;
 733        case AR5K_ANTMODE_FIXED_B:
 734                *tx_ant = 2; *rx_ant = 2; break;
 735        case AR5K_ANTMODE_DEFAULT:
 736                *tx_ant = 3; *rx_ant = 3; break;
 737        }
 738        return 0;
 739}
 740
 741
 742static void ath5k_get_ringparam(struct ieee80211_hw *hw,
 743                                u32 *tx, u32 *tx_max, u32 *rx, u32 *rx_max)
 744{
 745        struct ath5k_hw *ah = hw->priv;
 746
 747        *tx = ah->txqs[AR5K_TX_QUEUE_ID_DATA_MIN].txq_max;
 748
 749        *tx_max = ATH5K_TXQ_LEN_MAX;
 750        *rx = *rx_max = ATH_RXBUF;
 751}
 752
 753
 754static int ath5k_set_ringparam(struct ieee80211_hw *hw, u32 tx, u32 rx)
 755{
 756        struct ath5k_hw *ah = hw->priv;
 757        u16 qnum;
 758
 759        /* only support setting tx ring size for now */
 760        if (rx != ATH_RXBUF)
 761                return -EINVAL;
 762
 763        /* restrict tx ring size min/max */
 764        if (!tx || tx > ATH5K_TXQ_LEN_MAX)
 765                return -EINVAL;
 766
 767        for (qnum = 0; qnum < ARRAY_SIZE(ah->txqs); qnum++) {
 768                if (!ah->txqs[qnum].setup)
 769                        continue;
 770                if (ah->txqs[qnum].qnum < AR5K_TX_QUEUE_ID_DATA_MIN ||
 771                    ah->txqs[qnum].qnum > AR5K_TX_QUEUE_ID_DATA_MAX)
 772                        continue;
 773
 774                ah->txqs[qnum].txq_max = tx;
 775                if (ah->txqs[qnum].txq_len >= ah->txqs[qnum].txq_max)
 776                        ieee80211_stop_queue(hw, ah->txqs[qnum].qnum);
 777        }
 778
 779        return 0;
 780}
 781
 782
 783const struct ieee80211_ops ath5k_hw_ops = {
 784        .tx                     = ath5k_tx,
 785        .start                  = ath5k_start,
 786        .stop                   = ath5k_stop,
 787        .add_interface          = ath5k_add_interface,
 788        /* .change_interface    = not implemented */
 789        .remove_interface       = ath5k_remove_interface,
 790        .config                 = ath5k_config,
 791        .bss_info_changed       = ath5k_bss_info_changed,
 792        .prepare_multicast      = ath5k_prepare_multicast,
 793        .configure_filter       = ath5k_configure_filter,
 794        /* .set_tim             = not implemented */
 795        .set_key                = ath5k_set_key,
 796        /* .update_tkip_key     = not implemented */
 797        /* .hw_scan             = not implemented */
 798        .sw_scan_start          = ath5k_sw_scan_start,
 799        .sw_scan_complete       = ath5k_sw_scan_complete,
 800        .get_stats              = ath5k_get_stats,
 801        /* .set_frag_threshold  = not implemented */
 802        /* .set_rts_threshold   = not implemented */
 803        /* .sta_add             = not implemented */
 804        /* .sta_remove          = not implemented */
 805        /* .sta_notify          = not implemented */
 806        .conf_tx                = ath5k_conf_tx,
 807        .get_tsf                = ath5k_get_tsf,
 808        .set_tsf                = ath5k_set_tsf,
 809        .reset_tsf              = ath5k_reset_tsf,
 810        /* .tx_last_beacon      = not implemented */
 811        /* .ampdu_action        = not needed */
 812        .get_survey             = ath5k_get_survey,
 813        .set_coverage_class     = ath5k_set_coverage_class,
 814        /* .rfkill_poll         = not implemented */
 815        /* .flush               = not implemented */
 816        /* .channel_switch      = not implemented */
 817        /* .napi_poll           = not implemented */
 818        .set_antenna            = ath5k_set_antenna,
 819        .get_antenna            = ath5k_get_antenna,
 820        .set_ringparam          = ath5k_set_ringparam,
 821        .get_ringparam          = ath5k_get_ringparam,
 822};
 823