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 * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
10 * Copyright (C) 2018-2019 Intel Corporation
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) 2013 - 2014 Intel Corporation. All rights reserved.
31 * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
32 * Copyright (C) 2018-2019 Intel Corporation
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#include "mvm.h"
63
64/* For counting bound interfaces */
65struct iwl_mvm_active_iface_iterator_data {
66	struct ieee80211_vif *ignore_vif;
67	u8 sta_vif_ap_sta_id;
68	enum iwl_sf_state sta_vif_state;
69	u32 num_active_macs;
70};
71
72/*
73 * Count bound interfaces which are not p2p, besides data->ignore_vif.
74 * data->station_vif will point to one bound vif of type station, if exists.
75 */
76static void iwl_mvm_bound_iface_iterator(void *_data, u8 *mac,
77					 struct ieee80211_vif *vif)
78{
79	struct iwl_mvm_active_iface_iterator_data *data = _data;
80	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
81
82	if (vif == data->ignore_vif || !mvmvif->phy_ctxt ||
83	    vif->type == NL80211_IFTYPE_P2P_DEVICE)
84		return;
85
86	data->num_active_macs++;
87
88	if (vif->type == NL80211_IFTYPE_STATION) {
89		data->sta_vif_ap_sta_id = mvmvif->ap_sta_id;
90		if (vif->bss_conf.assoc)
91			data->sta_vif_state = SF_FULL_ON;
92		else
93			data->sta_vif_state = SF_INIT_OFF;
94	}
95}
96
97/*
98 * Aging and idle timeouts for the different possible scenarios
99 * in default configuration
100 */
101static const
102__le32 sf_full_timeout_def[SF_NUM_SCENARIO][SF_NUM_TIMEOUT_TYPES] = {
103	{
104		cpu_to_le32(SF_SINGLE_UNICAST_AGING_TIMER_DEF),
105		cpu_to_le32(SF_SINGLE_UNICAST_IDLE_TIMER_DEF)
106	},
107	{
108		cpu_to_le32(SF_AGG_UNICAST_AGING_TIMER_DEF),
109		cpu_to_le32(SF_AGG_UNICAST_IDLE_TIMER_DEF)
110	},
111	{
112		cpu_to_le32(SF_MCAST_AGING_TIMER_DEF),
113		cpu_to_le32(SF_MCAST_IDLE_TIMER_DEF)
114	},
115	{
116		cpu_to_le32(SF_BA_AGING_TIMER_DEF),
117		cpu_to_le32(SF_BA_IDLE_TIMER_DEF)
118	},
119	{
120		cpu_to_le32(SF_TX_RE_AGING_TIMER_DEF),
121		cpu_to_le32(SF_TX_RE_IDLE_TIMER_DEF)
122	},
123};
124
125/*
126 * Aging and idle timeouts for the different possible scenarios
127 * in single BSS MAC configuration.
128 */
129static const __le32 sf_full_timeout[SF_NUM_SCENARIO][SF_NUM_TIMEOUT_TYPES] = {
130	{
131		cpu_to_le32(SF_SINGLE_UNICAST_AGING_TIMER),
132		cpu_to_le32(SF_SINGLE_UNICAST_IDLE_TIMER)
133	},
134	{
135		cpu_to_le32(SF_AGG_UNICAST_AGING_TIMER),
136		cpu_to_le32(SF_AGG_UNICAST_IDLE_TIMER)
137	},
138	{
139		cpu_to_le32(SF_MCAST_AGING_TIMER),
140		cpu_to_le32(SF_MCAST_IDLE_TIMER)
141	},
142	{
143		cpu_to_le32(SF_BA_AGING_TIMER),
144		cpu_to_le32(SF_BA_IDLE_TIMER)
145	},
146	{
147		cpu_to_le32(SF_TX_RE_AGING_TIMER),
148		cpu_to_le32(SF_TX_RE_IDLE_TIMER)
149	},
150};
151
152static void iwl_mvm_fill_sf_command(struct iwl_mvm *mvm,
153				    struct iwl_sf_cfg_cmd *sf_cmd,
154				    struct ieee80211_sta *sta)
155{
156	int i, j, watermark;
157
158	sf_cmd->watermark[SF_LONG_DELAY_ON] = cpu_to_le32(SF_W_MARK_SCAN);
159
160	/*
161	 * If we are in association flow - check antenna configuration
162	 * capabilities of the AP station, and choose the watermark accordingly.
163	 */
164	if (sta) {
165		if (sta->ht_cap.ht_supported ||
166		    sta->vht_cap.vht_supported ||
167		    sta->he_cap.has_he) {
168			switch (sta->rx_nss) {
169			case 1:
170				watermark = SF_W_MARK_SISO;
171				break;
172			case 2:
173				watermark = SF_W_MARK_MIMO2;
174				break;
175			default:
176				watermark = SF_W_MARK_MIMO3;
177				break;
178			}
179		} else {
180			watermark = SF_W_MARK_LEGACY;
181		}
182	/* default watermark value for unassociated mode. */
183	} else {
184		watermark = SF_W_MARK_MIMO2;
185	}
186	sf_cmd->watermark[SF_FULL_ON] = cpu_to_le32(watermark);
187
188	for (i = 0; i < SF_NUM_SCENARIO; i++) {
189		for (j = 0; j < SF_NUM_TIMEOUT_TYPES; j++) {
190			sf_cmd->long_delay_timeouts[i][j] =
191					cpu_to_le32(SF_LONG_DELAY_AGING_TIMER);
192		}
193	}
194
195	if (sta) {
196		BUILD_BUG_ON(sizeof(sf_full_timeout) !=
197			     sizeof(__le32) * SF_NUM_SCENARIO *
198			     SF_NUM_TIMEOUT_TYPES);
199
200		memcpy(sf_cmd->full_on_timeouts, sf_full_timeout,
201		       sizeof(sf_full_timeout));
202	} else {
203		BUILD_BUG_ON(sizeof(sf_full_timeout_def) !=
204			     sizeof(__le32) * SF_NUM_SCENARIO *
205			     SF_NUM_TIMEOUT_TYPES);
206
207		memcpy(sf_cmd->full_on_timeouts, sf_full_timeout_def,
208		       sizeof(sf_full_timeout_def));
209	}
210
211}
212
213static int iwl_mvm_sf_config(struct iwl_mvm *mvm, u8 sta_id,
214			     enum iwl_sf_state new_state)
215{
216	struct iwl_sf_cfg_cmd sf_cmd = {
217		.state = cpu_to_le32(new_state),
218	};
219	struct ieee80211_sta *sta;
220	int ret = 0;
221
222	if (mvm->cfg->disable_dummy_notification)
223		sf_cmd.state |= cpu_to_le32(SF_CFG_DUMMY_NOTIF_OFF);
224
225	/*
226	 * If an associated AP sta changed its antenna configuration, the state
227	 * will remain FULL_ON but SF parameters need to be reconsidered.
228	 */
229	if (new_state != SF_FULL_ON && mvm->sf_state == new_state)
230		return 0;
231
232	switch (new_state) {
233	case SF_UNINIT:
234		iwl_mvm_fill_sf_command(mvm, &sf_cmd, NULL);
235		break;
236	case SF_FULL_ON:
237		if (sta_id == IWL_MVM_INVALID_STA) {
238			IWL_ERR(mvm,
239				"No station: Cannot switch SF to FULL_ON\n");
240			return -EINVAL;
241		}
242		rcu_read_lock();
243		sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]);
244		if (IS_ERR_OR_NULL(sta)) {
245			IWL_ERR(mvm, "Invalid station id\n");
246			rcu_read_unlock();
247			return -EINVAL;
248		}
249		iwl_mvm_fill_sf_command(mvm, &sf_cmd, sta);
250		rcu_read_unlock();
251		break;
252	case SF_INIT_OFF:
253		iwl_mvm_fill_sf_command(mvm, &sf_cmd, NULL);
254		break;
255	default:
256		WARN_ONCE(1, "Invalid state: %d. not sending Smart Fifo cmd\n",
257			  new_state);
258		return -EINVAL;
259	}
260
261	ret = iwl_mvm_send_cmd_pdu(mvm, REPLY_SF_CFG_CMD, CMD_ASYNC,
262				   sizeof(sf_cmd), &sf_cmd);
263	if (!ret)
264		mvm->sf_state = new_state;
265
266	return ret;
267}
268
269/*
270 * Update Smart fifo:
271 * Count bound interfaces that are not to be removed, ignoring p2p devices,
272 * and set new state accordingly.
273 */
274int iwl_mvm_sf_update(struct iwl_mvm *mvm, struct ieee80211_vif *changed_vif,
275		      bool remove_vif)
276{
277	enum iwl_sf_state new_state;
278	u8 sta_id = IWL_MVM_INVALID_STA;
279	struct iwl_mvm_vif *mvmvif = NULL;
280	struct iwl_mvm_active_iface_iterator_data data = {
281		.ignore_vif = changed_vif,
282		.sta_vif_state = SF_UNINIT,
283		.sta_vif_ap_sta_id = IWL_MVM_INVALID_STA,
284	};
285
286	/*
287	 * Ignore the call if we are in HW Restart flow, or if the handled
288	 * vif is a p2p device.
289	 */
290	if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status) ||
291	    (changed_vif && changed_vif->type == NL80211_IFTYPE_P2P_DEVICE))
292		return 0;
293
294	ieee80211_iterate_active_interfaces_atomic(mvm->hw,
295						   IEEE80211_IFACE_ITER_NORMAL,
296						   iwl_mvm_bound_iface_iterator,
297						   &data);
298
299	/* If changed_vif exists and is not to be removed, add to the count */
300	if (changed_vif && !remove_vif)
301		data.num_active_macs++;
302
303	switch (data.num_active_macs) {
304	case 0:
305		/* If there are no active macs - change state to SF_INIT_OFF */
306		new_state = SF_INIT_OFF;
307		break;
308	case 1:
309		if (remove_vif) {
310			/* The one active mac left is of type station
311			 * and we filled the relevant data during iteration
312			 */
313			new_state = data.sta_vif_state;
314			sta_id = data.sta_vif_ap_sta_id;
315		} else {
316			if (WARN_ON(!changed_vif))
317				return -EINVAL;
318			if (changed_vif->type != NL80211_IFTYPE_STATION) {
319				new_state = SF_UNINIT;
320			} else if (changed_vif->bss_conf.assoc &&
321				   changed_vif->bss_conf.dtim_period) {
322				mvmvif = iwl_mvm_vif_from_mac80211(changed_vif);
323				sta_id = mvmvif->ap_sta_id;
324				new_state = SF_FULL_ON;
325			} else {
326				new_state = SF_INIT_OFF;
327			}
328		}
329		break;
330	default:
331		/* If there are multiple active macs - change to SF_UNINIT */
332		new_state = SF_UNINIT;
333	}
334	return iwl_mvm_sf_config(mvm, sta_id, new_state);
335}
336