From: Sven Eckelmann <seckelmann@xxxxxxxxx> The survey counters from firmwares like 10.2.4 are not actually using the full 64 bit. Instead, they only use the lower 31 bit and overflow ever 14-30s. The driver must frequently fetch the survey data and add it to the survey data storage to avoid this problem and to present meaningful values to the caller of .get_survey. It is assumed for now that only the current rx_channel retrieves relevant updates for the survey data. This should avoid that the bss channel survey request times out too often. Tested on QCA988x hw2.0 10.2.4-1.0-00043 Signed-off-by: Sven Eckelmann <seckelmann@xxxxxxxxx> --- drivers/net/wireless/ath/ath10k/core.c | 8 ++++ drivers/net/wireless/ath/ath10k/core.h | 1 + drivers/net/wireless/ath/ath10k/mac.c | 52 ++++++++++++++++++++++++++ drivers/net/wireless/ath/ath10k/mac.h | 3 ++ 4 files changed, 64 insertions(+) diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index dc45d16e8d21..754c46047b15 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -2788,8 +2788,14 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode, goto err_hif_stop; } + status = ath10k_survey_start(ar); + if (status) + goto err_debug_stop; + return 0; +err_debug_stop: + ath10k_debug_stop(ar); err_hif_stop: ath10k_hif_stop(ar); err_htt_rx_detach: @@ -2829,6 +2835,7 @@ int ath10k_wait_for_suspend(struct ath10k *ar, u32 suspend_opt) void ath10k_core_stop(struct ath10k *ar) { lockdep_assert_held(&ar->conf_mutex); + ath10k_survey_stop(ar); ath10k_debug_stop(ar); /* try to suspend target */ @@ -3179,6 +3186,7 @@ struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev, init_completion(&ar->peer_delete_done); INIT_DELAYED_WORK(&ar->scan.timeout, ath10k_scan_timeout_work); + INIT_DELAYED_WORK(&ar->survey_dwork, ath10k_survey_dwork); ar->workqueue = create_singlethread_workqueue("ath10k_wq"); if (!ar->workqueue) diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 25c699f3a73b..66d2a1263898 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -1129,6 +1129,7 @@ struct ath10k { struct survey_info survey[ATH10K_NUM_CHANS]; u64 survey_last_total_cc[ATH10K_NUM_CHANS]; u64 survey_last_busy_cc[ATH10K_NUM_CHANS]; + struct delayed_work survey_dwork; /* Channel info events are expected to come in pairs without and with * COMPLETE flag set respectively for each channel visit during scan. diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 12dad659bf68..4190b0148e97 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -24,6 +24,9 @@ #include "wmi-ops.h" #include "wow.h" +/* ms */ +#define ATH10K_SURVEY_INTERVAL 10000 + /*********/ /* Rates */ /*********/ @@ -7152,6 +7155,55 @@ ath10k_mac_update_bss_chan_survey(struct ath10k *ar, } } +static void ath10k_request_survey(struct ath10k *ar) +{ + lockdep_assert_held(&ar->conf_mutex); + + if (ar->state != ATH10K_STATE_ON) + return; + + if (!ar->rx_channel) + return; + + ath10k_mac_update_bss_chan_survey(ar, ar->rx_channel); +} + +void ath10k_survey_dwork(struct work_struct *work) +{ + struct ath10k *ar = container_of(work, struct ath10k, + survey_dwork.work); + + mutex_lock(&ar->conf_mutex); + ath10k_request_survey(ar); + mutex_unlock(&ar->conf_mutex); + + queue_delayed_work(ar->workqueue, &ar->survey_dwork, + msecs_to_jiffies(ATH10K_SURVEY_INTERVAL)); +} + +int ath10k_survey_start(struct ath10k *ar) +{ + lockdep_assert_held(&ar->conf_mutex); + + if (ar->hw_params.cc_wraparound_type != ATH10K_HW_CC_WRAP_SHIFTED_ALL) + return 0; + + queue_delayed_work(ar->workqueue, &ar->survey_dwork, + msecs_to_jiffies(ATH10K_SURVEY_INTERVAL)); + + return 0; +} + +void ath10k_survey_stop(struct ath10k *ar) +{ + lockdep_assert_held(&ar->conf_mutex); + + if (ar->hw_params.cc_wraparound_type != ATH10K_HW_CC_WRAP_SHIFTED_ALL) + return; + + cancel_delayed_work_sync(&ar->survey_dwork); +} + static int ath10k_get_survey(struct ieee80211_hw *hw, int idx, struct survey_info *survey) { diff --git a/drivers/net/wireless/ath/ath10k/mac.h b/drivers/net/wireless/ath/ath10k/mac.h index 1fe84948b868..17e4d65edbe0 100644 --- a/drivers/net/wireless/ath/ath10k/mac.h +++ b/drivers/net/wireless/ath/ath10k/mac.h @@ -40,6 +40,9 @@ void ath10k_offchan_tx_purge(struct ath10k *ar); void ath10k_offchan_tx_work(struct work_struct *work); void ath10k_mgmt_over_wmi_tx_purge(struct ath10k *ar); void ath10k_mgmt_over_wmi_tx_work(struct work_struct *work); +void ath10k_survey_dwork(struct work_struct *work); +int ath10k_survey_start(struct ath10k *ar); +void ath10k_survey_stop(struct ath10k *ar); void ath10k_halt(struct ath10k *ar); void ath10k_mac_vif_beacon_free(struct ath10k_vif *arvif); void ath10k_drain_tx(struct ath10k *ar); -- 2.20.1