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