diff options
author | Sujith Manoharan <Sujith.Manoharan@atheros.com> | 2011-02-20 21:18:00 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2011-02-23 16:25:25 -0500 |
commit | a97b478c92c14255d375ed9ceb7a882083523593 (patch) | |
tree | 26f696e628401920344c069b46d21c8582d59af9 /drivers/net/wireless/ath | |
parent | 36bcce430657e6fece0e8dd91557f35dbb69ec67 (diff) |
ath9k_htc: Allow upto two simultaneous interfaces
Multiple interfaces can be configured if a slot is free
on the target. Monitor mode also requires a slot.
The maximum number of stations that can be handled in
the firmware is 8, manage the station slots accordingly.
Signed-off-by: Sujith Manoharan <Sujith.Manoharan@atheros.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/ath')
-rw-r--r-- | drivers/net/wireless/ath/ath9k/htc.h | 7 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/htc_drv_main.c | 148 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/htc_drv_txrx.c | 29 |
3 files changed, 130 insertions, 54 deletions
diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h index 0cb504d7b8c4..ab8d1f0cba13 100644 --- a/drivers/net/wireless/ath/ath9k/htc.h +++ b/drivers/net/wireless/ath/ath9k/htc.h | |||
@@ -204,6 +204,8 @@ struct ath9k_htc_target_stats { | |||
204 | __be32 ht_tx_xretries; | 204 | __be32 ht_tx_xretries; |
205 | } __packed; | 205 | } __packed; |
206 | 206 | ||
207 | #define ATH9K_HTC_MAX_VIF 2 | ||
208 | |||
207 | struct ath9k_htc_vif { | 209 | struct ath9k_htc_vif { |
208 | u8 index; | 210 | u8 index; |
209 | }; | 211 | }; |
@@ -358,6 +360,11 @@ struct ath9k_htc_priv { | |||
358 | enum htc_endpoint_id data_vi_ep; | 360 | enum htc_endpoint_id data_vi_ep; |
359 | enum htc_endpoint_id data_vo_ep; | 361 | enum htc_endpoint_id data_vo_ep; |
360 | 362 | ||
363 | u8 vif_slot; | ||
364 | u8 mon_vif_idx; | ||
365 | u8 sta_slot; | ||
366 | u8 vif_sta_pos[ATH9K_HTC_MAX_VIF]; | ||
367 | |||
361 | u16 op_flags; | 368 | u16 op_flags; |
362 | u16 curtxpow; | 369 | u16 curtxpow; |
363 | u16 txpowlimit; | 370 | u16 txpowlimit; |
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index 50fde0e10595..618670d318c5 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c | |||
@@ -227,6 +227,13 @@ err: | |||
227 | return ret; | 227 | return ret; |
228 | } | 228 | } |
229 | 229 | ||
230 | /* | ||
231 | * Monitor mode handling is a tad complicated because the firmware requires | ||
232 | * an interface to be created exclusively, while mac80211 doesn't associate | ||
233 | * an interface with the mode. | ||
234 | * | ||
235 | * So, for now, only one monitor interface can be configured. | ||
236 | */ | ||
230 | static void __ath9k_htc_remove_monitor_interface(struct ath9k_htc_priv *priv) | 237 | static void __ath9k_htc_remove_monitor_interface(struct ath9k_htc_priv *priv) |
231 | { | 238 | { |
232 | struct ath_common *common = ath9k_hw_common(priv->ah); | 239 | struct ath_common *common = ath9k_hw_common(priv->ah); |
@@ -236,9 +243,10 @@ static void __ath9k_htc_remove_monitor_interface(struct ath9k_htc_priv *priv) | |||
236 | 243 | ||
237 | memset(&hvif, 0, sizeof(struct ath9k_htc_target_vif)); | 244 | memset(&hvif, 0, sizeof(struct ath9k_htc_target_vif)); |
238 | memcpy(&hvif.myaddr, common->macaddr, ETH_ALEN); | 245 | memcpy(&hvif.myaddr, common->macaddr, ETH_ALEN); |
239 | hvif.index = 0; /* Should do for now */ | 246 | hvif.index = priv->mon_vif_idx; |
240 | WMI_CMD_BUF(WMI_VAP_REMOVE_CMDID, &hvif); | 247 | WMI_CMD_BUF(WMI_VAP_REMOVE_CMDID, &hvif); |
241 | priv->nvifs--; | 248 | priv->nvifs--; |
249 | priv->vif_slot &= ~(1 << priv->mon_vif_idx); | ||
242 | } | 250 | } |
243 | 251 | ||
244 | static int ath9k_htc_add_monitor_interface(struct ath9k_htc_priv *priv) | 252 | static int ath9k_htc_add_monitor_interface(struct ath9k_htc_priv *priv) |
@@ -246,51 +254,69 @@ static int ath9k_htc_add_monitor_interface(struct ath9k_htc_priv *priv) | |||
246 | struct ath_common *common = ath9k_hw_common(priv->ah); | 254 | struct ath_common *common = ath9k_hw_common(priv->ah); |
247 | struct ath9k_htc_target_vif hvif; | 255 | struct ath9k_htc_target_vif hvif; |
248 | struct ath9k_htc_target_sta tsta; | 256 | struct ath9k_htc_target_sta tsta; |
249 | int ret = 0; | 257 | int ret = 0, sta_idx; |
250 | u8 cmd_rsp; | 258 | u8 cmd_rsp; |
251 | 259 | ||
252 | if (priv->nvifs > 0) | 260 | if ((priv->nvifs >= ATH9K_HTC_MAX_VIF) || |
253 | return -ENOBUFS; | 261 | (priv->nstations >= ATH9K_HTC_MAX_STA)) { |
262 | ret = -ENOBUFS; | ||
263 | goto err_vif; | ||
264 | } | ||
254 | 265 | ||
255 | if (priv->nstations >= ATH9K_HTC_MAX_STA) | 266 | sta_idx = ffz(priv->sta_slot); |
256 | return -ENOBUFS; | 267 | if ((sta_idx < 0) || (sta_idx > ATH9K_HTC_MAX_STA)) { |
268 | ret = -ENOBUFS; | ||
269 | goto err_vif; | ||
270 | } | ||
257 | 271 | ||
258 | /* | 272 | /* |
259 | * Add an interface. | 273 | * Add an interface. |
260 | */ | 274 | */ |
261 | |||
262 | memset(&hvif, 0, sizeof(struct ath9k_htc_target_vif)); | 275 | memset(&hvif, 0, sizeof(struct ath9k_htc_target_vif)); |
263 | memcpy(&hvif.myaddr, common->macaddr, ETH_ALEN); | 276 | memcpy(&hvif.myaddr, common->macaddr, ETH_ALEN); |
264 | 277 | ||
265 | hvif.opmode = cpu_to_be32(HTC_M_MONITOR); | 278 | hvif.opmode = cpu_to_be32(HTC_M_MONITOR); |
266 | priv->ah->opmode = NL80211_IFTYPE_MONITOR; | 279 | hvif.index = ffz(priv->vif_slot); |
267 | hvif.index = priv->nvifs; | ||
268 | 280 | ||
269 | WMI_CMD_BUF(WMI_VAP_CREATE_CMDID, &hvif); | 281 | WMI_CMD_BUF(WMI_VAP_CREATE_CMDID, &hvif); |
270 | if (ret) | 282 | if (ret) |
271 | return ret; | 283 | goto err_vif; |
284 | |||
285 | /* | ||
286 | * Assign the monitor interface index as a special case here. | ||
287 | * This is needed when the interface is brought down. | ||
288 | */ | ||
289 | priv->mon_vif_idx = hvif.index; | ||
290 | priv->vif_slot |= (1 << hvif.index); | ||
291 | |||
292 | /* | ||
293 | * Set the hardware mode to monitor only if there are no | ||
294 | * other interfaces. | ||
295 | */ | ||
296 | if (!priv->nvifs) | ||
297 | priv->ah->opmode = NL80211_IFTYPE_MONITOR; | ||
272 | 298 | ||
273 | priv->nvifs++; | 299 | priv->nvifs++; |
274 | 300 | ||
275 | /* | 301 | /* |
276 | * Associate a station with the interface for packet injection. | 302 | * Associate a station with the interface for packet injection. |
277 | */ | 303 | */ |
278 | |||
279 | memset(&tsta, 0, sizeof(struct ath9k_htc_target_sta)); | 304 | memset(&tsta, 0, sizeof(struct ath9k_htc_target_sta)); |
280 | 305 | ||
281 | memcpy(&tsta.macaddr, common->macaddr, ETH_ALEN); | 306 | memcpy(&tsta.macaddr, common->macaddr, ETH_ALEN); |
282 | 307 | ||
283 | tsta.is_vif_sta = 1; | 308 | tsta.is_vif_sta = 1; |
284 | tsta.sta_index = priv->nstations; | 309 | tsta.sta_index = sta_idx; |
285 | tsta.vif_index = hvif.index; | 310 | tsta.vif_index = hvif.index; |
286 | tsta.maxampdu = 0xffff; | 311 | tsta.maxampdu = 0xffff; |
287 | 312 | ||
288 | WMI_CMD_BUF(WMI_NODE_CREATE_CMDID, &tsta); | 313 | WMI_CMD_BUF(WMI_NODE_CREATE_CMDID, &tsta); |
289 | if (ret) { | 314 | if (ret) { |
290 | ath_err(common, "Unable to add station entry for monitor mode\n"); | 315 | ath_err(common, "Unable to add station entry for monitor mode\n"); |
291 | goto err_vif; | 316 | goto err_sta; |
292 | } | 317 | } |
293 | 318 | ||
319 | priv->sta_slot |= (1 << sta_idx); | ||
294 | priv->nstations++; | 320 | priv->nstations++; |
295 | 321 | ||
296 | /* | 322 | /* |
@@ -301,15 +327,23 @@ static int ath9k_htc_add_monitor_interface(struct ath9k_htc_priv *priv) | |||
301 | ath_dbg(common, ATH_DBG_CONFIG, | 327 | ath_dbg(common, ATH_DBG_CONFIG, |
302 | "Failed to update capability in target\n"); | 328 | "Failed to update capability in target\n"); |
303 | 329 | ||
330 | priv->vif_sta_pos[priv->mon_vif_idx] = sta_idx; | ||
304 | priv->ah->is_monitoring = true; | 331 | priv->ah->is_monitoring = true; |
305 | 332 | ||
333 | ath_dbg(common, ATH_DBG_CONFIG, | ||
334 | "Attached a monitor interface at idx: %d, sta idx: %d\n", | ||
335 | priv->mon_vif_idx, sta_idx); | ||
336 | |||
306 | return 0; | 337 | return 0; |
307 | 338 | ||
308 | err_vif: | 339 | err_sta: |
309 | /* | 340 | /* |
310 | * Remove the interface from the target. | 341 | * Remove the interface from the target. |
311 | */ | 342 | */ |
312 | __ath9k_htc_remove_monitor_interface(priv); | 343 | __ath9k_htc_remove_monitor_interface(priv); |
344 | err_vif: | ||
345 | ath_dbg(common, ATH_DBG_FATAL, "Unable to attach a monitor interface\n"); | ||
346 | |||
313 | return ret; | 347 | return ret; |
314 | } | 348 | } |
315 | 349 | ||
@@ -321,7 +355,7 @@ static int ath9k_htc_remove_monitor_interface(struct ath9k_htc_priv *priv) | |||
321 | 355 | ||
322 | __ath9k_htc_remove_monitor_interface(priv); | 356 | __ath9k_htc_remove_monitor_interface(priv); |
323 | 357 | ||
324 | sta_idx = 0; /* Only single interface, for now */ | 358 | sta_idx = priv->vif_sta_pos[priv->mon_vif_idx]; |
325 | 359 | ||
326 | WMI_CMD_BUF(WMI_NODE_REMOVE_CMDID, &sta_idx); | 360 | WMI_CMD_BUF(WMI_NODE_REMOVE_CMDID, &sta_idx); |
327 | if (ret) { | 361 | if (ret) { |
@@ -329,9 +363,14 @@ static int ath9k_htc_remove_monitor_interface(struct ath9k_htc_priv *priv) | |||
329 | return ret; | 363 | return ret; |
330 | } | 364 | } |
331 | 365 | ||
366 | priv->sta_slot &= ~(1 << sta_idx); | ||
332 | priv->nstations--; | 367 | priv->nstations--; |
333 | priv->ah->is_monitoring = false; | 368 | priv->ah->is_monitoring = false; |
334 | 369 | ||
370 | ath_dbg(common, ATH_DBG_CONFIG, | ||
371 | "Removed a monitor interface at idx: %d, sta idx: %d\n", | ||
372 | priv->mon_vif_idx, sta_idx); | ||
373 | |||
335 | return 0; | 374 | return 0; |
336 | } | 375 | } |
337 | 376 | ||
@@ -343,12 +382,16 @@ static int ath9k_htc_add_station(struct ath9k_htc_priv *priv, | |||
343 | struct ath9k_htc_target_sta tsta; | 382 | struct ath9k_htc_target_sta tsta; |
344 | struct ath9k_htc_vif *avp = (struct ath9k_htc_vif *) vif->drv_priv; | 383 | struct ath9k_htc_vif *avp = (struct ath9k_htc_vif *) vif->drv_priv; |
345 | struct ath9k_htc_sta *ista; | 384 | struct ath9k_htc_sta *ista; |
346 | int ret; | 385 | int ret, sta_idx; |
347 | u8 cmd_rsp; | 386 | u8 cmd_rsp; |
348 | 387 | ||
349 | if (priv->nstations >= ATH9K_HTC_MAX_STA) | 388 | if (priv->nstations >= ATH9K_HTC_MAX_STA) |
350 | return -ENOBUFS; | 389 | return -ENOBUFS; |
351 | 390 | ||
391 | sta_idx = ffz(priv->sta_slot); | ||
392 | if ((sta_idx < 0) || (sta_idx > ATH9K_HTC_MAX_STA)) | ||
393 | return -ENOBUFS; | ||
394 | |||
352 | memset(&tsta, 0, sizeof(struct ath9k_htc_target_sta)); | 395 | memset(&tsta, 0, sizeof(struct ath9k_htc_target_sta)); |
353 | 396 | ||
354 | if (sta) { | 397 | if (sta) { |
@@ -358,13 +401,13 @@ static int ath9k_htc_add_station(struct ath9k_htc_priv *priv, | |||
358 | tsta.associd = common->curaid; | 401 | tsta.associd = common->curaid; |
359 | tsta.is_vif_sta = 0; | 402 | tsta.is_vif_sta = 0; |
360 | tsta.valid = true; | 403 | tsta.valid = true; |
361 | ista->index = priv->nstations; | 404 | ista->index = sta_idx; |
362 | } else { | 405 | } else { |
363 | memcpy(&tsta.macaddr, vif->addr, ETH_ALEN); | 406 | memcpy(&tsta.macaddr, vif->addr, ETH_ALEN); |
364 | tsta.is_vif_sta = 1; | 407 | tsta.is_vif_sta = 1; |
365 | } | 408 | } |
366 | 409 | ||
367 | tsta.sta_index = priv->nstations; | 410 | tsta.sta_index = sta_idx; |
368 | tsta.vif_index = avp->index; | 411 | tsta.vif_index = avp->index; |
369 | tsta.maxampdu = 0xffff; | 412 | tsta.maxampdu = 0xffff; |
370 | if (sta && sta->ht_cap.ht_supported) | 413 | if (sta && sta->ht_cap.ht_supported) |
@@ -379,12 +422,21 @@ static int ath9k_htc_add_station(struct ath9k_htc_priv *priv, | |||
379 | return ret; | 422 | return ret; |
380 | } | 423 | } |
381 | 424 | ||
382 | if (sta) | 425 | if (sta) { |
383 | ath_dbg(common, ATH_DBG_CONFIG, | 426 | ath_dbg(common, ATH_DBG_CONFIG, |
384 | "Added a station entry for: %pM (idx: %d)\n", | 427 | "Added a station entry for: %pM (idx: %d)\n", |
385 | sta->addr, tsta.sta_index); | 428 | sta->addr, tsta.sta_index); |
429 | } else { | ||
430 | ath_dbg(common, ATH_DBG_CONFIG, | ||
431 | "Added a station entry for VIF %d (idx: %d)\n", | ||
432 | avp->index, tsta.sta_index); | ||
433 | } | ||
386 | 434 | ||
435 | priv->sta_slot |= (1 << sta_idx); | ||
387 | priv->nstations++; | 436 | priv->nstations++; |
437 | if (!sta) | ||
438 | priv->vif_sta_pos[avp->index] = sta_idx; | ||
439 | |||
388 | return 0; | 440 | return 0; |
389 | } | 441 | } |
390 | 442 | ||
@@ -393,6 +445,7 @@ static int ath9k_htc_remove_station(struct ath9k_htc_priv *priv, | |||
393 | struct ieee80211_sta *sta) | 445 | struct ieee80211_sta *sta) |
394 | { | 446 | { |
395 | struct ath_common *common = ath9k_hw_common(priv->ah); | 447 | struct ath_common *common = ath9k_hw_common(priv->ah); |
448 | struct ath9k_htc_vif *avp = (struct ath9k_htc_vif *) vif->drv_priv; | ||
396 | struct ath9k_htc_sta *ista; | 449 | struct ath9k_htc_sta *ista; |
397 | int ret; | 450 | int ret; |
398 | u8 cmd_rsp, sta_idx; | 451 | u8 cmd_rsp, sta_idx; |
@@ -401,7 +454,7 @@ static int ath9k_htc_remove_station(struct ath9k_htc_priv *priv, | |||
401 | ista = (struct ath9k_htc_sta *) sta->drv_priv; | 454 | ista = (struct ath9k_htc_sta *) sta->drv_priv; |
402 | sta_idx = ista->index; | 455 | sta_idx = ista->index; |
403 | } else { | 456 | } else { |
404 | sta_idx = 0; | 457 | sta_idx = priv->vif_sta_pos[avp->index]; |
405 | } | 458 | } |
406 | 459 | ||
407 | WMI_CMD_BUF(WMI_NODE_REMOVE_CMDID, &sta_idx); | 460 | WMI_CMD_BUF(WMI_NODE_REMOVE_CMDID, &sta_idx); |
@@ -413,12 +466,19 @@ static int ath9k_htc_remove_station(struct ath9k_htc_priv *priv, | |||
413 | return ret; | 466 | return ret; |
414 | } | 467 | } |
415 | 468 | ||
416 | if (sta) | 469 | if (sta) { |
417 | ath_dbg(common, ATH_DBG_CONFIG, | 470 | ath_dbg(common, ATH_DBG_CONFIG, |
418 | "Removed a station entry for: %pM (idx: %d)\n", | 471 | "Removed a station entry for: %pM (idx: %d)\n", |
419 | sta->addr, sta_idx); | 472 | sta->addr, sta_idx); |
473 | } else { | ||
474 | ath_dbg(common, ATH_DBG_CONFIG, | ||
475 | "Removed a station entry for VIF %d (idx: %d)\n", | ||
476 | avp->index, sta_idx); | ||
477 | } | ||
420 | 478 | ||
479 | priv->sta_slot &= ~(1 << sta_idx); | ||
421 | priv->nstations--; | 480 | priv->nstations--; |
481 | |||
422 | return 0; | 482 | return 0; |
423 | } | 483 | } |
424 | 484 | ||
@@ -1049,21 +1109,16 @@ static void ath9k_htc_stop(struct ieee80211_hw *hw) | |||
1049 | 1109 | ||
1050 | mutex_lock(&priv->mutex); | 1110 | mutex_lock(&priv->mutex); |
1051 | 1111 | ||
1052 | /* Remove monitor interface here */ | ||
1053 | if (ah->opmode == NL80211_IFTYPE_MONITOR) { | ||
1054 | if (ath9k_htc_remove_monitor_interface(priv)) | ||
1055 | ath_err(common, "Unable to remove monitor interface\n"); | ||
1056 | else | ||
1057 | ath_dbg(common, ATH_DBG_CONFIG, | ||
1058 | "Monitor interface removed\n"); | ||
1059 | } | ||
1060 | |||
1061 | if (ah->btcoex_hw.enabled) { | 1112 | if (ah->btcoex_hw.enabled) { |
1062 | ath9k_hw_btcoex_disable(ah); | 1113 | ath9k_hw_btcoex_disable(ah); |
1063 | if (ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE) | 1114 | if (ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE) |
1064 | ath_htc_cancel_btcoex_work(priv); | 1115 | ath_htc_cancel_btcoex_work(priv); |
1065 | } | 1116 | } |
1066 | 1117 | ||
1118 | /* Remove a monitor interface if it's present. */ | ||
1119 | if (priv->ah->is_monitoring) | ||
1120 | ath9k_htc_remove_monitor_interface(priv); | ||
1121 | |||
1067 | ath9k_hw_phy_disable(ah); | 1122 | ath9k_hw_phy_disable(ah); |
1068 | ath9k_hw_disable(ah); | 1123 | ath9k_hw_disable(ah); |
1069 | ath9k_htc_ps_restore(priv); | 1124 | ath9k_htc_ps_restore(priv); |
@@ -1087,8 +1142,7 @@ static int ath9k_htc_add_interface(struct ieee80211_hw *hw, | |||
1087 | 1142 | ||
1088 | mutex_lock(&priv->mutex); | 1143 | mutex_lock(&priv->mutex); |
1089 | 1144 | ||
1090 | /* Only one interface for now */ | 1145 | if (priv->nvifs >= ATH9K_HTC_MAX_VIF) { |
1091 | if (priv->nvifs > 0) { | ||
1092 | ret = -ENOBUFS; | 1146 | ret = -ENOBUFS; |
1093 | goto out; | 1147 | goto out; |
1094 | } | 1148 | } |
@@ -1111,13 +1165,8 @@ static int ath9k_htc_add_interface(struct ieee80211_hw *hw, | |||
1111 | goto out; | 1165 | goto out; |
1112 | } | 1166 | } |
1113 | 1167 | ||
1114 | ath_dbg(common, ATH_DBG_CONFIG, | ||
1115 | "Attach a VIF of type: %d\n", vif->type); | ||
1116 | |||
1117 | priv->ah->opmode = vif->type; | ||
1118 | |||
1119 | /* Index starts from zero on the target */ | 1168 | /* Index starts from zero on the target */ |
1120 | avp->index = hvif.index = priv->nvifs; | 1169 | avp->index = hvif.index = ffz(priv->vif_slot); |
1121 | hvif.rtsthreshold = cpu_to_be16(2304); | 1170 | hvif.rtsthreshold = cpu_to_be16(2304); |
1122 | WMI_CMD_BUF(WMI_VAP_CREATE_CMDID, &hvif); | 1171 | WMI_CMD_BUF(WMI_VAP_CREATE_CMDID, &hvif); |
1123 | if (ret) | 1172 | if (ret) |
@@ -1138,7 +1187,13 @@ static int ath9k_htc_add_interface(struct ieee80211_hw *hw, | |||
1138 | ath_dbg(common, ATH_DBG_CONFIG, | 1187 | ath_dbg(common, ATH_DBG_CONFIG, |
1139 | "Failed to update capability in target\n"); | 1188 | "Failed to update capability in target\n"); |
1140 | 1189 | ||
1190 | priv->ah->opmode = vif->type; | ||
1191 | priv->vif_slot |= (1 << avp->index); | ||
1141 | priv->vif = vif; | 1192 | priv->vif = vif; |
1193 | |||
1194 | ath_dbg(common, ATH_DBG_CONFIG, | ||
1195 | "Attach a VIF of type: %d at idx: %d\n", vif->type, avp->index); | ||
1196 | |||
1142 | out: | 1197 | out: |
1143 | ath9k_htc_ps_restore(priv); | 1198 | ath9k_htc_ps_restore(priv); |
1144 | mutex_unlock(&priv->mutex); | 1199 | mutex_unlock(&priv->mutex); |
@@ -1156,8 +1211,6 @@ static void ath9k_htc_remove_interface(struct ieee80211_hw *hw, | |||
1156 | int ret = 0; | 1211 | int ret = 0; |
1157 | u8 cmd_rsp; | 1212 | u8 cmd_rsp; |
1158 | 1213 | ||
1159 | ath_dbg(common, ATH_DBG_CONFIG, "Detach Interface\n"); | ||
1160 | |||
1161 | mutex_lock(&priv->mutex); | 1214 | mutex_lock(&priv->mutex); |
1162 | ath9k_htc_ps_wakeup(priv); | 1215 | ath9k_htc_ps_wakeup(priv); |
1163 | 1216 | ||
@@ -1166,10 +1219,13 @@ static void ath9k_htc_remove_interface(struct ieee80211_hw *hw, | |||
1166 | hvif.index = avp->index; | 1219 | hvif.index = avp->index; |
1167 | WMI_CMD_BUF(WMI_VAP_REMOVE_CMDID, &hvif); | 1220 | WMI_CMD_BUF(WMI_VAP_REMOVE_CMDID, &hvif); |
1168 | priv->nvifs--; | 1221 | priv->nvifs--; |
1222 | priv->vif_slot &= ~(1 << avp->index); | ||
1169 | 1223 | ||
1170 | ath9k_htc_remove_station(priv, vif, NULL); | 1224 | ath9k_htc_remove_station(priv, vif, NULL); |
1171 | priv->vif = NULL; | 1225 | priv->vif = NULL; |
1172 | 1226 | ||
1227 | ath_dbg(common, ATH_DBG_CONFIG, "Detach Interface at idx: %d\n", avp->index); | ||
1228 | |||
1173 | ath9k_htc_ps_restore(priv); | 1229 | ath9k_htc_ps_restore(priv); |
1174 | mutex_unlock(&priv->mutex); | 1230 | mutex_unlock(&priv->mutex); |
1175 | } | 1231 | } |
@@ -1205,13 +1261,11 @@ static int ath9k_htc_config(struct ieee80211_hw *hw, u32 changed) | |||
1205 | * IEEE80211_CONF_CHANGE_CHANNEL is handled. | 1261 | * IEEE80211_CONF_CHANGE_CHANNEL is handled. |
1206 | */ | 1262 | */ |
1207 | if (changed & IEEE80211_CONF_CHANGE_MONITOR) { | 1263 | if (changed & IEEE80211_CONF_CHANGE_MONITOR) { |
1208 | if (conf->flags & IEEE80211_CONF_MONITOR) { | 1264 | if ((conf->flags & IEEE80211_CONF_MONITOR) && |
1209 | if (ath9k_htc_add_monitor_interface(priv)) | 1265 | !priv->ah->is_monitoring) |
1210 | ath_err(common, "Failed to set monitor mode\n"); | 1266 | ath9k_htc_add_monitor_interface(priv); |
1211 | else | 1267 | else if (priv->ah->is_monitoring) |
1212 | ath_dbg(common, ATH_DBG_CONFIG, | 1268 | ath9k_htc_remove_monitor_interface(priv); |
1213 | "HW opmode set to Monitor mode\n"); | ||
1214 | } | ||
1215 | } | 1269 | } |
1216 | 1270 | ||
1217 | if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { | 1271 | if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { |
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c index 7a5ffca21958..d5f0f41b4dec 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c | |||
@@ -84,7 +84,9 @@ int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, struct sk_buff *skb) | |||
84 | struct ieee80211_hdr *hdr; | 84 | struct ieee80211_hdr *hdr; |
85 | struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); | 85 | struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); |
86 | struct ieee80211_sta *sta = tx_info->control.sta; | 86 | struct ieee80211_sta *sta = tx_info->control.sta; |
87 | struct ieee80211_vif *vif = tx_info->control.vif; | ||
87 | struct ath9k_htc_sta *ista; | 88 | struct ath9k_htc_sta *ista; |
89 | struct ath9k_htc_vif *avp; | ||
88 | struct ath9k_htc_tx_ctl tx_ctl; | 90 | struct ath9k_htc_tx_ctl tx_ctl; |
89 | enum htc_endpoint_id epid; | 91 | enum htc_endpoint_id epid; |
90 | u16 qnum; | 92 | u16 qnum; |
@@ -95,18 +97,31 @@ int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, struct sk_buff *skb) | |||
95 | hdr = (struct ieee80211_hdr *) skb->data; | 97 | hdr = (struct ieee80211_hdr *) skb->data; |
96 | fc = hdr->frame_control; | 98 | fc = hdr->frame_control; |
97 | 99 | ||
98 | if (tx_info->control.vif && | 100 | /* |
99 | (struct ath9k_htc_vif *) tx_info->control.vif->drv_priv) | 101 | * Find out on which interface this packet has to be |
100 | vif_idx = ((struct ath9k_htc_vif *) | 102 | * sent out. |
101 | tx_info->control.vif->drv_priv)->index; | 103 | */ |
102 | else | 104 | if (vif) { |
103 | vif_idx = priv->nvifs; | 105 | avp = (struct ath9k_htc_vif *) vif->drv_priv; |
106 | vif_idx = avp->index; | ||
107 | } else { | ||
108 | if (!priv->ah->is_monitoring) { | ||
109 | ath_dbg(ath9k_hw_common(priv->ah), ATH_DBG_XMIT, | ||
110 | "VIF is null, but no monitor interface !\n"); | ||
111 | return -EINVAL; | ||
112 | } | ||
104 | 113 | ||
114 | vif_idx = priv->mon_vif_idx; | ||
115 | } | ||
116 | |||
117 | /* | ||
118 | * Find out which station this packet is destined for. | ||
119 | */ | ||
105 | if (sta) { | 120 | if (sta) { |
106 | ista = (struct ath9k_htc_sta *) sta->drv_priv; | 121 | ista = (struct ath9k_htc_sta *) sta->drv_priv; |
107 | sta_idx = ista->index; | 122 | sta_idx = ista->index; |
108 | } else { | 123 | } else { |
109 | sta_idx = 0; | 124 | sta_idx = priv->vif_sta_pos[vif_idx]; |
110 | } | 125 | } |
111 | 126 | ||
112 | memset(&tx_ctl, 0, sizeof(struct ath9k_htc_tx_ctl)); | 127 | memset(&tx_ctl, 0, sizeof(struct ath9k_htc_tx_ctl)); |