Skip to content

Commit

Permalink
ath10k: speed up hw recovery
Browse files Browse the repository at this point in the history
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: Michal Kazior <michal.kazior@tieto.com>
Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
  • Loading branch information
Michal Kazior authored and Kalle Valo committed Oct 31, 2014
1 parent 605cdba commit 7962b0d
Show file tree
Hide file tree
Showing 7 changed files with 47 additions and 5 deletions.
23 changes: 23 additions & 0 deletions drivers/net/wireless/ath/ath10k/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -744,6 +744,25 @@ static void ath10k_core_restart(struct work_struct *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);

switch (ar->state) {
Expand Down Expand Up @@ -781,6 +800,8 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode)

lockdep_assert_held(&ar->conf_mutex);

clear_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags);

ath10k_bmi_start(ar);

if (ath10k_init_configure_target(ar)) {
Expand Down Expand Up @@ -1185,6 +1206,8 @@ struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev,

INIT_LIST_HEAD(&ar->peers);
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_WORK(&ar->offchan_tx_work, ath10k_offchan_tx_work);
Expand Down
5 changes: 5 additions & 0 deletions drivers/net/wireless/ath/ath10k/core.h
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,11 @@ enum ath10k_dev_flags {
/* Indicates that ath10k device is during CAC phase of DFS */
ATH10K_CAC_RUNNING,
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 {
Expand Down
1 change: 0 additions & 1 deletion drivers/net/wireless/ath/ath10k/htt_tx.c
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,6 @@ int ath10k_htt_tx_alloc(struct ath10k_htt *htt)
struct ath10k *ar = htt->ar;

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))
htt->max_num_pending_tx = TARGET_10X_NUM_MSDU_DESC;
Expand Down
14 changes: 12 additions & 2 deletions drivers/net/wireless/ath/ath10k/mac.c
Original file line number Diff line number Diff line change
Expand Up @@ -519,6 +519,9 @@ static inline int ath10k_vdev_setup_sync(struct ath10k *ar)

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,
ATH10K_VDEV_SETUP_TIMEOUT_HZ);
if (ret == 0)
Expand Down Expand Up @@ -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_antenna_gain = channel->max_antenna_gain * 2;

reinit_completion(&ar->vdev_setup_done);

ret = ath10k_wmi_vdev_start(ar, &arg);
if (ret) {
ath10k_warn(ar, "failed to request monitor vdev %i start: %d\n",
Expand Down Expand Up @@ -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",
ar->monitor_vdev_id, ret);

reinit_completion(&ar->vdev_setup_done);

ret = ath10k_wmi_vdev_stop(ar, ar->monitor_vdev_id);
if (ret)
ath10k_warn(ar, "failed to to request monitor vdev %i stop: %d\n",
Expand Down Expand Up @@ -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. */
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 */
synchronize_net();
Expand Down Expand Up @@ -3910,7 +3917,9 @@ static void ath10k_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
empty = (ar->htt.num_pending_tx == 0);
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);
}), ATH10K_FLUSH_TIMEOUT_HZ);
Expand Down Expand Up @@ -4007,6 +4016,7 @@ static void ath10k_restart_complete(struct ieee80211_hw *hw)
if (ar->state == ATH10K_STATE_RESTARTED) {
ath10k_info(ar, "device successfully recovered\n");
ar->state = ATH10K_STATE_ON;
ieee80211_wake_queues(ar->hw);
}

mutex_unlock(&ar->conf_mutex);
Expand Down
1 change: 1 addition & 0 deletions drivers/net/wireless/ath/ath10k/mac.h
Original file line number Diff line number Diff line change
Expand Up @@ -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_halt(struct ath10k *ar);
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)
{
Expand Down
3 changes: 2 additions & 1 deletion drivers/net/wireless/ath/ath10k/txrx.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
spin_unlock_bh(&ar->data_lock);

mapped == expect_mapped;
(mapped == expect_mapped ||
test_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags));
}), 3*HZ);

if (ret <= 0)
Expand Down
5 changes: 4 additions & 1 deletion drivers/net/wireless/ath/ath10k/wmi.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);

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);
}), 3*HZ);

Expand Down Expand Up @@ -4398,7 +4402,6 @@ int ath10k_wmi_attach(struct ath10k *ar)

init_completion(&ar->wmi.service_ready);
init_completion(&ar->wmi.unified_ready);
init_waitqueue_head(&ar->wmi.tx_credits_wq);

return 0;
}
Expand Down

0 comments on commit 7962b0d

Please sign in to comment.