coex.c revision d14b28fd2c61af0bf310230472e342864d799c98
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 BT_ANTENNA_COUPLING_THRESHOLD		(30)
76
77const u32 iwl_bt_ctl_kill_msk[BT_KILL_MSK_MAX] = {
78	[BT_KILL_MSK_DEFAULT] = 0xfffffc00,
79	[BT_KILL_MSK_NEVER] = 0xffffffff,
80	[BT_KILL_MSK_ALWAYS] = 0,
81};
82
83const u8 iwl_bt_cts_kill_msk[BT_MAX_AG][BT_COEX_MAX_LUT] = {
84	{
85		BT_KILL_MSK_ALWAYS,
86		BT_KILL_MSK_ALWAYS,
87		BT_KILL_MSK_ALWAYS,
88	},
89	{
90		BT_KILL_MSK_NEVER,
91		BT_KILL_MSK_NEVER,
92		BT_KILL_MSK_NEVER,
93	},
94	{
95		BT_KILL_MSK_NEVER,
96		BT_KILL_MSK_NEVER,
97		BT_KILL_MSK_NEVER,
98	},
99	{
100		BT_KILL_MSK_DEFAULT,
101		BT_KILL_MSK_NEVER,
102		BT_KILL_MSK_DEFAULT,
103	},
104};
105
106const u8 iwl_bt_ack_kill_msk[BT_MAX_AG][BT_COEX_MAX_LUT] = {
107	{
108		BT_KILL_MSK_ALWAYS,
109		BT_KILL_MSK_ALWAYS,
110		BT_KILL_MSK_ALWAYS,
111	},
112	{
113		BT_KILL_MSK_ALWAYS,
114		BT_KILL_MSK_ALWAYS,
115		BT_KILL_MSK_ALWAYS,
116	},
117	{
118		BT_KILL_MSK_ALWAYS,
119		BT_KILL_MSK_ALWAYS,
120		BT_KILL_MSK_ALWAYS,
121	},
122	{
123		BT_KILL_MSK_DEFAULT,
124		BT_KILL_MSK_ALWAYS,
125		BT_KILL_MSK_DEFAULT,
126	},
127};
128
129static const __le32 iwl_bt_prio_boost[BT_COEX_BOOST_SIZE] = {
130	cpu_to_le32(0xf0f0f0f0), /* 50% */
131	cpu_to_le32(0xc0c0c0c0), /* 25% */
132	cpu_to_le32(0xfcfcfcfc), /* 75% */
133	cpu_to_le32(0xfefefefe), /* 87.5% */
134};
135
136static const __le32 iwl_single_shared_ant[BT_COEX_MAX_LUT][BT_COEX_LUT_SIZE] = {
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		cpu_to_le32(0x40000000),
167		cpu_to_le32(0x00000000),
168		cpu_to_le32(0x44000000),
169		cpu_to_le32(0x00000000),
170		cpu_to_le32(0x40000000),
171		cpu_to_le32(0x00000000),
172		cpu_to_le32(0x44000000),
173		cpu_to_le32(0x00000000),
174		cpu_to_le32(0xc0004000),
175		cpu_to_le32(0xf0005000),
176		cpu_to_le32(0xc0004000),
177		cpu_to_le32(0xf0005000),
178	},
179};
180
181static const __le32 iwl_combined_lookup[BT_COEX_MAX_LUT][BT_COEX_LUT_SIZE] = {
182	{
183		/* Tight */
184		cpu_to_le32(0xaaaaaaaa),
185		cpu_to_le32(0xaaaaaaaa),
186		cpu_to_le32(0xaeaaaaaa),
187		cpu_to_le32(0xaaaaaaaa),
188		cpu_to_le32(0xcc00ff28),
189		cpu_to_le32(0x0000aaaa),
190		cpu_to_le32(0xcc00aaaa),
191		cpu_to_le32(0x0000aaaa),
192		cpu_to_le32(0xc0004000),
193		cpu_to_le32(0x00004000),
194		cpu_to_le32(0xf0005000),
195		cpu_to_le32(0xf0005000),
196	},
197	{
198		/* Loose */
199		cpu_to_le32(0xaaaaaaaa),
200		cpu_to_le32(0xaaaaaaaa),
201		cpu_to_le32(0xaaaaaaaa),
202		cpu_to_le32(0xaaaaaaaa),
203		cpu_to_le32(0xcc00ff28),
204		cpu_to_le32(0x0000aaaa),
205		cpu_to_le32(0xcc00aaaa),
206		cpu_to_le32(0x0000aaaa),
207		cpu_to_le32(0x00000000),
208		cpu_to_le32(0x00000000),
209		cpu_to_le32(0xf0005000),
210		cpu_to_le32(0xf0005000),
211	},
212	{
213		/* Tx Tx disabled */
214		cpu_to_le32(0xaaaaaaaa),
215		cpu_to_le32(0xaaaaaaaa),
216		cpu_to_le32(0xeeaaaaaa),
217		cpu_to_le32(0xaaaaaaaa),
218		cpu_to_le32(0xcc00ff28),
219		cpu_to_le32(0x0000aaaa),
220		cpu_to_le32(0xcc00aaaa),
221		cpu_to_le32(0x0000aaaa),
222		cpu_to_le32(0xc0004000),
223		cpu_to_le32(0xc0004000),
224		cpu_to_le32(0xf0005000),
225		cpu_to_le32(0xf0005000),
226	},
227};
228
229/* 20MHz / 40MHz below / 40Mhz above*/
230static const __le64 iwl_ci_mask[][3] = {
231	/* dummy entry for channel 0 */
232	{cpu_to_le64(0), cpu_to_le64(0), cpu_to_le64(0)},
233	{
234		cpu_to_le64(0x0000001FFFULL),
235		cpu_to_le64(0x0ULL),
236		cpu_to_le64(0x00007FFFFFULL),
237	},
238	{
239		cpu_to_le64(0x000000FFFFULL),
240		cpu_to_le64(0x0ULL),
241		cpu_to_le64(0x0003FFFFFFULL),
242	},
243	{
244		cpu_to_le64(0x000003FFFCULL),
245		cpu_to_le64(0x0ULL),
246		cpu_to_le64(0x000FFFFFFCULL),
247	},
248	{
249		cpu_to_le64(0x00001FFFE0ULL),
250		cpu_to_le64(0x0ULL),
251		cpu_to_le64(0x007FFFFFE0ULL),
252	},
253	{
254		cpu_to_le64(0x00007FFF80ULL),
255		cpu_to_le64(0x00007FFFFFULL),
256		cpu_to_le64(0x01FFFFFF80ULL),
257	},
258	{
259		cpu_to_le64(0x0003FFFC00ULL),
260		cpu_to_le64(0x0003FFFFFFULL),
261		cpu_to_le64(0x0FFFFFFC00ULL),
262	},
263	{
264		cpu_to_le64(0x000FFFF000ULL),
265		cpu_to_le64(0x000FFFFFFCULL),
266		cpu_to_le64(0x3FFFFFF000ULL),
267	},
268	{
269		cpu_to_le64(0x007FFF8000ULL),
270		cpu_to_le64(0x007FFFFFE0ULL),
271		cpu_to_le64(0xFFFFFF8000ULL),
272	},
273	{
274		cpu_to_le64(0x01FFFE0000ULL),
275		cpu_to_le64(0x01FFFFFF80ULL),
276		cpu_to_le64(0xFFFFFE0000ULL),
277	},
278	{
279		cpu_to_le64(0x0FFFF00000ULL),
280		cpu_to_le64(0x0FFFFFFC00ULL),
281		cpu_to_le64(0x0ULL),
282	},
283	{
284		cpu_to_le64(0x3FFFC00000ULL),
285		cpu_to_le64(0x3FFFFFF000ULL),
286		cpu_to_le64(0x0)
287	},
288	{
289		cpu_to_le64(0xFFFE000000ULL),
290		cpu_to_le64(0xFFFFFF8000ULL),
291		cpu_to_le64(0x0)
292	},
293	{
294		cpu_to_le64(0xFFF8000000ULL),
295		cpu_to_le64(0xFFFFFE0000ULL),
296		cpu_to_le64(0x0)
297	},
298	{
299		cpu_to_le64(0xFFC0000000ULL),
300		cpu_to_le64(0x0ULL),
301		cpu_to_le64(0x0ULL)
302	},
303};
304
305static const __le32 iwl_bt_mprio_lut[BT_COEX_MULTI_PRIO_LUT_SIZE] = {
306	cpu_to_le32(0x2e402280),
307	cpu_to_le32(0x7711a751),
308};
309
310struct corunning_block_luts {
311	u8 range;
312	__le32 lut20[BT_COEX_CORUN_LUT_SIZE];
313};
314
315/*
316 * Ranges for the antenna coupling calibration / co-running block LUT:
317 *		LUT0: [ 0, 12[
318 *		LUT1: [12, 20[
319 *		LUT2: [20, 21[
320 *		LUT3: [21, 23[
321 *		LUT4: [23, 27[
322 *		LUT5: [27, 30[
323 *		LUT6: [30, 32[
324 *		LUT7: [32, 33[
325 *		LUT8: [33, - [
326 */
327static const struct corunning_block_luts antenna_coupling_ranges[] = {
328	{
329		.range = 0,
330		.lut20 = {
331			cpu_to_le32(0x00000000),  cpu_to_le32(0x00000000),
332			cpu_to_le32(0x00000000),  cpu_to_le32(0x00000000),
333			cpu_to_le32(0x00000000),  cpu_to_le32(0x00000000),
334			cpu_to_le32(0x00000000),  cpu_to_le32(0x00000000),
335			cpu_to_le32(0x00000000),  cpu_to_le32(0x00000000),
336			cpu_to_le32(0x00000000),  cpu_to_le32(0x00000000),
337			cpu_to_le32(0x00000000),  cpu_to_le32(0x00000000),
338			cpu_to_le32(0x00000000),  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		},
348	},
349	{
350		.range = 12,
351		.lut20 = {
352			cpu_to_le32(0x00000001),  cpu_to_le32(0x00000000),
353			cpu_to_le32(0x00000000),  cpu_to_le32(0x00000000),
354			cpu_to_le32(0x00000000),  cpu_to_le32(0x00000000),
355			cpu_to_le32(0x00000000),  cpu_to_le32(0x00000000),
356			cpu_to_le32(0x00000000),  cpu_to_le32(0x00000000),
357			cpu_to_le32(0x00000000),  cpu_to_le32(0x00000000),
358			cpu_to_le32(0x00000000),  cpu_to_le32(0x00000000),
359			cpu_to_le32(0x00000000),  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		},
369	},
370	{
371		.range = 20,
372		.lut20 = {
373			cpu_to_le32(0x00000002),  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			cpu_to_le32(0x00000000),  cpu_to_le32(0x00000000),
388			cpu_to_le32(0x00000000),  cpu_to_le32(0x00000000),
389		},
390	},
391	{
392		.range = 21,
393		.lut20 = {
394			cpu_to_le32(0x00000003),  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			cpu_to_le32(0x00000000),  cpu_to_le32(0x00000000),
409			cpu_to_le32(0x00000000),  cpu_to_le32(0x00000000),
410		},
411	},
412	{
413		.range = 23,
414		.lut20 = {
415			cpu_to_le32(0x00000004),  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			cpu_to_le32(0x00000000),  cpu_to_le32(0x00000000),
430			cpu_to_le32(0x00000000),  cpu_to_le32(0x00000000),
431		},
432	},
433	{
434		.range = 27,
435		.lut20 = {
436			cpu_to_le32(0x00000005),  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			cpu_to_le32(0x00000000),  cpu_to_le32(0x00000000),
451			cpu_to_le32(0x00000000),  cpu_to_le32(0x00000000),
452		},
453	},
454	{
455		.range = 30,
456		.lut20 = {
457			cpu_to_le32(0x00000006),  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			cpu_to_le32(0x00000000),  cpu_to_le32(0x00000000),
472			cpu_to_le32(0x00000000),  cpu_to_le32(0x00000000),
473		},
474	},
475	{
476		.range = 32,
477		.lut20 = {
478			cpu_to_le32(0x00000007),  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			cpu_to_le32(0x00000000),  cpu_to_le32(0x00000000),
493			cpu_to_le32(0x00000000),  cpu_to_le32(0x00000000),
494		},
495	},
496	{
497		.range = 33,
498		.lut20 = {
499			cpu_to_le32(0x00000008),  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			cpu_to_le32(0x00000000),  cpu_to_le32(0x00000000),
514			cpu_to_le32(0x00000000),  cpu_to_le32(0x00000000),
515		},
516	},
517};
518
519static enum iwl_bt_coex_lut_type
520iwl_get_coex_type(struct iwl_mvm *mvm, const struct ieee80211_vif *vif)
521{
522	struct ieee80211_chanctx_conf *chanctx_conf;
523	enum iwl_bt_coex_lut_type ret;
524	u16 phy_ctx_id;
525	u32 primary_ch_phy_id, secondary_ch_phy_id;
526
527	/*
528	 * Checking that we hold mvm->mutex is a good idea, but the rate
529	 * control can't acquire the mutex since it runs in Tx path.
530	 * So this is racy in that case, but in the worst case, the AMPDU
531	 * size limit will be wrong for a short time which is not a big
532	 * issue.
533	 */
534
535	rcu_read_lock();
536
537	chanctx_conf = rcu_dereference(vif->chanctx_conf);
538
539	if (!chanctx_conf ||
540	     chanctx_conf->def.chan->band != IEEE80211_BAND_2GHZ) {
541		rcu_read_unlock();
542		return BT_COEX_INVALID_LUT;
543	}
544
545	ret = BT_COEX_TX_DIS_LUT;
546
547	if (mvm->cfg->bt_shared_single_ant) {
548		rcu_read_unlock();
549		return ret;
550	}
551
552	phy_ctx_id = *((u16 *)chanctx_conf->drv_priv);
553	primary_ch_phy_id = le32_to_cpu(mvm->last_bt_ci_cmd.primary_ch_phy_id);
554	secondary_ch_phy_id =
555		le32_to_cpu(mvm->last_bt_ci_cmd.secondary_ch_phy_id);
556
557	if (primary_ch_phy_id == phy_ctx_id)
558		ret = le32_to_cpu(mvm->last_bt_notif.primary_ch_lut);
559	else if (secondary_ch_phy_id == phy_ctx_id)
560		ret = le32_to_cpu(mvm->last_bt_notif.secondary_ch_lut);
561	/* else - default = TX TX disallowed */
562
563	rcu_read_unlock();
564
565	return ret;
566}
567
568int iwl_send_bt_init_conf(struct iwl_mvm *mvm)
569{
570	struct iwl_bt_coex_cmd *bt_cmd;
571	struct iwl_host_cmd cmd = {
572		.id = BT_CONFIG,
573		.len = { sizeof(*bt_cmd), },
574		.dataflags = { IWL_HCMD_DFL_NOCOPY, },
575	};
576	int ret;
577	u32 mode;
578
579	if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BT_COEX_SPLIT))
580		return iwl_send_bt_init_conf_old(mvm);
581
582	bt_cmd = kzalloc(sizeof(*bt_cmd), GFP_KERNEL);
583	if (!bt_cmd)
584		return -ENOMEM;
585	cmd.data[0] = bt_cmd;
586
587	lockdep_assert_held(&mvm->mutex);
588
589	if (unlikely(mvm->bt_force_ant_mode != BT_FORCE_ANT_DIS)) {
590		switch (mvm->bt_force_ant_mode) {
591		case BT_FORCE_ANT_BT:
592			mode = BT_COEX_BT;
593			break;
594		case BT_FORCE_ANT_WIFI:
595			mode = BT_COEX_WIFI;
596			break;
597		default:
598			WARN_ON(1);
599			mode = 0;
600		}
601
602		bt_cmd->mode = cpu_to_le32(mode);
603		goto send_cmd;
604	}
605
606	bt_cmd->max_kill = cpu_to_le32(5);
607	bt_cmd->bt4_antenna_isolation_thr =
608				cpu_to_le32(BT_ANTENNA_COUPLING_THRESHOLD);
609	bt_cmd->bt4_tx_tx_delta_freq_thr = cpu_to_le32(15);
610	bt_cmd->bt4_tx_rx_max_freq0 = cpu_to_le32(15);
611	bt_cmd->override_primary_lut = cpu_to_le32(BT_COEX_INVALID_LUT);
612	bt_cmd->override_secondary_lut = cpu_to_le32(BT_COEX_INVALID_LUT);
613
614	mode = iwlwifi_mod_params.bt_coex_active ? BT_COEX_NW : BT_COEX_DISABLE;
615	bt_cmd->mode = cpu_to_le32(mode);
616
617	if (IWL_MVM_BT_COEX_SYNC2SCO)
618		bt_cmd->enabled_modules |=
619			cpu_to_le32(BT_COEX_SYNC2SCO_ENABLED);
620
621	if (IWL_MVM_BT_COEX_CORUNNING)
622		bt_cmd->enabled_modules |= cpu_to_le32(BT_COEX_CORUN_ENABLED);
623
624	if (IWL_MVM_BT_COEX_MPLUT) {
625		bt_cmd->enabled_modules |= cpu_to_le32(BT_COEX_MPLUT_ENABLED);
626		bt_cmd->enabled_modules |=
627			cpu_to_le32(BT_COEX_MPLUT_BOOST_ENABLED);
628	}
629
630	bt_cmd->enabled_modules |= cpu_to_le32(BT_COEX_HIGH_BAND_RET);
631
632	if (mvm->cfg->bt_shared_single_ant)
633		memcpy(&bt_cmd->decision_lut, iwl_single_shared_ant,
634		       sizeof(iwl_single_shared_ant));
635	else
636		memcpy(&bt_cmd->decision_lut, iwl_combined_lookup,
637		       sizeof(iwl_combined_lookup));
638
639	memcpy(&bt_cmd->mplut_prio_boost, iwl_bt_prio_boost,
640	       sizeof(iwl_bt_prio_boost));
641	memcpy(&bt_cmd->multiprio_lut, iwl_bt_mprio_lut,
642	       sizeof(iwl_bt_mprio_lut));
643
644send_cmd:
645	memset(&mvm->last_bt_notif, 0, sizeof(mvm->last_bt_notif));
646	memset(&mvm->last_bt_ci_cmd, 0, sizeof(mvm->last_bt_ci_cmd));
647
648	ret = iwl_mvm_send_cmd(mvm, &cmd);
649
650	kfree(bt_cmd);
651	return ret;
652}
653
654static int iwl_mvm_bt_udpate_sw_boost(struct iwl_mvm *mvm)
655{
656	struct iwl_bt_coex_profile_notif *notif = &mvm->last_bt_notif;
657	u32 primary_lut = le32_to_cpu(notif->primary_ch_lut);
658	u32 secondary_lut = le32_to_cpu(notif->secondary_ch_lut);
659	u32 ag = le32_to_cpu(notif->bt_activity_grading);
660	struct iwl_bt_coex_sw_boost_update_cmd cmd = {};
661	u8 ack_kill_msk[NUM_PHY_CTX] = {};
662	u8 cts_kill_msk[NUM_PHY_CTX] = {};
663	int i;
664
665	lockdep_assert_held(&mvm->mutex);
666
667	ack_kill_msk[0] = iwl_bt_ack_kill_msk[ag][primary_lut];
668	cts_kill_msk[0] = iwl_bt_cts_kill_msk[ag][primary_lut];
669
670	ack_kill_msk[1] = iwl_bt_ack_kill_msk[ag][secondary_lut];
671	cts_kill_msk[1] = iwl_bt_cts_kill_msk[ag][secondary_lut];
672
673	/* Don't send HCMD if there is no update */
674	if (!memcmp(ack_kill_msk, mvm->bt_ack_kill_msk, sizeof(ack_kill_msk)) ||
675	    !memcmp(cts_kill_msk, mvm->bt_cts_kill_msk, sizeof(cts_kill_msk)))
676		return 0;
677
678	memcpy(mvm->bt_ack_kill_msk, ack_kill_msk,
679	       sizeof(mvm->bt_ack_kill_msk));
680	memcpy(mvm->bt_cts_kill_msk, cts_kill_msk,
681	       sizeof(mvm->bt_cts_kill_msk));
682
683	BUILD_BUG_ON(ARRAY_SIZE(ack_kill_msk) < ARRAY_SIZE(cmd.boost_values));
684
685	for (i = 0; i < ARRAY_SIZE(cmd.boost_values); i++) {
686		cmd.boost_values[i].kill_ack_msk =
687			cpu_to_le32(iwl_bt_ctl_kill_msk[ack_kill_msk[i]]);
688		cmd.boost_values[i].kill_cts_msk =
689			cpu_to_le32(iwl_bt_ctl_kill_msk[cts_kill_msk[i]]);
690	}
691
692	return iwl_mvm_send_cmd_pdu(mvm, BT_COEX_UPDATE_SW_BOOST, 0,
693				    sizeof(cmd), &cmd);
694}
695
696static int iwl_mvm_bt_coex_reduced_txp(struct iwl_mvm *mvm, u8 sta_id,
697				       bool enable)
698{
699	struct iwl_bt_coex_reduced_txp_update_cmd cmd = {};
700	struct iwl_mvm_sta *mvmsta;
701	u32 value;
702	int ret;
703
704	mvmsta = iwl_mvm_sta_from_staid_protected(mvm, sta_id);
705	if (!mvmsta)
706		return 0;
707
708	/* nothing to do */
709	if (mvmsta->bt_reduced_txpower == enable)
710		return 0;
711
712	value = mvmsta->sta_id;
713
714	if (enable)
715		value |= BT_REDUCED_TX_POWER_BIT;
716
717	IWL_DEBUG_COEX(mvm, "%sable reduced Tx Power for sta %d\n",
718		       enable ? "en" : "dis", sta_id);
719
720	cmd.reduced_txp = cpu_to_le32(value);
721	mvmsta->bt_reduced_txpower = enable;
722
723	ret = iwl_mvm_send_cmd_pdu(mvm, BT_COEX_UPDATE_REDUCED_TXP, CMD_ASYNC,
724				   sizeof(cmd), &cmd);
725
726	return ret;
727}
728
729struct iwl_bt_iterator_data {
730	struct iwl_bt_coex_profile_notif *notif;
731	struct iwl_mvm *mvm;
732	struct ieee80211_chanctx_conf *primary;
733	struct ieee80211_chanctx_conf *secondary;
734	bool primary_ll;
735};
736
737static inline
738void iwl_mvm_bt_coex_enable_rssi_event(struct iwl_mvm *mvm,
739				       struct ieee80211_vif *vif,
740				       bool enable, int rssi)
741{
742	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
743
744	mvmvif->bf_data.last_bt_coex_event = rssi;
745	mvmvif->bf_data.bt_coex_max_thold =
746		enable ? -IWL_MVM_BT_COEX_EN_RED_TXP_THRESH : 0;
747	mvmvif->bf_data.bt_coex_min_thold =
748		enable ? -IWL_MVM_BT_COEX_DIS_RED_TXP_THRESH : 0;
749}
750
751/* must be called under rcu_read_lock */
752static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac,
753				      struct ieee80211_vif *vif)
754{
755	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
756	struct iwl_bt_iterator_data *data = _data;
757	struct iwl_mvm *mvm = data->mvm;
758	struct ieee80211_chanctx_conf *chanctx_conf;
759	/* default smps_mode is AUTOMATIC - only used for client modes */
760	enum ieee80211_smps_mode smps_mode = IEEE80211_SMPS_AUTOMATIC;
761	u32 bt_activity_grading;
762	int ave_rssi;
763
764	lockdep_assert_held(&mvm->mutex);
765
766	switch (vif->type) {
767	case NL80211_IFTYPE_STATION:
768		break;
769	case NL80211_IFTYPE_AP:
770		if (!mvmvif->ap_ibss_active)
771			return;
772		break;
773	default:
774		return;
775	}
776
777	chanctx_conf = rcu_dereference(vif->chanctx_conf);
778
779	/* If channel context is invalid or not on 2.4GHz .. */
780	if ((!chanctx_conf ||
781	     chanctx_conf->def.chan->band != IEEE80211_BAND_2GHZ)) {
782		if (vif->type == NL80211_IFTYPE_STATION) {
783			/* ... relax constraints and disable rssi events */
784			iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX,
785					    smps_mode);
786			iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id,
787						    false);
788			iwl_mvm_bt_coex_enable_rssi_event(mvm, vif, false, 0);
789		}
790		return;
791	}
792
793	bt_activity_grading = le32_to_cpu(data->notif->bt_activity_grading);
794	if (bt_activity_grading >= BT_HIGH_TRAFFIC)
795		smps_mode = IEEE80211_SMPS_STATIC;
796	else if (bt_activity_grading >= BT_LOW_TRAFFIC)
797		smps_mode = IEEE80211_SMPS_DYNAMIC;
798
799	/* relax SMPS constraints for next association */
800	if (!vif->bss_conf.assoc)
801		smps_mode = IEEE80211_SMPS_AUTOMATIC;
802
803	if (IWL_COEX_IS_RRC_ON(mvm->last_bt_notif.ttc_rrc_status,
804			       mvmvif->phy_ctxt->id))
805		smps_mode = IEEE80211_SMPS_AUTOMATIC;
806
807	IWL_DEBUG_COEX(data->mvm,
808		       "mac %d: bt_activity_grading %d smps_req %d\n",
809		       mvmvif->id, bt_activity_grading, smps_mode);
810
811	if (vif->type == NL80211_IFTYPE_STATION)
812		iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX,
813				    smps_mode);
814
815	/* low latency is always primary */
816	if (iwl_mvm_vif_low_latency(mvmvif)) {
817		data->primary_ll = true;
818
819		data->secondary = data->primary;
820		data->primary = chanctx_conf;
821	}
822
823	if (vif->type == NL80211_IFTYPE_AP) {
824		if (!mvmvif->ap_ibss_active)
825			return;
826
827		if (chanctx_conf == data->primary)
828			return;
829
830		if (!data->primary_ll) {
831			/*
832			 * downgrade the current primary no matter what its
833			 * type is.
834			 */
835			data->secondary = data->primary;
836			data->primary = chanctx_conf;
837		} else {
838			/* there is low latency vif - we will be secondary */
839			data->secondary = chanctx_conf;
840		}
841		return;
842	}
843
844	/*
845	 * STA / P2P Client, try to be primary if first vif. If we are in low
846	 * latency mode, we are already in primary and just don't do much
847	 */
848	if (!data->primary || data->primary == chanctx_conf)
849		data->primary = chanctx_conf;
850	else if (!data->secondary)
851		/* if secondary is not NULL, it might be a GO */
852		data->secondary = chanctx_conf;
853
854	/*
855	 * don't reduce the Tx power if one of these is true:
856	 *  we are in LOOSE
857	 *  single share antenna product
858	 *  BT is active
859	 *  we are associated
860	 */
861	if (iwl_get_coex_type(mvm, vif) == BT_COEX_LOOSE_LUT ||
862	    mvm->cfg->bt_shared_single_ant || !vif->bss_conf.assoc ||
863	    le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) == BT_OFF) {
864		iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, false);
865		iwl_mvm_bt_coex_enable_rssi_event(mvm, vif, false, 0);
866		return;
867	}
868
869	/* try to get the avg rssi from fw */
870	ave_rssi = mvmvif->bf_data.ave_beacon_signal;
871
872	/* if the RSSI isn't valid, fake it is very low */
873	if (!ave_rssi)
874		ave_rssi = -100;
875	if (ave_rssi > -IWL_MVM_BT_COEX_EN_RED_TXP_THRESH) {
876		if (iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, true))
877			IWL_ERR(mvm, "Couldn't send BT_CONFIG cmd\n");
878	} else if (ave_rssi < -IWL_MVM_BT_COEX_DIS_RED_TXP_THRESH) {
879		if (iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, false))
880			IWL_ERR(mvm, "Couldn't send BT_CONFIG cmd\n");
881	}
882
883	/* Begin to monitor the RSSI: it may influence the reduced Tx power */
884	iwl_mvm_bt_coex_enable_rssi_event(mvm, vif, true, ave_rssi);
885}
886
887static void iwl_mvm_bt_coex_notif_handle(struct iwl_mvm *mvm)
888{
889	struct iwl_bt_iterator_data data = {
890		.mvm = mvm,
891		.notif = &mvm->last_bt_notif,
892	};
893	struct iwl_bt_coex_ci_cmd cmd = {};
894	u8 ci_bw_idx;
895
896	/* Ignore updates if we are in force mode */
897	if (unlikely(mvm->bt_force_ant_mode != BT_FORCE_ANT_DIS))
898		return;
899
900	rcu_read_lock();
901	ieee80211_iterate_active_interfaces_atomic(
902					mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
903					iwl_mvm_bt_notif_iterator, &data);
904
905	if (data.primary) {
906		struct ieee80211_chanctx_conf *chan = data.primary;
907		if (WARN_ON(!chan->def.chan)) {
908			rcu_read_unlock();
909			return;
910		}
911
912		if (chan->def.width < NL80211_CHAN_WIDTH_40) {
913			ci_bw_idx = 0;
914		} else {
915			if (chan->def.center_freq1 >
916			    chan->def.chan->center_freq)
917				ci_bw_idx = 2;
918			else
919				ci_bw_idx = 1;
920		}
921
922		cmd.bt_primary_ci =
923			iwl_ci_mask[chan->def.chan->hw_value][ci_bw_idx];
924		cmd.primary_ch_phy_id =
925			cpu_to_le32(*((u16 *)data.primary->drv_priv));
926	}
927
928	if (data.secondary) {
929		struct ieee80211_chanctx_conf *chan = data.secondary;
930		if (WARN_ON(!data.secondary->def.chan)) {
931			rcu_read_unlock();
932			return;
933		}
934
935		if (chan->def.width < NL80211_CHAN_WIDTH_40) {
936			ci_bw_idx = 0;
937		} else {
938			if (chan->def.center_freq1 >
939			    chan->def.chan->center_freq)
940				ci_bw_idx = 2;
941			else
942				ci_bw_idx = 1;
943		}
944
945		cmd.bt_secondary_ci =
946			iwl_ci_mask[chan->def.chan->hw_value][ci_bw_idx];
947		cmd.secondary_ch_phy_id =
948			cpu_to_le32(*((u16 *)data.secondary->drv_priv));
949	}
950
951	rcu_read_unlock();
952
953	/* Don't spam the fw with the same command over and over */
954	if (memcmp(&cmd, &mvm->last_bt_ci_cmd, sizeof(cmd))) {
955		if (iwl_mvm_send_cmd_pdu(mvm, BT_COEX_CI, 0,
956					 sizeof(cmd), &cmd))
957			IWL_ERR(mvm, "Failed to send BT_CI cmd\n");
958		memcpy(&mvm->last_bt_ci_cmd, &cmd, sizeof(cmd));
959	}
960
961	if (iwl_mvm_bt_udpate_sw_boost(mvm))
962		IWL_ERR(mvm, "Failed to update the ctrl_kill_msk\n");
963}
964
965int iwl_mvm_rx_bt_coex_notif(struct iwl_mvm *mvm,
966			     struct iwl_rx_cmd_buffer *rxb,
967			     struct iwl_device_cmd *dev_cmd)
968{
969	struct iwl_rx_packet *pkt = rxb_addr(rxb);
970	struct iwl_bt_coex_profile_notif *notif = (void *)pkt->data;
971
972	if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BT_COEX_SPLIT))
973		return iwl_mvm_rx_bt_coex_notif_old(mvm, rxb, dev_cmd);
974
975	IWL_DEBUG_COEX(mvm, "BT Coex Notification received\n");
976	IWL_DEBUG_COEX(mvm, "\tBT ci compliance %d\n", notif->bt_ci_compliance);
977	IWL_DEBUG_COEX(mvm, "\tBT primary_ch_lut %d\n",
978		       le32_to_cpu(notif->primary_ch_lut));
979	IWL_DEBUG_COEX(mvm, "\tBT secondary_ch_lut %d\n",
980		       le32_to_cpu(notif->secondary_ch_lut));
981	IWL_DEBUG_COEX(mvm, "\tBT activity grading %d\n",
982		       le32_to_cpu(notif->bt_activity_grading));
983
984	/* remember this notification for future use: rssi fluctuations */
985	memcpy(&mvm->last_bt_notif, notif, sizeof(mvm->last_bt_notif));
986
987	iwl_mvm_bt_coex_notif_handle(mvm);
988
989	/*
990	 * This is an async handler for a notification, returning anything other
991	 * than 0 doesn't make sense even if HCMD failed.
992	 */
993	return 0;
994}
995
996static void iwl_mvm_bt_rssi_iterator(void *_data, u8 *mac,
997				   struct ieee80211_vif *vif)
998{
999	struct iwl_mvm_vif *mvmvif = (void *)vif->drv_priv;
1000	struct iwl_bt_iterator_data *data = _data;
1001	struct iwl_mvm *mvm = data->mvm;
1002
1003	struct ieee80211_sta *sta;
1004	struct iwl_mvm_sta *mvmsta;
1005
1006	struct ieee80211_chanctx_conf *chanctx_conf;
1007
1008	rcu_read_lock();
1009	chanctx_conf = rcu_dereference(vif->chanctx_conf);
1010	/* If channel context is invalid or not on 2.4GHz - don't count it */
1011	if (!chanctx_conf ||
1012	    chanctx_conf->def.chan->band != IEEE80211_BAND_2GHZ) {
1013		rcu_read_unlock();
1014		return;
1015	}
1016	rcu_read_unlock();
1017
1018	if (vif->type != NL80211_IFTYPE_STATION ||
1019	    mvmvif->ap_sta_id == IWL_MVM_STATION_COUNT)
1020		return;
1021
1022	sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[mvmvif->ap_sta_id],
1023					lockdep_is_held(&mvm->mutex));
1024
1025	/* This can happen if the station has been removed right now */
1026	if (IS_ERR_OR_NULL(sta))
1027		return;
1028
1029	mvmsta = iwl_mvm_sta_from_mac80211(sta);
1030}
1031
1032void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
1033			   enum ieee80211_rssi_event rssi_event)
1034{
1035	struct iwl_mvm_vif *mvmvif = (void *)vif->drv_priv;
1036	struct iwl_bt_iterator_data data = {
1037		.mvm = mvm,
1038	};
1039	int ret;
1040
1041	if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BT_COEX_SPLIT)) {
1042		iwl_mvm_bt_rssi_event_old(mvm, vif, rssi_event);
1043		return;
1044	}
1045
1046	lockdep_assert_held(&mvm->mutex);
1047
1048	/* Ignore updates if we are in force mode */
1049	if (unlikely(mvm->bt_force_ant_mode != BT_FORCE_ANT_DIS))
1050		return;
1051
1052	/*
1053	 * Rssi update while not associated - can happen since the statistics
1054	 * are handled asynchronously
1055	 */
1056	if (mvmvif->ap_sta_id == IWL_MVM_STATION_COUNT)
1057		return;
1058
1059	/* No BT - reports should be disabled */
1060	if (le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) == BT_OFF)
1061		return;
1062
1063	IWL_DEBUG_COEX(mvm, "RSSI for %pM is now %s\n", vif->bss_conf.bssid,
1064		       rssi_event == RSSI_EVENT_HIGH ? "HIGH" : "LOW");
1065
1066	/*
1067	 * Check if rssi is good enough for reduced Tx power, but not in loose
1068	 * scheme.
1069	 */
1070	if (rssi_event == RSSI_EVENT_LOW || mvm->cfg->bt_shared_single_ant ||
1071	    iwl_get_coex_type(mvm, vif) == BT_COEX_LOOSE_LUT)
1072		ret = iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id,
1073						  false);
1074	else
1075		ret = iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, true);
1076
1077	if (ret)
1078		IWL_ERR(mvm, "couldn't send BT_CONFIG HCMD upon RSSI event\n");
1079
1080	ieee80211_iterate_active_interfaces_atomic(
1081		mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
1082		iwl_mvm_bt_rssi_iterator, &data);
1083
1084	if (iwl_mvm_bt_udpate_sw_boost(mvm))
1085		IWL_ERR(mvm, "Failed to update the ctrl_kill_msk\n");
1086}
1087
1088#define LINK_QUAL_AGG_TIME_LIMIT_DEF	(4000)
1089#define LINK_QUAL_AGG_TIME_LIMIT_BT_ACT	(1200)
1090
1091u16 iwl_mvm_coex_agg_time_limit(struct iwl_mvm *mvm,
1092				struct ieee80211_sta *sta)
1093{
1094	struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
1095	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(mvmsta->vif);
1096	struct iwl_mvm_phy_ctxt *phy_ctxt = mvmvif->phy_ctxt;
1097	enum iwl_bt_coex_lut_type lut_type;
1098
1099	if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BT_COEX_SPLIT))
1100		return iwl_mvm_coex_agg_time_limit_old(mvm, sta);
1101
1102	if (IWL_COEX_IS_TTC_ON(mvm->last_bt_notif.ttc_rrc_status, phy_ctxt->id))
1103		return LINK_QUAL_AGG_TIME_LIMIT_DEF;
1104
1105	if (le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) <
1106	    BT_HIGH_TRAFFIC)
1107		return LINK_QUAL_AGG_TIME_LIMIT_DEF;
1108
1109	lut_type = iwl_get_coex_type(mvm, mvmsta->vif);
1110
1111	if (lut_type == BT_COEX_LOOSE_LUT || lut_type == BT_COEX_INVALID_LUT)
1112		return LINK_QUAL_AGG_TIME_LIMIT_DEF;
1113
1114	/* tight coex, high bt traffic, reduce AGG time limit */
1115	return LINK_QUAL_AGG_TIME_LIMIT_BT_ACT;
1116}
1117
1118bool iwl_mvm_bt_coex_is_mimo_allowed(struct iwl_mvm *mvm,
1119				     struct ieee80211_sta *sta)
1120{
1121	struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
1122	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(mvmsta->vif);
1123	struct iwl_mvm_phy_ctxt *phy_ctxt = mvmvif->phy_ctxt;
1124	enum iwl_bt_coex_lut_type lut_type;
1125
1126	if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BT_COEX_SPLIT))
1127		return iwl_mvm_bt_coex_is_mimo_allowed_old(mvm, sta);
1128
1129	if (IWL_COEX_IS_TTC_ON(mvm->last_bt_notif.ttc_rrc_status, phy_ctxt->id))
1130		return true;
1131
1132	if (le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) <
1133	    BT_HIGH_TRAFFIC)
1134		return true;
1135
1136	/*
1137	 * In Tight / TxTxDis, BT can't Rx while we Tx, so use both antennas
1138	 * since BT is already killed.
1139	 * In Loose, BT can Rx while we Tx, so forbid MIMO to let BT Rx while
1140	 * we Tx.
1141	 * When we are in 5GHz, we'll get BT_COEX_INVALID_LUT allowing MIMO.
1142	 */
1143	lut_type = iwl_get_coex_type(mvm, mvmsta->vif);
1144	return lut_type != BT_COEX_LOOSE_LUT;
1145}
1146
1147bool iwl_mvm_bt_coex_is_shared_ant_avail(struct iwl_mvm *mvm)
1148{
1149	/* there is no other antenna, shared antenna is always available */
1150	if (mvm->cfg->bt_shared_single_ant)
1151		return true;
1152
1153	if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BT_COEX_SPLIT))
1154		return iwl_mvm_bt_coex_is_shared_ant_avail_old(mvm);
1155
1156	return le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) == BT_OFF;
1157}
1158
1159bool iwl_mvm_bt_coex_is_tpc_allowed(struct iwl_mvm *mvm,
1160				    enum ieee80211_band band)
1161{
1162	u32 bt_activity = le32_to_cpu(mvm->last_bt_notif.bt_activity_grading);
1163
1164	if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BT_COEX_SPLIT))
1165		return iwl_mvm_bt_coex_is_tpc_allowed_old(mvm, band);
1166
1167	if (band != IEEE80211_BAND_2GHZ)
1168		return false;
1169
1170	return bt_activity >= BT_LOW_TRAFFIC;
1171}
1172
1173u8 iwl_mvm_bt_coex_tx_prio(struct iwl_mvm *mvm, struct ieee80211_hdr *hdr,
1174			   struct ieee80211_tx_info *info, u8 ac)
1175{
1176	__le16 fc = hdr->frame_control;
1177
1178	if (info->band != IEEE80211_BAND_2GHZ)
1179		return 0;
1180
1181	if (unlikely(mvm->bt_tx_prio))
1182		return mvm->bt_tx_prio - 1;
1183
1184	/* High prio packet (wrt. BT coex) if it is EAPOL, MCAST or MGMT */
1185	if (info->control.flags & IEEE80211_TX_CTRL_PORT_CTRL_PROTO ||
1186	     is_multicast_ether_addr(hdr->addr1) ||
1187	     ieee80211_is_ctl(fc) || ieee80211_is_mgmt(fc) ||
1188	     ieee80211_is_nullfunc(fc) || ieee80211_is_qos_nullfunc(fc))
1189		return 3;
1190
1191	switch (ac) {
1192	case IEEE80211_AC_BE:
1193		return 1;
1194	case IEEE80211_AC_VO:
1195		return 3;
1196	case IEEE80211_AC_VI:
1197		return 2;
1198	default:
1199		break;
1200	}
1201
1202	return 0;
1203}
1204
1205void iwl_mvm_bt_coex_vif_change(struct iwl_mvm *mvm)
1206{
1207	if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BT_COEX_SPLIT)) {
1208		iwl_mvm_bt_coex_vif_change_old(mvm);
1209		return;
1210	}
1211
1212	iwl_mvm_bt_coex_notif_handle(mvm);
1213}
1214
1215int iwl_mvm_rx_ant_coupling_notif(struct iwl_mvm *mvm,
1216				  struct iwl_rx_cmd_buffer *rxb,
1217				  struct iwl_device_cmd *dev_cmd)
1218{
1219	struct iwl_rx_packet *pkt = rxb_addr(rxb);
1220	u32 ant_isolation = le32_to_cpup((void *)pkt->data);
1221	struct iwl_bt_coex_corun_lut_update_cmd cmd = {};
1222	u8 __maybe_unused lower_bound, upper_bound;
1223	u8 lut;
1224
1225	if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BT_COEX_SPLIT))
1226		return iwl_mvm_rx_ant_coupling_notif_old(mvm, rxb, dev_cmd);
1227
1228	if (!IWL_MVM_BT_COEX_CORUNNING)
1229		return 0;
1230
1231	lockdep_assert_held(&mvm->mutex);
1232
1233	/* Ignore updates if we are in force mode */
1234	if (unlikely(mvm->bt_force_ant_mode != BT_FORCE_ANT_DIS))
1235		return 0;
1236
1237	if (ant_isolation ==  mvm->last_ant_isol)
1238		return 0;
1239
1240	for (lut = 0; lut < ARRAY_SIZE(antenna_coupling_ranges) - 1; lut++)
1241		if (ant_isolation < antenna_coupling_ranges[lut + 1].range)
1242			break;
1243
1244	lower_bound = antenna_coupling_ranges[lut].range;
1245
1246	if (lut < ARRAY_SIZE(antenna_coupling_ranges) - 1)
1247		upper_bound = antenna_coupling_ranges[lut + 1].range;
1248	else
1249		upper_bound = antenna_coupling_ranges[lut].range;
1250
1251	IWL_DEBUG_COEX(mvm, "Antenna isolation=%d in range [%d,%d[, lut=%d\n",
1252		       ant_isolation, lower_bound, upper_bound, lut);
1253
1254	mvm->last_ant_isol = ant_isolation;
1255
1256	if (mvm->last_corun_lut == lut)
1257		return 0;
1258
1259	mvm->last_corun_lut = lut;
1260
1261	/* For the moment, use the same LUT for 20GHz and 40GHz */
1262	memcpy(&cmd.corun_lut20, antenna_coupling_ranges[lut].lut20,
1263	       sizeof(cmd.corun_lut20));
1264
1265	memcpy(&cmd.corun_lut40, antenna_coupling_ranges[lut].lut20,
1266	       sizeof(cmd.corun_lut40));
1267
1268	return iwl_mvm_send_cmd_pdu(mvm, BT_COEX_UPDATE_CORUN_LUT, 0,
1269				    sizeof(cmd), &cmd);
1270}
1271