diff options
author | Michal Kazior <michal.kazior@tieto.com> | 2014-05-26 05:46:03 -0400 |
---|---|---|
committer | Kalle Valo <kvalo@qca.qualcomm.com> | 2014-05-27 05:27:59 -0400 |
commit | bca7bafbe2b75ed31cc6943b81218ea0f8a13686 (patch) | |
tree | bc42e3d0bf2ee9a4aae1515584c214976e00a12c | |
parent | c5058f5b82f226b236dc5a65015152ed3c23efff (diff) |
ath10k: drain tx before restarting hw
This makes sure no further tx requests are
submitted to HTT before driver teardown.
This should prevent invalid pointer/NULL
dereference on htt tx pool in ath10k_htt_tx() in
some cases of heavy traffic.
kvalo: remove the WARN_ON() if conf_mutex is held
Reported-By: Ben Greear <greearb@candelatech.com>
Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
-rw-r--r-- | drivers/net/wireless/ath/ath10k/mac.c | 31 |
1 files changed, 22 insertions, 9 deletions
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index d73f146611b9..8ad03d530820 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c | |||
@@ -2289,9 +2289,19 @@ static void ath10k_tx(struct ieee80211_hw *hw, | |||
2289 | ath10k_tx_htt(ar, skb); | 2289 | ath10k_tx_htt(ar, skb); |
2290 | } | 2290 | } |
2291 | 2291 | ||
2292 | /* | 2292 | /* Must not be called with conf_mutex held as workers can use that also. */ |
2293 | * Initialize various parameters with default vaules. | 2293 | static void ath10k_drain_tx(struct ath10k *ar) |
2294 | */ | 2294 | { |
2295 | /* make sure rcu-protected mac80211 tx path itself is drained */ | ||
2296 | synchronize_net(); | ||
2297 | |||
2298 | ath10k_offchan_tx_purge(ar); | ||
2299 | ath10k_mgmt_over_wmi_tx_purge(ar); | ||
2300 | |||
2301 | cancel_work_sync(&ar->offchan_tx_work); | ||
2302 | cancel_work_sync(&ar->wmi_mgmt_tx_work); | ||
2303 | } | ||
2304 | |||
2295 | void ath10k_halt(struct ath10k *ar) | 2305 | void ath10k_halt(struct ath10k *ar) |
2296 | { | 2306 | { |
2297 | struct ath10k_vif *arvif; | 2307 | struct ath10k_vif *arvif; |
@@ -2307,8 +2317,6 @@ void ath10k_halt(struct ath10k *ar) | |||
2307 | 2317 | ||
2308 | del_timer_sync(&ar->scan.timeout); | 2318 | del_timer_sync(&ar->scan.timeout); |
2309 | ath10k_reset_scan((unsigned long)ar); | 2319 | ath10k_reset_scan((unsigned long)ar); |
2310 | ath10k_offchan_tx_purge(ar); | ||
2311 | ath10k_mgmt_over_wmi_tx_purge(ar); | ||
2312 | ath10k_peer_cleanup_all(ar); | 2320 | ath10k_peer_cleanup_all(ar); |
2313 | ath10k_core_stop(ar); | 2321 | ath10k_core_stop(ar); |
2314 | ath10k_hif_power_down(ar); | 2322 | ath10k_hif_power_down(ar); |
@@ -2394,6 +2402,13 @@ static int ath10k_start(struct ieee80211_hw *hw) | |||
2394 | struct ath10k *ar = hw->priv; | 2402 | struct ath10k *ar = hw->priv; |
2395 | int ret = 0; | 2403 | int ret = 0; |
2396 | 2404 | ||
2405 | /* | ||
2406 | * This makes sense only when restarting hw. It is harmless to call | ||
2407 | * uncoditionally. This is necessary to make sure no HTT/WMI tx | ||
2408 | * commands will be submitted while restarting. | ||
2409 | */ | ||
2410 | ath10k_drain_tx(ar); | ||
2411 | |||
2397 | mutex_lock(&ar->conf_mutex); | 2412 | mutex_lock(&ar->conf_mutex); |
2398 | 2413 | ||
2399 | switch (ar->state) { | 2414 | switch (ar->state) { |
@@ -2481,6 +2496,8 @@ static void ath10k_stop(struct ieee80211_hw *hw) | |||
2481 | { | 2496 | { |
2482 | struct ath10k *ar = hw->priv; | 2497 | struct ath10k *ar = hw->priv; |
2483 | 2498 | ||
2499 | ath10k_drain_tx(ar); | ||
2500 | |||
2484 | mutex_lock(&ar->conf_mutex); | 2501 | mutex_lock(&ar->conf_mutex); |
2485 | if (ar->state != ATH10K_STATE_OFF) { | 2502 | if (ar->state != ATH10K_STATE_OFF) { |
2486 | ath10k_halt(ar); | 2503 | ath10k_halt(ar); |
@@ -2488,10 +2505,6 @@ static void ath10k_stop(struct ieee80211_hw *hw) | |||
2488 | } | 2505 | } |
2489 | mutex_unlock(&ar->conf_mutex); | 2506 | mutex_unlock(&ar->conf_mutex); |
2490 | 2507 | ||
2491 | ath10k_mgmt_over_wmi_tx_purge(ar); | ||
2492 | |||
2493 | cancel_work_sync(&ar->offchan_tx_work); | ||
2494 | cancel_work_sync(&ar->wmi_mgmt_tx_work); | ||
2495 | cancel_work_sync(&ar->restart_work); | 2508 | cancel_work_sync(&ar->restart_work); |
2496 | } | 2509 | } |
2497 | 2510 | ||