htc_drv_beacon.c revision 3800276a40751539a920ef8e0537ef2e19126799
1/* 2 * Copyright (c) 2010 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 21static void ath9k_htc_beacon_config_sta(struct ath9k_htc_priv *priv, 22 struct htc_beacon_config *bss_conf) 23{ 24 struct ath_common *common = ath9k_hw_common(priv->ah); 25 struct ath9k_beacon_state bs; 26 enum ath9k_int imask = 0; 27 int dtimperiod, dtimcount, sleepduration; 28 int cfpperiod, cfpcount, bmiss_timeout; 29 u32 nexttbtt = 0, intval, tsftu; 30 __be32 htc_imask = 0; 31 u64 tsf; 32 int num_beacons, offset, dtim_dec_count, cfp_dec_count; 33 int ret; 34 u8 cmd_rsp; 35 36 memset(&bs, 0, sizeof(bs)); 37 38 intval = bss_conf->beacon_interval & ATH9K_BEACON_PERIOD; 39 bmiss_timeout = (ATH_DEFAULT_BMISS_LIMIT * bss_conf->beacon_interval); 40 41 /* 42 * Setup dtim and cfp parameters according to 43 * last beacon we received (which may be none). 44 */ 45 dtimperiod = bss_conf->dtim_period; 46 if (dtimperiod <= 0) /* NB: 0 if not known */ 47 dtimperiod = 1; 48 dtimcount = 1; 49 if (dtimcount >= dtimperiod) /* NB: sanity check */ 50 dtimcount = 0; 51 cfpperiod = 1; /* NB: no PCF support yet */ 52 cfpcount = 0; 53 54 sleepduration = intval; 55 if (sleepduration <= 0) 56 sleepduration = intval; 57 58 /* 59 * Pull nexttbtt forward to reflect the current 60 * TSF and calculate dtim+cfp state for the result. 61 */ 62 tsf = ath9k_hw_gettsf64(priv->ah); 63 tsftu = TSF_TO_TU(tsf>>32, tsf) + FUDGE; 64 65 num_beacons = tsftu / intval + 1; 66 offset = tsftu % intval; 67 nexttbtt = tsftu - offset; 68 if (offset) 69 nexttbtt += intval; 70 71 /* DTIM Beacon every dtimperiod Beacon */ 72 dtim_dec_count = num_beacons % dtimperiod; 73 /* CFP every cfpperiod DTIM Beacon */ 74 cfp_dec_count = (num_beacons / dtimperiod) % cfpperiod; 75 if (dtim_dec_count) 76 cfp_dec_count++; 77 78 dtimcount -= dtim_dec_count; 79 if (dtimcount < 0) 80 dtimcount += dtimperiod; 81 82 cfpcount -= cfp_dec_count; 83 if (cfpcount < 0) 84 cfpcount += cfpperiod; 85 86 bs.bs_intval = intval; 87 bs.bs_nexttbtt = nexttbtt; 88 bs.bs_dtimperiod = dtimperiod*intval; 89 bs.bs_nextdtim = bs.bs_nexttbtt + dtimcount*intval; 90 bs.bs_cfpperiod = cfpperiod*bs.bs_dtimperiod; 91 bs.bs_cfpnext = bs.bs_nextdtim + cfpcount*bs.bs_dtimperiod; 92 bs.bs_cfpmaxduration = 0; 93 94 /* 95 * Calculate the number of consecutive beacons to miss* before taking 96 * a BMISS interrupt. The configuration is specified in TU so we only 97 * need calculate based on the beacon interval. Note that we clamp the 98 * result to at most 15 beacons. 99 */ 100 if (sleepduration > intval) { 101 bs.bs_bmissthreshold = ATH_DEFAULT_BMISS_LIMIT / 2; 102 } else { 103 bs.bs_bmissthreshold = DIV_ROUND_UP(bmiss_timeout, intval); 104 if (bs.bs_bmissthreshold > 15) 105 bs.bs_bmissthreshold = 15; 106 else if (bs.bs_bmissthreshold <= 0) 107 bs.bs_bmissthreshold = 1; 108 } 109 110 /* 111 * Calculate sleep duration. The configuration is given in ms. 112 * We ensure a multiple of the beacon period is used. Also, if the sleep 113 * duration is greater than the DTIM period then it makes senses 114 * to make it a multiple of that. 115 * 116 * XXX fixed at 100ms 117 */ 118 119 bs.bs_sleepduration = roundup(IEEE80211_MS_TO_TU(100), sleepduration); 120 if (bs.bs_sleepduration > bs.bs_dtimperiod) 121 bs.bs_sleepduration = bs.bs_dtimperiod; 122 123 /* TSF out of range threshold fixed at 1 second */ 124 bs.bs_tsfoor_threshold = ATH9K_TSFOOR_THRESHOLD; 125 126 ath_print(common, ATH_DBG_BEACON, "tsf: %llu tsftu: %u\n", tsf, tsftu); 127 ath_print(common, ATH_DBG_BEACON, 128 "bmiss: %u sleep: %u cfp-period: %u maxdur: %u next: %u\n", 129 bs.bs_bmissthreshold, bs.bs_sleepduration, 130 bs.bs_cfpperiod, bs.bs_cfpmaxduration, bs.bs_cfpnext); 131 132 /* Set the computed STA beacon timers */ 133 134 WMI_CMD(WMI_DISABLE_INTR_CMDID); 135 ath9k_hw_set_sta_beacon_timers(priv->ah, &bs); 136 imask |= ATH9K_INT_BMISS; 137 htc_imask = cpu_to_be32(imask); 138 WMI_CMD_BUF(WMI_ENABLE_INTR_CMDID, &htc_imask); 139} 140 141static void ath9k_htc_beacon_config_adhoc(struct ath9k_htc_priv *priv, 142 struct htc_beacon_config *bss_conf) 143{ 144 struct ath_common *common = ath9k_hw_common(priv->ah); 145 enum ath9k_int imask = 0; 146 u32 nexttbtt, intval; 147 __be32 htc_imask = 0; 148 int ret; 149 u8 cmd_rsp; 150 151 intval = bss_conf->beacon_interval & ATH9K_BEACON_PERIOD; 152 nexttbtt = intval; 153 intval |= ATH9K_BEACON_ENA; 154 if (priv->op_flags & OP_ENABLE_BEACON) 155 imask |= ATH9K_INT_SWBA; 156 157 ath_print(common, ATH_DBG_BEACON, 158 "IBSS Beacon config, intval: %d, imask: 0x%x\n", 159 bss_conf->beacon_interval, imask); 160 161 WMI_CMD(WMI_DISABLE_INTR_CMDID); 162 ath9k_hw_beaconinit(priv->ah, nexttbtt, intval); 163 priv->bmiss_cnt = 0; 164 htc_imask = cpu_to_be32(imask); 165 WMI_CMD_BUF(WMI_ENABLE_INTR_CMDID, &htc_imask); 166} 167 168void ath9k_htc_beaconep(void *drv_priv, struct sk_buff *skb, 169 enum htc_endpoint_id ep_id, bool txok) 170{ 171 dev_kfree_skb_any(skb); 172} 173 174void ath9k_htc_swba(struct ath9k_htc_priv *priv, u8 beacon_pending) 175{ 176 struct ath9k_htc_vif *avp = (void *)priv->vif->drv_priv; 177 struct tx_beacon_header beacon_hdr; 178 struct ath9k_htc_tx_ctl tx_ctl; 179 struct ieee80211_tx_info *info; 180 struct sk_buff *beacon; 181 u8 *tx_fhdr; 182 183 memset(&beacon_hdr, 0, sizeof(struct tx_beacon_header)); 184 memset(&tx_ctl, 0, sizeof(struct ath9k_htc_tx_ctl)); 185 186 /* FIXME: Handle BMISS */ 187 if (beacon_pending != 0) { 188 priv->bmiss_cnt++; 189 return; 190 } 191 192 spin_lock_bh(&priv->beacon_lock); 193 194 if (unlikely(priv->op_flags & OP_SCANNING)) { 195 spin_unlock_bh(&priv->beacon_lock); 196 return; 197 } 198 199 /* Get a new beacon */ 200 beacon = ieee80211_beacon_get(priv->hw, priv->vif); 201 if (!beacon) { 202 spin_unlock_bh(&priv->beacon_lock); 203 return; 204 } 205 206 info = IEEE80211_SKB_CB(beacon); 207 if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { 208 struct ieee80211_hdr *hdr = 209 (struct ieee80211_hdr *) beacon->data; 210 priv->seq_no += 0x10; 211 hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG); 212 hdr->seq_ctrl |= cpu_to_le16(priv->seq_no); 213 } 214 215 tx_ctl.type = ATH9K_HTC_NORMAL; 216 beacon_hdr.vif_index = avp->index; 217 tx_fhdr = skb_push(beacon, sizeof(beacon_hdr)); 218 memcpy(tx_fhdr, (u8 *) &beacon_hdr, sizeof(beacon_hdr)); 219 220 htc_send(priv->htc, beacon, priv->beacon_ep, &tx_ctl); 221 222 spin_unlock_bh(&priv->beacon_lock); 223} 224 225/* Currently, only for IBSS */ 226void ath9k_htc_beaconq_config(struct ath9k_htc_priv *priv) 227{ 228 struct ath_hw *ah = priv->ah; 229 struct ath9k_tx_queue_info qi, qi_be; 230 int qnum = priv->hwq_map[WME_AC_BE]; 231 232 memset(&qi, 0, sizeof(struct ath9k_tx_queue_info)); 233 memset(&qi_be, 0, sizeof(struct ath9k_tx_queue_info)); 234 235 ath9k_hw_get_txq_props(ah, qnum, &qi_be); 236 237 qi.tqi_aifs = qi_be.tqi_aifs; 238 /* For WIFI Beacon Distribution 239 * Long slot time : 2x cwmin 240 * Short slot time : 4x cwmin 241 */ 242 if (ah->slottime == ATH9K_SLOT_TIME_20) 243 qi.tqi_cwmin = 2*qi_be.tqi_cwmin; 244 else 245 qi.tqi_cwmin = 4*qi_be.tqi_cwmin; 246 qi.tqi_cwmax = qi_be.tqi_cwmax; 247 248 if (!ath9k_hw_set_txq_props(ah, priv->beaconq, &qi)) { 249 ath_err(ath9k_hw_common(ah), 250 "Unable to update beacon queue %u!\n", qnum); 251 } else { 252 ath9k_hw_resettxqueue(ah, priv->beaconq); 253 } 254} 255 256void ath9k_htc_beacon_config(struct ath9k_htc_priv *priv, 257 struct ieee80211_vif *vif) 258{ 259 struct ath_common *common = ath9k_hw_common(priv->ah); 260 struct htc_beacon_config *cur_conf = &priv->cur_beacon_conf; 261 struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; 262 263 cur_conf->beacon_interval = bss_conf->beacon_int; 264 if (cur_conf->beacon_interval == 0) 265 cur_conf->beacon_interval = 100; 266 267 cur_conf->dtim_period = bss_conf->dtim_period; 268 cur_conf->listen_interval = 1; 269 cur_conf->dtim_count = 1; 270 cur_conf->bmiss_timeout = 271 ATH_DEFAULT_BMISS_LIMIT * cur_conf->beacon_interval; 272 273 switch (vif->type) { 274 case NL80211_IFTYPE_STATION: 275 ath9k_htc_beacon_config_sta(priv, cur_conf); 276 break; 277 case NL80211_IFTYPE_ADHOC: 278 ath9k_htc_beacon_config_adhoc(priv, cur_conf); 279 break; 280 default: 281 ath_print(common, ATH_DBG_CONFIG, 282 "Unsupported beaconing mode\n"); 283 return; 284 } 285} 286