aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichal Kazior <michal.kazior@tieto.com>2014-05-26 05:46:03 -0400
committerKalle Valo <kvalo@qca.qualcomm.com>2014-05-27 05:27:59 -0400
commitbca7bafbe2b75ed31cc6943b81218ea0f8a13686 (patch)
treebc42e3d0bf2ee9a4aae1515584c214976e00a12c
parentc5058f5b82f226b236dc5a65015152ed3c23efff (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.c31
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. 2293static 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
2295void ath10k_halt(struct ath10k *ar) 2305void 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