aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi/mvm
diff options
context:
space:
mode:
authorEmmanuel Grumbach <emmanuel.grumbach@intel.com>2014-04-02 02:31:36 -0400
committerEmmanuel Grumbach <emmanuel.grumbach@intel.com>2014-07-07 14:34:05 -0400
commit0ea8d0432c09f240b8dfdec0dc0e4abaf422b838 (patch)
tree3dab5e49601cd4684b96e8c41279b9007e453e1a /drivers/net/wireless/iwlwifi/mvm
parent7f514f5c8767b20dbd8706985cdc00a56a9fd280 (diff)
iwlwifi: mvm: BT Coex - prepare towards new API
A new API is coming. This new API is not backward compatible. So we need to keep the old commands to be able to work with the former API. Move all the current code into a new file: coex_legacy. If a firmware with the new API is detected, we currently just bail out since the implementation of the new API will come in future patches. Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Diffstat (limited to 'drivers/net/wireless/iwlwifi/mvm')
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/Makefile2
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/coex.c84
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/coex_legacy.c1332
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/debugfs.c4
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/fw-api-coex.h36
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/mvm.h26
6 files changed, 1446 insertions, 38 deletions
diff --git a/drivers/net/wireless/iwlwifi/mvm/Makefile b/drivers/net/wireless/iwlwifi/mvm/Makefile
index c30d7f64ec1e..a28235913c2c 100644
--- a/drivers/net/wireless/iwlwifi/mvm/Makefile
+++ b/drivers/net/wireless/iwlwifi/mvm/Makefile
@@ -2,7 +2,7 @@ obj-$(CONFIG_IWLMVM) += iwlmvm.o
2iwlmvm-y += fw.o mac80211.o nvm.o ops.o phy-ctxt.o mac-ctxt.o 2iwlmvm-y += fw.o mac80211.o nvm.o ops.o phy-ctxt.o mac-ctxt.o
3iwlmvm-y += utils.o rx.o tx.o binding.o quota.o sta.o sf.o 3iwlmvm-y += utils.o rx.o tx.o binding.o quota.o sta.o sf.o
4iwlmvm-y += scan.o time-event.o rs.o 4iwlmvm-y += scan.o time-event.o rs.o
5iwlmvm-y += power.o coex.o 5iwlmvm-y += power.o coex.o coex_legacy.o
6iwlmvm-y += tt.o offloading.o 6iwlmvm-y += tt.o offloading.o
7iwlmvm-$(CONFIG_IWLWIFI_DEBUGFS) += debugfs.o debugfs-vif.o 7iwlmvm-$(CONFIG_IWLWIFI_DEBUGFS) += debugfs.o debugfs-vif.o
8iwlmvm-$(CONFIG_IWLWIFI_LEDS) += led.o 8iwlmvm-$(CONFIG_IWLWIFI_LEDS) += led.o
diff --git a/drivers/net/wireless/iwlwifi/mvm/coex.c b/drivers/net/wireless/iwlwifi/mvm/coex.c
index 7e0388a32912..f471de3373c9 100644
--- a/drivers/net/wireless/iwlwifi/mvm/coex.c
+++ b/drivers/net/wireless/iwlwifi/mvm/coex.c
@@ -561,7 +561,7 @@ iwl_get_coex_type(struct iwl_mvm *mvm, const struct ieee80211_vif *vif)
561 561
562int iwl_send_bt_init_conf(struct iwl_mvm *mvm) 562int iwl_send_bt_init_conf(struct iwl_mvm *mvm)
563{ 563{
564 struct iwl_bt_coex_cmd *bt_cmd; 564 struct iwl_bt_coex_cmd_old *bt_cmd;
565 struct iwl_host_cmd cmd = { 565 struct iwl_host_cmd cmd = {
566 .id = BT_CONFIG, 566 .id = BT_CONFIG,
567 .len = { sizeof(*bt_cmd), }, 567 .len = { sizeof(*bt_cmd), },
@@ -570,6 +570,12 @@ int iwl_send_bt_init_conf(struct iwl_mvm *mvm)
570 int ret; 570 int ret;
571 u32 flags; 571 u32 flags;
572 572
573 if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BT_COEX_SPLIT))
574 return iwl_send_bt_init_conf_old(mvm);
575
576 /* TODO */
577 return 0;
578
573 ret = iwl_send_bt_prio_tbl(mvm); 579 ret = iwl_send_bt_prio_tbl(mvm);
574 if (ret) 580 if (ret)
575 return ret; 581 return ret;
@@ -584,13 +590,13 @@ int iwl_send_bt_init_conf(struct iwl_mvm *mvm)
584 if (unlikely(mvm->bt_force_ant_mode != BT_FORCE_ANT_DIS)) { 590 if (unlikely(mvm->bt_force_ant_mode != BT_FORCE_ANT_DIS)) {
585 switch (mvm->bt_force_ant_mode) { 591 switch (mvm->bt_force_ant_mode) {
586 case BT_FORCE_ANT_AUTO: 592 case BT_FORCE_ANT_AUTO:
587 flags = BT_COEX_AUTO; 593 flags = BT_COEX_AUTO_OLD;
588 break; 594 break;
589 case BT_FORCE_ANT_BT: 595 case BT_FORCE_ANT_BT:
590 flags = BT_COEX_BT; 596 flags = BT_COEX_BT_OLD;
591 break; 597 break;
592 case BT_FORCE_ANT_WIFI: 598 case BT_FORCE_ANT_WIFI:
593 flags = BT_COEX_WIFI; 599 flags = BT_COEX_WIFI_OLD;
594 break; 600 break;
595 default: 601 default:
596 WARN_ON(1); 602 WARN_ON(1);
@@ -611,7 +617,7 @@ int iwl_send_bt_init_conf(struct iwl_mvm *mvm)
611 bt_cmd->override_secondary_lut = BT_COEX_INVALID_LUT; 617 bt_cmd->override_secondary_lut = BT_COEX_INVALID_LUT;
612 618
613 flags = iwlwifi_mod_params.bt_coex_active ? 619 flags = iwlwifi_mod_params.bt_coex_active ?
614 BT_COEX_NW : BT_COEX_DISABLE; 620 BT_COEX_NW_OLD : BT_COEX_DISABLE_OLD;
615 bt_cmd->flags = cpu_to_le32(flags); 621 bt_cmd->flags = cpu_to_le32(flags);
616 622
617 bt_cmd->valid_bit_msk = cpu_to_le32(BT_VALID_ENABLE | 623 bt_cmd->valid_bit_msk = cpu_to_le32(BT_VALID_ENABLE |
@@ -680,8 +686,8 @@ static int iwl_mvm_bt_udpate_ctrl_kill_msk(struct iwl_mvm *mvm,
680 bool reduced_tx_power) 686 bool reduced_tx_power)
681{ 687{
682 enum iwl_bt_kill_msk bt_kill_msk; 688 enum iwl_bt_kill_msk bt_kill_msk;
683 struct iwl_bt_coex_cmd *bt_cmd; 689 struct iwl_bt_coex_cmd_old *bt_cmd;
684 struct iwl_bt_coex_profile_notif *notif = &mvm->last_bt_notif; 690 struct iwl_bt_coex_profile_notif_old *notif = &mvm->last_bt_notif;
685 struct iwl_host_cmd cmd = { 691 struct iwl_host_cmd cmd = {
686 .id = BT_CONFIG, 692 .id = BT_CONFIG,
687 .data[0] = &bt_cmd, 693 .data[0] = &bt_cmd,
@@ -722,7 +728,7 @@ static int iwl_mvm_bt_udpate_ctrl_kill_msk(struct iwl_mvm *mvm,
722 if (!bt_cmd) 728 if (!bt_cmd)
723 return -ENOMEM; 729 return -ENOMEM;
724 cmd.data[0] = bt_cmd; 730 cmd.data[0] = bt_cmd;
725 bt_cmd->flags = cpu_to_le32(BT_COEX_NW); 731 bt_cmd->flags = cpu_to_le32(BT_COEX_NW_OLD);
726 732
727 bt_cmd->kill_ack_msk = cpu_to_le32(iwl_bt_ack_kill_msk[bt_kill_msk]); 733 bt_cmd->kill_ack_msk = cpu_to_le32(iwl_bt_ack_kill_msk[bt_kill_msk]);
728 bt_cmd->kill_cts_msk = cpu_to_le32(iwl_bt_cts_kill_msk[bt_kill_msk]); 734 bt_cmd->kill_cts_msk = cpu_to_le32(iwl_bt_cts_kill_msk[bt_kill_msk]);
@@ -743,7 +749,7 @@ static int iwl_mvm_bt_udpate_ctrl_kill_msk(struct iwl_mvm *mvm,
743static int iwl_mvm_bt_coex_reduced_txp(struct iwl_mvm *mvm, u8 sta_id, 749static int iwl_mvm_bt_coex_reduced_txp(struct iwl_mvm *mvm, u8 sta_id,
744 bool enable) 750 bool enable)
745{ 751{
746 struct iwl_bt_coex_cmd *bt_cmd; 752 struct iwl_bt_coex_cmd_old *bt_cmd;
747 /* Send ASYNC since this can be sent from an atomic context */ 753 /* Send ASYNC since this can be sent from an atomic context */
748 struct iwl_host_cmd cmd = { 754 struct iwl_host_cmd cmd = {
749 .id = BT_CONFIG, 755 .id = BT_CONFIG,
@@ -766,7 +772,7 @@ static int iwl_mvm_bt_coex_reduced_txp(struct iwl_mvm *mvm, u8 sta_id,
766 if (!bt_cmd) 772 if (!bt_cmd)
767 return -ENOMEM; 773 return -ENOMEM;
768 cmd.data[0] = bt_cmd; 774 cmd.data[0] = bt_cmd;
769 bt_cmd->flags = cpu_to_le32(BT_COEX_NW); 775 bt_cmd->flags = cpu_to_le32(BT_COEX_NW_OLD);
770 776
771 bt_cmd->valid_bit_msk = 777 bt_cmd->valid_bit_msk =
772 cpu_to_le32(BT_VALID_ENABLE | BT_VALID_REDUCED_TX_POWER); 778 cpu_to_le32(BT_VALID_ENABLE | BT_VALID_REDUCED_TX_POWER);
@@ -787,7 +793,7 @@ static int iwl_mvm_bt_coex_reduced_txp(struct iwl_mvm *mvm, u8 sta_id,
787} 793}
788 794
789struct iwl_bt_iterator_data { 795struct iwl_bt_iterator_data {
790 struct iwl_bt_coex_profile_notif *notif; 796 struct iwl_bt_coex_profile_notif_old *notif;
791 struct iwl_mvm *mvm; 797 struct iwl_mvm *mvm;
792 u32 num_bss_ifaces; 798 u32 num_bss_ifaces;
793 bool reduced_tx_power; 799 bool reduced_tx_power;
@@ -977,7 +983,7 @@ static void iwl_mvm_bt_coex_notif_handle(struct iwl_mvm *mvm)
977 .notif = &mvm->last_bt_notif, 983 .notif = &mvm->last_bt_notif,
978 .reduced_tx_power = true, 984 .reduced_tx_power = true,
979 }; 985 };
980 struct iwl_bt_coex_ci_cmd cmd = {}; 986 struct iwl_bt_coex_ci_cmd_old cmd = {};
981 u8 ci_bw_idx; 987 u8 ci_bw_idx;
982 988
983 /* Ignore updates if we are in force mode */ 989 /* Ignore updates if we are in force mode */
@@ -1063,8 +1069,13 @@ int iwl_mvm_rx_bt_coex_notif(struct iwl_mvm *mvm,
1063 struct iwl_device_cmd *dev_cmd) 1069 struct iwl_device_cmd *dev_cmd)
1064{ 1070{
1065 struct iwl_rx_packet *pkt = rxb_addr(rxb); 1071 struct iwl_rx_packet *pkt = rxb_addr(rxb);
1066 struct iwl_bt_coex_profile_notif *notif = (void *)pkt->data; 1072 struct iwl_bt_coex_profile_notif_old *notif = (void *)pkt->data;
1067 1073
1074 if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BT_COEX_SPLIT))
1075 return iwl_mvm_rx_bt_coex_notif_old(mvm, rxb, dev_cmd);
1076
1077 /* TODO */
1078 return 0;
1068 1079
1069 IWL_DEBUG_COEX(mvm, "BT Coex Notification received\n"); 1080 IWL_DEBUG_COEX(mvm, "BT Coex Notification received\n");
1070 IWL_DEBUG_COEX(mvm, "\tBT status: %s\n", 1081 IWL_DEBUG_COEX(mvm, "\tBT status: %s\n",
@@ -1148,6 +1159,14 @@ void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
1148 }; 1159 };
1149 int ret; 1160 int ret;
1150 1161
1162 if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BT_COEX_SPLIT)) {
1163 iwl_mvm_bt_rssi_event_old(mvm, vif, rssi_event);
1164 return;
1165 }
1166
1167 /* TODO */
1168 return;
1169
1151 lockdep_assert_held(&mvm->mutex); 1170 lockdep_assert_held(&mvm->mutex);
1152 1171
1153 /* Ignore updates if we are in force mode */ 1172 /* Ignore updates if we are in force mode */
@@ -1206,6 +1225,12 @@ u16 iwl_mvm_coex_agg_time_limit(struct iwl_mvm *mvm,
1206 struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); 1225 struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
1207 enum iwl_bt_coex_lut_type lut_type; 1226 enum iwl_bt_coex_lut_type lut_type;
1208 1227
1228 if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BT_COEX_SPLIT))
1229 return iwl_mvm_coex_agg_time_limit_old(mvm, sta);
1230
1231 /* TODO */
1232 return LINK_QUAL_AGG_TIME_LIMIT_DEF;
1233
1209 if (le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) < 1234 if (le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) <
1210 BT_HIGH_TRAFFIC) 1235 BT_HIGH_TRAFFIC)
1211 return LINK_QUAL_AGG_TIME_LIMIT_DEF; 1236 return LINK_QUAL_AGG_TIME_LIMIT_DEF;
@@ -1228,6 +1253,12 @@ bool iwl_mvm_bt_coex_is_mimo_allowed(struct iwl_mvm *mvm,
1228 struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); 1253 struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
1229 enum iwl_bt_coex_lut_type lut_type; 1254 enum iwl_bt_coex_lut_type lut_type;
1230 1255
1256 if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BT_COEX_SPLIT))
1257 return iwl_mvm_coex_agg_time_limit_old(mvm, sta);
1258
1259 return true;
1260
1261 /* TODO */
1231 if (mvm->last_bt_notif.ttc_enabled) 1262 if (mvm->last_bt_notif.ttc_enabled)
1232 return true; 1263 return true;
1233 1264
@@ -1248,6 +1279,9 @@ bool iwl_mvm_bt_coex_is_mimo_allowed(struct iwl_mvm *mvm,
1248 1279
1249bool iwl_mvm_bt_coex_is_shared_ant_avail(struct iwl_mvm *mvm) 1280bool iwl_mvm_bt_coex_is_shared_ant_avail(struct iwl_mvm *mvm)
1250{ 1281{
1282 if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BT_COEX_SPLIT))
1283 return iwl_mvm_bt_coex_is_shared_ant_avail_old(mvm);
1284
1251 return le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) == BT_OFF; 1285 return le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) == BT_OFF;
1252} 1286}
1253 1287
@@ -1256,6 +1290,12 @@ bool iwl_mvm_bt_coex_is_tpc_allowed(struct iwl_mvm *mvm,
1256{ 1290{
1257 u32 bt_activity = le32_to_cpu(mvm->last_bt_notif.bt_activity_grading); 1291 u32 bt_activity = le32_to_cpu(mvm->last_bt_notif.bt_activity_grading);
1258 1292
1293 if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BT_COEX_SPLIT))
1294 return iwl_mvm_bt_coex_is_tpc_allowed_old(mvm, band);
1295
1296 /* TODO */
1297 return false;
1298
1259 if (band != IEEE80211_BAND_2GHZ) 1299 if (band != IEEE80211_BAND_2GHZ)
1260 return false; 1300 return false;
1261 1301
@@ -1296,6 +1336,14 @@ u8 iwl_mvm_bt_coex_tx_prio(struct iwl_mvm *mvm, struct ieee80211_hdr *hdr,
1296 1336
1297void iwl_mvm_bt_coex_vif_change(struct iwl_mvm *mvm) 1337void iwl_mvm_bt_coex_vif_change(struct iwl_mvm *mvm)
1298{ 1338{
1339 if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BT_COEX_SPLIT)) {
1340 iwl_mvm_bt_coex_vif_change_old(mvm);
1341 return;
1342 }
1343
1344 /* TODO */
1345 return;
1346
1299 iwl_mvm_bt_coex_notif_handle(mvm); 1347 iwl_mvm_bt_coex_notif_handle(mvm);
1300} 1348}
1301 1349
@@ -1309,13 +1357,19 @@ int iwl_mvm_rx_ant_coupling_notif(struct iwl_mvm *mvm,
1309 int ret; 1357 int ret;
1310 u8 lut; 1358 u8 lut;
1311 1359
1312 struct iwl_bt_coex_cmd *bt_cmd; 1360 struct iwl_bt_coex_cmd_old *bt_cmd;
1313 struct iwl_host_cmd cmd = { 1361 struct iwl_host_cmd cmd = {
1314 .id = BT_CONFIG, 1362 .id = BT_CONFIG,
1315 .len = { sizeof(*bt_cmd), }, 1363 .len = { sizeof(*bt_cmd), },
1316 .dataflags = { IWL_HCMD_DFL_NOCOPY, }, 1364 .dataflags = { IWL_HCMD_DFL_NOCOPY, },
1317 }; 1365 };
1318 1366
1367 if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BT_COEX_SPLIT))
1368 return iwl_mvm_rx_ant_coupling_notif_old(mvm, rxb, dev_cmd);
1369
1370 /* TODO */
1371 return 0;
1372
1319 if (!IWL_MVM_BT_COEX_CORUNNING) 1373 if (!IWL_MVM_BT_COEX_CORUNNING)
1320 return 0; 1374 return 0;
1321 1375
@@ -1354,7 +1408,7 @@ int iwl_mvm_rx_ant_coupling_notif(struct iwl_mvm *mvm,
1354 return 0; 1408 return 0;
1355 cmd.data[0] = bt_cmd; 1409 cmd.data[0] = bt_cmd;
1356 1410
1357 bt_cmd->flags = cpu_to_le32(BT_COEX_NW); 1411 bt_cmd->flags = cpu_to_le32(BT_COEX_NW_OLD);
1358 bt_cmd->valid_bit_msk |= cpu_to_le32(BT_VALID_ENABLE | 1412 bt_cmd->valid_bit_msk |= cpu_to_le32(BT_VALID_ENABLE |
1359 BT_VALID_CORUN_LUT_20 | 1413 BT_VALID_CORUN_LUT_20 |
1360 BT_VALID_CORUN_LUT_40); 1414 BT_VALID_CORUN_LUT_40);
diff --git a/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c b/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c
new file mode 100644
index 000000000000..ce50363d314b
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c
@@ -0,0 +1,1332 @@
1/******************************************************************************
2 *
3 * This file is provided under a dual BSD/GPLv2 license. When using or
4 * redistributing this file, you may do so under either license.
5 *
6 * GPL LICENSE SUMMARY
7 *
8 * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved.
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of version 2 of the GNU General Public License as
12 * published by the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
22 * USA
23 *
24 * The full GNU General Public License is included in this distribution
25 * in the file called COPYING.
26 *
27 * Contact Information:
28 * Intel Linux Wireless <ilw@linux.intel.com>
29 * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
30 *
31 * BSD LICENSE
32 *
33 * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved.
34 * All rights reserved.
35 *
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions
38 * are met:
39 *
40 * * Redistributions of source code must retain the above copyright
41 * notice, this list of conditions and the following disclaimer.
42 * * Redistributions in binary form must reproduce the above copyright
43 * notice, this list of conditions and the following disclaimer in
44 * the documentation and/or other materials provided with the
45 * distribution.
46 * * Neither the name Intel Corporation nor the names of its
47 * contributors may be used to endorse or promote products derived
48 * from this software without specific prior written permission.
49 *
50 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
51 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
52 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
53 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
54 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
55 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
56 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
57 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
58 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
59 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
60 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
61 *
62 *****************************************************************************/
63
64#include <linux/ieee80211.h>
65#include <linux/etherdevice.h>
66#include <net/mac80211.h>
67
68#include "fw-api-coex.h"
69#include "iwl-modparams.h"
70#include "mvm.h"
71#include "iwl-debug.h"
72
73#define EVENT_PRIO_ANT(_evt, _prio, _shrd_ant) \
74 [(_evt)] = (((_prio) << BT_COEX_PRIO_TBL_PRIO_POS) | \
75 ((_shrd_ant) << BT_COEX_PRIO_TBL_SHRD_ANT_POS))
76
77static const u8 iwl_bt_prio_tbl[BT_COEX_PRIO_TBL_EVT_MAX] = {
78 EVENT_PRIO_ANT(BT_COEX_PRIO_TBL_EVT_INIT_CALIB1,
79 BT_COEX_PRIO_TBL_PRIO_BYPASS, 0),
80 EVENT_PRIO_ANT(BT_COEX_PRIO_TBL_EVT_INIT_CALIB2,
81 BT_COEX_PRIO_TBL_PRIO_BYPASS, 1),
82 EVENT_PRIO_ANT(BT_COEX_PRIO_TBL_EVT_PERIODIC_CALIB_LOW1,
83 BT_COEX_PRIO_TBL_PRIO_LOW, 0),
84 EVENT_PRIO_ANT(BT_COEX_PRIO_TBL_EVT_PERIODIC_CALIB_LOW2,
85 BT_COEX_PRIO_TBL_PRIO_LOW, 1),
86 EVENT_PRIO_ANT(BT_COEX_PRIO_TBL_EVT_PERIODIC_CALIB_HIGH1,
87 BT_COEX_PRIO_TBL_PRIO_HIGH, 0),
88 EVENT_PRIO_ANT(BT_COEX_PRIO_TBL_EVT_PERIODIC_CALIB_HIGH2,
89 BT_COEX_PRIO_TBL_PRIO_HIGH, 1),
90 EVENT_PRIO_ANT(BT_COEX_PRIO_TBL_EVT_DTIM,
91 BT_COEX_PRIO_TBL_DISABLED, 0),
92 EVENT_PRIO_ANT(BT_COEX_PRIO_TBL_EVT_SCAN52,
93 BT_COEX_PRIO_TBL_PRIO_COEX_OFF, 0),
94 EVENT_PRIO_ANT(BT_COEX_PRIO_TBL_EVT_SCAN24,
95 BT_COEX_PRIO_TBL_PRIO_COEX_ON, 0),
96 EVENT_PRIO_ANT(BT_COEX_PRIO_TBL_EVT_IDLE,
97 BT_COEX_PRIO_TBL_PRIO_COEX_IDLE, 0),
98 0, 0, 0, 0, 0, 0,
99};
100
101#undef EVENT_PRIO_ANT
102
103#define BT_ANTENNA_COUPLING_THRESHOLD (30)
104
105static int iwl_send_bt_prio_tbl(struct iwl_mvm *mvm)
106{
107 if (unlikely(mvm->bt_force_ant_mode != BT_FORCE_ANT_DIS))
108 return 0;
109
110 return iwl_mvm_send_cmd_pdu(mvm, BT_COEX_PRIO_TABLE, 0,
111 sizeof(struct iwl_bt_coex_prio_tbl_cmd),
112 &iwl_bt_prio_tbl);
113}
114
115static const __le32 iwl_bt_prio_boost[BT_COEX_BOOST_SIZE] = {
116 cpu_to_le32(0xf0f0f0f0), /* 50% */
117 cpu_to_le32(0xc0c0c0c0), /* 25% */
118 cpu_to_le32(0xfcfcfcfc), /* 75% */
119 cpu_to_le32(0xfefefefe), /* 87.5% */
120};
121
122static const __le32 iwl_single_shared_ant[BT_COEX_MAX_LUT][BT_COEX_LUT_SIZE] = {
123 {
124 cpu_to_le32(0x40000000),
125 cpu_to_le32(0x00000000),
126 cpu_to_le32(0x44000000),
127 cpu_to_le32(0x00000000),
128 cpu_to_le32(0x40000000),
129 cpu_to_le32(0x00000000),
130 cpu_to_le32(0x44000000),
131 cpu_to_le32(0x00000000),
132 cpu_to_le32(0xc0004000),
133 cpu_to_le32(0xf0005000),
134 cpu_to_le32(0xc0004000),
135 cpu_to_le32(0xf0005000),
136 },
137 {
138 cpu_to_le32(0x40000000),
139 cpu_to_le32(0x00000000),
140 cpu_to_le32(0x44000000),
141 cpu_to_le32(0x00000000),
142 cpu_to_le32(0x40000000),
143 cpu_to_le32(0x00000000),
144 cpu_to_le32(0x44000000),
145 cpu_to_le32(0x00000000),
146 cpu_to_le32(0xc0004000),
147 cpu_to_le32(0xf0005000),
148 cpu_to_le32(0xc0004000),
149 cpu_to_le32(0xf0005000),
150 },
151 {
152 cpu_to_le32(0x40000000),
153 cpu_to_le32(0x00000000),
154 cpu_to_le32(0x44000000),
155 cpu_to_le32(0x00000000),
156 cpu_to_le32(0x40000000),
157 cpu_to_le32(0x00000000),
158 cpu_to_le32(0x44000000),
159 cpu_to_le32(0x00000000),
160 cpu_to_le32(0xc0004000),
161 cpu_to_le32(0xf0005000),
162 cpu_to_le32(0xc0004000),
163 cpu_to_le32(0xf0005000),
164 },
165};
166
167static const __le32 iwl_combined_lookup[BT_COEX_MAX_LUT][BT_COEX_LUT_SIZE] = {
168 {
169 /* Tight */
170 cpu_to_le32(0xaaaaaaaa),
171 cpu_to_le32(0xaaaaaaaa),
172 cpu_to_le32(0xaeaaaaaa),
173 cpu_to_le32(0xaaaaaaaa),
174 cpu_to_le32(0xcc00ff28),
175 cpu_to_le32(0x0000aaaa),
176 cpu_to_le32(0xcc00aaaa),
177 cpu_to_le32(0x0000aaaa),
178 cpu_to_le32(0xc0004000),
179 cpu_to_le32(0x00004000),
180 cpu_to_le32(0xf0005000),
181 cpu_to_le32(0xf0005000),
182 },
183 {
184 /* Loose */
185 cpu_to_le32(0xaaaaaaaa),
186 cpu_to_le32(0xaaaaaaaa),
187 cpu_to_le32(0xaaaaaaaa),
188 cpu_to_le32(0xaaaaaaaa),
189 cpu_to_le32(0xcc00ff28),
190 cpu_to_le32(0x0000aaaa),
191 cpu_to_le32(0xcc00aaaa),
192 cpu_to_le32(0x0000aaaa),
193 cpu_to_le32(0x00000000),
194 cpu_to_le32(0x00000000),
195 cpu_to_le32(0xf0005000),
196 cpu_to_le32(0xf0005000),
197 },
198 {
199 /* Tx Tx disabled */
200 cpu_to_le32(0xaaaaaaaa),
201 cpu_to_le32(0xaaaaaaaa),
202 cpu_to_le32(0xeeaaaaaa),
203 cpu_to_le32(0xaaaaaaaa),
204 cpu_to_le32(0xcc00ff28),
205 cpu_to_le32(0x0000aaaa),
206 cpu_to_le32(0xcc00aaaa),
207 cpu_to_le32(0x0000aaaa),
208 cpu_to_le32(0xc0004000),
209 cpu_to_le32(0xc0004000),
210 cpu_to_le32(0xf0005000),
211 cpu_to_le32(0xf0005000),
212 },
213};
214
215/* 20MHz / 40MHz below / 40Mhz above*/
216static const __le64 iwl_ci_mask[][3] = {
217 /* dummy entry for channel 0 */
218 {cpu_to_le64(0), cpu_to_le64(0), cpu_to_le64(0)},
219 {
220 cpu_to_le64(0x0000001FFFULL),
221 cpu_to_le64(0x0ULL),
222 cpu_to_le64(0x00007FFFFFULL),
223 },
224 {
225 cpu_to_le64(0x000000FFFFULL),
226 cpu_to_le64(0x0ULL),
227 cpu_to_le64(0x0003FFFFFFULL),
228 },
229 {
230 cpu_to_le64(0x000003FFFCULL),
231 cpu_to_le64(0x0ULL),
232 cpu_to_le64(0x000FFFFFFCULL),
233 },
234 {
235 cpu_to_le64(0x00001FFFE0ULL),
236 cpu_to_le64(0x0ULL),
237 cpu_to_le64(0x007FFFFFE0ULL),
238 },
239 {
240 cpu_to_le64(0x00007FFF80ULL),
241 cpu_to_le64(0x00007FFFFFULL),
242 cpu_to_le64(0x01FFFFFF80ULL),
243 },
244 {
245 cpu_to_le64(0x0003FFFC00ULL),
246 cpu_to_le64(0x0003FFFFFFULL),
247 cpu_to_le64(0x0FFFFFFC00ULL),
248 },
249 {
250 cpu_to_le64(0x000FFFF000ULL),
251 cpu_to_le64(0x000FFFFFFCULL),
252 cpu_to_le64(0x3FFFFFF000ULL),
253 },
254 {
255 cpu_to_le64(0x007FFF8000ULL),
256 cpu_to_le64(0x007FFFFFE0ULL),
257 cpu_to_le64(0xFFFFFF8000ULL),
258 },
259 {
260 cpu_to_le64(0x01FFFE0000ULL),
261 cpu_to_le64(0x01FFFFFF80ULL),
262 cpu_to_le64(0xFFFFFE0000ULL),
263 },
264 {
265 cpu_to_le64(0x0FFFF00000ULL),
266 cpu_to_le64(0x0FFFFFFC00ULL),
267 cpu_to_le64(0x0ULL),
268 },
269 {
270 cpu_to_le64(0x3FFFC00000ULL),
271 cpu_to_le64(0x3FFFFFF000ULL),
272 cpu_to_le64(0x0)
273 },
274 {
275 cpu_to_le64(0xFFFE000000ULL),
276 cpu_to_le64(0xFFFFFF8000ULL),
277 cpu_to_le64(0x0)
278 },
279 {
280 cpu_to_le64(0xFFF8000000ULL),
281 cpu_to_le64(0xFFFFFE0000ULL),
282 cpu_to_le64(0x0)
283 },
284 {
285 cpu_to_le64(0xFFC0000000ULL),
286 cpu_to_le64(0x0ULL),
287 cpu_to_le64(0x0ULL)
288 },
289};
290
291static const __le32 iwl_bt_mprio_lut[BT_COEX_MULTI_PRIO_LUT_SIZE] = {
292 cpu_to_le32(0x28412201),
293 cpu_to_le32(0x11118451),
294};
295
296struct corunning_block_luts {
297 u8 range;
298 __le32 lut20[BT_COEX_CORUN_LUT_SIZE];
299};
300
301/*
302 * Ranges for the antenna coupling calibration / co-running block LUT:
303 * LUT0: [ 0, 12[
304 * LUT1: [12, 20[
305 * LUT2: [20, 21[
306 * LUT3: [21, 23[
307 * LUT4: [23, 27[
308 * LUT5: [27, 30[
309 * LUT6: [30, 32[
310 * LUT7: [32, 33[
311 * LUT8: [33, - [
312 */
313static const struct corunning_block_luts antenna_coupling_ranges[] = {
314 {
315 .range = 0,
316 .lut20 = {
317 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
318 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
319 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
320 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
321 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
322 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
323 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
324 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
325 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
326 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
327 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
328 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
329 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
330 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
331 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
332 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
333 },
334 },
335 {
336 .range = 12,
337 .lut20 = {
338 cpu_to_le32(0x00000001), cpu_to_le32(0x00000000),
339 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
340 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
341 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
342 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
343 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
344 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
345 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
346 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
347 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
348 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
349 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
350 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
351 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
352 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
353 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
354 },
355 },
356 {
357 .range = 20,
358 .lut20 = {
359 cpu_to_le32(0x00000002), cpu_to_le32(0x00000000),
360 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
361 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
362 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
363 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
364 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
365 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
366 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
367 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
368 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
369 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
370 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
371 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
372 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
373 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
374 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
375 },
376 },
377 {
378 .range = 21,
379 .lut20 = {
380 cpu_to_le32(0x00000003), cpu_to_le32(0x00000000),
381 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
382 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
383 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
384 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
385 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
386 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
387 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
388 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
389 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
390 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
391 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
392 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
393 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
394 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
395 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
396 },
397 },
398 {
399 .range = 23,
400 .lut20 = {
401 cpu_to_le32(0x00000004), cpu_to_le32(0x00000000),
402 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
403 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
404 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
405 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
406 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
407 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
408 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
409 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
410 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
411 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
412 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
413 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
414 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
415 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
416 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
417 },
418 },
419 {
420 .range = 27,
421 .lut20 = {
422 cpu_to_le32(0x00000005), cpu_to_le32(0x00000000),
423 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
424 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
425 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
426 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
427 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
428 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
429 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
430 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
431 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
432 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
433 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
434 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
435 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
436 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
437 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
438 },
439 },
440 {
441 .range = 30,
442 .lut20 = {
443 cpu_to_le32(0x00000006), cpu_to_le32(0x00000000),
444 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
445 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
446 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
447 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
448 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
449 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
450 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
451 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
452 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
453 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
454 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
455 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
456 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
457 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
458 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
459 },
460 },
461 {
462 .range = 32,
463 .lut20 = {
464 cpu_to_le32(0x00000007), cpu_to_le32(0x00000000),
465 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
466 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
467 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
468 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
469 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
470 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
471 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
472 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
473 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
474 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
475 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
476 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
477 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
478 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
479 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
480 },
481 },
482 {
483 .range = 33,
484 .lut20 = {
485 cpu_to_le32(0x00000008), cpu_to_le32(0x00000000),
486 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
487 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
488 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
489 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
490 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
491 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
492 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
493 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
494 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
495 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
496 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
497 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
498 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
499 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
500 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
501 },
502 },
503};
504
505static enum iwl_bt_coex_lut_type
506iwl_get_coex_type(struct iwl_mvm *mvm, const struct ieee80211_vif *vif)
507{
508 struct ieee80211_chanctx_conf *chanctx_conf;
509 enum iwl_bt_coex_lut_type ret;
510 u16 phy_ctx_id;
511
512 /*
513 * Checking that we hold mvm->mutex is a good idea, but the rate
514 * control can't acquire the mutex since it runs in Tx path.
515 * So this is racy in that case, but in the worst case, the AMPDU
516 * size limit will be wrong for a short time which is not a big
517 * issue.
518 */
519
520 rcu_read_lock();
521
522 chanctx_conf = rcu_dereference(vif->chanctx_conf);
523
524 if (!chanctx_conf ||
525 chanctx_conf->def.chan->band != IEEE80211_BAND_2GHZ) {
526 rcu_read_unlock();
527 return BT_COEX_INVALID_LUT;
528 }
529
530 ret = BT_COEX_TX_DIS_LUT;
531
532 if (mvm->cfg->bt_shared_single_ant) {
533 rcu_read_unlock();
534 return ret;
535 }
536
537 phy_ctx_id = *((u16 *)chanctx_conf->drv_priv);
538
539 if (mvm->last_bt_ci_cmd_old.primary_ch_phy_id == phy_ctx_id)
540 ret = le32_to_cpu(mvm->last_bt_notif_old.primary_ch_lut);
541 else if (mvm->last_bt_ci_cmd_old.secondary_ch_phy_id == phy_ctx_id)
542 ret = le32_to_cpu(mvm->last_bt_notif_old.secondary_ch_lut);
543 /* else - default = TX TX disallowed */
544
545 rcu_read_unlock();
546
547 return ret;
548}
549
550int iwl_send_bt_init_conf_old(struct iwl_mvm *mvm)
551{
552 struct iwl_bt_coex_cmd_old *bt_cmd;
553 struct iwl_host_cmd cmd = {
554 .id = BT_CONFIG,
555 .len = { sizeof(*bt_cmd), },
556 .dataflags = { IWL_HCMD_DFL_NOCOPY, },
557 };
558 int ret;
559 u32 flags;
560
561 ret = iwl_send_bt_prio_tbl(mvm);
562 if (ret)
563 return ret;
564
565 bt_cmd = kzalloc(sizeof(*bt_cmd), GFP_KERNEL);
566 if (!bt_cmd)
567 return -ENOMEM;
568 cmd.data[0] = bt_cmd;
569
570 lockdep_assert_held(&mvm->mutex);
571
572 if (unlikely(mvm->bt_force_ant_mode != BT_FORCE_ANT_DIS)) {
573 switch (mvm->bt_force_ant_mode) {
574 case BT_FORCE_ANT_AUTO:
575 flags = BT_COEX_AUTO_OLD;
576 break;
577 case BT_FORCE_ANT_BT:
578 flags = BT_COEX_BT_OLD;
579 break;
580 case BT_FORCE_ANT_WIFI:
581 flags = BT_COEX_WIFI_OLD;
582 break;
583 default:
584 WARN_ON(1);
585 flags = 0;
586 }
587
588 bt_cmd->flags = cpu_to_le32(flags);
589 bt_cmd->valid_bit_msk = cpu_to_le32(BT_VALID_ENABLE);
590 goto send_cmd;
591 }
592
593 bt_cmd->max_kill = 5;
594 bt_cmd->bt4_antenna_isolation_thr = BT_ANTENNA_COUPLING_THRESHOLD;
595 bt_cmd->bt4_antenna_isolation = iwlwifi_mod_params.ant_coupling;
596 bt_cmd->bt4_tx_tx_delta_freq_thr = 15;
597 bt_cmd->bt4_tx_rx_max_freq0 = 15;
598 bt_cmd->override_primary_lut = BT_COEX_INVALID_LUT;
599 bt_cmd->override_secondary_lut = BT_COEX_INVALID_LUT;
600
601 flags = iwlwifi_mod_params.bt_coex_active ?
602 BT_COEX_NW_OLD : BT_COEX_DISABLE_OLD;
603 bt_cmd->flags = cpu_to_le32(flags);
604
605 bt_cmd->valid_bit_msk = cpu_to_le32(BT_VALID_ENABLE |
606 BT_VALID_BT_PRIO_BOOST |
607 BT_VALID_MAX_KILL |
608 BT_VALID_3W_TMRS |
609 BT_VALID_KILL_ACK |
610 BT_VALID_KILL_CTS |
611 BT_VALID_REDUCED_TX_POWER |
612 BT_VALID_LUT |
613 BT_VALID_WIFI_RX_SW_PRIO_BOOST |
614 BT_VALID_WIFI_TX_SW_PRIO_BOOST |
615 BT_VALID_ANT_ISOLATION |
616 BT_VALID_ANT_ISOLATION_THRS |
617 BT_VALID_TXTX_DELTA_FREQ_THRS |
618 BT_VALID_TXRX_MAX_FREQ_0 |
619 BT_VALID_SYNC_TO_SCO);
620
621 if (IWL_MVM_BT_COEX_SYNC2SCO)
622 bt_cmd->flags |= cpu_to_le32(BT_COEX_SYNC2SCO);
623
624 if (IWL_MVM_BT_COEX_CORUNNING) {
625 bt_cmd->valid_bit_msk |= cpu_to_le32(BT_VALID_CORUN_LUT_20 |
626 BT_VALID_CORUN_LUT_40);
627 bt_cmd->flags |= cpu_to_le32(BT_COEX_CORUNNING);
628 }
629
630 if (IWL_MVM_BT_COEX_MPLUT) {
631 bt_cmd->flags |= cpu_to_le32(BT_COEX_MPLUT);
632 bt_cmd->valid_bit_msk |= cpu_to_le32(BT_VALID_MULTI_PRIO_LUT);
633 }
634
635 if (mvm->cfg->bt_shared_single_ant)
636 memcpy(&bt_cmd->decision_lut, iwl_single_shared_ant,
637 sizeof(iwl_single_shared_ant));
638 else
639 memcpy(&bt_cmd->decision_lut, iwl_combined_lookup,
640 sizeof(iwl_combined_lookup));
641
642 /* Take first Co-running block LUT to get started */
643 memcpy(bt_cmd->bt4_corun_lut20, antenna_coupling_ranges[0].lut20,
644 sizeof(bt_cmd->bt4_corun_lut20));
645 memcpy(bt_cmd->bt4_corun_lut40, antenna_coupling_ranges[0].lut20,
646 sizeof(bt_cmd->bt4_corun_lut40));
647
648 memcpy(&bt_cmd->bt_prio_boost, iwl_bt_prio_boost,
649 sizeof(iwl_bt_prio_boost));
650 memcpy(&bt_cmd->bt4_multiprio_lut, iwl_bt_mprio_lut,
651 sizeof(iwl_bt_mprio_lut));
652 bt_cmd->kill_ack_msk =
653 cpu_to_le32(iwl_bt_ack_kill_msk[BT_KILL_MSK_DEFAULT]);
654 bt_cmd->kill_cts_msk =
655 cpu_to_le32(iwl_bt_cts_kill_msk[BT_KILL_MSK_DEFAULT]);
656
657send_cmd:
658 memset(&mvm->last_bt_notif_old, 0, sizeof(mvm->last_bt_notif_old));
659 memset(&mvm->last_bt_ci_cmd_old, 0, sizeof(mvm->last_bt_ci_cmd_old));
660
661 ret = iwl_mvm_send_cmd(mvm, &cmd);
662
663 kfree(bt_cmd);
664 return ret;
665}
666
667static int iwl_mvm_bt_udpate_ctrl_kill_msk(struct iwl_mvm *mvm,
668 bool reduced_tx_power)
669{
670 enum iwl_bt_kill_msk bt_kill_msk;
671 struct iwl_bt_coex_cmd_old *bt_cmd;
672 struct iwl_bt_coex_profile_notif_old *notif = &mvm->last_bt_notif_old;
673 struct iwl_host_cmd cmd = {
674 .id = BT_CONFIG,
675 .data[0] = &bt_cmd,
676 .len = { sizeof(*bt_cmd), },
677 .dataflags = { IWL_HCMD_DFL_NOCOPY, },
678 };
679 int ret = 0;
680
681 lockdep_assert_held(&mvm->mutex);
682
683 if (reduced_tx_power) {
684 /* Reduced Tx power has precedence on the type of the profile */
685 bt_kill_msk = BT_KILL_MSK_REDUCED_TXPOW;
686 } else {
687 /* Low latency BT profile is active: give higher prio to BT */
688 if (BT_MBOX_MSG(notif, 3, SCO_STATE) ||
689 BT_MBOX_MSG(notif, 3, A2DP_STATE) ||
690 BT_MBOX_MSG(notif, 3, SNIFF_STATE))
691 bt_kill_msk = BT_KILL_MSK_SCO_HID_A2DP;
692 else
693 bt_kill_msk = BT_KILL_MSK_DEFAULT;
694 }
695
696 IWL_DEBUG_COEX(mvm,
697 "Update kill_msk: %d - SCO %sactive A2DP %sactive SNIFF %sactive\n",
698 bt_kill_msk,
699 BT_MBOX_MSG(notif, 3, SCO_STATE) ? "" : "in",
700 BT_MBOX_MSG(notif, 3, A2DP_STATE) ? "" : "in",
701 BT_MBOX_MSG(notif, 3, SNIFF_STATE) ? "" : "in");
702
703 /* Don't send HCMD if there is no update */
704 if (bt_kill_msk == mvm->bt_kill_msk)
705 return 0;
706
707 mvm->bt_kill_msk = bt_kill_msk;
708
709 bt_cmd = kzalloc(sizeof(*bt_cmd), GFP_KERNEL);
710 if (!bt_cmd)
711 return -ENOMEM;
712 cmd.data[0] = bt_cmd;
713 bt_cmd->flags = cpu_to_le32(BT_COEX_NW_OLD);
714
715 bt_cmd->kill_ack_msk = cpu_to_le32(iwl_bt_ack_kill_msk[bt_kill_msk]);
716 bt_cmd->kill_cts_msk = cpu_to_le32(iwl_bt_cts_kill_msk[bt_kill_msk]);
717 bt_cmd->valid_bit_msk |= cpu_to_le32(BT_VALID_ENABLE |
718 BT_VALID_KILL_ACK |
719 BT_VALID_KILL_CTS);
720
721 IWL_DEBUG_COEX(mvm, "ACK Kill msk = 0x%08x, CTS Kill msk = 0x%08x\n",
722 iwl_bt_ack_kill_msk[bt_kill_msk],
723 iwl_bt_cts_kill_msk[bt_kill_msk]);
724
725 ret = iwl_mvm_send_cmd(mvm, &cmd);
726
727 kfree(bt_cmd);
728 return ret;
729}
730
731static int iwl_mvm_bt_coex_reduced_txp(struct iwl_mvm *mvm, u8 sta_id,
732 bool enable)
733{
734 struct iwl_bt_coex_cmd_old *bt_cmd;
735 /* Send ASYNC since this can be sent from an atomic context */
736 struct iwl_host_cmd cmd = {
737 .id = BT_CONFIG,
738 .len = { sizeof(*bt_cmd), },
739 .dataflags = { IWL_HCMD_DFL_NOCOPY, },
740 .flags = CMD_ASYNC,
741 };
742 struct iwl_mvm_sta *mvmsta;
743 int ret;
744
745 mvmsta = iwl_mvm_sta_from_staid_protected(mvm, sta_id);
746 if (!mvmsta)
747 return 0;
748
749 /* nothing to do */
750 if (mvmsta->bt_reduced_txpower == enable)
751 return 0;
752
753 bt_cmd = kzalloc(sizeof(*bt_cmd), GFP_ATOMIC);
754 if (!bt_cmd)
755 return -ENOMEM;
756 cmd.data[0] = bt_cmd;
757 bt_cmd->flags = cpu_to_le32(BT_COEX_NW_OLD);
758
759 bt_cmd->valid_bit_msk =
760 cpu_to_le32(BT_VALID_ENABLE | BT_VALID_REDUCED_TX_POWER);
761 bt_cmd->bt_reduced_tx_power = sta_id;
762
763 if (enable)
764 bt_cmd->bt_reduced_tx_power |= BT_REDUCED_TX_POWER_BIT;
765
766 IWL_DEBUG_COEX(mvm, "%sable reduced Tx Power for sta %d\n",
767 enable ? "en" : "dis", sta_id);
768
769 mvmsta->bt_reduced_txpower = enable;
770
771 ret = iwl_mvm_send_cmd(mvm, &cmd);
772
773 kfree(bt_cmd);
774 return ret;
775}
776
777struct iwl_bt_iterator_data {
778 struct iwl_bt_coex_profile_notif_old *notif;
779 struct iwl_mvm *mvm;
780 u32 num_bss_ifaces;
781 bool reduced_tx_power;
782 struct ieee80211_chanctx_conf *primary;
783 struct ieee80211_chanctx_conf *secondary;
784 bool primary_ll;
785};
786
787static inline
788void iwl_mvm_bt_coex_enable_rssi_event(struct iwl_mvm *mvm,
789 struct ieee80211_vif *vif,
790 bool enable, int rssi)
791{
792 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
793
794 mvmvif->bf_data.last_bt_coex_event = rssi;
795 mvmvif->bf_data.bt_coex_max_thold =
796 enable ? -IWL_MVM_BT_COEX_EN_RED_TXP_THRESH : 0;
797 mvmvif->bf_data.bt_coex_min_thold =
798 enable ? -IWL_MVM_BT_COEX_DIS_RED_TXP_THRESH : 0;
799}
800
801/* must be called under rcu_read_lock */
802static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac,
803 struct ieee80211_vif *vif)
804{
805 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
806 struct iwl_bt_iterator_data *data = _data;
807 struct iwl_mvm *mvm = data->mvm;
808 struct ieee80211_chanctx_conf *chanctx_conf;
809 enum ieee80211_smps_mode smps_mode;
810 u32 bt_activity_grading;
811 int ave_rssi;
812
813 lockdep_assert_held(&mvm->mutex);
814
815 switch (vif->type) {
816 case NL80211_IFTYPE_STATION:
817 /* Count BSSes vifs */
818 data->num_bss_ifaces++;
819 /* default smps_mode for BSS / P2P client is AUTOMATIC */
820 smps_mode = IEEE80211_SMPS_AUTOMATIC;
821 break;
822 case NL80211_IFTYPE_AP:
823 /* default smps_mode for AP / GO is OFF */
824 smps_mode = IEEE80211_SMPS_OFF;
825 if (!mvmvif->ap_ibss_active) {
826 iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX,
827 smps_mode);
828 return;
829 }
830
831 /* the Ack / Cts kill mask must be default if AP / GO */
832 data->reduced_tx_power = false;
833 break;
834 default:
835 return;
836 }
837
838 chanctx_conf = rcu_dereference(vif->chanctx_conf);
839
840 /* If channel context is invalid or not on 2.4GHz .. */
841 if ((!chanctx_conf ||
842 chanctx_conf->def.chan->band != IEEE80211_BAND_2GHZ)) {
843 /* ... relax constraints and disable rssi events */
844 iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX,
845 smps_mode);
846 data->reduced_tx_power = false;
847 if (vif->type == NL80211_IFTYPE_STATION) {
848 iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id,
849 false);
850 iwl_mvm_bt_coex_enable_rssi_event(mvm, vif, false, 0);
851 }
852 return;
853 }
854
855 bt_activity_grading = le32_to_cpu(data->notif->bt_activity_grading);
856 if (bt_activity_grading >= BT_HIGH_TRAFFIC)
857 smps_mode = IEEE80211_SMPS_STATIC;
858 else if (bt_activity_grading >= BT_LOW_TRAFFIC)
859 smps_mode = vif->type == NL80211_IFTYPE_AP ?
860 IEEE80211_SMPS_OFF :
861 IEEE80211_SMPS_DYNAMIC;
862
863 /* relax SMPS contraints for next association */
864 if (!vif->bss_conf.assoc)
865 smps_mode = IEEE80211_SMPS_AUTOMATIC;
866
867 IWL_DEBUG_COEX(data->mvm,
868 "mac %d: bt_status %d bt_activity_grading %d smps_req %d\n",
869 mvmvif->id, data->notif->bt_status, bt_activity_grading,
870 smps_mode);
871
872 iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX, smps_mode);
873
874 /* low latency is always primary */
875 if (iwl_mvm_vif_low_latency(mvmvif)) {
876 data->primary_ll = true;
877
878 data->secondary = data->primary;
879 data->primary = chanctx_conf;
880 }
881
882 if (vif->type == NL80211_IFTYPE_AP) {
883 if (!mvmvif->ap_ibss_active)
884 return;
885
886 if (chanctx_conf == data->primary)
887 return;
888
889 if (!data->primary_ll) {
890 /*
891 * downgrade the current primary no matter what its
892 * type is.
893 */
894 data->secondary = data->primary;
895 data->primary = chanctx_conf;
896 } else {
897 /* there is low latency vif - we will be secondary */
898 data->secondary = chanctx_conf;
899 }
900 return;
901 }
902
903 /*
904 * STA / P2P Client, try to be primary if first vif. If we are in low
905 * latency mode, we are already in primary and just don't do much
906 */
907 if (!data->primary || data->primary == chanctx_conf)
908 data->primary = chanctx_conf;
909 else if (!data->secondary)
910 /* if secondary is not NULL, it might be a GO */
911 data->secondary = chanctx_conf;
912
913 /*
914 * don't reduce the Tx power if one of these is true:
915 * we are in LOOSE
916 * single share antenna product
917 * BT is active
918 * we are associated
919 */
920 if (iwl_get_coex_type(mvm, vif) == BT_COEX_LOOSE_LUT ||
921 mvm->cfg->bt_shared_single_ant || !vif->bss_conf.assoc ||
922 !data->notif->bt_status) {
923 data->reduced_tx_power = false;
924 iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, false);
925 iwl_mvm_bt_coex_enable_rssi_event(mvm, vif, false, 0);
926 return;
927 }
928
929 /* try to get the avg rssi from fw */
930 ave_rssi = mvmvif->bf_data.ave_beacon_signal;
931
932 /* if the RSSI isn't valid, fake it is very low */
933 if (!ave_rssi)
934 ave_rssi = -100;
935 if (ave_rssi > -IWL_MVM_BT_COEX_EN_RED_TXP_THRESH) {
936 if (iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, true))
937 IWL_ERR(mvm, "Couldn't send BT_CONFIG cmd\n");
938
939 /*
940 * bt_kill_msk can be BT_KILL_MSK_REDUCED_TXPOW only if all the
941 * BSS / P2P clients have rssi above threshold.
942 * We set the bt_kill_msk to BT_KILL_MSK_REDUCED_TXPOW before
943 * the iteration, if one interface's rssi isn't good enough,
944 * bt_kill_msk will be set to default values.
945 */
946 } else if (ave_rssi < -IWL_MVM_BT_COEX_DIS_RED_TXP_THRESH) {
947 if (iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, false))
948 IWL_ERR(mvm, "Couldn't send BT_CONFIG cmd\n");
949
950 /*
951 * One interface hasn't rssi above threshold, bt_kill_msk must
952 * be set to default values.
953 */
954 data->reduced_tx_power = false;
955 }
956
957 /* Begin to monitor the RSSI: it may influence the reduced Tx power */
958 iwl_mvm_bt_coex_enable_rssi_event(mvm, vif, true, ave_rssi);
959}
960
961static void iwl_mvm_bt_coex_notif_handle(struct iwl_mvm *mvm)
962{
963 struct iwl_bt_iterator_data data = {
964 .mvm = mvm,
965 .notif = &mvm->last_bt_notif_old,
966 .reduced_tx_power = true,
967 };
968 struct iwl_bt_coex_ci_cmd_old cmd = {};
969 u8 ci_bw_idx;
970
971 /* Ignore updates if we are in force mode */
972 if (unlikely(mvm->bt_force_ant_mode != BT_FORCE_ANT_DIS))
973 return;
974
975 rcu_read_lock();
976 ieee80211_iterate_active_interfaces_atomic(
977 mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
978 iwl_mvm_bt_notif_iterator, &data);
979
980 if (data.primary) {
981 struct ieee80211_chanctx_conf *chan = data.primary;
982
983 if (WARN_ON(!chan->def.chan)) {
984 rcu_read_unlock();
985 return;
986 }
987
988 if (chan->def.width < NL80211_CHAN_WIDTH_40) {
989 ci_bw_idx = 0;
990 cmd.co_run_bw_primary = 0;
991 } else {
992 cmd.co_run_bw_primary = 1;
993 if (chan->def.center_freq1 >
994 chan->def.chan->center_freq)
995 ci_bw_idx = 2;
996 else
997 ci_bw_idx = 1;
998 }
999
1000 cmd.bt_primary_ci =
1001 iwl_ci_mask[chan->def.chan->hw_value][ci_bw_idx];
1002 cmd.primary_ch_phy_id = *((u16 *)data.primary->drv_priv);
1003 }
1004
1005 if (data.secondary) {
1006 struct ieee80211_chanctx_conf *chan = data.secondary;
1007
1008 if (WARN_ON(!data.secondary->def.chan)) {
1009 rcu_read_unlock();
1010 return;
1011 }
1012
1013 if (chan->def.width < NL80211_CHAN_WIDTH_40) {
1014 ci_bw_idx = 0;
1015 cmd.co_run_bw_secondary = 0;
1016 } else {
1017 cmd.co_run_bw_secondary = 1;
1018 if (chan->def.center_freq1 >
1019 chan->def.chan->center_freq)
1020 ci_bw_idx = 2;
1021 else
1022 ci_bw_idx = 1;
1023 }
1024
1025 cmd.bt_secondary_ci =
1026 iwl_ci_mask[chan->def.chan->hw_value][ci_bw_idx];
1027 cmd.secondary_ch_phy_id = *((u16 *)data.secondary->drv_priv);
1028 }
1029
1030 rcu_read_unlock();
1031
1032 /* Don't spam the fw with the same command over and over */
1033 if (memcmp(&cmd, &mvm->last_bt_ci_cmd_old, sizeof(cmd))) {
1034 if (iwl_mvm_send_cmd_pdu(mvm, BT_COEX_CI, 0,
1035 sizeof(cmd), &cmd))
1036 IWL_ERR(mvm, "Failed to send BT_CI cmd\n");
1037 memcpy(&mvm->last_bt_ci_cmd_old, &cmd, sizeof(cmd));
1038 }
1039
1040 /*
1041 * If there are no BSS / P2P client interfaces, reduced Tx Power is
1042 * irrelevant since it is based on the RSSI coming from the beacon.
1043 * Use BT_KILL_MSK_DEFAULT in that case.
1044 */
1045 data.reduced_tx_power = data.reduced_tx_power && data.num_bss_ifaces;
1046
1047 if (iwl_mvm_bt_udpate_ctrl_kill_msk(mvm, data.reduced_tx_power))
1048 IWL_ERR(mvm, "Failed to update the ctrl_kill_msk\n");
1049}
1050
1051int iwl_mvm_rx_bt_coex_notif_old(struct iwl_mvm *mvm,
1052 struct iwl_rx_cmd_buffer *rxb,
1053 struct iwl_device_cmd *dev_cmd)
1054{
1055 struct iwl_rx_packet *pkt = rxb_addr(rxb);
1056 struct iwl_bt_coex_profile_notif_old *notif = (void *)pkt->data;
1057
1058 IWL_DEBUG_COEX(mvm, "BT Coex Notification received\n");
1059 IWL_DEBUG_COEX(mvm, "\tBT status: %s\n",
1060 notif->bt_status ? "ON" : "OFF");
1061 IWL_DEBUG_COEX(mvm, "\tBT open conn %d\n", notif->bt_open_conn);
1062 IWL_DEBUG_COEX(mvm, "\tBT ci compliance %d\n", notif->bt_ci_compliance);
1063 IWL_DEBUG_COEX(mvm, "\tBT primary_ch_lut %d\n",
1064 le32_to_cpu(notif->primary_ch_lut));
1065 IWL_DEBUG_COEX(mvm, "\tBT secondary_ch_lut %d\n",
1066 le32_to_cpu(notif->secondary_ch_lut));
1067 IWL_DEBUG_COEX(mvm, "\tBT activity grading %d\n",
1068 le32_to_cpu(notif->bt_activity_grading));
1069 IWL_DEBUG_COEX(mvm, "\tBT agg traffic load %d\n",
1070 notif->bt_agg_traffic_load);
1071
1072 /* remember this notification for future use: rssi fluctuations */
1073 memcpy(&mvm->last_bt_notif_old, notif, sizeof(mvm->last_bt_notif_old));
1074
1075 iwl_mvm_bt_coex_notif_handle(mvm);
1076
1077 /*
1078 * This is an async handler for a notification, returning anything other
1079 * than 0 doesn't make sense even if HCMD failed.
1080 */
1081 return 0;
1082}
1083
1084static void iwl_mvm_bt_rssi_iterator(void *_data, u8 *mac,
1085 struct ieee80211_vif *vif)
1086{
1087 struct iwl_mvm_vif *mvmvif = (void *)vif->drv_priv;
1088 struct iwl_bt_iterator_data *data = _data;
1089 struct iwl_mvm *mvm = data->mvm;
1090
1091 struct ieee80211_sta *sta;
1092 struct iwl_mvm_sta *mvmsta;
1093
1094 struct ieee80211_chanctx_conf *chanctx_conf;
1095
1096 rcu_read_lock();
1097 chanctx_conf = rcu_dereference(vif->chanctx_conf);
1098 /* If channel context is invalid or not on 2.4GHz - don't count it */
1099 if (!chanctx_conf ||
1100 chanctx_conf->def.chan->band != IEEE80211_BAND_2GHZ) {
1101 rcu_read_unlock();
1102 return;
1103 }
1104 rcu_read_unlock();
1105
1106 if (vif->type != NL80211_IFTYPE_STATION ||
1107 mvmvif->ap_sta_id == IWL_MVM_STATION_COUNT)
1108 return;
1109
1110 sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[mvmvif->ap_sta_id],
1111 lockdep_is_held(&mvm->mutex));
1112
1113 /* This can happen if the station has been removed right now */
1114 if (IS_ERR_OR_NULL(sta))
1115 return;
1116
1117 mvmsta = iwl_mvm_sta_from_mac80211(sta);
1118
1119 data->num_bss_ifaces++;
1120
1121 /*
1122 * This interface doesn't support reduced Tx power (because of low
1123 * RSSI probably), then set bt_kill_msk to default values.
1124 */
1125 if (!mvmsta->bt_reduced_txpower)
1126 data->reduced_tx_power = false;
1127 /* else - possibly leave it to BT_KILL_MSK_REDUCED_TXPOW */
1128}
1129
1130void iwl_mvm_bt_rssi_event_old(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
1131 enum ieee80211_rssi_event rssi_event)
1132{
1133 struct iwl_mvm_vif *mvmvif = (void *)vif->drv_priv;
1134 struct iwl_bt_iterator_data data = {
1135 .mvm = mvm,
1136 .reduced_tx_power = true,
1137 };
1138 int ret;
1139
1140 lockdep_assert_held(&mvm->mutex);
1141
1142 /* Ignore updates if we are in force mode */
1143 if (unlikely(mvm->bt_force_ant_mode != BT_FORCE_ANT_DIS))
1144 return;
1145
1146 /*
1147 * Rssi update while not associated - can happen since the statistics
1148 * are handled asynchronously
1149 */
1150 if (mvmvif->ap_sta_id == IWL_MVM_STATION_COUNT)
1151 return;
1152
1153 /* No BT - reports should be disabled */
1154 if (!mvm->last_bt_notif_old.bt_status)
1155 return;
1156
1157 IWL_DEBUG_COEX(mvm, "RSSI for %pM is now %s\n", vif->bss_conf.bssid,
1158 rssi_event == RSSI_EVENT_HIGH ? "HIGH" : "LOW");
1159
1160 /*
1161 * Check if rssi is good enough for reduced Tx power, but not in loose
1162 * scheme.
1163 */
1164 if (rssi_event == RSSI_EVENT_LOW || mvm->cfg->bt_shared_single_ant ||
1165 iwl_get_coex_type(mvm, vif) == BT_COEX_LOOSE_LUT)
1166 ret = iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id,
1167 false);
1168 else
1169 ret = iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, true);
1170
1171 if (ret)
1172 IWL_ERR(mvm, "couldn't send BT_CONFIG HCMD upon RSSI event\n");
1173
1174 ieee80211_iterate_active_interfaces_atomic(
1175 mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
1176 iwl_mvm_bt_rssi_iterator, &data);
1177
1178 /*
1179 * If there are no BSS / P2P client interfaces, reduced Tx Power is
1180 * irrelevant since it is based on the RSSI coming from the beacon.
1181 * Use BT_KILL_MSK_DEFAULT in that case.
1182 */
1183 data.reduced_tx_power = data.reduced_tx_power && data.num_bss_ifaces;
1184
1185 if (iwl_mvm_bt_udpate_ctrl_kill_msk(mvm, data.reduced_tx_power))
1186 IWL_ERR(mvm, "Failed to update the ctrl_kill_msk\n");
1187}
1188
1189#define LINK_QUAL_AGG_TIME_LIMIT_DEF (4000)
1190#define LINK_QUAL_AGG_TIME_LIMIT_BT_ACT (1200)
1191
1192u16 iwl_mvm_coex_agg_time_limit_old(struct iwl_mvm *mvm,
1193 struct ieee80211_sta *sta)
1194{
1195 struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
1196 enum iwl_bt_coex_lut_type lut_type;
1197
1198 if (le32_to_cpu(mvm->last_bt_notif_old.bt_activity_grading) <
1199 BT_HIGH_TRAFFIC)
1200 return LINK_QUAL_AGG_TIME_LIMIT_DEF;
1201
1202 if (mvm->last_bt_notif_old.ttc_enabled)
1203 return LINK_QUAL_AGG_TIME_LIMIT_DEF;
1204
1205 lut_type = iwl_get_coex_type(mvm, mvmsta->vif);
1206
1207 if (lut_type == BT_COEX_LOOSE_LUT || lut_type == BT_COEX_INVALID_LUT)
1208 return LINK_QUAL_AGG_TIME_LIMIT_DEF;
1209
1210 /* tight coex, high bt traffic, reduce AGG time limit */
1211 return LINK_QUAL_AGG_TIME_LIMIT_BT_ACT;
1212}
1213
1214bool iwl_mvm_bt_coex_is_mimo_allowed_old(struct iwl_mvm *mvm,
1215 struct ieee80211_sta *sta)
1216{
1217 struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
1218 enum iwl_bt_coex_lut_type lut_type;
1219
1220 if (mvm->last_bt_notif_old.ttc_enabled)
1221 return true;
1222
1223 if (le32_to_cpu(mvm->last_bt_notif_old.bt_activity_grading) <
1224 BT_HIGH_TRAFFIC)
1225 return true;
1226
1227 /*
1228 * In Tight / TxTxDis, BT can't Rx while we Tx, so use both antennas
1229 * since BT is already killed.
1230 * In Loose, BT can Rx while we Tx, so forbid MIMO to let BT Rx while
1231 * we Tx.
1232 * When we are in 5GHz, we'll get BT_COEX_INVALID_LUT allowing MIMO.
1233 */
1234 lut_type = iwl_get_coex_type(mvm, mvmsta->vif);
1235 return lut_type != BT_COEX_LOOSE_LUT;
1236}
1237
1238bool iwl_mvm_bt_coex_is_shared_ant_avail_old(struct iwl_mvm *mvm)
1239{
1240 u32 ag = le32_to_cpu(mvm->last_bt_notif_old.bt_activity_grading);
1241 return ag == BT_OFF;
1242}
1243
1244bool iwl_mvm_bt_coex_is_tpc_allowed_old(struct iwl_mvm *mvm,
1245 enum ieee80211_band band)
1246{
1247 u32 bt_activity =
1248 le32_to_cpu(mvm->last_bt_notif_old.bt_activity_grading);
1249
1250 if (band != IEEE80211_BAND_2GHZ)
1251 return false;
1252
1253 return bt_activity >= BT_LOW_TRAFFIC;
1254}
1255
1256void iwl_mvm_bt_coex_vif_change_old(struct iwl_mvm *mvm)
1257{
1258 iwl_mvm_bt_coex_notif_handle(mvm);
1259}
1260
1261int iwl_mvm_rx_ant_coupling_notif_old(struct iwl_mvm *mvm,
1262 struct iwl_rx_cmd_buffer *rxb,
1263 struct iwl_device_cmd *dev_cmd)
1264{
1265 struct iwl_rx_packet *pkt = rxb_addr(rxb);
1266 u32 ant_isolation = le32_to_cpup((void *)pkt->data);
1267 u8 __maybe_unused lower_bound, upper_bound;
1268 int ret;
1269 u8 lut;
1270
1271 struct iwl_bt_coex_cmd_old *bt_cmd;
1272 struct iwl_host_cmd cmd = {
1273 .id = BT_CONFIG,
1274 .len = { sizeof(*bt_cmd), },
1275 .dataflags = { IWL_HCMD_DFL_NOCOPY, },
1276 };
1277
1278 if (!IWL_MVM_BT_COEX_CORUNNING)
1279 return 0;
1280
1281 lockdep_assert_held(&mvm->mutex);
1282
1283 /* Ignore updates if we are in force mode */
1284 if (unlikely(mvm->bt_force_ant_mode != BT_FORCE_ANT_DIS))
1285 return 0;
1286
1287 if (ant_isolation == mvm->last_ant_isol)
1288 return 0;
1289
1290 for (lut = 0; lut < ARRAY_SIZE(antenna_coupling_ranges) - 1; lut++)
1291 if (ant_isolation < antenna_coupling_ranges[lut + 1].range)
1292 break;
1293
1294 lower_bound = antenna_coupling_ranges[lut].range;
1295
1296 if (lut < ARRAY_SIZE(antenna_coupling_ranges) - 1)
1297 upper_bound = antenna_coupling_ranges[lut + 1].range;
1298 else
1299 upper_bound = antenna_coupling_ranges[lut].range;
1300
1301 IWL_DEBUG_COEX(mvm, "Antenna isolation=%d in range [%d,%d[, lut=%d\n",
1302 ant_isolation, lower_bound, upper_bound, lut);
1303
1304 mvm->last_ant_isol = ant_isolation;
1305
1306 if (mvm->last_corun_lut == lut)
1307 return 0;
1308
1309 mvm->last_corun_lut = lut;
1310
1311 bt_cmd = kzalloc(sizeof(*bt_cmd), GFP_KERNEL);
1312 if (!bt_cmd)
1313 return 0;
1314 cmd.data[0] = bt_cmd;
1315
1316 bt_cmd->flags = cpu_to_le32(BT_COEX_NW_OLD);
1317 bt_cmd->valid_bit_msk |= cpu_to_le32(BT_VALID_ENABLE |
1318 BT_VALID_CORUN_LUT_20 |
1319 BT_VALID_CORUN_LUT_40);
1320
1321 /* For the moment, use the same LUT for 20GHz and 40GHz */
1322 memcpy(bt_cmd->bt4_corun_lut20, antenna_coupling_ranges[lut].lut20,
1323 sizeof(bt_cmd->bt4_corun_lut20));
1324
1325 memcpy(bt_cmd->bt4_corun_lut40, antenna_coupling_ranges[lut].lut20,
1326 sizeof(bt_cmd->bt4_corun_lut40));
1327
1328 ret = iwl_mvm_send_cmd(mvm, &cmd);
1329
1330 kfree(bt_cmd);
1331 return ret;
1332}
diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/iwlwifi/mvm/debugfs.c
index 602bbd29ec5a..b2c751e71581 100644
--- a/drivers/net/wireless/iwlwifi/mvm/debugfs.c
+++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.c
@@ -316,7 +316,7 @@ static ssize_t iwl_dbgfs_bt_notif_read(struct file *file, char __user *user_buf,
316 size_t count, loff_t *ppos) 316 size_t count, loff_t *ppos)
317{ 317{
318 struct iwl_mvm *mvm = file->private_data; 318 struct iwl_mvm *mvm = file->private_data;
319 struct iwl_bt_coex_profile_notif *notif = &mvm->last_bt_notif; 319 struct iwl_bt_coex_profile_notif_old *notif = &mvm->last_bt_notif;
320 char *buf; 320 char *buf;
321 int ret, pos = 0, bufsz = sizeof(char) * 1024; 321 int ret, pos = 0, bufsz = sizeof(char) * 1024;
322 322
@@ -411,7 +411,7 @@ static ssize_t iwl_dbgfs_bt_cmd_read(struct file *file, char __user *user_buf,
411 size_t count, loff_t *ppos) 411 size_t count, loff_t *ppos)
412{ 412{
413 struct iwl_mvm *mvm = file->private_data; 413 struct iwl_mvm *mvm = file->private_data;
414 struct iwl_bt_coex_ci_cmd *cmd = &mvm->last_bt_ci_cmd; 414 struct iwl_bt_coex_ci_cmd_old *cmd = &mvm->last_bt_ci_cmd;
415 char buf[256]; 415 char buf[256];
416 int bufsz = sizeof(buf); 416 int bufsz = sizeof(buf);
417 int pos = 0; 417 int pos = 0;
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-coex.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-coex.h
index 39cb33a19862..b3626cc69052 100644
--- a/drivers/net/wireless/iwlwifi/mvm/fw-api-coex.h
+++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-coex.h
@@ -72,13 +72,13 @@
72 * enum iwl_bt_coex_flags - flags for BT_COEX command 72 * enum iwl_bt_coex_flags - flags for BT_COEX command
73 * @BT_COEX_MODE_POS: 73 * @BT_COEX_MODE_POS:
74 * @BT_COEX_MODE_MSK: 74 * @BT_COEX_MODE_MSK:
75 * @BT_COEX_DISABLE: 75 * @BT_COEX_DISABLE_OLD:
76 * @BT_COEX_2W: 76 * @BT_COEX_2W_OLD:
77 * @BT_COEX_3W: 77 * @BT_COEX_3W_OLD:
78 * @BT_COEX_NW: 78 * @BT_COEX_NW_OLD:
79 * @BT_COEX_AUTO: 79 * @BT_COEX_AUTO_OLD:
80 * @BT_COEX_BT: Antenna is for BT (manufacuring tests) 80 * @BT_COEX_BT_OLD: Antenna is for BT (manufacuring tests)
81 * @BT_COEX_WIFI: Antenna is for BT (manufacuring tests) 81 * @BT_COEX_WIFI_OLD: Antenna is for BT (manufacuring tests)
82 * @BT_COEX_SYNC2SCO: 82 * @BT_COEX_SYNC2SCO:
83 * @BT_COEX_CORUNNING: 83 * @BT_COEX_CORUNNING:
84 * @BT_COEX_MPLUT: 84 * @BT_COEX_MPLUT:
@@ -88,13 +88,13 @@
88enum iwl_bt_coex_flags { 88enum iwl_bt_coex_flags {
89 BT_COEX_MODE_POS = 3, 89 BT_COEX_MODE_POS = 3,
90 BT_COEX_MODE_MSK = BITS(3) << BT_COEX_MODE_POS, 90 BT_COEX_MODE_MSK = BITS(3) << BT_COEX_MODE_POS,
91 BT_COEX_DISABLE = 0x0 << BT_COEX_MODE_POS, 91 BT_COEX_DISABLE_OLD = 0x0 << BT_COEX_MODE_POS,
92 BT_COEX_2W = 0x1 << BT_COEX_MODE_POS, 92 BT_COEX_2W_OLD = 0x1 << BT_COEX_MODE_POS,
93 BT_COEX_3W = 0x2 << BT_COEX_MODE_POS, 93 BT_COEX_3W_OLD = 0x2 << BT_COEX_MODE_POS,
94 BT_COEX_NW = 0x3 << BT_COEX_MODE_POS, 94 BT_COEX_NW_OLD = 0x3 << BT_COEX_MODE_POS,
95 BT_COEX_AUTO = 0x5 << BT_COEX_MODE_POS, 95 BT_COEX_AUTO_OLD = 0x5 << BT_COEX_MODE_POS,
96 BT_COEX_BT = 0x6 << BT_COEX_MODE_POS, 96 BT_COEX_BT_OLD = 0x6 << BT_COEX_MODE_POS,
97 BT_COEX_WIFI = 0x7 << BT_COEX_MODE_POS, 97 BT_COEX_WIFI_OLD = 0x7 << BT_COEX_MODE_POS,
98 BT_COEX_SYNC2SCO = BIT(7), 98 BT_COEX_SYNC2SCO = BIT(7),
99 BT_COEX_CORUNNING = BIT(8), 99 BT_COEX_CORUNNING = BIT(8),
100 BT_COEX_MPLUT = BIT(9), 100 BT_COEX_MPLUT = BIT(9),
@@ -157,7 +157,7 @@ enum iwl_bt_coex_lut_type {
157#define BT_REDUCED_TX_POWER_BIT BIT(7) 157#define BT_REDUCED_TX_POWER_BIT BIT(7)
158 158
159/** 159/**
160 * struct iwl_bt_coex_cmd - bt coex configuration command 160 * struct iwl_bt_coex_cmd_old - bt coex configuration command
161 * @flags:&enum iwl_bt_coex_flags 161 * @flags:&enum iwl_bt_coex_flags
162 * @max_kill: 162 * @max_kill:
163 * @bt_reduced_tx_power: enum %iwl_bt_reduced_tx_power 163 * @bt_reduced_tx_power: enum %iwl_bt_reduced_tx_power
@@ -182,7 +182,7 @@ enum iwl_bt_coex_lut_type {
182 * 182 *
183 * The structure is used for the BT_COEX command. 183 * The structure is used for the BT_COEX command.
184 */ 184 */
185struct iwl_bt_coex_cmd { 185struct iwl_bt_coex_cmd_old {
186 __le32 flags; 186 __le32 flags;
187 u8 max_kill; 187 u8 max_kill;
188 u8 bt_reduced_tx_power; 188 u8 bt_reduced_tx_power;
@@ -219,7 +219,7 @@ struct iwl_bt_coex_cmd {
219 * 219 *
220 * Used for BT_COEX_CI command 220 * Used for BT_COEX_CI command
221 */ 221 */
222struct iwl_bt_coex_ci_cmd { 222struct iwl_bt_coex_ci_cmd_old {
223 __le64 bt_primary_ci; 223 __le64 bt_primary_ci;
224 __le64 bt_secondary_ci; 224 __le64 bt_secondary_ci;
225 225
@@ -310,7 +310,7 @@ enum iwl_bt_activity_grading {
310 * @secondary_ch_lut: LUT used for secondary channel 310 * @secondary_ch_lut: LUT used for secondary channel
311 * @bt_activity_grading: the activity of BT enum %iwl_bt_activity_grading 311 * @bt_activity_grading: the activity of BT enum %iwl_bt_activity_grading
312 */ 312 */
313struct iwl_bt_coex_profile_notif { 313struct iwl_bt_coex_profile_notif_old {
314 __le32 mbox_msg[4]; 314 __le32 mbox_msg[4];
315 __le32 msg_idx; 315 __le32 msg_idx;
316 u8 bt_status; 316 u8 bt_status;
diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h
index 6fe93a7335c1..0b52d0ae4a0d 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mvm.h
+++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h
@@ -630,8 +630,12 @@ struct iwl_mvm {
630 630
631 /* BT-Coex */ 631 /* BT-Coex */
632 u8 bt_kill_msk; 632 u8 bt_kill_msk;
633 struct iwl_bt_coex_profile_notif last_bt_notif; 633
634 struct iwl_bt_coex_ci_cmd last_bt_ci_cmd; 634 struct iwl_bt_coex_profile_notif_old last_bt_notif_old;
635 struct iwl_bt_coex_ci_cmd_old last_bt_ci_cmd_old;
636 struct iwl_bt_coex_profile_notif_old last_bt_notif;
637 struct iwl_bt_coex_ci_cmd_old last_bt_ci_cmd;
638
635 u32 last_ant_isol; 639 u32 last_ant_isol;
636 u8 last_corun_lut; 640 u8 last_corun_lut;
637 u8 bt_tx_prio; 641 u8 bt_tx_prio;
@@ -974,6 +978,24 @@ bool iwl_mvm_bt_coex_is_tpc_allowed(struct iwl_mvm *mvm,
974u8 iwl_mvm_bt_coex_tx_prio(struct iwl_mvm *mvm, struct ieee80211_hdr *hdr, 978u8 iwl_mvm_bt_coex_tx_prio(struct iwl_mvm *mvm, struct ieee80211_hdr *hdr,
975 struct ieee80211_tx_info *info, u8 ac); 979 struct ieee80211_tx_info *info, u8 ac);
976 980
981bool iwl_mvm_bt_coex_is_shared_ant_avail_old(struct iwl_mvm *mvm);
982void iwl_mvm_bt_coex_vif_change_old(struct iwl_mvm *mvm);
983int iwl_send_bt_init_conf_old(struct iwl_mvm *mvm);
984int iwl_mvm_rx_bt_coex_notif_old(struct iwl_mvm *mvm,
985 struct iwl_rx_cmd_buffer *rxb,
986 struct iwl_device_cmd *cmd);
987void iwl_mvm_bt_rssi_event_old(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
988 enum ieee80211_rssi_event rssi_event);
989u16 iwl_mvm_coex_agg_time_limit_old(struct iwl_mvm *mvm,
990 struct ieee80211_sta *sta);
991bool iwl_mvm_bt_coex_is_mimo_allowed_old(struct iwl_mvm *mvm,
992 struct ieee80211_sta *sta);
993bool iwl_mvm_bt_coex_is_tpc_allowed_old(struct iwl_mvm *mvm,
994 enum ieee80211_band band);
995int iwl_mvm_rx_ant_coupling_notif_old(struct iwl_mvm *mvm,
996 struct iwl_rx_cmd_buffer *rxb,
997 struct iwl_device_cmd *cmd);
998
977enum iwl_bt_kill_msk { 999enum iwl_bt_kill_msk {
978 BT_KILL_MSK_DEFAULT, 1000 BT_KILL_MSK_DEFAULT,
979 BT_KILL_MSK_SCO_HID_A2DP, 1001 BT_KILL_MSK_SCO_HID_A2DP,