aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/ath/ath10k/wmi.c
diff options
context:
space:
mode:
authorRakesh Pillai <pillair@codeaurora.org>2018-10-17 16:50:03 +0530
committerKalle Valo <kvalo@codeaurora.org>2018-11-05 13:08:15 +0200
commit13104929d2ec32aec0552007d55b9e15bc07176b (patch)
tree5cb7de1f1c75b46a13b8bf0c281ba9efc5f89669 /drivers/net/wireless/ath/ath10k/wmi.c
parent4ab7fd955e471a71908d4970017c52b3ef6e47a2 (diff)
downloadlinux-13104929d2ec32aec0552007d55b9e15bc07176b.tar.gz
ath10k: fill the channel survey results for WCN3990 correctly
The host driver currently expects the channel info event to be received in pairs for all the channels, i.e. the first chan_info event for a particular channel will not have the COMPLETE flag set and the second chan_info event for the same channel will have the COMPLETE flag set. The HL2.0 firmware sends only one channel info event per channel which is scanned without the COMPLETE flag set. After sending the chan_info_event for all the channels, the HL2.0 firmware sends a chan_info_event with COMPLETE flag set to indicate the completion of the channel info event. The firmware does not indicate this behavior with any service bitmap and hence a new firmware feature flag is used to handle the modified parsing of the channel info events, in the host driver, for the firmware which sends single channel info event per scanned channel. Tested HW: WCN3990 Tested FW: WLAN.HL.2.0-01188-QCAHLSWMTPLZ-1 Co-developed-by: Surabhi Vishnoi <svishnoi@codeaurora.org> Signed-off-by: Surabhi Vishnoi <svishnoi@codeaurora.org> Signed-off-by: Rakesh Pillai <pillair@codeaurora.org> Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
Diffstat (limited to 'drivers/net/wireless/ath/ath10k/wmi.c')
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi.c128
1 files changed, 91 insertions, 37 deletions
diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c
index 25e8fa789e8d..659513bf4ddc 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.c
+++ b/drivers/net/wireless/ath/ath10k/wmi.c
@@ -2554,60 +2554,69 @@ static int ath10k_wmi_10_4_op_pull_ch_info_ev(struct ath10k *ar,
return 0;
}
-void ath10k_wmi_event_chan_info(struct ath10k *ar, struct sk_buff *skb)
+/*
+ * Handle the channel info event for firmware which only sends one
+ * chan_info event per scanned channel.
+ */
+static void ath10k_wmi_event_chan_info_unpaired(struct ath10k *ar,
+ struct chan_info_params *params)
{
- struct wmi_ch_info_ev_arg arg = {};
struct survey_info *survey;
- u32 err_code, freq, cmd_flags, noise_floor, rx_clear_count, cycle_count;
- int idx, ret;
+ int idx;
- ret = ath10k_wmi_pull_ch_info(ar, skb, &arg);
- if (ret) {
- ath10k_warn(ar, "failed to parse chan info event: %d\n", ret);
+ if (params->cmd_flags & WMI_CHAN_INFO_FLAG_COMPLETE) {
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "chan info report completed\n");
return;
}
- err_code = __le32_to_cpu(arg.err_code);
- freq = __le32_to_cpu(arg.freq);
- cmd_flags = __le32_to_cpu(arg.cmd_flags);
- noise_floor = __le32_to_cpu(arg.noise_floor);
- rx_clear_count = __le32_to_cpu(arg.rx_clear_count);
- cycle_count = __le32_to_cpu(arg.cycle_count);
+ idx = freq_to_idx(ar, params->freq);
+ if (idx >= ARRAY_SIZE(ar->survey)) {
+ ath10k_warn(ar, "chan info: invalid frequency %d (idx %d out of bounds)\n",
+ params->freq, idx);
+ return;
+ }
- ath10k_dbg(ar, ATH10K_DBG_WMI,
- "chan info err_code %d freq %d cmd_flags %d noise_floor %d rx_clear_count %d cycle_count %d\n",
- err_code, freq, cmd_flags, noise_floor, rx_clear_count,
- cycle_count);
+ survey = &ar->survey[idx];
- spin_lock_bh(&ar->data_lock);
+ if (!params->mac_clk_mhz || !survey)
+ return;
- switch (ar->scan.state) {
- case ATH10K_SCAN_IDLE:
- case ATH10K_SCAN_STARTING:
- ath10k_warn(ar, "received chan info event without a scan request, ignoring\n");
- goto exit;
- case ATH10K_SCAN_RUNNING:
- case ATH10K_SCAN_ABORTING:
- break;
- }
+ memset(survey, 0, sizeof(*survey));
- idx = freq_to_idx(ar, freq);
+ survey->noise = params->noise_floor;
+ survey->time = (params->cycle_count / params->mac_clk_mhz) / 1000;
+ survey->time_busy = (params->rx_clear_count / params->mac_clk_mhz) / 1000;
+ survey->filled |= SURVEY_INFO_NOISE_DBM | SURVEY_INFO_TIME |
+ SURVEY_INFO_TIME_BUSY;
+}
+
+/*
+ * Handle the channel info event for firmware which sends chan_info
+ * event in pairs(start and stop events) for every scanned channel.
+ */
+static void ath10k_wmi_event_chan_info_paired(struct ath10k *ar,
+ struct chan_info_params *params)
+{
+ struct survey_info *survey;
+ int idx;
+
+ idx = freq_to_idx(ar, params->freq);
if (idx >= ARRAY_SIZE(ar->survey)) {
ath10k_warn(ar, "chan info: invalid frequency %d (idx %d out of bounds)\n",
- freq, idx);
- goto exit;
+ params->freq, idx);
+ return;
}
- if (cmd_flags & WMI_CHAN_INFO_FLAG_COMPLETE) {
+ if (params->cmd_flags & WMI_CHAN_INFO_FLAG_COMPLETE) {
if (ar->ch_info_can_report_survey) {
survey = &ar->survey[idx];
- survey->noise = noise_floor;
+ survey->noise = params->noise_floor;
survey->filled = SURVEY_INFO_NOISE_DBM;
ath10k_hw_fill_survey_time(ar,
survey,
- cycle_count,
- rx_clear_count,
+ params->cycle_count,
+ params->rx_clear_count,
ar->survey_last_cycle_count,
ar->survey_last_rx_clear_count);
}
@@ -2617,11 +2626,56 @@ void ath10k_wmi_event_chan_info(struct ath10k *ar, struct sk_buff *skb)
ar->ch_info_can_report_survey = true;
}
- if (!(cmd_flags & WMI_CHAN_INFO_FLAG_PRE_COMPLETE)) {
- ar->survey_last_rx_clear_count = rx_clear_count;
- ar->survey_last_cycle_count = cycle_count;
+ if (!(params->cmd_flags & WMI_CHAN_INFO_FLAG_PRE_COMPLETE)) {
+ ar->survey_last_rx_clear_count = params->rx_clear_count;
+ ar->survey_last_cycle_count = params->cycle_count;
+ }
+}
+
+void ath10k_wmi_event_chan_info(struct ath10k *ar, struct sk_buff *skb)
+{
+ struct chan_info_params ch_info_param;
+ struct wmi_ch_info_ev_arg arg = {};
+ int ret;
+
+ ret = ath10k_wmi_pull_ch_info(ar, skb, &arg);
+ if (ret) {
+ ath10k_warn(ar, "failed to parse chan info event: %d\n", ret);
+ return;
+ }
+
+ ch_info_param.err_code = __le32_to_cpu(arg.err_code);
+ ch_info_param.freq = __le32_to_cpu(arg.freq);
+ ch_info_param.cmd_flags = __le32_to_cpu(arg.cmd_flags);
+ ch_info_param.noise_floor = __le32_to_cpu(arg.noise_floor);
+ ch_info_param.rx_clear_count = __le32_to_cpu(arg.rx_clear_count);
+ ch_info_param.cycle_count = __le32_to_cpu(arg.cycle_count);
+ ch_info_param.mac_clk_mhz = __le32_to_cpu(arg.mac_clk_mhz);
+
+ ath10k_dbg(ar, ATH10K_DBG_WMI,
+ "chan info err_code %d freq %d cmd_flags %d noise_floor %d rx_clear_count %d cycle_count %d\n",
+ ch_info_param.err_code, ch_info_param.freq, ch_info_param.cmd_flags,
+ ch_info_param.noise_floor, ch_info_param.rx_clear_count,
+ ch_info_param.cycle_count);
+
+ spin_lock_bh(&ar->data_lock);
+
+ switch (ar->scan.state) {
+ case ATH10K_SCAN_IDLE:
+ case ATH10K_SCAN_STARTING:
+ ath10k_warn(ar, "received chan info event without a scan request, ignoring\n");
+ goto exit;
+ case ATH10K_SCAN_RUNNING:
+ case ATH10K_SCAN_ABORTING:
+ break;
}
+ if (test_bit(ATH10K_FW_FEATURE_SINGLE_CHAN_INFO_PER_CHANNEL,
+ ar->running_fw->fw_file.fw_features))
+ ath10k_wmi_event_chan_info_unpaired(ar, &ch_info_param);
+ else
+ ath10k_wmi_event_chan_info_paired(ar, &ch_info_param);
+
exit:
spin_unlock_bh(&ar->data_lock);
}