Commit | Line | Data |
---|---|---|
fb9987d0 | 1 | /* |
5b68138e | 2 | * Copyright (c) 2010-2011 Atheros Communications Inc. |
fb9987d0 S |
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 | ||
2493a547 SM |
21 | void 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 | ||
a099874e | 29 | ath9k_hw_get_txq_props(ah, priv->beacon.beaconq, &qi); |
2493a547 | 30 | |
594e65b6 JC |
31 | if (priv->ah->opmode == NL80211_IFTYPE_AP || |
32 | priv->ah->opmode == NL80211_IFTYPE_MESH_POINT) { | |
2493a547 SM |
33 | qi.tqi_aifs = 1; |
34 | qi.tqi_cwmin = 0; | |
35 | qi.tqi_cwmax = 0; | |
36 | } else if (priv->ah->opmode == NL80211_IFTYPE_ADHOC) { | |
bea843c7 | 37 | int qnum = priv->hwq_map[IEEE80211_AC_BE]; |
2493a547 SM |
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 | */ | |
11b0ac2e | 48 | if (ah->slottime == 20) |
2493a547 SM |
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 | ||
a099874e | 57 | if (!ath9k_hw_set_txq_props(ah, priv->beacon.beaconq, &qi)) { |
2493a547 | 58 | ath_err(ath9k_hw_common(ah), |
a099874e | 59 | "Unable to update beacon queue %u!\n", priv->beacon.beaconq); |
2493a547 | 60 | } else { |
a099874e | 61 | ath9k_hw_resettxqueue(ah, priv->beacon.beaconq); |
2493a547 SM |
62 | } |
63 | } | |
64 | ||
7f5c4c83 OR |
65 | /* |
66 | * Both nexttbtt and intval have to be in usecs. | |
67 | */ | |
68 | static void ath9k_htc_beacon_init(struct ath9k_htc_priv *priv, | |
69 | struct ath_beacon_config *conf, | |
70 | bool reset_tsf) | |
71 | { | |
72 | struct ath_hw *ah = priv->ah; | |
73 | int ret __attribute__ ((unused)); | |
74 | __be32 htc_imask = 0; | |
75 | u8 cmd_rsp; | |
76 | ||
5f667642 OR |
77 | if (conf->intval >= TU_TO_USEC(DEFAULT_SWBA_RESPONSE)) |
78 | ah->config.sw_beacon_response_time = DEFAULT_SWBA_RESPONSE; | |
79 | else | |
80 | ah->config.sw_beacon_response_time = MIN_SWBA_RESPONSE; | |
81 | ||
7f5c4c83 OR |
82 | WMI_CMD(WMI_DISABLE_INTR_CMDID); |
83 | if (reset_tsf) | |
84 | ath9k_hw_reset_tsf(ah); | |
85 | ath9k_htc_beaconq_config(priv); | |
86 | ath9k_hw_beaconinit(ah, conf->nexttbtt, conf->intval); | |
87 | priv->beacon.bmisscnt = 0; | |
88 | htc_imask = cpu_to_be32(ah->imask); | |
89 | WMI_CMD_BUF(WMI_ENABLE_INTR_CMDID, &htc_imask); | |
90 | } | |
91 | ||
fb9987d0 | 92 | static void ath9k_htc_beacon_config_sta(struct ath9k_htc_priv *priv, |
3c4816d9 | 93 | struct ath_beacon_config *bss_conf) |
fb9987d0 | 94 | { |
fb9987d0 S |
95 | struct ath9k_beacon_state bs; |
96 | enum ath9k_int imask = 0; | |
7f1f5a00 | 97 | __be32 htc_imask = 0; |
0ff2b5c0 | 98 | int ret __attribute__ ((unused)); |
fb9987d0 S |
99 | u8 cmd_rsp; |
100 | ||
f8422440 OR |
101 | if (ath9k_cmn_beacon_config_sta(priv->ah, bss_conf, &bs) == -EPERM) |
102 | return; | |
fb9987d0 S |
103 | |
104 | WMI_CMD(WMI_DISABLE_INTR_CMDID); | |
105 | ath9k_hw_set_sta_beacon_timers(priv->ah, &bs); | |
106 | imask |= ATH9K_INT_BMISS; | |
107 | htc_imask = cpu_to_be32(imask); | |
108 | WMI_CMD_BUF(WMI_ENABLE_INTR_CMDID, &htc_imask); | |
109 | } | |
110 | ||
a5fae37d | 111 | static void ath9k_htc_beacon_config_ap(struct ath9k_htc_priv *priv, |
4b2d841f | 112 | struct ath_beacon_config *conf) |
a5fae37d | 113 | { |
4b2d841f OR |
114 | struct ath_hw *ah = priv->ah; |
115 | ah->imask = 0; | |
a5fae37d | 116 | |
4b2d841f | 117 | ath9k_cmn_beacon_config_ap(ah, conf, ATH9K_HTC_MAX_BCN_VIF); |
4b2d841f | 118 | ath9k_htc_beacon_init(priv, conf, false); |
a5fae37d SM |
119 | } |
120 | ||
fb9987d0 | 121 | static void ath9k_htc_beacon_config_adhoc(struct ath9k_htc_priv *priv, |
12f53c30 | 122 | struct ath_beacon_config *conf) |
fb9987d0 | 123 | { |
f7197924 | 124 | struct ath_hw *ah = priv->ah; |
12f53c30 | 125 | ah->imask = 0; |
200be651 | 126 | |
12f53c30 | 127 | ath9k_cmn_beacon_config_adhoc(ah, conf); |
12f53c30 | 128 | ath9k_htc_beacon_init(priv, conf, conf->ibss_creator); |
fb9987d0 S |
129 | } |
130 | ||
9c6dda4e S |
131 | void ath9k_htc_beaconep(void *drv_priv, struct sk_buff *skb, |
132 | enum htc_endpoint_id ep_id, bool txok) | |
fb9987d0 | 133 | { |
9c6dda4e | 134 | dev_kfree_skb_any(skb); |
fb9987d0 S |
135 | } |
136 | ||
7d547eb4 SM |
137 | static void ath9k_htc_send_buffered(struct ath9k_htc_priv *priv, |
138 | int slot) | |
139 | { | |
140 | struct ath_common *common = ath9k_hw_common(priv->ah); | |
141 | struct ieee80211_vif *vif; | |
142 | struct sk_buff *skb; | |
143 | struct ieee80211_hdr *hdr; | |
2c5d57f0 | 144 | int padpos, padsize, ret, tx_slot; |
7d547eb4 SM |
145 | |
146 | spin_lock_bh(&priv->beacon_lock); | |
147 | ||
3c4816d9 | 148 | vif = priv->beacon.bslot[slot]; |
7d547eb4 SM |
149 | |
150 | skb = ieee80211_get_buffered_bc(priv->hw, vif); | |
151 | ||
152 | while(skb) { | |
153 | hdr = (struct ieee80211_hdr *) skb->data; | |
154 | ||
c60c9929 | 155 | padpos = ieee80211_hdrlen(hdr->frame_control); |
7d547eb4 SM |
156 | padsize = padpos & 3; |
157 | if (padsize && skb->len > padpos) { | |
158 | if (skb_headroom(skb) < padsize) { | |
159 | dev_kfree_skb_any(skb); | |
160 | goto next; | |
161 | } | |
162 | skb_push(skb, padsize); | |
163 | memmove(skb->data, skb->data + padsize, padpos); | |
164 | } | |
165 | ||
2c5d57f0 | 166 | tx_slot = ath9k_htc_tx_get_slot(priv); |
cea3235c | 167 | if (tx_slot < 0) { |
d2182b69 | 168 | ath_dbg(common, XMIT, "No free CAB slot\n"); |
2c5d57f0 SM |
169 | dev_kfree_skb_any(skb); |
170 | goto next; | |
171 | } | |
172 | ||
36323f81 | 173 | ret = ath9k_htc_tx_start(priv, NULL, skb, tx_slot, true); |
7d547eb4 | 174 | if (ret != 0) { |
2c5d57f0 | 175 | ath9k_htc_tx_clear_slot(priv, tx_slot); |
7d547eb4 | 176 | dev_kfree_skb_any(skb); |
2c5d57f0 | 177 | |
d2182b69 | 178 | ath_dbg(common, XMIT, "Failed to send CAB frame\n"); |
8e86a547 SM |
179 | } else { |
180 | spin_lock_bh(&priv->tx.tx_lock); | |
181 | priv->tx.queued_cnt++; | |
182 | spin_unlock_bh(&priv->tx.tx_lock); | |
7d547eb4 SM |
183 | } |
184 | next: | |
185 | skb = ieee80211_get_buffered_bc(priv->hw, vif); | |
186 | } | |
187 | ||
188 | spin_unlock_bh(&priv->beacon_lock); | |
189 | } | |
190 | ||
832f6a18 SM |
191 | static void ath9k_htc_send_beacon(struct ath9k_htc_priv *priv, |
192 | int slot) | |
fb9987d0 | 193 | { |
b0a6ba98 | 194 | struct ath_common *common = ath9k_hw_common(priv->ah); |
832f6a18 SM |
195 | struct ieee80211_vif *vif; |
196 | struct ath9k_htc_vif *avp; | |
fb9987d0 | 197 | struct tx_beacon_header beacon_hdr; |
40dc9e4b | 198 | struct ath9k_htc_tx_ctl *tx_ctl; |
fb9987d0 | 199 | struct ieee80211_tx_info *info; |
9b674a02 | 200 | struct ieee80211_mgmt *mgmt; |
9c6dda4e | 201 | struct sk_buff *beacon; |
fb9987d0 | 202 | u8 *tx_fhdr; |
b0a6ba98 | 203 | int ret; |
fb9987d0 S |
204 | |
205 | memset(&beacon_hdr, 0, sizeof(struct tx_beacon_header)); | |
fb9987d0 | 206 | |
fb9987d0 S |
207 | spin_lock_bh(&priv->beacon_lock); |
208 | ||
3c4816d9 | 209 | vif = priv->beacon.bslot[slot]; |
832f6a18 SM |
210 | avp = (struct ath9k_htc_vif *)vif->drv_priv; |
211 | ||
92c3f7ef | 212 | if (unlikely(test_bit(ATH_OP_SCANNING, &common->op_flags))) { |
fb9987d0 S |
213 | spin_unlock_bh(&priv->beacon_lock); |
214 | return; | |
215 | } | |
216 | ||
fb9987d0 | 217 | /* Get a new beacon */ |
832f6a18 | 218 | beacon = ieee80211_beacon_get(priv->hw, vif); |
9c6dda4e | 219 | if (!beacon) { |
fb9987d0 S |
220 | spin_unlock_bh(&priv->beacon_lock); |
221 | return; | |
222 | } | |
223 | ||
9b674a02 SM |
224 | /* |
225 | * Update the TSF adjust value here, the HW will | |
226 | * add this value for every beacon. | |
227 | */ | |
228 | mgmt = (struct ieee80211_mgmt *)beacon->data; | |
229 | mgmt->u.beacon.timestamp = avp->tsfadjust; | |
230 | ||
9c6dda4e | 231 | info = IEEE80211_SKB_CB(beacon); |
fb9987d0 S |
232 | if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { |
233 | struct ieee80211_hdr *hdr = | |
9c6dda4e | 234 | (struct ieee80211_hdr *) beacon->data; |
9a3d025b | 235 | avp->seq_no += 0x10; |
fb9987d0 | 236 | hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG); |
9a3d025b | 237 | hdr->seq_ctrl |= cpu_to_le16(avp->seq_no); |
fb9987d0 S |
238 | } |
239 | ||
40dc9e4b SM |
240 | tx_ctl = HTC_SKB_CB(beacon); |
241 | memset(tx_ctl, 0, sizeof(*tx_ctl)); | |
242 | ||
243 | tx_ctl->type = ATH9K_HTC_BEACON; | |
d67ee533 | 244 | tx_ctl->epid = priv->beacon_ep; |
40dc9e4b | 245 | |
fb9987d0 | 246 | beacon_hdr.vif_index = avp->index; |
9c6dda4e | 247 | tx_fhdr = skb_push(beacon, sizeof(beacon_hdr)); |
fb9987d0 S |
248 | memcpy(tx_fhdr, (u8 *) &beacon_hdr, sizeof(beacon_hdr)); |
249 | ||
d67ee533 | 250 | ret = htc_send(priv->htc, beacon); |
b0a6ba98 SM |
251 | if (ret != 0) { |
252 | if (ret == -ENOMEM) { | |
d2182b69 | 253 | ath_dbg(common, BSTUCK, |
b0a6ba98 SM |
254 | "Failed to send beacon, no free TX buffer\n"); |
255 | } | |
256 | dev_kfree_skb_any(beacon); | |
257 | } | |
fb9987d0 S |
258 | |
259 | spin_unlock_bh(&priv->beacon_lock); | |
f0e44962 CYY |
260 | |
261 | ath9k_htc_csa_is_finished(priv); | |
fb9987d0 S |
262 | } |
263 | ||
f4c88991 SM |
264 | static int ath9k_htc_choose_bslot(struct ath9k_htc_priv *priv, |
265 | struct wmi_event_swba *swba) | |
832f6a18 SM |
266 | { |
267 | struct ath_common *common = ath9k_hw_common(priv->ah); | |
832f6a18 SM |
268 | u64 tsf; |
269 | u32 tsftu; | |
270 | u16 intval; | |
271 | int slot; | |
272 | ||
f29f5c08 | 273 | intval = priv->cur_beacon_conf.beacon_interval; |
832f6a18 | 274 | |
f4c88991 | 275 | tsf = be64_to_cpu(swba->tsf); |
832f6a18 SM |
276 | tsftu = TSF_TO_TU(tsf >> 32, tsf); |
277 | slot = ((tsftu % intval) * ATH9K_HTC_MAX_BCN_VIF) / intval; | |
278 | slot = ATH9K_HTC_MAX_BCN_VIF - slot - 1; | |
279 | ||
d2182b69 | 280 | ath_dbg(common, BEACON, |
832f6a18 SM |
281 | "Choose slot: %d, tsf: %llu, tsftu: %u, intval: %u\n", |
282 | slot, tsf, tsftu, intval); | |
283 | ||
284 | return slot; | |
285 | } | |
286 | ||
f4c88991 SM |
287 | void ath9k_htc_swba(struct ath9k_htc_priv *priv, |
288 | struct wmi_event_swba *swba) | |
832f6a18 SM |
289 | { |
290 | struct ath_common *common = ath9k_hw_common(priv->ah); | |
832f6a18 SM |
291 | int slot; |
292 | ||
f4c88991 | 293 | if (swba->beacon_pending != 0) { |
3c4816d9 OR |
294 | priv->beacon.bmisscnt++; |
295 | if (priv->beacon.bmisscnt > BSTUCK_THRESHOLD) { | |
d2182b69 | 296 | ath_dbg(common, BSTUCK, "Beacon stuck, HW reset\n"); |
f4c88991 SM |
297 | ieee80211_queue_work(priv->hw, |
298 | &priv->fatal_work); | |
832f6a18 SM |
299 | } |
300 | return; | |
301 | } | |
832f6a18 | 302 | |
3c4816d9 | 303 | if (priv->beacon.bmisscnt) { |
d2182b69 | 304 | ath_dbg(common, BSTUCK, |
832f6a18 | 305 | "Resuming beacon xmit after %u misses\n", |
3c4816d9 OR |
306 | priv->beacon.bmisscnt); |
307 | priv->beacon.bmisscnt = 0; | |
832f6a18 SM |
308 | } |
309 | ||
f4c88991 | 310 | slot = ath9k_htc_choose_bslot(priv, swba); |
832f6a18 | 311 | spin_lock_bh(&priv->beacon_lock); |
3c4816d9 | 312 | if (priv->beacon.bslot[slot] == NULL) { |
832f6a18 SM |
313 | spin_unlock_bh(&priv->beacon_lock); |
314 | return; | |
315 | } | |
316 | spin_unlock_bh(&priv->beacon_lock); | |
317 | ||
7d547eb4 | 318 | ath9k_htc_send_buffered(priv, slot); |
832f6a18 SM |
319 | ath9k_htc_send_beacon(priv, slot); |
320 | } | |
321 | ||
832f6a18 SM |
322 | void ath9k_htc_assign_bslot(struct ath9k_htc_priv *priv, |
323 | struct ieee80211_vif *vif) | |
324 | { | |
325 | struct ath_common *common = ath9k_hw_common(priv->ah); | |
326 | struct ath9k_htc_vif *avp = (struct ath9k_htc_vif *)vif->drv_priv; | |
327 | int i = 0; | |
328 | ||
329 | spin_lock_bh(&priv->beacon_lock); | |
330 | for (i = 0; i < ATH9K_HTC_MAX_BCN_VIF; i++) { | |
3c4816d9 | 331 | if (priv->beacon.bslot[i] == NULL) { |
832f6a18 SM |
332 | avp->bslot = i; |
333 | break; | |
334 | } | |
335 | } | |
336 | ||
3c4816d9 | 337 | priv->beacon.bslot[avp->bslot] = vif; |
832f6a18 SM |
338 | spin_unlock_bh(&priv->beacon_lock); |
339 | ||
d2182b69 JP |
340 | ath_dbg(common, CONFIG, "Added interface at beacon slot: %d\n", |
341 | avp->bslot); | |
832f6a18 SM |
342 | } |
343 | ||
344 | void ath9k_htc_remove_bslot(struct ath9k_htc_priv *priv, | |
345 | struct ieee80211_vif *vif) | |
346 | { | |
347 | struct ath_common *common = ath9k_hw_common(priv->ah); | |
348 | struct ath9k_htc_vif *avp = (struct ath9k_htc_vif *)vif->drv_priv; | |
349 | ||
350 | spin_lock_bh(&priv->beacon_lock); | |
3c4816d9 | 351 | priv->beacon.bslot[avp->bslot] = NULL; |
832f6a18 SM |
352 | spin_unlock_bh(&priv->beacon_lock); |
353 | ||
d2182b69 JP |
354 | ath_dbg(common, CONFIG, "Removed interface at beacon slot: %d\n", |
355 | avp->bslot); | |
832f6a18 SM |
356 | } |
357 | ||
9b674a02 SM |
358 | /* |
359 | * Calculate the TSF adjustment value for all slots | |
360 | * other than zero. | |
361 | */ | |
362 | void ath9k_htc_set_tsfadjust(struct ath9k_htc_priv *priv, | |
363 | struct ieee80211_vif *vif) | |
364 | { | |
365 | struct ath_common *common = ath9k_hw_common(priv->ah); | |
366 | struct ath9k_htc_vif *avp = (struct ath9k_htc_vif *)vif->drv_priv; | |
3c4816d9 | 367 | struct ath_beacon_config *cur_conf = &priv->cur_beacon_conf; |
9b674a02 SM |
368 | u64 tsfadjust; |
369 | ||
370 | if (avp->bslot == 0) | |
371 | return; | |
372 | ||
373 | /* | |
374 | * The beacon interval cannot be different for multi-AP mode, | |
375 | * and we reach here only for VIF slots greater than zero, | |
376 | * so beacon_interval is guaranteed to be set in cur_conf. | |
377 | */ | |
378 | tsfadjust = cur_conf->beacon_interval * avp->bslot / ATH9K_HTC_MAX_BCN_VIF; | |
379 | avp->tsfadjust = cpu_to_le64(TU_TO_USEC(tsfadjust)); | |
380 | ||
d2182b69 | 381 | ath_dbg(common, CONFIG, "tsfadjust is: %llu for bslot: %d\n", |
9b674a02 SM |
382 | (unsigned long long)tsfadjust, avp->bslot); |
383 | } | |
384 | ||
e7a2a4f5 SM |
385 | static void ath9k_htc_beacon_iter(void *data, u8 *mac, struct ieee80211_vif *vif) |
386 | { | |
50c8cd44 | 387 | bool *beacon_configured = data; |
e7a2a4f5 SM |
388 | struct ath9k_htc_vif *avp = (struct ath9k_htc_vif *) vif->drv_priv; |
389 | ||
390 | if (vif->type == NL80211_IFTYPE_STATION && | |
391 | avp->beacon_configured) | |
392 | *beacon_configured = true; | |
393 | } | |
394 | ||
395 | static bool ath9k_htc_check_beacon_config(struct ath9k_htc_priv *priv, | |
396 | struct ieee80211_vif *vif) | |
fb9987d0 S |
397 | { |
398 | struct ath_common *common = ath9k_hw_common(priv->ah); | |
3c4816d9 | 399 | struct ath_beacon_config *cur_conf = &priv->cur_beacon_conf; |
fcb9392f | 400 | struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; |
e7a2a4f5 | 401 | bool beacon_configured; |
1c3652a5 | 402 | |
a5fae37d SM |
403 | /* |
404 | * Changing the beacon interval when multiple AP interfaces | |
405 | * are configured will affect beacon transmission of all | |
406 | * of them. | |
407 | */ | |
408 | if ((priv->ah->opmode == NL80211_IFTYPE_AP) && | |
409 | (priv->num_ap_vif > 1) && | |
410 | (vif->type == NL80211_IFTYPE_AP) && | |
411 | (cur_conf->beacon_interval != bss_conf->beacon_int)) { | |
d2182b69 | 412 | ath_dbg(common, CONFIG, |
a5fae37d | 413 | "Changing beacon interval of multiple AP interfaces !\n"); |
e7a2a4f5 | 414 | return false; |
a5fae37d SM |
415 | } |
416 | ||
417 | /* | |
418 | * If the HW is operating in AP mode, any new station interfaces that | |
419 | * are added cannot change the beacon parameters. | |
420 | */ | |
421 | if (priv->num_ap_vif && | |
422 | (vif->type != NL80211_IFTYPE_AP)) { | |
d2182b69 | 423 | ath_dbg(common, CONFIG, |
a5fae37d | 424 | "HW in AP mode, cannot set STA beacon parameters\n"); |
e7a2a4f5 SM |
425 | return false; |
426 | } | |
427 | ||
428 | /* | |
429 | * The beacon parameters are configured only for the first | |
430 | * station interface. | |
431 | */ | |
432 | if ((priv->ah->opmode == NL80211_IFTYPE_STATION) && | |
433 | (priv->num_sta_vif > 1) && | |
434 | (vif->type == NL80211_IFTYPE_STATION)) { | |
435 | beacon_configured = false; | |
8b2c9824 JB |
436 | ieee80211_iterate_active_interfaces_atomic( |
437 | priv->hw, IEEE80211_IFACE_ITER_RESUME_ALL, | |
438 | ath9k_htc_beacon_iter, &beacon_configured); | |
e7a2a4f5 SM |
439 | |
440 | if (beacon_configured) { | |
d2182b69 | 441 | ath_dbg(common, CONFIG, |
e7a2a4f5 SM |
442 | "Beacon already configured for a station interface\n"); |
443 | return false; | |
444 | } | |
a5fae37d SM |
445 | } |
446 | ||
e7a2a4f5 SM |
447 | return true; |
448 | } | |
449 | ||
450 | void ath9k_htc_beacon_config(struct ath9k_htc_priv *priv, | |
451 | struct ieee80211_vif *vif) | |
452 | { | |
453 | struct ath_common *common = ath9k_hw_common(priv->ah); | |
3c4816d9 | 454 | struct ath_beacon_config *cur_conf = &priv->cur_beacon_conf; |
e7a2a4f5 SM |
455 | struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; |
456 | struct ath9k_htc_vif *avp = (struct ath9k_htc_vif *) vif->drv_priv; | |
457 | ||
458 | if (!ath9k_htc_check_beacon_config(priv, vif)) | |
459 | return; | |
460 | ||
fcb9392f | 461 | cur_conf->beacon_interval = bss_conf->beacon_int; |
1c3652a5 VN |
462 | if (cur_conf->beacon_interval == 0) |
463 | cur_conf->beacon_interval = 100; | |
464 | ||
fcb9392f | 465 | cur_conf->dtim_period = bss_conf->dtim_period; |
fcb9392f S |
466 | cur_conf->bmiss_timeout = |
467 | ATH_DEFAULT_BMISS_LIMIT * cur_conf->beacon_interval; | |
468 | ||
469 | switch (vif->type) { | |
fb9987d0 | 470 | case NL80211_IFTYPE_STATION: |
1c3652a5 | 471 | ath9k_htc_beacon_config_sta(priv, cur_conf); |
e7a2a4f5 | 472 | avp->beacon_configured = true; |
fb9987d0 S |
473 | break; |
474 | case NL80211_IFTYPE_ADHOC: | |
1c3652a5 | 475 | ath9k_htc_beacon_config_adhoc(priv, cur_conf); |
fb9987d0 | 476 | break; |
594e65b6 | 477 | case NL80211_IFTYPE_MESH_POINT: |
a5fae37d SM |
478 | case NL80211_IFTYPE_AP: |
479 | ath9k_htc_beacon_config_ap(priv, cur_conf); | |
480 | break; | |
fb9987d0 | 481 | default: |
d2182b69 | 482 | ath_dbg(common, CONFIG, "Unsupported beaconing mode\n"); |
fb9987d0 S |
483 | return; |
484 | } | |
485 | } | |
7c277349 SM |
486 | |
487 | void ath9k_htc_beacon_reconfig(struct ath9k_htc_priv *priv) | |
488 | { | |
489 | struct ath_common *common = ath9k_hw_common(priv->ah); | |
3c4816d9 | 490 | struct ath_beacon_config *cur_conf = &priv->cur_beacon_conf; |
7c277349 SM |
491 | |
492 | switch (priv->ah->opmode) { | |
493 | case NL80211_IFTYPE_STATION: | |
494 | ath9k_htc_beacon_config_sta(priv, cur_conf); | |
495 | break; | |
496 | case NL80211_IFTYPE_ADHOC: | |
497 | ath9k_htc_beacon_config_adhoc(priv, cur_conf); | |
498 | break; | |
594e65b6 | 499 | case NL80211_IFTYPE_MESH_POINT: |
a5fae37d SM |
500 | case NL80211_IFTYPE_AP: |
501 | ath9k_htc_beacon_config_ap(priv, cur_conf); | |
502 | break; | |
7c277349 | 503 | default: |
d2182b69 | 504 | ath_dbg(common, CONFIG, "Unsupported beaconing mode\n"); |
7c277349 SM |
505 | return; |
506 | } | |
507 | } | |
f0e44962 CYY |
508 | |
509 | bool ath9k_htc_csa_is_finished(struct ath9k_htc_priv *priv) | |
510 | { | |
511 | struct ieee80211_vif *vif; | |
512 | ||
513 | vif = priv->csa_vif; | |
514 | if (!vif || !vif->csa_active) | |
515 | return false; | |
516 | ||
517 | if (!ieee80211_csa_is_complete(vif)) | |
518 | return false; | |
519 | ||
520 | ieee80211_csa_finish(vif); | |
521 | ||
522 | priv->csa_vif = NULL; | |
523 | return true; | |
524 | } |