htc_drv_beacon.c revision a5fae37d118bb633708b2787e53871e38bf3b15e
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_dbg(common, ATH_DBG_BEACON, "tsf: %llu tsftu: %u\n", tsf, tsftu); 127 ath_dbg(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_ap(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, tsftu; 147 __be32 htc_imask = 0; 148 int ret; 149 u8 cmd_rsp; 150 u64 tsf; 151 152 intval = bss_conf->beacon_interval & ATH9K_BEACON_PERIOD; 153 intval /= ATH9K_HTC_MAX_BCN_VIF; 154 nexttbtt = intval; 155 156 if (priv->op_flags & OP_TSF_RESET) { 157 intval |= ATH9K_BEACON_RESET_TSF; 158 priv->op_flags &= ~OP_TSF_RESET; 159 } else { 160 /* 161 * Pull nexttbtt forward to reflect the current TSF. 162 */ 163 tsf = ath9k_hw_gettsf64(priv->ah); 164 tsftu = TSF_TO_TU(tsf >> 32, tsf) + FUDGE; 165 do { 166 nexttbtt += intval; 167 } while (nexttbtt < tsftu); 168 } 169 170 intval |= ATH9K_BEACON_ENA; 171 172 if (priv->op_flags & OP_ENABLE_BEACON) 173 imask |= ATH9K_INT_SWBA; 174 175 ath_dbg(common, ATH_DBG_CONFIG, 176 "AP Beacon config, intval: %d, nexttbtt: %u imask: 0x%x\n", 177 bss_conf->beacon_interval, nexttbtt, imask); 178 179 WMI_CMD(WMI_DISABLE_INTR_CMDID); 180 ath9k_hw_beaconinit(priv->ah, nexttbtt, intval); 181 priv->bmiss_cnt = 0; 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_adhoc(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; 192 __be32 htc_imask = 0; 193 int ret; 194 u8 cmd_rsp; 195 196 intval = bss_conf->beacon_interval & ATH9K_BEACON_PERIOD; 197 nexttbtt = intval; 198 intval |= ATH9K_BEACON_ENA; 199 if (priv->op_flags & OP_ENABLE_BEACON) 200 imask |= ATH9K_INT_SWBA; 201 202 ath_dbg(common, ATH_DBG_BEACON, 203 "IBSS Beacon config, intval: %d, imask: 0x%x\n", 204 bss_conf->beacon_interval, imask); 205 206 WMI_CMD(WMI_DISABLE_INTR_CMDID); 207 ath9k_hw_beaconinit(priv->ah, nexttbtt, intval); 208 priv->bmiss_cnt = 0; 209 htc_imask = cpu_to_be32(imask); 210 WMI_CMD_BUF(WMI_ENABLE_INTR_CMDID, &htc_imask); 211} 212 213void ath9k_htc_beaconep(void *drv_priv, struct sk_buff *skb, 214 enum htc_endpoint_id ep_id, bool txok) 215{ 216 dev_kfree_skb_any(skb); 217} 218 219void ath9k_htc_swba(struct ath9k_htc_priv *priv, u8 beacon_pending) 220{ 221 struct ath9k_htc_vif *avp = (void *)priv->vif->drv_priv; 222 struct tx_beacon_header beacon_hdr; 223 struct ath9k_htc_tx_ctl tx_ctl; 224 struct ieee80211_tx_info *info; 225 struct sk_buff *beacon; 226 u8 *tx_fhdr; 227 228 memset(&beacon_hdr, 0, sizeof(struct tx_beacon_header)); 229 memset(&tx_ctl, 0, sizeof(struct ath9k_htc_tx_ctl)); 230 231 /* FIXME: Handle BMISS */ 232 if (beacon_pending != 0) { 233 priv->bmiss_cnt++; 234 return; 235 } 236 237 spin_lock_bh(&priv->beacon_lock); 238 239 if (unlikely(priv->op_flags & OP_SCANNING)) { 240 spin_unlock_bh(&priv->beacon_lock); 241 return; 242 } 243 244 /* Get a new beacon */ 245 beacon = ieee80211_beacon_get(priv->hw, priv->vif); 246 if (!beacon) { 247 spin_unlock_bh(&priv->beacon_lock); 248 return; 249 } 250 251 info = IEEE80211_SKB_CB(beacon); 252 if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { 253 struct ieee80211_hdr *hdr = 254 (struct ieee80211_hdr *) beacon->data; 255 avp->seq_no += 0x10; 256 hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG); 257 hdr->seq_ctrl |= cpu_to_le16(avp->seq_no); 258 } 259 260 tx_ctl.type = ATH9K_HTC_NORMAL; 261 beacon_hdr.vif_index = avp->index; 262 tx_fhdr = skb_push(beacon, sizeof(beacon_hdr)); 263 memcpy(tx_fhdr, (u8 *) &beacon_hdr, sizeof(beacon_hdr)); 264 265 htc_send(priv->htc, beacon, priv->beacon_ep, &tx_ctl); 266 267 spin_unlock_bh(&priv->beacon_lock); 268} 269 270/* Currently, only for IBSS */ 271void ath9k_htc_beaconq_config(struct ath9k_htc_priv *priv) 272{ 273 struct ath_hw *ah = priv->ah; 274 struct ath9k_tx_queue_info qi, qi_be; 275 int qnum = priv->hwq_map[WME_AC_BE]; 276 277 memset(&qi, 0, sizeof(struct ath9k_tx_queue_info)); 278 memset(&qi_be, 0, sizeof(struct ath9k_tx_queue_info)); 279 280 ath9k_hw_get_txq_props(ah, qnum, &qi_be); 281 282 qi.tqi_aifs = qi_be.tqi_aifs; 283 /* For WIFI Beacon Distribution 284 * Long slot time : 2x cwmin 285 * Short slot time : 4x cwmin 286 */ 287 if (ah->slottime == ATH9K_SLOT_TIME_20) 288 qi.tqi_cwmin = 2*qi_be.tqi_cwmin; 289 else 290 qi.tqi_cwmin = 4*qi_be.tqi_cwmin; 291 qi.tqi_cwmax = qi_be.tqi_cwmax; 292 293 if (!ath9k_hw_set_txq_props(ah, priv->beaconq, &qi)) { 294 ath_err(ath9k_hw_common(ah), 295 "Unable to update beacon queue %u!\n", qnum); 296 } else { 297 ath9k_hw_resettxqueue(ah, priv->beaconq); 298 } 299} 300 301void ath9k_htc_beacon_config(struct ath9k_htc_priv *priv, 302 struct ieee80211_vif *vif) 303{ 304 struct ath_common *common = ath9k_hw_common(priv->ah); 305 struct htc_beacon_config *cur_conf = &priv->cur_beacon_conf; 306 struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; 307 308 /* 309 * Changing the beacon interval when multiple AP interfaces 310 * are configured will affect beacon transmission of all 311 * of them. 312 */ 313 if ((priv->ah->opmode == NL80211_IFTYPE_AP) && 314 (priv->num_ap_vif > 1) && 315 (vif->type == NL80211_IFTYPE_AP) && 316 (cur_conf->beacon_interval != bss_conf->beacon_int)) { 317 ath_dbg(common, ATH_DBG_CONFIG, 318 "Changing beacon interval of multiple AP interfaces !\n"); 319 return; 320 } 321 322 /* 323 * If the HW is operating in AP mode, any new station interfaces that 324 * are added cannot change the beacon parameters. 325 */ 326 if (priv->num_ap_vif && 327 (vif->type != NL80211_IFTYPE_AP)) { 328 ath_dbg(common, ATH_DBG_CONFIG, 329 "HW in AP mode, cannot set STA beacon parameters\n"); 330 return; 331 } 332 333 cur_conf->beacon_interval = bss_conf->beacon_int; 334 if (cur_conf->beacon_interval == 0) 335 cur_conf->beacon_interval = 100; 336 337 cur_conf->dtim_period = bss_conf->dtim_period; 338 cur_conf->bmiss_timeout = 339 ATH_DEFAULT_BMISS_LIMIT * cur_conf->beacon_interval; 340 341 switch (vif->type) { 342 case NL80211_IFTYPE_STATION: 343 ath9k_htc_beacon_config_sta(priv, cur_conf); 344 break; 345 case NL80211_IFTYPE_ADHOC: 346 ath9k_htc_beacon_config_adhoc(priv, cur_conf); 347 break; 348 case NL80211_IFTYPE_AP: 349 ath9k_htc_beacon_config_ap(priv, cur_conf); 350 break; 351 default: 352 ath_dbg(common, ATH_DBG_CONFIG, 353 "Unsupported beaconing mode\n"); 354 return; 355 } 356} 357 358void ath9k_htc_beacon_reconfig(struct ath9k_htc_priv *priv) 359{ 360 struct ath_common *common = ath9k_hw_common(priv->ah); 361 struct htc_beacon_config *cur_conf = &priv->cur_beacon_conf; 362 363 switch (priv->ah->opmode) { 364 case NL80211_IFTYPE_STATION: 365 ath9k_htc_beacon_config_sta(priv, cur_conf); 366 break; 367 case NL80211_IFTYPE_ADHOC: 368 ath9k_htc_beacon_config_adhoc(priv, cur_conf); 369 break; 370 case NL80211_IFTYPE_AP: 371 ath9k_htc_beacon_config_ap(priv, cur_conf); 372 break; 373 default: 374 ath_dbg(common, ATH_DBG_CONFIG, 375 "Unsupported beaconing mode\n"); 376 return; 377 } 378} 379