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 | */ | |
48 | if (ah->slottime == ATH9K_SLOT_TIME_20) | |
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); | |
260 | } | |
261 | ||
f4c88991 SM |
262 | static int ath9k_htc_choose_bslot(struct ath9k_htc_priv *priv, |
263 | struct wmi_event_swba *swba) | |
832f6a18 SM |
264 | { |
265 | struct ath_common *common = ath9k_hw_common(priv->ah); | |
832f6a18 SM |
266 | u64 tsf; |
267 | u32 tsftu; | |
268 | u16 intval; | |
269 | int slot; | |
270 | ||
f29f5c08 | 271 | intval = priv->cur_beacon_conf.beacon_interval; |
832f6a18 | 272 | |
f4c88991 | 273 | tsf = be64_to_cpu(swba->tsf); |
832f6a18 SM |
274 | tsftu = TSF_TO_TU(tsf >> 32, tsf); |
275 | slot = ((tsftu % intval) * ATH9K_HTC_MAX_BCN_VIF) / intval; | |
276 | slot = ATH9K_HTC_MAX_BCN_VIF - slot - 1; | |
277 | ||
d2182b69 | 278 | ath_dbg(common, BEACON, |
832f6a18 SM |
279 | "Choose slot: %d, tsf: %llu, tsftu: %u, intval: %u\n", |
280 | slot, tsf, tsftu, intval); | |
281 | ||
282 | return slot; | |
283 | } | |
284 | ||
f4c88991 SM |
285 | void ath9k_htc_swba(struct ath9k_htc_priv *priv, |
286 | struct wmi_event_swba *swba) | |
832f6a18 SM |
287 | { |
288 | struct ath_common *common = ath9k_hw_common(priv->ah); | |
832f6a18 SM |
289 | int slot; |
290 | ||
f4c88991 | 291 | if (swba->beacon_pending != 0) { |
3c4816d9 OR |
292 | priv->beacon.bmisscnt++; |
293 | if (priv->beacon.bmisscnt > BSTUCK_THRESHOLD) { | |
d2182b69 | 294 | ath_dbg(common, BSTUCK, "Beacon stuck, HW reset\n"); |
f4c88991 SM |
295 | ieee80211_queue_work(priv->hw, |
296 | &priv->fatal_work); | |
832f6a18 SM |
297 | } |
298 | return; | |
299 | } | |
832f6a18 | 300 | |
3c4816d9 | 301 | if (priv->beacon.bmisscnt) { |
d2182b69 | 302 | ath_dbg(common, BSTUCK, |
832f6a18 | 303 | "Resuming beacon xmit after %u misses\n", |
3c4816d9 OR |
304 | priv->beacon.bmisscnt); |
305 | priv->beacon.bmisscnt = 0; | |
832f6a18 SM |
306 | } |
307 | ||
f4c88991 | 308 | slot = ath9k_htc_choose_bslot(priv, swba); |
832f6a18 | 309 | spin_lock_bh(&priv->beacon_lock); |
3c4816d9 | 310 | if (priv->beacon.bslot[slot] == NULL) { |
832f6a18 SM |
311 | spin_unlock_bh(&priv->beacon_lock); |
312 | return; | |
313 | } | |
314 | spin_unlock_bh(&priv->beacon_lock); | |
315 | ||
7d547eb4 | 316 | ath9k_htc_send_buffered(priv, slot); |
832f6a18 SM |
317 | ath9k_htc_send_beacon(priv, slot); |
318 | } | |
319 | ||
832f6a18 SM |
320 | void ath9k_htc_assign_bslot(struct ath9k_htc_priv *priv, |
321 | struct ieee80211_vif *vif) | |
322 | { | |
323 | struct ath_common *common = ath9k_hw_common(priv->ah); | |
324 | struct ath9k_htc_vif *avp = (struct ath9k_htc_vif *)vif->drv_priv; | |
325 | int i = 0; | |
326 | ||
327 | spin_lock_bh(&priv->beacon_lock); | |
328 | for (i = 0; i < ATH9K_HTC_MAX_BCN_VIF; i++) { | |
3c4816d9 | 329 | if (priv->beacon.bslot[i] == NULL) { |
832f6a18 SM |
330 | avp->bslot = i; |
331 | break; | |
332 | } | |
333 | } | |
334 | ||
3c4816d9 | 335 | priv->beacon.bslot[avp->bslot] = vif; |
832f6a18 SM |
336 | spin_unlock_bh(&priv->beacon_lock); |
337 | ||
d2182b69 JP |
338 | ath_dbg(common, CONFIG, "Added interface at beacon slot: %d\n", |
339 | avp->bslot); | |
832f6a18 SM |
340 | } |
341 | ||
342 | void ath9k_htc_remove_bslot(struct ath9k_htc_priv *priv, | |
343 | struct ieee80211_vif *vif) | |
344 | { | |
345 | struct ath_common *common = ath9k_hw_common(priv->ah); | |
346 | struct ath9k_htc_vif *avp = (struct ath9k_htc_vif *)vif->drv_priv; | |
347 | ||
348 | spin_lock_bh(&priv->beacon_lock); | |
3c4816d9 | 349 | priv->beacon.bslot[avp->bslot] = NULL; |
832f6a18 SM |
350 | spin_unlock_bh(&priv->beacon_lock); |
351 | ||
d2182b69 JP |
352 | ath_dbg(common, CONFIG, "Removed interface at beacon slot: %d\n", |
353 | avp->bslot); | |
832f6a18 SM |
354 | } |
355 | ||
9b674a02 SM |
356 | /* |
357 | * Calculate the TSF adjustment value for all slots | |
358 | * other than zero. | |
359 | */ | |
360 | void ath9k_htc_set_tsfadjust(struct ath9k_htc_priv *priv, | |
361 | struct ieee80211_vif *vif) | |
362 | { | |
363 | struct ath_common *common = ath9k_hw_common(priv->ah); | |
364 | struct ath9k_htc_vif *avp = (struct ath9k_htc_vif *)vif->drv_priv; | |
3c4816d9 | 365 | struct ath_beacon_config *cur_conf = &priv->cur_beacon_conf; |
9b674a02 SM |
366 | u64 tsfadjust; |
367 | ||
368 | if (avp->bslot == 0) | |
369 | return; | |
370 | ||
371 | /* | |
372 | * The beacon interval cannot be different for multi-AP mode, | |
373 | * and we reach here only for VIF slots greater than zero, | |
374 | * so beacon_interval is guaranteed to be set in cur_conf. | |
375 | */ | |
376 | tsfadjust = cur_conf->beacon_interval * avp->bslot / ATH9K_HTC_MAX_BCN_VIF; | |
377 | avp->tsfadjust = cpu_to_le64(TU_TO_USEC(tsfadjust)); | |
378 | ||
d2182b69 | 379 | ath_dbg(common, CONFIG, "tsfadjust is: %llu for bslot: %d\n", |
9b674a02 SM |
380 | (unsigned long long)tsfadjust, avp->bslot); |
381 | } | |
382 | ||
e7a2a4f5 SM |
383 | static void ath9k_htc_beacon_iter(void *data, u8 *mac, struct ieee80211_vif *vif) |
384 | { | |
385 | bool *beacon_configured = (bool *)data; | |
386 | struct ath9k_htc_vif *avp = (struct ath9k_htc_vif *) vif->drv_priv; | |
387 | ||
388 | if (vif->type == NL80211_IFTYPE_STATION && | |
389 | avp->beacon_configured) | |
390 | *beacon_configured = true; | |
391 | } | |
392 | ||
393 | static bool ath9k_htc_check_beacon_config(struct ath9k_htc_priv *priv, | |
394 | struct ieee80211_vif *vif) | |
fb9987d0 S |
395 | { |
396 | struct ath_common *common = ath9k_hw_common(priv->ah); | |
3c4816d9 | 397 | struct ath_beacon_config *cur_conf = &priv->cur_beacon_conf; |
fcb9392f | 398 | struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; |
e7a2a4f5 | 399 | bool beacon_configured; |
1c3652a5 | 400 | |
a5fae37d SM |
401 | /* |
402 | * Changing the beacon interval when multiple AP interfaces | |
403 | * are configured will affect beacon transmission of all | |
404 | * of them. | |
405 | */ | |
406 | if ((priv->ah->opmode == NL80211_IFTYPE_AP) && | |
407 | (priv->num_ap_vif > 1) && | |
408 | (vif->type == NL80211_IFTYPE_AP) && | |
409 | (cur_conf->beacon_interval != bss_conf->beacon_int)) { | |
d2182b69 | 410 | ath_dbg(common, CONFIG, |
a5fae37d | 411 | "Changing beacon interval of multiple AP interfaces !\n"); |
e7a2a4f5 | 412 | return false; |
a5fae37d SM |
413 | } |
414 | ||
415 | /* | |
416 | * If the HW is operating in AP mode, any new station interfaces that | |
417 | * are added cannot change the beacon parameters. | |
418 | */ | |
419 | if (priv->num_ap_vif && | |
420 | (vif->type != NL80211_IFTYPE_AP)) { | |
d2182b69 | 421 | ath_dbg(common, CONFIG, |
a5fae37d | 422 | "HW in AP mode, cannot set STA beacon parameters\n"); |
e7a2a4f5 SM |
423 | return false; |
424 | } | |
425 | ||
426 | /* | |
427 | * The beacon parameters are configured only for the first | |
428 | * station interface. | |
429 | */ | |
430 | if ((priv->ah->opmode == NL80211_IFTYPE_STATION) && | |
431 | (priv->num_sta_vif > 1) && | |
432 | (vif->type == NL80211_IFTYPE_STATION)) { | |
433 | beacon_configured = false; | |
8b2c9824 JB |
434 | ieee80211_iterate_active_interfaces_atomic( |
435 | priv->hw, IEEE80211_IFACE_ITER_RESUME_ALL, | |
436 | ath9k_htc_beacon_iter, &beacon_configured); | |
e7a2a4f5 SM |
437 | |
438 | if (beacon_configured) { | |
d2182b69 | 439 | ath_dbg(common, CONFIG, |
e7a2a4f5 SM |
440 | "Beacon already configured for a station interface\n"); |
441 | return false; | |
442 | } | |
a5fae37d SM |
443 | } |
444 | ||
e7a2a4f5 SM |
445 | return true; |
446 | } | |
447 | ||
448 | void ath9k_htc_beacon_config(struct ath9k_htc_priv *priv, | |
449 | struct ieee80211_vif *vif) | |
450 | { | |
451 | struct ath_common *common = ath9k_hw_common(priv->ah); | |
3c4816d9 | 452 | struct ath_beacon_config *cur_conf = &priv->cur_beacon_conf; |
e7a2a4f5 SM |
453 | struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; |
454 | struct ath9k_htc_vif *avp = (struct ath9k_htc_vif *) vif->drv_priv; | |
455 | ||
456 | if (!ath9k_htc_check_beacon_config(priv, vif)) | |
457 | return; | |
458 | ||
fcb9392f | 459 | cur_conf->beacon_interval = bss_conf->beacon_int; |
1c3652a5 VN |
460 | if (cur_conf->beacon_interval == 0) |
461 | cur_conf->beacon_interval = 100; | |
462 | ||
fcb9392f | 463 | cur_conf->dtim_period = bss_conf->dtim_period; |
fcb9392f S |
464 | cur_conf->bmiss_timeout = |
465 | ATH_DEFAULT_BMISS_LIMIT * cur_conf->beacon_interval; | |
466 | ||
467 | switch (vif->type) { | |
fb9987d0 | 468 | case NL80211_IFTYPE_STATION: |
1c3652a5 | 469 | ath9k_htc_beacon_config_sta(priv, cur_conf); |
e7a2a4f5 | 470 | avp->beacon_configured = true; |
fb9987d0 S |
471 | break; |
472 | case NL80211_IFTYPE_ADHOC: | |
1c3652a5 | 473 | ath9k_htc_beacon_config_adhoc(priv, cur_conf); |
fb9987d0 | 474 | break; |
594e65b6 | 475 | case NL80211_IFTYPE_MESH_POINT: |
a5fae37d SM |
476 | case NL80211_IFTYPE_AP: |
477 | ath9k_htc_beacon_config_ap(priv, cur_conf); | |
478 | break; | |
fb9987d0 | 479 | default: |
d2182b69 | 480 | ath_dbg(common, CONFIG, "Unsupported beaconing mode\n"); |
fb9987d0 S |
481 | return; |
482 | } | |
483 | } | |
7c277349 SM |
484 | |
485 | void ath9k_htc_beacon_reconfig(struct ath9k_htc_priv *priv) | |
486 | { | |
487 | struct ath_common *common = ath9k_hw_common(priv->ah); | |
3c4816d9 | 488 | struct ath_beacon_config *cur_conf = &priv->cur_beacon_conf; |
7c277349 SM |
489 | |
490 | switch (priv->ah->opmode) { | |
491 | case NL80211_IFTYPE_STATION: | |
492 | ath9k_htc_beacon_config_sta(priv, cur_conf); | |
493 | break; | |
494 | case NL80211_IFTYPE_ADHOC: | |
495 | ath9k_htc_beacon_config_adhoc(priv, cur_conf); | |
496 | break; | |
594e65b6 | 497 | case NL80211_IFTYPE_MESH_POINT: |
a5fae37d SM |
498 | case NL80211_IFTYPE_AP: |
499 | ath9k_htc_beacon_config_ap(priv, cur_conf); | |
500 | break; | |
7c277349 | 501 | default: |
d2182b69 | 502 | ath_dbg(common, CONFIG, "Unsupported beaconing mode\n"); |
7c277349 SM |
503 | return; |
504 | } | |
505 | } |