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