18c2ecf20Sopenharmony_ci/****************************************************************************** 28c2ecf20Sopenharmony_ci * 38c2ecf20Sopenharmony_ci * This file is provided under a dual BSD/GPLv2 license. When using or 48c2ecf20Sopenharmony_ci * redistributing this file, you may do so under either license. 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * GPL LICENSE SUMMARY 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. 98c2ecf20Sopenharmony_ci * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH 108c2ecf20Sopenharmony_ci * Copyright(c) 2016 - 2017 Intel Deutschland GmbH 118c2ecf20Sopenharmony_ci * Copyright(c) 2018 - 2019 Intel Corporation 128c2ecf20Sopenharmony_ci * 138c2ecf20Sopenharmony_ci * This program is free software; you can redistribute it and/or modify 148c2ecf20Sopenharmony_ci * it under the terms of version 2 of the GNU General Public License as 158c2ecf20Sopenharmony_ci * published by the Free Software Foundation. 168c2ecf20Sopenharmony_ci * 178c2ecf20Sopenharmony_ci * This program is distributed in the hope that it will be useful, but 188c2ecf20Sopenharmony_ci * WITHOUT ANY WARRANTY; without even the implied warranty of 198c2ecf20Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 208c2ecf20Sopenharmony_ci * General Public License for more details. 218c2ecf20Sopenharmony_ci * 228c2ecf20Sopenharmony_ci * The full GNU General Public License is included in this distribution 238c2ecf20Sopenharmony_ci * in the file called COPYING. 248c2ecf20Sopenharmony_ci * 258c2ecf20Sopenharmony_ci * Contact Information: 268c2ecf20Sopenharmony_ci * Intel Linux Wireless <linuxwifi@intel.com> 278c2ecf20Sopenharmony_ci * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 288c2ecf20Sopenharmony_ci * 298c2ecf20Sopenharmony_ci * BSD LICENSE 308c2ecf20Sopenharmony_ci * 318c2ecf20Sopenharmony_ci * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. 328c2ecf20Sopenharmony_ci * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH 338c2ecf20Sopenharmony_ci * Copyright(c) 2016 - 2017 Intel Deutschland GmbH 348c2ecf20Sopenharmony_ci * Copyright(c) 2018 - 2019 Intel Corporation 358c2ecf20Sopenharmony_ci * All rights reserved. 368c2ecf20Sopenharmony_ci * 378c2ecf20Sopenharmony_ci * Redistribution and use in source and binary forms, with or without 388c2ecf20Sopenharmony_ci * modification, are permitted provided that the following conditions 398c2ecf20Sopenharmony_ci * are met: 408c2ecf20Sopenharmony_ci * 418c2ecf20Sopenharmony_ci * * Redistributions of source code must retain the above copyright 428c2ecf20Sopenharmony_ci * notice, this list of conditions and the following disclaimer. 438c2ecf20Sopenharmony_ci * * Redistributions in binary form must reproduce the above copyright 448c2ecf20Sopenharmony_ci * notice, this list of conditions and the following disclaimer in 458c2ecf20Sopenharmony_ci * the documentation and/or other materials provided with the 468c2ecf20Sopenharmony_ci * distribution. 478c2ecf20Sopenharmony_ci * * Neither the name Intel Corporation nor the names of its 488c2ecf20Sopenharmony_ci * contributors may be used to endorse or promote products derived 498c2ecf20Sopenharmony_ci * from this software without specific prior written permission. 508c2ecf20Sopenharmony_ci * 518c2ecf20Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 528c2ecf20Sopenharmony_ci * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 538c2ecf20Sopenharmony_ci * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 548c2ecf20Sopenharmony_ci * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 558c2ecf20Sopenharmony_ci * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 568c2ecf20Sopenharmony_ci * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 578c2ecf20Sopenharmony_ci * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 588c2ecf20Sopenharmony_ci * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 598c2ecf20Sopenharmony_ci * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 608c2ecf20Sopenharmony_ci * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 618c2ecf20Sopenharmony_ci * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 628c2ecf20Sopenharmony_ci * 638c2ecf20Sopenharmony_ci *****************************************************************************/ 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci#include <linux/etherdevice.h> 668c2ecf20Sopenharmony_ci#include <net/mac80211.h> 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci#include "mvm.h" 698c2ecf20Sopenharmony_ci#include "fw/api/scan.h" 708c2ecf20Sopenharmony_ci#include "iwl-io.h" 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci#define IWL_DENSE_EBS_SCAN_RATIO 5 738c2ecf20Sopenharmony_ci#define IWL_SPARSE_EBS_SCAN_RATIO 1 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci#define IWL_SCAN_DWELL_ACTIVE 10 768c2ecf20Sopenharmony_ci#define IWL_SCAN_DWELL_PASSIVE 110 778c2ecf20Sopenharmony_ci#define IWL_SCAN_DWELL_FRAGMENTED 44 788c2ecf20Sopenharmony_ci#define IWL_SCAN_DWELL_EXTENDED 90 798c2ecf20Sopenharmony_ci#define IWL_SCAN_NUM_OF_FRAGS 3 808c2ecf20Sopenharmony_ci#define IWL_SCAN_LAST_2_4_CHN 14 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci/* adaptive dwell max budget time [TU] for full scan */ 838c2ecf20Sopenharmony_ci#define IWL_SCAN_ADWELL_MAX_BUDGET_FULL_SCAN 300 848c2ecf20Sopenharmony_ci/* adaptive dwell max budget time [TU] for directed scan */ 858c2ecf20Sopenharmony_ci#define IWL_SCAN_ADWELL_MAX_BUDGET_DIRECTED_SCAN 100 868c2ecf20Sopenharmony_ci/* adaptive dwell default high band APs number */ 878c2ecf20Sopenharmony_ci#define IWL_SCAN_ADWELL_DEFAULT_HB_N_APS 8 888c2ecf20Sopenharmony_ci/* adaptive dwell default low band APs number */ 898c2ecf20Sopenharmony_ci#define IWL_SCAN_ADWELL_DEFAULT_LB_N_APS 2 908c2ecf20Sopenharmony_ci/* adaptive dwell default APs number in social channels (1, 6, 11) */ 918c2ecf20Sopenharmony_ci#define IWL_SCAN_ADWELL_DEFAULT_N_APS_SOCIAL 10 928c2ecf20Sopenharmony_ci/* number of scan channels */ 938c2ecf20Sopenharmony_ci#define IWL_SCAN_NUM_CHANNELS 112 948c2ecf20Sopenharmony_ci/* adaptive dwell number of APs override mask for p2p friendly GO */ 958c2ecf20Sopenharmony_ci#define IWL_SCAN_ADWELL_N_APS_GO_FRIENDLY_BIT BIT(20) 968c2ecf20Sopenharmony_ci/* adaptive dwell number of APs override mask for social channels */ 978c2ecf20Sopenharmony_ci#define IWL_SCAN_ADWELL_N_APS_SOCIAL_CHS_BIT BIT(21) 988c2ecf20Sopenharmony_ci/* adaptive dwell number of APs override for p2p friendly GO channels */ 998c2ecf20Sopenharmony_ci#define IWL_SCAN_ADWELL_N_APS_GO_FRIENDLY 10 1008c2ecf20Sopenharmony_ci/* adaptive dwell number of APs override for social channels */ 1018c2ecf20Sopenharmony_ci#define IWL_SCAN_ADWELL_N_APS_SOCIAL_CHS 2 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_cistruct iwl_mvm_scan_timing_params { 1048c2ecf20Sopenharmony_ci u32 suspend_time; 1058c2ecf20Sopenharmony_ci u32 max_out_time; 1068c2ecf20Sopenharmony_ci}; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_cistatic struct iwl_mvm_scan_timing_params scan_timing[] = { 1098c2ecf20Sopenharmony_ci [IWL_SCAN_TYPE_UNASSOC] = { 1108c2ecf20Sopenharmony_ci .suspend_time = 0, 1118c2ecf20Sopenharmony_ci .max_out_time = 0, 1128c2ecf20Sopenharmony_ci }, 1138c2ecf20Sopenharmony_ci [IWL_SCAN_TYPE_WILD] = { 1148c2ecf20Sopenharmony_ci .suspend_time = 30, 1158c2ecf20Sopenharmony_ci .max_out_time = 120, 1168c2ecf20Sopenharmony_ci }, 1178c2ecf20Sopenharmony_ci [IWL_SCAN_TYPE_MILD] = { 1188c2ecf20Sopenharmony_ci .suspend_time = 120, 1198c2ecf20Sopenharmony_ci .max_out_time = 120, 1208c2ecf20Sopenharmony_ci }, 1218c2ecf20Sopenharmony_ci [IWL_SCAN_TYPE_FRAGMENTED] = { 1228c2ecf20Sopenharmony_ci .suspend_time = 95, 1238c2ecf20Sopenharmony_ci .max_out_time = 44, 1248c2ecf20Sopenharmony_ci }, 1258c2ecf20Sopenharmony_ci [IWL_SCAN_TYPE_FAST_BALANCE] = { 1268c2ecf20Sopenharmony_ci .suspend_time = 30, 1278c2ecf20Sopenharmony_ci .max_out_time = 37, 1288c2ecf20Sopenharmony_ci }, 1298c2ecf20Sopenharmony_ci}; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_cistruct iwl_mvm_scan_params { 1328c2ecf20Sopenharmony_ci /* For CDB this is low band scan type, for non-CDB - type. */ 1338c2ecf20Sopenharmony_ci enum iwl_mvm_scan_type type; 1348c2ecf20Sopenharmony_ci enum iwl_mvm_scan_type hb_type; 1358c2ecf20Sopenharmony_ci u32 n_channels; 1368c2ecf20Sopenharmony_ci u16 delay; 1378c2ecf20Sopenharmony_ci int n_ssids; 1388c2ecf20Sopenharmony_ci struct cfg80211_ssid *ssids; 1398c2ecf20Sopenharmony_ci struct ieee80211_channel **channels; 1408c2ecf20Sopenharmony_ci u32 flags; 1418c2ecf20Sopenharmony_ci u8 *mac_addr; 1428c2ecf20Sopenharmony_ci u8 *mac_addr_mask; 1438c2ecf20Sopenharmony_ci bool no_cck; 1448c2ecf20Sopenharmony_ci bool pass_all; 1458c2ecf20Sopenharmony_ci int n_match_sets; 1468c2ecf20Sopenharmony_ci struct iwl_scan_probe_req preq; 1478c2ecf20Sopenharmony_ci struct cfg80211_match_set *match_sets; 1488c2ecf20Sopenharmony_ci int n_scan_plans; 1498c2ecf20Sopenharmony_ci struct cfg80211_sched_scan_plan *scan_plans; 1508c2ecf20Sopenharmony_ci bool iter_notif; 1518c2ecf20Sopenharmony_ci}; 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_cistatic inline void *iwl_mvm_get_scan_req_umac_data(struct iwl_mvm *mvm) 1548c2ecf20Sopenharmony_ci{ 1558c2ecf20Sopenharmony_ci struct iwl_scan_req_umac *cmd = mvm->scan_cmd; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci if (iwl_mvm_is_adaptive_dwell_v2_supported(mvm)) 1588c2ecf20Sopenharmony_ci return (void *)&cmd->v8.data; 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci if (iwl_mvm_is_adaptive_dwell_supported(mvm)) 1618c2ecf20Sopenharmony_ci return (void *)&cmd->v7.data; 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci if (iwl_mvm_cdb_scan_api(mvm)) 1648c2ecf20Sopenharmony_ci return (void *)&cmd->v6.data; 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci return (void *)&cmd->v1.data; 1678c2ecf20Sopenharmony_ci} 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_cistatic inline struct iwl_scan_umac_chan_param * 1708c2ecf20Sopenharmony_ciiwl_mvm_get_scan_req_umac_channel(struct iwl_mvm *mvm) 1718c2ecf20Sopenharmony_ci{ 1728c2ecf20Sopenharmony_ci struct iwl_scan_req_umac *cmd = mvm->scan_cmd; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci if (iwl_mvm_is_adaptive_dwell_v2_supported(mvm)) 1758c2ecf20Sopenharmony_ci return &cmd->v8.channel; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci if (iwl_mvm_is_adaptive_dwell_supported(mvm)) 1788c2ecf20Sopenharmony_ci return &cmd->v7.channel; 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci if (iwl_mvm_cdb_scan_api(mvm)) 1818c2ecf20Sopenharmony_ci return &cmd->v6.channel; 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci return &cmd->v1.channel; 1848c2ecf20Sopenharmony_ci} 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_cistatic u8 iwl_mvm_scan_rx_ant(struct iwl_mvm *mvm) 1878c2ecf20Sopenharmony_ci{ 1888c2ecf20Sopenharmony_ci if (mvm->scan_rx_ant != ANT_NONE) 1898c2ecf20Sopenharmony_ci return mvm->scan_rx_ant; 1908c2ecf20Sopenharmony_ci return iwl_mvm_get_valid_rx_ant(mvm); 1918c2ecf20Sopenharmony_ci} 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_cistatic inline __le16 iwl_mvm_scan_rx_chain(struct iwl_mvm *mvm) 1948c2ecf20Sopenharmony_ci{ 1958c2ecf20Sopenharmony_ci u16 rx_chain; 1968c2ecf20Sopenharmony_ci u8 rx_ant; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci rx_ant = iwl_mvm_scan_rx_ant(mvm); 1998c2ecf20Sopenharmony_ci rx_chain = rx_ant << PHY_RX_CHAIN_VALID_POS; 2008c2ecf20Sopenharmony_ci rx_chain |= rx_ant << PHY_RX_CHAIN_FORCE_MIMO_SEL_POS; 2018c2ecf20Sopenharmony_ci rx_chain |= rx_ant << PHY_RX_CHAIN_FORCE_SEL_POS; 2028c2ecf20Sopenharmony_ci rx_chain |= 0x1 << PHY_RX_CHAIN_DRIVER_FORCE_POS; 2038c2ecf20Sopenharmony_ci return cpu_to_le16(rx_chain); 2048c2ecf20Sopenharmony_ci} 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_cistatic inline __le32 2078c2ecf20Sopenharmony_ciiwl_mvm_scan_rate_n_flags(struct iwl_mvm *mvm, enum nl80211_band band, 2088c2ecf20Sopenharmony_ci bool no_cck) 2098c2ecf20Sopenharmony_ci{ 2108c2ecf20Sopenharmony_ci u32 tx_ant; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci iwl_mvm_toggle_tx_ant(mvm, &mvm->scan_last_antenna_idx); 2138c2ecf20Sopenharmony_ci tx_ant = BIT(mvm->scan_last_antenna_idx) << RATE_MCS_ANT_POS; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci if (band == NL80211_BAND_2GHZ && !no_cck) 2168c2ecf20Sopenharmony_ci return cpu_to_le32(IWL_RATE_1M_PLCP | RATE_MCS_CCK_MSK | 2178c2ecf20Sopenharmony_ci tx_ant); 2188c2ecf20Sopenharmony_ci else 2198c2ecf20Sopenharmony_ci return cpu_to_le32(IWL_RATE_6M_PLCP | tx_ant); 2208c2ecf20Sopenharmony_ci} 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_cistatic void iwl_mvm_scan_condition_iterator(void *data, u8 *mac, 2238c2ecf20Sopenharmony_ci struct ieee80211_vif *vif) 2248c2ecf20Sopenharmony_ci{ 2258c2ecf20Sopenharmony_ci struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 2268c2ecf20Sopenharmony_ci int *global_cnt = data; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci if (vif->type != NL80211_IFTYPE_P2P_DEVICE && mvmvif->phy_ctxt && 2298c2ecf20Sopenharmony_ci mvmvif->phy_ctxt->id < NUM_PHY_CTX) 2308c2ecf20Sopenharmony_ci *global_cnt += 1; 2318c2ecf20Sopenharmony_ci} 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_cistatic enum iwl_mvm_traffic_load iwl_mvm_get_traffic_load(struct iwl_mvm *mvm) 2348c2ecf20Sopenharmony_ci{ 2358c2ecf20Sopenharmony_ci return mvm->tcm.result.global_load; 2368c2ecf20Sopenharmony_ci} 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_cistatic enum iwl_mvm_traffic_load 2398c2ecf20Sopenharmony_ciiwl_mvm_get_traffic_load_band(struct iwl_mvm *mvm, enum nl80211_band band) 2408c2ecf20Sopenharmony_ci{ 2418c2ecf20Sopenharmony_ci return mvm->tcm.result.band_load[band]; 2428c2ecf20Sopenharmony_ci} 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_cistruct iwl_is_dcm_with_go_iterator_data { 2458c2ecf20Sopenharmony_ci struct ieee80211_vif *current_vif; 2468c2ecf20Sopenharmony_ci bool is_dcm_with_p2p_go; 2478c2ecf20Sopenharmony_ci}; 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_cistatic void iwl_mvm_is_dcm_with_go_iterator(void *_data, u8 *mac, 2508c2ecf20Sopenharmony_ci struct ieee80211_vif *vif) 2518c2ecf20Sopenharmony_ci{ 2528c2ecf20Sopenharmony_ci struct iwl_is_dcm_with_go_iterator_data *data = _data; 2538c2ecf20Sopenharmony_ci struct iwl_mvm_vif *other_mvmvif = iwl_mvm_vif_from_mac80211(vif); 2548c2ecf20Sopenharmony_ci struct iwl_mvm_vif *curr_mvmvif = 2558c2ecf20Sopenharmony_ci iwl_mvm_vif_from_mac80211(data->current_vif); 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci /* exclude the given vif */ 2588c2ecf20Sopenharmony_ci if (vif == data->current_vif) 2598c2ecf20Sopenharmony_ci return; 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci if (vif->type == NL80211_IFTYPE_AP && vif->p2p && 2628c2ecf20Sopenharmony_ci other_mvmvif->phy_ctxt && curr_mvmvif->phy_ctxt && 2638c2ecf20Sopenharmony_ci other_mvmvif->phy_ctxt->id != curr_mvmvif->phy_ctxt->id) 2648c2ecf20Sopenharmony_ci data->is_dcm_with_p2p_go = true; 2658c2ecf20Sopenharmony_ci} 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_cistatic enum 2688c2ecf20Sopenharmony_ciiwl_mvm_scan_type _iwl_mvm_get_scan_type(struct iwl_mvm *mvm, 2698c2ecf20Sopenharmony_ci struct ieee80211_vif *vif, 2708c2ecf20Sopenharmony_ci enum iwl_mvm_traffic_load load, 2718c2ecf20Sopenharmony_ci bool low_latency) 2728c2ecf20Sopenharmony_ci{ 2738c2ecf20Sopenharmony_ci int global_cnt = 0; 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci ieee80211_iterate_active_interfaces_atomic(mvm->hw, 2768c2ecf20Sopenharmony_ci IEEE80211_IFACE_ITER_NORMAL, 2778c2ecf20Sopenharmony_ci iwl_mvm_scan_condition_iterator, 2788c2ecf20Sopenharmony_ci &global_cnt); 2798c2ecf20Sopenharmony_ci if (!global_cnt) 2808c2ecf20Sopenharmony_ci return IWL_SCAN_TYPE_UNASSOC; 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci if (fw_has_api(&mvm->fw->ucode_capa, 2838c2ecf20Sopenharmony_ci IWL_UCODE_TLV_API_FRAGMENTED_SCAN)) { 2848c2ecf20Sopenharmony_ci if ((load == IWL_MVM_TRAFFIC_HIGH || low_latency) && 2858c2ecf20Sopenharmony_ci (!vif || vif->type != NL80211_IFTYPE_P2P_DEVICE)) 2868c2ecf20Sopenharmony_ci return IWL_SCAN_TYPE_FRAGMENTED; 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci /* in case of DCM with GO where BSS DTIM interval < 220msec 2898c2ecf20Sopenharmony_ci * set all scan requests as fast-balance scan 2908c2ecf20Sopenharmony_ci * */ 2918c2ecf20Sopenharmony_ci if (vif && vif->type == NL80211_IFTYPE_STATION && 2928c2ecf20Sopenharmony_ci vif->bss_conf.dtim_period < 220) { 2938c2ecf20Sopenharmony_ci struct iwl_is_dcm_with_go_iterator_data data = { 2948c2ecf20Sopenharmony_ci .current_vif = vif, 2958c2ecf20Sopenharmony_ci .is_dcm_with_p2p_go = false, 2968c2ecf20Sopenharmony_ci }; 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci ieee80211_iterate_active_interfaces_atomic(mvm->hw, 2998c2ecf20Sopenharmony_ci IEEE80211_IFACE_ITER_NORMAL, 3008c2ecf20Sopenharmony_ci iwl_mvm_is_dcm_with_go_iterator, 3018c2ecf20Sopenharmony_ci &data); 3028c2ecf20Sopenharmony_ci if (data.is_dcm_with_p2p_go) 3038c2ecf20Sopenharmony_ci return IWL_SCAN_TYPE_FAST_BALANCE; 3048c2ecf20Sopenharmony_ci } 3058c2ecf20Sopenharmony_ci } 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci if (load >= IWL_MVM_TRAFFIC_MEDIUM || low_latency) 3088c2ecf20Sopenharmony_ci return IWL_SCAN_TYPE_MILD; 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci return IWL_SCAN_TYPE_WILD; 3118c2ecf20Sopenharmony_ci} 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_cistatic enum 3148c2ecf20Sopenharmony_ciiwl_mvm_scan_type iwl_mvm_get_scan_type(struct iwl_mvm *mvm, 3158c2ecf20Sopenharmony_ci struct ieee80211_vif *vif) 3168c2ecf20Sopenharmony_ci{ 3178c2ecf20Sopenharmony_ci enum iwl_mvm_traffic_load load; 3188c2ecf20Sopenharmony_ci bool low_latency; 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci load = iwl_mvm_get_traffic_load(mvm); 3218c2ecf20Sopenharmony_ci low_latency = iwl_mvm_low_latency(mvm); 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci return _iwl_mvm_get_scan_type(mvm, vif, load, low_latency); 3248c2ecf20Sopenharmony_ci} 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_cistatic enum 3278c2ecf20Sopenharmony_ciiwl_mvm_scan_type iwl_mvm_get_scan_type_band(struct iwl_mvm *mvm, 3288c2ecf20Sopenharmony_ci struct ieee80211_vif *vif, 3298c2ecf20Sopenharmony_ci enum nl80211_band band) 3308c2ecf20Sopenharmony_ci{ 3318c2ecf20Sopenharmony_ci enum iwl_mvm_traffic_load load; 3328c2ecf20Sopenharmony_ci bool low_latency; 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci load = iwl_mvm_get_traffic_load_band(mvm, band); 3358c2ecf20Sopenharmony_ci low_latency = iwl_mvm_low_latency_band(mvm, band); 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci return _iwl_mvm_get_scan_type(mvm, vif, load, low_latency); 3388c2ecf20Sopenharmony_ci} 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_cistatic inline bool iwl_mvm_rrm_scan_needed(struct iwl_mvm *mvm) 3418c2ecf20Sopenharmony_ci{ 3428c2ecf20Sopenharmony_ci /* require rrm scan whenever the fw supports it */ 3438c2ecf20Sopenharmony_ci return fw_has_capa(&mvm->fw->ucode_capa, 3448c2ecf20Sopenharmony_ci IWL_UCODE_TLV_CAPA_DS_PARAM_SET_IE_SUPPORT); 3458c2ecf20Sopenharmony_ci} 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_cistatic int iwl_mvm_max_scan_ie_fw_cmd_room(struct iwl_mvm *mvm) 3488c2ecf20Sopenharmony_ci{ 3498c2ecf20Sopenharmony_ci int max_probe_len; 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci max_probe_len = SCAN_OFFLOAD_PROBE_REQ_SIZE; 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci /* we create the 802.11 header and SSID element */ 3548c2ecf20Sopenharmony_ci max_probe_len -= 24 + 2; 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci /* DS parameter set element is added on 2.4GHZ band if required */ 3578c2ecf20Sopenharmony_ci if (iwl_mvm_rrm_scan_needed(mvm)) 3588c2ecf20Sopenharmony_ci max_probe_len -= 3; 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci return max_probe_len; 3618c2ecf20Sopenharmony_ci} 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ciint iwl_mvm_max_scan_ie_len(struct iwl_mvm *mvm) 3648c2ecf20Sopenharmony_ci{ 3658c2ecf20Sopenharmony_ci int max_ie_len = iwl_mvm_max_scan_ie_fw_cmd_room(mvm); 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci /* TODO: [BUG] This function should return the maximum allowed size of 3688c2ecf20Sopenharmony_ci * scan IEs, however the LMAC scan api contains both 2GHZ and 5GHZ IEs 3698c2ecf20Sopenharmony_ci * in the same command. So the correct implementation of this function 3708c2ecf20Sopenharmony_ci * is just iwl_mvm_max_scan_ie_fw_cmd_room() / 2. Currently the scan 3718c2ecf20Sopenharmony_ci * command has only 512 bytes and it would leave us with about 240 3728c2ecf20Sopenharmony_ci * bytes for scan IEs, which is clearly not enough. So meanwhile 3738c2ecf20Sopenharmony_ci * we will report an incorrect value. This may result in a failure to 3748c2ecf20Sopenharmony_ci * issue a scan in unified_scan_lmac and unified_sched_scan_lmac 3758c2ecf20Sopenharmony_ci * functions with -ENOBUFS, if a large enough probe will be provided. 3768c2ecf20Sopenharmony_ci */ 3778c2ecf20Sopenharmony_ci return max_ie_len; 3788c2ecf20Sopenharmony_ci} 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_civoid iwl_mvm_rx_lmac_scan_iter_complete_notif(struct iwl_mvm *mvm, 3818c2ecf20Sopenharmony_ci struct iwl_rx_cmd_buffer *rxb) 3828c2ecf20Sopenharmony_ci{ 3838c2ecf20Sopenharmony_ci struct iwl_rx_packet *pkt = rxb_addr(rxb); 3848c2ecf20Sopenharmony_ci struct iwl_lmac_scan_complete_notif *notif = (void *)pkt->data; 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci IWL_DEBUG_SCAN(mvm, 3878c2ecf20Sopenharmony_ci "Scan offload iteration complete: status=0x%x scanned channels=%d\n", 3888c2ecf20Sopenharmony_ci notif->status, notif->scanned_channels); 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci if (mvm->sched_scan_pass_all == SCHED_SCAN_PASS_ALL_FOUND) { 3918c2ecf20Sopenharmony_ci IWL_DEBUG_SCAN(mvm, "Pass all scheduled scan results found\n"); 3928c2ecf20Sopenharmony_ci ieee80211_sched_scan_results(mvm->hw); 3938c2ecf20Sopenharmony_ci mvm->sched_scan_pass_all = SCHED_SCAN_PASS_ALL_ENABLED; 3948c2ecf20Sopenharmony_ci } 3958c2ecf20Sopenharmony_ci} 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_civoid iwl_mvm_rx_scan_match_found(struct iwl_mvm *mvm, 3988c2ecf20Sopenharmony_ci struct iwl_rx_cmd_buffer *rxb) 3998c2ecf20Sopenharmony_ci{ 4008c2ecf20Sopenharmony_ci IWL_DEBUG_SCAN(mvm, "Scheduled scan results\n"); 4018c2ecf20Sopenharmony_ci ieee80211_sched_scan_results(mvm->hw); 4028c2ecf20Sopenharmony_ci} 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_cistatic const char *iwl_mvm_ebs_status_str(enum iwl_scan_ebs_status status) 4058c2ecf20Sopenharmony_ci{ 4068c2ecf20Sopenharmony_ci switch (status) { 4078c2ecf20Sopenharmony_ci case IWL_SCAN_EBS_SUCCESS: 4088c2ecf20Sopenharmony_ci return "successful"; 4098c2ecf20Sopenharmony_ci case IWL_SCAN_EBS_INACTIVE: 4108c2ecf20Sopenharmony_ci return "inactive"; 4118c2ecf20Sopenharmony_ci case IWL_SCAN_EBS_FAILED: 4128c2ecf20Sopenharmony_ci case IWL_SCAN_EBS_CHAN_NOT_FOUND: 4138c2ecf20Sopenharmony_ci default: 4148c2ecf20Sopenharmony_ci return "failed"; 4158c2ecf20Sopenharmony_ci } 4168c2ecf20Sopenharmony_ci} 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_civoid iwl_mvm_rx_lmac_scan_complete_notif(struct iwl_mvm *mvm, 4198c2ecf20Sopenharmony_ci struct iwl_rx_cmd_buffer *rxb) 4208c2ecf20Sopenharmony_ci{ 4218c2ecf20Sopenharmony_ci struct iwl_rx_packet *pkt = rxb_addr(rxb); 4228c2ecf20Sopenharmony_ci struct iwl_periodic_scan_complete *scan_notif = (void *)pkt->data; 4238c2ecf20Sopenharmony_ci bool aborted = (scan_notif->status == IWL_SCAN_OFFLOAD_ABORTED); 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci /* If this happens, the firmware has mistakenly sent an LMAC 4268c2ecf20Sopenharmony_ci * notification during UMAC scans -- warn and ignore it. 4278c2ecf20Sopenharmony_ci */ 4288c2ecf20Sopenharmony_ci if (WARN_ON_ONCE(fw_has_capa(&mvm->fw->ucode_capa, 4298c2ecf20Sopenharmony_ci IWL_UCODE_TLV_CAPA_UMAC_SCAN))) 4308c2ecf20Sopenharmony_ci return; 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci /* scan status must be locked for proper checking */ 4338c2ecf20Sopenharmony_ci lockdep_assert_held(&mvm->mutex); 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci /* We first check if we were stopping a scan, in which case we 4368c2ecf20Sopenharmony_ci * just clear the stopping flag. Then we check if it was a 4378c2ecf20Sopenharmony_ci * firmware initiated stop, in which case we need to inform 4388c2ecf20Sopenharmony_ci * mac80211. 4398c2ecf20Sopenharmony_ci * Note that we can have a stopping and a running scan 4408c2ecf20Sopenharmony_ci * simultaneously, but we can't have two different types of 4418c2ecf20Sopenharmony_ci * scans stopping or running at the same time (since LMAC 4428c2ecf20Sopenharmony_ci * doesn't support it). 4438c2ecf20Sopenharmony_ci */ 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci if (mvm->scan_status & IWL_MVM_SCAN_STOPPING_SCHED) { 4468c2ecf20Sopenharmony_ci WARN_ON_ONCE(mvm->scan_status & IWL_MVM_SCAN_STOPPING_REGULAR); 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci IWL_DEBUG_SCAN(mvm, "Scheduled scan %s, EBS status %s\n", 4498c2ecf20Sopenharmony_ci aborted ? "aborted" : "completed", 4508c2ecf20Sopenharmony_ci iwl_mvm_ebs_status_str(scan_notif->ebs_status)); 4518c2ecf20Sopenharmony_ci IWL_DEBUG_SCAN(mvm, 4528c2ecf20Sopenharmony_ci "Last line %d, Last iteration %d, Time after last iteration %d\n", 4538c2ecf20Sopenharmony_ci scan_notif->last_schedule_line, 4548c2ecf20Sopenharmony_ci scan_notif->last_schedule_iteration, 4558c2ecf20Sopenharmony_ci __le32_to_cpu(scan_notif->time_after_last_iter)); 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci mvm->scan_status &= ~IWL_MVM_SCAN_STOPPING_SCHED; 4588c2ecf20Sopenharmony_ci } else if (mvm->scan_status & IWL_MVM_SCAN_STOPPING_REGULAR) { 4598c2ecf20Sopenharmony_ci IWL_DEBUG_SCAN(mvm, "Regular scan %s, EBS status %s\n", 4608c2ecf20Sopenharmony_ci aborted ? "aborted" : "completed", 4618c2ecf20Sopenharmony_ci iwl_mvm_ebs_status_str(scan_notif->ebs_status)); 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci mvm->scan_status &= ~IWL_MVM_SCAN_STOPPING_REGULAR; 4648c2ecf20Sopenharmony_ci } else if (mvm->scan_status & IWL_MVM_SCAN_SCHED) { 4658c2ecf20Sopenharmony_ci WARN_ON_ONCE(mvm->scan_status & IWL_MVM_SCAN_REGULAR); 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci IWL_DEBUG_SCAN(mvm, "Scheduled scan %s, EBS status %s\n", 4688c2ecf20Sopenharmony_ci aborted ? "aborted" : "completed", 4698c2ecf20Sopenharmony_ci iwl_mvm_ebs_status_str(scan_notif->ebs_status)); 4708c2ecf20Sopenharmony_ci IWL_DEBUG_SCAN(mvm, 4718c2ecf20Sopenharmony_ci "Last line %d, Last iteration %d, Time after last iteration %d (FW)\n", 4728c2ecf20Sopenharmony_ci scan_notif->last_schedule_line, 4738c2ecf20Sopenharmony_ci scan_notif->last_schedule_iteration, 4748c2ecf20Sopenharmony_ci __le32_to_cpu(scan_notif->time_after_last_iter)); 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci mvm->scan_status &= ~IWL_MVM_SCAN_SCHED; 4778c2ecf20Sopenharmony_ci ieee80211_sched_scan_stopped(mvm->hw); 4788c2ecf20Sopenharmony_ci mvm->sched_scan_pass_all = SCHED_SCAN_PASS_ALL_DISABLED; 4798c2ecf20Sopenharmony_ci } else if (mvm->scan_status & IWL_MVM_SCAN_REGULAR) { 4808c2ecf20Sopenharmony_ci struct cfg80211_scan_info info = { 4818c2ecf20Sopenharmony_ci .aborted = aborted, 4828c2ecf20Sopenharmony_ci }; 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci IWL_DEBUG_SCAN(mvm, "Regular scan %s, EBS status %s (FW)\n", 4858c2ecf20Sopenharmony_ci aborted ? "aborted" : "completed", 4868c2ecf20Sopenharmony_ci iwl_mvm_ebs_status_str(scan_notif->ebs_status)); 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci mvm->scan_status &= ~IWL_MVM_SCAN_REGULAR; 4898c2ecf20Sopenharmony_ci ieee80211_scan_completed(mvm->hw, &info); 4908c2ecf20Sopenharmony_ci cancel_delayed_work(&mvm->scan_timeout_dwork); 4918c2ecf20Sopenharmony_ci iwl_mvm_resume_tcm(mvm); 4928c2ecf20Sopenharmony_ci } else { 4938c2ecf20Sopenharmony_ci IWL_ERR(mvm, 4948c2ecf20Sopenharmony_ci "got scan complete notification but no scan is running\n"); 4958c2ecf20Sopenharmony_ci } 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci mvm->last_ebs_successful = 4988c2ecf20Sopenharmony_ci scan_notif->ebs_status == IWL_SCAN_EBS_SUCCESS || 4998c2ecf20Sopenharmony_ci scan_notif->ebs_status == IWL_SCAN_EBS_INACTIVE; 5008c2ecf20Sopenharmony_ci} 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_cistatic int iwl_ssid_exist(u8 *ssid, u8 ssid_len, struct iwl_ssid_ie *ssid_list) 5038c2ecf20Sopenharmony_ci{ 5048c2ecf20Sopenharmony_ci int i; 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci for (i = 0; i < PROBE_OPTION_MAX; i++) { 5078c2ecf20Sopenharmony_ci if (!ssid_list[i].len) 5088c2ecf20Sopenharmony_ci break; 5098c2ecf20Sopenharmony_ci if (ssid_list[i].len == ssid_len && 5108c2ecf20Sopenharmony_ci !memcmp(ssid_list->ssid, ssid, ssid_len)) 5118c2ecf20Sopenharmony_ci return i; 5128c2ecf20Sopenharmony_ci } 5138c2ecf20Sopenharmony_ci return -1; 5148c2ecf20Sopenharmony_ci} 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci/* We insert the SSIDs in an inverted order, because the FW will 5178c2ecf20Sopenharmony_ci * invert it back. 5188c2ecf20Sopenharmony_ci */ 5198c2ecf20Sopenharmony_cistatic void iwl_scan_build_ssids(struct iwl_mvm_scan_params *params, 5208c2ecf20Sopenharmony_ci struct iwl_ssid_ie *ssids, 5218c2ecf20Sopenharmony_ci u32 *ssid_bitmap) 5228c2ecf20Sopenharmony_ci{ 5238c2ecf20Sopenharmony_ci int i, j; 5248c2ecf20Sopenharmony_ci int index; 5258c2ecf20Sopenharmony_ci u32 tmp_bitmap = 0; 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci /* 5288c2ecf20Sopenharmony_ci * copy SSIDs from match list. 5298c2ecf20Sopenharmony_ci * iwl_config_sched_scan_profiles() uses the order of these ssids to 5308c2ecf20Sopenharmony_ci * config match list. 5318c2ecf20Sopenharmony_ci */ 5328c2ecf20Sopenharmony_ci for (i = 0, j = params->n_match_sets - 1; 5338c2ecf20Sopenharmony_ci j >= 0 && i < PROBE_OPTION_MAX; 5348c2ecf20Sopenharmony_ci i++, j--) { 5358c2ecf20Sopenharmony_ci /* skip empty SSID matchsets */ 5368c2ecf20Sopenharmony_ci if (!params->match_sets[j].ssid.ssid_len) 5378c2ecf20Sopenharmony_ci continue; 5388c2ecf20Sopenharmony_ci ssids[i].id = WLAN_EID_SSID; 5398c2ecf20Sopenharmony_ci ssids[i].len = params->match_sets[j].ssid.ssid_len; 5408c2ecf20Sopenharmony_ci memcpy(ssids[i].ssid, params->match_sets[j].ssid.ssid, 5418c2ecf20Sopenharmony_ci ssids[i].len); 5428c2ecf20Sopenharmony_ci } 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_ci /* add SSIDs from scan SSID list */ 5458c2ecf20Sopenharmony_ci for (j = params->n_ssids - 1; 5468c2ecf20Sopenharmony_ci j >= 0 && i < PROBE_OPTION_MAX; 5478c2ecf20Sopenharmony_ci i++, j--) { 5488c2ecf20Sopenharmony_ci index = iwl_ssid_exist(params->ssids[j].ssid, 5498c2ecf20Sopenharmony_ci params->ssids[j].ssid_len, 5508c2ecf20Sopenharmony_ci ssids); 5518c2ecf20Sopenharmony_ci if (index < 0) { 5528c2ecf20Sopenharmony_ci ssids[i].id = WLAN_EID_SSID; 5538c2ecf20Sopenharmony_ci ssids[i].len = params->ssids[j].ssid_len; 5548c2ecf20Sopenharmony_ci memcpy(ssids[i].ssid, params->ssids[j].ssid, 5558c2ecf20Sopenharmony_ci ssids[i].len); 5568c2ecf20Sopenharmony_ci tmp_bitmap |= BIT(i); 5578c2ecf20Sopenharmony_ci } else { 5588c2ecf20Sopenharmony_ci tmp_bitmap |= BIT(index); 5598c2ecf20Sopenharmony_ci } 5608c2ecf20Sopenharmony_ci } 5618c2ecf20Sopenharmony_ci if (ssid_bitmap) 5628c2ecf20Sopenharmony_ci *ssid_bitmap = tmp_bitmap; 5638c2ecf20Sopenharmony_ci} 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_cistatic int 5668c2ecf20Sopenharmony_ciiwl_mvm_config_sched_scan_profiles(struct iwl_mvm *mvm, 5678c2ecf20Sopenharmony_ci struct cfg80211_sched_scan_request *req) 5688c2ecf20Sopenharmony_ci{ 5698c2ecf20Sopenharmony_ci struct iwl_scan_offload_profile *profile; 5708c2ecf20Sopenharmony_ci struct iwl_scan_offload_profile_cfg_v1 *profile_cfg_v1; 5718c2ecf20Sopenharmony_ci struct iwl_scan_offload_blocklist *blocklist; 5728c2ecf20Sopenharmony_ci struct iwl_scan_offload_profile_cfg_data *data; 5738c2ecf20Sopenharmony_ci int max_profiles = iwl_umac_scan_get_max_profiles(mvm->fw); 5748c2ecf20Sopenharmony_ci int profile_cfg_size = sizeof(*data) + 5758c2ecf20Sopenharmony_ci sizeof(*profile) * max_profiles; 5768c2ecf20Sopenharmony_ci struct iwl_host_cmd cmd = { 5778c2ecf20Sopenharmony_ci .id = SCAN_OFFLOAD_UPDATE_PROFILES_CMD, 5788c2ecf20Sopenharmony_ci .len[1] = profile_cfg_size, 5798c2ecf20Sopenharmony_ci .dataflags[0] = IWL_HCMD_DFL_NOCOPY, 5808c2ecf20Sopenharmony_ci .dataflags[1] = IWL_HCMD_DFL_NOCOPY, 5818c2ecf20Sopenharmony_ci }; 5828c2ecf20Sopenharmony_ci int blocklist_len; 5838c2ecf20Sopenharmony_ci int i; 5848c2ecf20Sopenharmony_ci int ret; 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci if (WARN_ON(req->n_match_sets > max_profiles)) 5878c2ecf20Sopenharmony_ci return -EIO; 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ci if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_SHORT_BL) 5908c2ecf20Sopenharmony_ci blocklist_len = IWL_SCAN_SHORT_BLACKLIST_LEN; 5918c2ecf20Sopenharmony_ci else 5928c2ecf20Sopenharmony_ci blocklist_len = IWL_SCAN_MAX_BLACKLIST_LEN; 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci blocklist = kcalloc(blocklist_len, sizeof(*blocklist), GFP_KERNEL); 5958c2ecf20Sopenharmony_ci if (!blocklist) 5968c2ecf20Sopenharmony_ci return -ENOMEM; 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci profile_cfg_v1 = kzalloc(profile_cfg_size, GFP_KERNEL); 5998c2ecf20Sopenharmony_ci if (!profile_cfg_v1) { 6008c2ecf20Sopenharmony_ci ret = -ENOMEM; 6018c2ecf20Sopenharmony_ci goto free_blocklist; 6028c2ecf20Sopenharmony_ci } 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci cmd.data[0] = blocklist; 6058c2ecf20Sopenharmony_ci cmd.len[0] = sizeof(*blocklist) * blocklist_len; 6068c2ecf20Sopenharmony_ci cmd.data[1] = profile_cfg_v1; 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_ci /* if max_profile is MAX_PROFILES_V2, we have the new API */ 6098c2ecf20Sopenharmony_ci if (max_profiles == IWL_SCAN_MAX_PROFILES_V2) { 6108c2ecf20Sopenharmony_ci struct iwl_scan_offload_profile_cfg *profile_cfg = 6118c2ecf20Sopenharmony_ci (struct iwl_scan_offload_profile_cfg *)profile_cfg_v1; 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_ci data = &profile_cfg->data; 6148c2ecf20Sopenharmony_ci } else { 6158c2ecf20Sopenharmony_ci data = &profile_cfg_v1->data; 6168c2ecf20Sopenharmony_ci } 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ci /* No blocklist configuration */ 6198c2ecf20Sopenharmony_ci data->num_profiles = req->n_match_sets; 6208c2ecf20Sopenharmony_ci data->active_clients = SCAN_CLIENT_SCHED_SCAN; 6218c2ecf20Sopenharmony_ci data->pass_match = SCAN_CLIENT_SCHED_SCAN; 6228c2ecf20Sopenharmony_ci data->match_notify = SCAN_CLIENT_SCHED_SCAN; 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci if (!req->n_match_sets || !req->match_sets[0].ssid.ssid_len) 6258c2ecf20Sopenharmony_ci data->any_beacon_notify = SCAN_CLIENT_SCHED_SCAN; 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci for (i = 0; i < req->n_match_sets; i++) { 6288c2ecf20Sopenharmony_ci profile = &profile_cfg_v1->profiles[i]; 6298c2ecf20Sopenharmony_ci profile->ssid_index = i; 6308c2ecf20Sopenharmony_ci /* Support any cipher and auth algorithm */ 6318c2ecf20Sopenharmony_ci profile->unicast_cipher = 0xff; 6328c2ecf20Sopenharmony_ci profile->auth_alg = 0xff; 6338c2ecf20Sopenharmony_ci profile->network_type = IWL_NETWORK_TYPE_ANY; 6348c2ecf20Sopenharmony_ci profile->band_selection = IWL_SCAN_OFFLOAD_SELECT_ANY; 6358c2ecf20Sopenharmony_ci profile->client_bitmap = SCAN_CLIENT_SCHED_SCAN; 6368c2ecf20Sopenharmony_ci } 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci IWL_DEBUG_SCAN(mvm, "Sending scheduled scan profile config\n"); 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci ret = iwl_mvm_send_cmd(mvm, &cmd); 6418c2ecf20Sopenharmony_ci kfree(profile_cfg_v1); 6428c2ecf20Sopenharmony_cifree_blocklist: 6438c2ecf20Sopenharmony_ci kfree(blocklist); 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci return ret; 6468c2ecf20Sopenharmony_ci} 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_cistatic bool iwl_mvm_scan_pass_all(struct iwl_mvm *mvm, 6498c2ecf20Sopenharmony_ci struct cfg80211_sched_scan_request *req) 6508c2ecf20Sopenharmony_ci{ 6518c2ecf20Sopenharmony_ci if (req->n_match_sets && req->match_sets[0].ssid.ssid_len) { 6528c2ecf20Sopenharmony_ci IWL_DEBUG_SCAN(mvm, 6538c2ecf20Sopenharmony_ci "Sending scheduled scan with filtering, n_match_sets %d\n", 6548c2ecf20Sopenharmony_ci req->n_match_sets); 6558c2ecf20Sopenharmony_ci mvm->sched_scan_pass_all = SCHED_SCAN_PASS_ALL_DISABLED; 6568c2ecf20Sopenharmony_ci return false; 6578c2ecf20Sopenharmony_ci } 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ci IWL_DEBUG_SCAN(mvm, "Sending Scheduled scan without filtering\n"); 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_ci mvm->sched_scan_pass_all = SCHED_SCAN_PASS_ALL_ENABLED; 6628c2ecf20Sopenharmony_ci return true; 6638c2ecf20Sopenharmony_ci} 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_cistatic int iwl_mvm_lmac_scan_abort(struct iwl_mvm *mvm) 6668c2ecf20Sopenharmony_ci{ 6678c2ecf20Sopenharmony_ci int ret; 6688c2ecf20Sopenharmony_ci struct iwl_host_cmd cmd = { 6698c2ecf20Sopenharmony_ci .id = SCAN_OFFLOAD_ABORT_CMD, 6708c2ecf20Sopenharmony_ci }; 6718c2ecf20Sopenharmony_ci u32 status = CAN_ABORT_STATUS; 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ci ret = iwl_mvm_send_cmd_status(mvm, &cmd, &status); 6748c2ecf20Sopenharmony_ci if (ret) 6758c2ecf20Sopenharmony_ci return ret; 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci if (status != CAN_ABORT_STATUS) { 6788c2ecf20Sopenharmony_ci /* 6798c2ecf20Sopenharmony_ci * The scan abort will return 1 for success or 6808c2ecf20Sopenharmony_ci * 2 for "failure". A failure condition can be 6818c2ecf20Sopenharmony_ci * due to simply not being in an active scan which 6828c2ecf20Sopenharmony_ci * can occur if we send the scan abort before the 6838c2ecf20Sopenharmony_ci * microcode has notified us that a scan is completed. 6848c2ecf20Sopenharmony_ci */ 6858c2ecf20Sopenharmony_ci IWL_DEBUG_SCAN(mvm, "SCAN OFFLOAD ABORT ret %d.\n", status); 6868c2ecf20Sopenharmony_ci ret = -ENOENT; 6878c2ecf20Sopenharmony_ci } 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_ci return ret; 6908c2ecf20Sopenharmony_ci} 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_cistatic void iwl_mvm_scan_fill_tx_cmd(struct iwl_mvm *mvm, 6938c2ecf20Sopenharmony_ci struct iwl_scan_req_tx_cmd *tx_cmd, 6948c2ecf20Sopenharmony_ci bool no_cck) 6958c2ecf20Sopenharmony_ci{ 6968c2ecf20Sopenharmony_ci tx_cmd[0].tx_flags = cpu_to_le32(TX_CMD_FLG_SEQ_CTL | 6978c2ecf20Sopenharmony_ci TX_CMD_FLG_BT_DIS); 6988c2ecf20Sopenharmony_ci tx_cmd[0].rate_n_flags = iwl_mvm_scan_rate_n_flags(mvm, 6998c2ecf20Sopenharmony_ci NL80211_BAND_2GHZ, 7008c2ecf20Sopenharmony_ci no_cck); 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_ci if (iwl_fw_lookup_cmd_ver(mvm->fw, LONG_GROUP, 7038c2ecf20Sopenharmony_ci ADD_STA, 7048c2ecf20Sopenharmony_ci 0) < 12) { 7058c2ecf20Sopenharmony_ci tx_cmd[0].sta_id = mvm->aux_sta.sta_id; 7068c2ecf20Sopenharmony_ci tx_cmd[1].sta_id = mvm->aux_sta.sta_id; 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_ci /* 7098c2ecf20Sopenharmony_ci * Fw doesn't use this sta anymore, pending deprecation via HOST API 7108c2ecf20Sopenharmony_ci * change 7118c2ecf20Sopenharmony_ci */ 7128c2ecf20Sopenharmony_ci } else { 7138c2ecf20Sopenharmony_ci tx_cmd[0].sta_id = 0xff; 7148c2ecf20Sopenharmony_ci tx_cmd[1].sta_id = 0xff; 7158c2ecf20Sopenharmony_ci } 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_ci tx_cmd[1].tx_flags = cpu_to_le32(TX_CMD_FLG_SEQ_CTL | 7188c2ecf20Sopenharmony_ci TX_CMD_FLG_BT_DIS); 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_ci tx_cmd[1].rate_n_flags = iwl_mvm_scan_rate_n_flags(mvm, 7218c2ecf20Sopenharmony_ci NL80211_BAND_5GHZ, 7228c2ecf20Sopenharmony_ci no_cck); 7238c2ecf20Sopenharmony_ci} 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_cistatic void 7268c2ecf20Sopenharmony_ciiwl_mvm_lmac_scan_cfg_channels(struct iwl_mvm *mvm, 7278c2ecf20Sopenharmony_ci struct ieee80211_channel **channels, 7288c2ecf20Sopenharmony_ci int n_channels, u32 ssid_bitmap, 7298c2ecf20Sopenharmony_ci struct iwl_scan_req_lmac *cmd) 7308c2ecf20Sopenharmony_ci{ 7318c2ecf20Sopenharmony_ci struct iwl_scan_channel_cfg_lmac *channel_cfg = (void *)&cmd->data; 7328c2ecf20Sopenharmony_ci int i; 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci for (i = 0; i < n_channels; i++) { 7358c2ecf20Sopenharmony_ci channel_cfg[i].channel_num = 7368c2ecf20Sopenharmony_ci cpu_to_le16(channels[i]->hw_value); 7378c2ecf20Sopenharmony_ci channel_cfg[i].iter_count = cpu_to_le16(1); 7388c2ecf20Sopenharmony_ci channel_cfg[i].iter_interval = 0; 7398c2ecf20Sopenharmony_ci channel_cfg[i].flags = 7408c2ecf20Sopenharmony_ci cpu_to_le32(IWL_UNIFIED_SCAN_CHANNEL_PARTIAL | 7418c2ecf20Sopenharmony_ci ssid_bitmap); 7428c2ecf20Sopenharmony_ci } 7438c2ecf20Sopenharmony_ci} 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_cistatic u8 *iwl_mvm_copy_and_insert_ds_elem(struct iwl_mvm *mvm, const u8 *ies, 7468c2ecf20Sopenharmony_ci size_t len, u8 *const pos) 7478c2ecf20Sopenharmony_ci{ 7488c2ecf20Sopenharmony_ci static const u8 before_ds_params[] = { 7498c2ecf20Sopenharmony_ci WLAN_EID_SSID, 7508c2ecf20Sopenharmony_ci WLAN_EID_SUPP_RATES, 7518c2ecf20Sopenharmony_ci WLAN_EID_REQUEST, 7528c2ecf20Sopenharmony_ci WLAN_EID_EXT_SUPP_RATES, 7538c2ecf20Sopenharmony_ci }; 7548c2ecf20Sopenharmony_ci size_t offs; 7558c2ecf20Sopenharmony_ci u8 *newpos = pos; 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_ci if (!iwl_mvm_rrm_scan_needed(mvm)) { 7588c2ecf20Sopenharmony_ci memcpy(newpos, ies, len); 7598c2ecf20Sopenharmony_ci return newpos + len; 7608c2ecf20Sopenharmony_ci } 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_ci offs = ieee80211_ie_split(ies, len, 7638c2ecf20Sopenharmony_ci before_ds_params, 7648c2ecf20Sopenharmony_ci ARRAY_SIZE(before_ds_params), 7658c2ecf20Sopenharmony_ci 0); 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_ci memcpy(newpos, ies, offs); 7688c2ecf20Sopenharmony_ci newpos += offs; 7698c2ecf20Sopenharmony_ci 7708c2ecf20Sopenharmony_ci /* Add a placeholder for DS Parameter Set element */ 7718c2ecf20Sopenharmony_ci *newpos++ = WLAN_EID_DS_PARAMS; 7728c2ecf20Sopenharmony_ci *newpos++ = 1; 7738c2ecf20Sopenharmony_ci *newpos++ = 0; 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_ci memcpy(newpos, ies + offs, len - offs); 7768c2ecf20Sopenharmony_ci newpos += len - offs; 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ci return newpos; 7798c2ecf20Sopenharmony_ci} 7808c2ecf20Sopenharmony_ci 7818c2ecf20Sopenharmony_ci#define WFA_TPC_IE_LEN 9 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_cistatic void iwl_mvm_add_tpc_report_ie(u8 *pos) 7848c2ecf20Sopenharmony_ci{ 7858c2ecf20Sopenharmony_ci pos[0] = WLAN_EID_VENDOR_SPECIFIC; 7868c2ecf20Sopenharmony_ci pos[1] = WFA_TPC_IE_LEN - 2; 7878c2ecf20Sopenharmony_ci pos[2] = (WLAN_OUI_MICROSOFT >> 16) & 0xff; 7888c2ecf20Sopenharmony_ci pos[3] = (WLAN_OUI_MICROSOFT >> 8) & 0xff; 7898c2ecf20Sopenharmony_ci pos[4] = WLAN_OUI_MICROSOFT & 0xff; 7908c2ecf20Sopenharmony_ci pos[5] = WLAN_OUI_TYPE_MICROSOFT_TPC; 7918c2ecf20Sopenharmony_ci pos[6] = 0; 7928c2ecf20Sopenharmony_ci /* pos[7] - tx power will be inserted by the FW */ 7938c2ecf20Sopenharmony_ci pos[7] = 0; 7948c2ecf20Sopenharmony_ci pos[8] = 0; 7958c2ecf20Sopenharmony_ci} 7968c2ecf20Sopenharmony_ci 7978c2ecf20Sopenharmony_cistatic void 7988c2ecf20Sopenharmony_ciiwl_mvm_build_scan_probe(struct iwl_mvm *mvm, struct ieee80211_vif *vif, 7998c2ecf20Sopenharmony_ci struct ieee80211_scan_ies *ies, 8008c2ecf20Sopenharmony_ci struct iwl_mvm_scan_params *params) 8018c2ecf20Sopenharmony_ci{ 8028c2ecf20Sopenharmony_ci struct ieee80211_mgmt *frame = (void *)params->preq.buf; 8038c2ecf20Sopenharmony_ci u8 *pos, *newpos; 8048c2ecf20Sopenharmony_ci const u8 *mac_addr = params->flags & NL80211_SCAN_FLAG_RANDOM_ADDR ? 8058c2ecf20Sopenharmony_ci params->mac_addr : NULL; 8068c2ecf20Sopenharmony_ci 8078c2ecf20Sopenharmony_ci /* 8088c2ecf20Sopenharmony_ci * Unfortunately, right now the offload scan doesn't support randomising 8098c2ecf20Sopenharmony_ci * within the firmware, so until the firmware API is ready we implement 8108c2ecf20Sopenharmony_ci * it in the driver. This means that the scan iterations won't really be 8118c2ecf20Sopenharmony_ci * random, only when it's restarted, but at least that helps a bit. 8128c2ecf20Sopenharmony_ci */ 8138c2ecf20Sopenharmony_ci if (mac_addr) 8148c2ecf20Sopenharmony_ci get_random_mask_addr(frame->sa, mac_addr, 8158c2ecf20Sopenharmony_ci params->mac_addr_mask); 8168c2ecf20Sopenharmony_ci else 8178c2ecf20Sopenharmony_ci memcpy(frame->sa, vif->addr, ETH_ALEN); 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_ci frame->frame_control = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ); 8208c2ecf20Sopenharmony_ci eth_broadcast_addr(frame->da); 8218c2ecf20Sopenharmony_ci eth_broadcast_addr(frame->bssid); 8228c2ecf20Sopenharmony_ci frame->seq_ctrl = 0; 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_ci pos = frame->u.probe_req.variable; 8258c2ecf20Sopenharmony_ci *pos++ = WLAN_EID_SSID; 8268c2ecf20Sopenharmony_ci *pos++ = 0; 8278c2ecf20Sopenharmony_ci 8288c2ecf20Sopenharmony_ci params->preq.mac_header.offset = 0; 8298c2ecf20Sopenharmony_ci params->preq.mac_header.len = cpu_to_le16(24 + 2); 8308c2ecf20Sopenharmony_ci 8318c2ecf20Sopenharmony_ci /* Insert ds parameter set element on 2.4 GHz band */ 8328c2ecf20Sopenharmony_ci newpos = iwl_mvm_copy_and_insert_ds_elem(mvm, 8338c2ecf20Sopenharmony_ci ies->ies[NL80211_BAND_2GHZ], 8348c2ecf20Sopenharmony_ci ies->len[NL80211_BAND_2GHZ], 8358c2ecf20Sopenharmony_ci pos); 8368c2ecf20Sopenharmony_ci params->preq.band_data[0].offset = cpu_to_le16(pos - params->preq.buf); 8378c2ecf20Sopenharmony_ci params->preq.band_data[0].len = cpu_to_le16(newpos - pos); 8388c2ecf20Sopenharmony_ci pos = newpos; 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_ci memcpy(pos, ies->ies[NL80211_BAND_5GHZ], 8418c2ecf20Sopenharmony_ci ies->len[NL80211_BAND_5GHZ]); 8428c2ecf20Sopenharmony_ci params->preq.band_data[1].offset = cpu_to_le16(pos - params->preq.buf); 8438c2ecf20Sopenharmony_ci params->preq.band_data[1].len = 8448c2ecf20Sopenharmony_ci cpu_to_le16(ies->len[NL80211_BAND_5GHZ]); 8458c2ecf20Sopenharmony_ci pos += ies->len[NL80211_BAND_5GHZ]; 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_ci memcpy(pos, ies->common_ies, ies->common_ie_len); 8488c2ecf20Sopenharmony_ci params->preq.common_data.offset = cpu_to_le16(pos - params->preq.buf); 8498c2ecf20Sopenharmony_ci 8508c2ecf20Sopenharmony_ci if (iwl_mvm_rrm_scan_needed(mvm) && 8518c2ecf20Sopenharmony_ci !fw_has_capa(&mvm->fw->ucode_capa, 8528c2ecf20Sopenharmony_ci IWL_UCODE_TLV_CAPA_WFA_TPC_REP_IE_SUPPORT)) { 8538c2ecf20Sopenharmony_ci iwl_mvm_add_tpc_report_ie(pos + ies->common_ie_len); 8548c2ecf20Sopenharmony_ci params->preq.common_data.len = cpu_to_le16(ies->common_ie_len + 8558c2ecf20Sopenharmony_ci WFA_TPC_IE_LEN); 8568c2ecf20Sopenharmony_ci } else { 8578c2ecf20Sopenharmony_ci params->preq.common_data.len = cpu_to_le16(ies->common_ie_len); 8588c2ecf20Sopenharmony_ci } 8598c2ecf20Sopenharmony_ci} 8608c2ecf20Sopenharmony_ci 8618c2ecf20Sopenharmony_cistatic void iwl_mvm_scan_lmac_dwell(struct iwl_mvm *mvm, 8628c2ecf20Sopenharmony_ci struct iwl_scan_req_lmac *cmd, 8638c2ecf20Sopenharmony_ci struct iwl_mvm_scan_params *params) 8648c2ecf20Sopenharmony_ci{ 8658c2ecf20Sopenharmony_ci cmd->active_dwell = IWL_SCAN_DWELL_ACTIVE; 8668c2ecf20Sopenharmony_ci cmd->passive_dwell = IWL_SCAN_DWELL_PASSIVE; 8678c2ecf20Sopenharmony_ci cmd->fragmented_dwell = IWL_SCAN_DWELL_FRAGMENTED; 8688c2ecf20Sopenharmony_ci cmd->extended_dwell = IWL_SCAN_DWELL_EXTENDED; 8698c2ecf20Sopenharmony_ci cmd->max_out_time = cpu_to_le32(scan_timing[params->type].max_out_time); 8708c2ecf20Sopenharmony_ci cmd->suspend_time = cpu_to_le32(scan_timing[params->type].suspend_time); 8718c2ecf20Sopenharmony_ci cmd->scan_prio = cpu_to_le32(IWL_SCAN_PRIORITY_EXT_6); 8728c2ecf20Sopenharmony_ci} 8738c2ecf20Sopenharmony_ci 8748c2ecf20Sopenharmony_cistatic inline bool iwl_mvm_scan_fits(struct iwl_mvm *mvm, int n_ssids, 8758c2ecf20Sopenharmony_ci struct ieee80211_scan_ies *ies, 8768c2ecf20Sopenharmony_ci int n_channels) 8778c2ecf20Sopenharmony_ci{ 8788c2ecf20Sopenharmony_ci return ((n_ssids <= PROBE_OPTION_MAX) && 8798c2ecf20Sopenharmony_ci (n_channels <= mvm->fw->ucode_capa.n_scan_channels) & 8808c2ecf20Sopenharmony_ci (ies->common_ie_len + 8818c2ecf20Sopenharmony_ci ies->len[NL80211_BAND_2GHZ] + 8828c2ecf20Sopenharmony_ci ies->len[NL80211_BAND_5GHZ] <= 8838c2ecf20Sopenharmony_ci iwl_mvm_max_scan_ie_fw_cmd_room(mvm))); 8848c2ecf20Sopenharmony_ci} 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_cistatic inline bool iwl_mvm_scan_use_ebs(struct iwl_mvm *mvm, 8878c2ecf20Sopenharmony_ci struct ieee80211_vif *vif) 8888c2ecf20Sopenharmony_ci{ 8898c2ecf20Sopenharmony_ci const struct iwl_ucode_capabilities *capa = &mvm->fw->ucode_capa; 8908c2ecf20Sopenharmony_ci bool low_latency; 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_ci if (iwl_mvm_is_cdb_supported(mvm)) 8938c2ecf20Sopenharmony_ci low_latency = iwl_mvm_low_latency_band(mvm, NL80211_BAND_5GHZ); 8948c2ecf20Sopenharmony_ci else 8958c2ecf20Sopenharmony_ci low_latency = iwl_mvm_low_latency(mvm); 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_ci /* We can only use EBS if: 8988c2ecf20Sopenharmony_ci * 1. the feature is supported; 8998c2ecf20Sopenharmony_ci * 2. the last EBS was successful; 9008c2ecf20Sopenharmony_ci * 3. if only single scan, the single scan EBS API is supported; 9018c2ecf20Sopenharmony_ci * 4. it's not a p2p find operation. 9028c2ecf20Sopenharmony_ci * 5. we are not in low latency mode, 9038c2ecf20Sopenharmony_ci * or if fragmented ebs is supported by the FW 9048c2ecf20Sopenharmony_ci */ 9058c2ecf20Sopenharmony_ci return ((capa->flags & IWL_UCODE_TLV_FLAGS_EBS_SUPPORT) && 9068c2ecf20Sopenharmony_ci mvm->last_ebs_successful && IWL_MVM_ENABLE_EBS && 9078c2ecf20Sopenharmony_ci vif->type != NL80211_IFTYPE_P2P_DEVICE && 9088c2ecf20Sopenharmony_ci (!low_latency || iwl_mvm_is_frag_ebs_supported(mvm))); 9098c2ecf20Sopenharmony_ci} 9108c2ecf20Sopenharmony_ci 9118c2ecf20Sopenharmony_cistatic inline bool iwl_mvm_is_regular_scan(struct iwl_mvm_scan_params *params) 9128c2ecf20Sopenharmony_ci{ 9138c2ecf20Sopenharmony_ci return params->n_scan_plans == 1 && 9148c2ecf20Sopenharmony_ci params->scan_plans[0].iterations == 1; 9158c2ecf20Sopenharmony_ci} 9168c2ecf20Sopenharmony_ci 9178c2ecf20Sopenharmony_cistatic bool iwl_mvm_is_scan_fragmented(enum iwl_mvm_scan_type type) 9188c2ecf20Sopenharmony_ci{ 9198c2ecf20Sopenharmony_ci return (type == IWL_SCAN_TYPE_FRAGMENTED || 9208c2ecf20Sopenharmony_ci type == IWL_SCAN_TYPE_FAST_BALANCE); 9218c2ecf20Sopenharmony_ci} 9228c2ecf20Sopenharmony_ci 9238c2ecf20Sopenharmony_cistatic int iwl_mvm_scan_lmac_flags(struct iwl_mvm *mvm, 9248c2ecf20Sopenharmony_ci struct iwl_mvm_scan_params *params, 9258c2ecf20Sopenharmony_ci struct ieee80211_vif *vif) 9268c2ecf20Sopenharmony_ci{ 9278c2ecf20Sopenharmony_ci int flags = 0; 9288c2ecf20Sopenharmony_ci 9298c2ecf20Sopenharmony_ci if (params->n_ssids == 0) 9308c2ecf20Sopenharmony_ci flags |= IWL_MVM_LMAC_SCAN_FLAG_PASSIVE; 9318c2ecf20Sopenharmony_ci 9328c2ecf20Sopenharmony_ci if (params->n_ssids == 1 && params->ssids[0].ssid_len != 0) 9338c2ecf20Sopenharmony_ci flags |= IWL_MVM_LMAC_SCAN_FLAG_PRE_CONNECTION; 9348c2ecf20Sopenharmony_ci 9358c2ecf20Sopenharmony_ci if (iwl_mvm_is_scan_fragmented(params->type)) 9368c2ecf20Sopenharmony_ci flags |= IWL_MVM_LMAC_SCAN_FLAG_FRAGMENTED; 9378c2ecf20Sopenharmony_ci 9388c2ecf20Sopenharmony_ci if (iwl_mvm_rrm_scan_needed(mvm) && 9398c2ecf20Sopenharmony_ci fw_has_capa(&mvm->fw->ucode_capa, 9408c2ecf20Sopenharmony_ci IWL_UCODE_TLV_CAPA_WFA_TPC_REP_IE_SUPPORT)) 9418c2ecf20Sopenharmony_ci flags |= IWL_MVM_LMAC_SCAN_FLAGS_RRM_ENABLED; 9428c2ecf20Sopenharmony_ci 9438c2ecf20Sopenharmony_ci if (params->pass_all) 9448c2ecf20Sopenharmony_ci flags |= IWL_MVM_LMAC_SCAN_FLAG_PASS_ALL; 9458c2ecf20Sopenharmony_ci else 9468c2ecf20Sopenharmony_ci flags |= IWL_MVM_LMAC_SCAN_FLAG_MATCH; 9478c2ecf20Sopenharmony_ci 9488c2ecf20Sopenharmony_ci#ifdef CONFIG_IWLWIFI_DEBUGFS 9498c2ecf20Sopenharmony_ci if (mvm->scan_iter_notif_enabled) 9508c2ecf20Sopenharmony_ci flags |= IWL_MVM_LMAC_SCAN_FLAG_ITER_COMPLETE; 9518c2ecf20Sopenharmony_ci#endif 9528c2ecf20Sopenharmony_ci 9538c2ecf20Sopenharmony_ci if (mvm->sched_scan_pass_all == SCHED_SCAN_PASS_ALL_ENABLED) 9548c2ecf20Sopenharmony_ci flags |= IWL_MVM_LMAC_SCAN_FLAG_ITER_COMPLETE; 9558c2ecf20Sopenharmony_ci 9568c2ecf20Sopenharmony_ci if (iwl_mvm_is_regular_scan(params) && 9578c2ecf20Sopenharmony_ci vif->type != NL80211_IFTYPE_P2P_DEVICE && 9588c2ecf20Sopenharmony_ci !iwl_mvm_is_scan_fragmented(params->type)) 9598c2ecf20Sopenharmony_ci flags |= IWL_MVM_LMAC_SCAN_FLAG_EXTENDED_DWELL; 9608c2ecf20Sopenharmony_ci 9618c2ecf20Sopenharmony_ci return flags; 9628c2ecf20Sopenharmony_ci} 9638c2ecf20Sopenharmony_ci 9648c2ecf20Sopenharmony_cistatic void 9658c2ecf20Sopenharmony_ciiwl_mvm_scan_set_legacy_probe_req(struct iwl_scan_probe_req_v1 *p_req, 9668c2ecf20Sopenharmony_ci struct iwl_scan_probe_req *src_p_req) 9678c2ecf20Sopenharmony_ci{ 9688c2ecf20Sopenharmony_ci int i; 9698c2ecf20Sopenharmony_ci 9708c2ecf20Sopenharmony_ci p_req->mac_header = src_p_req->mac_header; 9718c2ecf20Sopenharmony_ci for (i = 0; i < SCAN_NUM_BAND_PROBE_DATA_V_1; i++) 9728c2ecf20Sopenharmony_ci p_req->band_data[i] = src_p_req->band_data[i]; 9738c2ecf20Sopenharmony_ci p_req->common_data = src_p_req->common_data; 9748c2ecf20Sopenharmony_ci memcpy(p_req->buf, src_p_req->buf, sizeof(p_req->buf)); 9758c2ecf20Sopenharmony_ci} 9768c2ecf20Sopenharmony_ci 9778c2ecf20Sopenharmony_cistatic int iwl_mvm_scan_lmac(struct iwl_mvm *mvm, struct ieee80211_vif *vif, 9788c2ecf20Sopenharmony_ci struct iwl_mvm_scan_params *params) 9798c2ecf20Sopenharmony_ci{ 9808c2ecf20Sopenharmony_ci struct iwl_scan_req_lmac *cmd = mvm->scan_cmd; 9818c2ecf20Sopenharmony_ci struct iwl_scan_probe_req_v1 *preq = 9828c2ecf20Sopenharmony_ci (void *)(cmd->data + sizeof(struct iwl_scan_channel_cfg_lmac) * 9838c2ecf20Sopenharmony_ci mvm->fw->ucode_capa.n_scan_channels); 9848c2ecf20Sopenharmony_ci u32 ssid_bitmap = 0; 9858c2ecf20Sopenharmony_ci int i; 9868c2ecf20Sopenharmony_ci u8 band; 9878c2ecf20Sopenharmony_ci 9888c2ecf20Sopenharmony_ci if (WARN_ON(params->n_scan_plans > IWL_MAX_SCHED_SCAN_PLANS)) 9898c2ecf20Sopenharmony_ci return -EINVAL; 9908c2ecf20Sopenharmony_ci 9918c2ecf20Sopenharmony_ci iwl_mvm_scan_lmac_dwell(mvm, cmd, params); 9928c2ecf20Sopenharmony_ci 9938c2ecf20Sopenharmony_ci cmd->rx_chain_select = iwl_mvm_scan_rx_chain(mvm); 9948c2ecf20Sopenharmony_ci cmd->iter_num = cpu_to_le32(1); 9958c2ecf20Sopenharmony_ci cmd->n_channels = (u8)params->n_channels; 9968c2ecf20Sopenharmony_ci 9978c2ecf20Sopenharmony_ci cmd->delay = cpu_to_le32(params->delay); 9988c2ecf20Sopenharmony_ci 9998c2ecf20Sopenharmony_ci cmd->scan_flags = cpu_to_le32(iwl_mvm_scan_lmac_flags(mvm, params, 10008c2ecf20Sopenharmony_ci vif)); 10018c2ecf20Sopenharmony_ci 10028c2ecf20Sopenharmony_ci band = iwl_mvm_phy_band_from_nl80211(params->channels[0]->band); 10038c2ecf20Sopenharmony_ci cmd->flags = cpu_to_le32(band); 10048c2ecf20Sopenharmony_ci cmd->filter_flags = cpu_to_le32(MAC_FILTER_ACCEPT_GRP | 10058c2ecf20Sopenharmony_ci MAC_FILTER_IN_BEACON); 10068c2ecf20Sopenharmony_ci iwl_mvm_scan_fill_tx_cmd(mvm, cmd->tx_cmd, params->no_cck); 10078c2ecf20Sopenharmony_ci iwl_scan_build_ssids(params, cmd->direct_scan, &ssid_bitmap); 10088c2ecf20Sopenharmony_ci 10098c2ecf20Sopenharmony_ci /* this API uses bits 1-20 instead of 0-19 */ 10108c2ecf20Sopenharmony_ci ssid_bitmap <<= 1; 10118c2ecf20Sopenharmony_ci 10128c2ecf20Sopenharmony_ci for (i = 0; i < params->n_scan_plans; i++) { 10138c2ecf20Sopenharmony_ci struct cfg80211_sched_scan_plan *scan_plan = 10148c2ecf20Sopenharmony_ci ¶ms->scan_plans[i]; 10158c2ecf20Sopenharmony_ci 10168c2ecf20Sopenharmony_ci cmd->schedule[i].delay = 10178c2ecf20Sopenharmony_ci cpu_to_le16(scan_plan->interval); 10188c2ecf20Sopenharmony_ci cmd->schedule[i].iterations = scan_plan->iterations; 10198c2ecf20Sopenharmony_ci cmd->schedule[i].full_scan_mul = 1; 10208c2ecf20Sopenharmony_ci } 10218c2ecf20Sopenharmony_ci 10228c2ecf20Sopenharmony_ci /* 10238c2ecf20Sopenharmony_ci * If the number of iterations of the last scan plan is set to 10248c2ecf20Sopenharmony_ci * zero, it should run infinitely. However, this is not always the case. 10258c2ecf20Sopenharmony_ci * For example, when regular scan is requested the driver sets one scan 10268c2ecf20Sopenharmony_ci * plan with one iteration. 10278c2ecf20Sopenharmony_ci */ 10288c2ecf20Sopenharmony_ci if (!cmd->schedule[i - 1].iterations) 10298c2ecf20Sopenharmony_ci cmd->schedule[i - 1].iterations = 0xff; 10308c2ecf20Sopenharmony_ci 10318c2ecf20Sopenharmony_ci if (iwl_mvm_scan_use_ebs(mvm, vif)) { 10328c2ecf20Sopenharmony_ci cmd->channel_opt[0].flags = 10338c2ecf20Sopenharmony_ci cpu_to_le16(IWL_SCAN_CHANNEL_FLAG_EBS | 10348c2ecf20Sopenharmony_ci IWL_SCAN_CHANNEL_FLAG_EBS_ACCURATE | 10358c2ecf20Sopenharmony_ci IWL_SCAN_CHANNEL_FLAG_CACHE_ADD); 10368c2ecf20Sopenharmony_ci cmd->channel_opt[0].non_ebs_ratio = 10378c2ecf20Sopenharmony_ci cpu_to_le16(IWL_DENSE_EBS_SCAN_RATIO); 10388c2ecf20Sopenharmony_ci cmd->channel_opt[1].flags = 10398c2ecf20Sopenharmony_ci cpu_to_le16(IWL_SCAN_CHANNEL_FLAG_EBS | 10408c2ecf20Sopenharmony_ci IWL_SCAN_CHANNEL_FLAG_EBS_ACCURATE | 10418c2ecf20Sopenharmony_ci IWL_SCAN_CHANNEL_FLAG_CACHE_ADD); 10428c2ecf20Sopenharmony_ci cmd->channel_opt[1].non_ebs_ratio = 10438c2ecf20Sopenharmony_ci cpu_to_le16(IWL_SPARSE_EBS_SCAN_RATIO); 10448c2ecf20Sopenharmony_ci } 10458c2ecf20Sopenharmony_ci 10468c2ecf20Sopenharmony_ci iwl_mvm_lmac_scan_cfg_channels(mvm, params->channels, 10478c2ecf20Sopenharmony_ci params->n_channels, ssid_bitmap, cmd); 10488c2ecf20Sopenharmony_ci 10498c2ecf20Sopenharmony_ci iwl_mvm_scan_set_legacy_probe_req(preq, ¶ms->preq); 10508c2ecf20Sopenharmony_ci 10518c2ecf20Sopenharmony_ci return 0; 10528c2ecf20Sopenharmony_ci} 10538c2ecf20Sopenharmony_ci 10548c2ecf20Sopenharmony_cistatic int rate_to_scan_rate_flag(unsigned int rate) 10558c2ecf20Sopenharmony_ci{ 10568c2ecf20Sopenharmony_ci static const int rate_to_scan_rate[IWL_RATE_COUNT] = { 10578c2ecf20Sopenharmony_ci [IWL_RATE_1M_INDEX] = SCAN_CONFIG_RATE_1M, 10588c2ecf20Sopenharmony_ci [IWL_RATE_2M_INDEX] = SCAN_CONFIG_RATE_2M, 10598c2ecf20Sopenharmony_ci [IWL_RATE_5M_INDEX] = SCAN_CONFIG_RATE_5M, 10608c2ecf20Sopenharmony_ci [IWL_RATE_11M_INDEX] = SCAN_CONFIG_RATE_11M, 10618c2ecf20Sopenharmony_ci [IWL_RATE_6M_INDEX] = SCAN_CONFIG_RATE_6M, 10628c2ecf20Sopenharmony_ci [IWL_RATE_9M_INDEX] = SCAN_CONFIG_RATE_9M, 10638c2ecf20Sopenharmony_ci [IWL_RATE_12M_INDEX] = SCAN_CONFIG_RATE_12M, 10648c2ecf20Sopenharmony_ci [IWL_RATE_18M_INDEX] = SCAN_CONFIG_RATE_18M, 10658c2ecf20Sopenharmony_ci [IWL_RATE_24M_INDEX] = SCAN_CONFIG_RATE_24M, 10668c2ecf20Sopenharmony_ci [IWL_RATE_36M_INDEX] = SCAN_CONFIG_RATE_36M, 10678c2ecf20Sopenharmony_ci [IWL_RATE_48M_INDEX] = SCAN_CONFIG_RATE_48M, 10688c2ecf20Sopenharmony_ci [IWL_RATE_54M_INDEX] = SCAN_CONFIG_RATE_54M, 10698c2ecf20Sopenharmony_ci }; 10708c2ecf20Sopenharmony_ci 10718c2ecf20Sopenharmony_ci return rate_to_scan_rate[rate]; 10728c2ecf20Sopenharmony_ci} 10738c2ecf20Sopenharmony_ci 10748c2ecf20Sopenharmony_cistatic __le32 iwl_mvm_scan_config_rates(struct iwl_mvm *mvm) 10758c2ecf20Sopenharmony_ci{ 10768c2ecf20Sopenharmony_ci struct ieee80211_supported_band *band; 10778c2ecf20Sopenharmony_ci unsigned int rates = 0; 10788c2ecf20Sopenharmony_ci int i; 10798c2ecf20Sopenharmony_ci 10808c2ecf20Sopenharmony_ci band = &mvm->nvm_data->bands[NL80211_BAND_2GHZ]; 10818c2ecf20Sopenharmony_ci for (i = 0; i < band->n_bitrates; i++) 10828c2ecf20Sopenharmony_ci rates |= rate_to_scan_rate_flag(band->bitrates[i].hw_value); 10838c2ecf20Sopenharmony_ci band = &mvm->nvm_data->bands[NL80211_BAND_5GHZ]; 10848c2ecf20Sopenharmony_ci for (i = 0; i < band->n_bitrates; i++) 10858c2ecf20Sopenharmony_ci rates |= rate_to_scan_rate_flag(band->bitrates[i].hw_value); 10868c2ecf20Sopenharmony_ci 10878c2ecf20Sopenharmony_ci /* Set both basic rates and supported rates */ 10888c2ecf20Sopenharmony_ci rates |= SCAN_CONFIG_SUPPORTED_RATE(rates); 10898c2ecf20Sopenharmony_ci 10908c2ecf20Sopenharmony_ci return cpu_to_le32(rates); 10918c2ecf20Sopenharmony_ci} 10928c2ecf20Sopenharmony_ci 10938c2ecf20Sopenharmony_cistatic void iwl_mvm_fill_scan_dwell(struct iwl_mvm *mvm, 10948c2ecf20Sopenharmony_ci struct iwl_scan_dwell *dwell) 10958c2ecf20Sopenharmony_ci{ 10968c2ecf20Sopenharmony_ci dwell->active = IWL_SCAN_DWELL_ACTIVE; 10978c2ecf20Sopenharmony_ci dwell->passive = IWL_SCAN_DWELL_PASSIVE; 10988c2ecf20Sopenharmony_ci dwell->fragmented = IWL_SCAN_DWELL_FRAGMENTED; 10998c2ecf20Sopenharmony_ci dwell->extended = IWL_SCAN_DWELL_EXTENDED; 11008c2ecf20Sopenharmony_ci} 11018c2ecf20Sopenharmony_ci 11028c2ecf20Sopenharmony_cistatic void iwl_mvm_fill_channels(struct iwl_mvm *mvm, u8 *channels, 11038c2ecf20Sopenharmony_ci u32 max_channels) 11048c2ecf20Sopenharmony_ci{ 11058c2ecf20Sopenharmony_ci struct ieee80211_supported_band *band; 11068c2ecf20Sopenharmony_ci int i, j = 0; 11078c2ecf20Sopenharmony_ci 11088c2ecf20Sopenharmony_ci band = &mvm->nvm_data->bands[NL80211_BAND_2GHZ]; 11098c2ecf20Sopenharmony_ci for (i = 0; i < band->n_channels && j < max_channels; i++, j++) 11108c2ecf20Sopenharmony_ci channels[j] = band->channels[i].hw_value; 11118c2ecf20Sopenharmony_ci band = &mvm->nvm_data->bands[NL80211_BAND_5GHZ]; 11128c2ecf20Sopenharmony_ci for (i = 0; i < band->n_channels && j < max_channels; i++, j++) 11138c2ecf20Sopenharmony_ci channels[j] = band->channels[i].hw_value; 11148c2ecf20Sopenharmony_ci} 11158c2ecf20Sopenharmony_ci 11168c2ecf20Sopenharmony_cistatic void iwl_mvm_fill_scan_config_v1(struct iwl_mvm *mvm, void *config, 11178c2ecf20Sopenharmony_ci u32 flags, u8 channel_flags, 11188c2ecf20Sopenharmony_ci u32 max_channels) 11198c2ecf20Sopenharmony_ci{ 11208c2ecf20Sopenharmony_ci enum iwl_mvm_scan_type type = iwl_mvm_get_scan_type(mvm, NULL); 11218c2ecf20Sopenharmony_ci struct iwl_scan_config_v1 *cfg = config; 11228c2ecf20Sopenharmony_ci 11238c2ecf20Sopenharmony_ci cfg->flags = cpu_to_le32(flags); 11248c2ecf20Sopenharmony_ci cfg->tx_chains = cpu_to_le32(iwl_mvm_get_valid_tx_ant(mvm)); 11258c2ecf20Sopenharmony_ci cfg->rx_chains = cpu_to_le32(iwl_mvm_scan_rx_ant(mvm)); 11268c2ecf20Sopenharmony_ci cfg->legacy_rates = iwl_mvm_scan_config_rates(mvm); 11278c2ecf20Sopenharmony_ci cfg->out_of_channel_time = cpu_to_le32(scan_timing[type].max_out_time); 11288c2ecf20Sopenharmony_ci cfg->suspend_time = cpu_to_le32(scan_timing[type].suspend_time); 11298c2ecf20Sopenharmony_ci 11308c2ecf20Sopenharmony_ci iwl_mvm_fill_scan_dwell(mvm, &cfg->dwell); 11318c2ecf20Sopenharmony_ci 11328c2ecf20Sopenharmony_ci memcpy(&cfg->mac_addr, &mvm->addresses[0].addr, ETH_ALEN); 11338c2ecf20Sopenharmony_ci 11348c2ecf20Sopenharmony_ci /* This function should not be called when using ADD_STA ver >=12 */ 11358c2ecf20Sopenharmony_ci WARN_ON_ONCE(iwl_fw_lookup_cmd_ver(mvm->fw, LONG_GROUP, 11368c2ecf20Sopenharmony_ci ADD_STA, 0) >= 12); 11378c2ecf20Sopenharmony_ci 11388c2ecf20Sopenharmony_ci cfg->bcast_sta_id = mvm->aux_sta.sta_id; 11398c2ecf20Sopenharmony_ci cfg->channel_flags = channel_flags; 11408c2ecf20Sopenharmony_ci 11418c2ecf20Sopenharmony_ci iwl_mvm_fill_channels(mvm, cfg->channel_array, max_channels); 11428c2ecf20Sopenharmony_ci} 11438c2ecf20Sopenharmony_ci 11448c2ecf20Sopenharmony_cistatic void iwl_mvm_fill_scan_config_v2(struct iwl_mvm *mvm, void *config, 11458c2ecf20Sopenharmony_ci u32 flags, u8 channel_flags, 11468c2ecf20Sopenharmony_ci u32 max_channels) 11478c2ecf20Sopenharmony_ci{ 11488c2ecf20Sopenharmony_ci struct iwl_scan_config_v2 *cfg = config; 11498c2ecf20Sopenharmony_ci 11508c2ecf20Sopenharmony_ci cfg->flags = cpu_to_le32(flags); 11518c2ecf20Sopenharmony_ci cfg->tx_chains = cpu_to_le32(iwl_mvm_get_valid_tx_ant(mvm)); 11528c2ecf20Sopenharmony_ci cfg->rx_chains = cpu_to_le32(iwl_mvm_scan_rx_ant(mvm)); 11538c2ecf20Sopenharmony_ci cfg->legacy_rates = iwl_mvm_scan_config_rates(mvm); 11548c2ecf20Sopenharmony_ci 11558c2ecf20Sopenharmony_ci if (iwl_mvm_is_cdb_supported(mvm)) { 11568c2ecf20Sopenharmony_ci enum iwl_mvm_scan_type lb_type, hb_type; 11578c2ecf20Sopenharmony_ci 11588c2ecf20Sopenharmony_ci lb_type = iwl_mvm_get_scan_type_band(mvm, NULL, 11598c2ecf20Sopenharmony_ci NL80211_BAND_2GHZ); 11608c2ecf20Sopenharmony_ci hb_type = iwl_mvm_get_scan_type_band(mvm, NULL, 11618c2ecf20Sopenharmony_ci NL80211_BAND_5GHZ); 11628c2ecf20Sopenharmony_ci 11638c2ecf20Sopenharmony_ci cfg->out_of_channel_time[SCAN_LB_LMAC_IDX] = 11648c2ecf20Sopenharmony_ci cpu_to_le32(scan_timing[lb_type].max_out_time); 11658c2ecf20Sopenharmony_ci cfg->suspend_time[SCAN_LB_LMAC_IDX] = 11668c2ecf20Sopenharmony_ci cpu_to_le32(scan_timing[lb_type].suspend_time); 11678c2ecf20Sopenharmony_ci 11688c2ecf20Sopenharmony_ci cfg->out_of_channel_time[SCAN_HB_LMAC_IDX] = 11698c2ecf20Sopenharmony_ci cpu_to_le32(scan_timing[hb_type].max_out_time); 11708c2ecf20Sopenharmony_ci cfg->suspend_time[SCAN_HB_LMAC_IDX] = 11718c2ecf20Sopenharmony_ci cpu_to_le32(scan_timing[hb_type].suspend_time); 11728c2ecf20Sopenharmony_ci } else { 11738c2ecf20Sopenharmony_ci enum iwl_mvm_scan_type type = 11748c2ecf20Sopenharmony_ci iwl_mvm_get_scan_type(mvm, NULL); 11758c2ecf20Sopenharmony_ci 11768c2ecf20Sopenharmony_ci cfg->out_of_channel_time[SCAN_LB_LMAC_IDX] = 11778c2ecf20Sopenharmony_ci cpu_to_le32(scan_timing[type].max_out_time); 11788c2ecf20Sopenharmony_ci cfg->suspend_time[SCAN_LB_LMAC_IDX] = 11798c2ecf20Sopenharmony_ci cpu_to_le32(scan_timing[type].suspend_time); 11808c2ecf20Sopenharmony_ci } 11818c2ecf20Sopenharmony_ci 11828c2ecf20Sopenharmony_ci iwl_mvm_fill_scan_dwell(mvm, &cfg->dwell); 11838c2ecf20Sopenharmony_ci 11848c2ecf20Sopenharmony_ci memcpy(&cfg->mac_addr, &mvm->addresses[0].addr, ETH_ALEN); 11858c2ecf20Sopenharmony_ci 11868c2ecf20Sopenharmony_ci /* This function should not be called when using ADD_STA ver >=12 */ 11878c2ecf20Sopenharmony_ci WARN_ON_ONCE(iwl_fw_lookup_cmd_ver(mvm->fw, LONG_GROUP, 11888c2ecf20Sopenharmony_ci ADD_STA, 0) >= 12); 11898c2ecf20Sopenharmony_ci 11908c2ecf20Sopenharmony_ci cfg->bcast_sta_id = mvm->aux_sta.sta_id; 11918c2ecf20Sopenharmony_ci cfg->channel_flags = channel_flags; 11928c2ecf20Sopenharmony_ci 11938c2ecf20Sopenharmony_ci iwl_mvm_fill_channels(mvm, cfg->channel_array, max_channels); 11948c2ecf20Sopenharmony_ci} 11958c2ecf20Sopenharmony_ci 11968c2ecf20Sopenharmony_cistatic int iwl_mvm_legacy_config_scan(struct iwl_mvm *mvm) 11978c2ecf20Sopenharmony_ci{ 11988c2ecf20Sopenharmony_ci void *cfg; 11998c2ecf20Sopenharmony_ci int ret, cmd_size; 12008c2ecf20Sopenharmony_ci struct iwl_host_cmd cmd = { 12018c2ecf20Sopenharmony_ci .id = iwl_cmd_id(SCAN_CFG_CMD, IWL_ALWAYS_LONG_GROUP, 0), 12028c2ecf20Sopenharmony_ci }; 12038c2ecf20Sopenharmony_ci enum iwl_mvm_scan_type type; 12048c2ecf20Sopenharmony_ci enum iwl_mvm_scan_type hb_type = IWL_SCAN_TYPE_NOT_SET; 12058c2ecf20Sopenharmony_ci int num_channels = 12068c2ecf20Sopenharmony_ci mvm->nvm_data->bands[NL80211_BAND_2GHZ].n_channels + 12078c2ecf20Sopenharmony_ci mvm->nvm_data->bands[NL80211_BAND_5GHZ].n_channels; 12088c2ecf20Sopenharmony_ci u32 flags; 12098c2ecf20Sopenharmony_ci u8 channel_flags; 12108c2ecf20Sopenharmony_ci 12118c2ecf20Sopenharmony_ci if (WARN_ON(num_channels > mvm->fw->ucode_capa.n_scan_channels)) 12128c2ecf20Sopenharmony_ci num_channels = mvm->fw->ucode_capa.n_scan_channels; 12138c2ecf20Sopenharmony_ci 12148c2ecf20Sopenharmony_ci if (iwl_mvm_is_cdb_supported(mvm)) { 12158c2ecf20Sopenharmony_ci type = iwl_mvm_get_scan_type_band(mvm, NULL, 12168c2ecf20Sopenharmony_ci NL80211_BAND_2GHZ); 12178c2ecf20Sopenharmony_ci hb_type = iwl_mvm_get_scan_type_band(mvm, NULL, 12188c2ecf20Sopenharmony_ci NL80211_BAND_5GHZ); 12198c2ecf20Sopenharmony_ci if (type == mvm->scan_type && hb_type == mvm->hb_scan_type) 12208c2ecf20Sopenharmony_ci return 0; 12218c2ecf20Sopenharmony_ci } else { 12228c2ecf20Sopenharmony_ci type = iwl_mvm_get_scan_type(mvm, NULL); 12238c2ecf20Sopenharmony_ci if (type == mvm->scan_type) 12248c2ecf20Sopenharmony_ci return 0; 12258c2ecf20Sopenharmony_ci } 12268c2ecf20Sopenharmony_ci 12278c2ecf20Sopenharmony_ci if (iwl_mvm_cdb_scan_api(mvm)) 12288c2ecf20Sopenharmony_ci cmd_size = sizeof(struct iwl_scan_config_v2); 12298c2ecf20Sopenharmony_ci else 12308c2ecf20Sopenharmony_ci cmd_size = sizeof(struct iwl_scan_config_v1); 12318c2ecf20Sopenharmony_ci cmd_size += mvm->fw->ucode_capa.n_scan_channels; 12328c2ecf20Sopenharmony_ci 12338c2ecf20Sopenharmony_ci cfg = kzalloc(cmd_size, GFP_KERNEL); 12348c2ecf20Sopenharmony_ci if (!cfg) 12358c2ecf20Sopenharmony_ci return -ENOMEM; 12368c2ecf20Sopenharmony_ci 12378c2ecf20Sopenharmony_ci flags = SCAN_CONFIG_FLAG_ACTIVATE | 12388c2ecf20Sopenharmony_ci SCAN_CONFIG_FLAG_ALLOW_CHUB_REQS | 12398c2ecf20Sopenharmony_ci SCAN_CONFIG_FLAG_SET_TX_CHAINS | 12408c2ecf20Sopenharmony_ci SCAN_CONFIG_FLAG_SET_RX_CHAINS | 12418c2ecf20Sopenharmony_ci SCAN_CONFIG_FLAG_SET_AUX_STA_ID | 12428c2ecf20Sopenharmony_ci SCAN_CONFIG_FLAG_SET_ALL_TIMES | 12438c2ecf20Sopenharmony_ci SCAN_CONFIG_FLAG_SET_LEGACY_RATES | 12448c2ecf20Sopenharmony_ci SCAN_CONFIG_FLAG_SET_MAC_ADDR | 12458c2ecf20Sopenharmony_ci SCAN_CONFIG_FLAG_SET_CHANNEL_FLAGS | 12468c2ecf20Sopenharmony_ci SCAN_CONFIG_N_CHANNELS(num_channels) | 12478c2ecf20Sopenharmony_ci (iwl_mvm_is_scan_fragmented(type) ? 12488c2ecf20Sopenharmony_ci SCAN_CONFIG_FLAG_SET_FRAGMENTED : 12498c2ecf20Sopenharmony_ci SCAN_CONFIG_FLAG_CLEAR_FRAGMENTED); 12508c2ecf20Sopenharmony_ci 12518c2ecf20Sopenharmony_ci channel_flags = IWL_CHANNEL_FLAG_EBS | 12528c2ecf20Sopenharmony_ci IWL_CHANNEL_FLAG_ACCURATE_EBS | 12538c2ecf20Sopenharmony_ci IWL_CHANNEL_FLAG_EBS_ADD | 12548c2ecf20Sopenharmony_ci IWL_CHANNEL_FLAG_PRE_SCAN_PASSIVE2ACTIVE; 12558c2ecf20Sopenharmony_ci 12568c2ecf20Sopenharmony_ci /* 12578c2ecf20Sopenharmony_ci * Check for fragmented scan on LMAC2 - high band. 12588c2ecf20Sopenharmony_ci * LMAC1 - low band is checked above. 12598c2ecf20Sopenharmony_ci */ 12608c2ecf20Sopenharmony_ci if (iwl_mvm_cdb_scan_api(mvm)) { 12618c2ecf20Sopenharmony_ci if (iwl_mvm_is_cdb_supported(mvm)) 12628c2ecf20Sopenharmony_ci flags |= (iwl_mvm_is_scan_fragmented(hb_type)) ? 12638c2ecf20Sopenharmony_ci SCAN_CONFIG_FLAG_SET_LMAC2_FRAGMENTED : 12648c2ecf20Sopenharmony_ci SCAN_CONFIG_FLAG_CLEAR_LMAC2_FRAGMENTED; 12658c2ecf20Sopenharmony_ci iwl_mvm_fill_scan_config_v2(mvm, cfg, flags, channel_flags, 12668c2ecf20Sopenharmony_ci num_channels); 12678c2ecf20Sopenharmony_ci } else { 12688c2ecf20Sopenharmony_ci iwl_mvm_fill_scan_config_v1(mvm, cfg, flags, channel_flags, 12698c2ecf20Sopenharmony_ci num_channels); 12708c2ecf20Sopenharmony_ci } 12718c2ecf20Sopenharmony_ci 12728c2ecf20Sopenharmony_ci cmd.data[0] = cfg; 12738c2ecf20Sopenharmony_ci cmd.len[0] = cmd_size; 12748c2ecf20Sopenharmony_ci cmd.dataflags[0] = IWL_HCMD_DFL_NOCOPY; 12758c2ecf20Sopenharmony_ci 12768c2ecf20Sopenharmony_ci IWL_DEBUG_SCAN(mvm, "Sending UMAC scan config\n"); 12778c2ecf20Sopenharmony_ci 12788c2ecf20Sopenharmony_ci ret = iwl_mvm_send_cmd(mvm, &cmd); 12798c2ecf20Sopenharmony_ci if (!ret) { 12808c2ecf20Sopenharmony_ci mvm->scan_type = type; 12818c2ecf20Sopenharmony_ci mvm->hb_scan_type = hb_type; 12828c2ecf20Sopenharmony_ci } 12838c2ecf20Sopenharmony_ci 12848c2ecf20Sopenharmony_ci kfree(cfg); 12858c2ecf20Sopenharmony_ci return ret; 12868c2ecf20Sopenharmony_ci} 12878c2ecf20Sopenharmony_ci 12888c2ecf20Sopenharmony_ciint iwl_mvm_config_scan(struct iwl_mvm *mvm) 12898c2ecf20Sopenharmony_ci{ 12908c2ecf20Sopenharmony_ci struct iwl_scan_config cfg; 12918c2ecf20Sopenharmony_ci struct iwl_host_cmd cmd = { 12928c2ecf20Sopenharmony_ci .id = iwl_cmd_id(SCAN_CFG_CMD, IWL_ALWAYS_LONG_GROUP, 0), 12938c2ecf20Sopenharmony_ci .len[0] = sizeof(cfg), 12948c2ecf20Sopenharmony_ci .data[0] = &cfg, 12958c2ecf20Sopenharmony_ci .dataflags[0] = IWL_HCMD_DFL_NOCOPY, 12968c2ecf20Sopenharmony_ci }; 12978c2ecf20Sopenharmony_ci 12988c2ecf20Sopenharmony_ci if (!iwl_mvm_is_reduced_config_scan_supported(mvm)) 12998c2ecf20Sopenharmony_ci return iwl_mvm_legacy_config_scan(mvm); 13008c2ecf20Sopenharmony_ci 13018c2ecf20Sopenharmony_ci memset(&cfg, 0, sizeof(cfg)); 13028c2ecf20Sopenharmony_ci 13038c2ecf20Sopenharmony_ci if (iwl_fw_lookup_cmd_ver(mvm->fw, LONG_GROUP, 13048c2ecf20Sopenharmony_ci ADD_STA, 0) < 12) 13058c2ecf20Sopenharmony_ci cfg.bcast_sta_id = mvm->aux_sta.sta_id; 13068c2ecf20Sopenharmony_ci /* 13078c2ecf20Sopenharmony_ci * Fw doesn't use this sta anymore, pending deprecation via HOST API 13088c2ecf20Sopenharmony_ci * change. 13098c2ecf20Sopenharmony_ci */ 13108c2ecf20Sopenharmony_ci else 13118c2ecf20Sopenharmony_ci cfg.bcast_sta_id = 0xff; 13128c2ecf20Sopenharmony_ci 13138c2ecf20Sopenharmony_ci cfg.tx_chains = cpu_to_le32(iwl_mvm_get_valid_tx_ant(mvm)); 13148c2ecf20Sopenharmony_ci cfg.rx_chains = cpu_to_le32(iwl_mvm_scan_rx_ant(mvm)); 13158c2ecf20Sopenharmony_ci 13168c2ecf20Sopenharmony_ci IWL_DEBUG_SCAN(mvm, "Sending UMAC scan config\n"); 13178c2ecf20Sopenharmony_ci 13188c2ecf20Sopenharmony_ci return iwl_mvm_send_cmd(mvm, &cmd); 13198c2ecf20Sopenharmony_ci} 13208c2ecf20Sopenharmony_ci 13218c2ecf20Sopenharmony_cistatic int iwl_mvm_scan_uid_by_status(struct iwl_mvm *mvm, int status) 13228c2ecf20Sopenharmony_ci{ 13238c2ecf20Sopenharmony_ci int i; 13248c2ecf20Sopenharmony_ci 13258c2ecf20Sopenharmony_ci for (i = 0; i < mvm->max_scans; i++) 13268c2ecf20Sopenharmony_ci if (mvm->scan_uid_status[i] == status) 13278c2ecf20Sopenharmony_ci return i; 13288c2ecf20Sopenharmony_ci 13298c2ecf20Sopenharmony_ci return -ENOENT; 13308c2ecf20Sopenharmony_ci} 13318c2ecf20Sopenharmony_ci 13328c2ecf20Sopenharmony_cistatic void iwl_mvm_scan_umac_dwell(struct iwl_mvm *mvm, 13338c2ecf20Sopenharmony_ci struct iwl_scan_req_umac *cmd, 13348c2ecf20Sopenharmony_ci struct iwl_mvm_scan_params *params) 13358c2ecf20Sopenharmony_ci{ 13368c2ecf20Sopenharmony_ci struct iwl_mvm_scan_timing_params *timing, *hb_timing; 13378c2ecf20Sopenharmony_ci u8 active_dwell, passive_dwell; 13388c2ecf20Sopenharmony_ci 13398c2ecf20Sopenharmony_ci timing = &scan_timing[params->type]; 13408c2ecf20Sopenharmony_ci active_dwell = IWL_SCAN_DWELL_ACTIVE; 13418c2ecf20Sopenharmony_ci passive_dwell = IWL_SCAN_DWELL_PASSIVE; 13428c2ecf20Sopenharmony_ci 13438c2ecf20Sopenharmony_ci if (iwl_mvm_is_adaptive_dwell_supported(mvm)) { 13448c2ecf20Sopenharmony_ci cmd->v7.adwell_default_n_aps_social = 13458c2ecf20Sopenharmony_ci IWL_SCAN_ADWELL_DEFAULT_N_APS_SOCIAL; 13468c2ecf20Sopenharmony_ci cmd->v7.adwell_default_n_aps = 13478c2ecf20Sopenharmony_ci IWL_SCAN_ADWELL_DEFAULT_LB_N_APS; 13488c2ecf20Sopenharmony_ci 13498c2ecf20Sopenharmony_ci if (iwl_mvm_is_adwell_hb_ap_num_supported(mvm)) 13508c2ecf20Sopenharmony_ci cmd->v9.adwell_default_hb_n_aps = 13518c2ecf20Sopenharmony_ci IWL_SCAN_ADWELL_DEFAULT_HB_N_APS; 13528c2ecf20Sopenharmony_ci 13538c2ecf20Sopenharmony_ci /* if custom max budget was configured with debugfs */ 13548c2ecf20Sopenharmony_ci if (IWL_MVM_ADWELL_MAX_BUDGET) 13558c2ecf20Sopenharmony_ci cmd->v7.adwell_max_budget = 13568c2ecf20Sopenharmony_ci cpu_to_le16(IWL_MVM_ADWELL_MAX_BUDGET); 13578c2ecf20Sopenharmony_ci else if (params->ssids && params->ssids[0].ssid_len) 13588c2ecf20Sopenharmony_ci cmd->v7.adwell_max_budget = 13598c2ecf20Sopenharmony_ci cpu_to_le16(IWL_SCAN_ADWELL_MAX_BUDGET_DIRECTED_SCAN); 13608c2ecf20Sopenharmony_ci else 13618c2ecf20Sopenharmony_ci cmd->v7.adwell_max_budget = 13628c2ecf20Sopenharmony_ci cpu_to_le16(IWL_SCAN_ADWELL_MAX_BUDGET_FULL_SCAN); 13638c2ecf20Sopenharmony_ci 13648c2ecf20Sopenharmony_ci cmd->v7.scan_priority = cpu_to_le32(IWL_SCAN_PRIORITY_EXT_6); 13658c2ecf20Sopenharmony_ci cmd->v7.max_out_time[SCAN_LB_LMAC_IDX] = 13668c2ecf20Sopenharmony_ci cpu_to_le32(timing->max_out_time); 13678c2ecf20Sopenharmony_ci cmd->v7.suspend_time[SCAN_LB_LMAC_IDX] = 13688c2ecf20Sopenharmony_ci cpu_to_le32(timing->suspend_time); 13698c2ecf20Sopenharmony_ci 13708c2ecf20Sopenharmony_ci if (iwl_mvm_is_cdb_supported(mvm)) { 13718c2ecf20Sopenharmony_ci hb_timing = &scan_timing[params->hb_type]; 13728c2ecf20Sopenharmony_ci 13738c2ecf20Sopenharmony_ci cmd->v7.max_out_time[SCAN_HB_LMAC_IDX] = 13748c2ecf20Sopenharmony_ci cpu_to_le32(hb_timing->max_out_time); 13758c2ecf20Sopenharmony_ci cmd->v7.suspend_time[SCAN_HB_LMAC_IDX] = 13768c2ecf20Sopenharmony_ci cpu_to_le32(hb_timing->suspend_time); 13778c2ecf20Sopenharmony_ci } 13788c2ecf20Sopenharmony_ci 13798c2ecf20Sopenharmony_ci if (!iwl_mvm_is_adaptive_dwell_v2_supported(mvm)) { 13808c2ecf20Sopenharmony_ci cmd->v7.active_dwell = active_dwell; 13818c2ecf20Sopenharmony_ci cmd->v7.passive_dwell = passive_dwell; 13828c2ecf20Sopenharmony_ci cmd->v7.fragmented_dwell = IWL_SCAN_DWELL_FRAGMENTED; 13838c2ecf20Sopenharmony_ci } else { 13848c2ecf20Sopenharmony_ci cmd->v8.active_dwell[SCAN_LB_LMAC_IDX] = active_dwell; 13858c2ecf20Sopenharmony_ci cmd->v8.passive_dwell[SCAN_LB_LMAC_IDX] = passive_dwell; 13868c2ecf20Sopenharmony_ci if (iwl_mvm_is_cdb_supported(mvm)) { 13878c2ecf20Sopenharmony_ci cmd->v8.active_dwell[SCAN_HB_LMAC_IDX] = 13888c2ecf20Sopenharmony_ci active_dwell; 13898c2ecf20Sopenharmony_ci cmd->v8.passive_dwell[SCAN_HB_LMAC_IDX] = 13908c2ecf20Sopenharmony_ci passive_dwell; 13918c2ecf20Sopenharmony_ci } 13928c2ecf20Sopenharmony_ci } 13938c2ecf20Sopenharmony_ci } else { 13948c2ecf20Sopenharmony_ci cmd->v1.extended_dwell = IWL_SCAN_DWELL_EXTENDED; 13958c2ecf20Sopenharmony_ci cmd->v1.active_dwell = active_dwell; 13968c2ecf20Sopenharmony_ci cmd->v1.passive_dwell = passive_dwell; 13978c2ecf20Sopenharmony_ci cmd->v1.fragmented_dwell = IWL_SCAN_DWELL_FRAGMENTED; 13988c2ecf20Sopenharmony_ci 13998c2ecf20Sopenharmony_ci if (iwl_mvm_is_cdb_supported(mvm)) { 14008c2ecf20Sopenharmony_ci hb_timing = &scan_timing[params->hb_type]; 14018c2ecf20Sopenharmony_ci 14028c2ecf20Sopenharmony_ci cmd->v6.max_out_time[SCAN_HB_LMAC_IDX] = 14038c2ecf20Sopenharmony_ci cpu_to_le32(hb_timing->max_out_time); 14048c2ecf20Sopenharmony_ci cmd->v6.suspend_time[SCAN_HB_LMAC_IDX] = 14058c2ecf20Sopenharmony_ci cpu_to_le32(hb_timing->suspend_time); 14068c2ecf20Sopenharmony_ci } 14078c2ecf20Sopenharmony_ci 14088c2ecf20Sopenharmony_ci if (iwl_mvm_cdb_scan_api(mvm)) { 14098c2ecf20Sopenharmony_ci cmd->v6.scan_priority = 14108c2ecf20Sopenharmony_ci cpu_to_le32(IWL_SCAN_PRIORITY_EXT_6); 14118c2ecf20Sopenharmony_ci cmd->v6.max_out_time[SCAN_LB_LMAC_IDX] = 14128c2ecf20Sopenharmony_ci cpu_to_le32(timing->max_out_time); 14138c2ecf20Sopenharmony_ci cmd->v6.suspend_time[SCAN_LB_LMAC_IDX] = 14148c2ecf20Sopenharmony_ci cpu_to_le32(timing->suspend_time); 14158c2ecf20Sopenharmony_ci } else { 14168c2ecf20Sopenharmony_ci cmd->v1.scan_priority = 14178c2ecf20Sopenharmony_ci cpu_to_le32(IWL_SCAN_PRIORITY_EXT_6); 14188c2ecf20Sopenharmony_ci cmd->v1.max_out_time = 14198c2ecf20Sopenharmony_ci cpu_to_le32(timing->max_out_time); 14208c2ecf20Sopenharmony_ci cmd->v1.suspend_time = 14218c2ecf20Sopenharmony_ci cpu_to_le32(timing->suspend_time); 14228c2ecf20Sopenharmony_ci } 14238c2ecf20Sopenharmony_ci } 14248c2ecf20Sopenharmony_ci 14258c2ecf20Sopenharmony_ci if (iwl_mvm_is_regular_scan(params)) 14268c2ecf20Sopenharmony_ci cmd->ooc_priority = cpu_to_le32(IWL_SCAN_PRIORITY_EXT_6); 14278c2ecf20Sopenharmony_ci else 14288c2ecf20Sopenharmony_ci cmd->ooc_priority = cpu_to_le32(IWL_SCAN_PRIORITY_EXT_2); 14298c2ecf20Sopenharmony_ci} 14308c2ecf20Sopenharmony_ci 14318c2ecf20Sopenharmony_cistatic u32 iwl_mvm_scan_umac_ooc_priority(struct iwl_mvm_scan_params *params) 14328c2ecf20Sopenharmony_ci{ 14338c2ecf20Sopenharmony_ci return iwl_mvm_is_regular_scan(params) ? 14348c2ecf20Sopenharmony_ci IWL_SCAN_PRIORITY_EXT_6 : 14358c2ecf20Sopenharmony_ci IWL_SCAN_PRIORITY_EXT_2; 14368c2ecf20Sopenharmony_ci} 14378c2ecf20Sopenharmony_ci 14388c2ecf20Sopenharmony_cistatic void 14398c2ecf20Sopenharmony_ciiwl_mvm_scan_umac_dwell_v10(struct iwl_mvm *mvm, 14408c2ecf20Sopenharmony_ci struct iwl_scan_general_params_v10 *general_params, 14418c2ecf20Sopenharmony_ci struct iwl_mvm_scan_params *params) 14428c2ecf20Sopenharmony_ci{ 14438c2ecf20Sopenharmony_ci struct iwl_mvm_scan_timing_params *timing, *hb_timing; 14448c2ecf20Sopenharmony_ci u8 active_dwell, passive_dwell; 14458c2ecf20Sopenharmony_ci 14468c2ecf20Sopenharmony_ci timing = &scan_timing[params->type]; 14478c2ecf20Sopenharmony_ci active_dwell = IWL_SCAN_DWELL_ACTIVE; 14488c2ecf20Sopenharmony_ci passive_dwell = IWL_SCAN_DWELL_PASSIVE; 14498c2ecf20Sopenharmony_ci 14508c2ecf20Sopenharmony_ci general_params->adwell_default_social_chn = 14518c2ecf20Sopenharmony_ci IWL_SCAN_ADWELL_DEFAULT_N_APS_SOCIAL; 14528c2ecf20Sopenharmony_ci general_params->adwell_default_2g = IWL_SCAN_ADWELL_DEFAULT_LB_N_APS; 14538c2ecf20Sopenharmony_ci general_params->adwell_default_5g = IWL_SCAN_ADWELL_DEFAULT_HB_N_APS; 14548c2ecf20Sopenharmony_ci 14558c2ecf20Sopenharmony_ci /* if custom max budget was configured with debugfs */ 14568c2ecf20Sopenharmony_ci if (IWL_MVM_ADWELL_MAX_BUDGET) 14578c2ecf20Sopenharmony_ci general_params->adwell_max_budget = 14588c2ecf20Sopenharmony_ci cpu_to_le16(IWL_MVM_ADWELL_MAX_BUDGET); 14598c2ecf20Sopenharmony_ci else if (params->ssids && params->ssids[0].ssid_len) 14608c2ecf20Sopenharmony_ci general_params->adwell_max_budget = 14618c2ecf20Sopenharmony_ci cpu_to_le16(IWL_SCAN_ADWELL_MAX_BUDGET_DIRECTED_SCAN); 14628c2ecf20Sopenharmony_ci else 14638c2ecf20Sopenharmony_ci general_params->adwell_max_budget = 14648c2ecf20Sopenharmony_ci cpu_to_le16(IWL_SCAN_ADWELL_MAX_BUDGET_FULL_SCAN); 14658c2ecf20Sopenharmony_ci 14668c2ecf20Sopenharmony_ci general_params->scan_priority = cpu_to_le32(IWL_SCAN_PRIORITY_EXT_6); 14678c2ecf20Sopenharmony_ci general_params->max_out_of_time[SCAN_LB_LMAC_IDX] = 14688c2ecf20Sopenharmony_ci cpu_to_le32(timing->max_out_time); 14698c2ecf20Sopenharmony_ci general_params->suspend_time[SCAN_LB_LMAC_IDX] = 14708c2ecf20Sopenharmony_ci cpu_to_le32(timing->suspend_time); 14718c2ecf20Sopenharmony_ci 14728c2ecf20Sopenharmony_ci hb_timing = &scan_timing[params->hb_type]; 14738c2ecf20Sopenharmony_ci 14748c2ecf20Sopenharmony_ci general_params->max_out_of_time[SCAN_HB_LMAC_IDX] = 14758c2ecf20Sopenharmony_ci cpu_to_le32(hb_timing->max_out_time); 14768c2ecf20Sopenharmony_ci general_params->suspend_time[SCAN_HB_LMAC_IDX] = 14778c2ecf20Sopenharmony_ci cpu_to_le32(hb_timing->suspend_time); 14788c2ecf20Sopenharmony_ci 14798c2ecf20Sopenharmony_ci general_params->active_dwell[SCAN_LB_LMAC_IDX] = active_dwell; 14808c2ecf20Sopenharmony_ci general_params->passive_dwell[SCAN_LB_LMAC_IDX] = passive_dwell; 14818c2ecf20Sopenharmony_ci general_params->active_dwell[SCAN_HB_LMAC_IDX] = active_dwell; 14828c2ecf20Sopenharmony_ci general_params->passive_dwell[SCAN_HB_LMAC_IDX] = passive_dwell; 14838c2ecf20Sopenharmony_ci} 14848c2ecf20Sopenharmony_ci 14858c2ecf20Sopenharmony_cistruct iwl_mvm_scan_channel_segment { 14868c2ecf20Sopenharmony_ci u8 start_idx; 14878c2ecf20Sopenharmony_ci u8 end_idx; 14888c2ecf20Sopenharmony_ci u8 first_channel_id; 14898c2ecf20Sopenharmony_ci u8 last_channel_id; 14908c2ecf20Sopenharmony_ci u8 channel_spacing_shift; 14918c2ecf20Sopenharmony_ci u8 band; 14928c2ecf20Sopenharmony_ci}; 14938c2ecf20Sopenharmony_ci 14948c2ecf20Sopenharmony_cistatic const struct iwl_mvm_scan_channel_segment scan_channel_segments[] = { 14958c2ecf20Sopenharmony_ci { 14968c2ecf20Sopenharmony_ci .start_idx = 0, 14978c2ecf20Sopenharmony_ci .end_idx = 13, 14988c2ecf20Sopenharmony_ci .first_channel_id = 1, 14998c2ecf20Sopenharmony_ci .last_channel_id = 14, 15008c2ecf20Sopenharmony_ci .channel_spacing_shift = 0, 15018c2ecf20Sopenharmony_ci .band = PHY_BAND_24 15028c2ecf20Sopenharmony_ci }, 15038c2ecf20Sopenharmony_ci { 15048c2ecf20Sopenharmony_ci .start_idx = 14, 15058c2ecf20Sopenharmony_ci .end_idx = 41, 15068c2ecf20Sopenharmony_ci .first_channel_id = 36, 15078c2ecf20Sopenharmony_ci .last_channel_id = 144, 15088c2ecf20Sopenharmony_ci .channel_spacing_shift = 2, 15098c2ecf20Sopenharmony_ci .band = PHY_BAND_5 15108c2ecf20Sopenharmony_ci }, 15118c2ecf20Sopenharmony_ci { 15128c2ecf20Sopenharmony_ci .start_idx = 42, 15138c2ecf20Sopenharmony_ci .end_idx = 50, 15148c2ecf20Sopenharmony_ci .first_channel_id = 149, 15158c2ecf20Sopenharmony_ci .last_channel_id = 181, 15168c2ecf20Sopenharmony_ci .channel_spacing_shift = 2, 15178c2ecf20Sopenharmony_ci .band = PHY_BAND_5 15188c2ecf20Sopenharmony_ci }, 15198c2ecf20Sopenharmony_ci}; 15208c2ecf20Sopenharmony_ci 15218c2ecf20Sopenharmony_cistatic int iwl_mvm_scan_ch_and_band_to_idx(u8 channel_id, u8 band) 15228c2ecf20Sopenharmony_ci{ 15238c2ecf20Sopenharmony_ci int i, index; 15248c2ecf20Sopenharmony_ci 15258c2ecf20Sopenharmony_ci if (!channel_id) 15268c2ecf20Sopenharmony_ci return -EINVAL; 15278c2ecf20Sopenharmony_ci 15288c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(scan_channel_segments); i++) { 15298c2ecf20Sopenharmony_ci const struct iwl_mvm_scan_channel_segment *ch_segment = 15308c2ecf20Sopenharmony_ci &scan_channel_segments[i]; 15318c2ecf20Sopenharmony_ci u32 ch_offset; 15328c2ecf20Sopenharmony_ci 15338c2ecf20Sopenharmony_ci if (ch_segment->band != band || 15348c2ecf20Sopenharmony_ci ch_segment->first_channel_id > channel_id || 15358c2ecf20Sopenharmony_ci ch_segment->last_channel_id < channel_id) 15368c2ecf20Sopenharmony_ci continue; 15378c2ecf20Sopenharmony_ci 15388c2ecf20Sopenharmony_ci ch_offset = (channel_id - ch_segment->first_channel_id) >> 15398c2ecf20Sopenharmony_ci ch_segment->channel_spacing_shift; 15408c2ecf20Sopenharmony_ci 15418c2ecf20Sopenharmony_ci index = scan_channel_segments[i].start_idx + ch_offset; 15428c2ecf20Sopenharmony_ci if (index < IWL_SCAN_NUM_CHANNELS) 15438c2ecf20Sopenharmony_ci return index; 15448c2ecf20Sopenharmony_ci 15458c2ecf20Sopenharmony_ci break; 15468c2ecf20Sopenharmony_ci } 15478c2ecf20Sopenharmony_ci 15488c2ecf20Sopenharmony_ci return -EINVAL; 15498c2ecf20Sopenharmony_ci} 15508c2ecf20Sopenharmony_ci 15518c2ecf20Sopenharmony_cistatic const u8 p2p_go_friendly_chs[] = { 15528c2ecf20Sopenharmony_ci 36, 40, 44, 48, 149, 153, 157, 161, 165, 15538c2ecf20Sopenharmony_ci}; 15548c2ecf20Sopenharmony_ci 15558c2ecf20Sopenharmony_cistatic const u8 social_chs[] = { 15568c2ecf20Sopenharmony_ci 1, 6, 11 15578c2ecf20Sopenharmony_ci}; 15588c2ecf20Sopenharmony_ci 15598c2ecf20Sopenharmony_cistatic void iwl_mvm_scan_ch_add_n_aps_override(enum nl80211_iftype vif_type, 15608c2ecf20Sopenharmony_ci u8 ch_id, u8 band, u8 *ch_bitmap, 15618c2ecf20Sopenharmony_ci size_t bitmap_n_entries) 15628c2ecf20Sopenharmony_ci{ 15638c2ecf20Sopenharmony_ci int i; 15648c2ecf20Sopenharmony_ci 15658c2ecf20Sopenharmony_ci if (vif_type != NL80211_IFTYPE_P2P_DEVICE) 15668c2ecf20Sopenharmony_ci return; 15678c2ecf20Sopenharmony_ci 15688c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(p2p_go_friendly_chs); i++) { 15698c2ecf20Sopenharmony_ci if (p2p_go_friendly_chs[i] == ch_id) { 15708c2ecf20Sopenharmony_ci int ch_idx, bitmap_idx; 15718c2ecf20Sopenharmony_ci 15728c2ecf20Sopenharmony_ci ch_idx = iwl_mvm_scan_ch_and_band_to_idx(ch_id, band); 15738c2ecf20Sopenharmony_ci if (ch_idx < 0) 15748c2ecf20Sopenharmony_ci return; 15758c2ecf20Sopenharmony_ci 15768c2ecf20Sopenharmony_ci bitmap_idx = ch_idx / 8; 15778c2ecf20Sopenharmony_ci if (bitmap_idx >= bitmap_n_entries) 15788c2ecf20Sopenharmony_ci return; 15798c2ecf20Sopenharmony_ci 15808c2ecf20Sopenharmony_ci ch_idx = ch_idx % 8; 15818c2ecf20Sopenharmony_ci ch_bitmap[bitmap_idx] |= BIT(ch_idx); 15828c2ecf20Sopenharmony_ci 15838c2ecf20Sopenharmony_ci return; 15848c2ecf20Sopenharmony_ci } 15858c2ecf20Sopenharmony_ci } 15868c2ecf20Sopenharmony_ci} 15878c2ecf20Sopenharmony_ci 15888c2ecf20Sopenharmony_cistatic u32 iwl_mvm_scan_ch_n_aps_flag(enum nl80211_iftype vif_type, u8 ch_id) 15898c2ecf20Sopenharmony_ci{ 15908c2ecf20Sopenharmony_ci int i; 15918c2ecf20Sopenharmony_ci u32 flags = 0; 15928c2ecf20Sopenharmony_ci 15938c2ecf20Sopenharmony_ci if (vif_type != NL80211_IFTYPE_P2P_DEVICE) 15948c2ecf20Sopenharmony_ci goto out; 15958c2ecf20Sopenharmony_ci 15968c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(p2p_go_friendly_chs); i++) { 15978c2ecf20Sopenharmony_ci if (p2p_go_friendly_chs[i] == ch_id) { 15988c2ecf20Sopenharmony_ci flags |= IWL_SCAN_ADWELL_N_APS_GO_FRIENDLY_BIT; 15998c2ecf20Sopenharmony_ci break; 16008c2ecf20Sopenharmony_ci } 16018c2ecf20Sopenharmony_ci } 16028c2ecf20Sopenharmony_ci 16038c2ecf20Sopenharmony_ci if (flags) 16048c2ecf20Sopenharmony_ci goto out; 16058c2ecf20Sopenharmony_ci 16068c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(social_chs); i++) { 16078c2ecf20Sopenharmony_ci if (social_chs[i] == ch_id) { 16088c2ecf20Sopenharmony_ci flags |= IWL_SCAN_ADWELL_N_APS_SOCIAL_CHS_BIT; 16098c2ecf20Sopenharmony_ci break; 16108c2ecf20Sopenharmony_ci } 16118c2ecf20Sopenharmony_ci } 16128c2ecf20Sopenharmony_ci 16138c2ecf20Sopenharmony_ciout: 16148c2ecf20Sopenharmony_ci return flags; 16158c2ecf20Sopenharmony_ci} 16168c2ecf20Sopenharmony_ci 16178c2ecf20Sopenharmony_cistatic void 16188c2ecf20Sopenharmony_ciiwl_mvm_umac_scan_cfg_channels(struct iwl_mvm *mvm, 16198c2ecf20Sopenharmony_ci struct ieee80211_channel **channels, 16208c2ecf20Sopenharmony_ci int n_channels, u32 flags, 16218c2ecf20Sopenharmony_ci struct iwl_scan_channel_cfg_umac *channel_cfg) 16228c2ecf20Sopenharmony_ci{ 16238c2ecf20Sopenharmony_ci int i; 16248c2ecf20Sopenharmony_ci 16258c2ecf20Sopenharmony_ci for (i = 0; i < n_channels; i++) { 16268c2ecf20Sopenharmony_ci channel_cfg[i].flags = cpu_to_le32(flags); 16278c2ecf20Sopenharmony_ci channel_cfg[i].v1.channel_num = channels[i]->hw_value; 16288c2ecf20Sopenharmony_ci if (iwl_mvm_is_scan_ext_chan_supported(mvm)) { 16298c2ecf20Sopenharmony_ci enum nl80211_band band = channels[i]->band; 16308c2ecf20Sopenharmony_ci 16318c2ecf20Sopenharmony_ci channel_cfg[i].v2.band = 16328c2ecf20Sopenharmony_ci iwl_mvm_phy_band_from_nl80211(band); 16338c2ecf20Sopenharmony_ci channel_cfg[i].v2.iter_count = 1; 16348c2ecf20Sopenharmony_ci channel_cfg[i].v2.iter_interval = 0; 16358c2ecf20Sopenharmony_ci } else { 16368c2ecf20Sopenharmony_ci channel_cfg[i].v1.iter_count = 1; 16378c2ecf20Sopenharmony_ci channel_cfg[i].v1.iter_interval = 0; 16388c2ecf20Sopenharmony_ci } 16398c2ecf20Sopenharmony_ci } 16408c2ecf20Sopenharmony_ci} 16418c2ecf20Sopenharmony_ci 16428c2ecf20Sopenharmony_cistatic void 16438c2ecf20Sopenharmony_ciiwl_mvm_umac_scan_cfg_channels_v4(struct iwl_mvm *mvm, 16448c2ecf20Sopenharmony_ci struct ieee80211_channel **channels, 16458c2ecf20Sopenharmony_ci struct iwl_scan_channel_params_v4 *cp, 16468c2ecf20Sopenharmony_ci int n_channels, u32 flags, 16478c2ecf20Sopenharmony_ci enum nl80211_iftype vif_type) 16488c2ecf20Sopenharmony_ci{ 16498c2ecf20Sopenharmony_ci u8 *bitmap = cp->adwell_ch_override_bitmap; 16508c2ecf20Sopenharmony_ci size_t bitmap_n_entries = ARRAY_SIZE(cp->adwell_ch_override_bitmap); 16518c2ecf20Sopenharmony_ci int i; 16528c2ecf20Sopenharmony_ci 16538c2ecf20Sopenharmony_ci for (i = 0; i < n_channels; i++) { 16548c2ecf20Sopenharmony_ci enum nl80211_band band = channels[i]->band; 16558c2ecf20Sopenharmony_ci struct iwl_scan_channel_cfg_umac *cfg = 16568c2ecf20Sopenharmony_ci &cp->channel_config[i]; 16578c2ecf20Sopenharmony_ci 16588c2ecf20Sopenharmony_ci cfg->flags = cpu_to_le32(flags); 16598c2ecf20Sopenharmony_ci cfg->v2.channel_num = channels[i]->hw_value; 16608c2ecf20Sopenharmony_ci cfg->v2.band = iwl_mvm_phy_band_from_nl80211(band); 16618c2ecf20Sopenharmony_ci cfg->v2.iter_count = 1; 16628c2ecf20Sopenharmony_ci cfg->v2.iter_interval = 0; 16638c2ecf20Sopenharmony_ci 16648c2ecf20Sopenharmony_ci iwl_mvm_scan_ch_add_n_aps_override(vif_type, 16658c2ecf20Sopenharmony_ci cfg->v2.channel_num, 16668c2ecf20Sopenharmony_ci cfg->v2.band, bitmap, 16678c2ecf20Sopenharmony_ci bitmap_n_entries); 16688c2ecf20Sopenharmony_ci } 16698c2ecf20Sopenharmony_ci} 16708c2ecf20Sopenharmony_ci 16718c2ecf20Sopenharmony_cistatic void 16728c2ecf20Sopenharmony_ciiwl_mvm_umac_scan_cfg_channels_v6(struct iwl_mvm *mvm, 16738c2ecf20Sopenharmony_ci struct ieee80211_channel **channels, 16748c2ecf20Sopenharmony_ci struct iwl_scan_channel_params_v6 *cp, 16758c2ecf20Sopenharmony_ci int n_channels, u32 flags, 16768c2ecf20Sopenharmony_ci enum nl80211_iftype vif_type) 16778c2ecf20Sopenharmony_ci{ 16788c2ecf20Sopenharmony_ci int i; 16798c2ecf20Sopenharmony_ci 16808c2ecf20Sopenharmony_ci for (i = 0; i < n_channels; i++) { 16818c2ecf20Sopenharmony_ci enum nl80211_band band = channels[i]->band; 16828c2ecf20Sopenharmony_ci struct iwl_scan_channel_cfg_umac *cfg = &cp->channel_config[i]; 16838c2ecf20Sopenharmony_ci u32 n_aps_flag = 16848c2ecf20Sopenharmony_ci iwl_mvm_scan_ch_n_aps_flag(vif_type, 16858c2ecf20Sopenharmony_ci channels[i]->hw_value); 16868c2ecf20Sopenharmony_ci 16878c2ecf20Sopenharmony_ci cfg->flags = cpu_to_le32(flags | n_aps_flag); 16888c2ecf20Sopenharmony_ci cfg->v2.channel_num = channels[i]->hw_value; 16898c2ecf20Sopenharmony_ci cfg->v2.band = iwl_mvm_phy_band_from_nl80211(band); 16908c2ecf20Sopenharmony_ci cfg->v2.iter_count = 1; 16918c2ecf20Sopenharmony_ci cfg->v2.iter_interval = 0; 16928c2ecf20Sopenharmony_ci } 16938c2ecf20Sopenharmony_ci} 16948c2ecf20Sopenharmony_ci 16958c2ecf20Sopenharmony_cistatic u8 iwl_mvm_scan_umac_chan_flags_v2(struct iwl_mvm *mvm, 16968c2ecf20Sopenharmony_ci struct iwl_mvm_scan_params *params, 16978c2ecf20Sopenharmony_ci struct ieee80211_vif *vif) 16988c2ecf20Sopenharmony_ci{ 16998c2ecf20Sopenharmony_ci u8 flags = 0; 17008c2ecf20Sopenharmony_ci 17018c2ecf20Sopenharmony_ci flags |= IWL_SCAN_CHANNEL_FLAG_ENABLE_CHAN_ORDER; 17028c2ecf20Sopenharmony_ci 17038c2ecf20Sopenharmony_ci if (iwl_mvm_scan_use_ebs(mvm, vif)) 17048c2ecf20Sopenharmony_ci flags |= IWL_SCAN_CHANNEL_FLAG_EBS | 17058c2ecf20Sopenharmony_ci IWL_SCAN_CHANNEL_FLAG_EBS_ACCURATE | 17068c2ecf20Sopenharmony_ci IWL_SCAN_CHANNEL_FLAG_CACHE_ADD; 17078c2ecf20Sopenharmony_ci 17088c2ecf20Sopenharmony_ci /* set fragmented ebs for fragmented scan on HB channels */ 17098c2ecf20Sopenharmony_ci if ((!iwl_mvm_is_cdb_supported(mvm) && 17108c2ecf20Sopenharmony_ci iwl_mvm_is_scan_fragmented(params->type)) || 17118c2ecf20Sopenharmony_ci (iwl_mvm_is_cdb_supported(mvm) && 17128c2ecf20Sopenharmony_ci iwl_mvm_is_scan_fragmented(params->hb_type))) 17138c2ecf20Sopenharmony_ci flags |= IWL_SCAN_CHANNEL_FLAG_EBS_FRAG; 17148c2ecf20Sopenharmony_ci 17158c2ecf20Sopenharmony_ci return flags; 17168c2ecf20Sopenharmony_ci} 17178c2ecf20Sopenharmony_ci 17188c2ecf20Sopenharmony_cistatic u16 iwl_mvm_scan_umac_flags_v2(struct iwl_mvm *mvm, 17198c2ecf20Sopenharmony_ci struct iwl_mvm_scan_params *params, 17208c2ecf20Sopenharmony_ci struct ieee80211_vif *vif, 17218c2ecf20Sopenharmony_ci int type) 17228c2ecf20Sopenharmony_ci{ 17238c2ecf20Sopenharmony_ci u16 flags = 0; 17248c2ecf20Sopenharmony_ci 17258c2ecf20Sopenharmony_ci if (params->n_ssids == 0) 17268c2ecf20Sopenharmony_ci flags |= IWL_UMAC_SCAN_GEN_FLAGS_V2_FORCE_PASSIVE; 17278c2ecf20Sopenharmony_ci 17288c2ecf20Sopenharmony_ci if (iwl_mvm_is_scan_fragmented(params->type)) 17298c2ecf20Sopenharmony_ci flags |= IWL_UMAC_SCAN_GEN_FLAGS_V2_FRAGMENTED_LMAC1; 17308c2ecf20Sopenharmony_ci 17318c2ecf20Sopenharmony_ci if (iwl_mvm_is_scan_fragmented(params->hb_type)) 17328c2ecf20Sopenharmony_ci flags |= IWL_UMAC_SCAN_GEN_FLAGS_V2_FRAGMENTED_LMAC2; 17338c2ecf20Sopenharmony_ci 17348c2ecf20Sopenharmony_ci if (params->pass_all) 17358c2ecf20Sopenharmony_ci flags |= IWL_UMAC_SCAN_GEN_FLAGS_V2_PASS_ALL; 17368c2ecf20Sopenharmony_ci else 17378c2ecf20Sopenharmony_ci flags |= IWL_UMAC_SCAN_GEN_FLAGS_V2_MATCH; 17388c2ecf20Sopenharmony_ci 17398c2ecf20Sopenharmony_ci if (!iwl_mvm_is_regular_scan(params)) 17408c2ecf20Sopenharmony_ci flags |= IWL_UMAC_SCAN_GEN_FLAGS_V2_PERIODIC; 17418c2ecf20Sopenharmony_ci 17428c2ecf20Sopenharmony_ci if (params->iter_notif || 17438c2ecf20Sopenharmony_ci mvm->sched_scan_pass_all == SCHED_SCAN_PASS_ALL_ENABLED) 17448c2ecf20Sopenharmony_ci flags |= IWL_UMAC_SCAN_GEN_FLAGS_V2_NTFY_ITER_COMPLETE; 17458c2ecf20Sopenharmony_ci 17468c2ecf20Sopenharmony_ci if (IWL_MVM_ADWELL_ENABLE) 17478c2ecf20Sopenharmony_ci flags |= IWL_UMAC_SCAN_GEN_FLAGS_V2_ADAPTIVE_DWELL; 17488c2ecf20Sopenharmony_ci 17498c2ecf20Sopenharmony_ci if (type == IWL_MVM_SCAN_SCHED || type == IWL_MVM_SCAN_NETDETECT) 17508c2ecf20Sopenharmony_ci flags |= IWL_UMAC_SCAN_GEN_FLAGS_V2_PREEMPTIVE; 17518c2ecf20Sopenharmony_ci 17528c2ecf20Sopenharmony_ci return flags; 17538c2ecf20Sopenharmony_ci} 17548c2ecf20Sopenharmony_ci 17558c2ecf20Sopenharmony_cistatic u16 iwl_mvm_scan_umac_flags(struct iwl_mvm *mvm, 17568c2ecf20Sopenharmony_ci struct iwl_mvm_scan_params *params, 17578c2ecf20Sopenharmony_ci struct ieee80211_vif *vif) 17588c2ecf20Sopenharmony_ci{ 17598c2ecf20Sopenharmony_ci u16 flags = 0; 17608c2ecf20Sopenharmony_ci 17618c2ecf20Sopenharmony_ci if (params->n_ssids == 0) 17628c2ecf20Sopenharmony_ci flags = IWL_UMAC_SCAN_GEN_FLAGS_PASSIVE; 17638c2ecf20Sopenharmony_ci 17648c2ecf20Sopenharmony_ci if (params->n_ssids == 1 && params->ssids[0].ssid_len != 0) 17658c2ecf20Sopenharmony_ci flags |= IWL_UMAC_SCAN_GEN_FLAGS_PRE_CONNECT; 17668c2ecf20Sopenharmony_ci 17678c2ecf20Sopenharmony_ci if (iwl_mvm_is_scan_fragmented(params->type)) 17688c2ecf20Sopenharmony_ci flags |= IWL_UMAC_SCAN_GEN_FLAGS_FRAGMENTED; 17698c2ecf20Sopenharmony_ci 17708c2ecf20Sopenharmony_ci if (iwl_mvm_is_cdb_supported(mvm) && 17718c2ecf20Sopenharmony_ci iwl_mvm_is_scan_fragmented(params->hb_type)) 17728c2ecf20Sopenharmony_ci flags |= IWL_UMAC_SCAN_GEN_FLAGS_LMAC2_FRAGMENTED; 17738c2ecf20Sopenharmony_ci 17748c2ecf20Sopenharmony_ci if (iwl_mvm_rrm_scan_needed(mvm) && 17758c2ecf20Sopenharmony_ci fw_has_capa(&mvm->fw->ucode_capa, 17768c2ecf20Sopenharmony_ci IWL_UCODE_TLV_CAPA_WFA_TPC_REP_IE_SUPPORT)) 17778c2ecf20Sopenharmony_ci flags |= IWL_UMAC_SCAN_GEN_FLAGS_RRM_ENABLED; 17788c2ecf20Sopenharmony_ci 17798c2ecf20Sopenharmony_ci if (params->pass_all) 17808c2ecf20Sopenharmony_ci flags |= IWL_UMAC_SCAN_GEN_FLAGS_PASS_ALL; 17818c2ecf20Sopenharmony_ci else 17828c2ecf20Sopenharmony_ci flags |= IWL_UMAC_SCAN_GEN_FLAGS_MATCH; 17838c2ecf20Sopenharmony_ci 17848c2ecf20Sopenharmony_ci if (!iwl_mvm_is_regular_scan(params)) 17858c2ecf20Sopenharmony_ci flags |= IWL_UMAC_SCAN_GEN_FLAGS_PERIODIC; 17868c2ecf20Sopenharmony_ci 17878c2ecf20Sopenharmony_ci if (params->iter_notif) 17888c2ecf20Sopenharmony_ci flags |= IWL_UMAC_SCAN_GEN_FLAGS_ITER_COMPLETE; 17898c2ecf20Sopenharmony_ci 17908c2ecf20Sopenharmony_ci#ifdef CONFIG_IWLWIFI_DEBUGFS 17918c2ecf20Sopenharmony_ci if (mvm->scan_iter_notif_enabled) 17928c2ecf20Sopenharmony_ci flags |= IWL_UMAC_SCAN_GEN_FLAGS_ITER_COMPLETE; 17938c2ecf20Sopenharmony_ci#endif 17948c2ecf20Sopenharmony_ci 17958c2ecf20Sopenharmony_ci if (mvm->sched_scan_pass_all == SCHED_SCAN_PASS_ALL_ENABLED) 17968c2ecf20Sopenharmony_ci flags |= IWL_UMAC_SCAN_GEN_FLAGS_ITER_COMPLETE; 17978c2ecf20Sopenharmony_ci 17988c2ecf20Sopenharmony_ci if (iwl_mvm_is_adaptive_dwell_supported(mvm) && IWL_MVM_ADWELL_ENABLE) 17998c2ecf20Sopenharmony_ci flags |= IWL_UMAC_SCAN_GEN_FLAGS_ADAPTIVE_DWELL; 18008c2ecf20Sopenharmony_ci 18018c2ecf20Sopenharmony_ci /* 18028c2ecf20Sopenharmony_ci * Extended dwell is relevant only for low band to start with, as it is 18038c2ecf20Sopenharmony_ci * being used for social channles only (1, 6, 11), so we can check 18048c2ecf20Sopenharmony_ci * only scan type on low band also for CDB. 18058c2ecf20Sopenharmony_ci */ 18068c2ecf20Sopenharmony_ci if (iwl_mvm_is_regular_scan(params) && 18078c2ecf20Sopenharmony_ci vif->type != NL80211_IFTYPE_P2P_DEVICE && 18088c2ecf20Sopenharmony_ci !iwl_mvm_is_scan_fragmented(params->type) && 18098c2ecf20Sopenharmony_ci !iwl_mvm_is_adaptive_dwell_supported(mvm) && 18108c2ecf20Sopenharmony_ci !iwl_mvm_is_oce_supported(mvm)) 18118c2ecf20Sopenharmony_ci flags |= IWL_UMAC_SCAN_GEN_FLAGS_EXTENDED_DWELL; 18128c2ecf20Sopenharmony_ci 18138c2ecf20Sopenharmony_ci if (iwl_mvm_is_oce_supported(mvm)) { 18148c2ecf20Sopenharmony_ci if ((params->flags & 18158c2ecf20Sopenharmony_ci NL80211_SCAN_FLAG_OCE_PROBE_REQ_HIGH_TX_RATE)) 18168c2ecf20Sopenharmony_ci flags |= IWL_UMAC_SCAN_GEN_FLAGS_PROB_REQ_HIGH_TX_RATE; 18178c2ecf20Sopenharmony_ci /* Since IWL_UMAC_SCAN_GEN_FLAGS_EXTENDED_DWELL and 18188c2ecf20Sopenharmony_ci * NL80211_SCAN_FLAG_OCE_PROBE_REQ_DEFERRAL_SUPPRESSION shares 18198c2ecf20Sopenharmony_ci * the same bit, we need to make sure that we use this bit here 18208c2ecf20Sopenharmony_ci * only when IWL_UMAC_SCAN_GEN_FLAGS_EXTENDED_DWELL cannot be 18218c2ecf20Sopenharmony_ci * used. */ 18228c2ecf20Sopenharmony_ci if ((params->flags & 18238c2ecf20Sopenharmony_ci NL80211_SCAN_FLAG_OCE_PROBE_REQ_DEFERRAL_SUPPRESSION) && 18248c2ecf20Sopenharmony_ci !WARN_ON_ONCE(!iwl_mvm_is_adaptive_dwell_supported(mvm))) 18258c2ecf20Sopenharmony_ci flags |= IWL_UMAC_SCAN_GEN_FLAGS_PROB_REQ_DEFER_SUPP; 18268c2ecf20Sopenharmony_ci if ((params->flags & NL80211_SCAN_FLAG_FILS_MAX_CHANNEL_TIME)) 18278c2ecf20Sopenharmony_ci flags |= IWL_UMAC_SCAN_GEN_FLAGS_MAX_CHNL_TIME; 18288c2ecf20Sopenharmony_ci } 18298c2ecf20Sopenharmony_ci 18308c2ecf20Sopenharmony_ci return flags; 18318c2ecf20Sopenharmony_ci} 18328c2ecf20Sopenharmony_ci 18338c2ecf20Sopenharmony_cistatic int 18348c2ecf20Sopenharmony_ciiwl_mvm_fill_scan_sched_params(struct iwl_mvm_scan_params *params, 18358c2ecf20Sopenharmony_ci struct iwl_scan_umac_schedule *schedule, 18368c2ecf20Sopenharmony_ci __le16 *delay) 18378c2ecf20Sopenharmony_ci{ 18388c2ecf20Sopenharmony_ci int i; 18398c2ecf20Sopenharmony_ci if (WARN_ON(!params->n_scan_plans || 18408c2ecf20Sopenharmony_ci params->n_scan_plans > IWL_MAX_SCHED_SCAN_PLANS)) 18418c2ecf20Sopenharmony_ci return -EINVAL; 18428c2ecf20Sopenharmony_ci 18438c2ecf20Sopenharmony_ci for (i = 0; i < params->n_scan_plans; i++) { 18448c2ecf20Sopenharmony_ci struct cfg80211_sched_scan_plan *scan_plan = 18458c2ecf20Sopenharmony_ci ¶ms->scan_plans[i]; 18468c2ecf20Sopenharmony_ci 18478c2ecf20Sopenharmony_ci schedule[i].iter_count = scan_plan->iterations; 18488c2ecf20Sopenharmony_ci schedule[i].interval = 18498c2ecf20Sopenharmony_ci cpu_to_le16(scan_plan->interval); 18508c2ecf20Sopenharmony_ci } 18518c2ecf20Sopenharmony_ci 18528c2ecf20Sopenharmony_ci /* 18538c2ecf20Sopenharmony_ci * If the number of iterations of the last scan plan is set to 18548c2ecf20Sopenharmony_ci * zero, it should run infinitely. However, this is not always the case. 18558c2ecf20Sopenharmony_ci * For example, when regular scan is requested the driver sets one scan 18568c2ecf20Sopenharmony_ci * plan with one iteration. 18578c2ecf20Sopenharmony_ci */ 18588c2ecf20Sopenharmony_ci if (!schedule[params->n_scan_plans - 1].iter_count) 18598c2ecf20Sopenharmony_ci schedule[params->n_scan_plans - 1].iter_count = 0xff; 18608c2ecf20Sopenharmony_ci 18618c2ecf20Sopenharmony_ci *delay = cpu_to_le16(params->delay); 18628c2ecf20Sopenharmony_ci 18638c2ecf20Sopenharmony_ci return 0; 18648c2ecf20Sopenharmony_ci} 18658c2ecf20Sopenharmony_ci 18668c2ecf20Sopenharmony_cistatic int iwl_mvm_scan_umac(struct iwl_mvm *mvm, struct ieee80211_vif *vif, 18678c2ecf20Sopenharmony_ci struct iwl_mvm_scan_params *params, 18688c2ecf20Sopenharmony_ci int type, int uid) 18698c2ecf20Sopenharmony_ci{ 18708c2ecf20Sopenharmony_ci struct iwl_scan_req_umac *cmd = mvm->scan_cmd; 18718c2ecf20Sopenharmony_ci struct iwl_scan_umac_chan_param *chan_param; 18728c2ecf20Sopenharmony_ci void *cmd_data = iwl_mvm_get_scan_req_umac_data(mvm); 18738c2ecf20Sopenharmony_ci void *sec_part = cmd_data + sizeof(struct iwl_scan_channel_cfg_umac) * 18748c2ecf20Sopenharmony_ci mvm->fw->ucode_capa.n_scan_channels; 18758c2ecf20Sopenharmony_ci struct iwl_scan_req_umac_tail_v2 *tail_v2 = 18768c2ecf20Sopenharmony_ci (struct iwl_scan_req_umac_tail_v2 *)sec_part; 18778c2ecf20Sopenharmony_ci struct iwl_scan_req_umac_tail_v1 *tail_v1; 18788c2ecf20Sopenharmony_ci struct iwl_ssid_ie *direct_scan; 18798c2ecf20Sopenharmony_ci int ret = 0; 18808c2ecf20Sopenharmony_ci u32 ssid_bitmap = 0; 18818c2ecf20Sopenharmony_ci u8 channel_flags = 0; 18828c2ecf20Sopenharmony_ci u16 gen_flags; 18838c2ecf20Sopenharmony_ci struct iwl_mvm_vif *scan_vif = iwl_mvm_vif_from_mac80211(vif); 18848c2ecf20Sopenharmony_ci 18858c2ecf20Sopenharmony_ci chan_param = iwl_mvm_get_scan_req_umac_channel(mvm); 18868c2ecf20Sopenharmony_ci 18878c2ecf20Sopenharmony_ci iwl_mvm_scan_umac_dwell(mvm, cmd, params); 18888c2ecf20Sopenharmony_ci 18898c2ecf20Sopenharmony_ci mvm->scan_uid_status[uid] = type; 18908c2ecf20Sopenharmony_ci 18918c2ecf20Sopenharmony_ci cmd->uid = cpu_to_le32(uid); 18928c2ecf20Sopenharmony_ci gen_flags = iwl_mvm_scan_umac_flags(mvm, params, vif); 18938c2ecf20Sopenharmony_ci cmd->general_flags = cpu_to_le16(gen_flags); 18948c2ecf20Sopenharmony_ci if (iwl_mvm_is_adaptive_dwell_v2_supported(mvm)) { 18958c2ecf20Sopenharmony_ci if (gen_flags & IWL_UMAC_SCAN_GEN_FLAGS_FRAGMENTED) 18968c2ecf20Sopenharmony_ci cmd->v8.num_of_fragments[SCAN_LB_LMAC_IDX] = 18978c2ecf20Sopenharmony_ci IWL_SCAN_NUM_OF_FRAGS; 18988c2ecf20Sopenharmony_ci if (gen_flags & IWL_UMAC_SCAN_GEN_FLAGS_LMAC2_FRAGMENTED) 18998c2ecf20Sopenharmony_ci cmd->v8.num_of_fragments[SCAN_HB_LMAC_IDX] = 19008c2ecf20Sopenharmony_ci IWL_SCAN_NUM_OF_FRAGS; 19018c2ecf20Sopenharmony_ci 19028c2ecf20Sopenharmony_ci cmd->v8.general_flags2 = 19038c2ecf20Sopenharmony_ci IWL_UMAC_SCAN_GEN_FLAGS2_ALLOW_CHNL_REORDER; 19048c2ecf20Sopenharmony_ci } 19058c2ecf20Sopenharmony_ci 19068c2ecf20Sopenharmony_ci cmd->scan_start_mac_id = scan_vif->id; 19078c2ecf20Sopenharmony_ci 19088c2ecf20Sopenharmony_ci if (type == IWL_MVM_SCAN_SCHED || type == IWL_MVM_SCAN_NETDETECT) 19098c2ecf20Sopenharmony_ci cmd->flags = cpu_to_le32(IWL_UMAC_SCAN_FLAG_PREEMPTIVE); 19108c2ecf20Sopenharmony_ci 19118c2ecf20Sopenharmony_ci if (iwl_mvm_scan_use_ebs(mvm, vif)) { 19128c2ecf20Sopenharmony_ci channel_flags = IWL_SCAN_CHANNEL_FLAG_EBS | 19138c2ecf20Sopenharmony_ci IWL_SCAN_CHANNEL_FLAG_EBS_ACCURATE | 19148c2ecf20Sopenharmony_ci IWL_SCAN_CHANNEL_FLAG_CACHE_ADD; 19158c2ecf20Sopenharmony_ci 19168c2ecf20Sopenharmony_ci /* set fragmented ebs for fragmented scan on HB channels */ 19178c2ecf20Sopenharmony_ci if (iwl_mvm_is_frag_ebs_supported(mvm)) { 19188c2ecf20Sopenharmony_ci if (gen_flags & 19198c2ecf20Sopenharmony_ci IWL_UMAC_SCAN_GEN_FLAGS_LMAC2_FRAGMENTED || 19208c2ecf20Sopenharmony_ci (!iwl_mvm_is_cdb_supported(mvm) && 19218c2ecf20Sopenharmony_ci gen_flags & IWL_UMAC_SCAN_GEN_FLAGS_FRAGMENTED)) 19228c2ecf20Sopenharmony_ci channel_flags |= IWL_SCAN_CHANNEL_FLAG_EBS_FRAG; 19238c2ecf20Sopenharmony_ci } 19248c2ecf20Sopenharmony_ci } 19258c2ecf20Sopenharmony_ci 19268c2ecf20Sopenharmony_ci chan_param->flags = channel_flags; 19278c2ecf20Sopenharmony_ci chan_param->count = params->n_channels; 19288c2ecf20Sopenharmony_ci 19298c2ecf20Sopenharmony_ci ret = iwl_mvm_fill_scan_sched_params(params, tail_v2->schedule, 19308c2ecf20Sopenharmony_ci &tail_v2->delay); 19318c2ecf20Sopenharmony_ci if (ret) 19328c2ecf20Sopenharmony_ci return ret; 19338c2ecf20Sopenharmony_ci 19348c2ecf20Sopenharmony_ci if (iwl_mvm_is_scan_ext_chan_supported(mvm)) { 19358c2ecf20Sopenharmony_ci tail_v2->preq = params->preq; 19368c2ecf20Sopenharmony_ci direct_scan = tail_v2->direct_scan; 19378c2ecf20Sopenharmony_ci } else { 19388c2ecf20Sopenharmony_ci tail_v1 = (struct iwl_scan_req_umac_tail_v1 *)sec_part; 19398c2ecf20Sopenharmony_ci iwl_mvm_scan_set_legacy_probe_req(&tail_v1->preq, 19408c2ecf20Sopenharmony_ci ¶ms->preq); 19418c2ecf20Sopenharmony_ci direct_scan = tail_v1->direct_scan; 19428c2ecf20Sopenharmony_ci } 19438c2ecf20Sopenharmony_ci iwl_scan_build_ssids(params, direct_scan, &ssid_bitmap); 19448c2ecf20Sopenharmony_ci iwl_mvm_umac_scan_cfg_channels(mvm, params->channels, 19458c2ecf20Sopenharmony_ci params->n_channels, ssid_bitmap, 19468c2ecf20Sopenharmony_ci cmd_data); 19478c2ecf20Sopenharmony_ci return 0; 19488c2ecf20Sopenharmony_ci} 19498c2ecf20Sopenharmony_ci 19508c2ecf20Sopenharmony_cistatic void 19518c2ecf20Sopenharmony_ciiwl_mvm_scan_umac_fill_general_p_v10(struct iwl_mvm *mvm, 19528c2ecf20Sopenharmony_ci struct iwl_mvm_scan_params *params, 19538c2ecf20Sopenharmony_ci struct ieee80211_vif *vif, 19548c2ecf20Sopenharmony_ci struct iwl_scan_general_params_v10 *gp, 19558c2ecf20Sopenharmony_ci u16 gen_flags) 19568c2ecf20Sopenharmony_ci{ 19578c2ecf20Sopenharmony_ci struct iwl_mvm_vif *scan_vif = iwl_mvm_vif_from_mac80211(vif); 19588c2ecf20Sopenharmony_ci 19598c2ecf20Sopenharmony_ci iwl_mvm_scan_umac_dwell_v10(mvm, gp, params); 19608c2ecf20Sopenharmony_ci 19618c2ecf20Sopenharmony_ci gp->flags = cpu_to_le16(gen_flags); 19628c2ecf20Sopenharmony_ci 19638c2ecf20Sopenharmony_ci if (gen_flags & IWL_UMAC_SCAN_GEN_FLAGS_V2_FRAGMENTED_LMAC1) 19648c2ecf20Sopenharmony_ci gp->num_of_fragments[SCAN_LB_LMAC_IDX] = IWL_SCAN_NUM_OF_FRAGS; 19658c2ecf20Sopenharmony_ci if (gen_flags & IWL_UMAC_SCAN_GEN_FLAGS_V2_FRAGMENTED_LMAC2) 19668c2ecf20Sopenharmony_ci gp->num_of_fragments[SCAN_HB_LMAC_IDX] = IWL_SCAN_NUM_OF_FRAGS; 19678c2ecf20Sopenharmony_ci 19688c2ecf20Sopenharmony_ci gp->scan_start_mac_id = scan_vif->id; 19698c2ecf20Sopenharmony_ci} 19708c2ecf20Sopenharmony_ci 19718c2ecf20Sopenharmony_cistatic void 19728c2ecf20Sopenharmony_ciiwl_mvm_scan_umac_fill_probe_p_v3(struct iwl_mvm_scan_params *params, 19738c2ecf20Sopenharmony_ci struct iwl_scan_probe_params_v3 *pp) 19748c2ecf20Sopenharmony_ci{ 19758c2ecf20Sopenharmony_ci pp->preq = params->preq; 19768c2ecf20Sopenharmony_ci pp->ssid_num = params->n_ssids; 19778c2ecf20Sopenharmony_ci iwl_scan_build_ssids(params, pp->direct_scan, NULL); 19788c2ecf20Sopenharmony_ci} 19798c2ecf20Sopenharmony_ci 19808c2ecf20Sopenharmony_cistatic void 19818c2ecf20Sopenharmony_ciiwl_mvm_scan_umac_fill_probe_p_v4(struct iwl_mvm_scan_params *params, 19828c2ecf20Sopenharmony_ci struct iwl_scan_probe_params_v4 *pp, 19838c2ecf20Sopenharmony_ci u32 *bitmap_ssid) 19848c2ecf20Sopenharmony_ci{ 19858c2ecf20Sopenharmony_ci pp->preq = params->preq; 19868c2ecf20Sopenharmony_ci iwl_scan_build_ssids(params, pp->direct_scan, bitmap_ssid); 19878c2ecf20Sopenharmony_ci} 19888c2ecf20Sopenharmony_ci 19898c2ecf20Sopenharmony_cistatic void 19908c2ecf20Sopenharmony_ciiwl_mvm_scan_umac_fill_ch_p_v4(struct iwl_mvm *mvm, 19918c2ecf20Sopenharmony_ci struct iwl_mvm_scan_params *params, 19928c2ecf20Sopenharmony_ci struct ieee80211_vif *vif, 19938c2ecf20Sopenharmony_ci struct iwl_scan_channel_params_v4 *cp, 19948c2ecf20Sopenharmony_ci u32 channel_cfg_flags) 19958c2ecf20Sopenharmony_ci{ 19968c2ecf20Sopenharmony_ci cp->flags = iwl_mvm_scan_umac_chan_flags_v2(mvm, params, vif); 19978c2ecf20Sopenharmony_ci cp->count = params->n_channels; 19988c2ecf20Sopenharmony_ci cp->num_of_aps_override = IWL_SCAN_ADWELL_N_APS_GO_FRIENDLY; 19998c2ecf20Sopenharmony_ci 20008c2ecf20Sopenharmony_ci iwl_mvm_umac_scan_cfg_channels_v4(mvm, params->channels, cp, 20018c2ecf20Sopenharmony_ci params->n_channels, 20028c2ecf20Sopenharmony_ci channel_cfg_flags, 20038c2ecf20Sopenharmony_ci vif->type); 20048c2ecf20Sopenharmony_ci} 20058c2ecf20Sopenharmony_ci 20068c2ecf20Sopenharmony_cistatic void 20078c2ecf20Sopenharmony_ciiwl_mvm_scan_umac_fill_ch_p_v6(struct iwl_mvm *mvm, 20088c2ecf20Sopenharmony_ci struct iwl_mvm_scan_params *params, 20098c2ecf20Sopenharmony_ci struct ieee80211_vif *vif, 20108c2ecf20Sopenharmony_ci struct iwl_scan_channel_params_v6 *cp, 20118c2ecf20Sopenharmony_ci u32 channel_cfg_flags) 20128c2ecf20Sopenharmony_ci{ 20138c2ecf20Sopenharmony_ci cp->flags = iwl_mvm_scan_umac_chan_flags_v2(mvm, params, vif); 20148c2ecf20Sopenharmony_ci cp->count = params->n_channels; 20158c2ecf20Sopenharmony_ci cp->n_aps_override[0] = IWL_SCAN_ADWELL_N_APS_GO_FRIENDLY; 20168c2ecf20Sopenharmony_ci cp->n_aps_override[1] = IWL_SCAN_ADWELL_N_APS_SOCIAL_CHS; 20178c2ecf20Sopenharmony_ci 20188c2ecf20Sopenharmony_ci iwl_mvm_umac_scan_cfg_channels_v6(mvm, params->channels, cp, 20198c2ecf20Sopenharmony_ci params->n_channels, 20208c2ecf20Sopenharmony_ci channel_cfg_flags, 20218c2ecf20Sopenharmony_ci vif->type); 20228c2ecf20Sopenharmony_ci} 20238c2ecf20Sopenharmony_ci 20248c2ecf20Sopenharmony_cistatic int iwl_mvm_scan_umac_v12(struct iwl_mvm *mvm, struct ieee80211_vif *vif, 20258c2ecf20Sopenharmony_ci struct iwl_mvm_scan_params *params, int type, 20268c2ecf20Sopenharmony_ci int uid) 20278c2ecf20Sopenharmony_ci{ 20288c2ecf20Sopenharmony_ci struct iwl_scan_req_umac_v12 *cmd = mvm->scan_cmd; 20298c2ecf20Sopenharmony_ci struct iwl_scan_req_params_v12 *scan_p = &cmd->scan_params; 20308c2ecf20Sopenharmony_ci int ret; 20318c2ecf20Sopenharmony_ci u16 gen_flags; 20328c2ecf20Sopenharmony_ci 20338c2ecf20Sopenharmony_ci mvm->scan_uid_status[uid] = type; 20348c2ecf20Sopenharmony_ci 20358c2ecf20Sopenharmony_ci cmd->ooc_priority = cpu_to_le32(iwl_mvm_scan_umac_ooc_priority(params)); 20368c2ecf20Sopenharmony_ci cmd->uid = cpu_to_le32(uid); 20378c2ecf20Sopenharmony_ci 20388c2ecf20Sopenharmony_ci gen_flags = iwl_mvm_scan_umac_flags_v2(mvm, params, vif, type); 20398c2ecf20Sopenharmony_ci iwl_mvm_scan_umac_fill_general_p_v10(mvm, params, vif, 20408c2ecf20Sopenharmony_ci &scan_p->general_params, 20418c2ecf20Sopenharmony_ci gen_flags); 20428c2ecf20Sopenharmony_ci 20438c2ecf20Sopenharmony_ci ret = iwl_mvm_fill_scan_sched_params(params, 20448c2ecf20Sopenharmony_ci scan_p->periodic_params.schedule, 20458c2ecf20Sopenharmony_ci &scan_p->periodic_params.delay); 20468c2ecf20Sopenharmony_ci if (ret) 20478c2ecf20Sopenharmony_ci return ret; 20488c2ecf20Sopenharmony_ci 20498c2ecf20Sopenharmony_ci iwl_mvm_scan_umac_fill_probe_p_v3(params, &scan_p->probe_params); 20508c2ecf20Sopenharmony_ci iwl_mvm_scan_umac_fill_ch_p_v4(mvm, params, vif, 20518c2ecf20Sopenharmony_ci &scan_p->channel_params, 0); 20528c2ecf20Sopenharmony_ci 20538c2ecf20Sopenharmony_ci return 0; 20548c2ecf20Sopenharmony_ci} 20558c2ecf20Sopenharmony_ci 20568c2ecf20Sopenharmony_cistatic int iwl_mvm_scan_umac_v14(struct iwl_mvm *mvm, struct ieee80211_vif *vif, 20578c2ecf20Sopenharmony_ci struct iwl_mvm_scan_params *params, int type, 20588c2ecf20Sopenharmony_ci int uid) 20598c2ecf20Sopenharmony_ci{ 20608c2ecf20Sopenharmony_ci struct iwl_scan_req_umac_v14 *cmd = mvm->scan_cmd; 20618c2ecf20Sopenharmony_ci struct iwl_scan_req_params_v14 *scan_p = &cmd->scan_params; 20628c2ecf20Sopenharmony_ci int ret; 20638c2ecf20Sopenharmony_ci u16 gen_flags; 20648c2ecf20Sopenharmony_ci u32 bitmap_ssid = 0; 20658c2ecf20Sopenharmony_ci 20668c2ecf20Sopenharmony_ci mvm->scan_uid_status[uid] = type; 20678c2ecf20Sopenharmony_ci 20688c2ecf20Sopenharmony_ci cmd->ooc_priority = cpu_to_le32(iwl_mvm_scan_umac_ooc_priority(params)); 20698c2ecf20Sopenharmony_ci cmd->uid = cpu_to_le32(uid); 20708c2ecf20Sopenharmony_ci 20718c2ecf20Sopenharmony_ci gen_flags = iwl_mvm_scan_umac_flags_v2(mvm, params, vif, type); 20728c2ecf20Sopenharmony_ci iwl_mvm_scan_umac_fill_general_p_v10(mvm, params, vif, 20738c2ecf20Sopenharmony_ci &scan_p->general_params, 20748c2ecf20Sopenharmony_ci gen_flags); 20758c2ecf20Sopenharmony_ci 20768c2ecf20Sopenharmony_ci ret = iwl_mvm_fill_scan_sched_params(params, 20778c2ecf20Sopenharmony_ci scan_p->periodic_params.schedule, 20788c2ecf20Sopenharmony_ci &scan_p->periodic_params.delay); 20798c2ecf20Sopenharmony_ci if (ret) 20808c2ecf20Sopenharmony_ci return ret; 20818c2ecf20Sopenharmony_ci 20828c2ecf20Sopenharmony_ci iwl_mvm_scan_umac_fill_probe_p_v4(params, &scan_p->probe_params, 20838c2ecf20Sopenharmony_ci &bitmap_ssid); 20848c2ecf20Sopenharmony_ci iwl_mvm_scan_umac_fill_ch_p_v6(mvm, params, vif, 20858c2ecf20Sopenharmony_ci &scan_p->channel_params, bitmap_ssid); 20868c2ecf20Sopenharmony_ci 20878c2ecf20Sopenharmony_ci return 0; 20888c2ecf20Sopenharmony_ci} 20898c2ecf20Sopenharmony_ci 20908c2ecf20Sopenharmony_cistatic int iwl_mvm_num_scans(struct iwl_mvm *mvm) 20918c2ecf20Sopenharmony_ci{ 20928c2ecf20Sopenharmony_ci return hweight32(mvm->scan_status & IWL_MVM_SCAN_MASK); 20938c2ecf20Sopenharmony_ci} 20948c2ecf20Sopenharmony_ci 20958c2ecf20Sopenharmony_cistatic int iwl_mvm_check_running_scans(struct iwl_mvm *mvm, int type) 20968c2ecf20Sopenharmony_ci{ 20978c2ecf20Sopenharmony_ci bool unified_image = fw_has_capa(&mvm->fw->ucode_capa, 20988c2ecf20Sopenharmony_ci IWL_UCODE_TLV_CAPA_CNSLDTD_D3_D0_IMG); 20998c2ecf20Sopenharmony_ci 21008c2ecf20Sopenharmony_ci /* This looks a bit arbitrary, but the idea is that if we run 21018c2ecf20Sopenharmony_ci * out of possible simultaneous scans and the userspace is 21028c2ecf20Sopenharmony_ci * trying to run a scan type that is already running, we 21038c2ecf20Sopenharmony_ci * return -EBUSY. But if the userspace wants to start a 21048c2ecf20Sopenharmony_ci * different type of scan, we stop the opposite type to make 21058c2ecf20Sopenharmony_ci * space for the new request. The reason is backwards 21068c2ecf20Sopenharmony_ci * compatibility with old wpa_supplicant that wouldn't stop a 21078c2ecf20Sopenharmony_ci * scheduled scan before starting a normal scan. 21088c2ecf20Sopenharmony_ci */ 21098c2ecf20Sopenharmony_ci 21108c2ecf20Sopenharmony_ci /* FW supports only a single periodic scan */ 21118c2ecf20Sopenharmony_ci if ((type == IWL_MVM_SCAN_SCHED || type == IWL_MVM_SCAN_NETDETECT) && 21128c2ecf20Sopenharmony_ci mvm->scan_status & (IWL_MVM_SCAN_SCHED | IWL_MVM_SCAN_NETDETECT)) 21138c2ecf20Sopenharmony_ci return -EBUSY; 21148c2ecf20Sopenharmony_ci 21158c2ecf20Sopenharmony_ci if (iwl_mvm_num_scans(mvm) < mvm->max_scans) 21168c2ecf20Sopenharmony_ci return 0; 21178c2ecf20Sopenharmony_ci 21188c2ecf20Sopenharmony_ci /* Use a switch, even though this is a bitmask, so that more 21198c2ecf20Sopenharmony_ci * than one bits set will fall in default and we will warn. 21208c2ecf20Sopenharmony_ci */ 21218c2ecf20Sopenharmony_ci switch (type) { 21228c2ecf20Sopenharmony_ci case IWL_MVM_SCAN_REGULAR: 21238c2ecf20Sopenharmony_ci if (mvm->scan_status & IWL_MVM_SCAN_REGULAR_MASK) 21248c2ecf20Sopenharmony_ci return -EBUSY; 21258c2ecf20Sopenharmony_ci return iwl_mvm_scan_stop(mvm, IWL_MVM_SCAN_SCHED, true); 21268c2ecf20Sopenharmony_ci case IWL_MVM_SCAN_SCHED: 21278c2ecf20Sopenharmony_ci if (mvm->scan_status & IWL_MVM_SCAN_SCHED_MASK) 21288c2ecf20Sopenharmony_ci return -EBUSY; 21298c2ecf20Sopenharmony_ci return iwl_mvm_scan_stop(mvm, IWL_MVM_SCAN_REGULAR, true); 21308c2ecf20Sopenharmony_ci case IWL_MVM_SCAN_NETDETECT: 21318c2ecf20Sopenharmony_ci /* For non-unified images, there's no need to stop 21328c2ecf20Sopenharmony_ci * anything for net-detect since the firmware is 21338c2ecf20Sopenharmony_ci * restarted anyway. This way, any sched scans that 21348c2ecf20Sopenharmony_ci * were running will be restarted when we resume. 21358c2ecf20Sopenharmony_ci */ 21368c2ecf20Sopenharmony_ci if (!unified_image) 21378c2ecf20Sopenharmony_ci return 0; 21388c2ecf20Sopenharmony_ci 21398c2ecf20Sopenharmony_ci /* If this is a unified image and we ran out of scans, 21408c2ecf20Sopenharmony_ci * we need to stop something. Prefer stopping regular 21418c2ecf20Sopenharmony_ci * scans, because the results are useless at this 21428c2ecf20Sopenharmony_ci * point, and we should be able to keep running 21438c2ecf20Sopenharmony_ci * another scheduled scan while suspended. 21448c2ecf20Sopenharmony_ci */ 21458c2ecf20Sopenharmony_ci if (mvm->scan_status & IWL_MVM_SCAN_REGULAR_MASK) 21468c2ecf20Sopenharmony_ci return iwl_mvm_scan_stop(mvm, IWL_MVM_SCAN_REGULAR, 21478c2ecf20Sopenharmony_ci true); 21488c2ecf20Sopenharmony_ci if (mvm->scan_status & IWL_MVM_SCAN_SCHED_MASK) 21498c2ecf20Sopenharmony_ci return iwl_mvm_scan_stop(mvm, IWL_MVM_SCAN_SCHED, 21508c2ecf20Sopenharmony_ci true); 21518c2ecf20Sopenharmony_ci /* Something is wrong if no scan was running but we 21528c2ecf20Sopenharmony_ci * ran out of scans. 21538c2ecf20Sopenharmony_ci */ 21548c2ecf20Sopenharmony_ci /* fall through */ 21558c2ecf20Sopenharmony_ci default: 21568c2ecf20Sopenharmony_ci WARN_ON(1); 21578c2ecf20Sopenharmony_ci break; 21588c2ecf20Sopenharmony_ci } 21598c2ecf20Sopenharmony_ci 21608c2ecf20Sopenharmony_ci return -EIO; 21618c2ecf20Sopenharmony_ci} 21628c2ecf20Sopenharmony_ci 21638c2ecf20Sopenharmony_ci#define SCAN_TIMEOUT 30000 21648c2ecf20Sopenharmony_ci 21658c2ecf20Sopenharmony_civoid iwl_mvm_scan_timeout_wk(struct work_struct *work) 21668c2ecf20Sopenharmony_ci{ 21678c2ecf20Sopenharmony_ci struct delayed_work *delayed_work = to_delayed_work(work); 21688c2ecf20Sopenharmony_ci struct iwl_mvm *mvm = container_of(delayed_work, struct iwl_mvm, 21698c2ecf20Sopenharmony_ci scan_timeout_dwork); 21708c2ecf20Sopenharmony_ci 21718c2ecf20Sopenharmony_ci IWL_ERR(mvm, "regular scan timed out\n"); 21728c2ecf20Sopenharmony_ci 21738c2ecf20Sopenharmony_ci iwl_force_nmi(mvm->trans); 21748c2ecf20Sopenharmony_ci} 21758c2ecf20Sopenharmony_ci 21768c2ecf20Sopenharmony_cistatic void iwl_mvm_fill_scan_type(struct iwl_mvm *mvm, 21778c2ecf20Sopenharmony_ci struct iwl_mvm_scan_params *params, 21788c2ecf20Sopenharmony_ci struct ieee80211_vif *vif) 21798c2ecf20Sopenharmony_ci{ 21808c2ecf20Sopenharmony_ci if (iwl_mvm_is_cdb_supported(mvm)) { 21818c2ecf20Sopenharmony_ci params->type = 21828c2ecf20Sopenharmony_ci iwl_mvm_get_scan_type_band(mvm, vif, 21838c2ecf20Sopenharmony_ci NL80211_BAND_2GHZ); 21848c2ecf20Sopenharmony_ci params->hb_type = 21858c2ecf20Sopenharmony_ci iwl_mvm_get_scan_type_band(mvm, vif, 21868c2ecf20Sopenharmony_ci NL80211_BAND_5GHZ); 21878c2ecf20Sopenharmony_ci } else { 21888c2ecf20Sopenharmony_ci params->type = iwl_mvm_get_scan_type(mvm, vif); 21898c2ecf20Sopenharmony_ci } 21908c2ecf20Sopenharmony_ci} 21918c2ecf20Sopenharmony_ci 21928c2ecf20Sopenharmony_cistruct iwl_scan_umac_handler { 21938c2ecf20Sopenharmony_ci u8 version; 21948c2ecf20Sopenharmony_ci int (*handler)(struct iwl_mvm *mvm, struct ieee80211_vif *vif, 21958c2ecf20Sopenharmony_ci struct iwl_mvm_scan_params *params, int type, int uid); 21968c2ecf20Sopenharmony_ci}; 21978c2ecf20Sopenharmony_ci 21988c2ecf20Sopenharmony_ci#define IWL_SCAN_UMAC_HANDLER(_ver) { \ 21998c2ecf20Sopenharmony_ci .version = _ver, \ 22008c2ecf20Sopenharmony_ci .handler = iwl_mvm_scan_umac_v##_ver, \ 22018c2ecf20Sopenharmony_ci} 22028c2ecf20Sopenharmony_ci 22038c2ecf20Sopenharmony_cistatic const struct iwl_scan_umac_handler iwl_scan_umac_handlers[] = { 22048c2ecf20Sopenharmony_ci /* set the newest version first to shorten the list traverse time */ 22058c2ecf20Sopenharmony_ci IWL_SCAN_UMAC_HANDLER(14), 22068c2ecf20Sopenharmony_ci IWL_SCAN_UMAC_HANDLER(12), 22078c2ecf20Sopenharmony_ci}; 22088c2ecf20Sopenharmony_ci 22098c2ecf20Sopenharmony_cistatic int iwl_mvm_build_scan_cmd(struct iwl_mvm *mvm, 22108c2ecf20Sopenharmony_ci struct ieee80211_vif *vif, 22118c2ecf20Sopenharmony_ci struct iwl_host_cmd *hcmd, 22128c2ecf20Sopenharmony_ci struct iwl_mvm_scan_params *params, 22138c2ecf20Sopenharmony_ci int type) 22148c2ecf20Sopenharmony_ci{ 22158c2ecf20Sopenharmony_ci int uid, i; 22168c2ecf20Sopenharmony_ci u8 scan_ver; 22178c2ecf20Sopenharmony_ci 22188c2ecf20Sopenharmony_ci lockdep_assert_held(&mvm->mutex); 22198c2ecf20Sopenharmony_ci memset(mvm->scan_cmd, 0, ksize(mvm->scan_cmd)); 22208c2ecf20Sopenharmony_ci 22218c2ecf20Sopenharmony_ci if (!fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_UMAC_SCAN)) { 22228c2ecf20Sopenharmony_ci hcmd->id = SCAN_OFFLOAD_REQUEST_CMD; 22238c2ecf20Sopenharmony_ci 22248c2ecf20Sopenharmony_ci return iwl_mvm_scan_lmac(mvm, vif, params); 22258c2ecf20Sopenharmony_ci } 22268c2ecf20Sopenharmony_ci 22278c2ecf20Sopenharmony_ci uid = iwl_mvm_scan_uid_by_status(mvm, 0); 22288c2ecf20Sopenharmony_ci if (uid < 0) 22298c2ecf20Sopenharmony_ci return uid; 22308c2ecf20Sopenharmony_ci 22318c2ecf20Sopenharmony_ci hcmd->id = iwl_cmd_id(SCAN_REQ_UMAC, IWL_ALWAYS_LONG_GROUP, 0); 22328c2ecf20Sopenharmony_ci 22338c2ecf20Sopenharmony_ci scan_ver = iwl_fw_lookup_cmd_ver(mvm->fw, IWL_ALWAYS_LONG_GROUP, 22348c2ecf20Sopenharmony_ci SCAN_REQ_UMAC, 22358c2ecf20Sopenharmony_ci IWL_FW_CMD_VER_UNKNOWN); 22368c2ecf20Sopenharmony_ci 22378c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(iwl_scan_umac_handlers); i++) { 22388c2ecf20Sopenharmony_ci const struct iwl_scan_umac_handler *ver_handler = 22398c2ecf20Sopenharmony_ci &iwl_scan_umac_handlers[i]; 22408c2ecf20Sopenharmony_ci 22418c2ecf20Sopenharmony_ci if (ver_handler->version != scan_ver) 22428c2ecf20Sopenharmony_ci continue; 22438c2ecf20Sopenharmony_ci 22448c2ecf20Sopenharmony_ci return ver_handler->handler(mvm, vif, params, type, uid); 22458c2ecf20Sopenharmony_ci } 22468c2ecf20Sopenharmony_ci 22478c2ecf20Sopenharmony_ci return iwl_mvm_scan_umac(mvm, vif, params, type, uid); 22488c2ecf20Sopenharmony_ci} 22498c2ecf20Sopenharmony_ci 22508c2ecf20Sopenharmony_ciint iwl_mvm_reg_scan_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif, 22518c2ecf20Sopenharmony_ci struct cfg80211_scan_request *req, 22528c2ecf20Sopenharmony_ci struct ieee80211_scan_ies *ies) 22538c2ecf20Sopenharmony_ci{ 22548c2ecf20Sopenharmony_ci struct iwl_host_cmd hcmd = { 22558c2ecf20Sopenharmony_ci .len = { iwl_mvm_scan_size(mvm), }, 22568c2ecf20Sopenharmony_ci .data = { mvm->scan_cmd, }, 22578c2ecf20Sopenharmony_ci .dataflags = { IWL_HCMD_DFL_NOCOPY, }, 22588c2ecf20Sopenharmony_ci }; 22598c2ecf20Sopenharmony_ci struct iwl_mvm_scan_params params = {}; 22608c2ecf20Sopenharmony_ci int ret; 22618c2ecf20Sopenharmony_ci struct cfg80211_sched_scan_plan scan_plan = { .iterations = 1 }; 22628c2ecf20Sopenharmony_ci 22638c2ecf20Sopenharmony_ci lockdep_assert_held(&mvm->mutex); 22648c2ecf20Sopenharmony_ci 22658c2ecf20Sopenharmony_ci if (iwl_mvm_is_lar_supported(mvm) && !mvm->lar_regdom_set) { 22668c2ecf20Sopenharmony_ci IWL_ERR(mvm, "scan while LAR regdomain is not set\n"); 22678c2ecf20Sopenharmony_ci return -EBUSY; 22688c2ecf20Sopenharmony_ci } 22698c2ecf20Sopenharmony_ci 22708c2ecf20Sopenharmony_ci ret = iwl_mvm_check_running_scans(mvm, IWL_MVM_SCAN_REGULAR); 22718c2ecf20Sopenharmony_ci if (ret) 22728c2ecf20Sopenharmony_ci return ret; 22738c2ecf20Sopenharmony_ci 22748c2ecf20Sopenharmony_ci /* we should have failed registration if scan_cmd was NULL */ 22758c2ecf20Sopenharmony_ci if (WARN_ON(!mvm->scan_cmd)) 22768c2ecf20Sopenharmony_ci return -ENOMEM; 22778c2ecf20Sopenharmony_ci 22788c2ecf20Sopenharmony_ci if (!iwl_mvm_scan_fits(mvm, req->n_ssids, ies, req->n_channels)) 22798c2ecf20Sopenharmony_ci return -ENOBUFS; 22808c2ecf20Sopenharmony_ci 22818c2ecf20Sopenharmony_ci params.n_ssids = req->n_ssids; 22828c2ecf20Sopenharmony_ci params.flags = req->flags; 22838c2ecf20Sopenharmony_ci params.n_channels = req->n_channels; 22848c2ecf20Sopenharmony_ci params.delay = 0; 22858c2ecf20Sopenharmony_ci params.ssids = req->ssids; 22868c2ecf20Sopenharmony_ci params.channels = req->channels; 22878c2ecf20Sopenharmony_ci params.mac_addr = req->mac_addr; 22888c2ecf20Sopenharmony_ci params.mac_addr_mask = req->mac_addr_mask; 22898c2ecf20Sopenharmony_ci params.no_cck = req->no_cck; 22908c2ecf20Sopenharmony_ci params.pass_all = true; 22918c2ecf20Sopenharmony_ci params.n_match_sets = 0; 22928c2ecf20Sopenharmony_ci params.match_sets = NULL; 22938c2ecf20Sopenharmony_ci 22948c2ecf20Sopenharmony_ci params.scan_plans = &scan_plan; 22958c2ecf20Sopenharmony_ci params.n_scan_plans = 1; 22968c2ecf20Sopenharmony_ci 22978c2ecf20Sopenharmony_ci iwl_mvm_fill_scan_type(mvm, ¶ms, vif); 22988c2ecf20Sopenharmony_ci 22998c2ecf20Sopenharmony_ci if (req->duration) 23008c2ecf20Sopenharmony_ci params.iter_notif = true; 23018c2ecf20Sopenharmony_ci 23028c2ecf20Sopenharmony_ci iwl_mvm_build_scan_probe(mvm, vif, ies, ¶ms); 23038c2ecf20Sopenharmony_ci 23048c2ecf20Sopenharmony_ci ret = iwl_mvm_build_scan_cmd(mvm, vif, &hcmd, ¶ms, 23058c2ecf20Sopenharmony_ci IWL_MVM_SCAN_REGULAR); 23068c2ecf20Sopenharmony_ci 23078c2ecf20Sopenharmony_ci if (ret) 23088c2ecf20Sopenharmony_ci return ret; 23098c2ecf20Sopenharmony_ci 23108c2ecf20Sopenharmony_ci iwl_mvm_pause_tcm(mvm, false); 23118c2ecf20Sopenharmony_ci 23128c2ecf20Sopenharmony_ci ret = iwl_mvm_send_cmd(mvm, &hcmd); 23138c2ecf20Sopenharmony_ci if (ret) { 23148c2ecf20Sopenharmony_ci /* If the scan failed, it usually means that the FW was unable 23158c2ecf20Sopenharmony_ci * to allocate the time events. Warn on it, but maybe we 23168c2ecf20Sopenharmony_ci * should try to send the command again with different params. 23178c2ecf20Sopenharmony_ci */ 23188c2ecf20Sopenharmony_ci IWL_ERR(mvm, "Scan failed! ret %d\n", ret); 23198c2ecf20Sopenharmony_ci iwl_mvm_resume_tcm(mvm); 23208c2ecf20Sopenharmony_ci return ret; 23218c2ecf20Sopenharmony_ci } 23228c2ecf20Sopenharmony_ci 23238c2ecf20Sopenharmony_ci IWL_DEBUG_SCAN(mvm, "Scan request was sent successfully\n"); 23248c2ecf20Sopenharmony_ci mvm->scan_status |= IWL_MVM_SCAN_REGULAR; 23258c2ecf20Sopenharmony_ci mvm->scan_vif = iwl_mvm_vif_from_mac80211(vif); 23268c2ecf20Sopenharmony_ci 23278c2ecf20Sopenharmony_ci schedule_delayed_work(&mvm->scan_timeout_dwork, 23288c2ecf20Sopenharmony_ci msecs_to_jiffies(SCAN_TIMEOUT)); 23298c2ecf20Sopenharmony_ci 23308c2ecf20Sopenharmony_ci return 0; 23318c2ecf20Sopenharmony_ci} 23328c2ecf20Sopenharmony_ci 23338c2ecf20Sopenharmony_ciint iwl_mvm_sched_scan_start(struct iwl_mvm *mvm, 23348c2ecf20Sopenharmony_ci struct ieee80211_vif *vif, 23358c2ecf20Sopenharmony_ci struct cfg80211_sched_scan_request *req, 23368c2ecf20Sopenharmony_ci struct ieee80211_scan_ies *ies, 23378c2ecf20Sopenharmony_ci int type) 23388c2ecf20Sopenharmony_ci{ 23398c2ecf20Sopenharmony_ci struct iwl_host_cmd hcmd = { 23408c2ecf20Sopenharmony_ci .len = { iwl_mvm_scan_size(mvm), }, 23418c2ecf20Sopenharmony_ci .data = { mvm->scan_cmd, }, 23428c2ecf20Sopenharmony_ci .dataflags = { IWL_HCMD_DFL_NOCOPY, }, 23438c2ecf20Sopenharmony_ci }; 23448c2ecf20Sopenharmony_ci struct iwl_mvm_scan_params params = {}; 23458c2ecf20Sopenharmony_ci int ret; 23468c2ecf20Sopenharmony_ci 23478c2ecf20Sopenharmony_ci lockdep_assert_held(&mvm->mutex); 23488c2ecf20Sopenharmony_ci 23498c2ecf20Sopenharmony_ci if (iwl_mvm_is_lar_supported(mvm) && !mvm->lar_regdom_set) { 23508c2ecf20Sopenharmony_ci IWL_ERR(mvm, "sched-scan while LAR regdomain is not set\n"); 23518c2ecf20Sopenharmony_ci return -EBUSY; 23528c2ecf20Sopenharmony_ci } 23538c2ecf20Sopenharmony_ci 23548c2ecf20Sopenharmony_ci ret = iwl_mvm_check_running_scans(mvm, type); 23558c2ecf20Sopenharmony_ci if (ret) 23568c2ecf20Sopenharmony_ci return ret; 23578c2ecf20Sopenharmony_ci 23588c2ecf20Sopenharmony_ci /* we should have failed registration if scan_cmd was NULL */ 23598c2ecf20Sopenharmony_ci if (WARN_ON(!mvm->scan_cmd)) 23608c2ecf20Sopenharmony_ci return -ENOMEM; 23618c2ecf20Sopenharmony_ci 23628c2ecf20Sopenharmony_ci if (!iwl_mvm_scan_fits(mvm, req->n_ssids, ies, req->n_channels)) 23638c2ecf20Sopenharmony_ci return -ENOBUFS; 23648c2ecf20Sopenharmony_ci 23658c2ecf20Sopenharmony_ci params.n_ssids = req->n_ssids; 23668c2ecf20Sopenharmony_ci params.flags = req->flags; 23678c2ecf20Sopenharmony_ci params.n_channels = req->n_channels; 23688c2ecf20Sopenharmony_ci params.ssids = req->ssids; 23698c2ecf20Sopenharmony_ci params.channels = req->channels; 23708c2ecf20Sopenharmony_ci params.mac_addr = req->mac_addr; 23718c2ecf20Sopenharmony_ci params.mac_addr_mask = req->mac_addr_mask; 23728c2ecf20Sopenharmony_ci params.no_cck = false; 23738c2ecf20Sopenharmony_ci params.pass_all = iwl_mvm_scan_pass_all(mvm, req); 23748c2ecf20Sopenharmony_ci params.n_match_sets = req->n_match_sets; 23758c2ecf20Sopenharmony_ci params.match_sets = req->match_sets; 23768c2ecf20Sopenharmony_ci if (!req->n_scan_plans) 23778c2ecf20Sopenharmony_ci return -EINVAL; 23788c2ecf20Sopenharmony_ci 23798c2ecf20Sopenharmony_ci params.n_scan_plans = req->n_scan_plans; 23808c2ecf20Sopenharmony_ci params.scan_plans = req->scan_plans; 23818c2ecf20Sopenharmony_ci 23828c2ecf20Sopenharmony_ci iwl_mvm_fill_scan_type(mvm, ¶ms, vif); 23838c2ecf20Sopenharmony_ci 23848c2ecf20Sopenharmony_ci /* In theory, LMAC scans can handle a 32-bit delay, but since 23858c2ecf20Sopenharmony_ci * waiting for over 18 hours to start the scan is a bit silly 23868c2ecf20Sopenharmony_ci * and to keep it aligned with UMAC scans (which only support 23878c2ecf20Sopenharmony_ci * 16-bit delays), trim it down to 16-bits. 23888c2ecf20Sopenharmony_ci */ 23898c2ecf20Sopenharmony_ci if (req->delay > U16_MAX) { 23908c2ecf20Sopenharmony_ci IWL_DEBUG_SCAN(mvm, 23918c2ecf20Sopenharmony_ci "delay value is > 16-bits, set to max possible\n"); 23928c2ecf20Sopenharmony_ci params.delay = U16_MAX; 23938c2ecf20Sopenharmony_ci } else { 23948c2ecf20Sopenharmony_ci params.delay = req->delay; 23958c2ecf20Sopenharmony_ci } 23968c2ecf20Sopenharmony_ci 23978c2ecf20Sopenharmony_ci ret = iwl_mvm_config_sched_scan_profiles(mvm, req); 23988c2ecf20Sopenharmony_ci if (ret) 23998c2ecf20Sopenharmony_ci return ret; 24008c2ecf20Sopenharmony_ci 24018c2ecf20Sopenharmony_ci iwl_mvm_build_scan_probe(mvm, vif, ies, ¶ms); 24028c2ecf20Sopenharmony_ci 24038c2ecf20Sopenharmony_ci ret = iwl_mvm_build_scan_cmd(mvm, vif, &hcmd, ¶ms, type); 24048c2ecf20Sopenharmony_ci 24058c2ecf20Sopenharmony_ci if (ret) 24068c2ecf20Sopenharmony_ci return ret; 24078c2ecf20Sopenharmony_ci 24088c2ecf20Sopenharmony_ci ret = iwl_mvm_send_cmd(mvm, &hcmd); 24098c2ecf20Sopenharmony_ci if (!ret) { 24108c2ecf20Sopenharmony_ci IWL_DEBUG_SCAN(mvm, 24118c2ecf20Sopenharmony_ci "Sched scan request was sent successfully\n"); 24128c2ecf20Sopenharmony_ci mvm->scan_status |= type; 24138c2ecf20Sopenharmony_ci } else { 24148c2ecf20Sopenharmony_ci /* If the scan failed, it usually means that the FW was unable 24158c2ecf20Sopenharmony_ci * to allocate the time events. Warn on it, but maybe we 24168c2ecf20Sopenharmony_ci * should try to send the command again with different params. 24178c2ecf20Sopenharmony_ci */ 24188c2ecf20Sopenharmony_ci IWL_ERR(mvm, "Sched scan failed! ret %d\n", ret); 24198c2ecf20Sopenharmony_ci } 24208c2ecf20Sopenharmony_ci 24218c2ecf20Sopenharmony_ci return ret; 24228c2ecf20Sopenharmony_ci} 24238c2ecf20Sopenharmony_ci 24248c2ecf20Sopenharmony_civoid iwl_mvm_rx_umac_scan_complete_notif(struct iwl_mvm *mvm, 24258c2ecf20Sopenharmony_ci struct iwl_rx_cmd_buffer *rxb) 24268c2ecf20Sopenharmony_ci{ 24278c2ecf20Sopenharmony_ci struct iwl_rx_packet *pkt = rxb_addr(rxb); 24288c2ecf20Sopenharmony_ci struct iwl_umac_scan_complete *notif = (void *)pkt->data; 24298c2ecf20Sopenharmony_ci u32 uid = __le32_to_cpu(notif->uid); 24308c2ecf20Sopenharmony_ci bool aborted = (notif->status == IWL_SCAN_OFFLOAD_ABORTED); 24318c2ecf20Sopenharmony_ci 24328c2ecf20Sopenharmony_ci if (WARN_ON(!(mvm->scan_uid_status[uid] & mvm->scan_status))) 24338c2ecf20Sopenharmony_ci return; 24348c2ecf20Sopenharmony_ci 24358c2ecf20Sopenharmony_ci /* if the scan is already stopping, we don't need to notify mac80211 */ 24368c2ecf20Sopenharmony_ci if (mvm->scan_uid_status[uid] == IWL_MVM_SCAN_REGULAR) { 24378c2ecf20Sopenharmony_ci struct cfg80211_scan_info info = { 24388c2ecf20Sopenharmony_ci .aborted = aborted, 24398c2ecf20Sopenharmony_ci .scan_start_tsf = mvm->scan_start, 24408c2ecf20Sopenharmony_ci }; 24418c2ecf20Sopenharmony_ci 24428c2ecf20Sopenharmony_ci memcpy(info.tsf_bssid, mvm->scan_vif->bssid, ETH_ALEN); 24438c2ecf20Sopenharmony_ci ieee80211_scan_completed(mvm->hw, &info); 24448c2ecf20Sopenharmony_ci mvm->scan_vif = NULL; 24458c2ecf20Sopenharmony_ci cancel_delayed_work(&mvm->scan_timeout_dwork); 24468c2ecf20Sopenharmony_ci iwl_mvm_resume_tcm(mvm); 24478c2ecf20Sopenharmony_ci } else if (mvm->scan_uid_status[uid] == IWL_MVM_SCAN_SCHED) { 24488c2ecf20Sopenharmony_ci ieee80211_sched_scan_stopped(mvm->hw); 24498c2ecf20Sopenharmony_ci mvm->sched_scan_pass_all = SCHED_SCAN_PASS_ALL_DISABLED; 24508c2ecf20Sopenharmony_ci } 24518c2ecf20Sopenharmony_ci 24528c2ecf20Sopenharmony_ci mvm->scan_status &= ~mvm->scan_uid_status[uid]; 24538c2ecf20Sopenharmony_ci IWL_DEBUG_SCAN(mvm, 24548c2ecf20Sopenharmony_ci "Scan completed, uid %u type %u, status %s, EBS status %s\n", 24558c2ecf20Sopenharmony_ci uid, mvm->scan_uid_status[uid], 24568c2ecf20Sopenharmony_ci notif->status == IWL_SCAN_OFFLOAD_COMPLETED ? 24578c2ecf20Sopenharmony_ci "completed" : "aborted", 24588c2ecf20Sopenharmony_ci iwl_mvm_ebs_status_str(notif->ebs_status)); 24598c2ecf20Sopenharmony_ci IWL_DEBUG_SCAN(mvm, 24608c2ecf20Sopenharmony_ci "Last line %d, Last iteration %d, Time from last iteration %d\n", 24618c2ecf20Sopenharmony_ci notif->last_schedule, notif->last_iter, 24628c2ecf20Sopenharmony_ci __le32_to_cpu(notif->time_from_last_iter)); 24638c2ecf20Sopenharmony_ci 24648c2ecf20Sopenharmony_ci if (notif->ebs_status != IWL_SCAN_EBS_SUCCESS && 24658c2ecf20Sopenharmony_ci notif->ebs_status != IWL_SCAN_EBS_INACTIVE) 24668c2ecf20Sopenharmony_ci mvm->last_ebs_successful = false; 24678c2ecf20Sopenharmony_ci 24688c2ecf20Sopenharmony_ci mvm->scan_uid_status[uid] = 0; 24698c2ecf20Sopenharmony_ci} 24708c2ecf20Sopenharmony_ci 24718c2ecf20Sopenharmony_civoid iwl_mvm_rx_umac_scan_iter_complete_notif(struct iwl_mvm *mvm, 24728c2ecf20Sopenharmony_ci struct iwl_rx_cmd_buffer *rxb) 24738c2ecf20Sopenharmony_ci{ 24748c2ecf20Sopenharmony_ci struct iwl_rx_packet *pkt = rxb_addr(rxb); 24758c2ecf20Sopenharmony_ci struct iwl_umac_scan_iter_complete_notif *notif = (void *)pkt->data; 24768c2ecf20Sopenharmony_ci 24778c2ecf20Sopenharmony_ci mvm->scan_start = le64_to_cpu(notif->start_tsf); 24788c2ecf20Sopenharmony_ci 24798c2ecf20Sopenharmony_ci IWL_DEBUG_SCAN(mvm, 24808c2ecf20Sopenharmony_ci "UMAC Scan iteration complete: status=0x%x scanned_channels=%d\n", 24818c2ecf20Sopenharmony_ci notif->status, notif->scanned_channels); 24828c2ecf20Sopenharmony_ci 24838c2ecf20Sopenharmony_ci if (mvm->sched_scan_pass_all == SCHED_SCAN_PASS_ALL_FOUND) { 24848c2ecf20Sopenharmony_ci IWL_DEBUG_SCAN(mvm, "Pass all scheduled scan results found\n"); 24858c2ecf20Sopenharmony_ci ieee80211_sched_scan_results(mvm->hw); 24868c2ecf20Sopenharmony_ci mvm->sched_scan_pass_all = SCHED_SCAN_PASS_ALL_ENABLED; 24878c2ecf20Sopenharmony_ci } 24888c2ecf20Sopenharmony_ci 24898c2ecf20Sopenharmony_ci IWL_DEBUG_SCAN(mvm, 24908c2ecf20Sopenharmony_ci "UMAC Scan iteration complete: scan started at %llu (TSF)\n", 24918c2ecf20Sopenharmony_ci mvm->scan_start); 24928c2ecf20Sopenharmony_ci} 24938c2ecf20Sopenharmony_ci 24948c2ecf20Sopenharmony_cistatic int iwl_mvm_umac_scan_abort(struct iwl_mvm *mvm, int type) 24958c2ecf20Sopenharmony_ci{ 24968c2ecf20Sopenharmony_ci struct iwl_umac_scan_abort cmd = {}; 24978c2ecf20Sopenharmony_ci int uid, ret; 24988c2ecf20Sopenharmony_ci 24998c2ecf20Sopenharmony_ci lockdep_assert_held(&mvm->mutex); 25008c2ecf20Sopenharmony_ci 25018c2ecf20Sopenharmony_ci /* We should always get a valid index here, because we already 25028c2ecf20Sopenharmony_ci * checked that this type of scan was running in the generic 25038c2ecf20Sopenharmony_ci * code. 25048c2ecf20Sopenharmony_ci */ 25058c2ecf20Sopenharmony_ci uid = iwl_mvm_scan_uid_by_status(mvm, type); 25068c2ecf20Sopenharmony_ci if (WARN_ON_ONCE(uid < 0)) 25078c2ecf20Sopenharmony_ci return uid; 25088c2ecf20Sopenharmony_ci 25098c2ecf20Sopenharmony_ci cmd.uid = cpu_to_le32(uid); 25108c2ecf20Sopenharmony_ci 25118c2ecf20Sopenharmony_ci IWL_DEBUG_SCAN(mvm, "Sending scan abort, uid %u\n", uid); 25128c2ecf20Sopenharmony_ci 25138c2ecf20Sopenharmony_ci ret = iwl_mvm_send_cmd_pdu(mvm, 25148c2ecf20Sopenharmony_ci iwl_cmd_id(SCAN_ABORT_UMAC, 25158c2ecf20Sopenharmony_ci IWL_ALWAYS_LONG_GROUP, 0), 25168c2ecf20Sopenharmony_ci 0, sizeof(cmd), &cmd); 25178c2ecf20Sopenharmony_ci if (!ret) 25188c2ecf20Sopenharmony_ci mvm->scan_uid_status[uid] = type << IWL_MVM_SCAN_STOPPING_SHIFT; 25198c2ecf20Sopenharmony_ci 25208c2ecf20Sopenharmony_ci return ret; 25218c2ecf20Sopenharmony_ci} 25228c2ecf20Sopenharmony_ci 25238c2ecf20Sopenharmony_cistatic int iwl_mvm_scan_stop_wait(struct iwl_mvm *mvm, int type) 25248c2ecf20Sopenharmony_ci{ 25258c2ecf20Sopenharmony_ci struct iwl_notification_wait wait_scan_done; 25268c2ecf20Sopenharmony_ci static const u16 scan_done_notif[] = { SCAN_COMPLETE_UMAC, 25278c2ecf20Sopenharmony_ci SCAN_OFFLOAD_COMPLETE, }; 25288c2ecf20Sopenharmony_ci int ret; 25298c2ecf20Sopenharmony_ci 25308c2ecf20Sopenharmony_ci lockdep_assert_held(&mvm->mutex); 25318c2ecf20Sopenharmony_ci 25328c2ecf20Sopenharmony_ci iwl_init_notification_wait(&mvm->notif_wait, &wait_scan_done, 25338c2ecf20Sopenharmony_ci scan_done_notif, 25348c2ecf20Sopenharmony_ci ARRAY_SIZE(scan_done_notif), 25358c2ecf20Sopenharmony_ci NULL, NULL); 25368c2ecf20Sopenharmony_ci 25378c2ecf20Sopenharmony_ci IWL_DEBUG_SCAN(mvm, "Preparing to stop scan, type %x\n", type); 25388c2ecf20Sopenharmony_ci 25398c2ecf20Sopenharmony_ci if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_UMAC_SCAN)) 25408c2ecf20Sopenharmony_ci ret = iwl_mvm_umac_scan_abort(mvm, type); 25418c2ecf20Sopenharmony_ci else 25428c2ecf20Sopenharmony_ci ret = iwl_mvm_lmac_scan_abort(mvm); 25438c2ecf20Sopenharmony_ci 25448c2ecf20Sopenharmony_ci if (ret) { 25458c2ecf20Sopenharmony_ci IWL_DEBUG_SCAN(mvm, "couldn't stop scan type %d\n", type); 25468c2ecf20Sopenharmony_ci iwl_remove_notification(&mvm->notif_wait, &wait_scan_done); 25478c2ecf20Sopenharmony_ci return ret; 25488c2ecf20Sopenharmony_ci } 25498c2ecf20Sopenharmony_ci 25508c2ecf20Sopenharmony_ci return iwl_wait_notification(&mvm->notif_wait, &wait_scan_done, 25518c2ecf20Sopenharmony_ci 1 * HZ); 25528c2ecf20Sopenharmony_ci} 25538c2ecf20Sopenharmony_ci 25548c2ecf20Sopenharmony_ci#define IWL_SCAN_REQ_UMAC_HANDLE_SIZE(_ver) { \ 25558c2ecf20Sopenharmony_ci case (_ver): return sizeof(struct iwl_scan_req_umac_v##_ver); \ 25568c2ecf20Sopenharmony_ci} 25578c2ecf20Sopenharmony_ci 25588c2ecf20Sopenharmony_cistatic int iwl_scan_req_umac_get_size(u8 scan_ver) 25598c2ecf20Sopenharmony_ci{ 25608c2ecf20Sopenharmony_ci switch (scan_ver) { 25618c2ecf20Sopenharmony_ci IWL_SCAN_REQ_UMAC_HANDLE_SIZE(14); 25628c2ecf20Sopenharmony_ci IWL_SCAN_REQ_UMAC_HANDLE_SIZE(12); 25638c2ecf20Sopenharmony_ci } 25648c2ecf20Sopenharmony_ci 25658c2ecf20Sopenharmony_ci return 0; 25668c2ecf20Sopenharmony_ci} 25678c2ecf20Sopenharmony_ci 25688c2ecf20Sopenharmony_ciint iwl_mvm_scan_size(struct iwl_mvm *mvm) 25698c2ecf20Sopenharmony_ci{ 25708c2ecf20Sopenharmony_ci int base_size, tail_size; 25718c2ecf20Sopenharmony_ci u8 scan_ver = iwl_fw_lookup_cmd_ver(mvm->fw, IWL_ALWAYS_LONG_GROUP, 25728c2ecf20Sopenharmony_ci SCAN_REQ_UMAC, 25738c2ecf20Sopenharmony_ci IWL_FW_CMD_VER_UNKNOWN); 25748c2ecf20Sopenharmony_ci 25758c2ecf20Sopenharmony_ci base_size = iwl_scan_req_umac_get_size(scan_ver); 25768c2ecf20Sopenharmony_ci if (base_size) 25778c2ecf20Sopenharmony_ci return base_size; 25788c2ecf20Sopenharmony_ci 25798c2ecf20Sopenharmony_ci 25808c2ecf20Sopenharmony_ci if (iwl_mvm_is_adaptive_dwell_v2_supported(mvm)) 25818c2ecf20Sopenharmony_ci base_size = IWL_SCAN_REQ_UMAC_SIZE_V8; 25828c2ecf20Sopenharmony_ci else if (iwl_mvm_is_adaptive_dwell_supported(mvm)) 25838c2ecf20Sopenharmony_ci base_size = IWL_SCAN_REQ_UMAC_SIZE_V7; 25848c2ecf20Sopenharmony_ci else if (iwl_mvm_cdb_scan_api(mvm)) 25858c2ecf20Sopenharmony_ci base_size = IWL_SCAN_REQ_UMAC_SIZE_V6; 25868c2ecf20Sopenharmony_ci else 25878c2ecf20Sopenharmony_ci base_size = IWL_SCAN_REQ_UMAC_SIZE_V1; 25888c2ecf20Sopenharmony_ci 25898c2ecf20Sopenharmony_ci if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_UMAC_SCAN)) { 25908c2ecf20Sopenharmony_ci if (iwl_mvm_is_scan_ext_chan_supported(mvm)) 25918c2ecf20Sopenharmony_ci tail_size = sizeof(struct iwl_scan_req_umac_tail_v2); 25928c2ecf20Sopenharmony_ci else 25938c2ecf20Sopenharmony_ci tail_size = sizeof(struct iwl_scan_req_umac_tail_v1); 25948c2ecf20Sopenharmony_ci 25958c2ecf20Sopenharmony_ci return base_size + 25968c2ecf20Sopenharmony_ci sizeof(struct iwl_scan_channel_cfg_umac) * 25978c2ecf20Sopenharmony_ci mvm->fw->ucode_capa.n_scan_channels + 25988c2ecf20Sopenharmony_ci tail_size; 25998c2ecf20Sopenharmony_ci } 26008c2ecf20Sopenharmony_ci return sizeof(struct iwl_scan_req_lmac) + 26018c2ecf20Sopenharmony_ci sizeof(struct iwl_scan_channel_cfg_lmac) * 26028c2ecf20Sopenharmony_ci mvm->fw->ucode_capa.n_scan_channels + 26038c2ecf20Sopenharmony_ci sizeof(struct iwl_scan_probe_req_v1); 26048c2ecf20Sopenharmony_ci} 26058c2ecf20Sopenharmony_ci 26068c2ecf20Sopenharmony_ci/* 26078c2ecf20Sopenharmony_ci * This function is used in nic restart flow, to inform mac80211 about scans 26088c2ecf20Sopenharmony_ci * that was aborted by restart flow or by an assert. 26098c2ecf20Sopenharmony_ci */ 26108c2ecf20Sopenharmony_civoid iwl_mvm_report_scan_aborted(struct iwl_mvm *mvm) 26118c2ecf20Sopenharmony_ci{ 26128c2ecf20Sopenharmony_ci if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_UMAC_SCAN)) { 26138c2ecf20Sopenharmony_ci int uid, i; 26148c2ecf20Sopenharmony_ci 26158c2ecf20Sopenharmony_ci uid = iwl_mvm_scan_uid_by_status(mvm, IWL_MVM_SCAN_REGULAR); 26168c2ecf20Sopenharmony_ci if (uid >= 0) { 26178c2ecf20Sopenharmony_ci struct cfg80211_scan_info info = { 26188c2ecf20Sopenharmony_ci .aborted = true, 26198c2ecf20Sopenharmony_ci }; 26208c2ecf20Sopenharmony_ci 26218c2ecf20Sopenharmony_ci ieee80211_scan_completed(mvm->hw, &info); 26228c2ecf20Sopenharmony_ci mvm->scan_uid_status[uid] = 0; 26238c2ecf20Sopenharmony_ci } 26248c2ecf20Sopenharmony_ci uid = iwl_mvm_scan_uid_by_status(mvm, IWL_MVM_SCAN_SCHED); 26258c2ecf20Sopenharmony_ci if (uid >= 0 && !mvm->fw_restart) { 26268c2ecf20Sopenharmony_ci ieee80211_sched_scan_stopped(mvm->hw); 26278c2ecf20Sopenharmony_ci mvm->sched_scan_pass_all = SCHED_SCAN_PASS_ALL_DISABLED; 26288c2ecf20Sopenharmony_ci mvm->scan_uid_status[uid] = 0; 26298c2ecf20Sopenharmony_ci } 26308c2ecf20Sopenharmony_ci uid = iwl_mvm_scan_uid_by_status(mvm, 26318c2ecf20Sopenharmony_ci IWL_MVM_SCAN_STOPPING_REGULAR); 26328c2ecf20Sopenharmony_ci if (uid >= 0) 26338c2ecf20Sopenharmony_ci mvm->scan_uid_status[uid] = 0; 26348c2ecf20Sopenharmony_ci 26358c2ecf20Sopenharmony_ci uid = iwl_mvm_scan_uid_by_status(mvm, 26368c2ecf20Sopenharmony_ci IWL_MVM_SCAN_STOPPING_SCHED); 26378c2ecf20Sopenharmony_ci if (uid >= 0) 26388c2ecf20Sopenharmony_ci mvm->scan_uid_status[uid] = 0; 26398c2ecf20Sopenharmony_ci 26408c2ecf20Sopenharmony_ci /* We shouldn't have any UIDs still set. Loop over all the 26418c2ecf20Sopenharmony_ci * UIDs to make sure there's nothing left there and warn if 26428c2ecf20Sopenharmony_ci * any is found. 26438c2ecf20Sopenharmony_ci */ 26448c2ecf20Sopenharmony_ci for (i = 0; i < mvm->max_scans; i++) { 26458c2ecf20Sopenharmony_ci if (WARN_ONCE(mvm->scan_uid_status[i], 26468c2ecf20Sopenharmony_ci "UMAC scan UID %d status was not cleaned\n", 26478c2ecf20Sopenharmony_ci i)) 26488c2ecf20Sopenharmony_ci mvm->scan_uid_status[i] = 0; 26498c2ecf20Sopenharmony_ci } 26508c2ecf20Sopenharmony_ci } else { 26518c2ecf20Sopenharmony_ci if (mvm->scan_status & IWL_MVM_SCAN_REGULAR) { 26528c2ecf20Sopenharmony_ci struct cfg80211_scan_info info = { 26538c2ecf20Sopenharmony_ci .aborted = true, 26548c2ecf20Sopenharmony_ci }; 26558c2ecf20Sopenharmony_ci 26568c2ecf20Sopenharmony_ci ieee80211_scan_completed(mvm->hw, &info); 26578c2ecf20Sopenharmony_ci } 26588c2ecf20Sopenharmony_ci 26598c2ecf20Sopenharmony_ci /* Sched scan will be restarted by mac80211 in 26608c2ecf20Sopenharmony_ci * restart_hw, so do not report if FW is about to be 26618c2ecf20Sopenharmony_ci * restarted. 26628c2ecf20Sopenharmony_ci */ 26638c2ecf20Sopenharmony_ci if ((mvm->scan_status & IWL_MVM_SCAN_SCHED) && 26648c2ecf20Sopenharmony_ci !mvm->fw_restart) { 26658c2ecf20Sopenharmony_ci ieee80211_sched_scan_stopped(mvm->hw); 26668c2ecf20Sopenharmony_ci mvm->sched_scan_pass_all = SCHED_SCAN_PASS_ALL_DISABLED; 26678c2ecf20Sopenharmony_ci } 26688c2ecf20Sopenharmony_ci } 26698c2ecf20Sopenharmony_ci} 26708c2ecf20Sopenharmony_ci 26718c2ecf20Sopenharmony_ciint iwl_mvm_scan_stop(struct iwl_mvm *mvm, int type, bool notify) 26728c2ecf20Sopenharmony_ci{ 26738c2ecf20Sopenharmony_ci int ret; 26748c2ecf20Sopenharmony_ci 26758c2ecf20Sopenharmony_ci if (!(mvm->scan_status & type)) 26768c2ecf20Sopenharmony_ci return 0; 26778c2ecf20Sopenharmony_ci 26788c2ecf20Sopenharmony_ci if (iwl_mvm_is_radio_killed(mvm)) { 26798c2ecf20Sopenharmony_ci ret = 0; 26808c2ecf20Sopenharmony_ci goto out; 26818c2ecf20Sopenharmony_ci } 26828c2ecf20Sopenharmony_ci 26838c2ecf20Sopenharmony_ci ret = iwl_mvm_scan_stop_wait(mvm, type); 26848c2ecf20Sopenharmony_ci if (!ret) 26858c2ecf20Sopenharmony_ci mvm->scan_status |= type << IWL_MVM_SCAN_STOPPING_SHIFT; 26868c2ecf20Sopenharmony_ciout: 26878c2ecf20Sopenharmony_ci /* Clear the scan status so the next scan requests will 26888c2ecf20Sopenharmony_ci * succeed and mark the scan as stopping, so that the Rx 26898c2ecf20Sopenharmony_ci * handler doesn't do anything, as the scan was stopped from 26908c2ecf20Sopenharmony_ci * above. 26918c2ecf20Sopenharmony_ci */ 26928c2ecf20Sopenharmony_ci mvm->scan_status &= ~type; 26938c2ecf20Sopenharmony_ci 26948c2ecf20Sopenharmony_ci if (type == IWL_MVM_SCAN_REGULAR) { 26958c2ecf20Sopenharmony_ci cancel_delayed_work(&mvm->scan_timeout_dwork); 26968c2ecf20Sopenharmony_ci if (notify) { 26978c2ecf20Sopenharmony_ci struct cfg80211_scan_info info = { 26988c2ecf20Sopenharmony_ci .aborted = true, 26998c2ecf20Sopenharmony_ci }; 27008c2ecf20Sopenharmony_ci 27018c2ecf20Sopenharmony_ci ieee80211_scan_completed(mvm->hw, &info); 27028c2ecf20Sopenharmony_ci } 27038c2ecf20Sopenharmony_ci } else if (notify) { 27048c2ecf20Sopenharmony_ci ieee80211_sched_scan_stopped(mvm->hw); 27058c2ecf20Sopenharmony_ci mvm->sched_scan_pass_all = SCHED_SCAN_PASS_ALL_DISABLED; 27068c2ecf20Sopenharmony_ci } 27078c2ecf20Sopenharmony_ci 27088c2ecf20Sopenharmony_ci return ret; 27098c2ecf20Sopenharmony_ci} 2710