Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
0002 /*
0003  * Copyright (C) 2012-2014, 2018, 2021-2022 Intel Corporation
0004  * Copyright (C) 2013-2014 Intel Mobile Communications GmbH
0005  * Copyright (C) 2016-2017 Intel Deutschland GmbH
0006  */
0007 #include <net/mac80211.h>
0008 #include "fw-api.h"
0009 #include "mvm.h"
0010 
0011 #define QUOTA_100   IWL_MVM_MAX_QUOTA
0012 #define QUOTA_LOWLAT_MIN ((QUOTA_100 * IWL_MVM_LOWLAT_QUOTA_MIN_PERCENT) / 100)
0013 
0014 struct iwl_mvm_quota_iterator_data {
0015     int n_interfaces[MAX_BINDINGS];
0016     int colors[MAX_BINDINGS];
0017     int low_latency[MAX_BINDINGS];
0018 #ifdef CONFIG_IWLWIFI_DEBUGFS
0019     int dbgfs_min[MAX_BINDINGS];
0020 #endif
0021     int n_low_latency_bindings;
0022     struct ieee80211_vif *disabled_vif;
0023 };
0024 
0025 static void iwl_mvm_quota_iterator(void *_data, u8 *mac,
0026                    struct ieee80211_vif *vif)
0027 {
0028     struct iwl_mvm_quota_iterator_data *data = _data;
0029     struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
0030     u16 id;
0031 
0032     /* skip disabled interfaces here immediately */
0033     if (vif == data->disabled_vif)
0034         return;
0035 
0036     if (!mvmvif->phy_ctxt)
0037         return;
0038 
0039     /* currently, PHY ID == binding ID */
0040     id = mvmvif->phy_ctxt->id;
0041 
0042     /* need at least one binding per PHY */
0043     BUILD_BUG_ON(NUM_PHY_CTX > MAX_BINDINGS);
0044 
0045     if (WARN_ON_ONCE(id >= MAX_BINDINGS))
0046         return;
0047 
0048     switch (vif->type) {
0049     case NL80211_IFTYPE_STATION:
0050         if (vif->cfg.assoc)
0051             break;
0052         return;
0053     case NL80211_IFTYPE_AP:
0054     case NL80211_IFTYPE_ADHOC:
0055         if (mvmvif->ap_ibss_active)
0056             break;
0057         return;
0058     case NL80211_IFTYPE_MONITOR:
0059         if (mvmvif->monitor_active)
0060             break;
0061         return;
0062     case NL80211_IFTYPE_P2P_DEVICE:
0063         return;
0064     default:
0065         WARN_ON_ONCE(1);
0066         return;
0067     }
0068 
0069     if (data->colors[id] < 0)
0070         data->colors[id] = mvmvif->phy_ctxt->color;
0071     else
0072         WARN_ON_ONCE(data->colors[id] != mvmvif->phy_ctxt->color);
0073 
0074     data->n_interfaces[id]++;
0075 
0076 #ifdef CONFIG_IWLWIFI_DEBUGFS
0077     if (mvmvif->dbgfs_quota_min)
0078         data->dbgfs_min[id] = max(data->dbgfs_min[id],
0079                       mvmvif->dbgfs_quota_min);
0080 #endif
0081 
0082     if (iwl_mvm_vif_low_latency(mvmvif) && !data->low_latency[id]) {
0083         data->n_low_latency_bindings++;
0084         data->low_latency[id] = true;
0085     }
0086 }
0087 
0088 static void iwl_mvm_adjust_quota_for_noa(struct iwl_mvm *mvm,
0089                      struct iwl_time_quota_cmd *cmd)
0090 {
0091 #ifdef CONFIG_NL80211_TESTMODE
0092     struct iwl_mvm_vif *mvmvif;
0093     int i, phy_id = -1, beacon_int = 0;
0094 
0095     if (!mvm->noa_duration || !mvm->noa_vif)
0096         return;
0097 
0098     mvmvif = iwl_mvm_vif_from_mac80211(mvm->noa_vif);
0099     if (!mvmvif->ap_ibss_active)
0100         return;
0101 
0102     phy_id = mvmvif->phy_ctxt->id;
0103     beacon_int = mvm->noa_vif->bss_conf.beacon_int;
0104 
0105     for (i = 0; i < MAX_BINDINGS; i++) {
0106         struct iwl_time_quota_data *data =
0107                     iwl_mvm_quota_cmd_get_quota(mvm, cmd,
0108                                     i);
0109         u32 id_n_c = le32_to_cpu(data->id_and_color);
0110         u32 id = (id_n_c & FW_CTXT_ID_MSK) >> FW_CTXT_ID_POS;
0111         u32 quota = le32_to_cpu(data->quota);
0112 
0113         if (id != phy_id)
0114             continue;
0115 
0116         quota *= (beacon_int - mvm->noa_duration);
0117         quota /= beacon_int;
0118 
0119         IWL_DEBUG_QUOTA(mvm, "quota: adjust for NoA from %d to %d\n",
0120                 le32_to_cpu(data->quota), quota);
0121 
0122         data->quota = cpu_to_le32(quota);
0123     }
0124 #endif
0125 }
0126 
0127 int iwl_mvm_update_quotas(struct iwl_mvm *mvm,
0128               bool force_update,
0129               struct ieee80211_vif *disabled_vif)
0130 {
0131     struct iwl_time_quota_cmd cmd = {};
0132     int i, idx, err, num_active_macs, quota, quota_rem, n_non_lowlat;
0133     struct iwl_mvm_quota_iterator_data data = {
0134         .n_interfaces = {},
0135         .colors = { -1, -1, -1, -1 },
0136         .disabled_vif = disabled_vif,
0137     };
0138     struct iwl_time_quota_cmd *last = &mvm->last_quota_cmd;
0139     struct iwl_time_quota_data *qdata, *last_data;
0140     bool send = false;
0141 
0142     lockdep_assert_held(&mvm->mutex);
0143 
0144     if (fw_has_capa(&mvm->fw->ucode_capa,
0145             IWL_UCODE_TLV_CAPA_DYNAMIC_QUOTA))
0146         return 0;
0147 
0148     /* update all upon completion */
0149     if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status))
0150         return 0;
0151 
0152     /* iterator data above must match */
0153     BUILD_BUG_ON(MAX_BINDINGS != 4);
0154 
0155     ieee80211_iterate_active_interfaces_atomic(
0156         mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
0157         iwl_mvm_quota_iterator, &data);
0158 
0159     /*
0160      * The FW's scheduling session consists of
0161      * IWL_MVM_MAX_QUOTA fragments. Divide these fragments
0162      * equally between all the bindings that require quota
0163      */
0164     num_active_macs = 0;
0165     for (i = 0; i < MAX_BINDINGS; i++) {
0166         qdata = iwl_mvm_quota_cmd_get_quota(mvm, &cmd, i);
0167         qdata->id_and_color = cpu_to_le32(FW_CTXT_INVALID);
0168         num_active_macs += data.n_interfaces[i];
0169     }
0170 
0171     n_non_lowlat = num_active_macs;
0172 
0173     if (data.n_low_latency_bindings == 1) {
0174         for (i = 0; i < MAX_BINDINGS; i++) {
0175             if (data.low_latency[i]) {
0176                 n_non_lowlat -= data.n_interfaces[i];
0177                 break;
0178             }
0179         }
0180     }
0181 
0182     if (data.n_low_latency_bindings == 1 && n_non_lowlat) {
0183         /*
0184          * Reserve quota for the low latency binding in case that
0185          * there are several data bindings but only a single
0186          * low latency one. Split the rest of the quota equally
0187          * between the other data interfaces.
0188          */
0189         quota = (QUOTA_100 - QUOTA_LOWLAT_MIN) / n_non_lowlat;
0190         quota_rem = QUOTA_100 - n_non_lowlat * quota -
0191                 QUOTA_LOWLAT_MIN;
0192         IWL_DEBUG_QUOTA(mvm,
0193                 "quota: low-latency binding active, remaining quota per other binding: %d\n",
0194                 quota);
0195     } else if (num_active_macs) {
0196         /*
0197          * There are 0 or more than 1 low latency bindings, or all the
0198          * data interfaces belong to the single low latency binding.
0199          * Split the quota equally between the data interfaces.
0200          */
0201         quota = QUOTA_100 / num_active_macs;
0202         quota_rem = QUOTA_100 % num_active_macs;
0203         IWL_DEBUG_QUOTA(mvm,
0204                 "quota: splitting evenly per binding: %d\n",
0205                 quota);
0206     } else {
0207         /* values don't really matter - won't be used */
0208         quota = 0;
0209         quota_rem = 0;
0210     }
0211 
0212     for (idx = 0, i = 0; i < MAX_BINDINGS; i++) {
0213         if (data.colors[i] < 0)
0214             continue;
0215 
0216         qdata = iwl_mvm_quota_cmd_get_quota(mvm, &cmd, idx);
0217 
0218         qdata->id_and_color =
0219             cpu_to_le32(FW_CMD_ID_AND_COLOR(i, data.colors[i]));
0220 
0221         if (data.n_interfaces[i] <= 0)
0222             qdata->quota = cpu_to_le32(0);
0223 #ifdef CONFIG_IWLWIFI_DEBUGFS
0224         else if (data.dbgfs_min[i])
0225             qdata->quota =
0226                 cpu_to_le32(data.dbgfs_min[i] * QUOTA_100 / 100);
0227 #endif
0228         else if (data.n_low_latency_bindings == 1 && n_non_lowlat &&
0229              data.low_latency[i])
0230             /*
0231              * There is more than one binding, but only one of the
0232              * bindings is in low latency. For this case, allocate
0233              * the minimal required quota for the low latency
0234              * binding.
0235              */
0236             qdata->quota = cpu_to_le32(QUOTA_LOWLAT_MIN);
0237         else
0238             qdata->quota =
0239                 cpu_to_le32(quota * data.n_interfaces[i]);
0240 
0241         WARN_ONCE(le32_to_cpu(qdata->quota) > QUOTA_100,
0242               "Binding=%d, quota=%u > max=%u\n",
0243               idx, le32_to_cpu(qdata->quota), QUOTA_100);
0244 
0245         qdata->max_duration = cpu_to_le32(0);
0246 
0247         idx++;
0248     }
0249 
0250     /* Give the remainder of the session to the first data binding */
0251     for (i = 0; i < MAX_BINDINGS; i++) {
0252         qdata = iwl_mvm_quota_cmd_get_quota(mvm, &cmd, i);
0253         if (le32_to_cpu(qdata->quota) != 0) {
0254             le32_add_cpu(&qdata->quota, quota_rem);
0255             IWL_DEBUG_QUOTA(mvm,
0256                     "quota: giving remainder of %d to binding %d\n",
0257                     quota_rem, i);
0258             break;
0259         }
0260     }
0261 
0262     iwl_mvm_adjust_quota_for_noa(mvm, &cmd);
0263 
0264     /* check that we have non-zero quota for all valid bindings */
0265     for (i = 0; i < MAX_BINDINGS; i++) {
0266         qdata = iwl_mvm_quota_cmd_get_quota(mvm, &cmd, i);
0267         last_data = iwl_mvm_quota_cmd_get_quota(mvm, last, i);
0268         if (qdata->id_and_color != last_data->id_and_color)
0269             send = true;
0270         if (qdata->max_duration != last_data->max_duration)
0271             send = true;
0272         if (abs((int)le32_to_cpu(qdata->quota) -
0273             (int)le32_to_cpu(last_data->quota))
0274                         > IWL_MVM_QUOTA_THRESHOLD)
0275             send = true;
0276         if (qdata->id_and_color == cpu_to_le32(FW_CTXT_INVALID))
0277             continue;
0278         WARN_ONCE(qdata->quota == 0,
0279               "zero quota on binding %d\n", i);
0280     }
0281 
0282     if (!send && !force_update) {
0283         /* don't send a practically unchanged command, the firmware has
0284          * to re-initialize a lot of state and that can have an adverse
0285          * impact on it
0286          */
0287         return 0;
0288     }
0289 
0290     err = iwl_mvm_send_cmd_pdu(mvm, TIME_QUOTA_CMD, 0,
0291                    iwl_mvm_quota_cmd_size(mvm), &cmd);
0292 
0293     if (err)
0294         IWL_ERR(mvm, "Failed to send quota: %d\n", err);
0295     else
0296         mvm->last_quota_cmd = cmd;
0297     return err;
0298 }