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