Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  1// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
  2/*
  3 * Copyright (C) 2013-2014, 2018-2019 Intel Corporation
  4 * Copyright (C) 2013-2014 Intel Mobile Communications GmbH
  5 */
  6#include "mvm.h"
  7
  8/* For counting bound interfaces */
  9struct iwl_mvm_active_iface_iterator_data {
 10	struct ieee80211_vif *ignore_vif;
 11	u8 sta_vif_ap_sta_id;
 12	enum iwl_sf_state sta_vif_state;
 13	u32 num_active_macs;
 14};
 15
 16/*
 17 * Count bound interfaces which are not p2p, besides data->ignore_vif.
 18 * data->station_vif will point to one bound vif of type station, if exists.
 19 */
 20static void iwl_mvm_bound_iface_iterator(void *_data, u8 *mac,
 21					 struct ieee80211_vif *vif)
 22{
 23	struct iwl_mvm_active_iface_iterator_data *data = _data;
 24	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
 25
 26	if (vif == data->ignore_vif || !mvmvif->phy_ctxt ||
 27	    vif->type == NL80211_IFTYPE_P2P_DEVICE)
 28		return;
 29
 30	data->num_active_macs++;
 31
 32	if (vif->type == NL80211_IFTYPE_STATION) {
 33		data->sta_vif_ap_sta_id = mvmvif->ap_sta_id;
 34		if (vif->bss_conf.assoc)
 35			data->sta_vif_state = SF_FULL_ON;
 36		else
 37			data->sta_vif_state = SF_INIT_OFF;
 38	}
 39}
 40
 41/*
 42 * Aging and idle timeouts for the different possible scenarios
 43 * in default configuration
 44 */
 45static const
 46__le32 sf_full_timeout_def[SF_NUM_SCENARIO][SF_NUM_TIMEOUT_TYPES] = {
 47	{
 48		cpu_to_le32(SF_SINGLE_UNICAST_AGING_TIMER_DEF),
 49		cpu_to_le32(SF_SINGLE_UNICAST_IDLE_TIMER_DEF)
 50	},
 51	{
 52		cpu_to_le32(SF_AGG_UNICAST_AGING_TIMER_DEF),
 53		cpu_to_le32(SF_AGG_UNICAST_IDLE_TIMER_DEF)
 54	},
 55	{
 56		cpu_to_le32(SF_MCAST_AGING_TIMER_DEF),
 57		cpu_to_le32(SF_MCAST_IDLE_TIMER_DEF)
 58	},
 59	{
 60		cpu_to_le32(SF_BA_AGING_TIMER_DEF),
 61		cpu_to_le32(SF_BA_IDLE_TIMER_DEF)
 62	},
 63	{
 64		cpu_to_le32(SF_TX_RE_AGING_TIMER_DEF),
 65		cpu_to_le32(SF_TX_RE_IDLE_TIMER_DEF)
 66	},
 67};
 68
 69/*
 70 * Aging and idle timeouts for the different possible scenarios
 71 * in single BSS MAC configuration.
 72 */
 73static const __le32 sf_full_timeout[SF_NUM_SCENARIO][SF_NUM_TIMEOUT_TYPES] = {
 74	{
 75		cpu_to_le32(SF_SINGLE_UNICAST_AGING_TIMER),
 76		cpu_to_le32(SF_SINGLE_UNICAST_IDLE_TIMER)
 77	},
 78	{
 79		cpu_to_le32(SF_AGG_UNICAST_AGING_TIMER),
 80		cpu_to_le32(SF_AGG_UNICAST_IDLE_TIMER)
 81	},
 82	{
 83		cpu_to_le32(SF_MCAST_AGING_TIMER),
 84		cpu_to_le32(SF_MCAST_IDLE_TIMER)
 85	},
 86	{
 87		cpu_to_le32(SF_BA_AGING_TIMER),
 88		cpu_to_le32(SF_BA_IDLE_TIMER)
 89	},
 90	{
 91		cpu_to_le32(SF_TX_RE_AGING_TIMER),
 92		cpu_to_le32(SF_TX_RE_IDLE_TIMER)
 93	},
 94};
 95
 96static void iwl_mvm_fill_sf_command(struct iwl_mvm *mvm,
 97				    struct iwl_sf_cfg_cmd *sf_cmd,
 98				    struct ieee80211_sta *sta)
 99{
100	int i, j, watermark;
101
102	sf_cmd->watermark[SF_LONG_DELAY_ON] = cpu_to_le32(SF_W_MARK_SCAN);
103
104	/*
105	 * If we are in association flow - check antenna configuration
106	 * capabilities of the AP station, and choose the watermark accordingly.
107	 */
108	if (sta) {
109		if (sta->ht_cap.ht_supported ||
110		    sta->vht_cap.vht_supported ||
111		    sta->he_cap.has_he) {
112			switch (sta->rx_nss) {
113			case 1:
114				watermark = SF_W_MARK_SISO;
115				break;
116			case 2:
117				watermark = SF_W_MARK_MIMO2;
118				break;
119			default:
120				watermark = SF_W_MARK_MIMO3;
121				break;
122			}
123		} else {
124			watermark = SF_W_MARK_LEGACY;
125		}
126	/* default watermark value for unassociated mode. */
127	} else {
128		watermark = SF_W_MARK_MIMO2;
129	}
130	sf_cmd->watermark[SF_FULL_ON] = cpu_to_le32(watermark);
131
132	for (i = 0; i < SF_NUM_SCENARIO; i++) {
133		for (j = 0; j < SF_NUM_TIMEOUT_TYPES; j++) {
134			sf_cmd->long_delay_timeouts[i][j] =
135					cpu_to_le32(SF_LONG_DELAY_AGING_TIMER);
136		}
137	}
138
139	if (sta) {
140		BUILD_BUG_ON(sizeof(sf_full_timeout) !=
141			     sizeof(__le32) * SF_NUM_SCENARIO *
142			     SF_NUM_TIMEOUT_TYPES);
143
144		memcpy(sf_cmd->full_on_timeouts, sf_full_timeout,
145		       sizeof(sf_full_timeout));
146	} else {
147		BUILD_BUG_ON(sizeof(sf_full_timeout_def) !=
148			     sizeof(__le32) * SF_NUM_SCENARIO *
149			     SF_NUM_TIMEOUT_TYPES);
150
151		memcpy(sf_cmd->full_on_timeouts, sf_full_timeout_def,
152		       sizeof(sf_full_timeout_def));
153	}
154
155}
156
157static int iwl_mvm_sf_config(struct iwl_mvm *mvm, u8 sta_id,
158			     enum iwl_sf_state new_state)
159{
160	struct iwl_sf_cfg_cmd sf_cmd = {
161		.state = cpu_to_le32(new_state),
162	};
163	struct ieee80211_sta *sta;
164	int ret = 0;
165
166	if (mvm->cfg->disable_dummy_notification)
167		sf_cmd.state |= cpu_to_le32(SF_CFG_DUMMY_NOTIF_OFF);
168
169	/*
170	 * If an associated AP sta changed its antenna configuration, the state
171	 * will remain FULL_ON but SF parameters need to be reconsidered.
172	 */
173	if (new_state != SF_FULL_ON && mvm->sf_state == new_state)
174		return 0;
175
176	switch (new_state) {
177	case SF_UNINIT:
178		iwl_mvm_fill_sf_command(mvm, &sf_cmd, NULL);
179		break;
180	case SF_FULL_ON:
181		if (sta_id == IWL_MVM_INVALID_STA) {
182			IWL_ERR(mvm,
183				"No station: Cannot switch SF to FULL_ON\n");
184			return -EINVAL;
185		}
186		rcu_read_lock();
187		sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]);
188		if (IS_ERR_OR_NULL(sta)) {
189			IWL_ERR(mvm, "Invalid station id\n");
190			rcu_read_unlock();
191			return -EINVAL;
192		}
193		iwl_mvm_fill_sf_command(mvm, &sf_cmd, sta);
194		rcu_read_unlock();
195		break;
196	case SF_INIT_OFF:
197		iwl_mvm_fill_sf_command(mvm, &sf_cmd, NULL);
198		break;
199	default:
200		WARN_ONCE(1, "Invalid state: %d. not sending Smart Fifo cmd\n",
201			  new_state);
202		return -EINVAL;
203	}
204
205	ret = iwl_mvm_send_cmd_pdu(mvm, REPLY_SF_CFG_CMD, CMD_ASYNC,
206				   sizeof(sf_cmd), &sf_cmd);
207	if (!ret)
208		mvm->sf_state = new_state;
209
210	return ret;
211}
212
213/*
214 * Update Smart fifo:
215 * Count bound interfaces that are not to be removed, ignoring p2p devices,
216 * and set new state accordingly.
217 */
218int iwl_mvm_sf_update(struct iwl_mvm *mvm, struct ieee80211_vif *changed_vif,
219		      bool remove_vif)
220{
221	enum iwl_sf_state new_state;
222	u8 sta_id = IWL_MVM_INVALID_STA;
223	struct iwl_mvm_vif *mvmvif = NULL;
224	struct iwl_mvm_active_iface_iterator_data data = {
225		.ignore_vif = changed_vif,
226		.sta_vif_state = SF_UNINIT,
227		.sta_vif_ap_sta_id = IWL_MVM_INVALID_STA,
228	};
229
230	/*
231	 * Ignore the call if we are in HW Restart flow, or if the handled
232	 * vif is a p2p device.
233	 */
234	if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status) ||
235	    (changed_vif && changed_vif->type == NL80211_IFTYPE_P2P_DEVICE))
236		return 0;
237
238	ieee80211_iterate_active_interfaces_atomic(mvm->hw,
239						   IEEE80211_IFACE_ITER_NORMAL,
240						   iwl_mvm_bound_iface_iterator,
241						   &data);
242
243	/* If changed_vif exists and is not to be removed, add to the count */
244	if (changed_vif && !remove_vif)
245		data.num_active_macs++;
246
247	switch (data.num_active_macs) {
248	case 0:
249		/* If there are no active macs - change state to SF_INIT_OFF */
250		new_state = SF_INIT_OFF;
251		break;
252	case 1:
253		if (remove_vif) {
254			/* The one active mac left is of type station
255			 * and we filled the relevant data during iteration
256			 */
257			new_state = data.sta_vif_state;
258			sta_id = data.sta_vif_ap_sta_id;
259		} else {
260			if (WARN_ON(!changed_vif))
261				return -EINVAL;
262			if (changed_vif->type != NL80211_IFTYPE_STATION) {
263				new_state = SF_UNINIT;
264			} else if (changed_vif->bss_conf.assoc &&
265				   changed_vif->bss_conf.dtim_period) {
266				mvmvif = iwl_mvm_vif_from_mac80211(changed_vif);
267				sta_id = mvmvif->ap_sta_id;
268				new_state = SF_FULL_ON;
269			} else {
270				new_state = SF_INIT_OFF;
271			}
272		}
273		break;
274	default:
275		/* If there are multiple active macs - change to SF_UNINIT */
276		new_state = SF_UNINIT;
277	}
278	return iwl_mvm_sf_config(mvm, sta_id, new_state);
279}