The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/contrib/dev/iwlwifi/mvm/coex.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
    2 /*
    3  * Copyright (C) 2013-2014, 2018-2020 Intel Corporation
    4  * Copyright (C) 2013-2015 Intel Mobile Communications GmbH
    5  */
    6 #include <linux/ieee80211.h>
    7 #include <linux/etherdevice.h>
    8 #include <net/mac80211.h>
    9 
   10 #include "fw/api/coex.h"
   11 #include "iwl-modparams.h"
   12 #include "mvm.h"
   13 #include "iwl-debug.h"
   14 
   15 /* 20MHz / 40MHz below / 40Mhz above*/
   16 static const __le64 iwl_ci_mask[][3] = {
   17         /* dummy entry for channel 0 */
   18         {cpu_to_le64(0), cpu_to_le64(0), cpu_to_le64(0)},
   19         {
   20                 cpu_to_le64(0x0000001FFFULL),
   21                 cpu_to_le64(0x0ULL),
   22                 cpu_to_le64(0x00007FFFFFULL),
   23         },
   24         {
   25                 cpu_to_le64(0x000000FFFFULL),
   26                 cpu_to_le64(0x0ULL),
   27                 cpu_to_le64(0x0003FFFFFFULL),
   28         },
   29         {
   30                 cpu_to_le64(0x000003FFFCULL),
   31                 cpu_to_le64(0x0ULL),
   32                 cpu_to_le64(0x000FFFFFFCULL),
   33         },
   34         {
   35                 cpu_to_le64(0x00001FFFE0ULL),
   36                 cpu_to_le64(0x0ULL),
   37                 cpu_to_le64(0x007FFFFFE0ULL),
   38         },
   39         {
   40                 cpu_to_le64(0x00007FFF80ULL),
   41                 cpu_to_le64(0x00007FFFFFULL),
   42                 cpu_to_le64(0x01FFFFFF80ULL),
   43         },
   44         {
   45                 cpu_to_le64(0x0003FFFC00ULL),
   46                 cpu_to_le64(0x0003FFFFFFULL),
   47                 cpu_to_le64(0x0FFFFFFC00ULL),
   48         },
   49         {
   50                 cpu_to_le64(0x000FFFF000ULL),
   51                 cpu_to_le64(0x000FFFFFFCULL),
   52                 cpu_to_le64(0x3FFFFFF000ULL),
   53         },
   54         {
   55                 cpu_to_le64(0x007FFF8000ULL),
   56                 cpu_to_le64(0x007FFFFFE0ULL),
   57                 cpu_to_le64(0xFFFFFF8000ULL),
   58         },
   59         {
   60                 cpu_to_le64(0x01FFFE0000ULL),
   61                 cpu_to_le64(0x01FFFFFF80ULL),
   62                 cpu_to_le64(0xFFFFFE0000ULL),
   63         },
   64         {
   65                 cpu_to_le64(0x0FFFF00000ULL),
   66                 cpu_to_le64(0x0FFFFFFC00ULL),
   67                 cpu_to_le64(0x0ULL),
   68         },
   69         {
   70                 cpu_to_le64(0x3FFFC00000ULL),
   71                 cpu_to_le64(0x3FFFFFF000ULL),
   72                 cpu_to_le64(0x0)
   73         },
   74         {
   75                 cpu_to_le64(0xFFFE000000ULL),
   76                 cpu_to_le64(0xFFFFFF8000ULL),
   77                 cpu_to_le64(0x0)
   78         },
   79         {
   80                 cpu_to_le64(0xFFF8000000ULL),
   81                 cpu_to_le64(0xFFFFFE0000ULL),
   82                 cpu_to_le64(0x0)
   83         },
   84         {
   85                 cpu_to_le64(0xFE00000000ULL),
   86                 cpu_to_le64(0x0ULL),
   87                 cpu_to_le64(0x0ULL)
   88         },
   89 };
   90 
   91 static enum iwl_bt_coex_lut_type
   92 iwl_get_coex_type(struct iwl_mvm *mvm, const struct ieee80211_vif *vif)
   93 {
   94         struct ieee80211_chanctx_conf *chanctx_conf;
   95         enum iwl_bt_coex_lut_type ret;
   96         u16 phy_ctx_id;
   97         u32 primary_ch_phy_id, secondary_ch_phy_id;
   98 
   99         /*
  100          * Checking that we hold mvm->mutex is a good idea, but the rate
  101          * control can't acquire the mutex since it runs in Tx path.
  102          * So this is racy in that case, but in the worst case, the AMPDU
  103          * size limit will be wrong for a short time which is not a big
  104          * issue.
  105          */
  106 
  107         rcu_read_lock();
  108 
  109         chanctx_conf = rcu_dereference(vif->chanctx_conf);
  110 
  111         if (!chanctx_conf ||
  112              chanctx_conf->def.chan->band != NL80211_BAND_2GHZ) {
  113                 rcu_read_unlock();
  114                 return BT_COEX_INVALID_LUT;
  115         }
  116 
  117         ret = BT_COEX_TX_DIS_LUT;
  118 
  119         if (mvm->cfg->bt_shared_single_ant) {
  120                 rcu_read_unlock();
  121                 return ret;
  122         }
  123 
  124         phy_ctx_id = *((u16 *)chanctx_conf->drv_priv);
  125         primary_ch_phy_id = le32_to_cpu(mvm->last_bt_ci_cmd.primary_ch_phy_id);
  126         secondary_ch_phy_id =
  127                 le32_to_cpu(mvm->last_bt_ci_cmd.secondary_ch_phy_id);
  128 
  129         if (primary_ch_phy_id == phy_ctx_id)
  130                 ret = le32_to_cpu(mvm->last_bt_notif.primary_ch_lut);
  131         else if (secondary_ch_phy_id == phy_ctx_id)
  132                 ret = le32_to_cpu(mvm->last_bt_notif.secondary_ch_lut);
  133         /* else - default = TX TX disallowed */
  134 
  135         rcu_read_unlock();
  136 
  137         return ret;
  138 }
  139 
  140 int iwl_mvm_send_bt_init_conf(struct iwl_mvm *mvm)
  141 {
  142         struct iwl_bt_coex_cmd bt_cmd = {};
  143         u32 mode;
  144 
  145         lockdep_assert_held(&mvm->mutex);
  146 
  147         if (unlikely(mvm->bt_force_ant_mode != BT_FORCE_ANT_DIS)) {
  148                 switch (mvm->bt_force_ant_mode) {
  149                 case BT_FORCE_ANT_BT:
  150                         mode = BT_COEX_BT;
  151                         break;
  152                 case BT_FORCE_ANT_WIFI:
  153                         mode = BT_COEX_WIFI;
  154                         break;
  155                 default:
  156                         WARN_ON(1);
  157                         mode = 0;
  158                 }
  159 
  160                 bt_cmd.mode = cpu_to_le32(mode);
  161                 goto send_cmd;
  162         }
  163 
  164         bt_cmd.mode = cpu_to_le32(BT_COEX_NW);
  165 
  166         if (IWL_MVM_BT_COEX_SYNC2SCO)
  167                 bt_cmd.enabled_modules |=
  168                         cpu_to_le32(BT_COEX_SYNC2SCO_ENABLED);
  169 
  170         if (iwl_mvm_is_mplut_supported(mvm))
  171                 bt_cmd.enabled_modules |= cpu_to_le32(BT_COEX_MPLUT_ENABLED);
  172 
  173         bt_cmd.enabled_modules |= cpu_to_le32(BT_COEX_HIGH_BAND_RET);
  174 
  175 send_cmd:
  176         memset(&mvm->last_bt_notif, 0, sizeof(mvm->last_bt_notif));
  177         memset(&mvm->last_bt_ci_cmd, 0, sizeof(mvm->last_bt_ci_cmd));
  178 
  179         return iwl_mvm_send_cmd_pdu(mvm, BT_CONFIG, 0, sizeof(bt_cmd), &bt_cmd);
  180 }
  181 
  182 static int iwl_mvm_bt_coex_reduced_txp(struct iwl_mvm *mvm, u8 sta_id,
  183                                        bool enable)
  184 {
  185         struct iwl_bt_coex_reduced_txp_update_cmd cmd = {};
  186         struct iwl_mvm_sta *mvmsta;
  187         u32 value;
  188 
  189         mvmsta = iwl_mvm_sta_from_staid_protected(mvm, sta_id);
  190         if (!mvmsta)
  191                 return 0;
  192 
  193         /* nothing to do */
  194         if (mvmsta->bt_reduced_txpower == enable)
  195                 return 0;
  196 
  197         value = mvmsta->sta_id;
  198 
  199         if (enable)
  200                 value |= BT_REDUCED_TX_POWER_BIT;
  201 
  202         IWL_DEBUG_COEX(mvm, "%sable reduced Tx Power for sta %d\n",
  203                        enable ? "en" : "dis", sta_id);
  204 
  205         cmd.reduced_txp = cpu_to_le32(value);
  206         mvmsta->bt_reduced_txpower = enable;
  207 
  208         return iwl_mvm_send_cmd_pdu(mvm, BT_COEX_UPDATE_REDUCED_TXP,
  209                                     CMD_ASYNC, sizeof(cmd), &cmd);
  210 }
  211 
  212 struct iwl_bt_iterator_data {
  213         struct iwl_bt_coex_profile_notif *notif;
  214         struct iwl_mvm *mvm;
  215         struct ieee80211_chanctx_conf *primary;
  216         struct ieee80211_chanctx_conf *secondary;
  217         bool primary_ll;
  218         u8 primary_load;
  219         u8 secondary_load;
  220 };
  221 
  222 static inline
  223 void iwl_mvm_bt_coex_enable_rssi_event(struct iwl_mvm *mvm,
  224                                        struct ieee80211_vif *vif,
  225                                        bool enable, int rssi)
  226 {
  227         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
  228 
  229         mvmvif->bf_data.last_bt_coex_event = rssi;
  230         mvmvif->bf_data.bt_coex_max_thold =
  231                 enable ? -IWL_MVM_BT_COEX_EN_RED_TXP_THRESH : 0;
  232         mvmvif->bf_data.bt_coex_min_thold =
  233                 enable ? -IWL_MVM_BT_COEX_DIS_RED_TXP_THRESH : 0;
  234 }
  235 
  236 #define MVM_COEX_TCM_PERIOD (HZ * 10)
  237 
  238 static void iwl_mvm_bt_coex_tcm_based_ci(struct iwl_mvm *mvm,
  239                                          struct iwl_bt_iterator_data *data)
  240 {
  241         unsigned long now = jiffies;
  242 
  243         if (!time_after(now, mvm->bt_coex_last_tcm_ts + MVM_COEX_TCM_PERIOD))
  244                 return;
  245 
  246         mvm->bt_coex_last_tcm_ts = now;
  247 
  248         /* We assume here that we don't have more than 2 vifs on 2.4GHz */
  249 
  250         /* if the primary is low latency, it will stay primary */
  251         if (data->primary_ll)
  252                 return;
  253 
  254         if (data->primary_load >= data->secondary_load)
  255                 return;
  256 
  257         swap(data->primary, data->secondary);
  258 }
  259 
  260 /* must be called under rcu_read_lock */
  261 static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac,
  262                                       struct ieee80211_vif *vif)
  263 {
  264         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
  265         struct iwl_bt_iterator_data *data = _data;
  266         struct iwl_mvm *mvm = data->mvm;
  267         struct ieee80211_chanctx_conf *chanctx_conf;
  268         /* default smps_mode is AUTOMATIC - only used for client modes */
  269         enum ieee80211_smps_mode smps_mode = IEEE80211_SMPS_AUTOMATIC;
  270         u32 bt_activity_grading, min_ag_for_static_smps;
  271         int ave_rssi;
  272 
  273         lockdep_assert_held(&mvm->mutex);
  274 
  275         switch (vif->type) {
  276         case NL80211_IFTYPE_STATION:
  277                 break;
  278         case NL80211_IFTYPE_AP:
  279                 if (!mvmvif->ap_ibss_active)
  280                         return;
  281                 break;
  282         default:
  283                 return;
  284         }
  285 
  286         chanctx_conf = rcu_dereference(vif->chanctx_conf);
  287 
  288         /* If channel context is invalid or not on 2.4GHz .. */
  289         if ((!chanctx_conf ||
  290              chanctx_conf->def.chan->band != NL80211_BAND_2GHZ)) {
  291                 if (vif->type == NL80211_IFTYPE_STATION) {
  292                         /* ... relax constraints and disable rssi events */
  293                         iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX,
  294                                             smps_mode);
  295                         iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id,
  296                                                     false);
  297                         iwl_mvm_bt_coex_enable_rssi_event(mvm, vif, false, 0);
  298                 }
  299                 return;
  300         }
  301 
  302         if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_COEX_SCHEMA_2))
  303                 min_ag_for_static_smps = BT_VERY_HIGH_TRAFFIC;
  304         else
  305                 min_ag_for_static_smps = BT_HIGH_TRAFFIC;
  306 
  307         bt_activity_grading = le32_to_cpu(data->notif->bt_activity_grading);
  308         if (bt_activity_grading >= min_ag_for_static_smps)
  309                 smps_mode = IEEE80211_SMPS_STATIC;
  310         else if (bt_activity_grading >= BT_LOW_TRAFFIC)
  311                 smps_mode = IEEE80211_SMPS_DYNAMIC;
  312 
  313         /* relax SMPS constraints for next association */
  314         if (!vif->bss_conf.assoc)
  315                 smps_mode = IEEE80211_SMPS_AUTOMATIC;
  316 
  317         if (mvmvif->phy_ctxt &&
  318             (mvm->last_bt_notif.rrc_status & BIT(mvmvif->phy_ctxt->id)))
  319                 smps_mode = IEEE80211_SMPS_AUTOMATIC;
  320 
  321         IWL_DEBUG_COEX(data->mvm,
  322                        "mac %d: bt_activity_grading %d smps_req %d\n",
  323                        mvmvif->id, bt_activity_grading, smps_mode);
  324 
  325         if (vif->type == NL80211_IFTYPE_STATION)
  326                 iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX,
  327                                     smps_mode);
  328 
  329         /* low latency is always primary */
  330         if (iwl_mvm_vif_low_latency(mvmvif)) {
  331                 data->primary_ll = true;
  332 
  333                 data->secondary = data->primary;
  334                 data->primary = chanctx_conf;
  335         }
  336 
  337         if (vif->type == NL80211_IFTYPE_AP) {
  338                 if (!mvmvif->ap_ibss_active)
  339                         return;
  340 
  341                 if (chanctx_conf == data->primary)
  342                         return;
  343 
  344                 if (!data->primary_ll) {
  345                         /*
  346                          * downgrade the current primary no matter what its
  347                          * type is.
  348                          */
  349                         data->secondary = data->primary;
  350                         data->primary = chanctx_conf;
  351                 } else {
  352                         /* there is low latency vif - we will be secondary */
  353                         data->secondary = chanctx_conf;
  354                 }
  355 
  356                 if (data->primary == chanctx_conf)
  357                         data->primary_load = mvm->tcm.result.load[mvmvif->id];
  358                 else if (data->secondary == chanctx_conf)
  359                         data->secondary_load = mvm->tcm.result.load[mvmvif->id];
  360                 return;
  361         }
  362 
  363         /*
  364          * STA / P2P Client, try to be primary if first vif. If we are in low
  365          * latency mode, we are already in primary and just don't do much
  366          */
  367         if (!data->primary || data->primary == chanctx_conf)
  368                 data->primary = chanctx_conf;
  369         else if (!data->secondary)
  370                 /* if secondary is not NULL, it might be a GO */
  371                 data->secondary = chanctx_conf;
  372 
  373         if (data->primary == chanctx_conf)
  374                 data->primary_load = mvm->tcm.result.load[mvmvif->id];
  375         else if (data->secondary == chanctx_conf)
  376                 data->secondary_load = mvm->tcm.result.load[mvmvif->id];
  377         /*
  378          * don't reduce the Tx power if one of these is true:
  379          *  we are in LOOSE
  380          *  single share antenna product
  381          *  BT is inactive
  382          *  we are not associated
  383          */
  384         if (iwl_get_coex_type(mvm, vif) == BT_COEX_LOOSE_LUT ||
  385             mvm->cfg->bt_shared_single_ant || !vif->bss_conf.assoc ||
  386             le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) == BT_OFF) {
  387                 iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, false);
  388                 iwl_mvm_bt_coex_enable_rssi_event(mvm, vif, false, 0);
  389                 return;
  390         }
  391 
  392         /* try to get the avg rssi from fw */
  393         ave_rssi = mvmvif->bf_data.ave_beacon_signal;
  394 
  395         /* if the RSSI isn't valid, fake it is very low */
  396         if (!ave_rssi)
  397                 ave_rssi = -100;
  398         if (ave_rssi > -IWL_MVM_BT_COEX_EN_RED_TXP_THRESH) {
  399                 if (iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, true))
  400                         IWL_ERR(mvm, "Couldn't send BT_CONFIG cmd\n");
  401         } else if (ave_rssi < -IWL_MVM_BT_COEX_DIS_RED_TXP_THRESH) {
  402                 if (iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, false))
  403                         IWL_ERR(mvm, "Couldn't send BT_CONFIG cmd\n");
  404         }
  405 
  406         /* Begin to monitor the RSSI: it may influence the reduced Tx power */
  407         iwl_mvm_bt_coex_enable_rssi_event(mvm, vif, true, ave_rssi);
  408 }
  409 
  410 static void iwl_mvm_bt_coex_notif_handle(struct iwl_mvm *mvm)
  411 {
  412         struct iwl_bt_iterator_data data = {
  413                 .mvm = mvm,
  414                 .notif = &mvm->last_bt_notif,
  415         };
  416         struct iwl_bt_coex_ci_cmd cmd = {};
  417         u8 ci_bw_idx;
  418 
  419         /* Ignore updates if we are in force mode */
  420         if (unlikely(mvm->bt_force_ant_mode != BT_FORCE_ANT_DIS))
  421                 return;
  422 
  423         rcu_read_lock();
  424         ieee80211_iterate_active_interfaces_atomic(
  425                                         mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
  426                                         iwl_mvm_bt_notif_iterator, &data);
  427 
  428         iwl_mvm_bt_coex_tcm_based_ci(mvm, &data);
  429 
  430         if (data.primary) {
  431                 struct ieee80211_chanctx_conf *chan = data.primary;
  432                 if (WARN_ON(!chan->def.chan)) {
  433                         rcu_read_unlock();
  434                         return;
  435                 }
  436 
  437                 if (chan->def.width < NL80211_CHAN_WIDTH_40) {
  438                         ci_bw_idx = 0;
  439                 } else {
  440                         if (chan->def.center_freq1 >
  441                             chan->def.chan->center_freq)
  442                                 ci_bw_idx = 2;
  443                         else
  444                                 ci_bw_idx = 1;
  445                 }
  446 
  447                 cmd.bt_primary_ci =
  448                         iwl_ci_mask[chan->def.chan->hw_value][ci_bw_idx];
  449                 cmd.primary_ch_phy_id =
  450                         cpu_to_le32(*((u16 *)data.primary->drv_priv));
  451         }
  452 
  453         if (data.secondary) {
  454                 struct ieee80211_chanctx_conf *chan = data.secondary;
  455                 if (WARN_ON(!data.secondary->def.chan)) {
  456                         rcu_read_unlock();
  457                         return;
  458                 }
  459 
  460                 if (chan->def.width < NL80211_CHAN_WIDTH_40) {
  461                         ci_bw_idx = 0;
  462                 } else {
  463                         if (chan->def.center_freq1 >
  464                             chan->def.chan->center_freq)
  465                                 ci_bw_idx = 2;
  466                         else
  467                                 ci_bw_idx = 1;
  468                 }
  469 
  470                 cmd.bt_secondary_ci =
  471                         iwl_ci_mask[chan->def.chan->hw_value][ci_bw_idx];
  472                 cmd.secondary_ch_phy_id =
  473                         cpu_to_le32(*((u16 *)data.secondary->drv_priv));
  474         }
  475 
  476         rcu_read_unlock();
  477 
  478         /* Don't spam the fw with the same command over and over */
  479         if (memcmp(&cmd, &mvm->last_bt_ci_cmd, sizeof(cmd))) {
  480                 if (iwl_mvm_send_cmd_pdu(mvm, BT_COEX_CI, 0,
  481                                          sizeof(cmd), &cmd))
  482                         IWL_ERR(mvm, "Failed to send BT_CI cmd\n");
  483                 memcpy(&mvm->last_bt_ci_cmd, &cmd, sizeof(cmd));
  484         }
  485 }
  486 
  487 void iwl_mvm_rx_bt_coex_notif(struct iwl_mvm *mvm,
  488                               struct iwl_rx_cmd_buffer *rxb)
  489 {
  490         struct iwl_rx_packet *pkt = rxb_addr(rxb);
  491         struct iwl_bt_coex_profile_notif *notif = (void *)pkt->data;
  492 
  493         IWL_DEBUG_COEX(mvm, "BT Coex Notification received\n");
  494         IWL_DEBUG_COEX(mvm, "\tBT ci compliance %d\n", notif->bt_ci_compliance);
  495         IWL_DEBUG_COEX(mvm, "\tBT primary_ch_lut %d\n",
  496                        le32_to_cpu(notif->primary_ch_lut));
  497         IWL_DEBUG_COEX(mvm, "\tBT secondary_ch_lut %d\n",
  498                        le32_to_cpu(notif->secondary_ch_lut));
  499         IWL_DEBUG_COEX(mvm, "\tBT activity grading %d\n",
  500                        le32_to_cpu(notif->bt_activity_grading));
  501 
  502         /* remember this notification for future use: rssi fluctuations */
  503         memcpy(&mvm->last_bt_notif, notif, sizeof(mvm->last_bt_notif));
  504 
  505         iwl_mvm_bt_coex_notif_handle(mvm);
  506 }
  507 
  508 void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
  509                            enum ieee80211_rssi_event_data rssi_event)
  510 {
  511         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
  512         int ret;
  513 
  514         lockdep_assert_held(&mvm->mutex);
  515 
  516         /* Ignore updates if we are in force mode */
  517         if (unlikely(mvm->bt_force_ant_mode != BT_FORCE_ANT_DIS))
  518                 return;
  519 
  520         /*
  521          * Rssi update while not associated - can happen since the statistics
  522          * are handled asynchronously
  523          */
  524         if (mvmvif->ap_sta_id == IWL_MVM_INVALID_STA)
  525                 return;
  526 
  527         /* No BT - reports should be disabled */
  528         if (le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) == BT_OFF)
  529                 return;
  530 
  531         IWL_DEBUG_COEX(mvm, "RSSI for %pM is now %s\n", vif->bss_conf.bssid,
  532                        rssi_event == RSSI_EVENT_HIGH ? "HIGH" : "LOW");
  533 
  534         /*
  535          * Check if rssi is good enough for reduced Tx power, but not in loose
  536          * scheme.
  537          */
  538         if (rssi_event == RSSI_EVENT_LOW || mvm->cfg->bt_shared_single_ant ||
  539             iwl_get_coex_type(mvm, vif) == BT_COEX_LOOSE_LUT)
  540                 ret = iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id,
  541                                                   false);
  542         else
  543                 ret = iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, true);
  544 
  545         if (ret)
  546                 IWL_ERR(mvm, "couldn't send BT_CONFIG HCMD upon RSSI event\n");
  547 }
  548 
  549 #define LINK_QUAL_AGG_TIME_LIMIT_DEF    (4000)
  550 #define LINK_QUAL_AGG_TIME_LIMIT_BT_ACT (1200)
  551 
  552 u16 iwl_mvm_coex_agg_time_limit(struct iwl_mvm *mvm,
  553                                 struct ieee80211_sta *sta)
  554 {
  555         struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
  556         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(mvmsta->vif);
  557         struct iwl_mvm_phy_ctxt *phy_ctxt = mvmvif->phy_ctxt;
  558         enum iwl_bt_coex_lut_type lut_type;
  559 
  560         if (mvm->last_bt_notif.ttc_status & BIT(phy_ctxt->id))
  561                 return LINK_QUAL_AGG_TIME_LIMIT_DEF;
  562 
  563         if (le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) <
  564             BT_HIGH_TRAFFIC)
  565                 return LINK_QUAL_AGG_TIME_LIMIT_DEF;
  566 
  567         lut_type = iwl_get_coex_type(mvm, mvmsta->vif);
  568 
  569         if (lut_type == BT_COEX_LOOSE_LUT || lut_type == BT_COEX_INVALID_LUT)
  570                 return LINK_QUAL_AGG_TIME_LIMIT_DEF;
  571 
  572         /* tight coex, high bt traffic, reduce AGG time limit */
  573         return LINK_QUAL_AGG_TIME_LIMIT_BT_ACT;
  574 }
  575 
  576 bool iwl_mvm_bt_coex_is_mimo_allowed(struct iwl_mvm *mvm,
  577                                      struct ieee80211_sta *sta)
  578 {
  579         struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
  580         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(mvmsta->vif);
  581         struct iwl_mvm_phy_ctxt *phy_ctxt = mvmvif->phy_ctxt;
  582         enum iwl_bt_coex_lut_type lut_type;
  583 
  584         if (mvm->last_bt_notif.ttc_status & BIT(phy_ctxt->id))
  585                 return true;
  586 
  587         if (le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) <
  588             BT_HIGH_TRAFFIC)
  589                 return true;
  590 
  591         /*
  592          * In Tight / TxTxDis, BT can't Rx while we Tx, so use both antennas
  593          * since BT is already killed.
  594          * In Loose, BT can Rx while we Tx, so forbid MIMO to let BT Rx while
  595          * we Tx.
  596          * When we are in 5GHz, we'll get BT_COEX_INVALID_LUT allowing MIMO.
  597          */
  598         lut_type = iwl_get_coex_type(mvm, mvmsta->vif);
  599         return lut_type != BT_COEX_LOOSE_LUT;
  600 }
  601 
  602 bool iwl_mvm_bt_coex_is_ant_avail(struct iwl_mvm *mvm, u8 ant)
  603 {
  604         /* there is no other antenna, shared antenna is always available */
  605         if (mvm->cfg->bt_shared_single_ant)
  606                 return true;
  607 
  608         if (ant & mvm->cfg->non_shared_ant)
  609                 return true;
  610 
  611         return le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) <
  612                 BT_HIGH_TRAFFIC;
  613 }
  614 
  615 bool iwl_mvm_bt_coex_is_shared_ant_avail(struct iwl_mvm *mvm)
  616 {
  617         /* there is no other antenna, shared antenna is always available */
  618         if (mvm->cfg->bt_shared_single_ant)
  619                 return true;
  620 
  621         return le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) < BT_HIGH_TRAFFIC;
  622 }
  623 
  624 bool iwl_mvm_bt_coex_is_tpc_allowed(struct iwl_mvm *mvm,
  625                                     enum nl80211_band band)
  626 {
  627         u32 bt_activity = le32_to_cpu(mvm->last_bt_notif.bt_activity_grading);
  628 
  629         if (band != NL80211_BAND_2GHZ)
  630                 return false;
  631 
  632         return bt_activity >= BT_LOW_TRAFFIC;
  633 }
  634 
  635 u8 iwl_mvm_bt_coex_get_single_ant_msk(struct iwl_mvm *mvm, u8 enabled_ants)
  636 {
  637         if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_COEX_SCHEMA_2) &&
  638             (mvm->cfg->non_shared_ant & enabled_ants))
  639                 return mvm->cfg->non_shared_ant;
  640 
  641         return first_antenna(enabled_ants);
  642 }
  643 
  644 u8 iwl_mvm_bt_coex_tx_prio(struct iwl_mvm *mvm, struct ieee80211_hdr *hdr,
  645                            struct ieee80211_tx_info *info, u8 ac)
  646 {
  647         __le16 fc = hdr->frame_control;
  648         bool mplut_enabled = iwl_mvm_is_mplut_supported(mvm);
  649 
  650         if (info->band != NL80211_BAND_2GHZ)
  651                 return 0;
  652 
  653         if (unlikely(mvm->bt_tx_prio))
  654                 return mvm->bt_tx_prio - 1;
  655 
  656         if (likely(ieee80211_is_data(fc))) {
  657                 if (likely(ieee80211_is_data_qos(fc))) {
  658                         switch (ac) {
  659                         case IEEE80211_AC_BE:
  660                                 return mplut_enabled ? 1 : 0;
  661                         case IEEE80211_AC_VI:
  662                                 return mplut_enabled ? 2 : 3;
  663                         case IEEE80211_AC_VO:
  664                                 return 3;
  665                         default:
  666                                 return 0;
  667                         }
  668                 } else if (is_multicast_ether_addr(hdr->addr1)) {
  669                         return 3;
  670                 } else
  671                         return 0;
  672         } else if (ieee80211_is_mgmt(fc)) {
  673                 return ieee80211_is_disassoc(fc) ? 0 : 3;
  674         } else if (ieee80211_is_ctl(fc)) {
  675                 /* ignore cfend and cfendack frames as we never send those */
  676                 return 3;
  677         }
  678 
  679         return 0;
  680 }
  681 
  682 void iwl_mvm_bt_coex_vif_change(struct iwl_mvm *mvm)
  683 {
  684         iwl_mvm_bt_coex_notif_handle(mvm);
  685 }

Cache object: 4c3ce6af1da722b8088fb4cb2680b7b6


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.