Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
0002 /*
0003  * Copyright (C) 2013-2014, 2018-2020, 2022 Intel Corporation
0004  * Copyright (C) 2013-2015 Intel Mobile Communications GmbH
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 /* 20MHz / 40MHz below / 40Mhz above*/
0016 static const __le64 iwl_ci_mask[][3] = {
0017     /* dummy entry for channel 0 */
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      * Checking that we hold mvm->mutex is a good idea, but the rate
0101      * control can't acquire the mutex since it runs in Tx path.
0102      * So this is racy in that case, but in the worst case, the AMPDU
0103      * size limit will be wrong for a short time which is not a big
0104      * issue.
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     /* else - default = TX TX disallowed */
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     /* nothing to do */
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     /* We assume here that we don't have more than 2 vifs on 2.4GHz */
0249 
0250     /* if the primary is low latency, it will stay primary */
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 /* must be called under rcu_read_lock */
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     /* default smps_mode is AUTOMATIC - only used for client modes */
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     /* If channel context is invalid or not on 2.4GHz .. */
0289     if ((!chanctx_conf ||
0290          chanctx_conf->def.chan->band != NL80211_BAND_2GHZ)) {
0291         if (vif->type == NL80211_IFTYPE_STATION) {
0292             /* ... relax constraints and disable rssi events */
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     /* relax SMPS constraints for next association */
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     /* low latency is always primary */
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              * downgrade the current primary no matter what its
0347              * type is.
0348              */
0349             data->secondary = data->primary;
0350             data->primary = chanctx_conf;
0351         } else {
0352             /* there is low latency vif - we will be secondary */
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      * STA / P2P Client, try to be primary if first vif. If we are in low
0365      * latency mode, we are already in primary and just don't do much
0366      */
0367     if (!data->primary || data->primary == chanctx_conf)
0368         data->primary = chanctx_conf;
0369     else if (!data->secondary)
0370         /* if secondary is not NULL, it might be a GO */
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      * don't reduce the Tx power if one of these is true:
0379      *  we are in LOOSE
0380      *  single share antenna product
0381      *  BT is inactive
0382      *  we are not associated
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     /* try to get the avg rssi from fw */
0393     ave_rssi = mvmvif->bf_data.ave_beacon_signal;
0394 
0395     /* if the RSSI isn't valid, fake it is very low */
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     /* Begin to monitor the RSSI: it may influence the reduced Tx power */
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     /* Ignore updates if we are in force mode */
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     /* Don't spam the fw with the same command over and over */
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     /* remember this notification for future use: rssi fluctuations */
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     /* Ignore updates if we are in force mode */
0517     if (unlikely(mvm->bt_force_ant_mode != BT_FORCE_ANT_DIS))
0518         return;
0519 
0520     /*
0521      * Rssi update while not associated - can happen since the statistics
0522      * are handled asynchronously
0523      */
0524     if (mvmvif->ap_sta_id == IWL_MVM_INVALID_STA)
0525         return;
0526 
0527     /* No BT - reports should be disabled */
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      * Check if rssi is good enough for reduced Tx power, but not in loose
0536      * scheme.
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     /* tight coex, high bt traffic, reduce AGG time limit */
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      * In Tight / TxTxDis, BT can't Rx while we Tx, so use both antennas
0593      * since BT is already killed.
0594      * In Loose, BT can Rx while we Tx, so forbid MIMO to let BT Rx while
0595      * we Tx.
0596      * When we are in 5GHz, we'll get BT_COEX_INVALID_LUT allowing MIMO.
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     /* there is no other antenna, shared antenna is always available */
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     /* there is no other antenna, shared antenna is always available */
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         /* ignore cfend and cfendack frames as we never send those */
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 }