blob: e843b67f2201f5c3159747c4128d08b1c28638a8 [file] [log] [blame]
Lilach Edelstein1f3b0ff2013-10-06 13:03:32 +02001/******************************************************************************
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 *
Emmanuel Grumbach51368bf2013-12-30 13:15:54 +02008 * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved.
Lilach Edelstein1f3b0ff2013-10-06 13:03:32 +02009 *
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
25 * in the file called COPYING.
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 *
Emmanuel Grumbach51368bf2013-12-30 13:15:54 +020033 * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved.
Lilach Edelstein1f3b0ff2013-10-06 13:03:32 +020034 * 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#include "mvm.h"
64
65/* For counting bound interfaces */
66struct iwl_mvm_active_iface_iterator_data {
67 struct ieee80211_vif *ignore_vif;
68 u8 sta_vif_ap_sta_id;
69 enum iwl_sf_state sta_vif_state;
70 int num_active_macs;
71};
72
73/*
74 * Count bound interfaces which are not p2p, besides data->ignore_vif.
75 * data->station_vif will point to one bound vif of type station, if exists.
76 */
77static void iwl_mvm_bound_iface_iterator(void *_data, u8 *mac,
78 struct ieee80211_vif *vif)
79{
80 struct iwl_mvm_active_iface_iterator_data *data = _data;
81 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
82
83 if (vif == data->ignore_vif || !mvmvif->phy_ctxt ||
84 vif->type == NL80211_IFTYPE_P2P_DEVICE)
85 return;
86
87 data->num_active_macs++;
88
89 if (vif->type == NL80211_IFTYPE_STATION) {
90 data->sta_vif_ap_sta_id = mvmvif->ap_sta_id;
91 if (vif->bss_conf.assoc)
92 data->sta_vif_state = SF_FULL_ON;
93 else
94 data->sta_vif_state = SF_INIT_OFF;
95 }
96}
97
98/*
99 * Aging and idle timeouts for the different possible scenarios
100 * in SF_FULL_ON state.
101 */
102static const __le32 sf_full_timeout[SF_NUM_SCENARIO][SF_NUM_TIMEOUT_TYPES] = {
103 {
104 cpu_to_le32(SF_SINGLE_UNICAST_AGING_TIMER),
105 cpu_to_le32(SF_SINGLE_UNICAST_IDLE_TIMER)
106 },
107 {
108 cpu_to_le32(SF_AGG_UNICAST_AGING_TIMER),
109 cpu_to_le32(SF_AGG_UNICAST_IDLE_TIMER)
110 },
111 {
112 cpu_to_le32(SF_MCAST_AGING_TIMER),
113 cpu_to_le32(SF_MCAST_IDLE_TIMER)
114 },
115 {
116 cpu_to_le32(SF_BA_AGING_TIMER),
117 cpu_to_le32(SF_BA_IDLE_TIMER)
118 },
119 {
120 cpu_to_le32(SF_TX_RE_AGING_TIMER),
121 cpu_to_le32(SF_TX_RE_IDLE_TIMER)
122 },
123};
124
125static void iwl_mvm_fill_sf_command(struct iwl_sf_cfg_cmd *sf_cmd,
126 struct ieee80211_sta *sta)
127{
128 int i, j, watermark;
129
130 sf_cmd->watermark[SF_LONG_DELAY_ON] = cpu_to_le32(SF_W_MARK_SCAN);
131
132 /*
133 * If we are in association flow - check antenna configuration
134 * capabilities of the AP station, and choose the watermark accordingly.
135 */
136 if (sta) {
137 if (sta->ht_cap.ht_supported || sta->vht_cap.vht_supported) {
138 switch (sta->rx_nss) {
139 case 1:
140 watermark = SF_W_MARK_SISO;
141 break;
142 case 2:
143 watermark = SF_W_MARK_MIMO2;
144 break;
145 default:
146 watermark = SF_W_MARK_MIMO3;
147 break;
148 }
149 } else {
150 watermark = SF_W_MARK_LEGACY;
151 }
152 /* default watermark value for unassociated mode. */
153 } else {
154 watermark = SF_W_MARK_MIMO2;
155 }
156 sf_cmd->watermark[SF_FULL_ON] = cpu_to_le32(watermark);
157
158 for (i = 0; i < SF_NUM_SCENARIO; i++) {
159 for (j = 0; j < SF_NUM_TIMEOUT_TYPES; j++) {
160 sf_cmd->long_delay_timeouts[i][j] =
161 cpu_to_le32(SF_LONG_DELAY_AGING_TIMER);
162 }
163 }
164 BUILD_BUG_ON(sizeof(sf_full_timeout) !=
165 sizeof(__le32) * SF_NUM_SCENARIO * SF_NUM_TIMEOUT_TYPES);
166
167 memcpy(sf_cmd->full_on_timeouts, sf_full_timeout,
168 sizeof(sf_full_timeout));
169}
170
171static int iwl_mvm_sf_config(struct iwl_mvm *mvm, u8 sta_id,
172 enum iwl_sf_state new_state)
173{
174 struct iwl_sf_cfg_cmd sf_cmd = {
Emmanuel Grumbach86974bf2014-07-31 14:32:37 +0300175 .state = cpu_to_le32(new_state),
Lilach Edelstein1f3b0ff2013-10-06 13:03:32 +0200176 };
177 struct ieee80211_sta *sta;
178 int ret = 0;
179
180 /*
181 * If an associated AP sta changed its antenna configuration, the state
182 * will remain FULL_ON but SF parameters need to be reconsidered.
183 */
184 if (new_state != SF_FULL_ON && mvm->sf_state == new_state)
185 return 0;
186
187 switch (new_state) {
188 case SF_UNINIT:
189 break;
190 case SF_FULL_ON:
191 if (sta_id == IWL_MVM_STATION_COUNT) {
192 IWL_ERR(mvm,
193 "No station: Cannot switch SF to FULL_ON\n");
194 return -EINVAL;
195 }
196 rcu_read_lock();
197 sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]);
198 if (IS_ERR_OR_NULL(sta)) {
199 IWL_ERR(mvm, "Invalid station id\n");
200 rcu_read_unlock();
201 return -EINVAL;
202 }
203 iwl_mvm_fill_sf_command(&sf_cmd, sta);
204 rcu_read_unlock();
205 break;
206 case SF_INIT_OFF:
207 iwl_mvm_fill_sf_command(&sf_cmd, NULL);
208 break;
209 default:
210 WARN_ONCE(1, "Invalid state: %d. not sending Smart Fifo cmd\n",
211 new_state);
212 return -EINVAL;
213 }
214
215 ret = iwl_mvm_send_cmd_pdu(mvm, REPLY_SF_CFG_CMD, CMD_ASYNC,
216 sizeof(sf_cmd), &sf_cmd);
217 if (!ret)
218 mvm->sf_state = new_state;
219
220 return ret;
221}
222
223/*
224 * Update Smart fifo:
225 * Count bound interfaces that are not to be removed, ignoring p2p devices,
226 * and set new state accordingly.
227 */
228int iwl_mvm_sf_update(struct iwl_mvm *mvm, struct ieee80211_vif *changed_vif,
229 bool remove_vif)
230{
231 enum iwl_sf_state new_state;
232 u8 sta_id = IWL_MVM_STATION_COUNT;
233 struct iwl_mvm_vif *mvmvif = NULL;
234 struct iwl_mvm_active_iface_iterator_data data = {
235 .ignore_vif = changed_vif,
236 .sta_vif_state = SF_UNINIT,
237 .sta_vif_ap_sta_id = IWL_MVM_STATION_COUNT,
238 };
239
Lilach Edelstein1f3b0ff2013-10-06 13:03:32 +0200240 /*
241 * Ignore the call if we are in HW Restart flow, or if the handled
242 * vif is a p2p device.
243 */
244 if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status) ||
245 (changed_vif && changed_vif->type == NL80211_IFTYPE_P2P_DEVICE))
246 return 0;
247
248 ieee80211_iterate_active_interfaces_atomic(mvm->hw,
249 IEEE80211_IFACE_ITER_NORMAL,
250 iwl_mvm_bound_iface_iterator,
251 &data);
252
253 /* If changed_vif exists and is not to be removed, add to the count */
254 if (changed_vif && !remove_vif)
255 data.num_active_macs++;
256
257 switch (data.num_active_macs) {
258 case 0:
259 /* If there are no active macs - change state to SF_INIT_OFF */
260 new_state = SF_INIT_OFF;
261 break;
262 case 1:
263 if (remove_vif) {
264 /* The one active mac left is of type station
265 * and we filled the relevant data during iteration
266 */
267 new_state = data.sta_vif_state;
268 sta_id = data.sta_vif_ap_sta_id;
269 } else {
270 if (WARN_ON(!changed_vif))
271 return -EINVAL;
272 if (changed_vif->type != NL80211_IFTYPE_STATION) {
273 new_state = SF_UNINIT;
Johannes Berg0229cda2014-03-19 18:36:39 +0100274 } else if (changed_vif->bss_conf.assoc &&
275 changed_vif->bss_conf.dtim_period) {
Lilach Edelstein1f3b0ff2013-10-06 13:03:32 +0200276 mvmvif = iwl_mvm_vif_from_mac80211(changed_vif);
277 sta_id = mvmvif->ap_sta_id;
278 new_state = SF_FULL_ON;
279 } else {
280 new_state = SF_INIT_OFF;
281 }
282 }
283 break;
284 default:
285 /* If there are multiple active macs - change to SF_UNINIT */
286 new_state = SF_UNINIT;
287 }
288 return iwl_mvm_sf_config(mvm, sta_id, new_state);
289}