From 13104929d2ec32aec0552007d55b9e15bc07176b Mon Sep 17 00:00:00 2001 From: Rakesh Pillai Date: Wed, 17 Oct 2018 16:50:03 +0530 Subject: 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 Signed-off-by: Surabhi Vishnoi Signed-off-by: Rakesh Pillai Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wmi.c | 128 ++++++++++++++++++++++++---------- 1 file changed, 91 insertions(+), 37 deletions(-) (limited to 'drivers/net/wireless/ath/ath10k/wmi.c') 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); } -- cgit v1.2.3 From 68c295f21abc192163c416b333aca7c41a195075 Mon Sep 17 00:00:00 2001 From: Sathishkumar Muruganandam Date: Thu, 20 Dec 2018 09:53:30 +0200 Subject: ath10k: disable 4addr source port learning in 10.4 FW by default Currently in 10.4 FW, all the received 4addr frames are processed for source port learning which is enabled by default. This learning can't be disabled by default in FW since it breaks backward compatibility. Since ath10k uses mac80211 based 4addr mode, source port learning done in 10.4 FW is redundant and also causes issues when 3addr frames are transmitted/received for a 4addr station. One such visible functional impact is when GTK rekey frame from hostapd based AP to 4addr STA is dropped in AP's 10.4 FW. This is since GTK rekey EAPOL frame is 3addr frame on AP interface and STA enabled with 4addr is already allowed for receiving 3addr EAPOL frames. Source port learning implementation in 10.4 FW drops this 3addr GTK rekey frame in AP destinated for 4addr STA causing disassociation and re-association for every GTK rekey session. GTK rekey issue is not seen when learning is disabled in FW. To prevent such issues without breaking backward compatibility, FW advertises new service bit making the source port learning configurable and this learning is being currently disabled during ath10k vdev creation. * Tested HW: QCA9984 * Tested FW: 10.4-3.6.0.1-00004 Signed-off-by: Sathishkumar Muruganandam Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wmi.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/net/wireless/ath/ath10k/wmi.c') diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 659513bf4ddc..9b41cec6d887 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -825,6 +825,7 @@ static struct wmi_vdev_param_map wmi_vdev_param_map = { .meru_vc = WMI_VDEV_PARAM_UNSUPPORTED, .rx_decap_type = WMI_VDEV_PARAM_UNSUPPORTED, .bw_nss_ratemask = WMI_VDEV_PARAM_UNSUPPORTED, + .disable_4addr_src_lrn = WMI_VDEV_PARAM_UNSUPPORTED, }; /* 10.X WMI VDEV param map */ @@ -900,6 +901,7 @@ static struct wmi_vdev_param_map wmi_10x_vdev_param_map = { .meru_vc = WMI_VDEV_PARAM_UNSUPPORTED, .rx_decap_type = WMI_VDEV_PARAM_UNSUPPORTED, .bw_nss_ratemask = WMI_VDEV_PARAM_UNSUPPORTED, + .disable_4addr_src_lrn = WMI_VDEV_PARAM_UNSUPPORTED, }; static struct wmi_vdev_param_map wmi_10_2_4_vdev_param_map = { @@ -974,6 +976,7 @@ static struct wmi_vdev_param_map wmi_10_2_4_vdev_param_map = { .meru_vc = WMI_VDEV_PARAM_UNSUPPORTED, .rx_decap_type = WMI_VDEV_PARAM_UNSUPPORTED, .bw_nss_ratemask = WMI_VDEV_PARAM_UNSUPPORTED, + .disable_4addr_src_lrn = WMI_VDEV_PARAM_UNSUPPORTED, }; static struct wmi_vdev_param_map wmi_10_4_vdev_param_map = { @@ -1051,6 +1054,7 @@ static struct wmi_vdev_param_map wmi_10_4_vdev_param_map = { .bw_nss_ratemask = WMI_10_4_VDEV_PARAM_BW_NSS_RATEMASK, .inc_tsf = WMI_10_4_VDEV_PARAM_TSF_INCREMENT, .dec_tsf = WMI_10_4_VDEV_PARAM_TSF_DECREMENT, + .disable_4addr_src_lrn = WMI_10_4_VDEV_PARAM_DISABLE_4_ADDR_SRC_LRN, }; static struct wmi_pdev_param_map wmi_pdev_param_map = { -- cgit v1.2.3 From 27120f2ac995d83fef383fb20e492037ecf09259 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 20 Dec 2018 09:53:45 +0200 Subject: ath10k: remove an unnecessary NULL check The "survey" pointer is the address of an array element. We know that it can't be NULL so this check can be removed. Signed-off-by: Dan Carpenter Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wmi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless/ath/ath10k/wmi.c') diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 9b41cec6d887..3d59d7d73f4b 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -2582,7 +2582,7 @@ static void ath10k_wmi_event_chan_info_unpaired(struct ath10k *ar, survey = &ar->survey[idx]; - if (!params->mac_clk_mhz || !survey) + if (!params->mac_clk_mhz) return; memset(survey, 0, sizeof(*survey)); -- cgit v1.2.3 From 84758d4d43e9e38f2bf9b5130b5f7db1c44f1e0b Mon Sep 17 00:00:00 2001 From: Bhagavathi Perumal S Date: Thu, 20 Dec 2018 14:26:00 +0200 Subject: ath10k: add support to configure BB timing over wmi Add wmi configuration cmd to configure base band(BB) power amplifier(PA) off timing values in hardware. The default PA off timings were fine tuned to make proper DFS radar detection in QCA reference design. If ODM uses different PA in their design, then the same default PA off timing values cannot be used, it requires different settling time to detect radar pulses very sooner and avoid radar detection problems. In that case it provides provision to select proper PA off timing values based on the PA hardware used. The PA component is part of FEM hardware and new device tree entry "ext-fem-name" is used to indentify the FEM hardware. And this wmi configuration cmd is enabled via wmi service flag "WMI_SERVICE_BB_TIMING_CONFIG_SUPPORT". Other way is to apply these values through calibration data, but recalibration of all boards out there might not be feasible. This change tested on firmware ver 10.2.4-1.0-00042 in QCA988X chipset. Signed-off-by: Bhagavathi Perumal S Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wmi.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) (limited to 'drivers/net/wireless/ath/ath10k/wmi.c') diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 3d59d7d73f4b..ba837403e266 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -539,6 +539,7 @@ static struct wmi_cmd_map wmi_10_2_4_cmd_map = { WMI_10_2_PDEV_BSS_CHAN_INFO_REQUEST_CMDID, .pdev_get_tpc_table_cmdid = WMI_CMD_UNSUPPORTED, .radar_found_cmdid = WMI_CMD_UNSUPPORTED, + .set_bb_timing_cmdid = WMI_10_2_PDEV_SET_BB_TIMING_CONFIG_CMDID, }; /* 10.4 WMI cmd track */ @@ -8843,6 +8844,27 @@ ath10k_wmi_barrier(struct ath10k *ar) return 0; } +static struct sk_buff * +ath10k_wmi_10_2_4_op_gen_bb_timing(struct ath10k *ar, + const struct wmi_bb_timing_cfg_arg *arg) +{ + struct wmi_pdev_bb_timing_cfg_cmd *cmd; + struct sk_buff *skb; + + skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); + if (!skb) + return ERR_PTR(-ENOMEM); + + cmd = (struct wmi_pdev_bb_timing_cfg_cmd *)skb->data; + cmd->bb_tx_timing = __cpu_to_le32(arg->bb_tx_timing); + cmd->bb_xpa_timing = __cpu_to_le32(arg->bb_xpa_timing); + + ath10k_dbg(ar, ATH10K_DBG_WMI, + "wmi pdev bb_tx_timing 0x%x bb_xpa_timing 0x%x\n", + arg->bb_tx_timing, arg->bb_xpa_timing); + return skb; +} + static const struct wmi_ops wmi_ops = { .rx = ath10k_wmi_op_rx, .map_svc = wmi_main_svc_map, @@ -9116,6 +9138,7 @@ static const struct wmi_ops wmi_10_2_4_ops = { .gen_pdev_enable_adaptive_cca = ath10k_wmi_op_gen_pdev_enable_adaptive_cca, .get_vdev_subtype = ath10k_wmi_10_2_4_op_get_vdev_subtype, + .gen_bb_timing = ath10k_wmi_10_2_4_op_gen_bb_timing, /* .gen_bcn_tmpl not implemented */ /* .gen_prb_tmpl not implemented */ /* .gen_p2p_go_bcn_ie not implemented */ -- cgit v1.2.3