diff options
Diffstat (limited to 'drivers/net/wireless/iwlwifi/mvm/quota.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/quota.c | 100 |
1 files changed, 79 insertions, 21 deletions
diff --git a/drivers/net/wireless/iwlwifi/mvm/quota.c b/drivers/net/wireless/iwlwifi/mvm/quota.c index ce5db6c4ef7e..35e86e06dffd 100644 --- a/drivers/net/wireless/iwlwifi/mvm/quota.c +++ b/drivers/net/wireless/iwlwifi/mvm/quota.c | |||
@@ -65,9 +65,14 @@ | |||
65 | #include "fw-api.h" | 65 | #include "fw-api.h" |
66 | #include "mvm.h" | 66 | #include "mvm.h" |
67 | 67 | ||
68 | #define QUOTA_100 IWL_MVM_MAX_QUOTA | ||
69 | #define QUOTA_LOWLAT_MIN ((QUOTA_100 * IWL_MVM_LOWLAT_QUOTA_MIN_PERCENT) / 100) | ||
70 | |||
68 | struct iwl_mvm_quota_iterator_data { | 71 | struct iwl_mvm_quota_iterator_data { |
69 | int n_interfaces[MAX_BINDINGS]; | 72 | int n_interfaces[MAX_BINDINGS]; |
70 | int colors[MAX_BINDINGS]; | 73 | int colors[MAX_BINDINGS]; |
74 | int low_latency[MAX_BINDINGS]; | ||
75 | int n_low_latency_bindings; | ||
71 | struct ieee80211_vif *new_vif; | 76 | struct ieee80211_vif *new_vif; |
72 | }; | 77 | }; |
73 | 78 | ||
@@ -107,22 +112,29 @@ static void iwl_mvm_quota_iterator(void *_data, u8 *mac, | |||
107 | switch (vif->type) { | 112 | switch (vif->type) { |
108 | case NL80211_IFTYPE_STATION: | 113 | case NL80211_IFTYPE_STATION: |
109 | if (vif->bss_conf.assoc) | 114 | if (vif->bss_conf.assoc) |
110 | data->n_interfaces[id]++; | 115 | break; |
111 | break; | 116 | return; |
112 | case NL80211_IFTYPE_AP: | 117 | case NL80211_IFTYPE_AP: |
113 | case NL80211_IFTYPE_ADHOC: | 118 | case NL80211_IFTYPE_ADHOC: |
114 | if (mvmvif->ap_ibss_active) | 119 | if (mvmvif->ap_ibss_active) |
115 | data->n_interfaces[id]++; | 120 | break; |
116 | break; | 121 | return; |
117 | case NL80211_IFTYPE_MONITOR: | 122 | case NL80211_IFTYPE_MONITOR: |
118 | if (mvmvif->monitor_active) | 123 | if (mvmvif->monitor_active) |
119 | data->n_interfaces[id]++; | 124 | break; |
120 | break; | 125 | return; |
121 | case NL80211_IFTYPE_P2P_DEVICE: | 126 | case NL80211_IFTYPE_P2P_DEVICE: |
122 | break; | 127 | return; |
123 | default: | 128 | default: |
124 | WARN_ON_ONCE(1); | 129 | WARN_ON_ONCE(1); |
125 | break; | 130 | return; |
131 | } | ||
132 | |||
133 | data->n_interfaces[id]++; | ||
134 | |||
135 | if (iwl_mvm_vif_low_latency(mvmvif) && !data->low_latency[id]) { | ||
136 | data->n_low_latency_bindings++; | ||
137 | data->low_latency[id] = true; | ||
126 | } | 138 | } |
127 | } | 139 | } |
128 | 140 | ||
@@ -162,7 +174,7 @@ static void iwl_mvm_adjust_quota_for_noa(struct iwl_mvm *mvm, | |||
162 | int iwl_mvm_update_quotas(struct iwl_mvm *mvm, struct ieee80211_vif *newvif) | 174 | int iwl_mvm_update_quotas(struct iwl_mvm *mvm, struct ieee80211_vif *newvif) |
163 | { | 175 | { |
164 | struct iwl_time_quota_cmd cmd = {}; | 176 | struct iwl_time_quota_cmd cmd = {}; |
165 | int i, idx, ret, num_active_macs, quota, quota_rem; | 177 | int i, idx, ret, num_active_macs, quota, quota_rem, n_non_lowlat; |
166 | struct iwl_mvm_quota_iterator_data data = { | 178 | struct iwl_mvm_quota_iterator_data data = { |
167 | .n_interfaces = {}, | 179 | .n_interfaces = {}, |
168 | .colors = { -1, -1, -1, -1 }, | 180 | .colors = { -1, -1, -1, -1 }, |
@@ -197,11 +209,39 @@ int iwl_mvm_update_quotas(struct iwl_mvm *mvm, struct ieee80211_vif *newvif) | |||
197 | num_active_macs += data.n_interfaces[i]; | 209 | num_active_macs += data.n_interfaces[i]; |
198 | } | 210 | } |
199 | 211 | ||
200 | quota = 0; | 212 | n_non_lowlat = num_active_macs; |
201 | quota_rem = 0; | 213 | |
202 | if (num_active_macs) { | 214 | if (data.n_low_latency_bindings == 1) { |
203 | quota = IWL_MVM_MAX_QUOTA / num_active_macs; | 215 | for (i = 0; i < MAX_BINDINGS; i++) { |
204 | quota_rem = IWL_MVM_MAX_QUOTA % num_active_macs; | 216 | if (data.low_latency[i]) { |
217 | n_non_lowlat -= data.n_interfaces[i]; | ||
218 | break; | ||
219 | } | ||
220 | } | ||
221 | } | ||
222 | |||
223 | if (data.n_low_latency_bindings == 1 && n_non_lowlat) { | ||
224 | /* | ||
225 | * Reserve quota for the low latency binding in case that | ||
226 | * there are several data bindings but only a single | ||
227 | * low latency one. Split the rest of the quota equally | ||
228 | * between the other data interfaces. | ||
229 | */ | ||
230 | quota = (QUOTA_100 - QUOTA_LOWLAT_MIN) / n_non_lowlat; | ||
231 | quota_rem = QUOTA_100 - n_non_lowlat * quota - | ||
232 | QUOTA_LOWLAT_MIN; | ||
233 | } else if (num_active_macs) { | ||
234 | /* | ||
235 | * There are 0 or more than 1 low latency bindings, or all the | ||
236 | * data interfaces belong to the single low latency binding. | ||
237 | * Split the quota equally between the data interfaces. | ||
238 | */ | ||
239 | quota = QUOTA_100 / num_active_macs; | ||
240 | quota_rem = QUOTA_100 % num_active_macs; | ||
241 | } else { | ||
242 | /* values don't really matter - won't be used */ | ||
243 | quota = 0; | ||
244 | quota_rem = 0; | ||
205 | } | 245 | } |
206 | 246 | ||
207 | for (idx = 0, i = 0; i < MAX_BINDINGS; i++) { | 247 | for (idx = 0, i = 0; i < MAX_BINDINGS; i++) { |
@@ -211,19 +251,37 @@ int iwl_mvm_update_quotas(struct iwl_mvm *mvm, struct ieee80211_vif *newvif) | |||
211 | cmd.quotas[idx].id_and_color = | 251 | cmd.quotas[idx].id_and_color = |
212 | cpu_to_le32(FW_CMD_ID_AND_COLOR(i, data.colors[i])); | 252 | cpu_to_le32(FW_CMD_ID_AND_COLOR(i, data.colors[i])); |
213 | 253 | ||
214 | if (data.n_interfaces[i] <= 0) { | 254 | if (data.n_interfaces[i] <= 0) |
215 | cmd.quotas[idx].quota = cpu_to_le32(0); | 255 | cmd.quotas[idx].quota = cpu_to_le32(0); |
216 | cmd.quotas[idx].max_duration = cpu_to_le32(0); | 256 | else if (data.n_low_latency_bindings == 1 && n_non_lowlat && |
217 | } else { | 257 | data.low_latency[i]) |
258 | /* | ||
259 | * There is more than one binding, but only one of the | ||
260 | * bindings is in low latency. For this case, allocate | ||
261 | * the minimal required quota for the low latency | ||
262 | * binding. | ||
263 | */ | ||
264 | cmd.quotas[idx].quota = cpu_to_le32(QUOTA_LOWLAT_MIN); | ||
265 | else | ||
218 | cmd.quotas[idx].quota = | 266 | cmd.quotas[idx].quota = |
219 | cpu_to_le32(quota * data.n_interfaces[i]); | 267 | cpu_to_le32(quota * data.n_interfaces[i]); |
220 | cmd.quotas[idx].max_duration = cpu_to_le32(0); | 268 | |
221 | } | 269 | WARN_ONCE(le32_to_cpu(cmd.quotas[idx].quota) > QUOTA_100, |
270 | "Binding=%d, quota=%u > max=%u\n", | ||
271 | idx, le32_to_cpu(cmd.quotas[idx].quota), QUOTA_100); | ||
272 | |||
273 | cmd.quotas[idx].max_duration = cpu_to_le32(0); | ||
274 | |||
222 | idx++; | 275 | idx++; |
223 | } | 276 | } |
224 | 277 | ||
225 | /* Give the remainder of the session to the first binding */ | 278 | /* Give the remainder of the session to the first data binding */ |
226 | le32_add_cpu(&cmd.quotas[0].quota, quota_rem); | 279 | for (i = 0; i < MAX_BINDINGS; i++) { |
280 | if (le32_to_cpu(cmd.quotas[i].quota) != 0) { | ||
281 | le32_add_cpu(&cmd.quotas[i].quota, quota_rem); | ||
282 | break; | ||
283 | } | ||
284 | } | ||
227 | 285 | ||
228 | iwl_mvm_adjust_quota_for_noa(mvm, &cmd); | 286 | iwl_mvm_adjust_quota_for_noa(mvm, &cmd); |
229 | 287 | ||