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        }
 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
 318static u64
 319ath5k_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 */
 366static void
 367ath5k_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                break;
 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                return -EOPNOTSUPP;
 506        }
 507
 508        mutex_lock(&ah->lock);
 509
 510        switch (cmd) {
 511        case SET_KEY:
 512                ret = ath_key_config(common, vif, sta, key);
 513                if (ret >= 0) {
 514                        key->hw_key_idx = ret;
 515                        /* push IV and Michael MIC generation to stack */
 516                        key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
 517                        if (key->cipher == WLAN_CIPHER_SUITE_TKIP)
 518                                key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
 519                        if (key->cipher == WLAN_CIPHER_SUITE_CCMP)
 520                                key->flags |= IEEE80211_KEY_FLAG_SW_MGMT_TX;
 521                        ret = 0;
 522                }
 523                break;
 524        case DISABLE_KEY:
 525                ath_key_delete(common, key->hw_key_idx);
 526                break;
 527        default:
 528                ret = -EINVAL;
 529        }
 530
 531        mutex_unlock(&ah->lock);
 532        return ret;
 533}
 534
 535
 536static void
 537ath5k_sw_scan_start(struct ieee80211_hw *hw,
 538                    struct ieee80211_vif *vif,
 539                    const u8 *mac_addr)
 540{
 541        struct ath5k_hw *ah = hw->priv;
 542        if (!ah->assoc)
 543                ath5k_hw_set_ledstate(ah, AR5K_LED_SCAN);
 544}
 545
 546
 547static void
 548ath5k_sw_scan_complete(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
 549{
 550        struct ath5k_hw *ah = hw->priv;
 551        ath5k_hw_set_ledstate(ah, ah->assoc ?
 552                AR5K_LED_ASSOC : AR5K_LED_INIT);
 553}
 554
 555
 556static int
 557ath5k_get_stats(struct ieee80211_hw *hw,
 558                struct ieee80211_low_level_stats *stats)
 559{
 560        struct ath5k_hw *ah = hw->priv;
 561
 562        /* Force update */
 563        ath5k_hw_update_mib_counters(ah);
 564
 565        stats->dot11ACKFailureCount = ah->stats.ack_fail;
 566        stats->dot11RTSFailureCount = ah->stats.rts_fail;
 567        stats->dot11RTSSuccessCount = ah->stats.rts_ok;
 568        stats->dot11FCSErrorCount = ah->stats.fcs_error;
 569
 570        return 0;
 571}
 572
 573
 574static int
 575ath5k_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u16 queue,
 576              const struct ieee80211_tx_queue_params *params)
 577{
 578        struct ath5k_hw *ah = hw->priv;
 579        struct ath5k_txq_info qi;
 580        int ret = 0;
 581
 582        if (queue >= ah->ah_capabilities.cap_queues.q_tx_num)
 583                return 0;
 584
 585        mutex_lock(&ah->lock);
 586
 587        ath5k_hw_get_tx_queueprops(ah, queue, &qi);
 588
 589        qi.tqi_aifs = params->aifs;
 590        qi.tqi_cw_min = params->cw_min;
 591        qi.tqi_cw_max = params->cw_max;
 592        qi.tqi_burst_time = params->txop * 32;
 593
 594        ATH5K_DBG(ah, ATH5K_DEBUG_ANY,
 595                  "Configure tx [queue %d],  "
 596                  "aifs: %d, cw_min: %d, cw_max: %d, txop: %d\n",
 597                  queue, params->aifs, params->cw_min,
 598                  params->cw_max, params->txop);
 599
 600        if (ath5k_hw_set_tx_queueprops(ah, queue, &qi)) {
 601                ATH5K_ERR(ah,
 602                          "Unable to update hardware queue %u!\n", queue);
 603                ret = -EIO;
 604        } else
 605                ath5k_hw_reset_tx_queue(ah, queue);
 606
 607        mutex_unlock(&ah->lock);
 608
 609        return ret;
 610}
 611
 612
 613static u64
 614ath5k_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
 615{
 616        struct ath5k_hw *ah = hw->priv;
 617
 618        return ath5k_hw_get_tsf64(ah);
 619}
 620
 621
 622static void
 623ath5k_set_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u64 tsf)
 624{
 625        struct ath5k_hw *ah = hw->priv;
 626
 627        ath5k_hw_set_tsf64(ah, tsf);
 628}
 629
 630
 631static void
 632ath5k_reset_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
 633{
 634        struct ath5k_hw *ah = hw->priv;
 635
 636        /*
 637         * in IBSS mode we need to update the beacon timers too.
 638         * this will also reset the TSF if we call it with 0
 639         */
 640        if (ah->opmode == NL80211_IFTYPE_ADHOC)
 641                ath5k_beacon_update_timers(ah, 0);
 642        else
 643                ath5k_hw_reset_tsf(ah);
 644}
 645
 646
 647static int
 648ath5k_get_survey(struct ieee80211_hw *hw, int idx, struct survey_info *survey)
 649{
 650        struct ath5k_hw *ah = hw->priv;
 651        struct ieee80211_conf *conf = &hw->conf;
 652        struct ath_common *common = ath5k_hw_common(ah);
 653        struct ath_cycle_counters *cc = &common->cc_survey;
 654        unsigned int div = common->clockrate * 1000;
 655
 656        if (idx != 0)
 657                return -ENOENT;
 658
 659        spin_lock_bh(&common->cc_lock);
 660        ath_hw_cycle_counters_update(common);
 661        if (cc->cycles > 0) {
 662                ah->survey.time += cc->cycles / div;
 663                ah->survey.time_busy += cc->rx_busy / div;
 664                ah->survey.time_rx += cc->rx_frame / div;
 665                ah->survey.time_tx += cc->tx_frame / div;
 666        }
 667        memset(cc, 0, sizeof(*cc));
 668        spin_unlock_bh(&common->cc_lock);
 669
 670        memcpy(survey, &ah->survey, sizeof(*survey));
 671
 672        survey->channel = conf->chandef.chan;
 673        survey->noise = ah->ah_noise_floor;
 674        survey->filled = SURVEY_INFO_NOISE_DBM |
 675                        SURVEY_INFO_IN_USE |
 676                        SURVEY_INFO_TIME |
 677                        SURVEY_INFO_TIME_BUSY |
 678                        SURVEY_INFO_TIME_RX |
 679                        SURVEY_INFO_TIME_TX;
 680
 681        return 0;
 682}
 683
 684
 685/**
 686 * ath5k_set_coverage_class - Set IEEE 802.11 coverage class
 687 *
 688 * @hw: struct ieee80211_hw pointer
 689 * @coverage_class: IEEE 802.11 coverage class number
 690 *
 691 * Mac80211 callback. Sets slot time, ACK timeout and CTS timeout for given
 692 * coverage class. The values are persistent, they are restored after device
 693 * reset.
 694 */
 695static void
 696ath5k_set_coverage_class(struct ieee80211_hw *hw, s16 coverage_class)
 697{
 698        struct ath5k_hw *ah = hw->priv;
 699
 700        mutex_lock(&ah->lock);
 701        ath5k_hw_set_coverage_class(ah, coverage_class);
 702        mutex_unlock(&ah->lock);
 703}
 704
 705
 706static int
 707ath5k_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant)
 708{
 709        struct ath5k_hw *ah = hw->priv;
 710
 711        if (tx_ant == 1 && rx_ant == 1)
 712                ath5k_hw_set_antenna_mode(ah, AR5K_ANTMODE_FIXED_A);
 713        else if (tx_ant == 2 && rx_ant == 2)
 714                ath5k_hw_set_antenna_mode(ah, AR5K_ANTMODE_FIXED_B);
 715        else if ((tx_ant & 3) == 3 && (rx_ant & 3) == 3)
 716                ath5k_hw_set_antenna_mode(ah, AR5K_ANTMODE_DEFAULT);
 717        else
 718                return -EINVAL;
 719        return 0;
 720}
 721
 722
 723static int
 724ath5k_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant)
 725{
 726        struct ath5k_hw *ah = hw->priv;
 727
 728        switch (ah->ah_ant_mode) {
 729        case AR5K_ANTMODE_FIXED_A:
 730                *tx_ant = 1; *rx_ant = 1; break;
 731        case AR5K_ANTMODE_FIXED_B:
 732                *tx_ant = 2; *rx_ant = 2; break;
 733        case AR5K_ANTMODE_DEFAULT:
 734                *tx_ant = 3; *rx_ant = 3; break;
 735        }
 736        return 0;
 737}
 738
 739
 740static void ath5k_get_ringparam(struct ieee80211_hw *hw,
 741                                u32 *tx, u32 *tx_max, u32 *rx, u32 *rx_max)
 742{
 743        struct ath5k_hw *ah = hw->priv;
 744
 745        *tx = ah->txqs[AR5K_TX_QUEUE_ID_DATA_MIN].txq_max;
 746
 747        *tx_max = ATH5K_TXQ_LEN_MAX;
 748        *rx = *rx_max = ATH_RXBUF;
 749}
 750
 751
 752static int ath5k_set_ringparam(struct ieee80211_hw *hw, u32 tx, u32 rx)
 753{
 754        struct ath5k_hw *ah = hw->priv;
 755        u16 qnum;
 756
 757        /* only support setting tx ring size for now */
 758        if (rx != ATH_RXBUF)
 759                return -EINVAL;
 760
 761        /* restrict tx ring size min/max */
 762        if (!tx || tx > ATH5K_TXQ_LEN_MAX)
 763                return -EINVAL;
 764
 765        for (qnum = 0; qnum < ARRAY_SIZE(ah->txqs); qnum++) {
 766                if (!ah->txqs[qnum].setup)
 767                        continue;
 768                if (ah->txqs[qnum].qnum < AR5K_TX_QUEUE_ID_DATA_MIN ||
 769                    ah->txqs[qnum].qnum > AR5K_TX_QUEUE_ID_DATA_MAX)
 770                        continue;
 771
 772                ah->txqs[qnum].txq_max = tx;
 773                if (ah->txqs[qnum].txq_len >= ah->txqs[qnum].txq_max)
 774                        ieee80211_stop_queue(hw, ah->txqs[qnum].qnum);
 775        }
 776
 777        return 0;
 778}
 779
 780
 781const struct ieee80211_ops ath5k_hw_ops = {
 782        .tx                     = ath5k_tx,
 783        .start                  = ath5k_start,
 784        .stop                   = ath5k_stop,
 785        .add_interface          = ath5k_add_interface,
 786        /* .change_interface    = not implemented */
 787        .remove_interface       = ath5k_remove_interface,
 788        .config                 = ath5k_config,
 789        .bss_info_changed       = ath5k_bss_info_changed,
 790        .prepare_multicast      = ath5k_prepare_multicast,
 791        .configure_filter       = ath5k_configure_filter,
 792        /* .set_tim             = not implemented */
 793        .set_key                = ath5k_set_key,
 794        /* .update_tkip_key     = not implemented */
 795        /* .hw_scan             = not implemented */
 796        .sw_scan_start          = ath5k_sw_scan_start,
 797        .sw_scan_complete       = ath5k_sw_scan_complete,
 798        .get_stats              = ath5k_get_stats,
 799        /* .set_frag_threshold  = not implemented */
 800        /* .set_rts_threshold   = not implemented */
 801        /* .sta_add             = not implemented */
 802        /* .sta_remove          = not implemented */
 803        /* .sta_notify          = not implemented */
 804        .conf_tx                = ath5k_conf_tx,
 805        .get_tsf                = ath5k_get_tsf,
 806        .set_tsf                = ath5k_set_tsf,
 807        .reset_tsf              = ath5k_reset_tsf,
 808        /* .tx_last_beacon      = not implemented */
 809        /* .ampdu_action        = not needed */
 810        .get_survey             = ath5k_get_survey,
 811        .set_coverage_class     = ath5k_set_coverage_class,
 812        /* .rfkill_poll         = not implemented */
 813        /* .flush               = not implemented */
 814        /* .channel_switch      = not implemented */
 815        /* .napi_poll           = not implemented */
 816        .set_antenna            = ath5k_set_antenna,
 817        .get_antenna            = ath5k_get_antenna,
 818        .set_ringparam          = ath5k_set_ringparam,
 819        .get_ringparam          = ath5k_get_ringparam,
 820};
 821