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