0001
0002
0003
0004
0005
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
0033 if (vif == data->disabled_vif)
0034 return;
0035
0036 if (!mvmvif->phy_ctxt)
0037 return;
0038
0039
0040 id = mvmvif->phy_ctxt->id;
0041
0042
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
0149 if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status))
0150 return 0;
0151
0152
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
0161
0162
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
0185
0186
0187
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
0198
0199
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
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
0232
0233
0234
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
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
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
0284
0285
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 }