0001
0002
0003
0004
0005
0006 #include <linux/ieee80211.h>
0007 #include <linux/etherdevice.h>
0008 #include <net/mac80211.h>
0009
0010 #include "fw/api/coex.h"
0011 #include "iwl-modparams.h"
0012 #include "mvm.h"
0013 #include "iwl-debug.h"
0014
0015
0016 static const __le64 iwl_ci_mask[][3] = {
0017
0018 {cpu_to_le64(0), cpu_to_le64(0), cpu_to_le64(0)},
0019 {
0020 cpu_to_le64(0x0000001FFFULL),
0021 cpu_to_le64(0x0ULL),
0022 cpu_to_le64(0x00007FFFFFULL),
0023 },
0024 {
0025 cpu_to_le64(0x000000FFFFULL),
0026 cpu_to_le64(0x0ULL),
0027 cpu_to_le64(0x0003FFFFFFULL),
0028 },
0029 {
0030 cpu_to_le64(0x000003FFFCULL),
0031 cpu_to_le64(0x0ULL),
0032 cpu_to_le64(0x000FFFFFFCULL),
0033 },
0034 {
0035 cpu_to_le64(0x00001FFFE0ULL),
0036 cpu_to_le64(0x0ULL),
0037 cpu_to_le64(0x007FFFFFE0ULL),
0038 },
0039 {
0040 cpu_to_le64(0x00007FFF80ULL),
0041 cpu_to_le64(0x00007FFFFFULL),
0042 cpu_to_le64(0x01FFFFFF80ULL),
0043 },
0044 {
0045 cpu_to_le64(0x0003FFFC00ULL),
0046 cpu_to_le64(0x0003FFFFFFULL),
0047 cpu_to_le64(0x0FFFFFFC00ULL),
0048 },
0049 {
0050 cpu_to_le64(0x000FFFF000ULL),
0051 cpu_to_le64(0x000FFFFFFCULL),
0052 cpu_to_le64(0x3FFFFFF000ULL),
0053 },
0054 {
0055 cpu_to_le64(0x007FFF8000ULL),
0056 cpu_to_le64(0x007FFFFFE0ULL),
0057 cpu_to_le64(0xFFFFFF8000ULL),
0058 },
0059 {
0060 cpu_to_le64(0x01FFFE0000ULL),
0061 cpu_to_le64(0x01FFFFFF80ULL),
0062 cpu_to_le64(0xFFFFFE0000ULL),
0063 },
0064 {
0065 cpu_to_le64(0x0FFFF00000ULL),
0066 cpu_to_le64(0x0FFFFFFC00ULL),
0067 cpu_to_le64(0x0ULL),
0068 },
0069 {
0070 cpu_to_le64(0x3FFFC00000ULL),
0071 cpu_to_le64(0x3FFFFFF000ULL),
0072 cpu_to_le64(0x0)
0073 },
0074 {
0075 cpu_to_le64(0xFFFE000000ULL),
0076 cpu_to_le64(0xFFFFFF8000ULL),
0077 cpu_to_le64(0x0)
0078 },
0079 {
0080 cpu_to_le64(0xFFF8000000ULL),
0081 cpu_to_le64(0xFFFFFE0000ULL),
0082 cpu_to_le64(0x0)
0083 },
0084 {
0085 cpu_to_le64(0xFE00000000ULL),
0086 cpu_to_le64(0x0ULL),
0087 cpu_to_le64(0x0ULL)
0088 },
0089 };
0090
0091 static enum iwl_bt_coex_lut_type
0092 iwl_get_coex_type(struct iwl_mvm *mvm, const struct ieee80211_vif *vif)
0093 {
0094 struct ieee80211_chanctx_conf *chanctx_conf;
0095 enum iwl_bt_coex_lut_type ret;
0096 u16 phy_ctx_id;
0097 u32 primary_ch_phy_id, secondary_ch_phy_id;
0098
0099
0100
0101
0102
0103
0104
0105
0106
0107 rcu_read_lock();
0108
0109 chanctx_conf = rcu_dereference(vif->bss_conf.chanctx_conf);
0110
0111 if (!chanctx_conf ||
0112 chanctx_conf->def.chan->band != NL80211_BAND_2GHZ) {
0113 rcu_read_unlock();
0114 return BT_COEX_INVALID_LUT;
0115 }
0116
0117 ret = BT_COEX_TX_DIS_LUT;
0118
0119 if (mvm->cfg->bt_shared_single_ant) {
0120 rcu_read_unlock();
0121 return ret;
0122 }
0123
0124 phy_ctx_id = *((u16 *)chanctx_conf->drv_priv);
0125 primary_ch_phy_id = le32_to_cpu(mvm->last_bt_ci_cmd.primary_ch_phy_id);
0126 secondary_ch_phy_id =
0127 le32_to_cpu(mvm->last_bt_ci_cmd.secondary_ch_phy_id);
0128
0129 if (primary_ch_phy_id == phy_ctx_id)
0130 ret = le32_to_cpu(mvm->last_bt_notif.primary_ch_lut);
0131 else if (secondary_ch_phy_id == phy_ctx_id)
0132 ret = le32_to_cpu(mvm->last_bt_notif.secondary_ch_lut);
0133
0134
0135 rcu_read_unlock();
0136
0137 return ret;
0138 }
0139
0140 int iwl_mvm_send_bt_init_conf(struct iwl_mvm *mvm)
0141 {
0142 struct iwl_bt_coex_cmd bt_cmd = {};
0143 u32 mode;
0144
0145 lockdep_assert_held(&mvm->mutex);
0146
0147 if (unlikely(mvm->bt_force_ant_mode != BT_FORCE_ANT_DIS)) {
0148 switch (mvm->bt_force_ant_mode) {
0149 case BT_FORCE_ANT_BT:
0150 mode = BT_COEX_BT;
0151 break;
0152 case BT_FORCE_ANT_WIFI:
0153 mode = BT_COEX_WIFI;
0154 break;
0155 default:
0156 WARN_ON(1);
0157 mode = 0;
0158 }
0159
0160 bt_cmd.mode = cpu_to_le32(mode);
0161 goto send_cmd;
0162 }
0163
0164 bt_cmd.mode = cpu_to_le32(BT_COEX_NW);
0165
0166 if (IWL_MVM_BT_COEX_SYNC2SCO)
0167 bt_cmd.enabled_modules |=
0168 cpu_to_le32(BT_COEX_SYNC2SCO_ENABLED);
0169
0170 if (iwl_mvm_is_mplut_supported(mvm))
0171 bt_cmd.enabled_modules |= cpu_to_le32(BT_COEX_MPLUT_ENABLED);
0172
0173 bt_cmd.enabled_modules |= cpu_to_le32(BT_COEX_HIGH_BAND_RET);
0174
0175 send_cmd:
0176 memset(&mvm->last_bt_notif, 0, sizeof(mvm->last_bt_notif));
0177 memset(&mvm->last_bt_ci_cmd, 0, sizeof(mvm->last_bt_ci_cmd));
0178
0179 return iwl_mvm_send_cmd_pdu(mvm, BT_CONFIG, 0, sizeof(bt_cmd), &bt_cmd);
0180 }
0181
0182 static int iwl_mvm_bt_coex_reduced_txp(struct iwl_mvm *mvm, u8 sta_id,
0183 bool enable)
0184 {
0185 struct iwl_bt_coex_reduced_txp_update_cmd cmd = {};
0186 struct iwl_mvm_sta *mvmsta;
0187 u32 value;
0188
0189 mvmsta = iwl_mvm_sta_from_staid_protected(mvm, sta_id);
0190 if (!mvmsta)
0191 return 0;
0192
0193
0194 if (mvmsta->bt_reduced_txpower == enable)
0195 return 0;
0196
0197 value = mvmsta->sta_id;
0198
0199 if (enable)
0200 value |= BT_REDUCED_TX_POWER_BIT;
0201
0202 IWL_DEBUG_COEX(mvm, "%sable reduced Tx Power for sta %d\n",
0203 enable ? "en" : "dis", sta_id);
0204
0205 cmd.reduced_txp = cpu_to_le32(value);
0206 mvmsta->bt_reduced_txpower = enable;
0207
0208 return iwl_mvm_send_cmd_pdu(mvm, BT_COEX_UPDATE_REDUCED_TXP,
0209 CMD_ASYNC, sizeof(cmd), &cmd);
0210 }
0211
0212 struct iwl_bt_iterator_data {
0213 struct iwl_bt_coex_profile_notif *notif;
0214 struct iwl_mvm *mvm;
0215 struct ieee80211_chanctx_conf *primary;
0216 struct ieee80211_chanctx_conf *secondary;
0217 bool primary_ll;
0218 u8 primary_load;
0219 u8 secondary_load;
0220 };
0221
0222 static inline
0223 void iwl_mvm_bt_coex_enable_rssi_event(struct iwl_mvm *mvm,
0224 struct ieee80211_vif *vif,
0225 bool enable, int rssi)
0226 {
0227 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
0228
0229 mvmvif->bf_data.last_bt_coex_event = rssi;
0230 mvmvif->bf_data.bt_coex_max_thold =
0231 enable ? -IWL_MVM_BT_COEX_EN_RED_TXP_THRESH : 0;
0232 mvmvif->bf_data.bt_coex_min_thold =
0233 enable ? -IWL_MVM_BT_COEX_DIS_RED_TXP_THRESH : 0;
0234 }
0235
0236 #define MVM_COEX_TCM_PERIOD (HZ * 10)
0237
0238 static void iwl_mvm_bt_coex_tcm_based_ci(struct iwl_mvm *mvm,
0239 struct iwl_bt_iterator_data *data)
0240 {
0241 unsigned long now = jiffies;
0242
0243 if (!time_after(now, mvm->bt_coex_last_tcm_ts + MVM_COEX_TCM_PERIOD))
0244 return;
0245
0246 mvm->bt_coex_last_tcm_ts = now;
0247
0248
0249
0250
0251 if (data->primary_ll)
0252 return;
0253
0254 if (data->primary_load >= data->secondary_load)
0255 return;
0256
0257 swap(data->primary, data->secondary);
0258 }
0259
0260
0261 static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac,
0262 struct ieee80211_vif *vif)
0263 {
0264 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
0265 struct iwl_bt_iterator_data *data = _data;
0266 struct iwl_mvm *mvm = data->mvm;
0267 struct ieee80211_chanctx_conf *chanctx_conf;
0268
0269 enum ieee80211_smps_mode smps_mode = IEEE80211_SMPS_AUTOMATIC;
0270 u32 bt_activity_grading, min_ag_for_static_smps;
0271 int ave_rssi;
0272
0273 lockdep_assert_held(&mvm->mutex);
0274
0275 switch (vif->type) {
0276 case NL80211_IFTYPE_STATION:
0277 break;
0278 case NL80211_IFTYPE_AP:
0279 if (!mvmvif->ap_ibss_active)
0280 return;
0281 break;
0282 default:
0283 return;
0284 }
0285
0286 chanctx_conf = rcu_dereference(vif->bss_conf.chanctx_conf);
0287
0288
0289 if ((!chanctx_conf ||
0290 chanctx_conf->def.chan->band != NL80211_BAND_2GHZ)) {
0291 if (vif->type == NL80211_IFTYPE_STATION) {
0292
0293 iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX,
0294 smps_mode);
0295 iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id,
0296 false);
0297 iwl_mvm_bt_coex_enable_rssi_event(mvm, vif, false, 0);
0298 }
0299 return;
0300 }
0301
0302 if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_COEX_SCHEMA_2))
0303 min_ag_for_static_smps = BT_VERY_HIGH_TRAFFIC;
0304 else
0305 min_ag_for_static_smps = BT_HIGH_TRAFFIC;
0306
0307 bt_activity_grading = le32_to_cpu(data->notif->bt_activity_grading);
0308 if (bt_activity_grading >= min_ag_for_static_smps)
0309 smps_mode = IEEE80211_SMPS_STATIC;
0310 else if (bt_activity_grading >= BT_LOW_TRAFFIC)
0311 smps_mode = IEEE80211_SMPS_DYNAMIC;
0312
0313
0314 if (!vif->cfg.assoc)
0315 smps_mode = IEEE80211_SMPS_AUTOMATIC;
0316
0317 if (mvmvif->phy_ctxt &&
0318 (mvm->last_bt_notif.rrc_status & BIT(mvmvif->phy_ctxt->id)))
0319 smps_mode = IEEE80211_SMPS_AUTOMATIC;
0320
0321 IWL_DEBUG_COEX(data->mvm,
0322 "mac %d: bt_activity_grading %d smps_req %d\n",
0323 mvmvif->id, bt_activity_grading, smps_mode);
0324
0325 if (vif->type == NL80211_IFTYPE_STATION)
0326 iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX,
0327 smps_mode);
0328
0329
0330 if (iwl_mvm_vif_low_latency(mvmvif)) {
0331 data->primary_ll = true;
0332
0333 data->secondary = data->primary;
0334 data->primary = chanctx_conf;
0335 }
0336
0337 if (vif->type == NL80211_IFTYPE_AP) {
0338 if (!mvmvif->ap_ibss_active)
0339 return;
0340
0341 if (chanctx_conf == data->primary)
0342 return;
0343
0344 if (!data->primary_ll) {
0345
0346
0347
0348
0349 data->secondary = data->primary;
0350 data->primary = chanctx_conf;
0351 } else {
0352
0353 data->secondary = chanctx_conf;
0354 }
0355
0356 if (data->primary == chanctx_conf)
0357 data->primary_load = mvm->tcm.result.load[mvmvif->id];
0358 else if (data->secondary == chanctx_conf)
0359 data->secondary_load = mvm->tcm.result.load[mvmvif->id];
0360 return;
0361 }
0362
0363
0364
0365
0366
0367 if (!data->primary || data->primary == chanctx_conf)
0368 data->primary = chanctx_conf;
0369 else if (!data->secondary)
0370
0371 data->secondary = chanctx_conf;
0372
0373 if (data->primary == chanctx_conf)
0374 data->primary_load = mvm->tcm.result.load[mvmvif->id];
0375 else if (data->secondary == chanctx_conf)
0376 data->secondary_load = mvm->tcm.result.load[mvmvif->id];
0377
0378
0379
0380
0381
0382
0383
0384 if (iwl_get_coex_type(mvm, vif) == BT_COEX_LOOSE_LUT ||
0385 mvm->cfg->bt_shared_single_ant || !vif->cfg.assoc ||
0386 le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) == BT_OFF) {
0387 iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, false);
0388 iwl_mvm_bt_coex_enable_rssi_event(mvm, vif, false, 0);
0389 return;
0390 }
0391
0392
0393 ave_rssi = mvmvif->bf_data.ave_beacon_signal;
0394
0395
0396 if (!ave_rssi)
0397 ave_rssi = -100;
0398 if (ave_rssi > -IWL_MVM_BT_COEX_EN_RED_TXP_THRESH) {
0399 if (iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, true))
0400 IWL_ERR(mvm, "Couldn't send BT_CONFIG cmd\n");
0401 } else if (ave_rssi < -IWL_MVM_BT_COEX_DIS_RED_TXP_THRESH) {
0402 if (iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, false))
0403 IWL_ERR(mvm, "Couldn't send BT_CONFIG cmd\n");
0404 }
0405
0406
0407 iwl_mvm_bt_coex_enable_rssi_event(mvm, vif, true, ave_rssi);
0408 }
0409
0410 static void iwl_mvm_bt_coex_notif_handle(struct iwl_mvm *mvm)
0411 {
0412 struct iwl_bt_iterator_data data = {
0413 .mvm = mvm,
0414 .notif = &mvm->last_bt_notif,
0415 };
0416 struct iwl_bt_coex_ci_cmd cmd = {};
0417 u8 ci_bw_idx;
0418
0419
0420 if (unlikely(mvm->bt_force_ant_mode != BT_FORCE_ANT_DIS))
0421 return;
0422
0423 rcu_read_lock();
0424 ieee80211_iterate_active_interfaces_atomic(
0425 mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
0426 iwl_mvm_bt_notif_iterator, &data);
0427
0428 iwl_mvm_bt_coex_tcm_based_ci(mvm, &data);
0429
0430 if (data.primary) {
0431 struct ieee80211_chanctx_conf *chan = data.primary;
0432 if (WARN_ON(!chan->def.chan)) {
0433 rcu_read_unlock();
0434 return;
0435 }
0436
0437 if (chan->def.width < NL80211_CHAN_WIDTH_40) {
0438 ci_bw_idx = 0;
0439 } else {
0440 if (chan->def.center_freq1 >
0441 chan->def.chan->center_freq)
0442 ci_bw_idx = 2;
0443 else
0444 ci_bw_idx = 1;
0445 }
0446
0447 cmd.bt_primary_ci =
0448 iwl_ci_mask[chan->def.chan->hw_value][ci_bw_idx];
0449 cmd.primary_ch_phy_id =
0450 cpu_to_le32(*((u16 *)data.primary->drv_priv));
0451 }
0452
0453 if (data.secondary) {
0454 struct ieee80211_chanctx_conf *chan = data.secondary;
0455 if (WARN_ON(!data.secondary->def.chan)) {
0456 rcu_read_unlock();
0457 return;
0458 }
0459
0460 if (chan->def.width < NL80211_CHAN_WIDTH_40) {
0461 ci_bw_idx = 0;
0462 } else {
0463 if (chan->def.center_freq1 >
0464 chan->def.chan->center_freq)
0465 ci_bw_idx = 2;
0466 else
0467 ci_bw_idx = 1;
0468 }
0469
0470 cmd.bt_secondary_ci =
0471 iwl_ci_mask[chan->def.chan->hw_value][ci_bw_idx];
0472 cmd.secondary_ch_phy_id =
0473 cpu_to_le32(*((u16 *)data.secondary->drv_priv));
0474 }
0475
0476 rcu_read_unlock();
0477
0478
0479 if (memcmp(&cmd, &mvm->last_bt_ci_cmd, sizeof(cmd))) {
0480 if (iwl_mvm_send_cmd_pdu(mvm, BT_COEX_CI, 0,
0481 sizeof(cmd), &cmd))
0482 IWL_ERR(mvm, "Failed to send BT_CI cmd\n");
0483 memcpy(&mvm->last_bt_ci_cmd, &cmd, sizeof(cmd));
0484 }
0485 }
0486
0487 void iwl_mvm_rx_bt_coex_notif(struct iwl_mvm *mvm,
0488 struct iwl_rx_cmd_buffer *rxb)
0489 {
0490 struct iwl_rx_packet *pkt = rxb_addr(rxb);
0491 struct iwl_bt_coex_profile_notif *notif = (void *)pkt->data;
0492
0493 IWL_DEBUG_COEX(mvm, "BT Coex Notification received\n");
0494 IWL_DEBUG_COEX(mvm, "\tBT ci compliance %d\n", notif->bt_ci_compliance);
0495 IWL_DEBUG_COEX(mvm, "\tBT primary_ch_lut %d\n",
0496 le32_to_cpu(notif->primary_ch_lut));
0497 IWL_DEBUG_COEX(mvm, "\tBT secondary_ch_lut %d\n",
0498 le32_to_cpu(notif->secondary_ch_lut));
0499 IWL_DEBUG_COEX(mvm, "\tBT activity grading %d\n",
0500 le32_to_cpu(notif->bt_activity_grading));
0501
0502
0503 memcpy(&mvm->last_bt_notif, notif, sizeof(mvm->last_bt_notif));
0504
0505 iwl_mvm_bt_coex_notif_handle(mvm);
0506 }
0507
0508 void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
0509 enum ieee80211_rssi_event_data rssi_event)
0510 {
0511 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
0512 int ret;
0513
0514 lockdep_assert_held(&mvm->mutex);
0515
0516
0517 if (unlikely(mvm->bt_force_ant_mode != BT_FORCE_ANT_DIS))
0518 return;
0519
0520
0521
0522
0523
0524 if (mvmvif->ap_sta_id == IWL_MVM_INVALID_STA)
0525 return;
0526
0527
0528 if (le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) == BT_OFF)
0529 return;
0530
0531 IWL_DEBUG_COEX(mvm, "RSSI for %pM is now %s\n", vif->bss_conf.bssid,
0532 rssi_event == RSSI_EVENT_HIGH ? "HIGH" : "LOW");
0533
0534
0535
0536
0537
0538 if (rssi_event == RSSI_EVENT_LOW || mvm->cfg->bt_shared_single_ant ||
0539 iwl_get_coex_type(mvm, vif) == BT_COEX_LOOSE_LUT)
0540 ret = iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id,
0541 false);
0542 else
0543 ret = iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, true);
0544
0545 if (ret)
0546 IWL_ERR(mvm, "couldn't send BT_CONFIG HCMD upon RSSI event\n");
0547 }
0548
0549 #define LINK_QUAL_AGG_TIME_LIMIT_DEF (4000)
0550 #define LINK_QUAL_AGG_TIME_LIMIT_BT_ACT (1200)
0551
0552 u16 iwl_mvm_coex_agg_time_limit(struct iwl_mvm *mvm,
0553 struct ieee80211_sta *sta)
0554 {
0555 struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
0556 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(mvmsta->vif);
0557 struct iwl_mvm_phy_ctxt *phy_ctxt = mvmvif->phy_ctxt;
0558 enum iwl_bt_coex_lut_type lut_type;
0559
0560 if (mvm->last_bt_notif.ttc_status & BIT(phy_ctxt->id))
0561 return LINK_QUAL_AGG_TIME_LIMIT_DEF;
0562
0563 if (le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) <
0564 BT_HIGH_TRAFFIC)
0565 return LINK_QUAL_AGG_TIME_LIMIT_DEF;
0566
0567 lut_type = iwl_get_coex_type(mvm, mvmsta->vif);
0568
0569 if (lut_type == BT_COEX_LOOSE_LUT || lut_type == BT_COEX_INVALID_LUT)
0570 return LINK_QUAL_AGG_TIME_LIMIT_DEF;
0571
0572
0573 return LINK_QUAL_AGG_TIME_LIMIT_BT_ACT;
0574 }
0575
0576 bool iwl_mvm_bt_coex_is_mimo_allowed(struct iwl_mvm *mvm,
0577 struct ieee80211_sta *sta)
0578 {
0579 struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
0580 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(mvmsta->vif);
0581 struct iwl_mvm_phy_ctxt *phy_ctxt = mvmvif->phy_ctxt;
0582 enum iwl_bt_coex_lut_type lut_type;
0583
0584 if (mvm->last_bt_notif.ttc_status & BIT(phy_ctxt->id))
0585 return true;
0586
0587 if (le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) <
0588 BT_HIGH_TRAFFIC)
0589 return true;
0590
0591
0592
0593
0594
0595
0596
0597
0598 lut_type = iwl_get_coex_type(mvm, mvmsta->vif);
0599 return lut_type != BT_COEX_LOOSE_LUT;
0600 }
0601
0602 bool iwl_mvm_bt_coex_is_ant_avail(struct iwl_mvm *mvm, u8 ant)
0603 {
0604
0605 if (mvm->cfg->bt_shared_single_ant)
0606 return true;
0607
0608 if (ant & mvm->cfg->non_shared_ant)
0609 return true;
0610
0611 return le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) <
0612 BT_HIGH_TRAFFIC;
0613 }
0614
0615 bool iwl_mvm_bt_coex_is_shared_ant_avail(struct iwl_mvm *mvm)
0616 {
0617
0618 if (mvm->cfg->bt_shared_single_ant)
0619 return true;
0620
0621 return le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) < BT_HIGH_TRAFFIC;
0622 }
0623
0624 bool iwl_mvm_bt_coex_is_tpc_allowed(struct iwl_mvm *mvm,
0625 enum nl80211_band band)
0626 {
0627 u32 bt_activity = le32_to_cpu(mvm->last_bt_notif.bt_activity_grading);
0628
0629 if (band != NL80211_BAND_2GHZ)
0630 return false;
0631
0632 return bt_activity >= BT_LOW_TRAFFIC;
0633 }
0634
0635 u8 iwl_mvm_bt_coex_get_single_ant_msk(struct iwl_mvm *mvm, u8 enabled_ants)
0636 {
0637 if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_COEX_SCHEMA_2) &&
0638 (mvm->cfg->non_shared_ant & enabled_ants))
0639 return mvm->cfg->non_shared_ant;
0640
0641 return first_antenna(enabled_ants);
0642 }
0643
0644 u8 iwl_mvm_bt_coex_tx_prio(struct iwl_mvm *mvm, struct ieee80211_hdr *hdr,
0645 struct ieee80211_tx_info *info, u8 ac)
0646 {
0647 __le16 fc = hdr->frame_control;
0648 bool mplut_enabled = iwl_mvm_is_mplut_supported(mvm);
0649
0650 if (info->band != NL80211_BAND_2GHZ)
0651 return 0;
0652
0653 if (unlikely(mvm->bt_tx_prio))
0654 return mvm->bt_tx_prio - 1;
0655
0656 if (likely(ieee80211_is_data(fc))) {
0657 if (likely(ieee80211_is_data_qos(fc))) {
0658 switch (ac) {
0659 case IEEE80211_AC_BE:
0660 return mplut_enabled ? 1 : 0;
0661 case IEEE80211_AC_VI:
0662 return mplut_enabled ? 2 : 3;
0663 case IEEE80211_AC_VO:
0664 return 3;
0665 default:
0666 return 0;
0667 }
0668 } else if (is_multicast_ether_addr(hdr->addr1)) {
0669 return 3;
0670 } else
0671 return 0;
0672 } else if (ieee80211_is_mgmt(fc)) {
0673 return ieee80211_is_disassoc(fc) ? 0 : 3;
0674 } else if (ieee80211_is_ctl(fc)) {
0675
0676 return 3;
0677 }
0678
0679 return 0;
0680 }
0681
0682 void iwl_mvm_bt_coex_vif_change(struct iwl_mvm *mvm)
0683 {
0684 iwl_mvm_bt_coex_notif_handle(mvm);
0685 }