linux/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2010-2011 Atheros Communications Inc.
   3 *
   4 * Permission to use, copy, modify, and/or distribute this software for any
   5 * purpose with or without fee is hereby granted, provided that the above
   6 * copyright notice and this permission notice appear in all copies.
   7 *
   8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
   9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  15 */
  16
  17#include "htc.h"
  18
  19#define FUDGE 2
  20
  21void ath9k_htc_beaconq_config(struct ath9k_htc_priv *priv)
  22{
  23        struct ath_hw *ah = priv->ah;
  24        struct ath9k_tx_queue_info qi, qi_be;
  25
  26        memset(&qi, 0, sizeof(struct ath9k_tx_queue_info));
  27        memset(&qi_be, 0, sizeof(struct ath9k_tx_queue_info));
  28
  29        ath9k_hw_get_txq_props(ah, priv->beaconq, &qi);
  30
  31        if (priv->ah->opmode == NL80211_IFTYPE_AP ||
  32            priv->ah->opmode == NL80211_IFTYPE_MESH_POINT) {
  33                qi.tqi_aifs = 1;
  34                qi.tqi_cwmin = 0;
  35                qi.tqi_cwmax = 0;
  36        } else if (priv->ah->opmode == NL80211_IFTYPE_ADHOC) {
  37                int qnum = priv->hwq_map[IEEE80211_AC_BE];
  38
  39                ath9k_hw_get_txq_props(ah, qnum, &qi_be);
  40
  41                qi.tqi_aifs = qi_be.tqi_aifs;
  42
  43                /*
  44                 * For WIFI Beacon Distribution
  45                 * Long slot time  : 2x cwmin
  46                 * Short slot time : 4x cwmin
  47                 */
  48                if (ah->slottime == ATH9K_SLOT_TIME_20)
  49                        qi.tqi_cwmin = 2*qi_be.tqi_cwmin;
  50                else
  51                        qi.tqi_cwmin = 4*qi_be.tqi_cwmin;
  52
  53                qi.tqi_cwmax = qi_be.tqi_cwmax;
  54
  55        }
  56
  57        if (!ath9k_hw_set_txq_props(ah, priv->beaconq, &qi)) {
  58                ath_err(ath9k_hw_common(ah),
  59                        "Unable to update beacon queue %u!\n", priv->beaconq);
  60        } else {
  61                ath9k_hw_resettxqueue(ah, priv->beaconq);
  62        }
  63}
  64
  65
  66static void ath9k_htc_beacon_config_sta(struct ath9k_htc_priv *priv,
  67                                        struct htc_beacon_config *bss_conf)
  68{
  69        struct ath_common *common = ath9k_hw_common(priv->ah);
  70        struct ath9k_beacon_state bs;
  71        enum ath9k_int imask = 0;
  72        int dtimperiod, dtimcount, sleepduration;
  73        int cfpperiod, cfpcount, bmiss_timeout;
  74        u32 nexttbtt = 0, intval, tsftu;
  75        __be32 htc_imask = 0;
  76        u64 tsf;
  77        int num_beacons, offset, dtim_dec_count, cfp_dec_count;
  78        int ret __attribute__ ((unused));
  79        u8 cmd_rsp;
  80
  81        memset(&bs, 0, sizeof(bs));
  82
  83        intval = bss_conf->beacon_interval;
  84        bmiss_timeout = (ATH_DEFAULT_BMISS_LIMIT * bss_conf->beacon_interval);
  85
  86        /*
  87         * Setup dtim and cfp parameters according to
  88         * last beacon we received (which may be none).
  89         */
  90        dtimperiod = bss_conf->dtim_period;
  91        if (dtimperiod <= 0)            /* NB: 0 if not known */
  92                dtimperiod = 1;
  93        dtimcount = 1;
  94        if (dtimcount >= dtimperiod)    /* NB: sanity check */
  95                dtimcount = 0;
  96        cfpperiod = 1;                  /* NB: no PCF support yet */
  97        cfpcount = 0;
  98
  99        sleepduration = intval;
 100        if (sleepduration <= 0)
 101                sleepduration = intval;
 102
 103        /*
 104         * Pull nexttbtt forward to reflect the current
 105         * TSF and calculate dtim+cfp state for the result.
 106         */
 107        tsf = ath9k_hw_gettsf64(priv->ah);
 108        tsftu = TSF_TO_TU(tsf>>32, tsf) + FUDGE;
 109
 110        num_beacons = tsftu / intval + 1;
 111        offset = tsftu % intval;
 112        nexttbtt = tsftu - offset;
 113        if (offset)
 114                nexttbtt += intval;
 115
 116        /* DTIM Beacon every dtimperiod Beacon */
 117        dtim_dec_count = num_beacons % dtimperiod;
 118        /* CFP every cfpperiod DTIM Beacon */
 119        cfp_dec_count = (num_beacons / dtimperiod) % cfpperiod;
 120        if (dtim_dec_count)
 121                cfp_dec_count++;
 122
 123        dtimcount -= dtim_dec_count;
 124        if (dtimcount < 0)
 125                dtimcount += dtimperiod;
 126
 127        cfpcount -= cfp_dec_count;
 128        if (cfpcount < 0)
 129                cfpcount += cfpperiod;
 130
 131        bs.bs_intval = intval;
 132        bs.bs_nexttbtt = nexttbtt;
 133        bs.bs_dtimperiod = dtimperiod*intval;
 134        bs.bs_nextdtim = bs.bs_nexttbtt + dtimcount*intval;
 135        bs.bs_cfpperiod = cfpperiod*bs.bs_dtimperiod;
 136        bs.bs_cfpnext = bs.bs_nextdtim + cfpcount*bs.bs_dtimperiod;
 137        bs.bs_cfpmaxduration = 0;
 138
 139        /*
 140         * Calculate the number of consecutive beacons to miss* before taking
 141         * a BMISS interrupt. The configuration is specified in TU so we only
 142         * need calculate based on the beacon interval.  Note that we clamp the
 143         * result to at most 15 beacons.
 144         */
 145        if (sleepduration > intval) {
 146                bs.bs_bmissthreshold = ATH_DEFAULT_BMISS_LIMIT / 2;
 147        } else {
 148                bs.bs_bmissthreshold = DIV_ROUND_UP(bmiss_timeout, intval);
 149                if (bs.bs_bmissthreshold > 15)
 150                        bs.bs_bmissthreshold = 15;
 151                else if (bs.bs_bmissthreshold <= 0)
 152                        bs.bs_bmissthreshold = 1;
 153        }
 154
 155        /*
 156         * Calculate sleep duration. The configuration is given in ms.
 157         * We ensure a multiple of the beacon period is used. Also, if the sleep
 158         * duration is greater than the DTIM period then it makes senses
 159         * to make it a multiple of that.
 160         *
 161         * XXX fixed at 100ms
 162         */
 163
 164        bs.bs_sleepduration = roundup(IEEE80211_MS_TO_TU(100), sleepduration);
 165        if (bs.bs_sleepduration > bs.bs_dtimperiod)
 166                bs.bs_sleepduration = bs.bs_dtimperiod;
 167
 168        /* TSF out of range threshold fixed at 1 second */
 169        bs.bs_tsfoor_threshold = ATH9K_TSFOOR_THRESHOLD;
 170
 171        ath_dbg(common, CONFIG, "intval: %u tsf: %llu tsftu: %u\n",
 172                intval, tsf, tsftu);
 173        ath_dbg(common, CONFIG,
 174                "bmiss: %u sleep: %u cfp-period: %u maxdur: %u next: %u\n",
 175                bs.bs_bmissthreshold, bs.bs_sleepduration,
 176                bs.bs_cfpperiod, bs.bs_cfpmaxduration, bs.bs_cfpnext);
 177
 178        /* Set the computed STA beacon timers */
 179
 180        WMI_CMD(WMI_DISABLE_INTR_CMDID);
 181        ath9k_hw_set_sta_beacon_timers(priv->ah, &bs);
 182        imask |= ATH9K_INT_BMISS;
 183        htc_imask = cpu_to_be32(imask);
 184        WMI_CMD_BUF(WMI_ENABLE_INTR_CMDID, &htc_imask);
 185}
 186
 187static void ath9k_htc_beacon_config_ap(struct ath9k_htc_priv *priv,
 188                                       struct htc_beacon_config *bss_conf)
 189{
 190        struct ath_common *common = ath9k_hw_common(priv->ah);
 191        enum ath9k_int imask = 0;
 192        u32 nexttbtt, intval, tsftu;
 193        __be32 htc_imask = 0;
 194        int ret __attribute__ ((unused));
 195        u8 cmd_rsp;
 196        u64 tsf;
 197
 198        intval = bss_conf->beacon_interval;
 199        intval /= ATH9K_HTC_MAX_BCN_VIF;
 200        nexttbtt = intval;
 201
 202        /*
 203         * To reduce beacon misses under heavy TX load,
 204         * set the beacon response time to a larger value.
 205         */
 206        if (intval > DEFAULT_SWBA_RESPONSE)
 207                priv->ah->config.sw_beacon_response_time = DEFAULT_SWBA_RESPONSE;
 208        else
 209                priv->ah->config.sw_beacon_response_time = MIN_SWBA_RESPONSE;
 210
 211        if (test_bit(OP_TSF_RESET, &priv->op_flags)) {
 212                ath9k_hw_reset_tsf(priv->ah);
 213                clear_bit(OP_TSF_RESET, &priv->op_flags);
 214        } else {
 215                /*
 216                 * Pull nexttbtt forward to reflect the current TSF.
 217                 */
 218                tsf = ath9k_hw_gettsf64(priv->ah);
 219                tsftu = TSF_TO_TU(tsf >> 32, tsf) + FUDGE;
 220                do {
 221                        nexttbtt += intval;
 222                } while (nexttbtt < tsftu);
 223        }
 224
 225        if (test_bit(OP_ENABLE_BEACON, &priv->op_flags))
 226                imask |= ATH9K_INT_SWBA;
 227
 228        ath_dbg(common, CONFIG,
 229                "AP Beacon config, intval: %d, nexttbtt: %u, resp_time: %d imask: 0x%x\n",
 230                bss_conf->beacon_interval, nexttbtt,
 231                priv->ah->config.sw_beacon_response_time, imask);
 232
 233        ath9k_htc_beaconq_config(priv);
 234
 235        WMI_CMD(WMI_DISABLE_INTR_CMDID);
 236        ath9k_hw_beaconinit(priv->ah, TU_TO_USEC(nexttbtt), TU_TO_USEC(intval));
 237        priv->cur_beacon_conf.bmiss_cnt = 0;
 238        htc_imask = cpu_to_be32(imask);
 239        WMI_CMD_BUF(WMI_ENABLE_INTR_CMDID, &htc_imask);
 240}
 241
 242static void ath9k_htc_beacon_config_adhoc(struct ath9k_htc_priv *priv,
 243                                          struct htc_beacon_config *bss_conf)
 244{
 245        struct ath_common *common = ath9k_hw_common(priv->ah);
 246        enum ath9k_int imask = 0;
 247        u32 nexttbtt, intval, tsftu;
 248        __be32 htc_imask = 0;
 249        int ret __attribute__ ((unused));
 250        u8 cmd_rsp;
 251        u64 tsf;
 252
 253        intval = bss_conf->beacon_interval;
 254        nexttbtt = intval;
 255
 256        /*
 257         * Pull nexttbtt forward to reflect the current TSF.
 258         */
 259        tsf = ath9k_hw_gettsf64(priv->ah);
 260        tsftu = TSF_TO_TU(tsf >> 32, tsf) + FUDGE;
 261        do {
 262                nexttbtt += intval;
 263        } while (nexttbtt < tsftu);
 264
 265        /*
 266         * Only one IBSS interfce is allowed.
 267         */
 268        if (intval > DEFAULT_SWBA_RESPONSE)
 269                priv->ah->config.sw_beacon_response_time = DEFAULT_SWBA_RESPONSE;
 270        else
 271                priv->ah->config.sw_beacon_response_time = MIN_SWBA_RESPONSE;
 272
 273        if (test_bit(OP_ENABLE_BEACON, &priv->op_flags))
 274                imask |= ATH9K_INT_SWBA;
 275
 276        ath_dbg(common, CONFIG,
 277                "IBSS Beacon config, intval: %d, nexttbtt: %u, resp_time: %d, imask: 0x%x\n",
 278                bss_conf->beacon_interval, nexttbtt,
 279                priv->ah->config.sw_beacon_response_time, imask);
 280
 281        WMI_CMD(WMI_DISABLE_INTR_CMDID);
 282        ath9k_hw_beaconinit(priv->ah, TU_TO_USEC(nexttbtt), TU_TO_USEC(intval));
 283        priv->cur_beacon_conf.bmiss_cnt = 0;
 284        htc_imask = cpu_to_be32(imask);
 285        WMI_CMD_BUF(WMI_ENABLE_INTR_CMDID, &htc_imask);
 286}
 287
 288void ath9k_htc_beaconep(void *drv_priv, struct sk_buff *skb,
 289                        enum htc_endpoint_id ep_id, bool txok)
 290{
 291        dev_kfree_skb_any(skb);
 292}
 293
 294static void ath9k_htc_send_buffered(struct ath9k_htc_priv *priv,
 295                                    int slot)
 296{
 297        struct ath_common *common = ath9k_hw_common(priv->ah);
 298        struct ieee80211_vif *vif;
 299        struct sk_buff *skb;
 300        struct ieee80211_hdr *hdr;
 301        int padpos, padsize, ret, tx_slot;
 302
 303        spin_lock_bh(&priv->beacon_lock);
 304
 305        vif = priv->cur_beacon_conf.bslot[slot];
 306
 307        skb = ieee80211_get_buffered_bc(priv->hw, vif);
 308
 309        while(skb) {
 310                hdr = (struct ieee80211_hdr *) skb->data;
 311
 312                padpos = ieee80211_hdrlen(hdr->frame_control);
 313                padsize = padpos & 3;
 314                if (padsize && skb->len > padpos) {
 315                        if (skb_headroom(skb) < padsize) {
 316                                dev_kfree_skb_any(skb);
 317                                goto next;
 318                        }
 319                        skb_push(skb, padsize);
 320                        memmove(skb->data, skb->data + padsize, padpos);
 321                }
 322
 323                tx_slot = ath9k_htc_tx_get_slot(priv);
 324                if (tx_slot < 0) {
 325                        ath_dbg(common, XMIT, "No free CAB slot\n");
 326                        dev_kfree_skb_any(skb);
 327                        goto next;
 328                }
 329
 330                ret = ath9k_htc_tx_start(priv, NULL, skb, tx_slot, true);
 331                if (ret != 0) {
 332                        ath9k_htc_tx_clear_slot(priv, tx_slot);
 333                        dev_kfree_skb_any(skb);
 334
 335                        ath_dbg(common, XMIT, "Failed to send CAB frame\n");
 336                } else {
 337                        spin_lock_bh(&priv->tx.tx_lock);
 338                        priv->tx.queued_cnt++;
 339                        spin_unlock_bh(&priv->tx.tx_lock);
 340                }
 341        next:
 342                skb = ieee80211_get_buffered_bc(priv->hw, vif);
 343        }
 344
 345        spin_unlock_bh(&priv->beacon_lock);
 346}
 347
 348static void ath9k_htc_send_beacon(struct ath9k_htc_priv *priv,
 349                                  int slot)
 350{
 351        struct ath_common *common = ath9k_hw_common(priv->ah);
 352        struct ieee80211_vif *vif;
 353        struct ath9k_htc_vif *avp;
 354        struct tx_beacon_header beacon_hdr;
 355        struct ath9k_htc_tx_ctl *tx_ctl;
 356        struct ieee80211_tx_info *info;
 357        struct ieee80211_mgmt *mgmt;
 358        struct sk_buff *beacon;
 359        u8 *tx_fhdr;
 360        int ret;
 361
 362        memset(&beacon_hdr, 0, sizeof(struct tx_beacon_header));
 363
 364        spin_lock_bh(&priv->beacon_lock);
 365
 366        vif = priv->cur_beacon_conf.bslot[slot];
 367        avp = (struct ath9k_htc_vif *)vif->drv_priv;
 368
 369        if (unlikely(test_bit(OP_SCANNING, &priv->op_flags))) {
 370                spin_unlock_bh(&priv->beacon_lock);
 371                return;
 372        }
 373
 374        /* Get a new beacon */
 375        beacon = ieee80211_beacon_get(priv->hw, vif);
 376        if (!beacon) {
 377                spin_unlock_bh(&priv->beacon_lock);
 378                return;
 379        }
 380
 381        /*
 382         * Update the TSF adjust value here, the HW will
 383         * add this value for every beacon.
 384         */
 385        mgmt = (struct ieee80211_mgmt *)beacon->data;
 386        mgmt->u.beacon.timestamp = avp->tsfadjust;
 387
 388        info = IEEE80211_SKB_CB(beacon);
 389        if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
 390                struct ieee80211_hdr *hdr =
 391                        (struct ieee80211_hdr *) beacon->data;
 392                avp->seq_no += 0x10;
 393                hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
 394                hdr->seq_ctrl |= cpu_to_le16(avp->seq_no);
 395        }
 396
 397        tx_ctl = HTC_SKB_CB(beacon);
 398        memset(tx_ctl, 0, sizeof(*tx_ctl));
 399
 400        tx_ctl->type = ATH9K_HTC_BEACON;
 401        tx_ctl->epid = priv->beacon_ep;
 402
 403        beacon_hdr.vif_index = avp->index;
 404        tx_fhdr = skb_push(beacon, sizeof(beacon_hdr));
 405        memcpy(tx_fhdr, (u8 *) &beacon_hdr, sizeof(beacon_hdr));
 406
 407        ret = htc_send(priv->htc, beacon);
 408        if (ret != 0) {
 409                if (ret == -ENOMEM) {
 410                        ath_dbg(common, BSTUCK,
 411                                "Failed to send beacon, no free TX buffer\n");
 412                }
 413                dev_kfree_skb_any(beacon);
 414        }
 415
 416        spin_unlock_bh(&priv->beacon_lock);
 417}
 418
 419static int ath9k_htc_choose_bslot(struct ath9k_htc_priv *priv,
 420                                  struct wmi_event_swba *swba)
 421{
 422        struct ath_common *common = ath9k_hw_common(priv->ah);
 423        u64 tsf;
 424        u32 tsftu;
 425        u16 intval;
 426        int slot;
 427
 428        intval = priv->cur_beacon_conf.beacon_interval;
 429
 430        tsf = be64_to_cpu(swba->tsf);
 431        tsftu = TSF_TO_TU(tsf >> 32, tsf);
 432        slot = ((tsftu % intval) * ATH9K_HTC_MAX_BCN_VIF) / intval;
 433        slot = ATH9K_HTC_MAX_BCN_VIF - slot - 1;
 434
 435        ath_dbg(common, BEACON,
 436                "Choose slot: %d, tsf: %llu, tsftu: %u, intval: %u\n",
 437                slot, tsf, tsftu, intval);
 438
 439        return slot;
 440}
 441
 442void ath9k_htc_swba(struct ath9k_htc_priv *priv,
 443                    struct wmi_event_swba *swba)
 444{
 445        struct ath_common *common = ath9k_hw_common(priv->ah);
 446        int slot;
 447
 448        if (swba->beacon_pending != 0) {
 449                priv->cur_beacon_conf.bmiss_cnt++;
 450                if (priv->cur_beacon_conf.bmiss_cnt > BSTUCK_THRESHOLD) {
 451                        ath_dbg(common, BSTUCK, "Beacon stuck, HW reset\n");
 452                        ieee80211_queue_work(priv->hw,
 453                                             &priv->fatal_work);
 454                }
 455                return;
 456        }
 457
 458        if (priv->cur_beacon_conf.bmiss_cnt) {
 459                ath_dbg(common, BSTUCK,
 460                        "Resuming beacon xmit after %u misses\n",
 461                        priv->cur_beacon_conf.bmiss_cnt);
 462                priv->cur_beacon_conf.bmiss_cnt = 0;
 463        }
 464
 465        slot = ath9k_htc_choose_bslot(priv, swba);
 466        spin_lock_bh(&priv->beacon_lock);
 467        if (priv->cur_beacon_conf.bslot[slot] == NULL) {
 468                spin_unlock_bh(&priv->beacon_lock);
 469                return;
 470        }
 471        spin_unlock_bh(&priv->beacon_lock);
 472
 473        ath9k_htc_send_buffered(priv, slot);
 474        ath9k_htc_send_beacon(priv, slot);
 475}
 476
 477void ath9k_htc_assign_bslot(struct ath9k_htc_priv *priv,
 478                            struct ieee80211_vif *vif)
 479{
 480        struct ath_common *common = ath9k_hw_common(priv->ah);
 481        struct ath9k_htc_vif *avp = (struct ath9k_htc_vif *)vif->drv_priv;
 482        int i = 0;
 483
 484        spin_lock_bh(&priv->beacon_lock);
 485        for (i = 0; i < ATH9K_HTC_MAX_BCN_VIF; i++) {
 486                if (priv->cur_beacon_conf.bslot[i] == NULL) {
 487                        avp->bslot = i;
 488                        break;
 489                }
 490        }
 491
 492        priv->cur_beacon_conf.bslot[avp->bslot] = vif;
 493        spin_unlock_bh(&priv->beacon_lock);
 494
 495        ath_dbg(common, CONFIG, "Added interface at beacon slot: %d\n",
 496                avp->bslot);
 497}
 498
 499void ath9k_htc_remove_bslot(struct ath9k_htc_priv *priv,
 500                            struct ieee80211_vif *vif)
 501{
 502        struct ath_common *common = ath9k_hw_common(priv->ah);
 503        struct ath9k_htc_vif *avp = (struct ath9k_htc_vif *)vif->drv_priv;
 504
 505        spin_lock_bh(&priv->beacon_lock);
 506        priv->cur_beacon_conf.bslot[avp->bslot] = NULL;
 507        spin_unlock_bh(&priv->beacon_lock);
 508
 509        ath_dbg(common, CONFIG, "Removed interface at beacon slot: %d\n",
 510                avp->bslot);
 511}
 512
 513/*
 514 * Calculate the TSF adjustment value for all slots
 515 * other than zero.
 516 */
 517void ath9k_htc_set_tsfadjust(struct ath9k_htc_priv *priv,
 518                             struct ieee80211_vif *vif)
 519{
 520        struct ath_common *common = ath9k_hw_common(priv->ah);
 521        struct ath9k_htc_vif *avp = (struct ath9k_htc_vif *)vif->drv_priv;
 522        struct htc_beacon_config *cur_conf = &priv->cur_beacon_conf;
 523        u64 tsfadjust;
 524
 525        if (avp->bslot == 0)
 526                return;
 527
 528        /*
 529         * The beacon interval cannot be different for multi-AP mode,
 530         * and we reach here only for VIF slots greater than zero,
 531         * so beacon_interval is guaranteed to be set in cur_conf.
 532         */
 533        tsfadjust = cur_conf->beacon_interval * avp->bslot / ATH9K_HTC_MAX_BCN_VIF;
 534        avp->tsfadjust = cpu_to_le64(TU_TO_USEC(tsfadjust));
 535
 536        ath_dbg(common, CONFIG, "tsfadjust is: %llu for bslot: %d\n",
 537                (unsigned long long)tsfadjust, avp->bslot);
 538}
 539
 540static void ath9k_htc_beacon_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
 541{
 542        bool *beacon_configured = (bool *)data;
 543        struct ath9k_htc_vif *avp = (struct ath9k_htc_vif *) vif->drv_priv;
 544
 545        if (vif->type == NL80211_IFTYPE_STATION &&
 546            avp->beacon_configured)
 547                *beacon_configured = true;
 548}
 549
 550static bool ath9k_htc_check_beacon_config(struct ath9k_htc_priv *priv,
 551                                          struct ieee80211_vif *vif)
 552{
 553        struct ath_common *common = ath9k_hw_common(priv->ah);
 554        struct htc_beacon_config *cur_conf = &priv->cur_beacon_conf;
 555        struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
 556        bool beacon_configured;
 557
 558        /*
 559         * Changing the beacon interval when multiple AP interfaces
 560         * are configured will affect beacon transmission of all
 561         * of them.
 562         */
 563        if ((priv->ah->opmode == NL80211_IFTYPE_AP) &&
 564            (priv->num_ap_vif > 1) &&
 565            (vif->type == NL80211_IFTYPE_AP) &&
 566            (cur_conf->beacon_interval != bss_conf->beacon_int)) {
 567                ath_dbg(common, CONFIG,
 568                        "Changing beacon interval of multiple AP interfaces !\n");
 569                return false;
 570        }
 571
 572        /*
 573         * If the HW is operating in AP mode, any new station interfaces that
 574         * are added cannot change the beacon parameters.
 575         */
 576        if (priv->num_ap_vif &&
 577            (vif->type != NL80211_IFTYPE_AP)) {
 578                ath_dbg(common, CONFIG,
 579                        "HW in AP mode, cannot set STA beacon parameters\n");
 580                return false;
 581        }
 582
 583        /*
 584         * The beacon parameters are configured only for the first
 585         * station interface.
 586         */
 587        if ((priv->ah->opmode == NL80211_IFTYPE_STATION) &&
 588            (priv->num_sta_vif > 1) &&
 589            (vif->type == NL80211_IFTYPE_STATION)) {
 590                beacon_configured = false;
 591                ieee80211_iterate_active_interfaces_atomic(
 592                        priv->hw, IEEE80211_IFACE_ITER_RESUME_ALL,
 593                        ath9k_htc_beacon_iter, &beacon_configured);
 594
 595                if (beacon_configured) {
 596                        ath_dbg(common, CONFIG,
 597                                "Beacon already configured for a station interface\n");
 598                        return false;
 599                }
 600        }
 601
 602        return true;
 603}
 604
 605void ath9k_htc_beacon_config(struct ath9k_htc_priv *priv,
 606                             struct ieee80211_vif *vif)
 607{
 608        struct ath_common *common = ath9k_hw_common(priv->ah);
 609        struct htc_beacon_config *cur_conf = &priv->cur_beacon_conf;
 610        struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
 611        struct ath9k_htc_vif *avp = (struct ath9k_htc_vif *) vif->drv_priv;
 612
 613        if (!ath9k_htc_check_beacon_config(priv, vif))
 614                return;
 615
 616        cur_conf->beacon_interval = bss_conf->beacon_int;
 617        if (cur_conf->beacon_interval == 0)
 618                cur_conf->beacon_interval = 100;
 619
 620        cur_conf->dtim_period = bss_conf->dtim_period;
 621        cur_conf->bmiss_timeout =
 622                ATH_DEFAULT_BMISS_LIMIT * cur_conf->beacon_interval;
 623
 624        switch (vif->type) {
 625        case NL80211_IFTYPE_STATION:
 626                ath9k_htc_beacon_config_sta(priv, cur_conf);
 627                avp->beacon_configured = true;
 628                break;
 629        case NL80211_IFTYPE_ADHOC:
 630                ath9k_htc_beacon_config_adhoc(priv, cur_conf);
 631                break;
 632        case NL80211_IFTYPE_MESH_POINT:
 633        case NL80211_IFTYPE_AP:
 634                ath9k_htc_beacon_config_ap(priv, cur_conf);
 635                break;
 636        default:
 637                ath_dbg(common, CONFIG, "Unsupported beaconing mode\n");
 638                return;
 639        }
 640}
 641
 642void ath9k_htc_beacon_reconfig(struct ath9k_htc_priv *priv)
 643{
 644        struct ath_common *common = ath9k_hw_common(priv->ah);
 645        struct htc_beacon_config *cur_conf = &priv->cur_beacon_conf;
 646
 647        switch (priv->ah->opmode) {
 648        case NL80211_IFTYPE_STATION:
 649                ath9k_htc_beacon_config_sta(priv, cur_conf);
 650                break;
 651        case NL80211_IFTYPE_ADHOC:
 652                ath9k_htc_beacon_config_adhoc(priv, cur_conf);
 653                break;
 654        case NL80211_IFTYPE_MESH_POINT:
 655        case NL80211_IFTYPE_AP:
 656                ath9k_htc_beacon_config_ap(priv, cur_conf);
 657                break;
 658        default:
 659                ath_dbg(common, CONFIG, "Unsupported beaconing mode\n");
 660                return;
 661        }
 662}
 663