1 /******************************************************************************
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.
8 * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved.
9 * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
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.
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.
20 * The full GNU General Public License is included in this distribution
21 * in the file called COPYING.
23 * Contact Information:
24 * Intel Linux Wireless <linuxwifi@intel.com>
25 * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
29 * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved.
30 * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
31 * All rights reserved.
33 * Redistribution and use in source and binary forms, with or without
34 * modification, are permitted provided that the following conditions
37 * * Redistributions of source code must retain the above copyright
38 * notice, this list of conditions and the following disclaimer.
39 * * Redistributions in binary form must reproduce the above copyright
40 * notice, this list of conditions and the following disclaimer in
41 * the documentation and/or other materials provided with the
43 * * Neither the name Intel Corporation nor the names of its
44 * contributors may be used to endorse or promote products derived
45 * from this software without specific prior written permission.
47 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
48 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
49 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
50 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
51 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
52 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
53 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
54 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
55 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
56 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
57 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
59 *****************************************************************************/
61 #include <linux/ieee80211.h>
62 #include <linux/etherdevice.h>
63 #include <net/mac80211.h>
65 #include "fw/api/coex.h"
66 #include "iwl-modparams.h"
68 #include "iwl-debug.h"
70 /* 20MHz / 40MHz below / 40Mhz above*/
71 static const __le64 iwl_ci_mask
[][3] = {
72 /* dummy entry for channel 0 */
73 {cpu_to_le64(0), cpu_to_le64(0), cpu_to_le64(0)},
75 cpu_to_le64(0x0000001FFFULL
),
77 cpu_to_le64(0x00007FFFFFULL
),
80 cpu_to_le64(0x000000FFFFULL
),
82 cpu_to_le64(0x0003FFFFFFULL
),
85 cpu_to_le64(0x000003FFFCULL
),
87 cpu_to_le64(0x000FFFFFFCULL
),
90 cpu_to_le64(0x00001FFFE0ULL
),
92 cpu_to_le64(0x007FFFFFE0ULL
),
95 cpu_to_le64(0x00007FFF80ULL
),
96 cpu_to_le64(0x00007FFFFFULL
),
97 cpu_to_le64(0x01FFFFFF80ULL
),
100 cpu_to_le64(0x0003FFFC00ULL
),
101 cpu_to_le64(0x0003FFFFFFULL
),
102 cpu_to_le64(0x0FFFFFFC00ULL
),
105 cpu_to_le64(0x000FFFF000ULL
),
106 cpu_to_le64(0x000FFFFFFCULL
),
107 cpu_to_le64(0x3FFFFFF000ULL
),
110 cpu_to_le64(0x007FFF8000ULL
),
111 cpu_to_le64(0x007FFFFFE0ULL
),
112 cpu_to_le64(0xFFFFFF8000ULL
),
115 cpu_to_le64(0x01FFFE0000ULL
),
116 cpu_to_le64(0x01FFFFFF80ULL
),
117 cpu_to_le64(0xFFFFFE0000ULL
),
120 cpu_to_le64(0x0FFFF00000ULL
),
121 cpu_to_le64(0x0FFFFFFC00ULL
),
125 cpu_to_le64(0x3FFFC00000ULL
),
126 cpu_to_le64(0x3FFFFFF000ULL
),
130 cpu_to_le64(0xFFFE000000ULL
),
131 cpu_to_le64(0xFFFFFF8000ULL
),
135 cpu_to_le64(0xFFF8000000ULL
),
136 cpu_to_le64(0xFFFFFE0000ULL
),
140 cpu_to_le64(0xFE00000000ULL
),
146 static enum iwl_bt_coex_lut_type
147 iwl_get_coex_type(struct iwl_mvm
*mvm
, const struct ieee80211_vif
*vif
)
149 struct ieee80211_chanctx_conf
*chanctx_conf
;
150 enum iwl_bt_coex_lut_type ret
;
152 u32 primary_ch_phy_id
, secondary_ch_phy_id
;
155 * Checking that we hold mvm->mutex is a good idea, but the rate
156 * control can't acquire the mutex since it runs in Tx path.
157 * So this is racy in that case, but in the worst case, the AMPDU
158 * size limit will be wrong for a short time which is not a big
164 chanctx_conf
= rcu_dereference(vif
->chanctx_conf
);
167 chanctx_conf
->def
.chan
->band
!= NL80211_BAND_2GHZ
) {
169 return BT_COEX_INVALID_LUT
;
172 ret
= BT_COEX_TX_DIS_LUT
;
174 if (mvm
->cfg
->bt_shared_single_ant
) {
179 phy_ctx_id
= *((u16
*)chanctx_conf
->drv_priv
);
180 primary_ch_phy_id
= le32_to_cpu(mvm
->last_bt_ci_cmd
.primary_ch_phy_id
);
181 secondary_ch_phy_id
=
182 le32_to_cpu(mvm
->last_bt_ci_cmd
.secondary_ch_phy_id
);
184 if (primary_ch_phy_id
== phy_ctx_id
)
185 ret
= le32_to_cpu(mvm
->last_bt_notif
.primary_ch_lut
);
186 else if (secondary_ch_phy_id
== phy_ctx_id
)
187 ret
= le32_to_cpu(mvm
->last_bt_notif
.secondary_ch_lut
);
188 /* else - default = TX TX disallowed */
195 int iwl_mvm_send_bt_init_conf(struct iwl_mvm
*mvm
)
197 struct iwl_bt_coex_cmd bt_cmd
= {};
200 lockdep_assert_held(&mvm
->mutex
);
202 if (unlikely(mvm
->bt_force_ant_mode
!= BT_FORCE_ANT_DIS
)) {
203 switch (mvm
->bt_force_ant_mode
) {
204 case BT_FORCE_ANT_BT
:
207 case BT_FORCE_ANT_WIFI
:
215 bt_cmd
.mode
= cpu_to_le32(mode
);
219 mode
= iwlwifi_mod_params
.bt_coex_active
? BT_COEX_NW
: BT_COEX_DISABLE
;
220 bt_cmd
.mode
= cpu_to_le32(mode
);
222 if (IWL_MVM_BT_COEX_SYNC2SCO
)
223 bt_cmd
.enabled_modules
|=
224 cpu_to_le32(BT_COEX_SYNC2SCO_ENABLED
);
226 if (iwl_mvm_is_mplut_supported(mvm
))
227 bt_cmd
.enabled_modules
|= cpu_to_le32(BT_COEX_MPLUT_ENABLED
);
229 bt_cmd
.enabled_modules
|= cpu_to_le32(BT_COEX_HIGH_BAND_RET
);
232 memset(&mvm
->last_bt_notif
, 0, sizeof(mvm
->last_bt_notif
));
233 memset(&mvm
->last_bt_ci_cmd
, 0, sizeof(mvm
->last_bt_ci_cmd
));
235 return iwl_mvm_send_cmd_pdu(mvm
, BT_CONFIG
, 0, sizeof(bt_cmd
), &bt_cmd
);
238 static int iwl_mvm_bt_coex_reduced_txp(struct iwl_mvm
*mvm
, u8 sta_id
,
241 struct iwl_bt_coex_reduced_txp_update_cmd cmd
= {};
242 struct iwl_mvm_sta
*mvmsta
;
245 mvmsta
= iwl_mvm_sta_from_staid_protected(mvm
, sta_id
);
250 if (mvmsta
->bt_reduced_txpower
== enable
)
253 value
= mvmsta
->sta_id
;
256 value
|= BT_REDUCED_TX_POWER_BIT
;
258 IWL_DEBUG_COEX(mvm
, "%sable reduced Tx Power for sta %d\n",
259 enable
? "en" : "dis", sta_id
);
261 cmd
.reduced_txp
= cpu_to_le32(value
);
262 mvmsta
->bt_reduced_txpower
= enable
;
264 return iwl_mvm_send_cmd_pdu(mvm
, BT_COEX_UPDATE_REDUCED_TXP
,
265 CMD_ASYNC
, sizeof(cmd
), &cmd
);
268 struct iwl_bt_iterator_data
{
269 struct iwl_bt_coex_profile_notif
*notif
;
271 struct ieee80211_chanctx_conf
*primary
;
272 struct ieee80211_chanctx_conf
*secondary
;
279 void iwl_mvm_bt_coex_enable_rssi_event(struct iwl_mvm
*mvm
,
280 struct ieee80211_vif
*vif
,
281 bool enable
, int rssi
)
283 struct iwl_mvm_vif
*mvmvif
= iwl_mvm_vif_from_mac80211(vif
);
285 mvmvif
->bf_data
.last_bt_coex_event
= rssi
;
286 mvmvif
->bf_data
.bt_coex_max_thold
=
287 enable
? -IWL_MVM_BT_COEX_EN_RED_TXP_THRESH
: 0;
288 mvmvif
->bf_data
.bt_coex_min_thold
=
289 enable
? -IWL_MVM_BT_COEX_DIS_RED_TXP_THRESH
: 0;
292 #define MVM_COEX_TCM_PERIOD (HZ * 10)
294 static void iwl_mvm_bt_coex_tcm_based_ci(struct iwl_mvm
*mvm
,
295 struct iwl_bt_iterator_data
*data
)
297 unsigned long now
= jiffies
;
299 if (!time_after(now
, mvm
->bt_coex_last_tcm_ts
+ MVM_COEX_TCM_PERIOD
))
302 mvm
->bt_coex_last_tcm_ts
= now
;
304 /* We assume here that we don't have more than 2 vifs on 2.4GHz */
306 /* if the primary is low latency, it will stay primary */
307 if (data
->primary_ll
)
310 if (data
->primary_load
>= data
->secondary_load
)
313 swap(data
->primary
, data
->secondary
);
316 /* must be called under rcu_read_lock */
317 static void iwl_mvm_bt_notif_iterator(void *_data
, u8
*mac
,
318 struct ieee80211_vif
*vif
)
320 struct iwl_mvm_vif
*mvmvif
= iwl_mvm_vif_from_mac80211(vif
);
321 struct iwl_bt_iterator_data
*data
= _data
;
322 struct iwl_mvm
*mvm
= data
->mvm
;
323 struct ieee80211_chanctx_conf
*chanctx_conf
;
324 /* default smps_mode is AUTOMATIC - only used for client modes */
325 enum ieee80211_smps_mode smps_mode
= IEEE80211_SMPS_AUTOMATIC
;
326 u32 bt_activity_grading
, min_ag_for_static_smps
;
329 lockdep_assert_held(&mvm
->mutex
);
332 case NL80211_IFTYPE_STATION
:
334 case NL80211_IFTYPE_AP
:
335 if (!mvmvif
->ap_ibss_active
)
342 chanctx_conf
= rcu_dereference(vif
->chanctx_conf
);
344 /* If channel context is invalid or not on 2.4GHz .. */
345 if ((!chanctx_conf
||
346 chanctx_conf
->def
.chan
->band
!= NL80211_BAND_2GHZ
)) {
347 if (vif
->type
== NL80211_IFTYPE_STATION
) {
348 /* ... relax constraints and disable rssi events */
349 iwl_mvm_update_smps(mvm
, vif
, IWL_MVM_SMPS_REQ_BT_COEX
,
351 iwl_mvm_bt_coex_reduced_txp(mvm
, mvmvif
->ap_sta_id
,
353 iwl_mvm_bt_coex_enable_rssi_event(mvm
, vif
, false, 0);
358 if (fw_has_capa(&mvm
->fw
->ucode_capa
, IWL_UCODE_TLV_CAPA_COEX_SCHEMA_2
))
359 min_ag_for_static_smps
= BT_VERY_HIGH_TRAFFIC
;
361 min_ag_for_static_smps
= BT_HIGH_TRAFFIC
;
363 bt_activity_grading
= le32_to_cpu(data
->notif
->bt_activity_grading
);
364 if (bt_activity_grading
>= min_ag_for_static_smps
)
365 smps_mode
= IEEE80211_SMPS_STATIC
;
366 else if (bt_activity_grading
>= BT_LOW_TRAFFIC
)
367 smps_mode
= IEEE80211_SMPS_DYNAMIC
;
369 /* relax SMPS constraints for next association */
370 if (!vif
->bss_conf
.assoc
)
371 smps_mode
= IEEE80211_SMPS_AUTOMATIC
;
373 if (mvmvif
->phy_ctxt
&&
374 (mvm
->last_bt_notif
.rrc_status
& BIT(mvmvif
->phy_ctxt
->id
)))
375 smps_mode
= IEEE80211_SMPS_AUTOMATIC
;
377 IWL_DEBUG_COEX(data
->mvm
,
378 "mac %d: bt_activity_grading %d smps_req %d\n",
379 mvmvif
->id
, bt_activity_grading
, smps_mode
);
381 if (vif
->type
== NL80211_IFTYPE_STATION
)
382 iwl_mvm_update_smps(mvm
, vif
, IWL_MVM_SMPS_REQ_BT_COEX
,
385 /* low latency is always primary */
386 if (iwl_mvm_vif_low_latency(mvmvif
)) {
387 data
->primary_ll
= true;
389 data
->secondary
= data
->primary
;
390 data
->primary
= chanctx_conf
;
393 if (vif
->type
== NL80211_IFTYPE_AP
) {
394 if (!mvmvif
->ap_ibss_active
)
397 if (chanctx_conf
== data
->primary
)
400 if (!data
->primary_ll
) {
402 * downgrade the current primary no matter what its
405 data
->secondary
= data
->primary
;
406 data
->primary
= chanctx_conf
;
408 /* there is low latency vif - we will be secondary */
409 data
->secondary
= chanctx_conf
;
412 if (data
->primary
== chanctx_conf
)
413 data
->primary_load
= mvm
->tcm
.result
.load
[mvmvif
->id
];
414 else if (data
->secondary
== chanctx_conf
)
415 data
->secondary_load
= mvm
->tcm
.result
.load
[mvmvif
->id
];
420 * STA / P2P Client, try to be primary if first vif. If we are in low
421 * latency mode, we are already in primary and just don't do much
423 if (!data
->primary
|| data
->primary
== chanctx_conf
)
424 data
->primary
= chanctx_conf
;
425 else if (!data
->secondary
)
426 /* if secondary is not NULL, it might be a GO */
427 data
->secondary
= chanctx_conf
;
429 if (data
->primary
== chanctx_conf
)
430 data
->primary_load
= mvm
->tcm
.result
.load
[mvmvif
->id
];
431 else if (data
->secondary
== chanctx_conf
)
432 data
->secondary_load
= mvm
->tcm
.result
.load
[mvmvif
->id
];
434 * don't reduce the Tx power if one of these is true:
436 * single share antenna product
438 * we are not associated
440 if (iwl_get_coex_type(mvm
, vif
) == BT_COEX_LOOSE_LUT
||
441 mvm
->cfg
->bt_shared_single_ant
|| !vif
->bss_conf
.assoc
||
442 le32_to_cpu(mvm
->last_bt_notif
.bt_activity_grading
) == BT_OFF
) {
443 iwl_mvm_bt_coex_reduced_txp(mvm
, mvmvif
->ap_sta_id
, false);
444 iwl_mvm_bt_coex_enable_rssi_event(mvm
, vif
, false, 0);
448 /* try to get the avg rssi from fw */
449 ave_rssi
= mvmvif
->bf_data
.ave_beacon_signal
;
451 /* if the RSSI isn't valid, fake it is very low */
454 if (ave_rssi
> -IWL_MVM_BT_COEX_EN_RED_TXP_THRESH
) {
455 if (iwl_mvm_bt_coex_reduced_txp(mvm
, mvmvif
->ap_sta_id
, true))
456 IWL_ERR(mvm
, "Couldn't send BT_CONFIG cmd\n");
457 } else if (ave_rssi
< -IWL_MVM_BT_COEX_DIS_RED_TXP_THRESH
) {
458 if (iwl_mvm_bt_coex_reduced_txp(mvm
, mvmvif
->ap_sta_id
, false))
459 IWL_ERR(mvm
, "Couldn't send BT_CONFIG cmd\n");
462 /* Begin to monitor the RSSI: it may influence the reduced Tx power */
463 iwl_mvm_bt_coex_enable_rssi_event(mvm
, vif
, true, ave_rssi
);
466 static void iwl_mvm_bt_coex_notif_handle(struct iwl_mvm
*mvm
)
468 struct iwl_bt_iterator_data data
= {
470 .notif
= &mvm
->last_bt_notif
,
472 struct iwl_bt_coex_ci_cmd cmd
= {};
475 /* Ignore updates if we are in force mode */
476 if (unlikely(mvm
->bt_force_ant_mode
!= BT_FORCE_ANT_DIS
))
480 ieee80211_iterate_active_interfaces_atomic(
481 mvm
->hw
, IEEE80211_IFACE_ITER_NORMAL
,
482 iwl_mvm_bt_notif_iterator
, &data
);
484 iwl_mvm_bt_coex_tcm_based_ci(mvm
, &data
);
487 struct ieee80211_chanctx_conf
*chan
= data
.primary
;
488 if (WARN_ON(!chan
->def
.chan
)) {
493 if (chan
->def
.width
< NL80211_CHAN_WIDTH_40
) {
496 if (chan
->def
.center_freq1
>
497 chan
->def
.chan
->center_freq
)
504 iwl_ci_mask
[chan
->def
.chan
->hw_value
][ci_bw_idx
];
505 cmd
.primary_ch_phy_id
=
506 cpu_to_le32(*((u16
*)data
.primary
->drv_priv
));
509 if (data
.secondary
) {
510 struct ieee80211_chanctx_conf
*chan
= data
.secondary
;
511 if (WARN_ON(!data
.secondary
->def
.chan
)) {
516 if (chan
->def
.width
< NL80211_CHAN_WIDTH_40
) {
519 if (chan
->def
.center_freq1
>
520 chan
->def
.chan
->center_freq
)
526 cmd
.bt_secondary_ci
=
527 iwl_ci_mask
[chan
->def
.chan
->hw_value
][ci_bw_idx
];
528 cmd
.secondary_ch_phy_id
=
529 cpu_to_le32(*((u16
*)data
.secondary
->drv_priv
));
534 /* Don't spam the fw with the same command over and over */
535 if (memcmp(&cmd
, &mvm
->last_bt_ci_cmd
, sizeof(cmd
))) {
536 if (iwl_mvm_send_cmd_pdu(mvm
, BT_COEX_CI
, 0,
538 IWL_ERR(mvm
, "Failed to send BT_CI cmd\n");
539 memcpy(&mvm
->last_bt_ci_cmd
, &cmd
, sizeof(cmd
));
543 void iwl_mvm_rx_bt_coex_notif(struct iwl_mvm
*mvm
,
544 struct iwl_rx_cmd_buffer
*rxb
)
546 struct iwl_rx_packet
*pkt
= rxb_addr(rxb
);
547 struct iwl_bt_coex_profile_notif
*notif
= (void *)pkt
->data
;
549 IWL_DEBUG_COEX(mvm
, "BT Coex Notification received\n");
550 IWL_DEBUG_COEX(mvm
, "\tBT ci compliance %d\n", notif
->bt_ci_compliance
);
551 IWL_DEBUG_COEX(mvm
, "\tBT primary_ch_lut %d\n",
552 le32_to_cpu(notif
->primary_ch_lut
));
553 IWL_DEBUG_COEX(mvm
, "\tBT secondary_ch_lut %d\n",
554 le32_to_cpu(notif
->secondary_ch_lut
));
555 IWL_DEBUG_COEX(mvm
, "\tBT activity grading %d\n",
556 le32_to_cpu(notif
->bt_activity_grading
));
558 /* remember this notification for future use: rssi fluctuations */
559 memcpy(&mvm
->last_bt_notif
, notif
, sizeof(mvm
->last_bt_notif
));
561 iwl_mvm_bt_coex_notif_handle(mvm
);
564 void iwl_mvm_bt_rssi_event(struct iwl_mvm
*mvm
, struct ieee80211_vif
*vif
,
565 enum ieee80211_rssi_event_data rssi_event
)
567 struct iwl_mvm_vif
*mvmvif
= iwl_mvm_vif_from_mac80211(vif
);
570 lockdep_assert_held(&mvm
->mutex
);
572 /* Ignore updates if we are in force mode */
573 if (unlikely(mvm
->bt_force_ant_mode
!= BT_FORCE_ANT_DIS
))
577 * Rssi update while not associated - can happen since the statistics
578 * are handled asynchronously
580 if (mvmvif
->ap_sta_id
== IWL_MVM_INVALID_STA
)
583 /* No BT - reports should be disabled */
584 if (le32_to_cpu(mvm
->last_bt_notif
.bt_activity_grading
) == BT_OFF
)
587 IWL_DEBUG_COEX(mvm
, "RSSI for %pM is now %s\n", vif
->bss_conf
.bssid
,
588 rssi_event
== RSSI_EVENT_HIGH
? "HIGH" : "LOW");
591 * Check if rssi is good enough for reduced Tx power, but not in loose
594 if (rssi_event
== RSSI_EVENT_LOW
|| mvm
->cfg
->bt_shared_single_ant
||
595 iwl_get_coex_type(mvm
, vif
) == BT_COEX_LOOSE_LUT
)
596 ret
= iwl_mvm_bt_coex_reduced_txp(mvm
, mvmvif
->ap_sta_id
,
599 ret
= iwl_mvm_bt_coex_reduced_txp(mvm
, mvmvif
->ap_sta_id
, true);
602 IWL_ERR(mvm
, "couldn't send BT_CONFIG HCMD upon RSSI event\n");
605 #define LINK_QUAL_AGG_TIME_LIMIT_DEF (4000)
606 #define LINK_QUAL_AGG_TIME_LIMIT_BT_ACT (1200)
608 u16
iwl_mvm_coex_agg_time_limit(struct iwl_mvm
*mvm
,
609 struct ieee80211_sta
*sta
)
611 struct iwl_mvm_sta
*mvmsta
= iwl_mvm_sta_from_mac80211(sta
);
612 struct iwl_mvm_vif
*mvmvif
= iwl_mvm_vif_from_mac80211(mvmsta
->vif
);
613 struct iwl_mvm_phy_ctxt
*phy_ctxt
= mvmvif
->phy_ctxt
;
614 enum iwl_bt_coex_lut_type lut_type
;
616 if (mvm
->last_bt_notif
.ttc_status
& BIT(phy_ctxt
->id
))
617 return LINK_QUAL_AGG_TIME_LIMIT_DEF
;
619 if (le32_to_cpu(mvm
->last_bt_notif
.bt_activity_grading
) <
621 return LINK_QUAL_AGG_TIME_LIMIT_DEF
;
623 lut_type
= iwl_get_coex_type(mvm
, mvmsta
->vif
);
625 if (lut_type
== BT_COEX_LOOSE_LUT
|| lut_type
== BT_COEX_INVALID_LUT
)
626 return LINK_QUAL_AGG_TIME_LIMIT_DEF
;
628 /* tight coex, high bt traffic, reduce AGG time limit */
629 return LINK_QUAL_AGG_TIME_LIMIT_BT_ACT
;
632 bool iwl_mvm_bt_coex_is_mimo_allowed(struct iwl_mvm
*mvm
,
633 struct ieee80211_sta
*sta
)
635 struct iwl_mvm_sta
*mvmsta
= iwl_mvm_sta_from_mac80211(sta
);
636 struct iwl_mvm_vif
*mvmvif
= iwl_mvm_vif_from_mac80211(mvmsta
->vif
);
637 struct iwl_mvm_phy_ctxt
*phy_ctxt
= mvmvif
->phy_ctxt
;
638 enum iwl_bt_coex_lut_type lut_type
;
640 if (mvm
->last_bt_notif
.ttc_status
& BIT(phy_ctxt
->id
))
643 if (le32_to_cpu(mvm
->last_bt_notif
.bt_activity_grading
) <
648 * In Tight / TxTxDis, BT can't Rx while we Tx, so use both antennas
649 * since BT is already killed.
650 * In Loose, BT can Rx while we Tx, so forbid MIMO to let BT Rx while
652 * When we are in 5GHz, we'll get BT_COEX_INVALID_LUT allowing MIMO.
654 lut_type
= iwl_get_coex_type(mvm
, mvmsta
->vif
);
655 return lut_type
!= BT_COEX_LOOSE_LUT
;
658 bool iwl_mvm_bt_coex_is_ant_avail(struct iwl_mvm
*mvm
, u8 ant
)
660 /* there is no other antenna, shared antenna is always available */
661 if (mvm
->cfg
->bt_shared_single_ant
)
664 if (ant
& mvm
->cfg
->non_shared_ant
)
667 return le32_to_cpu(mvm
->last_bt_notif
.bt_activity_grading
) <
671 bool iwl_mvm_bt_coex_is_shared_ant_avail(struct iwl_mvm
*mvm
)
673 /* there is no other antenna, shared antenna is always available */
674 if (mvm
->cfg
->bt_shared_single_ant
)
677 return le32_to_cpu(mvm
->last_bt_notif
.bt_activity_grading
) < BT_HIGH_TRAFFIC
;
680 bool iwl_mvm_bt_coex_is_tpc_allowed(struct iwl_mvm
*mvm
,
681 enum nl80211_band band
)
683 u32 bt_activity
= le32_to_cpu(mvm
->last_bt_notif
.bt_activity_grading
);
685 if (band
!= NL80211_BAND_2GHZ
)
688 return bt_activity
>= BT_LOW_TRAFFIC
;
691 u8
iwl_mvm_bt_coex_get_single_ant_msk(struct iwl_mvm
*mvm
, u8 enabled_ants
)
693 if (fw_has_capa(&mvm
->fw
->ucode_capa
, IWL_UCODE_TLV_CAPA_COEX_SCHEMA_2
) &&
694 (mvm
->cfg
->non_shared_ant
& enabled_ants
))
695 return mvm
->cfg
->non_shared_ant
;
697 return first_antenna(enabled_ants
);
700 u8
iwl_mvm_bt_coex_tx_prio(struct iwl_mvm
*mvm
, struct ieee80211_hdr
*hdr
,
701 struct ieee80211_tx_info
*info
, u8 ac
)
703 __le16 fc
= hdr
->frame_control
;
704 bool mplut_enabled
= iwl_mvm_is_mplut_supported(mvm
);
706 if (info
->band
!= NL80211_BAND_2GHZ
)
709 if (unlikely(mvm
->bt_tx_prio
))
710 return mvm
->bt_tx_prio
- 1;
712 if (likely(ieee80211_is_data(fc
))) {
713 if (likely(ieee80211_is_data_qos(fc
))) {
715 case IEEE80211_AC_BE
:
716 return mplut_enabled
? 1 : 0;
717 case IEEE80211_AC_VI
:
718 return mplut_enabled
? 2 : 3;
719 case IEEE80211_AC_VO
:
724 } else if (is_multicast_ether_addr(hdr
->addr1
)) {
728 } else if (ieee80211_is_mgmt(fc
)) {
729 return ieee80211_is_disassoc(fc
) ? 0 : 3;
730 } else if (ieee80211_is_ctl(fc
)) {
731 /* ignore cfend and cfendack frames as we never send those */
738 void iwl_mvm_bt_coex_vif_change(struct iwl_mvm
*mvm
)
740 iwl_mvm_bt_coex_notif_handle(mvm
);