Merge remote-tracking branches 'regulator/fix/da9211', 'regulator/fix/ltc3589' and...
[sfrench/cifs-2.6.git] / drivers / net / wireless / iwlwifi / mvm / sf.c
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) 2013 - 2014 Intel Corporation. All rights reserved.
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
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  *
33  * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved.
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 #include "mvm.h"
64
65 /* For counting bound interfaces */
66 struct 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  */
77 static 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  */
102 static 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
125 static 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
171 static 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 = {
175                 .state = cpu_to_le32(new_state),
176         };
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  */
228 int 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
240         /*
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;
274                         } else if (changed_vif->bss_conf.assoc &&
275                                    changed_vif->bss_conf.dtim_period) {
276                                 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 }