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) 2013 - 2014, 2018 - 2020 Intel Corporation. All rights reserved. 98c2ecf20Sopenharmony_ci * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * This program is free software; you can redistribute it and/or modify 128c2ecf20Sopenharmony_ci * it under the terms of version 2 of the GNU General Public License as 138c2ecf20Sopenharmony_ci * published by the Free Software Foundation. 148c2ecf20Sopenharmony_ci * 158c2ecf20Sopenharmony_ci * This program is distributed in the hope that it will be useful, but 168c2ecf20Sopenharmony_ci * WITHOUT ANY WARRANTY; without even the implied warranty of 178c2ecf20Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 188c2ecf20Sopenharmony_ci * General Public License for more details. 198c2ecf20Sopenharmony_ci * 208c2ecf20Sopenharmony_ci * The full GNU General Public License is included in this distribution 218c2ecf20Sopenharmony_ci * in the file called COPYING. 228c2ecf20Sopenharmony_ci * 238c2ecf20Sopenharmony_ci * Contact Information: 248c2ecf20Sopenharmony_ci * Intel Linux Wireless <linuxwifi@intel.com> 258c2ecf20Sopenharmony_ci * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 268c2ecf20Sopenharmony_ci * 278c2ecf20Sopenharmony_ci * BSD LICENSE 288c2ecf20Sopenharmony_ci * 298c2ecf20Sopenharmony_ci * Copyright(c) 2013 - 2014, 2018 - 2020 Intel Corporation. All rights reserved. 308c2ecf20Sopenharmony_ci * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH 318c2ecf20Sopenharmony_ci * All rights reserved. 328c2ecf20Sopenharmony_ci * 338c2ecf20Sopenharmony_ci * Redistribution and use in source and binary forms, with or without 348c2ecf20Sopenharmony_ci * modification, are permitted provided that the following conditions 358c2ecf20Sopenharmony_ci * are met: 368c2ecf20Sopenharmony_ci * 378c2ecf20Sopenharmony_ci * * Redistributions of source code must retain the above copyright 388c2ecf20Sopenharmony_ci * notice, this list of conditions and the following disclaimer. 398c2ecf20Sopenharmony_ci * * Redistributions in binary form must reproduce the above copyright 408c2ecf20Sopenharmony_ci * notice, this list of conditions and the following disclaimer in 418c2ecf20Sopenharmony_ci * the documentation and/or other materials provided with the 428c2ecf20Sopenharmony_ci * distribution. 438c2ecf20Sopenharmony_ci * * Neither the name Intel Corporation nor the names of its 448c2ecf20Sopenharmony_ci * contributors may be used to endorse or promote products derived 458c2ecf20Sopenharmony_ci * from this software without specific prior written permission. 468c2ecf20Sopenharmony_ci * 478c2ecf20Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 488c2ecf20Sopenharmony_ci * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 498c2ecf20Sopenharmony_ci * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 508c2ecf20Sopenharmony_ci * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 518c2ecf20Sopenharmony_ci * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 528c2ecf20Sopenharmony_ci * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 538c2ecf20Sopenharmony_ci * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 548c2ecf20Sopenharmony_ci * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 558c2ecf20Sopenharmony_ci * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 568c2ecf20Sopenharmony_ci * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 578c2ecf20Sopenharmony_ci * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 588c2ecf20Sopenharmony_ci * 598c2ecf20Sopenharmony_ci *****************************************************************************/ 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci#include <linux/ieee80211.h> 628c2ecf20Sopenharmony_ci#include <linux/etherdevice.h> 638c2ecf20Sopenharmony_ci#include <net/mac80211.h> 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci#include "fw/api/coex.h" 668c2ecf20Sopenharmony_ci#include "iwl-modparams.h" 678c2ecf20Sopenharmony_ci#include "mvm.h" 688c2ecf20Sopenharmony_ci#include "iwl-debug.h" 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci/* 20MHz / 40MHz below / 40Mhz above*/ 718c2ecf20Sopenharmony_cistatic const __le64 iwl_ci_mask[][3] = { 728c2ecf20Sopenharmony_ci /* dummy entry for channel 0 */ 738c2ecf20Sopenharmony_ci {cpu_to_le64(0), cpu_to_le64(0), cpu_to_le64(0)}, 748c2ecf20Sopenharmony_ci { 758c2ecf20Sopenharmony_ci cpu_to_le64(0x0000001FFFULL), 768c2ecf20Sopenharmony_ci cpu_to_le64(0x0ULL), 778c2ecf20Sopenharmony_ci cpu_to_le64(0x00007FFFFFULL), 788c2ecf20Sopenharmony_ci }, 798c2ecf20Sopenharmony_ci { 808c2ecf20Sopenharmony_ci cpu_to_le64(0x000000FFFFULL), 818c2ecf20Sopenharmony_ci cpu_to_le64(0x0ULL), 828c2ecf20Sopenharmony_ci cpu_to_le64(0x0003FFFFFFULL), 838c2ecf20Sopenharmony_ci }, 848c2ecf20Sopenharmony_ci { 858c2ecf20Sopenharmony_ci cpu_to_le64(0x000003FFFCULL), 868c2ecf20Sopenharmony_ci cpu_to_le64(0x0ULL), 878c2ecf20Sopenharmony_ci cpu_to_le64(0x000FFFFFFCULL), 888c2ecf20Sopenharmony_ci }, 898c2ecf20Sopenharmony_ci { 908c2ecf20Sopenharmony_ci cpu_to_le64(0x00001FFFE0ULL), 918c2ecf20Sopenharmony_ci cpu_to_le64(0x0ULL), 928c2ecf20Sopenharmony_ci cpu_to_le64(0x007FFFFFE0ULL), 938c2ecf20Sopenharmony_ci }, 948c2ecf20Sopenharmony_ci { 958c2ecf20Sopenharmony_ci cpu_to_le64(0x00007FFF80ULL), 968c2ecf20Sopenharmony_ci cpu_to_le64(0x00007FFFFFULL), 978c2ecf20Sopenharmony_ci cpu_to_le64(0x01FFFFFF80ULL), 988c2ecf20Sopenharmony_ci }, 998c2ecf20Sopenharmony_ci { 1008c2ecf20Sopenharmony_ci cpu_to_le64(0x0003FFFC00ULL), 1018c2ecf20Sopenharmony_ci cpu_to_le64(0x0003FFFFFFULL), 1028c2ecf20Sopenharmony_ci cpu_to_le64(0x0FFFFFFC00ULL), 1038c2ecf20Sopenharmony_ci }, 1048c2ecf20Sopenharmony_ci { 1058c2ecf20Sopenharmony_ci cpu_to_le64(0x000FFFF000ULL), 1068c2ecf20Sopenharmony_ci cpu_to_le64(0x000FFFFFFCULL), 1078c2ecf20Sopenharmony_ci cpu_to_le64(0x3FFFFFF000ULL), 1088c2ecf20Sopenharmony_ci }, 1098c2ecf20Sopenharmony_ci { 1108c2ecf20Sopenharmony_ci cpu_to_le64(0x007FFF8000ULL), 1118c2ecf20Sopenharmony_ci cpu_to_le64(0x007FFFFFE0ULL), 1128c2ecf20Sopenharmony_ci cpu_to_le64(0xFFFFFF8000ULL), 1138c2ecf20Sopenharmony_ci }, 1148c2ecf20Sopenharmony_ci { 1158c2ecf20Sopenharmony_ci cpu_to_le64(0x01FFFE0000ULL), 1168c2ecf20Sopenharmony_ci cpu_to_le64(0x01FFFFFF80ULL), 1178c2ecf20Sopenharmony_ci cpu_to_le64(0xFFFFFE0000ULL), 1188c2ecf20Sopenharmony_ci }, 1198c2ecf20Sopenharmony_ci { 1208c2ecf20Sopenharmony_ci cpu_to_le64(0x0FFFF00000ULL), 1218c2ecf20Sopenharmony_ci cpu_to_le64(0x0FFFFFFC00ULL), 1228c2ecf20Sopenharmony_ci cpu_to_le64(0x0ULL), 1238c2ecf20Sopenharmony_ci }, 1248c2ecf20Sopenharmony_ci { 1258c2ecf20Sopenharmony_ci cpu_to_le64(0x3FFFC00000ULL), 1268c2ecf20Sopenharmony_ci cpu_to_le64(0x3FFFFFF000ULL), 1278c2ecf20Sopenharmony_ci cpu_to_le64(0x0) 1288c2ecf20Sopenharmony_ci }, 1298c2ecf20Sopenharmony_ci { 1308c2ecf20Sopenharmony_ci cpu_to_le64(0xFFFE000000ULL), 1318c2ecf20Sopenharmony_ci cpu_to_le64(0xFFFFFF8000ULL), 1328c2ecf20Sopenharmony_ci cpu_to_le64(0x0) 1338c2ecf20Sopenharmony_ci }, 1348c2ecf20Sopenharmony_ci { 1358c2ecf20Sopenharmony_ci cpu_to_le64(0xFFF8000000ULL), 1368c2ecf20Sopenharmony_ci cpu_to_le64(0xFFFFFE0000ULL), 1378c2ecf20Sopenharmony_ci cpu_to_le64(0x0) 1388c2ecf20Sopenharmony_ci }, 1398c2ecf20Sopenharmony_ci { 1408c2ecf20Sopenharmony_ci cpu_to_le64(0xFE00000000ULL), 1418c2ecf20Sopenharmony_ci cpu_to_le64(0x0ULL), 1428c2ecf20Sopenharmony_ci cpu_to_le64(0x0ULL) 1438c2ecf20Sopenharmony_ci }, 1448c2ecf20Sopenharmony_ci}; 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_cistatic enum iwl_bt_coex_lut_type 1478c2ecf20Sopenharmony_ciiwl_get_coex_type(struct iwl_mvm *mvm, const struct ieee80211_vif *vif) 1488c2ecf20Sopenharmony_ci{ 1498c2ecf20Sopenharmony_ci struct ieee80211_chanctx_conf *chanctx_conf; 1508c2ecf20Sopenharmony_ci enum iwl_bt_coex_lut_type ret; 1518c2ecf20Sopenharmony_ci u16 phy_ctx_id; 1528c2ecf20Sopenharmony_ci u32 primary_ch_phy_id, secondary_ch_phy_id; 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci /* 1558c2ecf20Sopenharmony_ci * Checking that we hold mvm->mutex is a good idea, but the rate 1568c2ecf20Sopenharmony_ci * control can't acquire the mutex since it runs in Tx path. 1578c2ecf20Sopenharmony_ci * So this is racy in that case, but in the worst case, the AMPDU 1588c2ecf20Sopenharmony_ci * size limit will be wrong for a short time which is not a big 1598c2ecf20Sopenharmony_ci * issue. 1608c2ecf20Sopenharmony_ci */ 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci rcu_read_lock(); 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci chanctx_conf = rcu_dereference(vif->chanctx_conf); 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci if (!chanctx_conf || 1678c2ecf20Sopenharmony_ci chanctx_conf->def.chan->band != NL80211_BAND_2GHZ) { 1688c2ecf20Sopenharmony_ci rcu_read_unlock(); 1698c2ecf20Sopenharmony_ci return BT_COEX_INVALID_LUT; 1708c2ecf20Sopenharmony_ci } 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci ret = BT_COEX_TX_DIS_LUT; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci if (mvm->cfg->bt_shared_single_ant) { 1758c2ecf20Sopenharmony_ci rcu_read_unlock(); 1768c2ecf20Sopenharmony_ci return ret; 1778c2ecf20Sopenharmony_ci } 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci phy_ctx_id = *((u16 *)chanctx_conf->drv_priv); 1808c2ecf20Sopenharmony_ci primary_ch_phy_id = le32_to_cpu(mvm->last_bt_ci_cmd.primary_ch_phy_id); 1818c2ecf20Sopenharmony_ci secondary_ch_phy_id = 1828c2ecf20Sopenharmony_ci le32_to_cpu(mvm->last_bt_ci_cmd.secondary_ch_phy_id); 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci if (primary_ch_phy_id == phy_ctx_id) 1858c2ecf20Sopenharmony_ci ret = le32_to_cpu(mvm->last_bt_notif.primary_ch_lut); 1868c2ecf20Sopenharmony_ci else if (secondary_ch_phy_id == phy_ctx_id) 1878c2ecf20Sopenharmony_ci ret = le32_to_cpu(mvm->last_bt_notif.secondary_ch_lut); 1888c2ecf20Sopenharmony_ci /* else - default = TX TX disallowed */ 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci rcu_read_unlock(); 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci return ret; 1938c2ecf20Sopenharmony_ci} 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ciint iwl_mvm_send_bt_init_conf(struct iwl_mvm *mvm) 1968c2ecf20Sopenharmony_ci{ 1978c2ecf20Sopenharmony_ci struct iwl_bt_coex_cmd bt_cmd = {}; 1988c2ecf20Sopenharmony_ci u32 mode; 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci lockdep_assert_held(&mvm->mutex); 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci if (unlikely(mvm->bt_force_ant_mode != BT_FORCE_ANT_DIS)) { 2038c2ecf20Sopenharmony_ci switch (mvm->bt_force_ant_mode) { 2048c2ecf20Sopenharmony_ci case BT_FORCE_ANT_BT: 2058c2ecf20Sopenharmony_ci mode = BT_COEX_BT; 2068c2ecf20Sopenharmony_ci break; 2078c2ecf20Sopenharmony_ci case BT_FORCE_ANT_WIFI: 2088c2ecf20Sopenharmony_ci mode = BT_COEX_WIFI; 2098c2ecf20Sopenharmony_ci break; 2108c2ecf20Sopenharmony_ci default: 2118c2ecf20Sopenharmony_ci WARN_ON(1); 2128c2ecf20Sopenharmony_ci mode = 0; 2138c2ecf20Sopenharmony_ci } 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci bt_cmd.mode = cpu_to_le32(mode); 2168c2ecf20Sopenharmony_ci goto send_cmd; 2178c2ecf20Sopenharmony_ci } 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci bt_cmd.mode = cpu_to_le32(BT_COEX_NW); 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci if (IWL_MVM_BT_COEX_SYNC2SCO) 2228c2ecf20Sopenharmony_ci bt_cmd.enabled_modules |= 2238c2ecf20Sopenharmony_ci cpu_to_le32(BT_COEX_SYNC2SCO_ENABLED); 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci if (iwl_mvm_is_mplut_supported(mvm)) 2268c2ecf20Sopenharmony_ci bt_cmd.enabled_modules |= cpu_to_le32(BT_COEX_MPLUT_ENABLED); 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci bt_cmd.enabled_modules |= cpu_to_le32(BT_COEX_HIGH_BAND_RET); 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_cisend_cmd: 2318c2ecf20Sopenharmony_ci memset(&mvm->last_bt_notif, 0, sizeof(mvm->last_bt_notif)); 2328c2ecf20Sopenharmony_ci memset(&mvm->last_bt_ci_cmd, 0, sizeof(mvm->last_bt_ci_cmd)); 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci return iwl_mvm_send_cmd_pdu(mvm, BT_CONFIG, 0, sizeof(bt_cmd), &bt_cmd); 2358c2ecf20Sopenharmony_ci} 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_cistatic int iwl_mvm_bt_coex_reduced_txp(struct iwl_mvm *mvm, u8 sta_id, 2388c2ecf20Sopenharmony_ci bool enable) 2398c2ecf20Sopenharmony_ci{ 2408c2ecf20Sopenharmony_ci struct iwl_bt_coex_reduced_txp_update_cmd cmd = {}; 2418c2ecf20Sopenharmony_ci struct iwl_mvm_sta *mvmsta; 2428c2ecf20Sopenharmony_ci u32 value; 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci mvmsta = iwl_mvm_sta_from_staid_protected(mvm, sta_id); 2458c2ecf20Sopenharmony_ci if (!mvmsta) 2468c2ecf20Sopenharmony_ci return 0; 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci /* nothing to do */ 2498c2ecf20Sopenharmony_ci if (mvmsta->bt_reduced_txpower == enable) 2508c2ecf20Sopenharmony_ci return 0; 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci value = mvmsta->sta_id; 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci if (enable) 2558c2ecf20Sopenharmony_ci value |= BT_REDUCED_TX_POWER_BIT; 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci IWL_DEBUG_COEX(mvm, "%sable reduced Tx Power for sta %d\n", 2588c2ecf20Sopenharmony_ci enable ? "en" : "dis", sta_id); 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci cmd.reduced_txp = cpu_to_le32(value); 2618c2ecf20Sopenharmony_ci mvmsta->bt_reduced_txpower = enable; 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci return iwl_mvm_send_cmd_pdu(mvm, BT_COEX_UPDATE_REDUCED_TXP, 2648c2ecf20Sopenharmony_ci CMD_ASYNC, sizeof(cmd), &cmd); 2658c2ecf20Sopenharmony_ci} 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_cistruct iwl_bt_iterator_data { 2688c2ecf20Sopenharmony_ci struct iwl_bt_coex_profile_notif *notif; 2698c2ecf20Sopenharmony_ci struct iwl_mvm *mvm; 2708c2ecf20Sopenharmony_ci struct ieee80211_chanctx_conf *primary; 2718c2ecf20Sopenharmony_ci struct ieee80211_chanctx_conf *secondary; 2728c2ecf20Sopenharmony_ci bool primary_ll; 2738c2ecf20Sopenharmony_ci u8 primary_load; 2748c2ecf20Sopenharmony_ci u8 secondary_load; 2758c2ecf20Sopenharmony_ci}; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_cistatic inline 2788c2ecf20Sopenharmony_civoid iwl_mvm_bt_coex_enable_rssi_event(struct iwl_mvm *mvm, 2798c2ecf20Sopenharmony_ci struct ieee80211_vif *vif, 2808c2ecf20Sopenharmony_ci bool enable, int rssi) 2818c2ecf20Sopenharmony_ci{ 2828c2ecf20Sopenharmony_ci struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci mvmvif->bf_data.last_bt_coex_event = rssi; 2858c2ecf20Sopenharmony_ci mvmvif->bf_data.bt_coex_max_thold = 2868c2ecf20Sopenharmony_ci enable ? -IWL_MVM_BT_COEX_EN_RED_TXP_THRESH : 0; 2878c2ecf20Sopenharmony_ci mvmvif->bf_data.bt_coex_min_thold = 2888c2ecf20Sopenharmony_ci enable ? -IWL_MVM_BT_COEX_DIS_RED_TXP_THRESH : 0; 2898c2ecf20Sopenharmony_ci} 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci#define MVM_COEX_TCM_PERIOD (HZ * 10) 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_cistatic void iwl_mvm_bt_coex_tcm_based_ci(struct iwl_mvm *mvm, 2948c2ecf20Sopenharmony_ci struct iwl_bt_iterator_data *data) 2958c2ecf20Sopenharmony_ci{ 2968c2ecf20Sopenharmony_ci unsigned long now = jiffies; 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci if (!time_after(now, mvm->bt_coex_last_tcm_ts + MVM_COEX_TCM_PERIOD)) 2998c2ecf20Sopenharmony_ci return; 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci mvm->bt_coex_last_tcm_ts = now; 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci /* We assume here that we don't have more than 2 vifs on 2.4GHz */ 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci /* if the primary is low latency, it will stay primary */ 3068c2ecf20Sopenharmony_ci if (data->primary_ll) 3078c2ecf20Sopenharmony_ci return; 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci if (data->primary_load >= data->secondary_load) 3108c2ecf20Sopenharmony_ci return; 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci swap(data->primary, data->secondary); 3138c2ecf20Sopenharmony_ci} 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci/* must be called under rcu_read_lock */ 3168c2ecf20Sopenharmony_cistatic void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac, 3178c2ecf20Sopenharmony_ci struct ieee80211_vif *vif) 3188c2ecf20Sopenharmony_ci{ 3198c2ecf20Sopenharmony_ci struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 3208c2ecf20Sopenharmony_ci struct iwl_bt_iterator_data *data = _data; 3218c2ecf20Sopenharmony_ci struct iwl_mvm *mvm = data->mvm; 3228c2ecf20Sopenharmony_ci struct ieee80211_chanctx_conf *chanctx_conf; 3238c2ecf20Sopenharmony_ci /* default smps_mode is AUTOMATIC - only used for client modes */ 3248c2ecf20Sopenharmony_ci enum ieee80211_smps_mode smps_mode = IEEE80211_SMPS_AUTOMATIC; 3258c2ecf20Sopenharmony_ci u32 bt_activity_grading, min_ag_for_static_smps; 3268c2ecf20Sopenharmony_ci int ave_rssi; 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci lockdep_assert_held(&mvm->mutex); 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci switch (vif->type) { 3318c2ecf20Sopenharmony_ci case NL80211_IFTYPE_STATION: 3328c2ecf20Sopenharmony_ci break; 3338c2ecf20Sopenharmony_ci case NL80211_IFTYPE_AP: 3348c2ecf20Sopenharmony_ci if (!mvmvif->ap_ibss_active) 3358c2ecf20Sopenharmony_ci return; 3368c2ecf20Sopenharmony_ci break; 3378c2ecf20Sopenharmony_ci default: 3388c2ecf20Sopenharmony_ci return; 3398c2ecf20Sopenharmony_ci } 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci chanctx_conf = rcu_dereference(vif->chanctx_conf); 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci /* If channel context is invalid or not on 2.4GHz .. */ 3448c2ecf20Sopenharmony_ci if ((!chanctx_conf || 3458c2ecf20Sopenharmony_ci chanctx_conf->def.chan->band != NL80211_BAND_2GHZ)) { 3468c2ecf20Sopenharmony_ci if (vif->type == NL80211_IFTYPE_STATION) { 3478c2ecf20Sopenharmony_ci /* ... relax constraints and disable rssi events */ 3488c2ecf20Sopenharmony_ci iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX, 3498c2ecf20Sopenharmony_ci smps_mode); 3508c2ecf20Sopenharmony_ci iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, 3518c2ecf20Sopenharmony_ci false); 3528c2ecf20Sopenharmony_ci iwl_mvm_bt_coex_enable_rssi_event(mvm, vif, false, 0); 3538c2ecf20Sopenharmony_ci } 3548c2ecf20Sopenharmony_ci return; 3558c2ecf20Sopenharmony_ci } 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_COEX_SCHEMA_2)) 3588c2ecf20Sopenharmony_ci min_ag_for_static_smps = BT_VERY_HIGH_TRAFFIC; 3598c2ecf20Sopenharmony_ci else 3608c2ecf20Sopenharmony_ci min_ag_for_static_smps = BT_HIGH_TRAFFIC; 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci bt_activity_grading = le32_to_cpu(data->notif->bt_activity_grading); 3638c2ecf20Sopenharmony_ci if (bt_activity_grading >= min_ag_for_static_smps) 3648c2ecf20Sopenharmony_ci smps_mode = IEEE80211_SMPS_STATIC; 3658c2ecf20Sopenharmony_ci else if (bt_activity_grading >= BT_LOW_TRAFFIC) 3668c2ecf20Sopenharmony_ci smps_mode = IEEE80211_SMPS_DYNAMIC; 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci /* relax SMPS constraints for next association */ 3698c2ecf20Sopenharmony_ci if (!vif->bss_conf.assoc) 3708c2ecf20Sopenharmony_ci smps_mode = IEEE80211_SMPS_AUTOMATIC; 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci if (mvmvif->phy_ctxt && 3738c2ecf20Sopenharmony_ci (mvm->last_bt_notif.rrc_status & BIT(mvmvif->phy_ctxt->id))) 3748c2ecf20Sopenharmony_ci smps_mode = IEEE80211_SMPS_AUTOMATIC; 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci IWL_DEBUG_COEX(data->mvm, 3778c2ecf20Sopenharmony_ci "mac %d: bt_activity_grading %d smps_req %d\n", 3788c2ecf20Sopenharmony_ci mvmvif->id, bt_activity_grading, smps_mode); 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci if (vif->type == NL80211_IFTYPE_STATION) 3818c2ecf20Sopenharmony_ci iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX, 3828c2ecf20Sopenharmony_ci smps_mode); 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci /* low latency is always primary */ 3858c2ecf20Sopenharmony_ci if (iwl_mvm_vif_low_latency(mvmvif)) { 3868c2ecf20Sopenharmony_ci data->primary_ll = true; 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci data->secondary = data->primary; 3898c2ecf20Sopenharmony_ci data->primary = chanctx_conf; 3908c2ecf20Sopenharmony_ci } 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci if (vif->type == NL80211_IFTYPE_AP) { 3938c2ecf20Sopenharmony_ci if (!mvmvif->ap_ibss_active) 3948c2ecf20Sopenharmony_ci return; 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci if (chanctx_conf == data->primary) 3978c2ecf20Sopenharmony_ci return; 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci if (!data->primary_ll) { 4008c2ecf20Sopenharmony_ci /* 4018c2ecf20Sopenharmony_ci * downgrade the current primary no matter what its 4028c2ecf20Sopenharmony_ci * type is. 4038c2ecf20Sopenharmony_ci */ 4048c2ecf20Sopenharmony_ci data->secondary = data->primary; 4058c2ecf20Sopenharmony_ci data->primary = chanctx_conf; 4068c2ecf20Sopenharmony_ci } else { 4078c2ecf20Sopenharmony_ci /* there is low latency vif - we will be secondary */ 4088c2ecf20Sopenharmony_ci data->secondary = chanctx_conf; 4098c2ecf20Sopenharmony_ci } 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci if (data->primary == chanctx_conf) 4128c2ecf20Sopenharmony_ci data->primary_load = mvm->tcm.result.load[mvmvif->id]; 4138c2ecf20Sopenharmony_ci else if (data->secondary == chanctx_conf) 4148c2ecf20Sopenharmony_ci data->secondary_load = mvm->tcm.result.load[mvmvif->id]; 4158c2ecf20Sopenharmony_ci return; 4168c2ecf20Sopenharmony_ci } 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci /* 4198c2ecf20Sopenharmony_ci * STA / P2P Client, try to be primary if first vif. If we are in low 4208c2ecf20Sopenharmony_ci * latency mode, we are already in primary and just don't do much 4218c2ecf20Sopenharmony_ci */ 4228c2ecf20Sopenharmony_ci if (!data->primary || data->primary == chanctx_conf) 4238c2ecf20Sopenharmony_ci data->primary = chanctx_conf; 4248c2ecf20Sopenharmony_ci else if (!data->secondary) 4258c2ecf20Sopenharmony_ci /* if secondary is not NULL, it might be a GO */ 4268c2ecf20Sopenharmony_ci data->secondary = chanctx_conf; 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci if (data->primary == chanctx_conf) 4298c2ecf20Sopenharmony_ci data->primary_load = mvm->tcm.result.load[mvmvif->id]; 4308c2ecf20Sopenharmony_ci else if (data->secondary == chanctx_conf) 4318c2ecf20Sopenharmony_ci data->secondary_load = mvm->tcm.result.load[mvmvif->id]; 4328c2ecf20Sopenharmony_ci /* 4338c2ecf20Sopenharmony_ci * don't reduce the Tx power if one of these is true: 4348c2ecf20Sopenharmony_ci * we are in LOOSE 4358c2ecf20Sopenharmony_ci * single share antenna product 4368c2ecf20Sopenharmony_ci * BT is inactive 4378c2ecf20Sopenharmony_ci * we are not associated 4388c2ecf20Sopenharmony_ci */ 4398c2ecf20Sopenharmony_ci if (iwl_get_coex_type(mvm, vif) == BT_COEX_LOOSE_LUT || 4408c2ecf20Sopenharmony_ci mvm->cfg->bt_shared_single_ant || !vif->bss_conf.assoc || 4418c2ecf20Sopenharmony_ci le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) == BT_OFF) { 4428c2ecf20Sopenharmony_ci iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, false); 4438c2ecf20Sopenharmony_ci iwl_mvm_bt_coex_enable_rssi_event(mvm, vif, false, 0); 4448c2ecf20Sopenharmony_ci return; 4458c2ecf20Sopenharmony_ci } 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci /* try to get the avg rssi from fw */ 4488c2ecf20Sopenharmony_ci ave_rssi = mvmvif->bf_data.ave_beacon_signal; 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci /* if the RSSI isn't valid, fake it is very low */ 4518c2ecf20Sopenharmony_ci if (!ave_rssi) 4528c2ecf20Sopenharmony_ci ave_rssi = -100; 4538c2ecf20Sopenharmony_ci if (ave_rssi > -IWL_MVM_BT_COEX_EN_RED_TXP_THRESH) { 4548c2ecf20Sopenharmony_ci if (iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, true)) 4558c2ecf20Sopenharmony_ci IWL_ERR(mvm, "Couldn't send BT_CONFIG cmd\n"); 4568c2ecf20Sopenharmony_ci } else if (ave_rssi < -IWL_MVM_BT_COEX_DIS_RED_TXP_THRESH) { 4578c2ecf20Sopenharmony_ci if (iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, false)) 4588c2ecf20Sopenharmony_ci IWL_ERR(mvm, "Couldn't send BT_CONFIG cmd\n"); 4598c2ecf20Sopenharmony_ci } 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci /* Begin to monitor the RSSI: it may influence the reduced Tx power */ 4628c2ecf20Sopenharmony_ci iwl_mvm_bt_coex_enable_rssi_event(mvm, vif, true, ave_rssi); 4638c2ecf20Sopenharmony_ci} 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_cistatic void iwl_mvm_bt_coex_notif_handle(struct iwl_mvm *mvm) 4668c2ecf20Sopenharmony_ci{ 4678c2ecf20Sopenharmony_ci struct iwl_bt_iterator_data data = { 4688c2ecf20Sopenharmony_ci .mvm = mvm, 4698c2ecf20Sopenharmony_ci .notif = &mvm->last_bt_notif, 4708c2ecf20Sopenharmony_ci }; 4718c2ecf20Sopenharmony_ci struct iwl_bt_coex_ci_cmd cmd = {}; 4728c2ecf20Sopenharmony_ci u8 ci_bw_idx; 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci /* Ignore updates if we are in force mode */ 4758c2ecf20Sopenharmony_ci if (unlikely(mvm->bt_force_ant_mode != BT_FORCE_ANT_DIS)) 4768c2ecf20Sopenharmony_ci return; 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci rcu_read_lock(); 4798c2ecf20Sopenharmony_ci ieee80211_iterate_active_interfaces_atomic( 4808c2ecf20Sopenharmony_ci mvm->hw, IEEE80211_IFACE_ITER_NORMAL, 4818c2ecf20Sopenharmony_ci iwl_mvm_bt_notif_iterator, &data); 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci iwl_mvm_bt_coex_tcm_based_ci(mvm, &data); 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci if (data.primary) { 4868c2ecf20Sopenharmony_ci struct ieee80211_chanctx_conf *chan = data.primary; 4878c2ecf20Sopenharmony_ci if (WARN_ON(!chan->def.chan)) { 4888c2ecf20Sopenharmony_ci rcu_read_unlock(); 4898c2ecf20Sopenharmony_ci return; 4908c2ecf20Sopenharmony_ci } 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci if (chan->def.width < NL80211_CHAN_WIDTH_40) { 4938c2ecf20Sopenharmony_ci ci_bw_idx = 0; 4948c2ecf20Sopenharmony_ci } else { 4958c2ecf20Sopenharmony_ci if (chan->def.center_freq1 > 4968c2ecf20Sopenharmony_ci chan->def.chan->center_freq) 4978c2ecf20Sopenharmony_ci ci_bw_idx = 2; 4988c2ecf20Sopenharmony_ci else 4998c2ecf20Sopenharmony_ci ci_bw_idx = 1; 5008c2ecf20Sopenharmony_ci } 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci cmd.bt_primary_ci = 5038c2ecf20Sopenharmony_ci iwl_ci_mask[chan->def.chan->hw_value][ci_bw_idx]; 5048c2ecf20Sopenharmony_ci cmd.primary_ch_phy_id = 5058c2ecf20Sopenharmony_ci cpu_to_le32(*((u16 *)data.primary->drv_priv)); 5068c2ecf20Sopenharmony_ci } 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci if (data.secondary) { 5098c2ecf20Sopenharmony_ci struct ieee80211_chanctx_conf *chan = data.secondary; 5108c2ecf20Sopenharmony_ci if (WARN_ON(!data.secondary->def.chan)) { 5118c2ecf20Sopenharmony_ci rcu_read_unlock(); 5128c2ecf20Sopenharmony_ci return; 5138c2ecf20Sopenharmony_ci } 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci if (chan->def.width < NL80211_CHAN_WIDTH_40) { 5168c2ecf20Sopenharmony_ci ci_bw_idx = 0; 5178c2ecf20Sopenharmony_ci } else { 5188c2ecf20Sopenharmony_ci if (chan->def.center_freq1 > 5198c2ecf20Sopenharmony_ci chan->def.chan->center_freq) 5208c2ecf20Sopenharmony_ci ci_bw_idx = 2; 5218c2ecf20Sopenharmony_ci else 5228c2ecf20Sopenharmony_ci ci_bw_idx = 1; 5238c2ecf20Sopenharmony_ci } 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci cmd.bt_secondary_ci = 5268c2ecf20Sopenharmony_ci iwl_ci_mask[chan->def.chan->hw_value][ci_bw_idx]; 5278c2ecf20Sopenharmony_ci cmd.secondary_ch_phy_id = 5288c2ecf20Sopenharmony_ci cpu_to_le32(*((u16 *)data.secondary->drv_priv)); 5298c2ecf20Sopenharmony_ci } 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci rcu_read_unlock(); 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci /* Don't spam the fw with the same command over and over */ 5348c2ecf20Sopenharmony_ci if (memcmp(&cmd, &mvm->last_bt_ci_cmd, sizeof(cmd))) { 5358c2ecf20Sopenharmony_ci if (iwl_mvm_send_cmd_pdu(mvm, BT_COEX_CI, 0, 5368c2ecf20Sopenharmony_ci sizeof(cmd), &cmd)) 5378c2ecf20Sopenharmony_ci IWL_ERR(mvm, "Failed to send BT_CI cmd\n"); 5388c2ecf20Sopenharmony_ci memcpy(&mvm->last_bt_ci_cmd, &cmd, sizeof(cmd)); 5398c2ecf20Sopenharmony_ci } 5408c2ecf20Sopenharmony_ci} 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_civoid iwl_mvm_rx_bt_coex_notif(struct iwl_mvm *mvm, 5438c2ecf20Sopenharmony_ci struct iwl_rx_cmd_buffer *rxb) 5448c2ecf20Sopenharmony_ci{ 5458c2ecf20Sopenharmony_ci struct iwl_rx_packet *pkt = rxb_addr(rxb); 5468c2ecf20Sopenharmony_ci struct iwl_bt_coex_profile_notif *notif = (void *)pkt->data; 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci IWL_DEBUG_COEX(mvm, "BT Coex Notification received\n"); 5498c2ecf20Sopenharmony_ci IWL_DEBUG_COEX(mvm, "\tBT ci compliance %d\n", notif->bt_ci_compliance); 5508c2ecf20Sopenharmony_ci IWL_DEBUG_COEX(mvm, "\tBT primary_ch_lut %d\n", 5518c2ecf20Sopenharmony_ci le32_to_cpu(notif->primary_ch_lut)); 5528c2ecf20Sopenharmony_ci IWL_DEBUG_COEX(mvm, "\tBT secondary_ch_lut %d\n", 5538c2ecf20Sopenharmony_ci le32_to_cpu(notif->secondary_ch_lut)); 5548c2ecf20Sopenharmony_ci IWL_DEBUG_COEX(mvm, "\tBT activity grading %d\n", 5558c2ecf20Sopenharmony_ci le32_to_cpu(notif->bt_activity_grading)); 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci /* remember this notification for future use: rssi fluctuations */ 5588c2ecf20Sopenharmony_ci memcpy(&mvm->last_bt_notif, notif, sizeof(mvm->last_bt_notif)); 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci iwl_mvm_bt_coex_notif_handle(mvm); 5618c2ecf20Sopenharmony_ci} 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_civoid iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif, 5648c2ecf20Sopenharmony_ci enum ieee80211_rssi_event_data rssi_event) 5658c2ecf20Sopenharmony_ci{ 5668c2ecf20Sopenharmony_ci struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 5678c2ecf20Sopenharmony_ci int ret; 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci lockdep_assert_held(&mvm->mutex); 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci /* Ignore updates if we are in force mode */ 5728c2ecf20Sopenharmony_ci if (unlikely(mvm->bt_force_ant_mode != BT_FORCE_ANT_DIS)) 5738c2ecf20Sopenharmony_ci return; 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci /* 5768c2ecf20Sopenharmony_ci * Rssi update while not associated - can happen since the statistics 5778c2ecf20Sopenharmony_ci * are handled asynchronously 5788c2ecf20Sopenharmony_ci */ 5798c2ecf20Sopenharmony_ci if (mvmvif->ap_sta_id == IWL_MVM_INVALID_STA) 5808c2ecf20Sopenharmony_ci return; 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci /* No BT - reports should be disabled */ 5838c2ecf20Sopenharmony_ci if (le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) == BT_OFF) 5848c2ecf20Sopenharmony_ci return; 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci IWL_DEBUG_COEX(mvm, "RSSI for %pM is now %s\n", vif->bss_conf.bssid, 5878c2ecf20Sopenharmony_ci rssi_event == RSSI_EVENT_HIGH ? "HIGH" : "LOW"); 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ci /* 5908c2ecf20Sopenharmony_ci * Check if rssi is good enough for reduced Tx power, but not in loose 5918c2ecf20Sopenharmony_ci * scheme. 5928c2ecf20Sopenharmony_ci */ 5938c2ecf20Sopenharmony_ci if (rssi_event == RSSI_EVENT_LOW || mvm->cfg->bt_shared_single_ant || 5948c2ecf20Sopenharmony_ci iwl_get_coex_type(mvm, vif) == BT_COEX_LOOSE_LUT) 5958c2ecf20Sopenharmony_ci ret = iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, 5968c2ecf20Sopenharmony_ci false); 5978c2ecf20Sopenharmony_ci else 5988c2ecf20Sopenharmony_ci ret = iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, true); 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_ci if (ret) 6018c2ecf20Sopenharmony_ci IWL_ERR(mvm, "couldn't send BT_CONFIG HCMD upon RSSI event\n"); 6028c2ecf20Sopenharmony_ci} 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci#define LINK_QUAL_AGG_TIME_LIMIT_DEF (4000) 6058c2ecf20Sopenharmony_ci#define LINK_QUAL_AGG_TIME_LIMIT_BT_ACT (1200) 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ciu16 iwl_mvm_coex_agg_time_limit(struct iwl_mvm *mvm, 6088c2ecf20Sopenharmony_ci struct ieee80211_sta *sta) 6098c2ecf20Sopenharmony_ci{ 6108c2ecf20Sopenharmony_ci struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); 6118c2ecf20Sopenharmony_ci struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(mvmsta->vif); 6128c2ecf20Sopenharmony_ci struct iwl_mvm_phy_ctxt *phy_ctxt = mvmvif->phy_ctxt; 6138c2ecf20Sopenharmony_ci enum iwl_bt_coex_lut_type lut_type; 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci if (mvm->last_bt_notif.ttc_status & BIT(phy_ctxt->id)) 6168c2ecf20Sopenharmony_ci return LINK_QUAL_AGG_TIME_LIMIT_DEF; 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ci if (le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) < 6198c2ecf20Sopenharmony_ci BT_HIGH_TRAFFIC) 6208c2ecf20Sopenharmony_ci return LINK_QUAL_AGG_TIME_LIMIT_DEF; 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci lut_type = iwl_get_coex_type(mvm, mvmsta->vif); 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci if (lut_type == BT_COEX_LOOSE_LUT || lut_type == BT_COEX_INVALID_LUT) 6258c2ecf20Sopenharmony_ci return LINK_QUAL_AGG_TIME_LIMIT_DEF; 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci /* tight coex, high bt traffic, reduce AGG time limit */ 6288c2ecf20Sopenharmony_ci return LINK_QUAL_AGG_TIME_LIMIT_BT_ACT; 6298c2ecf20Sopenharmony_ci} 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_cibool iwl_mvm_bt_coex_is_mimo_allowed(struct iwl_mvm *mvm, 6328c2ecf20Sopenharmony_ci struct ieee80211_sta *sta) 6338c2ecf20Sopenharmony_ci{ 6348c2ecf20Sopenharmony_ci struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); 6358c2ecf20Sopenharmony_ci struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(mvmsta->vif); 6368c2ecf20Sopenharmony_ci struct iwl_mvm_phy_ctxt *phy_ctxt = mvmvif->phy_ctxt; 6378c2ecf20Sopenharmony_ci enum iwl_bt_coex_lut_type lut_type; 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci if (mvm->last_bt_notif.ttc_status & BIT(phy_ctxt->id)) 6408c2ecf20Sopenharmony_ci return true; 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci if (le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) < 6438c2ecf20Sopenharmony_ci BT_HIGH_TRAFFIC) 6448c2ecf20Sopenharmony_ci return true; 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci /* 6478c2ecf20Sopenharmony_ci * In Tight / TxTxDis, BT can't Rx while we Tx, so use both antennas 6488c2ecf20Sopenharmony_ci * since BT is already killed. 6498c2ecf20Sopenharmony_ci * In Loose, BT can Rx while we Tx, so forbid MIMO to let BT Rx while 6508c2ecf20Sopenharmony_ci * we Tx. 6518c2ecf20Sopenharmony_ci * When we are in 5GHz, we'll get BT_COEX_INVALID_LUT allowing MIMO. 6528c2ecf20Sopenharmony_ci */ 6538c2ecf20Sopenharmony_ci lut_type = iwl_get_coex_type(mvm, mvmsta->vif); 6548c2ecf20Sopenharmony_ci return lut_type != BT_COEX_LOOSE_LUT; 6558c2ecf20Sopenharmony_ci} 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_cibool iwl_mvm_bt_coex_is_ant_avail(struct iwl_mvm *mvm, u8 ant) 6588c2ecf20Sopenharmony_ci{ 6598c2ecf20Sopenharmony_ci /* there is no other antenna, shared antenna is always available */ 6608c2ecf20Sopenharmony_ci if (mvm->cfg->bt_shared_single_ant) 6618c2ecf20Sopenharmony_ci return true; 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci if (ant & mvm->cfg->non_shared_ant) 6648c2ecf20Sopenharmony_ci return true; 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci return le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) < 6678c2ecf20Sopenharmony_ci BT_HIGH_TRAFFIC; 6688c2ecf20Sopenharmony_ci} 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_cibool iwl_mvm_bt_coex_is_shared_ant_avail(struct iwl_mvm *mvm) 6718c2ecf20Sopenharmony_ci{ 6728c2ecf20Sopenharmony_ci /* there is no other antenna, shared antenna is always available */ 6738c2ecf20Sopenharmony_ci if (mvm->cfg->bt_shared_single_ant) 6748c2ecf20Sopenharmony_ci return true; 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_ci return le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) < BT_HIGH_TRAFFIC; 6778c2ecf20Sopenharmony_ci} 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_cibool iwl_mvm_bt_coex_is_tpc_allowed(struct iwl_mvm *mvm, 6808c2ecf20Sopenharmony_ci enum nl80211_band band) 6818c2ecf20Sopenharmony_ci{ 6828c2ecf20Sopenharmony_ci u32 bt_activity = le32_to_cpu(mvm->last_bt_notif.bt_activity_grading); 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ci if (band != NL80211_BAND_2GHZ) 6858c2ecf20Sopenharmony_ci return false; 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_ci return bt_activity >= BT_LOW_TRAFFIC; 6888c2ecf20Sopenharmony_ci} 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ciu8 iwl_mvm_bt_coex_get_single_ant_msk(struct iwl_mvm *mvm, u8 enabled_ants) 6918c2ecf20Sopenharmony_ci{ 6928c2ecf20Sopenharmony_ci if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_COEX_SCHEMA_2) && 6938c2ecf20Sopenharmony_ci (mvm->cfg->non_shared_ant & enabled_ants)) 6948c2ecf20Sopenharmony_ci return mvm->cfg->non_shared_ant; 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci return first_antenna(enabled_ants); 6978c2ecf20Sopenharmony_ci} 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ciu8 iwl_mvm_bt_coex_tx_prio(struct iwl_mvm *mvm, struct ieee80211_hdr *hdr, 7008c2ecf20Sopenharmony_ci struct ieee80211_tx_info *info, u8 ac) 7018c2ecf20Sopenharmony_ci{ 7028c2ecf20Sopenharmony_ci __le16 fc = hdr->frame_control; 7038c2ecf20Sopenharmony_ci bool mplut_enabled = iwl_mvm_is_mplut_supported(mvm); 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_ci if (info->band != NL80211_BAND_2GHZ) 7068c2ecf20Sopenharmony_ci return 0; 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_ci if (unlikely(mvm->bt_tx_prio)) 7098c2ecf20Sopenharmony_ci return mvm->bt_tx_prio - 1; 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_ci if (likely(ieee80211_is_data(fc))) { 7128c2ecf20Sopenharmony_ci if (likely(ieee80211_is_data_qos(fc))) { 7138c2ecf20Sopenharmony_ci switch (ac) { 7148c2ecf20Sopenharmony_ci case IEEE80211_AC_BE: 7158c2ecf20Sopenharmony_ci return mplut_enabled ? 1 : 0; 7168c2ecf20Sopenharmony_ci case IEEE80211_AC_VI: 7178c2ecf20Sopenharmony_ci return mplut_enabled ? 2 : 3; 7188c2ecf20Sopenharmony_ci case IEEE80211_AC_VO: 7198c2ecf20Sopenharmony_ci return 3; 7208c2ecf20Sopenharmony_ci default: 7218c2ecf20Sopenharmony_ci return 0; 7228c2ecf20Sopenharmony_ci } 7238c2ecf20Sopenharmony_ci } else if (is_multicast_ether_addr(hdr->addr1)) { 7248c2ecf20Sopenharmony_ci return 3; 7258c2ecf20Sopenharmony_ci } else 7268c2ecf20Sopenharmony_ci return 0; 7278c2ecf20Sopenharmony_ci } else if (ieee80211_is_mgmt(fc)) { 7288c2ecf20Sopenharmony_ci return ieee80211_is_disassoc(fc) ? 0 : 3; 7298c2ecf20Sopenharmony_ci } else if (ieee80211_is_ctl(fc)) { 7308c2ecf20Sopenharmony_ci /* ignore cfend and cfendack frames as we never send those */ 7318c2ecf20Sopenharmony_ci return 3; 7328c2ecf20Sopenharmony_ci } 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci return 0; 7358c2ecf20Sopenharmony_ci} 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_civoid iwl_mvm_bt_coex_vif_change(struct iwl_mvm *mvm) 7388c2ecf20Sopenharmony_ci{ 7398c2ecf20Sopenharmony_ci iwl_mvm_bt_coex_notif_handle(mvm); 7408c2ecf20Sopenharmony_ci} 741