1 /****************************************************************************** 2 * 3 * This file is provided under a dual BSD/GPLv2 license. When using or 4 * redistributing this file, you may do so under either license. 5 * 6 * GPL LICENSE SUMMARY 7 * 8 * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. 9 * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH 10 * Copyright(c) 2016 - 2017 Intel Deutschland GmbH 11 * 12 * This program is free software; you can redistribute it and/or modify 13 * it under the terms of version 2 of the GNU General Public License as 14 * published by the Free Software Foundation. 15 * 16 * This program is distributed in the hope that it will be useful, but 17 * WITHOUT ANY WARRANTY; without even the implied warranty of 18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19 * General Public License for more details. 20 * 21 * The full GNU General Public License is included in this distribution 22 * in the file called COPYING. 23 * 24 * Contact Information: 25 * Intel Linux Wireless <linuxwifi@intel.com> 26 * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 27 * 28 * BSD LICENSE 29 * 30 * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. 31 * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH 32 * Copyright(c) 2016 - 2017 Intel Deutschland GmbH 33 * All rights reserved. 34 * 35 * Redistribution and use in source and binary forms, with or without 36 * modification, are permitted provided that the following conditions 37 * are met: 38 * 39 * * Redistributions of source code must retain the above copyright 40 * notice, this list of conditions and the following disclaimer. 41 * * Redistributions in binary form must reproduce the above copyright 42 * notice, this list of conditions and the following disclaimer in 43 * the documentation and/or other materials provided with the 44 * distribution. 45 * * Neither the name Intel Corporation nor the names of its 46 * contributors may be used to endorse or promote products derived 47 * from this software without specific prior written permission. 48 * 49 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 50 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 51 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 52 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 53 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 54 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 55 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 56 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 57 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 58 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 59 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 60 * 61 *****************************************************************************/ 62 63 #include <net/mac80211.h> 64 #include "fw-api.h" 65 #include "mvm.h" 66 67 #define QUOTA_100 IWL_MVM_MAX_QUOTA 68 #define QUOTA_LOWLAT_MIN ((QUOTA_100 * IWL_MVM_LOWLAT_QUOTA_MIN_PERCENT) / 100) 69 70 struct iwl_mvm_quota_iterator_data { 71 int n_interfaces[MAX_BINDINGS]; 72 int colors[MAX_BINDINGS]; 73 int low_latency[MAX_BINDINGS]; 74 #ifdef CONFIG_IWLWIFI_DEBUGFS 75 int dbgfs_min[MAX_BINDINGS]; 76 #endif 77 int n_low_latency_bindings; 78 struct ieee80211_vif *disabled_vif; 79 }; 80 81 static void iwl_mvm_quota_iterator(void *_data, u8 *mac, 82 struct ieee80211_vif *vif) 83 { 84 struct iwl_mvm_quota_iterator_data *data = _data; 85 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 86 u16 id; 87 88 /* skip disabled interfaces here immediately */ 89 if (vif == data->disabled_vif) 90 return; 91 92 if (!mvmvif->phy_ctxt) 93 return; 94 95 /* currently, PHY ID == binding ID */ 96 id = mvmvif->phy_ctxt->id; 97 98 /* need at least one binding per PHY */ 99 BUILD_BUG_ON(NUM_PHY_CTX > MAX_BINDINGS); 100 101 if (WARN_ON_ONCE(id >= MAX_BINDINGS)) 102 return; 103 104 switch (vif->type) { 105 case NL80211_IFTYPE_STATION: 106 if (vif->bss_conf.assoc) 107 break; 108 return; 109 case NL80211_IFTYPE_AP: 110 case NL80211_IFTYPE_ADHOC: 111 if (mvmvif->ap_ibss_active) 112 break; 113 return; 114 case NL80211_IFTYPE_MONITOR: 115 if (mvmvif->monitor_active) 116 break; 117 return; 118 case NL80211_IFTYPE_P2P_DEVICE: 119 return; 120 default: 121 WARN_ON_ONCE(1); 122 return; 123 } 124 125 if (data->colors[id] < 0) 126 data->colors[id] = mvmvif->phy_ctxt->color; 127 else 128 WARN_ON_ONCE(data->colors[id] != mvmvif->phy_ctxt->color); 129 130 data->n_interfaces[id]++; 131 132 #ifdef CONFIG_IWLWIFI_DEBUGFS 133 if (mvmvif->dbgfs_quota_min) 134 data->dbgfs_min[id] = max(data->dbgfs_min[id], 135 mvmvif->dbgfs_quota_min); 136 #endif 137 138 if (iwl_mvm_vif_low_latency(mvmvif) && !data->low_latency[id]) { 139 data->n_low_latency_bindings++; 140 data->low_latency[id] = true; 141 } 142 } 143 144 static void iwl_mvm_adjust_quota_for_noa(struct iwl_mvm *mvm, 145 struct iwl_time_quota_cmd *cmd) 146 { 147 #ifdef CONFIG_NL80211_TESTMODE 148 struct iwl_mvm_vif *mvmvif; 149 int i, phy_id = -1, beacon_int = 0; 150 151 if (!mvm->noa_duration || !mvm->noa_vif) 152 return; 153 154 mvmvif = iwl_mvm_vif_from_mac80211(mvm->noa_vif); 155 if (!mvmvif->ap_ibss_active) 156 return; 157 158 phy_id = mvmvif->phy_ctxt->id; 159 beacon_int = mvm->noa_vif->bss_conf.beacon_int; 160 161 for (i = 0; i < MAX_BINDINGS; i++) { 162 struct iwl_time_quota_data *data = 163 iwl_mvm_quota_cmd_get_quota(mvm, cmd, 164 i); 165 u32 id_n_c = le32_to_cpu(data->id_and_color); 166 u32 id = (id_n_c & FW_CTXT_ID_MSK) >> FW_CTXT_ID_POS; 167 u32 quota = le32_to_cpu(data->quota); 168 169 if (id != phy_id) 170 continue; 171 172 quota *= (beacon_int - mvm->noa_duration); 173 quota /= beacon_int; 174 175 IWL_DEBUG_QUOTA(mvm, "quota: adjust for NoA from %d to %d\n", 176 le32_to_cpu(data->quota), quota); 177 178 data->quota = cpu_to_le32(quota); 179 } 180 #endif 181 } 182 183 int iwl_mvm_update_quotas(struct iwl_mvm *mvm, 184 bool force_update, 185 struct ieee80211_vif *disabled_vif) 186 { 187 struct iwl_time_quota_cmd cmd = {}; 188 int i, idx, err, num_active_macs, quota, quota_rem, n_non_lowlat; 189 struct iwl_mvm_quota_iterator_data data = { 190 .n_interfaces = {}, 191 .colors = { -1, -1, -1, -1 }, 192 .disabled_vif = disabled_vif, 193 }; 194 struct iwl_time_quota_cmd *last = &mvm->last_quota_cmd; 195 struct iwl_time_quota_data *qdata, *last_data; 196 bool send = false; 197 198 lockdep_assert_held(&mvm->mutex); 199 200 if (fw_has_capa(&mvm->fw->ucode_capa, 201 IWL_UCODE_TLV_CAPA_DYNAMIC_QUOTA)) 202 return 0; 203 204 /* update all upon completion */ 205 if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) 206 return 0; 207 208 /* iterator data above must match */ 209 BUILD_BUG_ON(MAX_BINDINGS != 4); 210 211 ieee80211_iterate_active_interfaces_atomic( 212 mvm->hw, IEEE80211_IFACE_ITER_NORMAL, 213 iwl_mvm_quota_iterator, &data); 214 215 /* 216 * The FW's scheduling session consists of 217 * IWL_MVM_MAX_QUOTA fragments. Divide these fragments 218 * equally between all the bindings that require quota 219 */ 220 num_active_macs = 0; 221 for (i = 0; i < MAX_BINDINGS; i++) { 222 qdata = iwl_mvm_quota_cmd_get_quota(mvm, &cmd, i); 223 qdata->id_and_color = cpu_to_le32(FW_CTXT_INVALID); 224 num_active_macs += data.n_interfaces[i]; 225 } 226 227 n_non_lowlat = num_active_macs; 228 229 if (data.n_low_latency_bindings == 1) { 230 for (i = 0; i < MAX_BINDINGS; i++) { 231 if (data.low_latency[i]) { 232 n_non_lowlat -= data.n_interfaces[i]; 233 break; 234 } 235 } 236 } 237 238 if (data.n_low_latency_bindings == 1 && n_non_lowlat) { 239 /* 240 * Reserve quota for the low latency binding in case that 241 * there are several data bindings but only a single 242 * low latency one. Split the rest of the quota equally 243 * between the other data interfaces. 244 */ 245 quota = (QUOTA_100 - QUOTA_LOWLAT_MIN) / n_non_lowlat; 246 quota_rem = QUOTA_100 - n_non_lowlat * quota - 247 QUOTA_LOWLAT_MIN; 248 IWL_DEBUG_QUOTA(mvm, 249 "quota: low-latency binding active, remaining quota per other binding: %d\n", 250 quota); 251 } else if (num_active_macs) { 252 /* 253 * There are 0 or more than 1 low latency bindings, or all the 254 * data interfaces belong to the single low latency binding. 255 * Split the quota equally between the data interfaces. 256 */ 257 quota = QUOTA_100 / num_active_macs; 258 quota_rem = QUOTA_100 % num_active_macs; 259 IWL_DEBUG_QUOTA(mvm, 260 "quota: splitting evenly per binding: %d\n", 261 quota); 262 } else { 263 /* values don't really matter - won't be used */ 264 quota = 0; 265 quota_rem = 0; 266 } 267 268 for (idx = 0, i = 0; i < MAX_BINDINGS; i++) { 269 if (data.colors[i] < 0) 270 continue; 271 272 qdata = iwl_mvm_quota_cmd_get_quota(mvm, &cmd, idx); 273 274 qdata->id_and_color = 275 cpu_to_le32(FW_CMD_ID_AND_COLOR(i, data.colors[i])); 276 277 if (data.n_interfaces[i] <= 0) 278 qdata->quota = cpu_to_le32(0); 279 #ifdef CONFIG_IWLWIFI_DEBUGFS 280 else if (data.dbgfs_min[i]) 281 qdata->quota = 282 cpu_to_le32(data.dbgfs_min[i] * QUOTA_100 / 100); 283 #endif 284 else if (data.n_low_latency_bindings == 1 && n_non_lowlat && 285 data.low_latency[i]) 286 /* 287 * There is more than one binding, but only one of the 288 * bindings is in low latency. For this case, allocate 289 * the minimal required quota for the low latency 290 * binding. 291 */ 292 qdata->quota = cpu_to_le32(QUOTA_LOWLAT_MIN); 293 else 294 qdata->quota = 295 cpu_to_le32(quota * data.n_interfaces[i]); 296 297 WARN_ONCE(le32_to_cpu(qdata->quota) > QUOTA_100, 298 "Binding=%d, quota=%u > max=%u\n", 299 idx, le32_to_cpu(qdata->quota), QUOTA_100); 300 301 qdata->max_duration = cpu_to_le32(0); 302 303 idx++; 304 } 305 306 /* Give the remainder of the session to the first data binding */ 307 for (i = 0; i < MAX_BINDINGS; i++) { 308 qdata = iwl_mvm_quota_cmd_get_quota(mvm, &cmd, i); 309 if (le32_to_cpu(qdata->quota) != 0) { 310 le32_add_cpu(&qdata->quota, quota_rem); 311 IWL_DEBUG_QUOTA(mvm, 312 "quota: giving remainder of %d to binding %d\n", 313 quota_rem, i); 314 break; 315 } 316 } 317 318 iwl_mvm_adjust_quota_for_noa(mvm, &cmd); 319 320 /* check that we have non-zero quota for all valid bindings */ 321 for (i = 0; i < MAX_BINDINGS; i++) { 322 qdata = iwl_mvm_quota_cmd_get_quota(mvm, &cmd, i); 323 last_data = iwl_mvm_quota_cmd_get_quota(mvm, last, i); 324 if (qdata->id_and_color != last_data->id_and_color) 325 send = true; 326 if (qdata->max_duration != last_data->max_duration) 327 send = true; 328 if (abs((int)le32_to_cpu(qdata->quota) - 329 (int)le32_to_cpu(last_data->quota)) 330 > IWL_MVM_QUOTA_THRESHOLD) 331 send = true; 332 if (qdata->id_and_color == cpu_to_le32(FW_CTXT_INVALID)) 333 continue; 334 WARN_ONCE(qdata->quota == 0, 335 "zero quota on binding %d\n", i); 336 } 337 338 if (!send && !force_update) { 339 /* don't send a practically unchanged command, the firmware has 340 * to re-initialize a lot of state and that can have an adverse 341 * impact on it 342 */ 343 return 0; 344 } 345 346 err = iwl_mvm_send_cmd_pdu(mvm, TIME_QUOTA_CMD, 0, 347 iwl_mvm_quota_cmd_size(mvm), &cmd); 348 349 if (err) 350 IWL_ERR(mvm, "Failed to send quota: %d\n", err); 351 else 352 mvm->last_quota_cmd = cmd; 353 return err; 354 } 355