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/quota.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) 2012-2014, 2018, 2021 Intel Corporation
    4  * Copyright (C) 2013-2014 Intel Mobile Communications GmbH
    5  * Copyright (C) 2016-2017 Intel Deutschland GmbH
    6  */
    7 #include <net/mac80211.h>
    8 #include "fw-api.h"
    9 #include "mvm.h"
   10 
   11 #define QUOTA_100       IWL_MVM_MAX_QUOTA
   12 #define QUOTA_LOWLAT_MIN ((QUOTA_100 * IWL_MVM_LOWLAT_QUOTA_MIN_PERCENT) / 100)
   13 
   14 struct iwl_mvm_quota_iterator_data {
   15         int n_interfaces[MAX_BINDINGS];
   16         int colors[MAX_BINDINGS];
   17         int low_latency[MAX_BINDINGS];
   18 #ifdef CONFIG_IWLWIFI_DEBUGFS
   19         int dbgfs_min[MAX_BINDINGS];
   20 #endif
   21         int n_low_latency_bindings;
   22         struct ieee80211_vif *disabled_vif;
   23 };
   24 
   25 static void iwl_mvm_quota_iterator(void *_data, u8 *mac,
   26                                    struct ieee80211_vif *vif)
   27 {
   28         struct iwl_mvm_quota_iterator_data *data = _data;
   29         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
   30         u16 id;
   31 
   32         /* skip disabled interfaces here immediately */
   33         if (vif == data->disabled_vif)
   34                 return;
   35 
   36         if (!mvmvif->phy_ctxt)
   37                 return;
   38 
   39         /* currently, PHY ID == binding ID */
   40         id = mvmvif->phy_ctxt->id;
   41 
   42         /* need at least one binding per PHY */
   43         BUILD_BUG_ON(NUM_PHY_CTX > MAX_BINDINGS);
   44 
   45         if (WARN_ON_ONCE(id >= MAX_BINDINGS))
   46                 return;
   47 
   48         switch (vif->type) {
   49         case NL80211_IFTYPE_STATION:
   50                 if (vif->bss_conf.assoc)
   51                         break;
   52                 return;
   53         case NL80211_IFTYPE_AP:
   54         case NL80211_IFTYPE_ADHOC:
   55                 if (mvmvif->ap_ibss_active)
   56                         break;
   57                 return;
   58         case NL80211_IFTYPE_MONITOR:
   59                 if (mvmvif->monitor_active)
   60                         break;
   61                 return;
   62         case NL80211_IFTYPE_P2P_DEVICE:
   63                 return;
   64         default:
   65                 WARN_ON_ONCE(1);
   66                 return;
   67         }
   68 
   69         if (data->colors[id] < 0)
   70                 data->colors[id] = mvmvif->phy_ctxt->color;
   71         else
   72                 WARN_ON_ONCE(data->colors[id] != mvmvif->phy_ctxt->color);
   73 
   74         data->n_interfaces[id]++;
   75 
   76 #ifdef CONFIG_IWLWIFI_DEBUGFS
   77         if (mvmvif->dbgfs_quota_min)
   78                 data->dbgfs_min[id] = max(data->dbgfs_min[id],
   79                                           mvmvif->dbgfs_quota_min);
   80 #endif
   81 
   82         if (iwl_mvm_vif_low_latency(mvmvif) && !data->low_latency[id]) {
   83                 data->n_low_latency_bindings++;
   84                 data->low_latency[id] = true;
   85         }
   86 }
   87 
   88 static void iwl_mvm_adjust_quota_for_noa(struct iwl_mvm *mvm,
   89                                          struct iwl_time_quota_cmd *cmd)
   90 {
   91 #ifdef CONFIG_NL80211_TESTMODE
   92         struct iwl_mvm_vif *mvmvif;
   93         int i, phy_id = -1, beacon_int = 0;
   94 
   95         if (!mvm->noa_duration || !mvm->noa_vif)
   96                 return;
   97 
   98         mvmvif = iwl_mvm_vif_from_mac80211(mvm->noa_vif);
   99         if (!mvmvif->ap_ibss_active)
  100                 return;
  101 
  102         phy_id = mvmvif->phy_ctxt->id;
  103         beacon_int = mvm->noa_vif->bss_conf.beacon_int;
  104 
  105         for (i = 0; i < MAX_BINDINGS; i++) {
  106                 struct iwl_time_quota_data *data =
  107                                         iwl_mvm_quota_cmd_get_quota(mvm, cmd,
  108                                                                     i);
  109                 u32 id_n_c = le32_to_cpu(data->id_and_color);
  110                 u32 id = (id_n_c & FW_CTXT_ID_MSK) >> FW_CTXT_ID_POS;
  111                 u32 quota = le32_to_cpu(data->quota);
  112 
  113                 if (id != phy_id)
  114                         continue;
  115 
  116                 quota *= (beacon_int - mvm->noa_duration);
  117                 quota /= beacon_int;
  118 
  119                 IWL_DEBUG_QUOTA(mvm, "quota: adjust for NoA from %d to %d\n",
  120                                 le32_to_cpu(data->quota), quota);
  121 
  122                 data->quota = cpu_to_le32(quota);
  123         }
  124 #endif
  125 }
  126 
  127 int iwl_mvm_update_quotas(struct iwl_mvm *mvm,
  128                           bool force_update,
  129                           struct ieee80211_vif *disabled_vif)
  130 {
  131         struct iwl_time_quota_cmd cmd = {};
  132         int i, idx, err, num_active_macs, quota, quota_rem, n_non_lowlat;
  133         struct iwl_mvm_quota_iterator_data data = {
  134                 .n_interfaces = {},
  135                 .colors = { -1, -1, -1, -1 },
  136                 .disabled_vif = disabled_vif,
  137         };
  138         struct iwl_time_quota_cmd *last = &mvm->last_quota_cmd;
  139         struct iwl_time_quota_data *qdata, *last_data;
  140         bool send = false;
  141 
  142         lockdep_assert_held(&mvm->mutex);
  143 
  144         if (fw_has_capa(&mvm->fw->ucode_capa,
  145                         IWL_UCODE_TLV_CAPA_DYNAMIC_QUOTA))
  146                 return 0;
  147 
  148         /* update all upon completion */
  149         if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status))
  150                 return 0;
  151 
  152         /* iterator data above must match */
  153         BUILD_BUG_ON(MAX_BINDINGS != 4);
  154 
  155         ieee80211_iterate_active_interfaces_atomic(
  156                 mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
  157                 iwl_mvm_quota_iterator, &data);
  158 
  159         /*
  160          * The FW's scheduling session consists of
  161          * IWL_MVM_MAX_QUOTA fragments. Divide these fragments
  162          * equally between all the bindings that require quota
  163          */
  164         num_active_macs = 0;
  165         for (i = 0; i < MAX_BINDINGS; i++) {
  166                 qdata = iwl_mvm_quota_cmd_get_quota(mvm, &cmd, i);
  167                 qdata->id_and_color = cpu_to_le32(FW_CTXT_INVALID);
  168                 num_active_macs += data.n_interfaces[i];
  169         }
  170 
  171         n_non_lowlat = num_active_macs;
  172 
  173         if (data.n_low_latency_bindings == 1) {
  174                 for (i = 0; i < MAX_BINDINGS; i++) {
  175                         if (data.low_latency[i]) {
  176                                 n_non_lowlat -= data.n_interfaces[i];
  177                                 break;
  178                         }
  179                 }
  180         }
  181 
  182         if (data.n_low_latency_bindings == 1 && n_non_lowlat) {
  183                 /*
  184                  * Reserve quota for the low latency binding in case that
  185                  * there are several data bindings but only a single
  186                  * low latency one. Split the rest of the quota equally
  187                  * between the other data interfaces.
  188                  */
  189                 quota = (QUOTA_100 - QUOTA_LOWLAT_MIN) / n_non_lowlat;
  190                 quota_rem = QUOTA_100 - n_non_lowlat * quota -
  191                             QUOTA_LOWLAT_MIN;
  192                 IWL_DEBUG_QUOTA(mvm,
  193                                 "quota: low-latency binding active, remaining quota per other binding: %d\n",
  194                                 quota);
  195         } else if (num_active_macs) {
  196                 /*
  197                  * There are 0 or more than 1 low latency bindings, or all the
  198                  * data interfaces belong to the single low latency binding.
  199                  * Split the quota equally between the data interfaces.
  200                  */
  201                 quota = QUOTA_100 / num_active_macs;
  202                 quota_rem = QUOTA_100 % num_active_macs;
  203                 IWL_DEBUG_QUOTA(mvm,
  204                                 "quota: splitting evenly per binding: %d\n",
  205                                 quota);
  206         } else {
  207                 /* values don't really matter - won't be used */
  208                 quota = 0;
  209                 quota_rem = 0;
  210         }
  211 
  212         for (idx = 0, i = 0; i < MAX_BINDINGS; i++) {
  213                 if (data.colors[i] < 0)
  214                         continue;
  215 
  216                 qdata = iwl_mvm_quota_cmd_get_quota(mvm, &cmd, idx);
  217 
  218                 qdata->id_and_color =
  219                         cpu_to_le32(FW_CMD_ID_AND_COLOR(i, data.colors[i]));
  220 
  221                 if (data.n_interfaces[i] <= 0)
  222                         qdata->quota = cpu_to_le32(0);
  223 #ifdef CONFIG_IWLWIFI_DEBUGFS
  224                 else if (data.dbgfs_min[i])
  225                         qdata->quota =
  226                                 cpu_to_le32(data.dbgfs_min[i] * QUOTA_100 / 100);
  227 #endif
  228                 else if (data.n_low_latency_bindings == 1 && n_non_lowlat &&
  229                          data.low_latency[i])
  230                         /*
  231                          * There is more than one binding, but only one of the
  232                          * bindings is in low latency. For this case, allocate
  233                          * the minimal required quota for the low latency
  234                          * binding.
  235                          */
  236                         qdata->quota = cpu_to_le32(QUOTA_LOWLAT_MIN);
  237                 else
  238                         qdata->quota =
  239                                 cpu_to_le32(quota * data.n_interfaces[i]);
  240 
  241                 WARN_ONCE(le32_to_cpu(qdata->quota) > QUOTA_100,
  242                           "Binding=%d, quota=%u > max=%u\n",
  243                           idx, le32_to_cpu(qdata->quota), QUOTA_100);
  244 
  245                 qdata->max_duration = cpu_to_le32(0);
  246 
  247                 idx++;
  248         }
  249 
  250         /* Give the remainder of the session to the first data binding */
  251         for (i = 0; i < MAX_BINDINGS; i++) {
  252                 qdata = iwl_mvm_quota_cmd_get_quota(mvm, &cmd, i);
  253                 if (le32_to_cpu(qdata->quota) != 0) {
  254                         le32_add_cpu(&qdata->quota, quota_rem);
  255                         IWL_DEBUG_QUOTA(mvm,
  256                                         "quota: giving remainder of %d to binding %d\n",
  257                                         quota_rem, i);
  258                         break;
  259                 }
  260         }
  261 
  262         iwl_mvm_adjust_quota_for_noa(mvm, &cmd);
  263 
  264         /* check that we have non-zero quota for all valid bindings */
  265         for (i = 0; i < MAX_BINDINGS; i++) {
  266                 qdata = iwl_mvm_quota_cmd_get_quota(mvm, &cmd, i);
  267                 last_data = iwl_mvm_quota_cmd_get_quota(mvm, last, i);
  268                 if (qdata->id_and_color != last_data->id_and_color)
  269                         send = true;
  270                 if (qdata->max_duration != last_data->max_duration)
  271                         send = true;
  272                 if (abs((int)le32_to_cpu(qdata->quota) -
  273                         (int)le32_to_cpu(last_data->quota))
  274                                                 > IWL_MVM_QUOTA_THRESHOLD)
  275                         send = true;
  276                 if (qdata->id_and_color == cpu_to_le32(FW_CTXT_INVALID))
  277                         continue;
  278                 WARN_ONCE(qdata->quota == 0,
  279                           "zero quota on binding %d\n", i);
  280         }
  281 
  282         if (!send && !force_update) {
  283                 /* don't send a practically unchanged command, the firmware has
  284                  * to re-initialize a lot of state and that can have an adverse
  285                  * impact on it
  286                  */
  287                 return 0;
  288         }
  289 
  290         err = iwl_mvm_send_cmd_pdu(mvm, TIME_QUOTA_CMD, 0,
  291                                    iwl_mvm_quota_cmd_size(mvm), &cmd);
  292 
  293         if (err)
  294                 IWL_ERR(mvm, "Failed to send quota: %d\n", err);
  295         else
  296                 mvm->last_quota_cmd = cmd;
  297         return err;
  298 }

Cache object: ca9692bcdb049e1f1fef0735b5bd0fa4


[ 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.