[go: nahoru, domu]

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