Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright (c) 2010-2011 Atheros Communications Inc.
0003  *
0004  * Permission to use, copy, modify, and/or distribute this software for any
0005  * purpose with or without fee is hereby granted, provided that the above
0006  * copyright notice and this permission notice appear in all copies.
0007  *
0008  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
0009  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
0010  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
0011  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
0012  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
0013  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
0014  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
0015  */
0016 
0017 #include "htc.h"
0018 
0019 #define FUDGE 2
0020 
0021 void ath9k_htc_beaconq_config(struct ath9k_htc_priv *priv)
0022 {
0023     struct ath_hw *ah = priv->ah;
0024     struct ath9k_tx_queue_info qi, qi_be;
0025 
0026     memset(&qi, 0, sizeof(struct ath9k_tx_queue_info));
0027     memset(&qi_be, 0, sizeof(struct ath9k_tx_queue_info));
0028 
0029     ath9k_hw_get_txq_props(ah, priv->beacon.beaconq, &qi);
0030 
0031     if (priv->ah->opmode == NL80211_IFTYPE_AP ||
0032         priv->ah->opmode == NL80211_IFTYPE_MESH_POINT) {
0033         qi.tqi_aifs = 1;
0034         qi.tqi_cwmin = 0;
0035         qi.tqi_cwmax = 0;
0036     } else if (priv->ah->opmode == NL80211_IFTYPE_ADHOC) {
0037         int qnum = priv->hwq_map[IEEE80211_AC_BE];
0038 
0039         ath9k_hw_get_txq_props(ah, qnum, &qi_be);
0040 
0041         qi.tqi_aifs = qi_be.tqi_aifs;
0042 
0043         /*
0044          * For WIFI Beacon Distribution
0045          * Long slot time  : 2x cwmin
0046          * Short slot time : 4x cwmin
0047          */
0048         if (ah->slottime == 20)
0049             qi.tqi_cwmin = 2*qi_be.tqi_cwmin;
0050         else
0051             qi.tqi_cwmin = 4*qi_be.tqi_cwmin;
0052 
0053         qi.tqi_cwmax = qi_be.tqi_cwmax;
0054 
0055     }
0056 
0057     if (!ath9k_hw_set_txq_props(ah, priv->beacon.beaconq, &qi)) {
0058         ath_err(ath9k_hw_common(ah),
0059             "Unable to update beacon queue %u!\n", priv->beacon.beaconq);
0060     } else {
0061         ath9k_hw_resettxqueue(ah, priv->beacon.beaconq);
0062     }
0063 }
0064 
0065 /*
0066  * Both nexttbtt and intval have to be in usecs.
0067  */
0068 static void ath9k_htc_beacon_init(struct ath9k_htc_priv *priv,
0069                   struct ath_beacon_config *conf,
0070                   bool reset_tsf)
0071 {
0072     struct ath_hw *ah = priv->ah;
0073     int ret __attribute__ ((unused));
0074     __be32 htc_imask = 0;
0075     u8 cmd_rsp;
0076 
0077     if (conf->intval >= TU_TO_USEC(DEFAULT_SWBA_RESPONSE))
0078         ah->config.sw_beacon_response_time = DEFAULT_SWBA_RESPONSE;
0079     else
0080         ah->config.sw_beacon_response_time = MIN_SWBA_RESPONSE;
0081 
0082     WMI_CMD(WMI_DISABLE_INTR_CMDID);
0083     if (reset_tsf)
0084         ath9k_hw_reset_tsf(ah);
0085     ath9k_htc_beaconq_config(priv);
0086     ath9k_hw_beaconinit(ah, conf->nexttbtt, conf->intval);
0087     priv->beacon.bmisscnt = 0;
0088     htc_imask = cpu_to_be32(ah->imask);
0089     WMI_CMD_BUF(WMI_ENABLE_INTR_CMDID, &htc_imask);
0090 }
0091 
0092 static void ath9k_htc_beacon_config_sta(struct ath9k_htc_priv *priv,
0093                     struct ath_beacon_config *bss_conf)
0094 {
0095     struct ath9k_beacon_state bs;
0096     enum ath9k_int imask = 0;
0097     __be32 htc_imask = 0;
0098     int ret __attribute__ ((unused));
0099     u8 cmd_rsp;
0100 
0101     if (ath9k_cmn_beacon_config_sta(priv->ah, bss_conf, &bs) == -EPERM)
0102         return;
0103 
0104     WMI_CMD(WMI_DISABLE_INTR_CMDID);
0105     ath9k_hw_set_sta_beacon_timers(priv->ah, &bs);
0106     imask |= ATH9K_INT_BMISS;
0107     htc_imask = cpu_to_be32(imask);
0108     WMI_CMD_BUF(WMI_ENABLE_INTR_CMDID, &htc_imask);
0109 }
0110 
0111 static void ath9k_htc_beacon_config_ap(struct ath9k_htc_priv *priv,
0112                        struct ath_beacon_config *conf)
0113 {
0114     struct ath_hw *ah = priv->ah;
0115     ah->imask = 0;
0116 
0117     ath9k_cmn_beacon_config_ap(ah, conf, ATH9K_HTC_MAX_BCN_VIF);
0118     ath9k_htc_beacon_init(priv, conf, false);
0119 }
0120 
0121 static void ath9k_htc_beacon_config_adhoc(struct ath9k_htc_priv *priv,
0122                       struct ath_beacon_config *conf)
0123 {
0124     struct ath_hw *ah = priv->ah;
0125     ah->imask = 0;
0126 
0127     ath9k_cmn_beacon_config_adhoc(ah, conf);
0128     ath9k_htc_beacon_init(priv, conf, conf->ibss_creator);
0129 }
0130 
0131 void ath9k_htc_beaconep(void *drv_priv, struct sk_buff *skb,
0132             enum htc_endpoint_id ep_id, bool txok)
0133 {
0134     dev_kfree_skb_any(skb);
0135 }
0136 
0137 static void ath9k_htc_send_buffered(struct ath9k_htc_priv *priv,
0138                     int slot)
0139 {
0140     struct ath_common *common = ath9k_hw_common(priv->ah);
0141     struct ieee80211_vif *vif;
0142     struct sk_buff *skb;
0143     struct ieee80211_hdr *hdr;
0144     int padpos, padsize, ret, tx_slot;
0145 
0146     spin_lock_bh(&priv->beacon_lock);
0147 
0148     vif = priv->beacon.bslot[slot];
0149 
0150     skb = ieee80211_get_buffered_bc(priv->hw, vif);
0151 
0152     while(skb) {
0153         hdr = (struct ieee80211_hdr *) skb->data;
0154 
0155         padpos = ieee80211_hdrlen(hdr->frame_control);
0156         padsize = padpos & 3;
0157         if (padsize && skb->len > padpos) {
0158             if (skb_headroom(skb) < padsize) {
0159                 dev_kfree_skb_any(skb);
0160                 goto next;
0161             }
0162             skb_push(skb, padsize);
0163             memmove(skb->data, skb->data + padsize, padpos);
0164         }
0165 
0166         tx_slot = ath9k_htc_tx_get_slot(priv);
0167         if (tx_slot < 0) {
0168             ath_dbg(common, XMIT, "No free CAB slot\n");
0169             dev_kfree_skb_any(skb);
0170             goto next;
0171         }
0172 
0173         ret = ath9k_htc_tx_start(priv, NULL, skb, tx_slot, true);
0174         if (ret != 0) {
0175             ath9k_htc_tx_clear_slot(priv, tx_slot);
0176             dev_kfree_skb_any(skb);
0177 
0178             ath_dbg(common, XMIT, "Failed to send CAB frame\n");
0179         } else {
0180             spin_lock_bh(&priv->tx.tx_lock);
0181             priv->tx.queued_cnt++;
0182             spin_unlock_bh(&priv->tx.tx_lock);
0183         }
0184     next:
0185         skb = ieee80211_get_buffered_bc(priv->hw, vif);
0186     }
0187 
0188     spin_unlock_bh(&priv->beacon_lock);
0189 }
0190 
0191 static void ath9k_htc_send_beacon(struct ath9k_htc_priv *priv,
0192                   int slot)
0193 {
0194     struct ath_common *common = ath9k_hw_common(priv->ah);
0195     struct ieee80211_vif *vif;
0196     struct ath9k_htc_vif *avp;
0197     struct tx_beacon_header beacon_hdr;
0198     struct ath9k_htc_tx_ctl *tx_ctl;
0199     struct ieee80211_tx_info *info;
0200     struct ieee80211_mgmt *mgmt;
0201     struct sk_buff *beacon;
0202     u8 *tx_fhdr;
0203     int ret;
0204 
0205     memset(&beacon_hdr, 0, sizeof(struct tx_beacon_header));
0206 
0207     spin_lock_bh(&priv->beacon_lock);
0208 
0209     vif = priv->beacon.bslot[slot];
0210     avp = (struct ath9k_htc_vif *)vif->drv_priv;
0211 
0212     if (unlikely(test_bit(ATH_OP_SCANNING, &common->op_flags))) {
0213         spin_unlock_bh(&priv->beacon_lock);
0214         return;
0215     }
0216 
0217     /* Get a new beacon */
0218     beacon = ieee80211_beacon_get(priv->hw, vif, 0);
0219     if (!beacon) {
0220         spin_unlock_bh(&priv->beacon_lock);
0221         return;
0222     }
0223 
0224     /*
0225      * Update the TSF adjust value here, the HW will
0226      * add this value for every beacon.
0227      */
0228     mgmt = (struct ieee80211_mgmt *)beacon->data;
0229     mgmt->u.beacon.timestamp = avp->tsfadjust;
0230 
0231     info = IEEE80211_SKB_CB(beacon);
0232     if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
0233         struct ieee80211_hdr *hdr =
0234             (struct ieee80211_hdr *) beacon->data;
0235         avp->seq_no += 0x10;
0236         hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
0237         hdr->seq_ctrl |= cpu_to_le16(avp->seq_no);
0238     }
0239 
0240     tx_ctl = HTC_SKB_CB(beacon);
0241     memset(tx_ctl, 0, sizeof(*tx_ctl));
0242 
0243     tx_ctl->type = ATH9K_HTC_BEACON;
0244     tx_ctl->epid = priv->beacon_ep;
0245 
0246     beacon_hdr.vif_index = avp->index;
0247     tx_fhdr = skb_push(beacon, sizeof(beacon_hdr));
0248     memcpy(tx_fhdr, (u8 *) &beacon_hdr, sizeof(beacon_hdr));
0249 
0250     ret = htc_send(priv->htc, beacon);
0251     if (ret != 0) {
0252         if (ret == -ENOMEM) {
0253             ath_dbg(common, BSTUCK,
0254                 "Failed to send beacon, no free TX buffer\n");
0255         }
0256         dev_kfree_skb_any(beacon);
0257     }
0258 
0259     spin_unlock_bh(&priv->beacon_lock);
0260 
0261     ath9k_htc_csa_is_finished(priv);
0262 }
0263 
0264 static int ath9k_htc_choose_bslot(struct ath9k_htc_priv *priv,
0265                   struct wmi_event_swba *swba)
0266 {
0267     struct ath_common *common = ath9k_hw_common(priv->ah);
0268     u64 tsf;
0269     u32 tsftu;
0270     u16 intval;
0271     int slot;
0272 
0273     intval = priv->cur_beacon_conf.beacon_interval;
0274 
0275     tsf = be64_to_cpu(swba->tsf);
0276     tsftu = TSF_TO_TU(tsf >> 32, tsf);
0277     slot = ((tsftu % intval) * ATH9K_HTC_MAX_BCN_VIF) / intval;
0278     slot = ATH9K_HTC_MAX_BCN_VIF - slot - 1;
0279 
0280     ath_dbg(common, BEACON,
0281         "Choose slot: %d, tsf: %llu, tsftu: %u, intval: %u\n",
0282         slot, tsf, tsftu, intval);
0283 
0284     return slot;
0285 }
0286 
0287 void ath9k_htc_swba(struct ath9k_htc_priv *priv,
0288             struct wmi_event_swba *swba)
0289 {
0290     struct ath_common *common = ath9k_hw_common(priv->ah);
0291     int slot;
0292 
0293     if (swba->beacon_pending != 0) {
0294         priv->beacon.bmisscnt++;
0295         if (priv->beacon.bmisscnt > BSTUCK_THRESHOLD) {
0296             ath_dbg(common, BSTUCK, "Beacon stuck, HW reset\n");
0297             ieee80211_queue_work(priv->hw,
0298                          &priv->fatal_work);
0299         }
0300         return;
0301     }
0302 
0303     if (priv->beacon.bmisscnt) {
0304         ath_dbg(common, BSTUCK,
0305             "Resuming beacon xmit after %u misses\n",
0306             priv->beacon.bmisscnt);
0307         priv->beacon.bmisscnt = 0;
0308     }
0309 
0310     slot = ath9k_htc_choose_bslot(priv, swba);
0311     spin_lock_bh(&priv->beacon_lock);
0312     if (priv->beacon.bslot[slot] == NULL) {
0313         spin_unlock_bh(&priv->beacon_lock);
0314         return;
0315     }
0316     spin_unlock_bh(&priv->beacon_lock);
0317 
0318     ath9k_htc_send_buffered(priv, slot);
0319     ath9k_htc_send_beacon(priv, slot);
0320 }
0321 
0322 void ath9k_htc_assign_bslot(struct ath9k_htc_priv *priv,
0323                 struct ieee80211_vif *vif)
0324 {
0325     struct ath_common *common = ath9k_hw_common(priv->ah);
0326     struct ath9k_htc_vif *avp = (struct ath9k_htc_vif *)vif->drv_priv;
0327     int i = 0;
0328 
0329     spin_lock_bh(&priv->beacon_lock);
0330     for (i = 0; i < ATH9K_HTC_MAX_BCN_VIF; i++) {
0331         if (priv->beacon.bslot[i] == NULL) {
0332             avp->bslot = i;
0333             break;
0334         }
0335     }
0336 
0337     priv->beacon.bslot[avp->bslot] = vif;
0338     spin_unlock_bh(&priv->beacon_lock);
0339 
0340     ath_dbg(common, CONFIG, "Added interface at beacon slot: %d\n",
0341         avp->bslot);
0342 }
0343 
0344 void ath9k_htc_remove_bslot(struct ath9k_htc_priv *priv,
0345                 struct ieee80211_vif *vif)
0346 {
0347     struct ath_common *common = ath9k_hw_common(priv->ah);
0348     struct ath9k_htc_vif *avp = (struct ath9k_htc_vif *)vif->drv_priv;
0349 
0350     spin_lock_bh(&priv->beacon_lock);
0351     priv->beacon.bslot[avp->bslot] = NULL;
0352     spin_unlock_bh(&priv->beacon_lock);
0353 
0354     ath_dbg(common, CONFIG, "Removed interface at beacon slot: %d\n",
0355         avp->bslot);
0356 }
0357 
0358 /*
0359  * Calculate the TSF adjustment value for all slots
0360  * other than zero.
0361  */
0362 void ath9k_htc_set_tsfadjust(struct ath9k_htc_priv *priv,
0363                  struct ieee80211_vif *vif)
0364 {
0365     struct ath_common *common = ath9k_hw_common(priv->ah);
0366     struct ath9k_htc_vif *avp = (struct ath9k_htc_vif *)vif->drv_priv;
0367     struct ath_beacon_config *cur_conf = &priv->cur_beacon_conf;
0368     u64 tsfadjust;
0369 
0370     if (avp->bslot == 0)
0371         return;
0372 
0373     /*
0374      * The beacon interval cannot be different for multi-AP mode,
0375      * and we reach here only for VIF slots greater than zero,
0376      * so beacon_interval is guaranteed to be set in cur_conf.
0377      */
0378     tsfadjust = cur_conf->beacon_interval * avp->bslot / ATH9K_HTC_MAX_BCN_VIF;
0379     avp->tsfadjust = cpu_to_le64(TU_TO_USEC(tsfadjust));
0380 
0381     ath_dbg(common, CONFIG, "tsfadjust is: %llu for bslot: %d\n",
0382         (unsigned long long)tsfadjust, avp->bslot);
0383 }
0384 
0385 static void ath9k_htc_beacon_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
0386 {
0387     bool *beacon_configured = data;
0388     struct ath9k_htc_vif *avp = (struct ath9k_htc_vif *) vif->drv_priv;
0389 
0390     if (vif->type == NL80211_IFTYPE_STATION &&
0391         avp->beacon_configured)
0392         *beacon_configured = true;
0393 }
0394 
0395 static bool ath9k_htc_check_beacon_config(struct ath9k_htc_priv *priv,
0396                       struct ieee80211_vif *vif)
0397 {
0398     struct ath_common *common = ath9k_hw_common(priv->ah);
0399     struct ath_beacon_config *cur_conf = &priv->cur_beacon_conf;
0400     struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
0401     bool beacon_configured;
0402 
0403     /*
0404      * Changing the beacon interval when multiple AP interfaces
0405      * are configured will affect beacon transmission of all
0406      * of them.
0407      */
0408     if ((priv->ah->opmode == NL80211_IFTYPE_AP) &&
0409         (priv->num_ap_vif > 1) &&
0410         (vif->type == NL80211_IFTYPE_AP) &&
0411         (cur_conf->beacon_interval != bss_conf->beacon_int)) {
0412         ath_dbg(common, CONFIG,
0413             "Changing beacon interval of multiple AP interfaces !\n");
0414         return false;
0415     }
0416 
0417     /*
0418      * If the HW is operating in AP mode, any new station interfaces that
0419      * are added cannot change the beacon parameters.
0420      */
0421     if (priv->num_ap_vif &&
0422         (vif->type != NL80211_IFTYPE_AP)) {
0423         ath_dbg(common, CONFIG,
0424             "HW in AP mode, cannot set STA beacon parameters\n");
0425         return false;
0426     }
0427 
0428     /*
0429      * The beacon parameters are configured only for the first
0430      * station interface.
0431      */
0432     if ((priv->ah->opmode == NL80211_IFTYPE_STATION) &&
0433         (priv->num_sta_vif > 1) &&
0434         (vif->type == NL80211_IFTYPE_STATION)) {
0435         beacon_configured = false;
0436         ieee80211_iterate_active_interfaces_atomic(
0437             priv->hw, IEEE80211_IFACE_ITER_RESUME_ALL,
0438             ath9k_htc_beacon_iter, &beacon_configured);
0439 
0440         if (beacon_configured) {
0441             ath_dbg(common, CONFIG,
0442                 "Beacon already configured for a station interface\n");
0443             return false;
0444         }
0445     }
0446 
0447     return true;
0448 }
0449 
0450 void ath9k_htc_beacon_config(struct ath9k_htc_priv *priv,
0451                  struct ieee80211_vif *vif)
0452 {
0453     struct ath_common *common = ath9k_hw_common(priv->ah);
0454     struct ath_beacon_config *cur_conf = &priv->cur_beacon_conf;
0455     struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
0456     struct ath9k_htc_vif *avp = (struct ath9k_htc_vif *) vif->drv_priv;
0457 
0458     if (!ath9k_htc_check_beacon_config(priv, vif))
0459         return;
0460 
0461     cur_conf->beacon_interval = bss_conf->beacon_int;
0462     if (cur_conf->beacon_interval == 0)
0463         cur_conf->beacon_interval = 100;
0464 
0465     cur_conf->dtim_period = bss_conf->dtim_period;
0466     cur_conf->bmiss_timeout =
0467         ATH_DEFAULT_BMISS_LIMIT * cur_conf->beacon_interval;
0468 
0469     switch (vif->type) {
0470     case NL80211_IFTYPE_STATION:
0471         ath9k_htc_beacon_config_sta(priv, cur_conf);
0472         avp->beacon_configured = true;
0473         break;
0474     case NL80211_IFTYPE_ADHOC:
0475         ath9k_htc_beacon_config_adhoc(priv, cur_conf);
0476         break;
0477     case NL80211_IFTYPE_MESH_POINT:
0478     case NL80211_IFTYPE_AP:
0479         ath9k_htc_beacon_config_ap(priv, cur_conf);
0480         break;
0481     default:
0482         ath_dbg(common, CONFIG, "Unsupported beaconing mode\n");
0483         return;
0484     }
0485 }
0486 
0487 void ath9k_htc_beacon_reconfig(struct ath9k_htc_priv *priv)
0488 {
0489     struct ath_common *common = ath9k_hw_common(priv->ah);
0490     struct ath_beacon_config *cur_conf = &priv->cur_beacon_conf;
0491 
0492     switch (priv->ah->opmode) {
0493     case NL80211_IFTYPE_STATION:
0494         ath9k_htc_beacon_config_sta(priv, cur_conf);
0495         break;
0496     case NL80211_IFTYPE_ADHOC:
0497         ath9k_htc_beacon_config_adhoc(priv, cur_conf);
0498         break;
0499     case NL80211_IFTYPE_MESH_POINT:
0500     case NL80211_IFTYPE_AP:
0501         ath9k_htc_beacon_config_ap(priv, cur_conf);
0502         break;
0503     default:
0504         ath_dbg(common, CONFIG, "Unsupported beaconing mode\n");
0505         return;
0506     }
0507 }
0508 
0509 bool ath9k_htc_csa_is_finished(struct ath9k_htc_priv *priv)
0510 {
0511     struct ieee80211_vif *vif;
0512 
0513     vif = priv->csa_vif;
0514     if (!vif || !vif->bss_conf.csa_active)
0515         return false;
0516 
0517     if (!ieee80211_beacon_cntdwn_is_complete(vif))
0518         return false;
0519 
0520     ieee80211_csa_finish(vif);
0521 
0522     priv->csa_vif = NULL;
0523     return true;
0524 }