Commit fa7937e3 authored by Rajkumar Manoharan's avatar Rajkumar Manoharan Committed by Kalle Valo

ath10k: update bss channel survey information

During hw scan, firmware sends two channel information events (pre-
complete, complete) to host for each channel change. The snap shot of cycle
counters (rx_clear and total) between these two events are given for
survey dump. In order to get latest survey statistics of all channels, a
scan request has to be issued. In general, an AP DUT is brought up, it
won't leave BSS channel except few cases like overlapping bss or radar
detection. So survey statistics of bss channel is always referring to
older data that are collected before starting AP (either ACS/OBSS scan).

To collect latest survey information from target, firmware provides WMI
interface to read cycle counters from hardware. For each survey dump
request, BSS channel cycle counters are read and cleared in hardware.
This makes sure that behavior is in align with ath9k survey report.
So survey dump always gives snap shot of cycle counters b/w two survey
requests.
Signed-off-by: default avatarYanbo Li <yanbol@qca.qualcomm.com>
Signed-off-by: default avatarRajkumar Manoharan <rmanohar@qti.qualcomm.com>
Signed-off-by: default avatarKalle Valo <kvalo@qca.qualcomm.com>
parent 89d2d183
...@@ -1392,6 +1392,7 @@ static void ath10k_core_restart(struct work_struct *work) ...@@ -1392,6 +1392,7 @@ static void ath10k_core_restart(struct work_struct *work)
complete_all(&ar->install_key_done); complete_all(&ar->install_key_done);
complete_all(&ar->vdev_setup_done); complete_all(&ar->vdev_setup_done);
complete_all(&ar->thermal.wmi_sync); complete_all(&ar->thermal.wmi_sync);
complete_all(&ar->bss_survey_done);
wake_up(&ar->htt.empty_tx_wq); wake_up(&ar->htt.empty_tx_wq);
wake_up(&ar->wmi.tx_credits_wq); wake_up(&ar->wmi.tx_credits_wq);
wake_up(&ar->peer_mapping_wq); wake_up(&ar->peer_mapping_wq);
...@@ -1724,6 +1725,9 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode, ...@@ -1724,6 +1725,9 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode,
if (ath10k_peer_stats_enabled(ar)) if (ath10k_peer_stats_enabled(ar))
val = WMI_10_4_PEER_STATS; val = WMI_10_4_PEER_STATS;
if (test_bit(WMI_SERVICE_BSS_CHANNEL_INFO_64, ar->wmi.svc_map))
val |= WMI_10_4_BSS_CHANNEL_INFO_64;
status = ath10k_mac_ext_resource_config(ar, val); status = ath10k_mac_ext_resource_config(ar, val);
if (status) { if (status) {
ath10k_err(ar, ath10k_err(ar,
...@@ -2085,6 +2089,7 @@ struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev, ...@@ -2085,6 +2089,7 @@ struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev,
init_completion(&ar->install_key_done); init_completion(&ar->install_key_done);
init_completion(&ar->vdev_setup_done); init_completion(&ar->vdev_setup_done);
init_completion(&ar->thermal.wmi_sync); init_completion(&ar->thermal.wmi_sync);
init_completion(&ar->bss_survey_done);
INIT_DELAYED_WORK(&ar->scan.timeout, ath10k_scan_timeout_work); INIT_DELAYED_WORK(&ar->scan.timeout, ath10k_scan_timeout_work);
......
...@@ -876,6 +876,7 @@ struct ath10k { ...@@ -876,6 +876,7 @@ struct ath10k {
* avoid reporting garbage data. * avoid reporting garbage data.
*/ */
bool ch_info_can_report_survey; bool ch_info_can_report_survey;
struct completion bss_survey_done;
struct dfs_pattern_detector *dfs_detector; struct dfs_pattern_detector *dfs_detector;
......
...@@ -6404,6 +6404,39 @@ static void ath10k_reconfig_complete(struct ieee80211_hw *hw, ...@@ -6404,6 +6404,39 @@ static void ath10k_reconfig_complete(struct ieee80211_hw *hw,
mutex_unlock(&ar->conf_mutex); mutex_unlock(&ar->conf_mutex);
} }
static void
ath10k_mac_update_bss_chan_survey(struct ath10k *ar,
struct ieee80211_channel *channel)
{
int ret;
enum wmi_bss_survey_req_type type = WMI_BSS_SURVEY_REQ_TYPE_READ_CLEAR;
lockdep_assert_held(&ar->conf_mutex);
if (!test_bit(WMI_SERVICE_BSS_CHANNEL_INFO_64, ar->wmi.svc_map) ||
(ar->rx_channel != channel))
return;
if (ar->scan.state != ATH10K_SCAN_IDLE) {
ath10k_dbg(ar, ATH10K_DBG_MAC, "ignoring bss chan info request while scanning..\n");
return;
}
reinit_completion(&ar->bss_survey_done);
ret = ath10k_wmi_pdev_bss_chan_info_request(ar, type);
if (ret) {
ath10k_warn(ar, "failed to send pdev bss chan info request\n");
return;
}
ret = wait_for_completion_timeout(&ar->bss_survey_done, 3 * HZ);
if (!ret) {
ath10k_warn(ar, "bss channel survey timed out\n");
return;
}
}
static int ath10k_get_survey(struct ieee80211_hw *hw, int idx, static int ath10k_get_survey(struct ieee80211_hw *hw, int idx,
struct survey_info *survey) struct survey_info *survey)
{ {
...@@ -6428,6 +6461,8 @@ static int ath10k_get_survey(struct ieee80211_hw *hw, int idx, ...@@ -6428,6 +6461,8 @@ static int ath10k_get_survey(struct ieee80211_hw *hw, int idx,
goto exit; goto exit;
} }
ath10k_mac_update_bss_chan_survey(ar, survey->channel);
spin_lock_bh(&ar->data_lock); spin_lock_bh(&ar->data_lock);
memcpy(survey, ar_survey, sizeof(*survey)); memcpy(survey, ar_survey, sizeof(*survey));
spin_unlock_bh(&ar->data_lock); spin_unlock_bh(&ar->data_lock);
......
...@@ -4798,8 +4798,11 @@ static int ath10k_wmi_event_pdev_bss_chan_info(struct ath10k *ar, ...@@ -4798,8 +4798,11 @@ static int ath10k_wmi_event_pdev_bss_chan_info(struct ath10k *ar,
struct sk_buff *skb) struct sk_buff *skb)
{ {
struct wmi_pdev_bss_chan_info_event *ev; struct wmi_pdev_bss_chan_info_event *ev;
struct survey_info *survey;
u64 busy, total, tx, rx, rx_bss; u64 busy, total, tx, rx, rx_bss;
u32 freq, noise_floor; u32 freq, noise_floor;
u32 cc_freq_hz = ar->hw_params.channel_counters_freq_hz;
int idx;
ev = (struct wmi_pdev_bss_chan_info_event *)skb->data; ev = (struct wmi_pdev_bss_chan_info_event *)skb->data;
if (WARN_ON(skb->len < sizeof(*ev))) if (WARN_ON(skb->len < sizeof(*ev)))
...@@ -4817,6 +4820,29 @@ static int ath10k_wmi_event_pdev_bss_chan_info(struct ath10k *ar, ...@@ -4817,6 +4820,29 @@ static int ath10k_wmi_event_pdev_bss_chan_info(struct ath10k *ar,
"wmi event pdev bss chan info:\n freq: %d noise: %d cycle: busy %llu total %llu tx %llu rx %llu rx_bss %llu\n", "wmi event pdev bss chan info:\n freq: %d noise: %d cycle: busy %llu total %llu tx %llu rx %llu rx_bss %llu\n",
freq, noise_floor, busy, total, tx, rx, rx_bss); freq, noise_floor, busy, total, tx, rx, rx_bss);
spin_lock_bh(&ar->data_lock);
idx = freq_to_idx(ar, freq);
if (idx >= ARRAY_SIZE(ar->survey)) {
ath10k_warn(ar, "bss chan info: invalid frequency %d (idx %d out of bounds)\n",
freq, idx);
goto exit;
}
survey = &ar->survey[idx];
survey->noise = noise_floor;
survey->time = div_u64(total, cc_freq_hz);
survey->time_busy = div_u64(busy, cc_freq_hz);
survey->time_rx = div_u64(rx_bss, cc_freq_hz);
survey->time_tx = div_u64(tx, cc_freq_hz);
survey->filled |= (SURVEY_INFO_NOISE_DBM |
SURVEY_INFO_TIME |
SURVEY_INFO_TIME_BUSY |
SURVEY_INFO_TIME_RX |
SURVEY_INFO_TIME_TX);
exit:
spin_unlock_bh(&ar->data_lock);
complete(&ar->bss_survey_done);
return 0; return 0;
} }
...@@ -5640,6 +5666,9 @@ static struct sk_buff *ath10k_wmi_10_2_op_gen_init(struct ath10k *ar) ...@@ -5640,6 +5666,9 @@ static struct sk_buff *ath10k_wmi_10_2_op_gen_init(struct ath10k *ar)
if (ath10k_peer_stats_enabled(ar)) if (ath10k_peer_stats_enabled(ar))
features |= WMI_10_2_PEER_STATS; features |= WMI_10_2_PEER_STATS;
if (test_bit(WMI_SERVICE_BSS_CHANNEL_INFO_64, ar->wmi.svc_map))
features |= WMI_10_2_BSS_CHAN_INFO;
cmd->resource_config.feature_mask = __cpu_to_le32(features); cmd->resource_config.feature_mask = __cpu_to_le32(features);
memcpy(&cmd->resource_config.common, &config, sizeof(config)); memcpy(&cmd->resource_config.common, &config, sizeof(config));
......
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