]>
Commit | Line | Data |
---|---|---|
8ca151b5 JB |
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 | * | |
51368bf7 | 8 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. |
8ca151b5 JB |
9 | * |
10 | * This program is free software; you can redistribute it and/or modify | |
11 | * it under the terms of version 2 of the GNU General Public License as | |
12 | * published by the Free Software Foundation. | |
13 | * | |
14 | * This program is distributed in the hope that it will be useful, but | |
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
17 | * General Public License for more details. | |
18 | * | |
19 | * You should have received a copy of the GNU General Public License | |
20 | * along with this program; if not, write to the Free Software | |
21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, | |
22 | * USA | |
23 | * | |
24 | * The full GNU General Public License is included in this distribution | |
410dc5aa | 25 | * in the file called COPYING. |
8ca151b5 JB |
26 | * |
27 | * Contact Information: | |
28 | * Intel Linux Wireless <ilw@linux.intel.com> | |
29 | * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | |
30 | * | |
31 | * BSD LICENSE | |
32 | * | |
51368bf7 | 33 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. |
8ca151b5 JB |
34 | * All rights reserved. |
35 | * | |
36 | * Redistribution and use in source and binary forms, with or without | |
37 | * modification, are permitted provided that the following conditions | |
38 | * are met: | |
39 | * | |
40 | * * Redistributions of source code must retain the above copyright | |
41 | * notice, this list of conditions and the following disclaimer. | |
42 | * * Redistributions in binary form must reproduce the above copyright | |
43 | * notice, this list of conditions and the following disclaimer in | |
44 | * the documentation and/or other materials provided with the | |
45 | * distribution. | |
46 | * * Neither the name Intel Corporation nor the names of its | |
47 | * contributors may be used to endorse or promote products derived | |
48 | * from this software without specific prior written permission. | |
49 | * | |
50 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
51 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
52 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
53 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
54 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
55 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
56 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
57 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
58 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
59 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
60 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
61 | * | |
62 | *****************************************************************************/ | |
63 | ||
64 | #include <net/mac80211.h> | |
65 | #include "fw-api.h" | |
66 | #include "mvm.h" | |
67 | ||
6ca40d6e JB |
68 | #define QUOTA_100 IWL_MVM_MAX_QUOTA |
69 | #define QUOTA_LOWLAT_MIN ((QUOTA_100 * IWL_MVM_LOWLAT_QUOTA_MIN_PERCENT) / 100) | |
70 | ||
8ca151b5 JB |
71 | struct iwl_mvm_quota_iterator_data { |
72 | int n_interfaces[MAX_BINDINGS]; | |
73 | int colors[MAX_BINDINGS]; | |
6ca40d6e JB |
74 | int low_latency[MAX_BINDINGS]; |
75 | int n_low_latency_bindings; | |
8ca151b5 JB |
76 | struct ieee80211_vif *new_vif; |
77 | }; | |
78 | ||
79 | static void iwl_mvm_quota_iterator(void *_data, u8 *mac, | |
80 | struct ieee80211_vif *vif) | |
81 | { | |
82 | struct iwl_mvm_quota_iterator_data *data = _data; | |
83 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | |
84 | u16 id; | |
85 | ||
86 | /* | |
87 | * We'll account for the new interface (if any) below, | |
88 | * skip it here in case we're not called from within | |
89 | * the add_interface callback (otherwise it won't show | |
90 | * up in iteration) | |
91 | */ | |
92 | if (vif == data->new_vif) | |
93 | return; | |
94 | ||
95 | if (!mvmvif->phy_ctxt) | |
96 | return; | |
97 | ||
98 | /* currently, PHY ID == binding ID */ | |
99 | id = mvmvif->phy_ctxt->id; | |
100 | ||
101 | /* need at least one binding per PHY */ | |
102 | BUILD_BUG_ON(NUM_PHY_CTX > MAX_BINDINGS); | |
103 | ||
104 | if (WARN_ON_ONCE(id >= MAX_BINDINGS)) | |
105 | return; | |
106 | ||
107 | if (data->colors[id] < 0) | |
108 | data->colors[id] = mvmvif->phy_ctxt->color; | |
109 | else | |
110 | WARN_ON_ONCE(data->colors[id] != mvmvif->phy_ctxt->color); | |
111 | ||
112 | switch (vif->type) { | |
113 | case NL80211_IFTYPE_STATION: | |
114 | if (vif->bss_conf.assoc) | |
6ca40d6e JB |
115 | break; |
116 | return; | |
8ca151b5 | 117 | case NL80211_IFTYPE_AP: |
5023d966 JB |
118 | case NL80211_IFTYPE_ADHOC: |
119 | if (mvmvif->ap_ibss_active) | |
6ca40d6e JB |
120 | break; |
121 | return; | |
8ca151b5 | 122 | case NL80211_IFTYPE_MONITOR: |
1e1391ca | 123 | if (mvmvif->monitor_active) |
6ca40d6e JB |
124 | break; |
125 | return; | |
8ca151b5 | 126 | case NL80211_IFTYPE_P2P_DEVICE: |
6ca40d6e | 127 | return; |
8ca151b5 JB |
128 | default: |
129 | WARN_ON_ONCE(1); | |
6ca40d6e JB |
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; | |
8ca151b5 JB |
138 | } |
139 | } | |
140 | ||
507cadf2 DS |
141 | static void iwl_mvm_adjust_quota_for_noa(struct iwl_mvm *mvm, |
142 | struct iwl_time_quota_cmd *cmd) | |
143 | { | |
144 | #ifdef CONFIG_NL80211_TESTMODE | |
145 | struct iwl_mvm_vif *mvmvif; | |
146 | int i, phy_id = -1, beacon_int = 0; | |
147 | ||
148 | if (!mvm->noa_duration || !mvm->noa_vif) | |
149 | return; | |
150 | ||
151 | mvmvif = iwl_mvm_vif_from_mac80211(mvm->noa_vif); | |
5023d966 | 152 | if (!mvmvif->ap_ibss_active) |
507cadf2 DS |
153 | return; |
154 | ||
155 | phy_id = mvmvif->phy_ctxt->id; | |
156 | beacon_int = mvm->noa_vif->bss_conf.beacon_int; | |
157 | ||
158 | for (i = 0; i < MAX_BINDINGS; i++) { | |
159 | u32 id_n_c = le32_to_cpu(cmd->quotas[i].id_and_color); | |
160 | u32 id = (id_n_c & FW_CTXT_ID_MSK) >> FW_CTXT_ID_POS; | |
161 | u32 quota = le32_to_cpu(cmd->quotas[i].quota); | |
162 | ||
163 | if (id != phy_id) | |
164 | continue; | |
165 | ||
246dd992 DS |
166 | quota *= (beacon_int - mvm->noa_duration); |
167 | quota /= beacon_int; | |
507cadf2 DS |
168 | |
169 | cmd->quotas[i].quota = cpu_to_le32(quota); | |
170 | } | |
171 | #endif | |
172 | } | |
173 | ||
8ca151b5 JB |
174 | int iwl_mvm_update_quotas(struct iwl_mvm *mvm, struct ieee80211_vif *newvif) |
175 | { | |
f5e45f2d | 176 | struct iwl_time_quota_cmd cmd = {}; |
6ca40d6e | 177 | int i, idx, ret, num_active_macs, quota, quota_rem, n_non_lowlat; |
8ca151b5 JB |
178 | struct iwl_mvm_quota_iterator_data data = { |
179 | .n_interfaces = {}, | |
180 | .colors = { -1, -1, -1, -1 }, | |
181 | .new_vif = newvif, | |
182 | }; | |
183 | ||
f5e45f2d JB |
184 | lockdep_assert_held(&mvm->mutex); |
185 | ||
8ca151b5 JB |
186 | /* update all upon completion */ |
187 | if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) | |
188 | return 0; | |
189 | ||
f5e45f2d JB |
190 | /* iterator data above must match */ |
191 | BUILD_BUG_ON(MAX_BINDINGS != 4); | |
8ca151b5 JB |
192 | |
193 | ieee80211_iterate_active_interfaces_atomic( | |
194 | mvm->hw, IEEE80211_IFACE_ITER_NORMAL, | |
195 | iwl_mvm_quota_iterator, &data); | |
196 | if (newvif) { | |
197 | data.new_vif = NULL; | |
198 | iwl_mvm_quota_iterator(&data, newvif->addr, newvif); | |
199 | } | |
200 | ||
35adfd6e IP |
201 | /* |
202 | * The FW's scheduling session consists of | |
203 | * IWL_MVM_MAX_QUOTA fragments. Divide these fragments | |
204 | * equally between all the bindings that require quota | |
205 | */ | |
7b8359cf | 206 | num_active_macs = 0; |
35adfd6e IP |
207 | for (i = 0; i < MAX_BINDINGS; i++) { |
208 | cmd.quotas[i].id_and_color = cpu_to_le32(FW_CTXT_INVALID); | |
7b8359cf | 209 | num_active_macs += data.n_interfaces[i]; |
35adfd6e IP |
210 | } |
211 | ||
6ca40d6e JB |
212 | n_non_lowlat = num_active_macs; |
213 | ||
214 | if (data.n_low_latency_bindings == 1) { | |
215 | for (i = 0; i < MAX_BINDINGS; i++) { | |
216 | if (data.low_latency[i]) { | |
217 | n_non_lowlat -= data.n_interfaces[i]; | |
218 | break; | |
219 | } | |
220 | } | |
7b4fe06c IP |
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; | |
6ca40d6e | 233 | } else if (num_active_macs) { |
7b4fe06c IP |
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 | */ | |
6ca40d6e JB |
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; | |
8d683b79 | 245 | } |
35adfd6e | 246 | |
8ca151b5 | 247 | for (idx = 0, i = 0; i < MAX_BINDINGS; i++) { |
8d683b79 | 248 | if (data.colors[i] < 0) |
8ca151b5 JB |
249 | continue; |
250 | ||
251 | cmd.quotas[idx].id_and_color = | |
252 | cpu_to_le32(FW_CMD_ID_AND_COLOR(i, data.colors[i])); | |
8d683b79 | 253 | |
1fb184b4 | 254 | if (data.n_interfaces[i] <= 0) |
8d683b79 | 255 | cmd.quotas[idx].quota = cpu_to_le32(0); |
1fb184b4 JB |
256 | else if (data.n_low_latency_bindings == 1 && n_non_lowlat && |
257 | data.low_latency[i]) | |
7b4fe06c IP |
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 | */ | |
6ca40d6e | 264 | cmd.quotas[idx].quota = cpu_to_le32(QUOTA_LOWLAT_MIN); |
1fb184b4 | 265 | else |
7b8359cf JB |
266 | cmd.quotas[idx].quota = |
267 | cpu_to_le32(quota * data.n_interfaces[i]); | |
1fb184b4 | 268 | |
7b4fe06c IP |
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 | ||
65d66628 | 273 | cmd.quotas[idx].max_duration = cpu_to_le32(0); |
1fb184b4 | 274 | |
8ca151b5 JB |
275 | idx++; |
276 | } | |
277 | ||
2d675e52 IP |
278 | /* Give the remainder of the session to the first data binding */ |
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 | } | |
8ca151b5 | 285 | |
507cadf2 DS |
286 | iwl_mvm_adjust_quota_for_noa(mvm, &cmd); |
287 | ||
a1022927 | 288 | ret = iwl_mvm_send_cmd_pdu(mvm, TIME_QUOTA_CMD, 0, |
8ca151b5 JB |
289 | sizeof(cmd), &cmd); |
290 | if (ret) | |
291 | IWL_ERR(mvm, "Failed to send quota: %d\n", ret); | |
292 | return ret; | |
293 | } |