diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-04-02 23:53:45 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-04-02 23:53:45 -0400 |
commit | cd6362befe4cc7bf589a5236d2a780af2d47bcc9 (patch) | |
tree | 3bd4e13ec3f92a00dc4f6c3d65e820b54dbfe46e /drivers/net/wireless/iwlwifi/mvm/coex.c | |
parent | 0f1b1e6d73cb989ce2c071edc57deade3b084dfe (diff) | |
parent | b1586f099ba897542ece36e8a23c1a62907261ef (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next
Pull networking updates from David Miller:
"Here is my initial pull request for the networking subsystem during
this merge window:
1) Support for ESN in AH (RFC 4302) from Fan Du.
2) Add full kernel doc for ethtool command structures, from Ben
Hutchings.
3) Add BCM7xxx PHY driver, from Florian Fainelli.
4) Export computed TCP rate information in netlink socket dumps, from
Eric Dumazet.
5) Allow IPSEC SA to be dumped partially using a filter, from Nicolas
Dichtel.
6) Convert many drivers to pci_enable_msix_range(), from Alexander
Gordeev.
7) Record SKB timestamps more efficiently, from Eric Dumazet.
8) Switch to microsecond resolution for TCP round trip times, also
from Eric Dumazet.
9) Clean up and fix 6lowpan fragmentation handling by making use of
the existing inet_frag api for it's implementation.
10) Add TX grant mapping to xen-netback driver, from Zoltan Kiss.
11) Auto size SKB lengths when composing netlink messages based upon
past message sizes used, from Eric Dumazet.
12) qdisc dumps can take a long time, add a cond_resched(), From Eric
Dumazet.
13) Sanitize netpoll core and drivers wrt. SKB handling semantics.
Get rid of never-used-in-tree netpoll RX handling. From Eric W
Biederman.
14) Support inter-address-family and namespace changing in VTI tunnel
driver(s). From Steffen Klassert.
15) Add Altera TSE driver, from Vince Bridgers.
16) Optimizing csum_replace2() so that it doesn't adjust the checksum
by checksumming the entire header, from Eric Dumazet.
17) Expand BPF internal implementation for faster interpreting, more
direct translations into JIT'd code, and much cleaner uses of BPF
filtering in non-socket ocntexts. From Daniel Borkmann and Alexei
Starovoitov"
* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next: (1976 commits)
netpoll: Use skb_irq_freeable to make zap_completion_queue safe.
net: Add a test to see if a skb is freeable in irq context
qlcnic: Fix build failure due to undefined reference to `vxlan_get_rx_port'
net: ptp: move PTP classifier in its own file
net: sxgbe: make "core_ops" static
net: sxgbe: fix logical vs bitwise operation
net: sxgbe: sxgbe_mdio_register() frees the bus
Call efx_set_channels() before efx->type->dimension_resources()
xen-netback: disable rogue vif in kthread context
net/mlx4: Set proper build dependancy with vxlan
be2net: fix build dependency on VxLAN
mac802154: make csma/cca parameters per-wpan
mac802154: allow only one WPAN to be up at any given time
net: filter: minor: fix kdoc in __sk_run_filter
netlink: don't compare the nul-termination in nla_strcmp
can: c_can: Avoid led toggling for every packet.
can: c_can: Simplify TX interrupt cleanup
can: c_can: Store dlc private
can: c_can: Reduce register access
can: c_can: Make the code readable
...
Diffstat (limited to 'drivers/net/wireless/iwlwifi/mvm/coex.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/coex.c | 1322 |
1 files changed, 1322 insertions, 0 deletions
diff --git a/drivers/net/wireless/iwlwifi/mvm/coex.c b/drivers/net/wireless/iwlwifi/mvm/coex.c new file mode 100644 index 000000000000..685f7e8e6943 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/mvm/coex.c | |||
@@ -0,0 +1,1322 @@ | |||
1 | /****************************************************************************** | ||
2 | * | ||
3 | * This file is provided under a dual BSD/GPLv2 license. When using or | ||
4 | * redistributing this file, you may do so under either license. | ||
5 | * | ||
6 | * GPL LICENSE SUMMARY | ||
7 | * | ||
8 | * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved. | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of version 2 of the GNU General Public License as | ||
12 | * published by the Free Software Foundation. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, but | ||
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
17 | * General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, | ||
22 | * USA | ||
23 | * | ||
24 | * The full GNU General Public License is included in this distribution | ||
25 | * in the file called COPYING. | ||
26 | * | ||
27 | * Contact Information: | ||
28 | * Intel Linux Wireless <ilw@linux.intel.com> | ||
29 | * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | ||
30 | * | ||
31 | * BSD LICENSE | ||
32 | * | ||
33 | * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved. | ||
34 | * All rights reserved. | ||
35 | * | ||
36 | * Redistribution and use in source and binary forms, with or without | ||
37 | * modification, are permitted provided that the following conditions | ||
38 | * are met: | ||
39 | * | ||
40 | * * Redistributions of source code must retain the above copyright | ||
41 | * notice, this list of conditions and the following disclaimer. | ||
42 | * * Redistributions in binary form must reproduce the above copyright | ||
43 | * notice, this list of conditions and the following disclaimer in | ||
44 | * the documentation and/or other materials provided with the | ||
45 | * distribution. | ||
46 | * * Neither the name Intel Corporation nor the names of its | ||
47 | * contributors may be used to endorse or promote products derived | ||
48 | * from this software without specific prior written permission. | ||
49 | * | ||
50 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
51 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
52 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
53 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
54 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
55 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
56 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
57 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
58 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
59 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
60 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
61 | * | ||
62 | *****************************************************************************/ | ||
63 | |||
64 | #include <linux/ieee80211.h> | ||
65 | #include <linux/etherdevice.h> | ||
66 | #include <net/mac80211.h> | ||
67 | |||
68 | #include "fw-api-coex.h" | ||
69 | #include "iwl-modparams.h" | ||
70 | #include "mvm.h" | ||
71 | #include "iwl-debug.h" | ||
72 | |||
73 | #define EVENT_PRIO_ANT(_evt, _prio, _shrd_ant) \ | ||
74 | [(_evt)] = (((_prio) << BT_COEX_PRIO_TBL_PRIO_POS) | \ | ||
75 | ((_shrd_ant) << BT_COEX_PRIO_TBL_SHRD_ANT_POS)) | ||
76 | |||
77 | static const u8 iwl_bt_prio_tbl[BT_COEX_PRIO_TBL_EVT_MAX] = { | ||
78 | EVENT_PRIO_ANT(BT_COEX_PRIO_TBL_EVT_INIT_CALIB1, | ||
79 | BT_COEX_PRIO_TBL_PRIO_BYPASS, 0), | ||
80 | EVENT_PRIO_ANT(BT_COEX_PRIO_TBL_EVT_INIT_CALIB2, | ||
81 | BT_COEX_PRIO_TBL_PRIO_BYPASS, 1), | ||
82 | EVENT_PRIO_ANT(BT_COEX_PRIO_TBL_EVT_PERIODIC_CALIB_LOW1, | ||
83 | BT_COEX_PRIO_TBL_PRIO_LOW, 0), | ||
84 | EVENT_PRIO_ANT(BT_COEX_PRIO_TBL_EVT_PERIODIC_CALIB_LOW2, | ||
85 | BT_COEX_PRIO_TBL_PRIO_LOW, 1), | ||
86 | EVENT_PRIO_ANT(BT_COEX_PRIO_TBL_EVT_PERIODIC_CALIB_HIGH1, | ||
87 | BT_COEX_PRIO_TBL_PRIO_HIGH, 0), | ||
88 | EVENT_PRIO_ANT(BT_COEX_PRIO_TBL_EVT_PERIODIC_CALIB_HIGH2, | ||
89 | BT_COEX_PRIO_TBL_PRIO_HIGH, 1), | ||
90 | EVENT_PRIO_ANT(BT_COEX_PRIO_TBL_EVT_DTIM, | ||
91 | BT_COEX_PRIO_TBL_DISABLED, 0), | ||
92 | EVENT_PRIO_ANT(BT_COEX_PRIO_TBL_EVT_SCAN52, | ||
93 | BT_COEX_PRIO_TBL_PRIO_COEX_OFF, 0), | ||
94 | EVENT_PRIO_ANT(BT_COEX_PRIO_TBL_EVT_SCAN24, | ||
95 | BT_COEX_PRIO_TBL_PRIO_COEX_ON, 0), | ||
96 | EVENT_PRIO_ANT(BT_COEX_PRIO_TBL_EVT_IDLE, | ||
97 | BT_COEX_PRIO_TBL_PRIO_COEX_IDLE, 0), | ||
98 | 0, 0, 0, 0, 0, 0, | ||
99 | }; | ||
100 | |||
101 | #undef EVENT_PRIO_ANT | ||
102 | |||
103 | #define BT_ENABLE_REDUCED_TXPOWER_THRESHOLD (-62) | ||
104 | #define BT_DISABLE_REDUCED_TXPOWER_THRESHOLD (-65) | ||
105 | #define BT_ANTENNA_COUPLING_THRESHOLD (30) | ||
106 | |||
107 | int iwl_send_bt_prio_tbl(struct iwl_mvm *mvm) | ||
108 | { | ||
109 | if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_NEWBT_COEX)) | ||
110 | return 0; | ||
111 | |||
112 | return iwl_mvm_send_cmd_pdu(mvm, BT_COEX_PRIO_TABLE, CMD_SYNC, | ||
113 | sizeof(struct iwl_bt_coex_prio_tbl_cmd), | ||
114 | &iwl_bt_prio_tbl); | ||
115 | } | ||
116 | |||
117 | const u32 iwl_bt_ack_kill_msk[BT_KILL_MSK_MAX] = { | ||
118 | [BT_KILL_MSK_DEFAULT] = 0xffff0000, | ||
119 | [BT_KILL_MSK_SCO_HID_A2DP] = 0xffffffff, | ||
120 | [BT_KILL_MSK_REDUCED_TXPOW] = 0, | ||
121 | }; | ||
122 | |||
123 | const u32 iwl_bt_cts_kill_msk[BT_KILL_MSK_MAX] = { | ||
124 | [BT_KILL_MSK_DEFAULT] = 0xffff0000, | ||
125 | [BT_KILL_MSK_SCO_HID_A2DP] = 0xffffffff, | ||
126 | [BT_KILL_MSK_REDUCED_TXPOW] = 0, | ||
127 | }; | ||
128 | |||
129 | static const __le32 iwl_bt_prio_boost[BT_COEX_BOOST_SIZE] = { | ||
130 | cpu_to_le32(0xf0f0f0f0), | ||
131 | cpu_to_le32(0xc0c0c0c0), | ||
132 | cpu_to_le32(0xfcfcfcfc), | ||
133 | cpu_to_le32(0xff00ff00), | ||
134 | }; | ||
135 | |||
136 | static 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 | |||
181 | static 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(0x00000000), | ||
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(0xaaaaaaaa), | ||
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*/ | ||
230 | static 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 | |||
305 | static const __le32 iwl_bt_mprio_lut[BT_COEX_MULTI_PRIO_LUT_SIZE] = { | ||
306 | cpu_to_le32(0x22002200), | ||
307 | cpu_to_le32(0x33113311), | ||
308 | }; | ||
309 | |||
310 | struct 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 | */ | ||
327 | static 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 | |||
519 | static enum iwl_bt_coex_lut_type | ||
520 | iwl_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 | |||
526 | /* | ||
527 | * Checking that we hold mvm->mutex is a good idea, but the rate | ||
528 | * control can't acquire the mutex since it runs in Tx path. | ||
529 | * So this is racy in that case, but in the worst case, the AMPDU | ||
530 | * size limit will be wrong for a short time which is not a big | ||
531 | * issue. | ||
532 | */ | ||
533 | |||
534 | rcu_read_lock(); | ||
535 | |||
536 | chanctx_conf = rcu_dereference(vif->chanctx_conf); | ||
537 | |||
538 | if (!chanctx_conf || | ||
539 | chanctx_conf->def.chan->band != IEEE80211_BAND_2GHZ) { | ||
540 | rcu_read_unlock(); | ||
541 | return BT_COEX_LOOSE_LUT; | ||
542 | } | ||
543 | |||
544 | ret = BT_COEX_TX_DIS_LUT; | ||
545 | |||
546 | if (mvm->cfg->bt_shared_single_ant) { | ||
547 | rcu_read_unlock(); | ||
548 | return ret; | ||
549 | } | ||
550 | |||
551 | phy_ctx_id = *((u16 *)chanctx_conf->drv_priv); | ||
552 | |||
553 | if (mvm->last_bt_ci_cmd.primary_ch_phy_id == phy_ctx_id) | ||
554 | ret = le32_to_cpu(mvm->last_bt_notif.primary_ch_lut); | ||
555 | else if (mvm->last_bt_ci_cmd.secondary_ch_phy_id == phy_ctx_id) | ||
556 | ret = le32_to_cpu(mvm->last_bt_notif.secondary_ch_lut); | ||
557 | /* else - default = TX TX disallowed */ | ||
558 | |||
559 | rcu_read_unlock(); | ||
560 | |||
561 | return ret; | ||
562 | } | ||
563 | |||
564 | int iwl_send_bt_init_conf(struct iwl_mvm *mvm) | ||
565 | { | ||
566 | struct iwl_bt_coex_cmd *bt_cmd; | ||
567 | struct iwl_host_cmd cmd = { | ||
568 | .id = BT_CONFIG, | ||
569 | .len = { sizeof(*bt_cmd), }, | ||
570 | .dataflags = { IWL_HCMD_DFL_NOCOPY, }, | ||
571 | .flags = CMD_SYNC, | ||
572 | }; | ||
573 | int ret; | ||
574 | u32 flags; | ||
575 | |||
576 | if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_NEWBT_COEX)) | ||
577 | return 0; | ||
578 | |||
579 | bt_cmd = kzalloc(sizeof(*bt_cmd), GFP_KERNEL); | ||
580 | if (!bt_cmd) | ||
581 | return -ENOMEM; | ||
582 | cmd.data[0] = bt_cmd; | ||
583 | |||
584 | bt_cmd->max_kill = 5; | ||
585 | bt_cmd->bt4_antenna_isolation_thr = BT_ANTENNA_COUPLING_THRESHOLD, | ||
586 | bt_cmd->bt4_antenna_isolation = iwlwifi_mod_params.ant_coupling, | ||
587 | bt_cmd->bt4_tx_tx_delta_freq_thr = 15, | ||
588 | bt_cmd->bt4_tx_rx_max_freq0 = 15, | ||
589 | |||
590 | flags = iwlwifi_mod_params.bt_coex_active ? | ||
591 | BT_COEX_NW : BT_COEX_DISABLE; | ||
592 | bt_cmd->flags = cpu_to_le32(flags); | ||
593 | |||
594 | bt_cmd->valid_bit_msk = cpu_to_le32(BT_VALID_ENABLE | | ||
595 | BT_VALID_BT_PRIO_BOOST | | ||
596 | BT_VALID_MAX_KILL | | ||
597 | BT_VALID_3W_TMRS | | ||
598 | BT_VALID_KILL_ACK | | ||
599 | BT_VALID_KILL_CTS | | ||
600 | BT_VALID_REDUCED_TX_POWER | | ||
601 | BT_VALID_LUT | | ||
602 | BT_VALID_WIFI_RX_SW_PRIO_BOOST | | ||
603 | BT_VALID_WIFI_TX_SW_PRIO_BOOST | | ||
604 | BT_VALID_ANT_ISOLATION | | ||
605 | BT_VALID_ANT_ISOLATION_THRS | | ||
606 | BT_VALID_TXTX_DELTA_FREQ_THRS | | ||
607 | BT_VALID_TXRX_MAX_FREQ_0 | | ||
608 | BT_VALID_SYNC_TO_SCO); | ||
609 | |||
610 | if (IWL_MVM_BT_COEX_SYNC2SCO) | ||
611 | bt_cmd->flags |= cpu_to_le32(BT_COEX_SYNC2SCO); | ||
612 | |||
613 | if (IWL_MVM_BT_COEX_CORUNNING) { | ||
614 | bt_cmd->valid_bit_msk = cpu_to_le32(BT_VALID_CORUN_LUT_20 | | ||
615 | BT_VALID_CORUN_LUT_40); | ||
616 | bt_cmd->flags |= cpu_to_le32(BT_COEX_CORUNNING); | ||
617 | } | ||
618 | |||
619 | if (IWL_MVM_BT_COEX_MPLUT) { | ||
620 | bt_cmd->flags |= cpu_to_le32(BT_COEX_MPLUT); | ||
621 | bt_cmd->valid_bit_msk = cpu_to_le32(BT_VALID_MULTI_PRIO_LUT); | ||
622 | } | ||
623 | |||
624 | if (mvm->cfg->bt_shared_single_ant) | ||
625 | memcpy(&bt_cmd->decision_lut, iwl_single_shared_ant, | ||
626 | sizeof(iwl_single_shared_ant)); | ||
627 | else | ||
628 | memcpy(&bt_cmd->decision_lut, iwl_combined_lookup, | ||
629 | sizeof(iwl_combined_lookup)); | ||
630 | |||
631 | /* Take first Co-running block LUT to get started */ | ||
632 | memcpy(bt_cmd->bt4_corun_lut20, antenna_coupling_ranges[0].lut20, | ||
633 | sizeof(bt_cmd->bt4_corun_lut20)); | ||
634 | memcpy(bt_cmd->bt4_corun_lut40, antenna_coupling_ranges[0].lut20, | ||
635 | sizeof(bt_cmd->bt4_corun_lut40)); | ||
636 | |||
637 | memcpy(&bt_cmd->bt_prio_boost, iwl_bt_prio_boost, | ||
638 | sizeof(iwl_bt_prio_boost)); | ||
639 | memcpy(&bt_cmd->bt4_multiprio_lut, iwl_bt_mprio_lut, | ||
640 | sizeof(iwl_bt_mprio_lut)); | ||
641 | bt_cmd->kill_ack_msk = | ||
642 | cpu_to_le32(iwl_bt_ack_kill_msk[BT_KILL_MSK_DEFAULT]); | ||
643 | bt_cmd->kill_cts_msk = | ||
644 | cpu_to_le32(iwl_bt_cts_kill_msk[BT_KILL_MSK_DEFAULT]); | ||
645 | |||
646 | memset(&mvm->last_bt_notif, 0, sizeof(mvm->last_bt_notif)); | ||
647 | memset(&mvm->last_bt_ci_cmd, 0, sizeof(mvm->last_bt_ci_cmd)); | ||
648 | |||
649 | ret = iwl_mvm_send_cmd(mvm, &cmd); | ||
650 | |||
651 | kfree(bt_cmd); | ||
652 | return ret; | ||
653 | } | ||
654 | |||
655 | static int iwl_mvm_bt_udpate_ctrl_kill_msk(struct iwl_mvm *mvm, | ||
656 | bool reduced_tx_power) | ||
657 | { | ||
658 | enum iwl_bt_kill_msk bt_kill_msk; | ||
659 | struct iwl_bt_coex_cmd *bt_cmd; | ||
660 | struct iwl_bt_coex_profile_notif *notif = &mvm->last_bt_notif; | ||
661 | struct iwl_host_cmd cmd = { | ||
662 | .id = BT_CONFIG, | ||
663 | .data[0] = &bt_cmd, | ||
664 | .len = { sizeof(*bt_cmd), }, | ||
665 | .dataflags = { IWL_HCMD_DFL_NOCOPY, }, | ||
666 | .flags = CMD_SYNC, | ||
667 | }; | ||
668 | int ret = 0; | ||
669 | |||
670 | lockdep_assert_held(&mvm->mutex); | ||
671 | |||
672 | if (reduced_tx_power) { | ||
673 | /* Reduced Tx power has precedence on the type of the profile */ | ||
674 | bt_kill_msk = BT_KILL_MSK_REDUCED_TXPOW; | ||
675 | } else { | ||
676 | /* Low latency BT profile is active: give higher prio to BT */ | ||
677 | if (BT_MBOX_MSG(notif, 3, SCO_STATE) || | ||
678 | BT_MBOX_MSG(notif, 3, A2DP_STATE) || | ||
679 | BT_MBOX_MSG(notif, 3, SNIFF_STATE)) | ||
680 | bt_kill_msk = BT_KILL_MSK_SCO_HID_A2DP; | ||
681 | else | ||
682 | bt_kill_msk = BT_KILL_MSK_DEFAULT; | ||
683 | } | ||
684 | |||
685 | IWL_DEBUG_COEX(mvm, | ||
686 | "Update kill_msk: %d - SCO %sactive A2DP %sactive SNIFF %sactive\n", | ||
687 | bt_kill_msk, | ||
688 | BT_MBOX_MSG(notif, 3, SCO_STATE) ? "" : "in", | ||
689 | BT_MBOX_MSG(notif, 3, A2DP_STATE) ? "" : "in", | ||
690 | BT_MBOX_MSG(notif, 3, SNIFF_STATE) ? "" : "in"); | ||
691 | |||
692 | /* Don't send HCMD if there is no update */ | ||
693 | if (bt_kill_msk == mvm->bt_kill_msk) | ||
694 | return 0; | ||
695 | |||
696 | mvm->bt_kill_msk = bt_kill_msk; | ||
697 | |||
698 | bt_cmd = kzalloc(sizeof(*bt_cmd), GFP_KERNEL); | ||
699 | if (!bt_cmd) | ||
700 | return -ENOMEM; | ||
701 | cmd.data[0] = bt_cmd; | ||
702 | bt_cmd->flags = cpu_to_le32(BT_COEX_NW); | ||
703 | |||
704 | bt_cmd->kill_ack_msk = cpu_to_le32(iwl_bt_ack_kill_msk[bt_kill_msk]); | ||
705 | bt_cmd->kill_cts_msk = cpu_to_le32(iwl_bt_cts_kill_msk[bt_kill_msk]); | ||
706 | bt_cmd->valid_bit_msk |= cpu_to_le32(BT_VALID_ENABLE | | ||
707 | BT_VALID_KILL_ACK | | ||
708 | BT_VALID_KILL_CTS); | ||
709 | |||
710 | IWL_DEBUG_COEX(mvm, "ACK Kill msk = 0x%08x, CTS Kill msk = 0x%08x\n", | ||
711 | iwl_bt_ack_kill_msk[bt_kill_msk], | ||
712 | iwl_bt_cts_kill_msk[bt_kill_msk]); | ||
713 | |||
714 | ret = iwl_mvm_send_cmd(mvm, &cmd); | ||
715 | |||
716 | kfree(bt_cmd); | ||
717 | return ret; | ||
718 | } | ||
719 | |||
720 | int iwl_mvm_bt_coex_reduced_txp(struct iwl_mvm *mvm, u8 sta_id, bool enable) | ||
721 | { | ||
722 | struct iwl_bt_coex_cmd *bt_cmd; | ||
723 | /* Send ASYNC since this can be sent from an atomic context */ | ||
724 | struct iwl_host_cmd cmd = { | ||
725 | .id = BT_CONFIG, | ||
726 | .len = { sizeof(*bt_cmd), }, | ||
727 | .dataflags = { IWL_HCMD_DFL_NOCOPY, }, | ||
728 | .flags = CMD_ASYNC, | ||
729 | }; | ||
730 | struct iwl_mvm_sta *mvmsta; | ||
731 | int ret; | ||
732 | |||
733 | mvmsta = iwl_mvm_sta_from_staid_protected(mvm, sta_id); | ||
734 | if (!mvmsta) | ||
735 | return 0; | ||
736 | |||
737 | /* nothing to do */ | ||
738 | if (mvmsta->bt_reduced_txpower_dbg || | ||
739 | mvmsta->bt_reduced_txpower == enable) | ||
740 | return 0; | ||
741 | |||
742 | bt_cmd = kzalloc(sizeof(*bt_cmd), GFP_ATOMIC); | ||
743 | if (!bt_cmd) | ||
744 | return -ENOMEM; | ||
745 | cmd.data[0] = bt_cmd; | ||
746 | bt_cmd->flags = cpu_to_le32(BT_COEX_NW); | ||
747 | |||
748 | bt_cmd->valid_bit_msk = | ||
749 | cpu_to_le32(BT_VALID_ENABLE | BT_VALID_REDUCED_TX_POWER); | ||
750 | bt_cmd->bt_reduced_tx_power = sta_id; | ||
751 | |||
752 | if (enable) | ||
753 | bt_cmd->bt_reduced_tx_power |= BT_REDUCED_TX_POWER_BIT; | ||
754 | |||
755 | IWL_DEBUG_COEX(mvm, "%sable reduced Tx Power for sta %d\n", | ||
756 | enable ? "en" : "dis", sta_id); | ||
757 | |||
758 | mvmsta->bt_reduced_txpower = enable; | ||
759 | |||
760 | ret = iwl_mvm_send_cmd(mvm, &cmd); | ||
761 | |||
762 | kfree(bt_cmd); | ||
763 | return ret; | ||
764 | } | ||
765 | |||
766 | struct iwl_bt_iterator_data { | ||
767 | struct iwl_bt_coex_profile_notif *notif; | ||
768 | struct iwl_mvm *mvm; | ||
769 | u32 num_bss_ifaces; | ||
770 | bool reduced_tx_power; | ||
771 | struct ieee80211_chanctx_conf *primary; | ||
772 | struct ieee80211_chanctx_conf *secondary; | ||
773 | bool primary_ll; | ||
774 | }; | ||
775 | |||
776 | static inline | ||
777 | void iwl_mvm_bt_coex_enable_rssi_event(struct iwl_mvm *mvm, | ||
778 | struct ieee80211_vif *vif, | ||
779 | bool enable, int rssi) | ||
780 | { | ||
781 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
782 | |||
783 | mvmvif->bf_data.last_bt_coex_event = rssi; | ||
784 | mvmvif->bf_data.bt_coex_max_thold = | ||
785 | enable ? BT_ENABLE_REDUCED_TXPOWER_THRESHOLD : 0; | ||
786 | mvmvif->bf_data.bt_coex_min_thold = | ||
787 | enable ? BT_DISABLE_REDUCED_TXPOWER_THRESHOLD : 0; | ||
788 | } | ||
789 | |||
790 | /* must be called under rcu_read_lock */ | ||
791 | static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac, | ||
792 | struct ieee80211_vif *vif) | ||
793 | { | ||
794 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
795 | struct iwl_bt_iterator_data *data = _data; | ||
796 | struct iwl_mvm *mvm = data->mvm; | ||
797 | struct ieee80211_chanctx_conf *chanctx_conf; | ||
798 | enum ieee80211_smps_mode smps_mode; | ||
799 | u32 bt_activity_grading; | ||
800 | int ave_rssi; | ||
801 | |||
802 | lockdep_assert_held(&mvm->mutex); | ||
803 | |||
804 | switch (vif->type) { | ||
805 | case NL80211_IFTYPE_STATION: | ||
806 | /* default smps_mode for BSS / P2P client is AUTOMATIC */ | ||
807 | smps_mode = IEEE80211_SMPS_AUTOMATIC; | ||
808 | data->num_bss_ifaces++; | ||
809 | |||
810 | /* | ||
811 | * Count unassoc BSSes, relax SMSP constraints | ||
812 | * and disable reduced Tx Power | ||
813 | */ | ||
814 | if (!vif->bss_conf.assoc) { | ||
815 | iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX, | ||
816 | smps_mode); | ||
817 | if (iwl_mvm_bt_coex_reduced_txp(mvm, | ||
818 | mvmvif->ap_sta_id, | ||
819 | false)) | ||
820 | IWL_ERR(mvm, "Couldn't send BT_CONFIG cmd\n"); | ||
821 | return; | ||
822 | } | ||
823 | break; | ||
824 | case NL80211_IFTYPE_AP: | ||
825 | /* default smps_mode for AP / GO is OFF */ | ||
826 | smps_mode = IEEE80211_SMPS_OFF; | ||
827 | if (!mvmvif->ap_ibss_active) { | ||
828 | iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX, | ||
829 | smps_mode); | ||
830 | return; | ||
831 | } | ||
832 | |||
833 | /* the Ack / Cts kill mask must be default if AP / GO */ | ||
834 | data->reduced_tx_power = false; | ||
835 | break; | ||
836 | default: | ||
837 | return; | ||
838 | } | ||
839 | |||
840 | chanctx_conf = rcu_dereference(vif->chanctx_conf); | ||
841 | |||
842 | /* If channel context is invalid or not on 2.4GHz .. */ | ||
843 | if ((!chanctx_conf || | ||
844 | chanctx_conf->def.chan->band != IEEE80211_BAND_2GHZ)) { | ||
845 | /* ... relax constraints and disable rssi events */ | ||
846 | iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX, | ||
847 | smps_mode); | ||
848 | if (vif->type == NL80211_IFTYPE_STATION) | ||
849 | iwl_mvm_bt_coex_enable_rssi_event(mvm, vif, false, 0); | ||
850 | return; | ||
851 | } | ||
852 | |||
853 | bt_activity_grading = le32_to_cpu(data->notif->bt_activity_grading); | ||
854 | if (bt_activity_grading >= BT_HIGH_TRAFFIC) | ||
855 | smps_mode = IEEE80211_SMPS_STATIC; | ||
856 | else if (bt_activity_grading >= BT_LOW_TRAFFIC) | ||
857 | smps_mode = vif->type == NL80211_IFTYPE_AP ? | ||
858 | IEEE80211_SMPS_OFF : | ||
859 | IEEE80211_SMPS_DYNAMIC; | ||
860 | IWL_DEBUG_COEX(data->mvm, | ||
861 | "mac %d: bt_status %d bt_activity_grading %d smps_req %d\n", | ||
862 | mvmvif->id, data->notif->bt_status, bt_activity_grading, | ||
863 | smps_mode); | ||
864 | |||
865 | iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX, smps_mode); | ||
866 | |||
867 | /* low latency is always primary */ | ||
868 | if (iwl_mvm_vif_low_latency(mvmvif)) { | ||
869 | data->primary_ll = true; | ||
870 | |||
871 | data->secondary = data->primary; | ||
872 | data->primary = chanctx_conf; | ||
873 | } | ||
874 | |||
875 | if (vif->type == NL80211_IFTYPE_AP) { | ||
876 | if (!mvmvif->ap_ibss_active) | ||
877 | return; | ||
878 | |||
879 | if (chanctx_conf == data->primary) | ||
880 | return; | ||
881 | |||
882 | if (!data->primary_ll) { | ||
883 | /* | ||
884 | * downgrade the current primary no matter what its | ||
885 | * type is. | ||
886 | */ | ||
887 | data->secondary = data->primary; | ||
888 | data->primary = chanctx_conf; | ||
889 | } else { | ||
890 | /* there is low latency vif - we will be secondary */ | ||
891 | data->secondary = chanctx_conf; | ||
892 | } | ||
893 | return; | ||
894 | } | ||
895 | |||
896 | /* | ||
897 | * STA / P2P Client, try to be primary if first vif. If we are in low | ||
898 | * latency mode, we are already in primary and just don't do much | ||
899 | */ | ||
900 | if (!data->primary || data->primary == chanctx_conf) | ||
901 | data->primary = chanctx_conf; | ||
902 | else if (!data->secondary) | ||
903 | /* if secondary is not NULL, it might be a GO */ | ||
904 | data->secondary = chanctx_conf; | ||
905 | |||
906 | /* don't reduce the Tx power if in loose scheme */ | ||
907 | if (iwl_get_coex_type(mvm, vif) == BT_COEX_LOOSE_LUT || | ||
908 | mvm->cfg->bt_shared_single_ant) { | ||
909 | data->reduced_tx_power = false; | ||
910 | iwl_mvm_bt_coex_enable_rssi_event(mvm, vif, false, 0); | ||
911 | return; | ||
912 | } | ||
913 | |||
914 | /* reduced Txpower only if BT is on, so ...*/ | ||
915 | if (!data->notif->bt_status) { | ||
916 | /* ... cancel reduced Tx power ... */ | ||
917 | if (iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, false)) | ||
918 | IWL_ERR(mvm, "Couldn't send BT_CONFIG cmd\n"); | ||
919 | data->reduced_tx_power = false; | ||
920 | |||
921 | /* ... and there is no need to get reports on RSSI any more. */ | ||
922 | iwl_mvm_bt_coex_enable_rssi_event(mvm, vif, false, 0); | ||
923 | return; | ||
924 | } | ||
925 | |||
926 | /* try to get the avg rssi from fw */ | ||
927 | ave_rssi = mvmvif->bf_data.ave_beacon_signal; | ||
928 | |||
929 | /* if the RSSI isn't valid, fake it is very low */ | ||
930 | if (!ave_rssi) | ||
931 | ave_rssi = -100; | ||
932 | if (ave_rssi > BT_ENABLE_REDUCED_TXPOWER_THRESHOLD) { | ||
933 | if (iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, true)) | ||
934 | IWL_ERR(mvm, "Couldn't send BT_CONFIG cmd\n"); | ||
935 | |||
936 | /* | ||
937 | * bt_kill_msk can be BT_KILL_MSK_REDUCED_TXPOW only if all the | ||
938 | * BSS / P2P clients have rssi above threshold. | ||
939 | * We set the bt_kill_msk to BT_KILL_MSK_REDUCED_TXPOW before | ||
940 | * the iteration, if one interface's rssi isn't good enough, | ||
941 | * bt_kill_msk will be set to default values. | ||
942 | */ | ||
943 | } else if (ave_rssi < BT_DISABLE_REDUCED_TXPOWER_THRESHOLD) { | ||
944 | if (iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, false)) | ||
945 | IWL_ERR(mvm, "Couldn't send BT_CONFIG cmd\n"); | ||
946 | |||
947 | /* | ||
948 | * One interface hasn't rssi above threshold, bt_kill_msk must | ||
949 | * be set to default values. | ||
950 | */ | ||
951 | data->reduced_tx_power = false; | ||
952 | } | ||
953 | |||
954 | /* Begin to monitor the RSSI: it may influence the reduced Tx power */ | ||
955 | iwl_mvm_bt_coex_enable_rssi_event(mvm, vif, true, ave_rssi); | ||
956 | } | ||
957 | |||
958 | static void iwl_mvm_bt_coex_notif_handle(struct iwl_mvm *mvm) | ||
959 | { | ||
960 | struct iwl_bt_iterator_data data = { | ||
961 | .mvm = mvm, | ||
962 | .notif = &mvm->last_bt_notif, | ||
963 | .reduced_tx_power = true, | ||
964 | }; | ||
965 | struct iwl_bt_coex_ci_cmd cmd = {}; | ||
966 | u8 ci_bw_idx; | ||
967 | |||
968 | rcu_read_lock(); | ||
969 | ieee80211_iterate_active_interfaces_atomic( | ||
970 | mvm->hw, IEEE80211_IFACE_ITER_NORMAL, | ||
971 | iwl_mvm_bt_notif_iterator, &data); | ||
972 | |||
973 | if (data.primary) { | ||
974 | struct ieee80211_chanctx_conf *chan = data.primary; | ||
975 | if (WARN_ON(!chan->def.chan)) { | ||
976 | rcu_read_unlock(); | ||
977 | return; | ||
978 | } | ||
979 | |||
980 | if (chan->def.width < NL80211_CHAN_WIDTH_40) { | ||
981 | ci_bw_idx = 0; | ||
982 | cmd.co_run_bw_primary = 0; | ||
983 | } else { | ||
984 | cmd.co_run_bw_primary = 1; | ||
985 | if (chan->def.center_freq1 > | ||
986 | chan->def.chan->center_freq) | ||
987 | ci_bw_idx = 2; | ||
988 | else | ||
989 | ci_bw_idx = 1; | ||
990 | } | ||
991 | |||
992 | cmd.bt_primary_ci = | ||
993 | iwl_ci_mask[chan->def.chan->hw_value][ci_bw_idx]; | ||
994 | cmd.primary_ch_phy_id = *((u16 *)data.primary->drv_priv); | ||
995 | } | ||
996 | |||
997 | if (data.secondary) { | ||
998 | struct ieee80211_chanctx_conf *chan = data.secondary; | ||
999 | if (WARN_ON(!data.secondary->def.chan)) { | ||
1000 | rcu_read_unlock(); | ||
1001 | return; | ||
1002 | } | ||
1003 | |||
1004 | if (chan->def.width < NL80211_CHAN_WIDTH_40) { | ||
1005 | ci_bw_idx = 0; | ||
1006 | cmd.co_run_bw_secondary = 0; | ||
1007 | } else { | ||
1008 | cmd.co_run_bw_secondary = 1; | ||
1009 | if (chan->def.center_freq1 > | ||
1010 | chan->def.chan->center_freq) | ||
1011 | ci_bw_idx = 2; | ||
1012 | else | ||
1013 | ci_bw_idx = 1; | ||
1014 | } | ||
1015 | |||
1016 | cmd.bt_secondary_ci = | ||
1017 | iwl_ci_mask[chan->def.chan->hw_value][ci_bw_idx]; | ||
1018 | cmd.secondary_ch_phy_id = *((u16 *)data.secondary->drv_priv); | ||
1019 | } | ||
1020 | |||
1021 | rcu_read_unlock(); | ||
1022 | |||
1023 | /* Don't spam the fw with the same command over and over */ | ||
1024 | if (memcmp(&cmd, &mvm->last_bt_ci_cmd, sizeof(cmd))) { | ||
1025 | if (iwl_mvm_send_cmd_pdu(mvm, BT_COEX_CI, CMD_SYNC, | ||
1026 | sizeof(cmd), &cmd)) | ||
1027 | IWL_ERR(mvm, "Failed to send BT_CI cmd"); | ||
1028 | memcpy(&mvm->last_bt_ci_cmd, &cmd, sizeof(cmd)); | ||
1029 | } | ||
1030 | |||
1031 | /* | ||
1032 | * If there are no BSS / P2P client interfaces, reduced Tx Power is | ||
1033 | * irrelevant since it is based on the RSSI coming from the beacon. | ||
1034 | * Use BT_KILL_MSK_DEFAULT in that case. | ||
1035 | */ | ||
1036 | data.reduced_tx_power = data.reduced_tx_power && data.num_bss_ifaces; | ||
1037 | |||
1038 | if (iwl_mvm_bt_udpate_ctrl_kill_msk(mvm, data.reduced_tx_power)) | ||
1039 | IWL_ERR(mvm, "Failed to update the ctrl_kill_msk\n"); | ||
1040 | } | ||
1041 | |||
1042 | /* upon association, the fw will send in BT Coex notification */ | ||
1043 | int iwl_mvm_rx_bt_coex_notif(struct iwl_mvm *mvm, | ||
1044 | struct iwl_rx_cmd_buffer *rxb, | ||
1045 | struct iwl_device_cmd *dev_cmd) | ||
1046 | { | ||
1047 | struct iwl_rx_packet *pkt = rxb_addr(rxb); | ||
1048 | struct iwl_bt_coex_profile_notif *notif = (void *)pkt->data; | ||
1049 | |||
1050 | |||
1051 | IWL_DEBUG_COEX(mvm, "BT Coex Notification received\n"); | ||
1052 | IWL_DEBUG_COEX(mvm, "\tBT status: %s\n", | ||
1053 | notif->bt_status ? "ON" : "OFF"); | ||
1054 | IWL_DEBUG_COEX(mvm, "\tBT open conn %d\n", notif->bt_open_conn); | ||
1055 | IWL_DEBUG_COEX(mvm, "\tBT ci compliance %d\n", notif->bt_ci_compliance); | ||
1056 | IWL_DEBUG_COEX(mvm, "\tBT primary_ch_lut %d\n", | ||
1057 | le32_to_cpu(notif->primary_ch_lut)); | ||
1058 | IWL_DEBUG_COEX(mvm, "\tBT secondary_ch_lut %d\n", | ||
1059 | le32_to_cpu(notif->secondary_ch_lut)); | ||
1060 | IWL_DEBUG_COEX(mvm, "\tBT activity grading %d\n", | ||
1061 | le32_to_cpu(notif->bt_activity_grading)); | ||
1062 | IWL_DEBUG_COEX(mvm, "\tBT agg traffic load %d\n", | ||
1063 | notif->bt_agg_traffic_load); | ||
1064 | |||
1065 | /* remember this notification for future use: rssi fluctuations */ | ||
1066 | memcpy(&mvm->last_bt_notif, notif, sizeof(mvm->last_bt_notif)); | ||
1067 | |||
1068 | iwl_mvm_bt_coex_notif_handle(mvm); | ||
1069 | |||
1070 | /* | ||
1071 | * This is an async handler for a notification, returning anything other | ||
1072 | * than 0 doesn't make sense even if HCMD failed. | ||
1073 | */ | ||
1074 | return 0; | ||
1075 | } | ||
1076 | |||
1077 | static void iwl_mvm_bt_rssi_iterator(void *_data, u8 *mac, | ||
1078 | struct ieee80211_vif *vif) | ||
1079 | { | ||
1080 | struct iwl_mvm_vif *mvmvif = (void *)vif->drv_priv; | ||
1081 | struct iwl_bt_iterator_data *data = _data; | ||
1082 | struct iwl_mvm *mvm = data->mvm; | ||
1083 | |||
1084 | struct ieee80211_sta *sta; | ||
1085 | struct iwl_mvm_sta *mvmsta; | ||
1086 | |||
1087 | struct ieee80211_chanctx_conf *chanctx_conf; | ||
1088 | |||
1089 | rcu_read_lock(); | ||
1090 | chanctx_conf = rcu_dereference(vif->chanctx_conf); | ||
1091 | /* If channel context is invalid or not on 2.4GHz - don't count it */ | ||
1092 | if (!chanctx_conf || | ||
1093 | chanctx_conf->def.chan->band != IEEE80211_BAND_2GHZ) { | ||
1094 | rcu_read_unlock(); | ||
1095 | return; | ||
1096 | } | ||
1097 | rcu_read_unlock(); | ||
1098 | |||
1099 | if (vif->type != NL80211_IFTYPE_STATION || | ||
1100 | mvmvif->ap_sta_id == IWL_MVM_STATION_COUNT) | ||
1101 | return; | ||
1102 | |||
1103 | sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[mvmvif->ap_sta_id], | ||
1104 | lockdep_is_held(&mvm->mutex)); | ||
1105 | |||
1106 | /* This can happen if the station has been removed right now */ | ||
1107 | if (IS_ERR_OR_NULL(sta)) | ||
1108 | return; | ||
1109 | |||
1110 | mvmsta = iwl_mvm_sta_from_mac80211(sta); | ||
1111 | |||
1112 | data->num_bss_ifaces++; | ||
1113 | |||
1114 | /* | ||
1115 | * This interface doesn't support reduced Tx power (because of low | ||
1116 | * RSSI probably), then set bt_kill_msk to default values. | ||
1117 | */ | ||
1118 | if (!mvmsta->bt_reduced_txpower) | ||
1119 | data->reduced_tx_power = false; | ||
1120 | /* else - possibly leave it to BT_KILL_MSK_REDUCED_TXPOW */ | ||
1121 | } | ||
1122 | |||
1123 | void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | ||
1124 | enum ieee80211_rssi_event rssi_event) | ||
1125 | { | ||
1126 | struct iwl_mvm_vif *mvmvif = (void *)vif->drv_priv; | ||
1127 | struct iwl_bt_iterator_data data = { | ||
1128 | .mvm = mvm, | ||
1129 | .reduced_tx_power = true, | ||
1130 | }; | ||
1131 | int ret; | ||
1132 | |||
1133 | lockdep_assert_held(&mvm->mutex); | ||
1134 | |||
1135 | /* | ||
1136 | * Rssi update while not associated - can happen since the statistics | ||
1137 | * are handled asynchronously | ||
1138 | */ | ||
1139 | if (mvmvif->ap_sta_id == IWL_MVM_STATION_COUNT) | ||
1140 | return; | ||
1141 | |||
1142 | /* No BT - reports should be disabled */ | ||
1143 | if (!mvm->last_bt_notif.bt_status) | ||
1144 | return; | ||
1145 | |||
1146 | IWL_DEBUG_COEX(mvm, "RSSI for %pM is now %s\n", vif->bss_conf.bssid, | ||
1147 | rssi_event == RSSI_EVENT_HIGH ? "HIGH" : "LOW"); | ||
1148 | |||
1149 | /* | ||
1150 | * Check if rssi is good enough for reduced Tx power, but not in loose | ||
1151 | * scheme. | ||
1152 | */ | ||
1153 | if (rssi_event == RSSI_EVENT_LOW || mvm->cfg->bt_shared_single_ant || | ||
1154 | iwl_get_coex_type(mvm, vif) == BT_COEX_LOOSE_LUT) | ||
1155 | ret = iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, | ||
1156 | false); | ||
1157 | else | ||
1158 | ret = iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, true); | ||
1159 | |||
1160 | if (ret) | ||
1161 | IWL_ERR(mvm, "couldn't send BT_CONFIG HCMD upon RSSI event\n"); | ||
1162 | |||
1163 | ieee80211_iterate_active_interfaces_atomic( | ||
1164 | mvm->hw, IEEE80211_IFACE_ITER_NORMAL, | ||
1165 | iwl_mvm_bt_rssi_iterator, &data); | ||
1166 | |||
1167 | /* | ||
1168 | * If there are no BSS / P2P client interfaces, reduced Tx Power is | ||
1169 | * irrelevant since it is based on the RSSI coming from the beacon. | ||
1170 | * Use BT_KILL_MSK_DEFAULT in that case. | ||
1171 | */ | ||
1172 | data.reduced_tx_power = data.reduced_tx_power && data.num_bss_ifaces; | ||
1173 | |||
1174 | if (iwl_mvm_bt_udpate_ctrl_kill_msk(mvm, data.reduced_tx_power)) | ||
1175 | IWL_ERR(mvm, "Failed to update the ctrl_kill_msk\n"); | ||
1176 | } | ||
1177 | |||
1178 | #define LINK_QUAL_AGG_TIME_LIMIT_DEF (4000) | ||
1179 | #define LINK_QUAL_AGG_TIME_LIMIT_BT_ACT (1200) | ||
1180 | |||
1181 | u16 iwl_mvm_coex_agg_time_limit(struct iwl_mvm *mvm, | ||
1182 | struct ieee80211_sta *sta) | ||
1183 | { | ||
1184 | struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); | ||
1185 | enum iwl_bt_coex_lut_type lut_type; | ||
1186 | |||
1187 | if (le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) < | ||
1188 | BT_HIGH_TRAFFIC) | ||
1189 | return LINK_QUAL_AGG_TIME_LIMIT_DEF; | ||
1190 | |||
1191 | lut_type = iwl_get_coex_type(mvm, mvmsta->vif); | ||
1192 | |||
1193 | if (lut_type == BT_COEX_LOOSE_LUT) | ||
1194 | return LINK_QUAL_AGG_TIME_LIMIT_DEF; | ||
1195 | |||
1196 | /* tight coex, high bt traffic, reduce AGG time limit */ | ||
1197 | return LINK_QUAL_AGG_TIME_LIMIT_BT_ACT; | ||
1198 | } | ||
1199 | |||
1200 | bool iwl_mvm_bt_coex_is_mimo_allowed(struct iwl_mvm *mvm, | ||
1201 | struct ieee80211_sta *sta) | ||
1202 | { | ||
1203 | struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); | ||
1204 | |||
1205 | if (le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) < | ||
1206 | BT_HIGH_TRAFFIC) | ||
1207 | return true; | ||
1208 | |||
1209 | /* | ||
1210 | * In Tight, BT can't Rx while we Tx, so use both antennas since BT is | ||
1211 | * already killed. | ||
1212 | * In Loose, BT can Rx while we Tx, so forbid MIMO to let BT Rx while we | ||
1213 | * Tx. | ||
1214 | */ | ||
1215 | return iwl_get_coex_type(mvm, mvmsta->vif) == BT_COEX_TIGHT_LUT; | ||
1216 | } | ||
1217 | |||
1218 | u8 iwl_mvm_bt_coex_tx_prio(struct iwl_mvm *mvm, struct ieee80211_hdr *hdr, | ||
1219 | struct ieee80211_tx_info *info, u8 ac) | ||
1220 | { | ||
1221 | __le16 fc = hdr->frame_control; | ||
1222 | |||
1223 | if (info->band != IEEE80211_BAND_2GHZ) | ||
1224 | return 0; | ||
1225 | |||
1226 | if (unlikely(mvm->bt_tx_prio)) | ||
1227 | return mvm->bt_tx_prio - 1; | ||
1228 | |||
1229 | /* High prio packet (wrt. BT coex) if it is EAPOL, MCAST or MGMT */ | ||
1230 | if (info->control.flags & IEEE80211_TX_CTRL_PORT_CTRL_PROTO || | ||
1231 | is_multicast_ether_addr(hdr->addr1) || | ||
1232 | ieee80211_is_ctl(fc) || ieee80211_is_mgmt(fc) || | ||
1233 | ieee80211_is_nullfunc(fc) || ieee80211_is_qos_nullfunc(fc)) | ||
1234 | return 3; | ||
1235 | |||
1236 | switch (ac) { | ||
1237 | case IEEE80211_AC_BE: | ||
1238 | return 1; | ||
1239 | case IEEE80211_AC_VO: | ||
1240 | return 3; | ||
1241 | case IEEE80211_AC_VI: | ||
1242 | return 2; | ||
1243 | default: | ||
1244 | break; | ||
1245 | } | ||
1246 | |||
1247 | return 0; | ||
1248 | } | ||
1249 | |||
1250 | void iwl_mvm_bt_coex_vif_change(struct iwl_mvm *mvm) | ||
1251 | { | ||
1252 | if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_NEWBT_COEX)) | ||
1253 | return; | ||
1254 | |||
1255 | iwl_mvm_bt_coex_notif_handle(mvm); | ||
1256 | } | ||
1257 | |||
1258 | int iwl_mvm_rx_ant_coupling_notif(struct iwl_mvm *mvm, | ||
1259 | struct iwl_rx_cmd_buffer *rxb, | ||
1260 | struct iwl_device_cmd *dev_cmd) | ||
1261 | { | ||
1262 | struct iwl_rx_packet *pkt = rxb_addr(rxb); | ||
1263 | u32 ant_isolation = le32_to_cpup((void *)pkt->data); | ||
1264 | u8 __maybe_unused lower_bound, upper_bound; | ||
1265 | u8 lut; | ||
1266 | |||
1267 | struct iwl_bt_coex_cmd *bt_cmd; | ||
1268 | struct iwl_host_cmd cmd = { | ||
1269 | .id = BT_CONFIG, | ||
1270 | .len = { sizeof(*bt_cmd), }, | ||
1271 | .dataflags = { IWL_HCMD_DFL_NOCOPY, }, | ||
1272 | .flags = CMD_SYNC, | ||
1273 | }; | ||
1274 | |||
1275 | if (!IWL_MVM_BT_COEX_CORUNNING) | ||
1276 | return 0; | ||
1277 | |||
1278 | lockdep_assert_held(&mvm->mutex); | ||
1279 | |||
1280 | if (ant_isolation == mvm->last_ant_isol) | ||
1281 | return 0; | ||
1282 | |||
1283 | for (lut = 0; lut < ARRAY_SIZE(antenna_coupling_ranges) - 1; lut++) | ||
1284 | if (ant_isolation < antenna_coupling_ranges[lut + 1].range) | ||
1285 | break; | ||
1286 | |||
1287 | lower_bound = antenna_coupling_ranges[lut].range; | ||
1288 | |||
1289 | if (lut < ARRAY_SIZE(antenna_coupling_ranges) - 1) | ||
1290 | upper_bound = antenna_coupling_ranges[lut + 1].range; | ||
1291 | else | ||
1292 | upper_bound = antenna_coupling_ranges[lut].range; | ||
1293 | |||
1294 | IWL_DEBUG_COEX(mvm, "Antenna isolation=%d in range [%d,%d[, lut=%d\n", | ||
1295 | ant_isolation, lower_bound, upper_bound, lut); | ||
1296 | |||
1297 | mvm->last_ant_isol = ant_isolation; | ||
1298 | |||
1299 | if (mvm->last_corun_lut == lut) | ||
1300 | return 0; | ||
1301 | |||
1302 | mvm->last_corun_lut = lut; | ||
1303 | |||
1304 | bt_cmd = kzalloc(sizeof(*bt_cmd), GFP_KERNEL); | ||
1305 | if (!bt_cmd) | ||
1306 | return 0; | ||
1307 | cmd.data[0] = bt_cmd; | ||
1308 | |||
1309 | bt_cmd->flags = cpu_to_le32(BT_COEX_NW); | ||
1310 | bt_cmd->valid_bit_msk |= cpu_to_le32(BT_VALID_ENABLE | | ||
1311 | BT_VALID_CORUN_LUT_20 | | ||
1312 | BT_VALID_CORUN_LUT_40); | ||
1313 | |||
1314 | /* For the moment, use the same LUT for 20GHz and 40GHz */ | ||
1315 | memcpy(bt_cmd->bt4_corun_lut20, antenna_coupling_ranges[lut].lut20, | ||
1316 | sizeof(bt_cmd->bt4_corun_lut20)); | ||
1317 | |||
1318 | memcpy(bt_cmd->bt4_corun_lut40, antenna_coupling_ranges[lut].lut20, | ||
1319 | sizeof(bt_cmd->bt4_corun_lut40)); | ||
1320 | |||
1321 | return 0; | ||
1322 | } | ||