Commit 7962b0d8 authored by Michal Kazior's avatar Michal Kazior Committed by Kalle Valo

ath10k: speed up hw recovery

In some cases hw recovery was taking an absurdly
long time due to ath10k waiting for things that
would never really complete.

Instead of waiting for inevitable timeouts poke
all completions and wakequeues and check if it's
still worth waiting.

Reading/writing ar->state requires conf_mutex.
Since waiters might be holding it introduce a new
flag CRASH_FLUSH so it's possible to tell waiters
to abort whatever they were waiting for.
Signed-off-by: default avatarMichal Kazior <michal.kazior@tieto.com>
Signed-off-by: default avatarKalle Valo <kvalo@qca.qualcomm.com>
parent 605cdba1
...@@ -744,6 +744,25 @@ static void ath10k_core_restart(struct work_struct *work) ...@@ -744,6 +744,25 @@ static void ath10k_core_restart(struct work_struct *work)
{ {
struct ath10k *ar = container_of(work, struct ath10k, restart_work); struct ath10k *ar = container_of(work, struct ath10k, restart_work);
set_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags);
/* Place a barrier to make sure the compiler doesn't reorder
* CRASH_FLUSH and calling other functions.
*/
barrier();
ieee80211_stop_queues(ar->hw);
ath10k_drain_tx(ar);
complete_all(&ar->scan.started);
complete_all(&ar->scan.completed);
complete_all(&ar->scan.on_channel);
complete_all(&ar->offchan_tx_completed);
complete_all(&ar->install_key_done);
complete_all(&ar->vdev_setup_done);
wake_up(&ar->htt.empty_tx_wq);
wake_up(&ar->wmi.tx_credits_wq);
wake_up(&ar->peer_mapping_wq);
mutex_lock(&ar->conf_mutex); mutex_lock(&ar->conf_mutex);
switch (ar->state) { switch (ar->state) {
...@@ -781,6 +800,8 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode) ...@@ -781,6 +800,8 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode)
lockdep_assert_held(&ar->conf_mutex); lockdep_assert_held(&ar->conf_mutex);
clear_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags);
ath10k_bmi_start(ar); ath10k_bmi_start(ar);
if (ath10k_init_configure_target(ar)) { if (ath10k_init_configure_target(ar)) {
...@@ -1185,6 +1206,8 @@ struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev, ...@@ -1185,6 +1206,8 @@ struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev,
INIT_LIST_HEAD(&ar->peers); INIT_LIST_HEAD(&ar->peers);
init_waitqueue_head(&ar->peer_mapping_wq); init_waitqueue_head(&ar->peer_mapping_wq);
init_waitqueue_head(&ar->htt.empty_tx_wq);
init_waitqueue_head(&ar->wmi.tx_credits_wq);
init_completion(&ar->offchan_tx_completed); init_completion(&ar->offchan_tx_completed);
INIT_WORK(&ar->offchan_tx_work, ath10k_offchan_tx_work); INIT_WORK(&ar->offchan_tx_work, ath10k_offchan_tx_work);
......
...@@ -386,6 +386,11 @@ enum ath10k_dev_flags { ...@@ -386,6 +386,11 @@ enum ath10k_dev_flags {
/* Indicates that ath10k device is during CAC phase of DFS */ /* Indicates that ath10k device is during CAC phase of DFS */
ATH10K_CAC_RUNNING, ATH10K_CAC_RUNNING,
ATH10K_FLAG_CORE_REGISTERED, ATH10K_FLAG_CORE_REGISTERED,
/* Device has crashed and needs to restart. This indicates any pending
* waiters should immediately cancel instead of waiting for a time out.
*/
ATH10K_FLAG_CRASH_FLUSH,
}; };
enum ath10k_cal_mode { enum ath10k_cal_mode {
......
...@@ -92,7 +92,6 @@ int ath10k_htt_tx_alloc(struct ath10k_htt *htt) ...@@ -92,7 +92,6 @@ int ath10k_htt_tx_alloc(struct ath10k_htt *htt)
struct ath10k *ar = htt->ar; struct ath10k *ar = htt->ar;
spin_lock_init(&htt->tx_lock); spin_lock_init(&htt->tx_lock);
init_waitqueue_head(&htt->empty_tx_wq);
if (test_bit(ATH10K_FW_FEATURE_WMI_10X, htt->ar->fw_features)) if (test_bit(ATH10K_FW_FEATURE_WMI_10X, htt->ar->fw_features))
htt->max_num_pending_tx = TARGET_10X_NUM_MSDU_DESC; htt->max_num_pending_tx = TARGET_10X_NUM_MSDU_DESC;
......
...@@ -519,6 +519,9 @@ static inline int ath10k_vdev_setup_sync(struct ath10k *ar) ...@@ -519,6 +519,9 @@ static inline int ath10k_vdev_setup_sync(struct ath10k *ar)
lockdep_assert_held(&ar->conf_mutex); lockdep_assert_held(&ar->conf_mutex);
if (test_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags))
return -ESHUTDOWN;
ret = wait_for_completion_timeout(&ar->vdev_setup_done, ret = wait_for_completion_timeout(&ar->vdev_setup_done,
ATH10K_VDEV_SETUP_TIMEOUT_HZ); ATH10K_VDEV_SETUP_TIMEOUT_HZ);
if (ret == 0) if (ret == 0)
...@@ -551,6 +554,8 @@ static int ath10k_monitor_vdev_start(struct ath10k *ar, int vdev_id) ...@@ -551,6 +554,8 @@ static int ath10k_monitor_vdev_start(struct ath10k *ar, int vdev_id)
arg.channel.max_reg_power = channel->max_reg_power * 2; arg.channel.max_reg_power = channel->max_reg_power * 2;
arg.channel.max_antenna_gain = channel->max_antenna_gain * 2; arg.channel.max_antenna_gain = channel->max_antenna_gain * 2;
reinit_completion(&ar->vdev_setup_done);
ret = ath10k_wmi_vdev_start(ar, &arg); ret = ath10k_wmi_vdev_start(ar, &arg);
if (ret) { if (ret) {
ath10k_warn(ar, "failed to request monitor vdev %i start: %d\n", ath10k_warn(ar, "failed to request monitor vdev %i start: %d\n",
...@@ -598,6 +603,8 @@ static int ath10k_monitor_vdev_stop(struct ath10k *ar) ...@@ -598,6 +603,8 @@ static int ath10k_monitor_vdev_stop(struct ath10k *ar)
ath10k_warn(ar, "failed to put down monitor vdev %i: %d\n", ath10k_warn(ar, "failed to put down monitor vdev %i: %d\n",
ar->monitor_vdev_id, ret); ar->monitor_vdev_id, ret);
reinit_completion(&ar->vdev_setup_done);
ret = ath10k_wmi_vdev_stop(ar, ar->monitor_vdev_id); ret = ath10k_wmi_vdev_stop(ar, ar->monitor_vdev_id);
if (ret) if (ret)
ath10k_warn(ar, "failed to to request monitor vdev %i stop: %d\n", ath10k_warn(ar, "failed to to request monitor vdev %i stop: %d\n",
...@@ -2350,7 +2357,7 @@ static void ath10k_tx(struct ieee80211_hw *hw, ...@@ -2350,7 +2357,7 @@ static void ath10k_tx(struct ieee80211_hw *hw,
} }
/* Must not be called with conf_mutex held as workers can use that also. */ /* Must not be called with conf_mutex held as workers can use that also. */
static void ath10k_drain_tx(struct ath10k *ar) void ath10k_drain_tx(struct ath10k *ar)
{ {
/* make sure rcu-protected mac80211 tx path itself is drained */ /* make sure rcu-protected mac80211 tx path itself is drained */
synchronize_net(); synchronize_net();
...@@ -3910,7 +3917,9 @@ static void ath10k_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, ...@@ -3910,7 +3917,9 @@ static void ath10k_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
empty = (ar->htt.num_pending_tx == 0); empty = (ar->htt.num_pending_tx == 0);
spin_unlock_bh(&ar->htt.tx_lock); spin_unlock_bh(&ar->htt.tx_lock);
skip = (ar->state == ATH10K_STATE_WEDGED); skip = (ar->state == ATH10K_STATE_WEDGED) ||
test_bit(ATH10K_FLAG_CRASH_FLUSH,
&ar->dev_flags);
(empty || skip); (empty || skip);
}), ATH10K_FLUSH_TIMEOUT_HZ); }), ATH10K_FLUSH_TIMEOUT_HZ);
...@@ -4007,6 +4016,7 @@ static void ath10k_restart_complete(struct ieee80211_hw *hw) ...@@ -4007,6 +4016,7 @@ static void ath10k_restart_complete(struct ieee80211_hw *hw)
if (ar->state == ATH10K_STATE_RESTARTED) { if (ar->state == ATH10K_STATE_RESTARTED) {
ath10k_info(ar, "device successfully recovered\n"); ath10k_info(ar, "device successfully recovered\n");
ar->state = ATH10K_STATE_ON; ar->state = ATH10K_STATE_ON;
ieee80211_wake_queues(ar->hw);
} }
mutex_unlock(&ar->conf_mutex); mutex_unlock(&ar->conf_mutex);
......
...@@ -40,6 +40,7 @@ void ath10k_mgmt_over_wmi_tx_purge(struct ath10k *ar); ...@@ -40,6 +40,7 @@ void ath10k_mgmt_over_wmi_tx_purge(struct ath10k *ar);
void ath10k_mgmt_over_wmi_tx_work(struct work_struct *work); void ath10k_mgmt_over_wmi_tx_work(struct work_struct *work);
void ath10k_halt(struct ath10k *ar); void ath10k_halt(struct ath10k *ar);
void ath10k_mac_vif_beacon_free(struct ath10k_vif *arvif); void ath10k_mac_vif_beacon_free(struct ath10k_vif *arvif);
void ath10k_drain_tx(struct ath10k *ar);
static inline struct ath10k_vif *ath10k_vif_to_arvif(struct ieee80211_vif *vif) static inline struct ath10k_vif *ath10k_vif_to_arvif(struct ieee80211_vif *vif)
{ {
......
...@@ -146,7 +146,8 @@ static int ath10k_wait_for_peer_common(struct ath10k *ar, int vdev_id, ...@@ -146,7 +146,8 @@ static int ath10k_wait_for_peer_common(struct ath10k *ar, int vdev_id,
mapped = !!ath10k_peer_find(ar, vdev_id, addr); mapped = !!ath10k_peer_find(ar, vdev_id, addr);
spin_unlock_bh(&ar->data_lock); spin_unlock_bh(&ar->data_lock);
mapped == expect_mapped; (mapped == expect_mapped ||
test_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags));
}), 3*HZ); }), 3*HZ);
if (ret <= 0) if (ret <= 0)
......
...@@ -779,6 +779,10 @@ int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb, u32 cmd_id) ...@@ -779,6 +779,10 @@ int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb, u32 cmd_id)
ath10k_wmi_tx_beacons_nowait(ar); ath10k_wmi_tx_beacons_nowait(ar);
ret = ath10k_wmi_cmd_send_nowait(ar, skb, cmd_id); ret = ath10k_wmi_cmd_send_nowait(ar, skb, cmd_id);
if (ret && test_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags))
ret = -ESHUTDOWN;
(ret != -EAGAIN); (ret != -EAGAIN);
}), 3*HZ); }), 3*HZ);
...@@ -4398,7 +4402,6 @@ int ath10k_wmi_attach(struct ath10k *ar) ...@@ -4398,7 +4402,6 @@ int ath10k_wmi_attach(struct ath10k *ar)
init_completion(&ar->wmi.service_ready); init_completion(&ar->wmi.service_ready);
init_completion(&ar->wmi.unified_ready); init_completion(&ar->wmi.unified_ready);
init_waitqueue_head(&ar->wmi.tx_credits_wq);
return 0; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment