diff options
Diffstat (limited to 'sys/contrib/dev/iwlwifi/mvm/scan.c')
| -rw-r--r-- | sys/contrib/dev/iwlwifi/mvm/scan.c | 192 |
1 files changed, 53 insertions, 139 deletions
diff --git a/sys/contrib/dev/iwlwifi/mvm/scan.c b/sys/contrib/dev/iwlwifi/mvm/scan.c index 0b705e497343..9ce1ce0dab34 100644 --- a/sys/contrib/dev/iwlwifi/mvm/scan.c +++ b/sys/contrib/dev/iwlwifi/mvm/scan.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2012-2014, 2018-2024 Intel Corporation + * Copyright (C) 2012-2014, 2018-2025 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -11,6 +11,7 @@ #include "mvm.h" #include "fw/api/scan.h" #include "iwl-io.h" +#include "iwl-utils.h" #define IWL_DENSE_EBS_SCAN_RATIO 5 #define IWL_SPARSE_EBS_SCAN_RATIO 1 @@ -462,11 +463,7 @@ static int iwl_ssid_exist(u8 *ssid, u8 ssid_len, struct iwl_ssid_ie *ssid_list) if (!ssid_list[i].len) break; if (ssid_list[i].len == ssid_len && -#if defined(__linux__) - !memcmp(ssid_list->ssid, ssid, ssid_len)) -#elif defined(__FreeBSD__) !memcmp(ssid_list[i].ssid, ssid, ssid_len)) -#endif return i; } return -1; @@ -839,7 +836,7 @@ static inline bool iwl_mvm_scan_fits(struct iwl_mvm *mvm, int n_ssids, int n_channels) { return ((n_ssids <= PROBE_OPTION_MAX) && - (n_channels <= mvm->fw->ucode_capa.n_scan_channels) & + (n_channels <= mvm->fw->ucode_capa.n_scan_channels) && (ies->common_ie_len + ies->len[NL80211_BAND_2GHZ] + ies->len[NL80211_BAND_5GHZ] + ies->len[NL80211_BAND_6GHZ] <= @@ -1598,7 +1595,7 @@ iwl_mvm_umac_scan_cfg_channels(struct iwl_mvm *mvm, for (i = 0; i < n_channels; i++) { channel_cfg[i].flags = cpu_to_le32(flags); - channel_cfg[i].v1.channel_num = channels[i]->hw_value; + channel_cfg[i].channel_num = channels[i]->hw_value; if (iwl_mvm_is_scan_ext_chan_supported(mvm)) { enum nl80211_band band = channels[i]->band; @@ -1630,13 +1627,13 @@ iwl_mvm_umac_scan_cfg_channels_v4(struct iwl_mvm *mvm, &cp->channel_config[i]; cfg->flags = cpu_to_le32(flags); - cfg->v2.channel_num = channels[i]->hw_value; + cfg->channel_num = channels[i]->hw_value; cfg->v2.band = iwl_mvm_phy_band_from_nl80211(band); cfg->v2.iter_count = 1; cfg->v2.iter_interval = 0; iwl_mvm_scan_ch_add_n_aps_override(vif_type, - cfg->v2.channel_num, + cfg->channel_num, cfg->v2.band, bitmap, bitmap_n_entries); } @@ -1660,7 +1657,7 @@ iwl_mvm_umac_scan_cfg_channels_v7(struct iwl_mvm *mvm, u8 iwl_band = iwl_mvm_phy_band_from_nl80211(band); cfg->flags = cpu_to_le32(flags | n_aps_flag); - cfg->v2.channel_num = channels[i]->hw_value; + cfg->channel_num = channels[i]->hw_value; if (cfg80211_channel_is_psc(channels[i])) cfg->flags = 0; @@ -1778,7 +1775,7 @@ iwl_mvm_umac_scan_cfg_channels_v7_6g(struct iwl_mvm *mvm, &cp->channel_config[ch_cnt]; u32 s_ssid_bitmap = 0, bssid_bitmap = 0, flags = 0; - u8 j, k, n_s_ssids = 0, n_bssids = 0; + u8 k, n_s_ssids = 0, n_bssids = 0; u8 max_s_ssids, max_bssids; bool force_passive = false, found = false, allow_passive = true, unsolicited_probe_on_chan = false, psc_no_listen = false; @@ -1793,7 +1790,7 @@ iwl_mvm_umac_scan_cfg_channels_v7_6g(struct iwl_mvm *mvm, !params->n_6ghz_params && params->n_ssids) continue; - cfg->v1.channel_num = params->channels[i]->hw_value; + cfg->channel_num = params->channels[i]->hw_value; if (version < 17) cfg->v2.band = PHY_BAND_6; else @@ -1803,7 +1800,7 @@ iwl_mvm_umac_scan_cfg_channels_v7_6g(struct iwl_mvm *mvm, cfg->v5.iter_count = 1; cfg->v5.iter_interval = 0; - for (j = 0; j < params->n_6ghz_params; j++) { + for (u32 j = 0; j < params->n_6ghz_params; j++) { s8 tmp_psd_20; if (!(scan_6ghz_params[j].channel_idx == i)) @@ -1877,7 +1874,7 @@ iwl_mvm_umac_scan_cfg_channels_v7_6g(struct iwl_mvm *mvm, * SSID. * TODO: improve this logic */ - for (j = 0; j < params->n_6ghz_params; j++) { + for (u32 j = 0; j < params->n_6ghz_params; j++) { if (!(scan_6ghz_params[j].channel_idx == i)) continue; @@ -2481,7 +2478,7 @@ iwl_mvm_scan_umac_fill_ch_p_v7(struct iwl_mvm *mvm, if (!cfg80211_channel_is_psc(channel)) continue; - cfg->v5.channel_num = channel->hw_value; + cfg->channel_num = channel->hw_value; cfg->v5.iter_count = 1; cfg->v5.iter_interval = 0; @@ -3317,13 +3314,23 @@ void iwl_mvm_rx_umac_scan_iter_complete_notif(struct iwl_mvm *mvm, mvm->scan_start); } -static int iwl_mvm_umac_scan_abort(struct iwl_mvm *mvm, int type) +static int iwl_mvm_umac_scan_abort(struct iwl_mvm *mvm, int type, bool *wait) { - struct iwl_umac_scan_abort cmd = {}; + struct iwl_umac_scan_abort abort_cmd = {}; + struct iwl_host_cmd cmd = { + .id = WIDE_ID(IWL_ALWAYS_LONG_GROUP, SCAN_ABORT_UMAC), + .len = { sizeof(abort_cmd), }, + .data = { &abort_cmd, }, + .flags = CMD_SEND_IN_RFKILL, + }; + int uid, ret; + u32 status = IWL_UMAC_SCAN_ABORT_STATUS_NOT_FOUND; lockdep_assert_held(&mvm->mutex); + *wait = true; + /* We should always get a valid index here, because we already * checked that this type of scan was running in the generic * code. @@ -3332,17 +3339,28 @@ static int iwl_mvm_umac_scan_abort(struct iwl_mvm *mvm, int type) if (WARN_ON_ONCE(uid < 0)) return uid; - cmd.uid = cpu_to_le32(uid); + abort_cmd.uid = cpu_to_le32(uid); IWL_DEBUG_SCAN(mvm, "Sending scan abort, uid %u\n", uid); - ret = iwl_mvm_send_cmd_pdu(mvm, - WIDE_ID(IWL_ALWAYS_LONG_GROUP, SCAN_ABORT_UMAC), - CMD_SEND_IN_RFKILL, sizeof(cmd), &cmd); + ret = iwl_mvm_send_cmd_status(mvm, &cmd, &status); + + IWL_DEBUG_SCAN(mvm, "Scan abort: ret=%d, status=%u\n", ret, status); if (!ret) mvm->scan_uid_status[uid] = type << IWL_MVM_SCAN_STOPPING_SHIFT; - IWL_DEBUG_SCAN(mvm, "Scan abort: ret=%d\n", ret); + /* Handle the case that the FW is no longer familiar with the scan that + * is to be stopped. In such a case, it is expected that the scan + * complete notification was already received but not yet processed. + * In such a case, there is no need to wait for a scan complete + * notification and the flow should continue similar to the case that + * the scan was really aborted. + */ + if (status == IWL_UMAC_SCAN_ABORT_STATUS_NOT_FOUND) { + mvm->scan_uid_status[uid] = type << IWL_MVM_SCAN_STOPPING_SHIFT; + *wait = false; + } + return ret; } @@ -3352,6 +3370,7 @@ static int iwl_mvm_scan_stop_wait(struct iwl_mvm *mvm, int type) static const u16 scan_done_notif[] = { SCAN_COMPLETE_UMAC, SCAN_OFFLOAD_COMPLETE, }; int ret; + bool wait = true; lockdep_assert_held(&mvm->mutex); @@ -3363,7 +3382,7 @@ static int iwl_mvm_scan_stop_wait(struct iwl_mvm *mvm, int type) IWL_DEBUG_SCAN(mvm, "Preparing to stop scan, type %x\n", type); if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_UMAC_SCAN)) - ret = iwl_mvm_umac_scan_abort(mvm, type); + ret = iwl_mvm_umac_scan_abort(mvm, type, &wait); else ret = iwl_mvm_lmac_scan_abort(mvm); @@ -3371,6 +3390,10 @@ static int iwl_mvm_scan_stop_wait(struct iwl_mvm *mvm, int type) IWL_DEBUG_SCAN(mvm, "couldn't stop scan type %d\n", type); iwl_remove_notification(&mvm->notif_wait, &wait_scan_done); return ret; + } else if (!wait) { + IWL_DEBUG_SCAN(mvm, "no need to wait for scan type %d\n", type); + iwl_remove_notification(&mvm->notif_wait, &wait_scan_done); + return 0; } return iwl_wait_notification(&mvm->notif_wait, &wait_scan_done, @@ -3455,7 +3478,7 @@ void iwl_mvm_report_scan_aborted(struct iwl_mvm *mvm) * restart_hw, so do not report if FW is about to be * restarted. */ - if (!mvm->fw_restart) + if (!iwlwifi_mod_params.fw_restart) ieee80211_sched_scan_stopped(mvm->hw); mvm->sched_scan_pass_all = SCHED_SCAN_PASS_ALL_DISABLED; mvm->scan_uid_status[uid] = 0; @@ -3506,7 +3529,7 @@ void iwl_mvm_report_scan_aborted(struct iwl_mvm *mvm) * restarted. */ if ((mvm->scan_status & IWL_MVM_SCAN_SCHED) && - !mvm->fw_restart) { + !iwlwifi_mod_params.fw_restart) { ieee80211_sched_scan_stopped(mvm->hw); mvm->sched_scan_pass_all = SCHED_SCAN_PASS_ALL_DISABLED; } @@ -3524,7 +3547,7 @@ int iwl_mvm_scan_stop(struct iwl_mvm *mvm, int type, bool notify) if (!(mvm->scan_status & type)) return 0; - if (!test_bit(STATUS_DEVICE_ENABLED, &mvm->trans->status)) { + if (!iwl_trans_device_enabled(mvm->trans)) { ret = 0; goto out; } @@ -3575,7 +3598,8 @@ static int iwl_mvm_int_mlo_scan_start(struct iwl_mvm *mvm, IWL_DEBUG_SCAN(mvm, "Starting Internal MLO scan: n_channels=%zu\n", n_channels); - if (!vif->cfg.assoc || !ieee80211_vif_is_mld(vif)) + if (!vif->cfg.assoc || !ieee80211_vif_is_mld(vif) || + hweight16(vif->valid_links) == 1) return -EINVAL; size = struct_size(req, channels, n_channels); @@ -3662,117 +3686,6 @@ static int iwl_mvm_chanidx_from_phy(struct iwl_mvm *mvm, return -EINVAL; } -static u32 iwl_mvm_div_by_db(u32 value, u8 db) -{ - /* - * 2^32 * 10**(i / 10) for i = [1, 10], skipping 0 and simply stopping - * at 10 dB and looping instead of using a much larger table. - * - * Using 64 bit math is overkill, but means the helper does not require - * a limit on the input range. - */ - static const u32 db_to_val[] = { - 0xcb59185e, 0xa1866ba8, 0x804dce7a, 0x65ea59fe, 0x50f44d89, - 0x404de61f, 0x331426af, 0x2892c18b, 0x203a7e5b, 0x1999999a, - }; - - while (value && db > 0) { - u8 change = min_t(u8, db, ARRAY_SIZE(db_to_val)); - - value = (((u64)value) * db_to_val[change - 1]) >> 32; - - db -= change; - } - - return value; -} - -VISIBLE_IF_IWLWIFI_KUNIT s8 -iwl_mvm_average_dbm_values(const struct iwl_umac_scan_channel_survey_notif *notif) -{ - s8 average_magnitude; - u32 average_factor; - s8 sum_magnitude = -128; - u32 sum_factor = 0; - int i, count = 0; - - /* - * To properly average the decibel values (signal values given in dBm) - * we need to do the math in linear space. Doing a linear average of - * dB (dBm) values is a bit annoying though due to the large range of - * at least -10 to -110 dBm that will not fit into a 32 bit integer. - * - * A 64 bit integer should be sufficient, but then we still have the - * problem that there are no directly usable utility functions - * available. - * - * So, lets not deal with that and instead do much of the calculation - * with a 16.16 fixed point integer along with a base in dBm. 16.16 bit - * gives us plenty of head-room for adding up a few values and even - * doing some math on it. And the tail should be accurate enough too - * (1/2^16 is somewhere around -48 dB, so effectively zero). - * - * i.e. the real value of sum is: - * sum = sum_factor / 2^16 * 10^(sum_magnitude / 10) mW - * - * However, that does mean we need to be able to bring two values to - * a common base, so we need a helper for that. - * - * Note that this function takes an input with unsigned negative dBm - * values but returns a signed dBm (i.e. a negative value). - */ - - for (i = 0; i < ARRAY_SIZE(notif->noise); i++) { - s8 val_magnitude; - u32 val_factor; - - if (notif->noise[i] == 0xff) - continue; - - val_factor = 0x10000; - val_magnitude = -notif->noise[i]; - - if (val_magnitude <= sum_magnitude) { - u8 div_db = sum_magnitude - val_magnitude; - - val_factor = iwl_mvm_div_by_db(val_factor, div_db); - val_magnitude = sum_magnitude; - } else { - u8 div_db = val_magnitude - sum_magnitude; - - sum_factor = iwl_mvm_div_by_db(sum_factor, div_db); - sum_magnitude = val_magnitude; - } - - sum_factor += val_factor; - count++; - } - - /* No valid noise measurement, return a very high noise level */ - if (count == 0) - return 0; - - average_magnitude = sum_magnitude; - average_factor = sum_factor / count; - - /* - * average_factor will be a number smaller than 1.0 (0x10000) at this - * point. What we need to do now is to adjust average_magnitude so that - * average_factor is between -0.5 dB and 0.5 dB. - * - * Just do -1 dB steps and find the point where - * -0.5 dB * -i dB = 0x10000 * 10^(-0.5/10) / i dB - * = div_by_db(0xe429, i) - * is smaller than average_factor. - */ - for (i = 0; average_factor < iwl_mvm_div_by_db(0xe429, i); i++) { - /* nothing */ - } - - return average_magnitude - i; -} -EXPORT_SYMBOL_IF_IWLWIFI_KUNIT(iwl_mvm_average_dbm_values); - void iwl_mvm_rx_channel_survey_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb) { @@ -3830,5 +3743,6 @@ void iwl_mvm_rx_channel_survey_notif(struct iwl_mvm *mvm, info->time_busy = le32_to_cpu(notif->busy_time); info->time_rx = le32_to_cpu(notif->rx_time); info->time_tx = le32_to_cpu(notif->tx_time); - info->noise = iwl_mvm_average_dbm_values(notif); + info->noise = + iwl_average_neg_dbm(notif->noise, ARRAY_SIZE(notif->noise)); } |
