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 * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH 10 * 11 * This program is free software; you can redistribute it and/or modify 12 * it under the terms of version 2 of the GNU General Public License as 13 * published by the Free Software Foundation. 14 * 15 * This program is distributed in the hope that it will be useful, but 16 * WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 18 * General Public License for more details. 19 * 20 * You should have received a copy of the GNU General Public License 21 * along with this program; if not, write to the Free Software 22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, 23 * USA 24 * 25 * The full GNU General Public License is included in this distribution 26 * in the file called COPYING. 27 * 28 * Contact Information: 29 * Intel Linux Wireless <ilw@linux.intel.com> 30 * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 31 * 32 * BSD LICENSE 33 * 34 * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved. 35 * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH 36 * All rights reserved. 37 * 38 * Redistribution and use in source and binary forms, with or without 39 * modification, are permitted provided that the following conditions 40 * are met: 41 * 42 * * Redistributions of source code must retain the above copyright 43 * notice, this list of conditions and the following disclaimer. 44 * * Redistributions in binary form must reproduce the above copyright 45 * notice, this list of conditions and the following disclaimer in 46 * the documentation and/or other materials provided with the 47 * distribution. 48 * * Neither the name Intel Corporation nor the names of its 49 * contributors may be used to endorse or promote products derived 50 * from this software without specific prior written permission. 51 * 52 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 53 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 54 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 55 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 56 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 57 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 58 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 59 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 60 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 61 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 62 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 63 * 64 *****************************************************************************/ 65 66#include <linux/ieee80211.h> 67#include <linux/etherdevice.h> 68#include <net/mac80211.h> 69 70#include "fw-api-coex.h" 71#include "iwl-modparams.h" 72#include "mvm.h" 73#include "iwl-debug.h" 74 75#define EVENT_PRIO_ANT(_evt, _prio, _shrd_ant) \ 76 [(_evt)] = (((_prio) << BT_COEX_PRIO_TBL_PRIO_POS) | \ 77 ((_shrd_ant) << BT_COEX_PRIO_TBL_SHRD_ANT_POS)) 78 79static const u8 iwl_bt_prio_tbl[BT_COEX_PRIO_TBL_EVT_MAX] = { 80 EVENT_PRIO_ANT(BT_COEX_PRIO_TBL_EVT_INIT_CALIB1, 81 BT_COEX_PRIO_TBL_PRIO_BYPASS, 0), 82 EVENT_PRIO_ANT(BT_COEX_PRIO_TBL_EVT_INIT_CALIB2, 83 BT_COEX_PRIO_TBL_PRIO_BYPASS, 1), 84 EVENT_PRIO_ANT(BT_COEX_PRIO_TBL_EVT_PERIODIC_CALIB_LOW1, 85 BT_COEX_PRIO_TBL_PRIO_LOW, 0), 86 EVENT_PRIO_ANT(BT_COEX_PRIO_TBL_EVT_PERIODIC_CALIB_LOW2, 87 BT_COEX_PRIO_TBL_PRIO_LOW, 1), 88 EVENT_PRIO_ANT(BT_COEX_PRIO_TBL_EVT_PERIODIC_CALIB_HIGH1, 89 BT_COEX_PRIO_TBL_PRIO_HIGH, 0), 90 EVENT_PRIO_ANT(BT_COEX_PRIO_TBL_EVT_PERIODIC_CALIB_HIGH2, 91 BT_COEX_PRIO_TBL_PRIO_HIGH, 1), 92 EVENT_PRIO_ANT(BT_COEX_PRIO_TBL_EVT_DTIM, 93 BT_COEX_PRIO_TBL_DISABLED, 0), 94 EVENT_PRIO_ANT(BT_COEX_PRIO_TBL_EVT_SCAN52, 95 BT_COEX_PRIO_TBL_PRIO_COEX_OFF, 0), 96 EVENT_PRIO_ANT(BT_COEX_PRIO_TBL_EVT_SCAN24, 97 BT_COEX_PRIO_TBL_PRIO_COEX_ON, 0), 98 EVENT_PRIO_ANT(BT_COEX_PRIO_TBL_EVT_IDLE, 99 BT_COEX_PRIO_TBL_PRIO_COEX_IDLE, 0), 100 0, 0, 0, 0, 0, 0, 101}; 102 103#undef EVENT_PRIO_ANT 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 291enum iwl_bt_kill_msk { 292 BT_KILL_MSK_DEFAULT, 293 BT_KILL_MSK_NEVER, 294 BT_KILL_MSK_ALWAYS, 295 BT_KILL_MSK_MAX, 296}; 297 298static const u32 iwl_bt_ctl_kill_msk[BT_KILL_MSK_MAX] = { 299 [BT_KILL_MSK_DEFAULT] = 0xfffffc00, 300 [BT_KILL_MSK_NEVER] = 0xffffffff, 301 [BT_KILL_MSK_ALWAYS] = 0, 302}; 303 304static const u8 iwl_bt_cts_kill_msk[BT_MAX_AG][BT_COEX_MAX_LUT] = { 305 { 306 BT_KILL_MSK_ALWAYS, 307 BT_KILL_MSK_ALWAYS, 308 BT_KILL_MSK_ALWAYS, 309 }, 310 { 311 BT_KILL_MSK_NEVER, 312 BT_KILL_MSK_NEVER, 313 BT_KILL_MSK_NEVER, 314 }, 315 { 316 BT_KILL_MSK_NEVER, 317 BT_KILL_MSK_NEVER, 318 BT_KILL_MSK_NEVER, 319 }, 320 { 321 BT_KILL_MSK_DEFAULT, 322 BT_KILL_MSK_NEVER, 323 BT_KILL_MSK_DEFAULT, 324 }, 325}; 326 327static const u8 iwl_bt_ack_kill_msk[BT_MAX_AG][BT_COEX_MAX_LUT] = { 328 { 329 BT_KILL_MSK_ALWAYS, 330 BT_KILL_MSK_ALWAYS, 331 BT_KILL_MSK_ALWAYS, 332 }, 333 { 334 BT_KILL_MSK_ALWAYS, 335 BT_KILL_MSK_ALWAYS, 336 BT_KILL_MSK_ALWAYS, 337 }, 338 { 339 BT_KILL_MSK_ALWAYS, 340 BT_KILL_MSK_ALWAYS, 341 BT_KILL_MSK_ALWAYS, 342 }, 343 { 344 BT_KILL_MSK_DEFAULT, 345 BT_KILL_MSK_ALWAYS, 346 BT_KILL_MSK_DEFAULT, 347 }, 348}; 349 350struct corunning_block_luts { 351 u8 range; 352 __le32 lut20[BT_COEX_CORUN_LUT_SIZE]; 353}; 354 355/* 356 * Ranges for the antenna coupling calibration / co-running block LUT: 357 * LUT0: [ 0, 12[ 358 * LUT1: [12, 20[ 359 * LUT2: [20, 21[ 360 * LUT3: [21, 23[ 361 * LUT4: [23, 27[ 362 * LUT5: [27, 30[ 363 * LUT6: [30, 32[ 364 * LUT7: [32, 33[ 365 * LUT8: [33, - [ 366 */ 367static const struct corunning_block_luts antenna_coupling_ranges[] = { 368 { 369 .range = 0, 370 .lut20 = { 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 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), 376 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), 377 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), 378 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), 379 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), 380 cpu_to_le32(0x00000000), 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 }, 388 }, 389 { 390 .range = 12, 391 .lut20 = { 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 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), 397 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), 398 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), 399 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), 400 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), 401 cpu_to_le32(0x00000000), 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 }, 409 }, 410 { 411 .range = 20, 412 .lut20 = { 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 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), 418 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), 419 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), 420 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), 421 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), 422 cpu_to_le32(0x00000000), 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 }, 430 }, 431 { 432 .range = 21, 433 .lut20 = { 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 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), 439 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), 440 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), 441 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), 442 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), 443 cpu_to_le32(0x00000000), 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 }, 451 }, 452 { 453 .range = 23, 454 .lut20 = { 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 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), 460 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), 461 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), 462 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), 463 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), 464 cpu_to_le32(0x00000000), 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 }, 472 }, 473 { 474 .range = 27, 475 .lut20 = { 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 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), 481 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), 482 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), 483 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), 484 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), 485 cpu_to_le32(0x00000000), 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 }, 493 }, 494 { 495 .range = 30, 496 .lut20 = { 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 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), 502 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), 503 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), 504 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), 505 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), 506 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), 507 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), 508 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), 509 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), 510 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), 511 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), 512 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), 513 }, 514 }, 515 { 516 .range = 32, 517 .lut20 = { 518 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), 519 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), 520 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), 521 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), 522 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), 523 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), 524 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), 525 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), 526 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), 527 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), 528 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), 529 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), 530 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), 531 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), 532 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), 533 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), 534 }, 535 }, 536 { 537 .range = 33, 538 .lut20 = { 539 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), 540 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), 541 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), 542 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), 543 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), 544 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), 545 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), 546 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), 547 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), 548 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), 549 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), 550 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), 551 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), 552 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), 553 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), 554 cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), 555 }, 556 }, 557}; 558 559static enum iwl_bt_coex_lut_type 560iwl_get_coex_type(struct iwl_mvm *mvm, const struct ieee80211_vif *vif) 561{ 562 struct ieee80211_chanctx_conf *chanctx_conf; 563 enum iwl_bt_coex_lut_type ret; 564 u16 phy_ctx_id; 565 566 /* 567 * Checking that we hold mvm->mutex is a good idea, but the rate 568 * control can't acquire the mutex since it runs in Tx path. 569 * So this is racy in that case, but in the worst case, the AMPDU 570 * size limit will be wrong for a short time which is not a big 571 * issue. 572 */ 573 574 rcu_read_lock(); 575 576 chanctx_conf = rcu_dereference(vif->chanctx_conf); 577 578 if (!chanctx_conf || 579 chanctx_conf->def.chan->band != IEEE80211_BAND_2GHZ) { 580 rcu_read_unlock(); 581 return BT_COEX_INVALID_LUT; 582 } 583 584 ret = BT_COEX_TX_DIS_LUT; 585 586 if (mvm->cfg->bt_shared_single_ant) { 587 rcu_read_unlock(); 588 return ret; 589 } 590 591 phy_ctx_id = *((u16 *)chanctx_conf->drv_priv); 592 593 if (mvm->last_bt_ci_cmd_old.primary_ch_phy_id == phy_ctx_id) 594 ret = le32_to_cpu(mvm->last_bt_notif_old.primary_ch_lut); 595 else if (mvm->last_bt_ci_cmd_old.secondary_ch_phy_id == phy_ctx_id) 596 ret = le32_to_cpu(mvm->last_bt_notif_old.secondary_ch_lut); 597 /* else - default = TX TX disallowed */ 598 599 rcu_read_unlock(); 600 601 return ret; 602} 603 604int iwl_send_bt_init_conf_old(struct iwl_mvm *mvm) 605{ 606 struct iwl_bt_coex_cmd_old *bt_cmd; 607 struct iwl_host_cmd cmd = { 608 .id = BT_CONFIG, 609 .len = { sizeof(*bt_cmd), }, 610 .dataflags = { IWL_HCMD_DFL_NOCOPY, }, 611 }; 612 int ret; 613 u32 flags; 614 615 ret = iwl_send_bt_prio_tbl(mvm); 616 if (ret) 617 return ret; 618 619 bt_cmd = kzalloc(sizeof(*bt_cmd), GFP_KERNEL); 620 if (!bt_cmd) 621 return -ENOMEM; 622 cmd.data[0] = bt_cmd; 623 624 lockdep_assert_held(&mvm->mutex); 625 626 if (unlikely(mvm->bt_force_ant_mode != BT_FORCE_ANT_DIS)) { 627 switch (mvm->bt_force_ant_mode) { 628 case BT_FORCE_ANT_AUTO: 629 flags = BT_COEX_AUTO_OLD; 630 break; 631 case BT_FORCE_ANT_BT: 632 flags = BT_COEX_BT_OLD; 633 break; 634 case BT_FORCE_ANT_WIFI: 635 flags = BT_COEX_WIFI_OLD; 636 break; 637 default: 638 WARN_ON(1); 639 flags = 0; 640 } 641 642 bt_cmd->flags = cpu_to_le32(flags); 643 bt_cmd->valid_bit_msk = cpu_to_le32(BT_VALID_ENABLE); 644 goto send_cmd; 645 } 646 647 bt_cmd->max_kill = 5; 648 bt_cmd->bt4_antenna_isolation_thr = 649 IWL_MVM_BT_COEX_ANTENNA_COUPLING_THRS; 650 bt_cmd->bt4_antenna_isolation = iwlwifi_mod_params.ant_coupling; 651 bt_cmd->bt4_tx_tx_delta_freq_thr = 15; 652 bt_cmd->bt4_tx_rx_max_freq0 = 15; 653 bt_cmd->override_primary_lut = BT_COEX_INVALID_LUT; 654 bt_cmd->override_secondary_lut = BT_COEX_INVALID_LUT; 655 656 flags = iwlwifi_mod_params.bt_coex_active ? 657 BT_COEX_NW_OLD : BT_COEX_DISABLE_OLD; 658 bt_cmd->flags = cpu_to_le32(flags); 659 660 bt_cmd->valid_bit_msk = cpu_to_le32(BT_VALID_ENABLE | 661 BT_VALID_BT_PRIO_BOOST | 662 BT_VALID_MAX_KILL | 663 BT_VALID_3W_TMRS | 664 BT_VALID_KILL_ACK | 665 BT_VALID_KILL_CTS | 666 BT_VALID_REDUCED_TX_POWER | 667 BT_VALID_LUT | 668 BT_VALID_WIFI_RX_SW_PRIO_BOOST | 669 BT_VALID_WIFI_TX_SW_PRIO_BOOST | 670 BT_VALID_ANT_ISOLATION | 671 BT_VALID_ANT_ISOLATION_THRS | 672 BT_VALID_TXTX_DELTA_FREQ_THRS | 673 BT_VALID_TXRX_MAX_FREQ_0 | 674 BT_VALID_SYNC_TO_SCO | 675 BT_VALID_TTC | 676 BT_VALID_RRC); 677 678 if (IWL_MVM_BT_COEX_SYNC2SCO) 679 bt_cmd->flags |= cpu_to_le32(BT_COEX_SYNC2SCO); 680 681 if (iwl_mvm_bt_is_plcr_supported(mvm)) { 682 bt_cmd->valid_bit_msk |= cpu_to_le32(BT_VALID_CORUN_LUT_20 | 683 BT_VALID_CORUN_LUT_40); 684 bt_cmd->flags |= cpu_to_le32(BT_COEX_CORUNNING); 685 } 686 687 if (IWL_MVM_BT_COEX_MPLUT) { 688 bt_cmd->flags |= cpu_to_le32(BT_COEX_MPLUT); 689 bt_cmd->valid_bit_msk |= cpu_to_le32(BT_VALID_MULTI_PRIO_LUT); 690 } 691 692 if (IWL_MVM_BT_COEX_TTC) 693 bt_cmd->flags |= cpu_to_le32(BT_COEX_TTC); 694 695 if (iwl_mvm_bt_is_rrc_supported(mvm)) 696 bt_cmd->flags |= cpu_to_le32(BT_COEX_RRC); 697 698 if (mvm->cfg->bt_shared_single_ant) 699 memcpy(&bt_cmd->decision_lut, iwl_single_shared_ant, 700 sizeof(iwl_single_shared_ant)); 701 else 702 memcpy(&bt_cmd->decision_lut, iwl_combined_lookup, 703 sizeof(iwl_combined_lookup)); 704 705 /* Take first Co-running block LUT to get started */ 706 memcpy(bt_cmd->bt4_corun_lut20, antenna_coupling_ranges[0].lut20, 707 sizeof(bt_cmd->bt4_corun_lut20)); 708 memcpy(bt_cmd->bt4_corun_lut40, antenna_coupling_ranges[0].lut20, 709 sizeof(bt_cmd->bt4_corun_lut40)); 710 711 memcpy(&bt_cmd->bt_prio_boost, iwl_bt_prio_boost, 712 sizeof(iwl_bt_prio_boost)); 713 bt_cmd->bt4_multiprio_lut[0] = cpu_to_le32(IWL_MVM_BT_COEX_MPLUT_REG0); 714 bt_cmd->bt4_multiprio_lut[1] = cpu_to_le32(IWL_MVM_BT_COEX_MPLUT_REG1); 715 716send_cmd: 717 memset(&mvm->last_bt_notif_old, 0, sizeof(mvm->last_bt_notif_old)); 718 memset(&mvm->last_bt_ci_cmd_old, 0, sizeof(mvm->last_bt_ci_cmd_old)); 719 720 ret = iwl_mvm_send_cmd(mvm, &cmd); 721 722 kfree(bt_cmd); 723 return ret; 724} 725 726static int iwl_mvm_bt_udpate_ctrl_kill_msk(struct iwl_mvm *mvm) 727{ 728 struct iwl_bt_coex_profile_notif_old *notif = &mvm->last_bt_notif_old; 729 u32 primary_lut = le32_to_cpu(notif->primary_ch_lut); 730 u32 ag = le32_to_cpu(notif->bt_activity_grading); 731 struct iwl_bt_coex_cmd_old *bt_cmd; 732 u8 ack_kill_msk, cts_kill_msk; 733 struct iwl_host_cmd cmd = { 734 .id = BT_CONFIG, 735 .data[0] = &bt_cmd, 736 .len = { sizeof(*bt_cmd), }, 737 .dataflags = { IWL_HCMD_DFL_NOCOPY, }, 738 }; 739 int ret = 0; 740 741 lockdep_assert_held(&mvm->mutex); 742 743 ack_kill_msk = iwl_bt_ack_kill_msk[ag][primary_lut]; 744 cts_kill_msk = iwl_bt_cts_kill_msk[ag][primary_lut]; 745 746 if (mvm->bt_ack_kill_msk[0] == ack_kill_msk && 747 mvm->bt_cts_kill_msk[0] == cts_kill_msk) 748 return 0; 749 750 mvm->bt_ack_kill_msk[0] = ack_kill_msk; 751 mvm->bt_cts_kill_msk[0] = cts_kill_msk; 752 753 bt_cmd = kzalloc(sizeof(*bt_cmd), GFP_KERNEL); 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->kill_ack_msk = cpu_to_le32(iwl_bt_ctl_kill_msk[ack_kill_msk]); 760 bt_cmd->kill_cts_msk = cpu_to_le32(iwl_bt_ctl_kill_msk[cts_kill_msk]); 761 bt_cmd->valid_bit_msk |= cpu_to_le32(BT_VALID_ENABLE | 762 BT_VALID_KILL_ACK | 763 BT_VALID_KILL_CTS); 764 765 ret = iwl_mvm_send_cmd(mvm, &cmd); 766 767 kfree(bt_cmd); 768 return ret; 769} 770 771static int iwl_mvm_bt_coex_reduced_txp(struct iwl_mvm *mvm, u8 sta_id, 772 bool enable) 773{ 774 struct iwl_bt_coex_cmd_old *bt_cmd; 775 /* Send ASYNC since this can be sent from an atomic context */ 776 struct iwl_host_cmd cmd = { 777 .id = BT_CONFIG, 778 .len = { sizeof(*bt_cmd), }, 779 .dataflags = { IWL_HCMD_DFL_DUP, }, 780 .flags = CMD_ASYNC, 781 }; 782 struct iwl_mvm_sta *mvmsta; 783 int ret; 784 785 mvmsta = iwl_mvm_sta_from_staid_protected(mvm, sta_id); 786 if (!mvmsta) 787 return 0; 788 789 /* nothing to do */ 790 if (mvmsta->bt_reduced_txpower == enable) 791 return 0; 792 793 bt_cmd = kzalloc(sizeof(*bt_cmd), GFP_ATOMIC); 794 if (!bt_cmd) 795 return -ENOMEM; 796 cmd.data[0] = bt_cmd; 797 bt_cmd->flags = cpu_to_le32(BT_COEX_NW_OLD); 798 799 bt_cmd->valid_bit_msk = 800 cpu_to_le32(BT_VALID_ENABLE | BT_VALID_REDUCED_TX_POWER); 801 bt_cmd->bt_reduced_tx_power = sta_id; 802 803 if (enable) 804 bt_cmd->bt_reduced_tx_power |= BT_REDUCED_TX_POWER_BIT; 805 806 IWL_DEBUG_COEX(mvm, "%sable reduced Tx Power for sta %d\n", 807 enable ? "en" : "dis", sta_id); 808 809 mvmsta->bt_reduced_txpower = enable; 810 811 ret = iwl_mvm_send_cmd(mvm, &cmd); 812 813 kfree(bt_cmd); 814 return ret; 815} 816 817struct iwl_bt_iterator_data { 818 struct iwl_bt_coex_profile_notif_old *notif; 819 struct iwl_mvm *mvm; 820 struct ieee80211_chanctx_conf *primary; 821 struct ieee80211_chanctx_conf *secondary; 822 bool primary_ll; 823}; 824 825static inline 826void iwl_mvm_bt_coex_enable_rssi_event(struct iwl_mvm *mvm, 827 struct ieee80211_vif *vif, 828 bool enable, int rssi) 829{ 830 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 831 832 mvmvif->bf_data.last_bt_coex_event = rssi; 833 mvmvif->bf_data.bt_coex_max_thold = 834 enable ? -IWL_MVM_BT_COEX_EN_RED_TXP_THRESH : 0; 835 mvmvif->bf_data.bt_coex_min_thold = 836 enable ? -IWL_MVM_BT_COEX_DIS_RED_TXP_THRESH : 0; 837} 838 839/* must be called under rcu_read_lock */ 840static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac, 841 struct ieee80211_vif *vif) 842{ 843 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 844 struct iwl_bt_iterator_data *data = _data; 845 struct iwl_mvm *mvm = data->mvm; 846 struct ieee80211_chanctx_conf *chanctx_conf; 847 enum ieee80211_smps_mode smps_mode; 848 u32 bt_activity_grading; 849 int ave_rssi; 850 851 lockdep_assert_held(&mvm->mutex); 852 853 switch (vif->type) { 854 case NL80211_IFTYPE_STATION: 855 /* default smps_mode for BSS / P2P client is AUTOMATIC */ 856 smps_mode = IEEE80211_SMPS_AUTOMATIC; 857 break; 858 case NL80211_IFTYPE_AP: 859 if (!mvmvif->ap_ibss_active) 860 return; 861 break; 862 default: 863 return; 864 } 865 866 chanctx_conf = rcu_dereference(vif->chanctx_conf); 867 868 /* If channel context is invalid or not on 2.4GHz .. */ 869 if ((!chanctx_conf || 870 chanctx_conf->def.chan->band != IEEE80211_BAND_2GHZ)) { 871 if (vif->type == NL80211_IFTYPE_STATION) { 872 /* ... relax constraints and disable rssi events */ 873 iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX, 874 smps_mode); 875 iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, 876 false); 877 iwl_mvm_bt_coex_enable_rssi_event(mvm, vif, false, 0); 878 } 879 return; 880 } 881 882 bt_activity_grading = le32_to_cpu(data->notif->bt_activity_grading); 883 if (bt_activity_grading >= BT_HIGH_TRAFFIC) 884 smps_mode = IEEE80211_SMPS_STATIC; 885 else if (bt_activity_grading >= BT_LOW_TRAFFIC) 886 smps_mode = vif->type == NL80211_IFTYPE_AP ? 887 IEEE80211_SMPS_OFF : 888 IEEE80211_SMPS_DYNAMIC; 889 890 /* relax SMPS contraints for next association */ 891 if (!vif->bss_conf.assoc) 892 smps_mode = IEEE80211_SMPS_AUTOMATIC; 893 894 if (mvmvif->phy_ctxt && 895 data->notif->rrc_enabled & BIT(mvmvif->phy_ctxt->id)) 896 smps_mode = IEEE80211_SMPS_AUTOMATIC; 897 898 IWL_DEBUG_COEX(data->mvm, 899 "mac %d: bt_status %d bt_activity_grading %d smps_req %d\n", 900 mvmvif->id, data->notif->bt_status, bt_activity_grading, 901 smps_mode); 902 903 if (vif->type == NL80211_IFTYPE_STATION) 904 iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX, 905 smps_mode); 906 907 /* low latency is always primary */ 908 if (iwl_mvm_vif_low_latency(mvmvif)) { 909 data->primary_ll = true; 910 911 data->secondary = data->primary; 912 data->primary = chanctx_conf; 913 } 914 915 if (vif->type == NL80211_IFTYPE_AP) { 916 if (!mvmvif->ap_ibss_active) 917 return; 918 919 if (chanctx_conf == data->primary) 920 return; 921 922 if (!data->primary_ll) { 923 /* 924 * downgrade the current primary no matter what its 925 * type is. 926 */ 927 data->secondary = data->primary; 928 data->primary = chanctx_conf; 929 } else { 930 /* there is low latency vif - we will be secondary */ 931 data->secondary = chanctx_conf; 932 } 933 return; 934 } 935 936 /* 937 * STA / P2P Client, try to be primary if first vif. If we are in low 938 * latency mode, we are already in primary and just don't do much 939 */ 940 if (!data->primary || data->primary == chanctx_conf) 941 data->primary = chanctx_conf; 942 else if (!data->secondary) 943 /* if secondary is not NULL, it might be a GO */ 944 data->secondary = chanctx_conf; 945 946 /* 947 * don't reduce the Tx power if one of these is true: 948 * we are in LOOSE 949 * single share antenna product 950 * BT is active 951 * we are associated 952 */ 953 if (iwl_get_coex_type(mvm, vif) == BT_COEX_LOOSE_LUT || 954 mvm->cfg->bt_shared_single_ant || !vif->bss_conf.assoc || 955 !data->notif->bt_status) { 956 iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, false); 957 iwl_mvm_bt_coex_enable_rssi_event(mvm, vif, false, 0); 958 return; 959 } 960 961 /* try to get the avg rssi from fw */ 962 ave_rssi = mvmvif->bf_data.ave_beacon_signal; 963 964 /* if the RSSI isn't valid, fake it is very low */ 965 if (!ave_rssi) 966 ave_rssi = -100; 967 if (ave_rssi > -IWL_MVM_BT_COEX_EN_RED_TXP_THRESH) { 968 if (iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, true)) 969 IWL_ERR(mvm, "Couldn't send BT_CONFIG cmd\n"); 970 } else if (ave_rssi < -IWL_MVM_BT_COEX_DIS_RED_TXP_THRESH) { 971 if (iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, false)) 972 IWL_ERR(mvm, "Couldn't send BT_CONFIG cmd\n"); 973 } 974 975 /* Begin to monitor the RSSI: it may influence the reduced Tx power */ 976 iwl_mvm_bt_coex_enable_rssi_event(mvm, vif, true, ave_rssi); 977} 978 979static void iwl_mvm_bt_coex_notif_handle(struct iwl_mvm *mvm) 980{ 981 struct iwl_bt_iterator_data data = { 982 .mvm = mvm, 983 .notif = &mvm->last_bt_notif_old, 984 }; 985 struct iwl_bt_coex_ci_cmd_old cmd = {}; 986 u8 ci_bw_idx; 987 988 /* Ignore updates if we are in force mode */ 989 if (unlikely(mvm->bt_force_ant_mode != BT_FORCE_ANT_DIS)) 990 return; 991 992 rcu_read_lock(); 993 ieee80211_iterate_active_interfaces_atomic( 994 mvm->hw, IEEE80211_IFACE_ITER_NORMAL, 995 iwl_mvm_bt_notif_iterator, &data); 996 997 if (data.primary) { 998 struct ieee80211_chanctx_conf *chan = data.primary; 999 1000 if (WARN_ON(!chan->def.chan)) { 1001 rcu_read_unlock(); 1002 return; 1003 } 1004 1005 if (chan->def.width < NL80211_CHAN_WIDTH_40) { 1006 ci_bw_idx = 0; 1007 cmd.co_run_bw_primary = 0; 1008 } else { 1009 cmd.co_run_bw_primary = 1; 1010 if (chan->def.center_freq1 > 1011 chan->def.chan->center_freq) 1012 ci_bw_idx = 2; 1013 else 1014 ci_bw_idx = 1; 1015 } 1016 1017 cmd.bt_primary_ci = 1018 iwl_ci_mask[chan->def.chan->hw_value][ci_bw_idx]; 1019 cmd.primary_ch_phy_id = *((u16 *)data.primary->drv_priv); 1020 } 1021 1022 if (data.secondary) { 1023 struct ieee80211_chanctx_conf *chan = data.secondary; 1024 1025 if (WARN_ON(!data.secondary->def.chan)) { 1026 rcu_read_unlock(); 1027 return; 1028 } 1029 1030 if (chan->def.width < NL80211_CHAN_WIDTH_40) { 1031 ci_bw_idx = 0; 1032 cmd.co_run_bw_secondary = 0; 1033 } else { 1034 cmd.co_run_bw_secondary = 1; 1035 if (chan->def.center_freq1 > 1036 chan->def.chan->center_freq) 1037 ci_bw_idx = 2; 1038 else 1039 ci_bw_idx = 1; 1040 } 1041 1042 cmd.bt_secondary_ci = 1043 iwl_ci_mask[chan->def.chan->hw_value][ci_bw_idx]; 1044 cmd.secondary_ch_phy_id = *((u16 *)data.secondary->drv_priv); 1045 } 1046 1047 rcu_read_unlock(); 1048 1049 /* Don't spam the fw with the same command over and over */ 1050 if (memcmp(&cmd, &mvm->last_bt_ci_cmd_old, sizeof(cmd))) { 1051 if (iwl_mvm_send_cmd_pdu(mvm, BT_COEX_CI, 0, 1052 sizeof(cmd), &cmd)) 1053 IWL_ERR(mvm, "Failed to send BT_CI cmd\n"); 1054 memcpy(&mvm->last_bt_ci_cmd_old, &cmd, sizeof(cmd)); 1055 } 1056 1057 if (iwl_mvm_bt_udpate_ctrl_kill_msk(mvm)) 1058 IWL_ERR(mvm, "Failed to update the ctrl_kill_msk\n"); 1059} 1060 1061int iwl_mvm_rx_bt_coex_notif_old(struct iwl_mvm *mvm, 1062 struct iwl_rx_cmd_buffer *rxb, 1063 struct iwl_device_cmd *dev_cmd) 1064{ 1065 struct iwl_rx_packet *pkt = rxb_addr(rxb); 1066 struct iwl_bt_coex_profile_notif_old *notif = (void *)pkt->data; 1067 1068 IWL_DEBUG_COEX(mvm, "BT Coex Notification received\n"); 1069 IWL_DEBUG_COEX(mvm, "\tBT status: %s\n", 1070 notif->bt_status ? "ON" : "OFF"); 1071 IWL_DEBUG_COEX(mvm, "\tBT open conn %d\n", notif->bt_open_conn); 1072 IWL_DEBUG_COEX(mvm, "\tBT ci compliance %d\n", notif->bt_ci_compliance); 1073 IWL_DEBUG_COEX(mvm, "\tBT primary_ch_lut %d\n", 1074 le32_to_cpu(notif->primary_ch_lut)); 1075 IWL_DEBUG_COEX(mvm, "\tBT secondary_ch_lut %d\n", 1076 le32_to_cpu(notif->secondary_ch_lut)); 1077 IWL_DEBUG_COEX(mvm, "\tBT activity grading %d\n", 1078 le32_to_cpu(notif->bt_activity_grading)); 1079 IWL_DEBUG_COEX(mvm, "\tBT agg traffic load %d\n", 1080 notif->bt_agg_traffic_load); 1081 1082 /* remember this notification for future use: rssi fluctuations */ 1083 memcpy(&mvm->last_bt_notif_old, notif, sizeof(mvm->last_bt_notif_old)); 1084 1085 iwl_mvm_bt_coex_notif_handle(mvm); 1086 1087 /* 1088 * This is an async handler for a notification, returning anything other 1089 * than 0 doesn't make sense even if HCMD failed. 1090 */ 1091 return 0; 1092} 1093 1094static void iwl_mvm_bt_rssi_iterator(void *_data, u8 *mac, 1095 struct ieee80211_vif *vif) 1096{ 1097 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 1098 struct iwl_bt_iterator_data *data = _data; 1099 struct iwl_mvm *mvm = data->mvm; 1100 1101 struct ieee80211_sta *sta; 1102 struct iwl_mvm_sta *mvmsta; 1103 1104 struct ieee80211_chanctx_conf *chanctx_conf; 1105 1106 rcu_read_lock(); 1107 chanctx_conf = rcu_dereference(vif->chanctx_conf); 1108 /* If channel context is invalid or not on 2.4GHz - don't count it */ 1109 if (!chanctx_conf || 1110 chanctx_conf->def.chan->band != IEEE80211_BAND_2GHZ) { 1111 rcu_read_unlock(); 1112 return; 1113 } 1114 rcu_read_unlock(); 1115 1116 if (vif->type != NL80211_IFTYPE_STATION || 1117 mvmvif->ap_sta_id == IWL_MVM_STATION_COUNT) 1118 return; 1119 1120 sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[mvmvif->ap_sta_id], 1121 lockdep_is_held(&mvm->mutex)); 1122 1123 /* This can happen if the station has been removed right now */ 1124 if (IS_ERR_OR_NULL(sta)) 1125 return; 1126 1127 mvmsta = iwl_mvm_sta_from_mac80211(sta); 1128} 1129 1130void iwl_mvm_bt_rssi_event_old(struct iwl_mvm *mvm, struct ieee80211_vif *vif, 1131 enum ieee80211_rssi_event_data rssi_event) 1132{ 1133 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 1134 struct iwl_bt_iterator_data data = { 1135 .mvm = mvm, 1136 }; 1137 int ret; 1138 1139 lockdep_assert_held(&mvm->mutex); 1140 1141 /* Ignore updates if we are in force mode */ 1142 if (unlikely(mvm->bt_force_ant_mode != BT_FORCE_ANT_DIS)) 1143 return; 1144 1145 /* 1146 * Rssi update while not associated - can happen since the statistics 1147 * are handled asynchronously 1148 */ 1149 if (mvmvif->ap_sta_id == IWL_MVM_STATION_COUNT) 1150 return; 1151 1152 /* No BT - reports should be disabled */ 1153 if (!mvm->last_bt_notif_old.bt_status) 1154 return; 1155 1156 IWL_DEBUG_COEX(mvm, "RSSI for %pM is now %s\n", vif->bss_conf.bssid, 1157 rssi_event == RSSI_EVENT_HIGH ? "HIGH" : "LOW"); 1158 1159 /* 1160 * Check if rssi is good enough for reduced Tx power, but not in loose 1161 * scheme. 1162 */ 1163 if (rssi_event == RSSI_EVENT_LOW || mvm->cfg->bt_shared_single_ant || 1164 iwl_get_coex_type(mvm, vif) == BT_COEX_LOOSE_LUT) 1165 ret = iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, 1166 false); 1167 else 1168 ret = iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, true); 1169 1170 if (ret) 1171 IWL_ERR(mvm, "couldn't send BT_CONFIG HCMD upon RSSI event\n"); 1172 1173 ieee80211_iterate_active_interfaces_atomic( 1174 mvm->hw, IEEE80211_IFACE_ITER_NORMAL, 1175 iwl_mvm_bt_rssi_iterator, &data); 1176 1177 if (iwl_mvm_bt_udpate_ctrl_kill_msk(mvm)) 1178 IWL_ERR(mvm, "Failed to update the ctrl_kill_msk\n"); 1179} 1180 1181#define LINK_QUAL_AGG_TIME_LIMIT_DEF (4000) 1182#define LINK_QUAL_AGG_TIME_LIMIT_BT_ACT (1200) 1183 1184u16 iwl_mvm_coex_agg_time_limit_old(struct iwl_mvm *mvm, 1185 struct ieee80211_sta *sta) 1186{ 1187 struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); 1188 enum iwl_bt_coex_lut_type lut_type; 1189 1190 if (le32_to_cpu(mvm->last_bt_notif_old.bt_activity_grading) < 1191 BT_HIGH_TRAFFIC) 1192 return LINK_QUAL_AGG_TIME_LIMIT_DEF; 1193 1194 if (mvm->last_bt_notif_old.ttc_enabled) 1195 return LINK_QUAL_AGG_TIME_LIMIT_DEF; 1196 1197 lut_type = iwl_get_coex_type(mvm, mvmsta->vif); 1198 1199 if (lut_type == BT_COEX_LOOSE_LUT || lut_type == BT_COEX_INVALID_LUT) 1200 return LINK_QUAL_AGG_TIME_LIMIT_DEF; 1201 1202 /* tight coex, high bt traffic, reduce AGG time limit */ 1203 return LINK_QUAL_AGG_TIME_LIMIT_BT_ACT; 1204} 1205 1206bool iwl_mvm_bt_coex_is_mimo_allowed_old(struct iwl_mvm *mvm, 1207 struct ieee80211_sta *sta) 1208{ 1209 struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); 1210 enum iwl_bt_coex_lut_type lut_type; 1211 1212 if (mvm->last_bt_notif_old.ttc_enabled) 1213 return true; 1214 1215 if (le32_to_cpu(mvm->last_bt_notif_old.bt_activity_grading) < 1216 BT_HIGH_TRAFFIC) 1217 return true; 1218 1219 /* 1220 * In Tight / TxTxDis, BT can't Rx while we Tx, so use both antennas 1221 * since BT is already killed. 1222 * In Loose, BT can Rx while we Tx, so forbid MIMO to let BT Rx while 1223 * we Tx. 1224 * When we are in 5GHz, we'll get BT_COEX_INVALID_LUT allowing MIMO. 1225 */ 1226 lut_type = iwl_get_coex_type(mvm, mvmsta->vif); 1227 return lut_type != BT_COEX_LOOSE_LUT; 1228} 1229 1230bool iwl_mvm_bt_coex_is_shared_ant_avail_old(struct iwl_mvm *mvm) 1231{ 1232 u32 ag = le32_to_cpu(mvm->last_bt_notif_old.bt_activity_grading); 1233 return ag < BT_HIGH_TRAFFIC; 1234} 1235 1236bool iwl_mvm_bt_coex_is_tpc_allowed_old(struct iwl_mvm *mvm, 1237 enum ieee80211_band band) 1238{ 1239 u32 bt_activity = 1240 le32_to_cpu(mvm->last_bt_notif_old.bt_activity_grading); 1241 1242 if (band != IEEE80211_BAND_2GHZ) 1243 return false; 1244 1245 return bt_activity >= BT_LOW_TRAFFIC; 1246} 1247 1248void iwl_mvm_bt_coex_vif_change_old(struct iwl_mvm *mvm) 1249{ 1250 iwl_mvm_bt_coex_notif_handle(mvm); 1251} 1252 1253int iwl_mvm_rx_ant_coupling_notif_old(struct iwl_mvm *mvm, 1254 struct iwl_rx_cmd_buffer *rxb, 1255 struct iwl_device_cmd *dev_cmd) 1256{ 1257 struct iwl_rx_packet *pkt = rxb_addr(rxb); 1258 u32 ant_isolation = le32_to_cpup((void *)pkt->data); 1259 u8 __maybe_unused lower_bound, upper_bound; 1260 int ret; 1261 u8 lut; 1262 1263 struct iwl_bt_coex_cmd_old *bt_cmd; 1264 struct iwl_host_cmd cmd = { 1265 .id = BT_CONFIG, 1266 .len = { sizeof(*bt_cmd), }, 1267 .dataflags = { IWL_HCMD_DFL_NOCOPY, }, 1268 }; 1269 1270 if (!iwl_mvm_bt_is_plcr_supported(mvm)) 1271 return 0; 1272 1273 lockdep_assert_held(&mvm->mutex); 1274 1275 /* Ignore updates if we are in force mode */ 1276 if (unlikely(mvm->bt_force_ant_mode != BT_FORCE_ANT_DIS)) 1277 return 0; 1278 1279 if (ant_isolation == mvm->last_ant_isol) 1280 return 0; 1281 1282 for (lut = 0; lut < ARRAY_SIZE(antenna_coupling_ranges) - 1; lut++) 1283 if (ant_isolation < antenna_coupling_ranges[lut + 1].range) 1284 break; 1285 1286 lower_bound = antenna_coupling_ranges[lut].range; 1287 1288 if (lut < ARRAY_SIZE(antenna_coupling_ranges) - 1) 1289 upper_bound = antenna_coupling_ranges[lut + 1].range; 1290 else 1291 upper_bound = antenna_coupling_ranges[lut].range; 1292 1293 IWL_DEBUG_COEX(mvm, "Antenna isolation=%d in range [%d,%d[, lut=%d\n", 1294 ant_isolation, lower_bound, upper_bound, lut); 1295 1296 mvm->last_ant_isol = ant_isolation; 1297 1298 if (mvm->last_corun_lut == lut) 1299 return 0; 1300 1301 mvm->last_corun_lut = lut; 1302 1303 bt_cmd = kzalloc(sizeof(*bt_cmd), GFP_KERNEL); 1304 if (!bt_cmd) 1305 return 0; 1306 cmd.data[0] = bt_cmd; 1307 1308 bt_cmd->flags = cpu_to_le32(BT_COEX_NW_OLD); 1309 bt_cmd->valid_bit_msk |= cpu_to_le32(BT_VALID_ENABLE | 1310 BT_VALID_CORUN_LUT_20 | 1311 BT_VALID_CORUN_LUT_40); 1312 1313 /* For the moment, use the same LUT for 20GHz and 40GHz */ 1314 memcpy(bt_cmd->bt4_corun_lut20, antenna_coupling_ranges[lut].lut20, 1315 sizeof(bt_cmd->bt4_corun_lut20)); 1316 1317 memcpy(bt_cmd->bt4_corun_lut40, antenna_coupling_ranges[lut].lut20, 1318 sizeof(bt_cmd->bt4_corun_lut40)); 1319 1320 ret = iwl_mvm_send_cmd(mvm, &cmd); 1321 1322 kfree(bt_cmd); 1323 return ret; 1324} 1325