diff options
Diffstat (limited to 'drivers/net/wireless/ath/ath9k/htc_drv_main.c')
-rw-r--r-- | drivers/net/wireless/ath/ath9k/htc_drv_main.c | 485 |
1 files changed, 331 insertions, 154 deletions
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index 6bb59958f71e..db8c0c044e9e 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c | |||
@@ -24,17 +24,6 @@ static struct dentry *ath9k_debugfs_root; | |||
24 | /* Utilities */ | 24 | /* Utilities */ |
25 | /*************/ | 25 | /*************/ |
26 | 26 | ||
27 | void ath_update_txpow(struct ath9k_htc_priv *priv) | ||
28 | { | ||
29 | struct ath_hw *ah = priv->ah; | ||
30 | |||
31 | if (priv->curtxpow != priv->txpowlimit) { | ||
32 | ath9k_hw_set_txpowerlimit(ah, priv->txpowlimit, false); | ||
33 | /* read back in case value is clamped */ | ||
34 | priv->curtxpow = ath9k_hw_regulatory(ah)->power_limit; | ||
35 | } | ||
36 | } | ||
37 | |||
38 | /* HACK Alert: Use 11NG for 2.4, use 11NA for 5 */ | 27 | /* HACK Alert: Use 11NG for 2.4, use 11NA for 5 */ |
39 | static enum htc_phymode ath9k_htc_get_curmode(struct ath9k_htc_priv *priv, | 28 | static enum htc_phymode ath9k_htc_get_curmode(struct ath9k_htc_priv *priv, |
40 | struct ath9k_channel *ichan) | 29 | struct ath9k_channel *ichan) |
@@ -116,12 +105,88 @@ void ath9k_ps_work(struct work_struct *work) | |||
116 | ath9k_htc_setpower(priv, ATH9K_PM_NETWORK_SLEEP); | 105 | ath9k_htc_setpower(priv, ATH9K_PM_NETWORK_SLEEP); |
117 | } | 106 | } |
118 | 107 | ||
108 | static void ath9k_htc_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif) | ||
109 | { | ||
110 | struct ath9k_htc_priv *priv = data; | ||
111 | struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; | ||
112 | |||
113 | if ((vif->type == NL80211_IFTYPE_AP) && bss_conf->enable_beacon) | ||
114 | priv->reconfig_beacon = true; | ||
115 | |||
116 | if (bss_conf->assoc) { | ||
117 | priv->rearm_ani = true; | ||
118 | priv->reconfig_beacon = true; | ||
119 | } | ||
120 | } | ||
121 | |||
122 | static void ath9k_htc_vif_reconfig(struct ath9k_htc_priv *priv) | ||
123 | { | ||
124 | priv->rearm_ani = false; | ||
125 | priv->reconfig_beacon = false; | ||
126 | |||
127 | ieee80211_iterate_active_interfaces_atomic(priv->hw, | ||
128 | ath9k_htc_vif_iter, priv); | ||
129 | if (priv->rearm_ani) | ||
130 | ath9k_htc_start_ani(priv); | ||
131 | |||
132 | if (priv->reconfig_beacon) { | ||
133 | ath9k_htc_ps_wakeup(priv); | ||
134 | ath9k_htc_beacon_reconfig(priv); | ||
135 | ath9k_htc_ps_restore(priv); | ||
136 | } | ||
137 | } | ||
138 | |||
139 | static void ath9k_htc_bssid_iter(void *data, u8 *mac, struct ieee80211_vif *vif) | ||
140 | { | ||
141 | struct ath9k_vif_iter_data *iter_data = data; | ||
142 | int i; | ||
143 | |||
144 | for (i = 0; i < ETH_ALEN; i++) | ||
145 | iter_data->mask[i] &= ~(iter_data->hw_macaddr[i] ^ mac[i]); | ||
146 | } | ||
147 | |||
148 | static void ath9k_htc_set_bssid_mask(struct ath9k_htc_priv *priv, | ||
149 | struct ieee80211_vif *vif) | ||
150 | { | ||
151 | struct ath_common *common = ath9k_hw_common(priv->ah); | ||
152 | struct ath9k_vif_iter_data iter_data; | ||
153 | |||
154 | /* | ||
155 | * Use the hardware MAC address as reference, the hardware uses it | ||
156 | * together with the BSSID mask when matching addresses. | ||
157 | */ | ||
158 | iter_data.hw_macaddr = common->macaddr; | ||
159 | memset(&iter_data.mask, 0xff, ETH_ALEN); | ||
160 | |||
161 | if (vif) | ||
162 | ath9k_htc_bssid_iter(&iter_data, vif->addr, vif); | ||
163 | |||
164 | /* Get list of all active MAC addresses */ | ||
165 | ieee80211_iterate_active_interfaces_atomic(priv->hw, ath9k_htc_bssid_iter, | ||
166 | &iter_data); | ||
167 | |||
168 | memcpy(common->bssidmask, iter_data.mask, ETH_ALEN); | ||
169 | ath_hw_setbssidmask(common); | ||
170 | } | ||
171 | |||
172 | static void ath9k_htc_set_opmode(struct ath9k_htc_priv *priv) | ||
173 | { | ||
174 | if (priv->num_ibss_vif) | ||
175 | priv->ah->opmode = NL80211_IFTYPE_ADHOC; | ||
176 | else if (priv->num_ap_vif) | ||
177 | priv->ah->opmode = NL80211_IFTYPE_AP; | ||
178 | else | ||
179 | priv->ah->opmode = NL80211_IFTYPE_STATION; | ||
180 | |||
181 | ath9k_hw_setopmode(priv->ah); | ||
182 | } | ||
183 | |||
119 | void ath9k_htc_reset(struct ath9k_htc_priv *priv) | 184 | void ath9k_htc_reset(struct ath9k_htc_priv *priv) |
120 | { | 185 | { |
121 | struct ath_hw *ah = priv->ah; | 186 | struct ath_hw *ah = priv->ah; |
122 | struct ath_common *common = ath9k_hw_common(ah); | 187 | struct ath_common *common = ath9k_hw_common(ah); |
123 | struct ieee80211_channel *channel = priv->hw->conf.channel; | 188 | struct ieee80211_channel *channel = priv->hw->conf.channel; |
124 | struct ath9k_hw_cal_data *caldata; | 189 | struct ath9k_hw_cal_data *caldata = NULL; |
125 | enum htc_phymode mode; | 190 | enum htc_phymode mode; |
126 | __be16 htc_mode; | 191 | __be16 htc_mode; |
127 | u8 cmd_rsp; | 192 | u8 cmd_rsp; |
@@ -130,16 +195,14 @@ void ath9k_htc_reset(struct ath9k_htc_priv *priv) | |||
130 | mutex_lock(&priv->mutex); | 195 | mutex_lock(&priv->mutex); |
131 | ath9k_htc_ps_wakeup(priv); | 196 | ath9k_htc_ps_wakeup(priv); |
132 | 197 | ||
133 | if (priv->op_flags & OP_ASSOCIATED) | 198 | ath9k_htc_stop_ani(priv); |
134 | cancel_delayed_work_sync(&priv->ath9k_ani_work); | ||
135 | |||
136 | ieee80211_stop_queues(priv->hw); | 199 | ieee80211_stop_queues(priv->hw); |
137 | htc_stop(priv->htc); | 200 | htc_stop(priv->htc); |
138 | WMI_CMD(WMI_DISABLE_INTR_CMDID); | 201 | WMI_CMD(WMI_DISABLE_INTR_CMDID); |
139 | WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID); | 202 | WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID); |
140 | WMI_CMD(WMI_STOP_RECV_CMDID); | 203 | WMI_CMD(WMI_STOP_RECV_CMDID); |
141 | 204 | ||
142 | caldata = &priv->caldata[channel->hw_value]; | 205 | caldata = &priv->caldata; |
143 | ret = ath9k_hw_reset(ah, ah->curchan, caldata, false); | 206 | ret = ath9k_hw_reset(ah, ah->curchan, caldata, false); |
144 | if (ret) { | 207 | if (ret) { |
145 | ath_err(common, | 208 | ath_err(common, |
@@ -147,7 +210,8 @@ void ath9k_htc_reset(struct ath9k_htc_priv *priv) | |||
147 | channel->center_freq, ret); | 210 | channel->center_freq, ret); |
148 | } | 211 | } |
149 | 212 | ||
150 | ath_update_txpow(priv); | 213 | ath9k_cmn_update_txpow(ah, priv->curtxpow, priv->txpowlimit, |
214 | &priv->curtxpow); | ||
151 | 215 | ||
152 | WMI_CMD(WMI_START_RECV_CMDID); | 216 | WMI_CMD(WMI_START_RECV_CMDID); |
153 | ath9k_host_rx_init(priv); | 217 | ath9k_host_rx_init(priv); |
@@ -158,12 +222,7 @@ void ath9k_htc_reset(struct ath9k_htc_priv *priv) | |||
158 | 222 | ||
159 | WMI_CMD(WMI_ENABLE_INTR_CMDID); | 223 | WMI_CMD(WMI_ENABLE_INTR_CMDID); |
160 | htc_start(priv->htc); | 224 | htc_start(priv->htc); |
161 | 225 | ath9k_htc_vif_reconfig(priv); | |
162 | if (priv->op_flags & OP_ASSOCIATED) { | ||
163 | ath9k_htc_beacon_config(priv, priv->vif); | ||
164 | ath_start_ani(priv); | ||
165 | } | ||
166 | |||
167 | ieee80211_wake_queues(priv->hw); | 226 | ieee80211_wake_queues(priv->hw); |
168 | 227 | ||
169 | ath9k_htc_ps_restore(priv); | 228 | ath9k_htc_ps_restore(priv); |
@@ -179,7 +238,7 @@ static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv, | |||
179 | struct ieee80211_conf *conf = &common->hw->conf; | 238 | struct ieee80211_conf *conf = &common->hw->conf; |
180 | bool fastcc; | 239 | bool fastcc; |
181 | struct ieee80211_channel *channel = hw->conf.channel; | 240 | struct ieee80211_channel *channel = hw->conf.channel; |
182 | struct ath9k_hw_cal_data *caldata; | 241 | struct ath9k_hw_cal_data *caldata = NULL; |
183 | enum htc_phymode mode; | 242 | enum htc_phymode mode; |
184 | __be16 htc_mode; | 243 | __be16 htc_mode; |
185 | u8 cmd_rsp; | 244 | u8 cmd_rsp; |
@@ -202,7 +261,8 @@ static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv, | |||
202 | channel->center_freq, conf_is_ht(conf), conf_is_ht40(conf), | 261 | channel->center_freq, conf_is_ht(conf), conf_is_ht40(conf), |
203 | fastcc); | 262 | fastcc); |
204 | 263 | ||
205 | caldata = &priv->caldata[channel->hw_value]; | 264 | if (!fastcc) |
265 | caldata = &priv->caldata; | ||
206 | ret = ath9k_hw_reset(ah, hchan, caldata, fastcc); | 266 | ret = ath9k_hw_reset(ah, hchan, caldata, fastcc); |
207 | if (ret) { | 267 | if (ret) { |
208 | ath_err(common, | 268 | ath_err(common, |
@@ -211,7 +271,8 @@ static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv, | |||
211 | goto err; | 271 | goto err; |
212 | } | 272 | } |
213 | 273 | ||
214 | ath_update_txpow(priv); | 274 | ath9k_cmn_update_txpow(ah, priv->curtxpow, priv->txpowlimit, |
275 | &priv->curtxpow); | ||
215 | 276 | ||
216 | WMI_CMD(WMI_START_RECV_CMDID); | 277 | WMI_CMD(WMI_START_RECV_CMDID); |
217 | if (ret) | 278 | if (ret) |
@@ -230,11 +291,23 @@ static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv, | |||
230 | goto err; | 291 | goto err; |
231 | 292 | ||
232 | htc_start(priv->htc); | 293 | htc_start(priv->htc); |
294 | |||
295 | if (!(priv->op_flags & OP_SCANNING) && | ||
296 | !(hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)) | ||
297 | ath9k_htc_vif_reconfig(priv); | ||
298 | |||
233 | err: | 299 | err: |
234 | ath9k_htc_ps_restore(priv); | 300 | ath9k_htc_ps_restore(priv); |
235 | return ret; | 301 | return ret; |
236 | } | 302 | } |
237 | 303 | ||
304 | /* | ||
305 | * Monitor mode handling is a tad complicated because the firmware requires | ||
306 | * an interface to be created exclusively, while mac80211 doesn't associate | ||
307 | * an interface with the mode. | ||
308 | * | ||
309 | * So, for now, only one monitor interface can be configured. | ||
310 | */ | ||
238 | static void __ath9k_htc_remove_monitor_interface(struct ath9k_htc_priv *priv) | 311 | static void __ath9k_htc_remove_monitor_interface(struct ath9k_htc_priv *priv) |
239 | { | 312 | { |
240 | struct ath_common *common = ath9k_hw_common(priv->ah); | 313 | struct ath_common *common = ath9k_hw_common(priv->ah); |
@@ -244,9 +317,10 @@ static void __ath9k_htc_remove_monitor_interface(struct ath9k_htc_priv *priv) | |||
244 | 317 | ||
245 | memset(&hvif, 0, sizeof(struct ath9k_htc_target_vif)); | 318 | memset(&hvif, 0, sizeof(struct ath9k_htc_target_vif)); |
246 | memcpy(&hvif.myaddr, common->macaddr, ETH_ALEN); | 319 | memcpy(&hvif.myaddr, common->macaddr, ETH_ALEN); |
247 | hvif.index = 0; /* Should do for now */ | 320 | hvif.index = priv->mon_vif_idx; |
248 | WMI_CMD_BUF(WMI_VAP_REMOVE_CMDID, &hvif); | 321 | WMI_CMD_BUF(WMI_VAP_REMOVE_CMDID, &hvif); |
249 | priv->nvifs--; | 322 | priv->nvifs--; |
323 | priv->vif_slot &= ~(1 << priv->mon_vif_idx); | ||
250 | } | 324 | } |
251 | 325 | ||
252 | static int ath9k_htc_add_monitor_interface(struct ath9k_htc_priv *priv) | 326 | static int ath9k_htc_add_monitor_interface(struct ath9k_htc_priv *priv) |
@@ -254,70 +328,87 @@ static int ath9k_htc_add_monitor_interface(struct ath9k_htc_priv *priv) | |||
254 | struct ath_common *common = ath9k_hw_common(priv->ah); | 328 | struct ath_common *common = ath9k_hw_common(priv->ah); |
255 | struct ath9k_htc_target_vif hvif; | 329 | struct ath9k_htc_target_vif hvif; |
256 | struct ath9k_htc_target_sta tsta; | 330 | struct ath9k_htc_target_sta tsta; |
257 | int ret = 0; | 331 | int ret = 0, sta_idx; |
258 | u8 cmd_rsp; | 332 | u8 cmd_rsp; |
259 | 333 | ||
260 | if (priv->nvifs > 0) | 334 | if ((priv->nvifs >= ATH9K_HTC_MAX_VIF) || |
261 | return -ENOBUFS; | 335 | (priv->nstations >= ATH9K_HTC_MAX_STA)) { |
336 | ret = -ENOBUFS; | ||
337 | goto err_vif; | ||
338 | } | ||
262 | 339 | ||
263 | if (priv->nstations >= ATH9K_HTC_MAX_STA) | 340 | sta_idx = ffz(priv->sta_slot); |
264 | return -ENOBUFS; | 341 | if ((sta_idx < 0) || (sta_idx > ATH9K_HTC_MAX_STA)) { |
342 | ret = -ENOBUFS; | ||
343 | goto err_vif; | ||
344 | } | ||
265 | 345 | ||
266 | /* | 346 | /* |
267 | * Add an interface. | 347 | * Add an interface. |
268 | */ | 348 | */ |
269 | |||
270 | memset(&hvif, 0, sizeof(struct ath9k_htc_target_vif)); | 349 | memset(&hvif, 0, sizeof(struct ath9k_htc_target_vif)); |
271 | memcpy(&hvif.myaddr, common->macaddr, ETH_ALEN); | 350 | memcpy(&hvif.myaddr, common->macaddr, ETH_ALEN); |
272 | 351 | ||
273 | hvif.opmode = cpu_to_be32(HTC_M_MONITOR); | 352 | hvif.opmode = cpu_to_be32(HTC_M_MONITOR); |
274 | priv->ah->opmode = NL80211_IFTYPE_MONITOR; | 353 | hvif.index = ffz(priv->vif_slot); |
275 | hvif.index = priv->nvifs; | ||
276 | 354 | ||
277 | WMI_CMD_BUF(WMI_VAP_CREATE_CMDID, &hvif); | 355 | WMI_CMD_BUF(WMI_VAP_CREATE_CMDID, &hvif); |
278 | if (ret) | 356 | if (ret) |
279 | return ret; | 357 | goto err_vif; |
358 | |||
359 | /* | ||
360 | * Assign the monitor interface index as a special case here. | ||
361 | * This is needed when the interface is brought down. | ||
362 | */ | ||
363 | priv->mon_vif_idx = hvif.index; | ||
364 | priv->vif_slot |= (1 << hvif.index); | ||
365 | |||
366 | /* | ||
367 | * Set the hardware mode to monitor only if there are no | ||
368 | * other interfaces. | ||
369 | */ | ||
370 | if (!priv->nvifs) | ||
371 | priv->ah->opmode = NL80211_IFTYPE_MONITOR; | ||
280 | 372 | ||
281 | priv->nvifs++; | 373 | priv->nvifs++; |
282 | 374 | ||
283 | /* | 375 | /* |
284 | * Associate a station with the interface for packet injection. | 376 | * Associate a station with the interface for packet injection. |
285 | */ | 377 | */ |
286 | |||
287 | memset(&tsta, 0, sizeof(struct ath9k_htc_target_sta)); | 378 | memset(&tsta, 0, sizeof(struct ath9k_htc_target_sta)); |
288 | 379 | ||
289 | memcpy(&tsta.macaddr, common->macaddr, ETH_ALEN); | 380 | memcpy(&tsta.macaddr, common->macaddr, ETH_ALEN); |
290 | 381 | ||
291 | tsta.is_vif_sta = 1; | 382 | tsta.is_vif_sta = 1; |
292 | tsta.sta_index = priv->nstations; | 383 | tsta.sta_index = sta_idx; |
293 | tsta.vif_index = hvif.index; | 384 | tsta.vif_index = hvif.index; |
294 | tsta.maxampdu = 0xffff; | 385 | tsta.maxampdu = 0xffff; |
295 | 386 | ||
296 | WMI_CMD_BUF(WMI_NODE_CREATE_CMDID, &tsta); | 387 | WMI_CMD_BUF(WMI_NODE_CREATE_CMDID, &tsta); |
297 | if (ret) { | 388 | if (ret) { |
298 | ath_err(common, "Unable to add station entry for monitor mode\n"); | 389 | ath_err(common, "Unable to add station entry for monitor mode\n"); |
299 | goto err_vif; | 390 | goto err_sta; |
300 | } | 391 | } |
301 | 392 | ||
393 | priv->sta_slot |= (1 << sta_idx); | ||
302 | priv->nstations++; | 394 | priv->nstations++; |
303 | 395 | priv->vif_sta_pos[priv->mon_vif_idx] = sta_idx; | |
304 | /* | ||
305 | * Set chainmask etc. on the target. | ||
306 | */ | ||
307 | ret = ath9k_htc_update_cap_target(priv); | ||
308 | if (ret) | ||
309 | ath_dbg(common, ATH_DBG_CONFIG, | ||
310 | "Failed to update capability in target\n"); | ||
311 | |||
312 | priv->ah->is_monitoring = true; | 396 | priv->ah->is_monitoring = true; |
313 | 397 | ||
398 | ath_dbg(common, ATH_DBG_CONFIG, | ||
399 | "Attached a monitor interface at idx: %d, sta idx: %d\n", | ||
400 | priv->mon_vif_idx, sta_idx); | ||
401 | |||
314 | return 0; | 402 | return 0; |
315 | 403 | ||
316 | err_vif: | 404 | err_sta: |
317 | /* | 405 | /* |
318 | * Remove the interface from the target. | 406 | * Remove the interface from the target. |
319 | */ | 407 | */ |
320 | __ath9k_htc_remove_monitor_interface(priv); | 408 | __ath9k_htc_remove_monitor_interface(priv); |
409 | err_vif: | ||
410 | ath_dbg(common, ATH_DBG_FATAL, "Unable to attach a monitor interface\n"); | ||
411 | |||
321 | return ret; | 412 | return ret; |
322 | } | 413 | } |
323 | 414 | ||
@@ -329,7 +420,7 @@ static int ath9k_htc_remove_monitor_interface(struct ath9k_htc_priv *priv) | |||
329 | 420 | ||
330 | __ath9k_htc_remove_monitor_interface(priv); | 421 | __ath9k_htc_remove_monitor_interface(priv); |
331 | 422 | ||
332 | sta_idx = 0; /* Only single interface, for now */ | 423 | sta_idx = priv->vif_sta_pos[priv->mon_vif_idx]; |
333 | 424 | ||
334 | WMI_CMD_BUF(WMI_NODE_REMOVE_CMDID, &sta_idx); | 425 | WMI_CMD_BUF(WMI_NODE_REMOVE_CMDID, &sta_idx); |
335 | if (ret) { | 426 | if (ret) { |
@@ -337,9 +428,14 @@ static int ath9k_htc_remove_monitor_interface(struct ath9k_htc_priv *priv) | |||
337 | return ret; | 428 | return ret; |
338 | } | 429 | } |
339 | 430 | ||
431 | priv->sta_slot &= ~(1 << sta_idx); | ||
340 | priv->nstations--; | 432 | priv->nstations--; |
341 | priv->ah->is_monitoring = false; | 433 | priv->ah->is_monitoring = false; |
342 | 434 | ||
435 | ath_dbg(common, ATH_DBG_CONFIG, | ||
436 | "Removed a monitor interface at idx: %d, sta idx: %d\n", | ||
437 | priv->mon_vif_idx, sta_idx); | ||
438 | |||
343 | return 0; | 439 | return 0; |
344 | } | 440 | } |
345 | 441 | ||
@@ -351,12 +447,16 @@ static int ath9k_htc_add_station(struct ath9k_htc_priv *priv, | |||
351 | struct ath9k_htc_target_sta tsta; | 447 | struct ath9k_htc_target_sta tsta; |
352 | struct ath9k_htc_vif *avp = (struct ath9k_htc_vif *) vif->drv_priv; | 448 | struct ath9k_htc_vif *avp = (struct ath9k_htc_vif *) vif->drv_priv; |
353 | struct ath9k_htc_sta *ista; | 449 | struct ath9k_htc_sta *ista; |
354 | int ret; | 450 | int ret, sta_idx; |
355 | u8 cmd_rsp; | 451 | u8 cmd_rsp; |
356 | 452 | ||
357 | if (priv->nstations >= ATH9K_HTC_MAX_STA) | 453 | if (priv->nstations >= ATH9K_HTC_MAX_STA) |
358 | return -ENOBUFS; | 454 | return -ENOBUFS; |
359 | 455 | ||
456 | sta_idx = ffz(priv->sta_slot); | ||
457 | if ((sta_idx < 0) || (sta_idx > ATH9K_HTC_MAX_STA)) | ||
458 | return -ENOBUFS; | ||
459 | |||
360 | memset(&tsta, 0, sizeof(struct ath9k_htc_target_sta)); | 460 | memset(&tsta, 0, sizeof(struct ath9k_htc_target_sta)); |
361 | 461 | ||
362 | if (sta) { | 462 | if (sta) { |
@@ -366,13 +466,13 @@ static int ath9k_htc_add_station(struct ath9k_htc_priv *priv, | |||
366 | tsta.associd = common->curaid; | 466 | tsta.associd = common->curaid; |
367 | tsta.is_vif_sta = 0; | 467 | tsta.is_vif_sta = 0; |
368 | tsta.valid = true; | 468 | tsta.valid = true; |
369 | ista->index = priv->nstations; | 469 | ista->index = sta_idx; |
370 | } else { | 470 | } else { |
371 | memcpy(&tsta.macaddr, vif->addr, ETH_ALEN); | 471 | memcpy(&tsta.macaddr, vif->addr, ETH_ALEN); |
372 | tsta.is_vif_sta = 1; | 472 | tsta.is_vif_sta = 1; |
373 | } | 473 | } |
374 | 474 | ||
375 | tsta.sta_index = priv->nstations; | 475 | tsta.sta_index = sta_idx; |
376 | tsta.vif_index = avp->index; | 476 | tsta.vif_index = avp->index; |
377 | tsta.maxampdu = 0xffff; | 477 | tsta.maxampdu = 0xffff; |
378 | if (sta && sta->ht_cap.ht_supported) | 478 | if (sta && sta->ht_cap.ht_supported) |
@@ -387,12 +487,21 @@ static int ath9k_htc_add_station(struct ath9k_htc_priv *priv, | |||
387 | return ret; | 487 | return ret; |
388 | } | 488 | } |
389 | 489 | ||
390 | if (sta) | 490 | if (sta) { |
391 | ath_dbg(common, ATH_DBG_CONFIG, | 491 | ath_dbg(common, ATH_DBG_CONFIG, |
392 | "Added a station entry for: %pM (idx: %d)\n", | 492 | "Added a station entry for: %pM (idx: %d)\n", |
393 | sta->addr, tsta.sta_index); | 493 | sta->addr, tsta.sta_index); |
494 | } else { | ||
495 | ath_dbg(common, ATH_DBG_CONFIG, | ||
496 | "Added a station entry for VIF %d (idx: %d)\n", | ||
497 | avp->index, tsta.sta_index); | ||
498 | } | ||
394 | 499 | ||
500 | priv->sta_slot |= (1 << sta_idx); | ||
395 | priv->nstations++; | 501 | priv->nstations++; |
502 | if (!sta) | ||
503 | priv->vif_sta_pos[avp->index] = sta_idx; | ||
504 | |||
396 | return 0; | 505 | return 0; |
397 | } | 506 | } |
398 | 507 | ||
@@ -401,6 +510,7 @@ static int ath9k_htc_remove_station(struct ath9k_htc_priv *priv, | |||
401 | struct ieee80211_sta *sta) | 510 | struct ieee80211_sta *sta) |
402 | { | 511 | { |
403 | struct ath_common *common = ath9k_hw_common(priv->ah); | 512 | struct ath_common *common = ath9k_hw_common(priv->ah); |
513 | struct ath9k_htc_vif *avp = (struct ath9k_htc_vif *) vif->drv_priv; | ||
404 | struct ath9k_htc_sta *ista; | 514 | struct ath9k_htc_sta *ista; |
405 | int ret; | 515 | int ret; |
406 | u8 cmd_rsp, sta_idx; | 516 | u8 cmd_rsp, sta_idx; |
@@ -409,7 +519,7 @@ static int ath9k_htc_remove_station(struct ath9k_htc_priv *priv, | |||
409 | ista = (struct ath9k_htc_sta *) sta->drv_priv; | 519 | ista = (struct ath9k_htc_sta *) sta->drv_priv; |
410 | sta_idx = ista->index; | 520 | sta_idx = ista->index; |
411 | } else { | 521 | } else { |
412 | sta_idx = 0; | 522 | sta_idx = priv->vif_sta_pos[avp->index]; |
413 | } | 523 | } |
414 | 524 | ||
415 | WMI_CMD_BUF(WMI_NODE_REMOVE_CMDID, &sta_idx); | 525 | WMI_CMD_BUF(WMI_NODE_REMOVE_CMDID, &sta_idx); |
@@ -421,12 +531,19 @@ static int ath9k_htc_remove_station(struct ath9k_htc_priv *priv, | |||
421 | return ret; | 531 | return ret; |
422 | } | 532 | } |
423 | 533 | ||
424 | if (sta) | 534 | if (sta) { |
425 | ath_dbg(common, ATH_DBG_CONFIG, | 535 | ath_dbg(common, ATH_DBG_CONFIG, |
426 | "Removed a station entry for: %pM (idx: %d)\n", | 536 | "Removed a station entry for: %pM (idx: %d)\n", |
427 | sta->addr, sta_idx); | 537 | sta->addr, sta_idx); |
538 | } else { | ||
539 | ath_dbg(common, ATH_DBG_CONFIG, | ||
540 | "Removed a station entry for VIF %d (idx: %d)\n", | ||
541 | avp->index, sta_idx); | ||
542 | } | ||
428 | 543 | ||
544 | priv->sta_slot &= ~(1 << sta_idx); | ||
429 | priv->nstations--; | 545 | priv->nstations--; |
546 | |||
430 | return 0; | 547 | return 0; |
431 | } | 548 | } |
432 | 549 | ||
@@ -808,7 +925,7 @@ void ath9k_htc_debug_remove_root(void) | |||
808 | /* ANI */ | 925 | /* ANI */ |
809 | /*******/ | 926 | /*******/ |
810 | 927 | ||
811 | void ath_start_ani(struct ath9k_htc_priv *priv) | 928 | void ath9k_htc_start_ani(struct ath9k_htc_priv *priv) |
812 | { | 929 | { |
813 | struct ath_common *common = ath9k_hw_common(priv->ah); | 930 | struct ath_common *common = ath9k_hw_common(priv->ah); |
814 | unsigned long timestamp = jiffies_to_msecs(jiffies); | 931 | unsigned long timestamp = jiffies_to_msecs(jiffies); |
@@ -817,15 +934,22 @@ void ath_start_ani(struct ath9k_htc_priv *priv) | |||
817 | common->ani.shortcal_timer = timestamp; | 934 | common->ani.shortcal_timer = timestamp; |
818 | common->ani.checkani_timer = timestamp; | 935 | common->ani.checkani_timer = timestamp; |
819 | 936 | ||
820 | ieee80211_queue_delayed_work(common->hw, &priv->ath9k_ani_work, | 937 | priv->op_flags |= OP_ANI_RUNNING; |
938 | |||
939 | ieee80211_queue_delayed_work(common->hw, &priv->ani_work, | ||
821 | msecs_to_jiffies(ATH_ANI_POLLINTERVAL)); | 940 | msecs_to_jiffies(ATH_ANI_POLLINTERVAL)); |
822 | } | 941 | } |
823 | 942 | ||
824 | void ath9k_ani_work(struct work_struct *work) | 943 | void ath9k_htc_stop_ani(struct ath9k_htc_priv *priv) |
944 | { | ||
945 | cancel_delayed_work_sync(&priv->ani_work); | ||
946 | priv->op_flags &= ~OP_ANI_RUNNING; | ||
947 | } | ||
948 | |||
949 | void ath9k_htc_ani_work(struct work_struct *work) | ||
825 | { | 950 | { |
826 | struct ath9k_htc_priv *priv = | 951 | struct ath9k_htc_priv *priv = |
827 | container_of(work, struct ath9k_htc_priv, | 952 | container_of(work, struct ath9k_htc_priv, ani_work.work); |
828 | ath9k_ani_work.work); | ||
829 | struct ath_hw *ah = priv->ah; | 953 | struct ath_hw *ah = priv->ah; |
830 | struct ath_common *common = ath9k_hw_common(ah); | 954 | struct ath_common *common = ath9k_hw_common(ah); |
831 | bool longcal = false; | 955 | bool longcal = false; |
@@ -834,7 +958,8 @@ void ath9k_ani_work(struct work_struct *work) | |||
834 | unsigned int timestamp = jiffies_to_msecs(jiffies); | 958 | unsigned int timestamp = jiffies_to_msecs(jiffies); |
835 | u32 cal_interval, short_cal_interval; | 959 | u32 cal_interval, short_cal_interval; |
836 | 960 | ||
837 | short_cal_interval = ATH_STA_SHORT_CALINTERVAL; | 961 | short_cal_interval = (ah->opmode == NL80211_IFTYPE_AP) ? |
962 | ATH_AP_SHORT_CALINTERVAL : ATH_STA_SHORT_CALINTERVAL; | ||
838 | 963 | ||
839 | /* Only calibrate if awake */ | 964 | /* Only calibrate if awake */ |
840 | if (ah->power_mode != ATH9K_PM_AWAKE) | 965 | if (ah->power_mode != ATH9K_PM_AWAKE) |
@@ -903,7 +1028,7 @@ set_timer: | |||
903 | if (!common->ani.caldone) | 1028 | if (!common->ani.caldone) |
904 | cal_interval = min(cal_interval, (u32)short_cal_interval); | 1029 | cal_interval = min(cal_interval, (u32)short_cal_interval); |
905 | 1030 | ||
906 | ieee80211_queue_delayed_work(common->hw, &priv->ath9k_ani_work, | 1031 | ieee80211_queue_delayed_work(common->hw, &priv->ani_work, |
907 | msecs_to_jiffies(cal_interval)); | 1032 | msecs_to_jiffies(cal_interval)); |
908 | } | 1033 | } |
909 | 1034 | ||
@@ -911,7 +1036,7 @@ set_timer: | |||
911 | /* mac80211 Callbacks */ | 1036 | /* mac80211 Callbacks */ |
912 | /**********************/ | 1037 | /**********************/ |
913 | 1038 | ||
914 | static int ath9k_htc_tx(struct ieee80211_hw *hw, struct sk_buff *skb) | 1039 | static void ath9k_htc_tx(struct ieee80211_hw *hw, struct sk_buff *skb) |
915 | { | 1040 | { |
916 | struct ieee80211_hdr *hdr; | 1041 | struct ieee80211_hdr *hdr; |
917 | struct ath9k_htc_priv *priv = hw->priv; | 1042 | struct ath9k_htc_priv *priv = hw->priv; |
@@ -924,7 +1049,7 @@ static int ath9k_htc_tx(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
924 | padsize = padpos & 3; | 1049 | padsize = padpos & 3; |
925 | if (padsize && skb->len > padpos) { | 1050 | if (padsize && skb->len > padpos) { |
926 | if (skb_headroom(skb) < padsize) | 1051 | if (skb_headroom(skb) < padsize) |
927 | return -1; | 1052 | goto fail_tx; |
928 | skb_push(skb, padsize); | 1053 | skb_push(skb, padsize); |
929 | memmove(skb->data, skb->data + padsize, padpos); | 1054 | memmove(skb->data, skb->data + padsize, padpos); |
930 | } | 1055 | } |
@@ -945,11 +1070,10 @@ static int ath9k_htc_tx(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
945 | goto fail_tx; | 1070 | goto fail_tx; |
946 | } | 1071 | } |
947 | 1072 | ||
948 | return 0; | 1073 | return; |
949 | 1074 | ||
950 | fail_tx: | 1075 | fail_tx: |
951 | dev_kfree_skb_any(skb); | 1076 | dev_kfree_skb_any(skb); |
952 | return 0; | ||
953 | } | 1077 | } |
954 | 1078 | ||
955 | static int ath9k_htc_start(struct ieee80211_hw *hw) | 1079 | static int ath9k_htc_start(struct ieee80211_hw *hw) |
@@ -987,7 +1111,8 @@ static int ath9k_htc_start(struct ieee80211_hw *hw) | |||
987 | return ret; | 1111 | return ret; |
988 | } | 1112 | } |
989 | 1113 | ||
990 | ath_update_txpow(priv); | 1114 | ath9k_cmn_update_txpow(ah, priv->curtxpow, priv->txpowlimit, |
1115 | &priv->curtxpow); | ||
991 | 1116 | ||
992 | mode = ath9k_htc_get_curmode(priv, init_channel); | 1117 | mode = ath9k_htc_get_curmode(priv, init_channel); |
993 | htc_mode = cpu_to_be16(mode); | 1118 | htc_mode = cpu_to_be16(mode); |
@@ -997,6 +1122,11 @@ static int ath9k_htc_start(struct ieee80211_hw *hw) | |||
997 | 1122 | ||
998 | ath9k_host_rx_init(priv); | 1123 | ath9k_host_rx_init(priv); |
999 | 1124 | ||
1125 | ret = ath9k_htc_update_cap_target(priv); | ||
1126 | if (ret) | ||
1127 | ath_dbg(common, ATH_DBG_CONFIG, | ||
1128 | "Failed to update capability in target\n"); | ||
1129 | |||
1000 | priv->op_flags &= ~OP_INVALID; | 1130 | priv->op_flags &= ~OP_INVALID; |
1001 | htc_start(priv->htc); | 1131 | htc_start(priv->htc); |
1002 | 1132 | ||
@@ -1051,25 +1181,21 @@ static void ath9k_htc_stop(struct ieee80211_hw *hw) | |||
1051 | cancel_work_sync(&priv->fatal_work); | 1181 | cancel_work_sync(&priv->fatal_work); |
1052 | cancel_work_sync(&priv->ps_work); | 1182 | cancel_work_sync(&priv->ps_work); |
1053 | cancel_delayed_work_sync(&priv->ath9k_led_blink_work); | 1183 | cancel_delayed_work_sync(&priv->ath9k_led_blink_work); |
1184 | ath9k_htc_stop_ani(priv); | ||
1054 | ath9k_led_stop_brightness(priv); | 1185 | ath9k_led_stop_brightness(priv); |
1055 | 1186 | ||
1056 | mutex_lock(&priv->mutex); | 1187 | mutex_lock(&priv->mutex); |
1057 | 1188 | ||
1058 | /* Remove monitor interface here */ | ||
1059 | if (ah->opmode == NL80211_IFTYPE_MONITOR) { | ||
1060 | if (ath9k_htc_remove_monitor_interface(priv)) | ||
1061 | ath_err(common, "Unable to remove monitor interface\n"); | ||
1062 | else | ||
1063 | ath_dbg(common, ATH_DBG_CONFIG, | ||
1064 | "Monitor interface removed\n"); | ||
1065 | } | ||
1066 | |||
1067 | if (ah->btcoex_hw.enabled) { | 1189 | if (ah->btcoex_hw.enabled) { |
1068 | ath9k_hw_btcoex_disable(ah); | 1190 | ath9k_hw_btcoex_disable(ah); |
1069 | if (ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE) | 1191 | if (ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE) |
1070 | ath_htc_cancel_btcoex_work(priv); | 1192 | ath_htc_cancel_btcoex_work(priv); |
1071 | } | 1193 | } |
1072 | 1194 | ||
1195 | /* Remove a monitor interface if it's present. */ | ||
1196 | if (priv->ah->is_monitoring) | ||
1197 | ath9k_htc_remove_monitor_interface(priv); | ||
1198 | |||
1073 | ath9k_hw_phy_disable(ah); | 1199 | ath9k_hw_phy_disable(ah); |
1074 | ath9k_hw_disable(ah); | 1200 | ath9k_hw_disable(ah); |
1075 | ath9k_htc_ps_restore(priv); | 1201 | ath9k_htc_ps_restore(priv); |
@@ -1093,10 +1219,24 @@ static int ath9k_htc_add_interface(struct ieee80211_hw *hw, | |||
1093 | 1219 | ||
1094 | mutex_lock(&priv->mutex); | 1220 | mutex_lock(&priv->mutex); |
1095 | 1221 | ||
1096 | /* Only one interface for now */ | 1222 | if (priv->nvifs >= ATH9K_HTC_MAX_VIF) { |
1097 | if (priv->nvifs > 0) { | 1223 | mutex_unlock(&priv->mutex); |
1098 | ret = -ENOBUFS; | 1224 | return -ENOBUFS; |
1099 | goto out; | 1225 | } |
1226 | |||
1227 | if (priv->num_ibss_vif || | ||
1228 | (priv->nvifs && vif->type == NL80211_IFTYPE_ADHOC)) { | ||
1229 | ath_err(common, "IBSS coexistence with other modes is not allowed\n"); | ||
1230 | mutex_unlock(&priv->mutex); | ||
1231 | return -ENOBUFS; | ||
1232 | } | ||
1233 | |||
1234 | if (((vif->type == NL80211_IFTYPE_AP) || | ||
1235 | (vif->type == NL80211_IFTYPE_ADHOC)) && | ||
1236 | ((priv->num_ap_vif + priv->num_ibss_vif) >= ATH9K_HTC_MAX_BCN_VIF)) { | ||
1237 | ath_err(common, "Max. number of beaconing interfaces reached\n"); | ||
1238 | mutex_unlock(&priv->mutex); | ||
1239 | return -ENOBUFS; | ||
1100 | } | 1240 | } |
1101 | 1241 | ||
1102 | ath9k_htc_ps_wakeup(priv); | 1242 | ath9k_htc_ps_wakeup(priv); |
@@ -1110,6 +1250,9 @@ static int ath9k_htc_add_interface(struct ieee80211_hw *hw, | |||
1110 | case NL80211_IFTYPE_ADHOC: | 1250 | case NL80211_IFTYPE_ADHOC: |
1111 | hvif.opmode = cpu_to_be32(HTC_M_IBSS); | 1251 | hvif.opmode = cpu_to_be32(HTC_M_IBSS); |
1112 | break; | 1252 | break; |
1253 | case NL80211_IFTYPE_AP: | ||
1254 | hvif.opmode = cpu_to_be32(HTC_M_HOSTAP); | ||
1255 | break; | ||
1113 | default: | 1256 | default: |
1114 | ath_err(common, | 1257 | ath_err(common, |
1115 | "Interface type %d not yet supported\n", vif->type); | 1258 | "Interface type %d not yet supported\n", vif->type); |
@@ -1117,34 +1260,39 @@ static int ath9k_htc_add_interface(struct ieee80211_hw *hw, | |||
1117 | goto out; | 1260 | goto out; |
1118 | } | 1261 | } |
1119 | 1262 | ||
1120 | ath_dbg(common, ATH_DBG_CONFIG, | ||
1121 | "Attach a VIF of type: %d\n", vif->type); | ||
1122 | |||
1123 | priv->ah->opmode = vif->type; | ||
1124 | |||
1125 | /* Index starts from zero on the target */ | 1263 | /* Index starts from zero on the target */ |
1126 | avp->index = hvif.index = priv->nvifs; | 1264 | avp->index = hvif.index = ffz(priv->vif_slot); |
1127 | hvif.rtsthreshold = cpu_to_be16(2304); | 1265 | hvif.rtsthreshold = cpu_to_be16(2304); |
1128 | WMI_CMD_BUF(WMI_VAP_CREATE_CMDID, &hvif); | 1266 | WMI_CMD_BUF(WMI_VAP_CREATE_CMDID, &hvif); |
1129 | if (ret) | 1267 | if (ret) |
1130 | goto out; | 1268 | goto out; |
1131 | 1269 | ||
1132 | priv->nvifs++; | ||
1133 | |||
1134 | /* | 1270 | /* |
1135 | * We need a node in target to tx mgmt frames | 1271 | * We need a node in target to tx mgmt frames |
1136 | * before association. | 1272 | * before association. |
1137 | */ | 1273 | */ |
1138 | ret = ath9k_htc_add_station(priv, vif, NULL); | 1274 | ret = ath9k_htc_add_station(priv, vif, NULL); |
1139 | if (ret) | 1275 | if (ret) { |
1276 | WMI_CMD_BUF(WMI_VAP_REMOVE_CMDID, &hvif); | ||
1140 | goto out; | 1277 | goto out; |
1278 | } | ||
1141 | 1279 | ||
1142 | ret = ath9k_htc_update_cap_target(priv); | 1280 | ath9k_htc_set_bssid_mask(priv, vif); |
1143 | if (ret) | ||
1144 | ath_dbg(common, ATH_DBG_CONFIG, | ||
1145 | "Failed to update capability in target\n"); | ||
1146 | 1281 | ||
1282 | priv->vif_slot |= (1 << avp->index); | ||
1283 | priv->nvifs++; | ||
1147 | priv->vif = vif; | 1284 | priv->vif = vif; |
1285 | |||
1286 | INC_VIF(priv, vif->type); | ||
1287 | ath9k_htc_set_opmode(priv); | ||
1288 | |||
1289 | if ((priv->ah->opmode == NL80211_IFTYPE_AP) && | ||
1290 | !(priv->op_flags & OP_ANI_RUNNING)) | ||
1291 | ath9k_htc_start_ani(priv); | ||
1292 | |||
1293 | ath_dbg(common, ATH_DBG_CONFIG, | ||
1294 | "Attach a VIF of type: %d at idx: %d\n", vif->type, avp->index); | ||
1295 | |||
1148 | out: | 1296 | out: |
1149 | ath9k_htc_ps_restore(priv); | 1297 | ath9k_htc_ps_restore(priv); |
1150 | mutex_unlock(&priv->mutex); | 1298 | mutex_unlock(&priv->mutex); |
@@ -1162,8 +1310,6 @@ static void ath9k_htc_remove_interface(struct ieee80211_hw *hw, | |||
1162 | int ret = 0; | 1310 | int ret = 0; |
1163 | u8 cmd_rsp; | 1311 | u8 cmd_rsp; |
1164 | 1312 | ||
1165 | ath_dbg(common, ATH_DBG_CONFIG, "Detach Interface\n"); | ||
1166 | |||
1167 | mutex_lock(&priv->mutex); | 1313 | mutex_lock(&priv->mutex); |
1168 | ath9k_htc_ps_wakeup(priv); | 1314 | ath9k_htc_ps_wakeup(priv); |
1169 | 1315 | ||
@@ -1172,10 +1318,27 @@ static void ath9k_htc_remove_interface(struct ieee80211_hw *hw, | |||
1172 | hvif.index = avp->index; | 1318 | hvif.index = avp->index; |
1173 | WMI_CMD_BUF(WMI_VAP_REMOVE_CMDID, &hvif); | 1319 | WMI_CMD_BUF(WMI_VAP_REMOVE_CMDID, &hvif); |
1174 | priv->nvifs--; | 1320 | priv->nvifs--; |
1321 | priv->vif_slot &= ~(1 << avp->index); | ||
1175 | 1322 | ||
1176 | ath9k_htc_remove_station(priv, vif, NULL); | 1323 | ath9k_htc_remove_station(priv, vif, NULL); |
1177 | priv->vif = NULL; | 1324 | priv->vif = NULL; |
1178 | 1325 | ||
1326 | DEC_VIF(priv, vif->type); | ||
1327 | ath9k_htc_set_opmode(priv); | ||
1328 | |||
1329 | /* | ||
1330 | * Stop ANI only if there are no associated station interfaces. | ||
1331 | */ | ||
1332 | if ((vif->type == NL80211_IFTYPE_AP) && (priv->num_ap_vif == 0)) { | ||
1333 | priv->rearm_ani = false; | ||
1334 | ieee80211_iterate_active_interfaces_atomic(priv->hw, | ||
1335 | ath9k_htc_vif_iter, priv); | ||
1336 | if (!priv->rearm_ani) | ||
1337 | ath9k_htc_stop_ani(priv); | ||
1338 | } | ||
1339 | |||
1340 | ath_dbg(common, ATH_DBG_CONFIG, "Detach Interface at idx: %d\n", avp->index); | ||
1341 | |||
1179 | ath9k_htc_ps_restore(priv); | 1342 | ath9k_htc_ps_restore(priv); |
1180 | mutex_unlock(&priv->mutex); | 1343 | mutex_unlock(&priv->mutex); |
1181 | } | 1344 | } |
@@ -1211,13 +1374,11 @@ static int ath9k_htc_config(struct ieee80211_hw *hw, u32 changed) | |||
1211 | * IEEE80211_CONF_CHANGE_CHANNEL is handled. | 1374 | * IEEE80211_CONF_CHANGE_CHANNEL is handled. |
1212 | */ | 1375 | */ |
1213 | if (changed & IEEE80211_CONF_CHANGE_MONITOR) { | 1376 | if (changed & IEEE80211_CONF_CHANGE_MONITOR) { |
1214 | if (conf->flags & IEEE80211_CONF_MONITOR) { | 1377 | if ((conf->flags & IEEE80211_CONF_MONITOR) && |
1215 | if (ath9k_htc_add_monitor_interface(priv)) | 1378 | !priv->ah->is_monitoring) |
1216 | ath_err(common, "Failed to set monitor mode\n"); | 1379 | ath9k_htc_add_monitor_interface(priv); |
1217 | else | 1380 | else if (priv->ah->is_monitoring) |
1218 | ath_dbg(common, ATH_DBG_CONFIG, | 1381 | ath9k_htc_remove_monitor_interface(priv); |
1219 | "HW opmode set to Monitor mode\n"); | ||
1220 | } | ||
1221 | } | 1382 | } |
1222 | 1383 | ||
1223 | if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { | 1384 | if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { |
@@ -1252,7 +1413,8 @@ static int ath9k_htc_config(struct ieee80211_hw *hw, u32 changed) | |||
1252 | 1413 | ||
1253 | if (changed & IEEE80211_CONF_CHANGE_POWER) { | 1414 | if (changed & IEEE80211_CONF_CHANGE_POWER) { |
1254 | priv->txpowlimit = 2 * conf->power_level; | 1415 | priv->txpowlimit = 2 * conf->power_level; |
1255 | ath_update_txpow(priv); | 1416 | ath9k_cmn_update_txpow(priv->ah, priv->curtxpow, |
1417 | priv->txpowlimit, &priv->curtxpow); | ||
1256 | } | 1418 | } |
1257 | 1419 | ||
1258 | if (changed & IEEE80211_CONF_CHANGE_IDLE) { | 1420 | if (changed & IEEE80211_CONF_CHANGE_IDLE) { |
@@ -1439,66 +1601,81 @@ static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw, | |||
1439 | struct ath9k_htc_priv *priv = hw->priv; | 1601 | struct ath9k_htc_priv *priv = hw->priv; |
1440 | struct ath_hw *ah = priv->ah; | 1602 | struct ath_hw *ah = priv->ah; |
1441 | struct ath_common *common = ath9k_hw_common(ah); | 1603 | struct ath_common *common = ath9k_hw_common(ah); |
1604 | bool set_assoc; | ||
1442 | 1605 | ||
1443 | mutex_lock(&priv->mutex); | 1606 | mutex_lock(&priv->mutex); |
1444 | ath9k_htc_ps_wakeup(priv); | 1607 | ath9k_htc_ps_wakeup(priv); |
1445 | 1608 | ||
1609 | /* | ||
1610 | * Set the HW AID/BSSID only for the first station interface | ||
1611 | * or in IBSS mode. | ||
1612 | */ | ||
1613 | set_assoc = !!((priv->ah->opmode == NL80211_IFTYPE_ADHOC) || | ||
1614 | ((priv->ah->opmode == NL80211_IFTYPE_STATION) && | ||
1615 | (priv->num_sta_vif == 1))); | ||
1616 | |||
1617 | |||
1446 | if (changed & BSS_CHANGED_ASSOC) { | 1618 | if (changed & BSS_CHANGED_ASSOC) { |
1447 | common->curaid = bss_conf->assoc ? | 1619 | if (set_assoc) { |
1448 | bss_conf->aid : 0; | 1620 | ath_dbg(common, ATH_DBG_CONFIG, "BSS Changed ASSOC %d\n", |
1449 | ath_dbg(common, ATH_DBG_CONFIG, "BSS Changed ASSOC %d\n", | 1621 | bss_conf->assoc); |
1450 | bss_conf->assoc); | 1622 | |
1451 | 1623 | common->curaid = bss_conf->assoc ? | |
1452 | if (bss_conf->assoc) { | 1624 | bss_conf->aid : 0; |
1453 | priv->op_flags |= OP_ASSOCIATED; | 1625 | |
1454 | ath_start_ani(priv); | 1626 | if (bss_conf->assoc) |
1455 | } else { | 1627 | ath9k_htc_start_ani(priv); |
1456 | priv->op_flags &= ~OP_ASSOCIATED; | 1628 | else |
1457 | cancel_delayed_work_sync(&priv->ath9k_ani_work); | 1629 | ath9k_htc_stop_ani(priv); |
1458 | } | 1630 | } |
1459 | } | 1631 | } |
1460 | 1632 | ||
1461 | if (changed & BSS_CHANGED_BSSID) { | 1633 | if (changed & BSS_CHANGED_BSSID) { |
1462 | /* Set BSSID */ | 1634 | if (set_assoc) { |
1463 | memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN); | 1635 | memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN); |
1464 | ath9k_hw_write_associd(ah); | 1636 | ath9k_hw_write_associd(ah); |
1465 | 1637 | ||
1466 | ath_dbg(common, ATH_DBG_CONFIG, | 1638 | ath_dbg(common, ATH_DBG_CONFIG, |
1467 | "BSSID: %pM aid: 0x%x\n", | 1639 | "BSSID: %pM aid: 0x%x\n", |
1468 | common->curbssid, common->curaid); | 1640 | common->curbssid, common->curaid); |
1641 | } | ||
1469 | } | 1642 | } |
1470 | 1643 | ||
1471 | if ((changed & BSS_CHANGED_BEACON_INT) || | 1644 | if ((changed & BSS_CHANGED_BEACON_ENABLED) && bss_conf->enable_beacon) { |
1472 | (changed & BSS_CHANGED_BEACON) || | 1645 | ath_dbg(common, ATH_DBG_CONFIG, |
1473 | ((changed & BSS_CHANGED_BEACON_ENABLED) && | 1646 | "Beacon enabled for BSS: %pM\n", bss_conf->bssid); |
1474 | bss_conf->enable_beacon)) { | ||
1475 | priv->op_flags |= OP_ENABLE_BEACON; | 1647 | priv->op_flags |= OP_ENABLE_BEACON; |
1476 | ath9k_htc_beacon_config(priv, vif); | 1648 | ath9k_htc_beacon_config(priv, vif); |
1477 | } | 1649 | } |
1478 | 1650 | ||
1479 | if ((changed & BSS_CHANGED_BEACON_ENABLED) && | 1651 | if ((changed & BSS_CHANGED_BEACON_ENABLED) && !bss_conf->enable_beacon) { |
1480 | !bss_conf->enable_beacon) { | 1652 | /* |
1481 | priv->op_flags &= ~OP_ENABLE_BEACON; | 1653 | * Disable SWBA interrupt only if there are no |
1482 | ath9k_htc_beacon_config(priv, vif); | 1654 | * AP/IBSS interfaces. |
1483 | } | 1655 | */ |
1484 | 1656 | if ((priv->num_ap_vif <= 1) || priv->num_ibss_vif) { | |
1485 | if (changed & BSS_CHANGED_ERP_PREAMBLE) { | 1657 | ath_dbg(common, ATH_DBG_CONFIG, |
1486 | ath_dbg(common, ATH_DBG_CONFIG, "BSS Changed PREAMBLE %d\n", | 1658 | "Beacon disabled for BSS: %pM\n", |
1487 | bss_conf->use_short_preamble); | 1659 | bss_conf->bssid); |
1488 | if (bss_conf->use_short_preamble) | 1660 | priv->op_flags &= ~OP_ENABLE_BEACON; |
1489 | priv->op_flags |= OP_PREAMBLE_SHORT; | 1661 | ath9k_htc_beacon_config(priv, vif); |
1490 | else | 1662 | } |
1491 | priv->op_flags &= ~OP_PREAMBLE_SHORT; | ||
1492 | } | 1663 | } |
1493 | 1664 | ||
1494 | if (changed & BSS_CHANGED_ERP_CTS_PROT) { | 1665 | if (changed & BSS_CHANGED_BEACON_INT) { |
1495 | ath_dbg(common, ATH_DBG_CONFIG, "BSS Changed CTS PROT %d\n", | 1666 | /* |
1496 | bss_conf->use_cts_prot); | 1667 | * Reset the HW TSF for the first AP interface. |
1497 | if (bss_conf->use_cts_prot && | 1668 | */ |
1498 | hw->conf.channel->band != IEEE80211_BAND_5GHZ) | 1669 | if ((priv->ah->opmode == NL80211_IFTYPE_AP) && |
1499 | priv->op_flags |= OP_PROTECT_ENABLE; | 1670 | (priv->nvifs == 1) && |
1500 | else | 1671 | (priv->num_ap_vif == 1) && |
1501 | priv->op_flags &= ~OP_PROTECT_ENABLE; | 1672 | (vif->type == NL80211_IFTYPE_AP)) { |
1673 | priv->op_flags |= OP_TSF_RESET; | ||
1674 | } | ||
1675 | ath_dbg(common, ATH_DBG_CONFIG, | ||
1676 | "Beacon interval changed for BSS: %pM\n", | ||
1677 | bss_conf->bssid); | ||
1678 | ath9k_htc_beacon_config(priv, vif); | ||
1502 | } | 1679 | } |
1503 | 1680 | ||
1504 | if (changed & BSS_CHANGED_ERP_SLOT) { | 1681 | if (changed & BSS_CHANGED_ERP_SLOT) { |
@@ -1557,12 +1734,14 @@ static int ath9k_htc_ampdu_action(struct ieee80211_hw *hw, | |||
1557 | struct ieee80211_vif *vif, | 1734 | struct ieee80211_vif *vif, |
1558 | enum ieee80211_ampdu_mlme_action action, | 1735 | enum ieee80211_ampdu_mlme_action action, |
1559 | struct ieee80211_sta *sta, | 1736 | struct ieee80211_sta *sta, |
1560 | u16 tid, u16 *ssn) | 1737 | u16 tid, u16 *ssn, u8 buf_size) |
1561 | { | 1738 | { |
1562 | struct ath9k_htc_priv *priv = hw->priv; | 1739 | struct ath9k_htc_priv *priv = hw->priv; |
1563 | struct ath9k_htc_sta *ista; | 1740 | struct ath9k_htc_sta *ista; |
1564 | int ret = 0; | 1741 | int ret = 0; |
1565 | 1742 | ||
1743 | mutex_lock(&priv->mutex); | ||
1744 | |||
1566 | switch (action) { | 1745 | switch (action) { |
1567 | case IEEE80211_AMPDU_RX_START: | 1746 | case IEEE80211_AMPDU_RX_START: |
1568 | break; | 1747 | break; |
@@ -1587,6 +1766,8 @@ static int ath9k_htc_ampdu_action(struct ieee80211_hw *hw, | |||
1587 | ath_err(ath9k_hw_common(priv->ah), "Unknown AMPDU action\n"); | 1766 | ath_err(ath9k_hw_common(priv->ah), "Unknown AMPDU action\n"); |
1588 | } | 1767 | } |
1589 | 1768 | ||
1769 | mutex_unlock(&priv->mutex); | ||
1770 | |||
1590 | return ret; | 1771 | return ret; |
1591 | } | 1772 | } |
1592 | 1773 | ||
@@ -1599,8 +1780,7 @@ static void ath9k_htc_sw_scan_start(struct ieee80211_hw *hw) | |||
1599 | priv->op_flags |= OP_SCANNING; | 1780 | priv->op_flags |= OP_SCANNING; |
1600 | spin_unlock_bh(&priv->beacon_lock); | 1781 | spin_unlock_bh(&priv->beacon_lock); |
1601 | cancel_work_sync(&priv->ps_work); | 1782 | cancel_work_sync(&priv->ps_work); |
1602 | if (priv->op_flags & OP_ASSOCIATED) | 1783 | ath9k_htc_stop_ani(priv); |
1603 | cancel_delayed_work_sync(&priv->ath9k_ani_work); | ||
1604 | mutex_unlock(&priv->mutex); | 1784 | mutex_unlock(&priv->mutex); |
1605 | } | 1785 | } |
1606 | 1786 | ||
@@ -1609,14 +1789,11 @@ static void ath9k_htc_sw_scan_complete(struct ieee80211_hw *hw) | |||
1609 | struct ath9k_htc_priv *priv = hw->priv; | 1789 | struct ath9k_htc_priv *priv = hw->priv; |
1610 | 1790 | ||
1611 | mutex_lock(&priv->mutex); | 1791 | mutex_lock(&priv->mutex); |
1612 | ath9k_htc_ps_wakeup(priv); | ||
1613 | spin_lock_bh(&priv->beacon_lock); | 1792 | spin_lock_bh(&priv->beacon_lock); |
1614 | priv->op_flags &= ~OP_SCANNING; | 1793 | priv->op_flags &= ~OP_SCANNING; |
1615 | spin_unlock_bh(&priv->beacon_lock); | 1794 | spin_unlock_bh(&priv->beacon_lock); |
1616 | if (priv->op_flags & OP_ASSOCIATED) { | 1795 | ath9k_htc_ps_wakeup(priv); |
1617 | ath9k_htc_beacon_config(priv, priv->vif); | 1796 | ath9k_htc_vif_reconfig(priv); |
1618 | ath_start_ani(priv); | ||
1619 | } | ||
1620 | ath9k_htc_ps_restore(priv); | 1797 | ath9k_htc_ps_restore(priv); |
1621 | mutex_unlock(&priv->mutex); | 1798 | mutex_unlock(&priv->mutex); |
1622 | } | 1799 | } |