18c2ecf20Sopenharmony_ci/******************************************************************************
28c2ecf20Sopenharmony_ci *
38c2ecf20Sopenharmony_ci * This file is provided under a dual BSD/GPLv2 license.  When using or
48c2ecf20Sopenharmony_ci * redistributing this file, you may do so under either license.
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * GPL LICENSE SUMMARY
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved.
98c2ecf20Sopenharmony_ci * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
108c2ecf20Sopenharmony_ci * Copyright (C) 2018-2019 Intel Corporation
118c2ecf20Sopenharmony_ci *
128c2ecf20Sopenharmony_ci * This program is free software; you can redistribute it and/or modify
138c2ecf20Sopenharmony_ci * it under the terms of version 2 of the GNU General Public License as
148c2ecf20Sopenharmony_ci * published by the Free Software Foundation.
158c2ecf20Sopenharmony_ci *
168c2ecf20Sopenharmony_ci * This program is distributed in the hope that it will be useful, but
178c2ecf20Sopenharmony_ci * WITHOUT ANY WARRANTY; without even the implied warranty of
188c2ecf20Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
198c2ecf20Sopenharmony_ci * General Public License for more details.
208c2ecf20Sopenharmony_ci *
218c2ecf20Sopenharmony_ci * The full GNU General Public License is included in this distribution
228c2ecf20Sopenharmony_ci * in the file called COPYING.
238c2ecf20Sopenharmony_ci *
248c2ecf20Sopenharmony_ci * Contact Information:
258c2ecf20Sopenharmony_ci *  Intel Linux Wireless <linuxwifi@intel.com>
268c2ecf20Sopenharmony_ci * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
278c2ecf20Sopenharmony_ci *
288c2ecf20Sopenharmony_ci * BSD LICENSE
298c2ecf20Sopenharmony_ci *
308c2ecf20Sopenharmony_ci * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved.
318c2ecf20Sopenharmony_ci * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
328c2ecf20Sopenharmony_ci * Copyright (C) 2018-2019 Intel Corporation
338c2ecf20Sopenharmony_ci * All rights reserved.
348c2ecf20Sopenharmony_ci *
358c2ecf20Sopenharmony_ci * Redistribution and use in source and binary forms, with or without
368c2ecf20Sopenharmony_ci * modification, are permitted provided that the following conditions
378c2ecf20Sopenharmony_ci * are met:
388c2ecf20Sopenharmony_ci *
398c2ecf20Sopenharmony_ci *  * Redistributions of source code must retain the above copyright
408c2ecf20Sopenharmony_ci *    notice, this list of conditions and the following disclaimer.
418c2ecf20Sopenharmony_ci *  * Redistributions in binary form must reproduce the above copyright
428c2ecf20Sopenharmony_ci *    notice, this list of conditions and the following disclaimer in
438c2ecf20Sopenharmony_ci *    the documentation and/or other materials provided with the
448c2ecf20Sopenharmony_ci *    distribution.
458c2ecf20Sopenharmony_ci *  * Neither the name Intel Corporation nor the names of its
468c2ecf20Sopenharmony_ci *    contributors may be used to endorse or promote products derived
478c2ecf20Sopenharmony_ci *    from this software without specific prior written permission.
488c2ecf20Sopenharmony_ci *
498c2ecf20Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
508c2ecf20Sopenharmony_ci * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
518c2ecf20Sopenharmony_ci * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
528c2ecf20Sopenharmony_ci * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
538c2ecf20Sopenharmony_ci * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
548c2ecf20Sopenharmony_ci * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
558c2ecf20Sopenharmony_ci * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
568c2ecf20Sopenharmony_ci * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
578c2ecf20Sopenharmony_ci * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
588c2ecf20Sopenharmony_ci * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
598c2ecf20Sopenharmony_ci * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
608c2ecf20Sopenharmony_ci *
618c2ecf20Sopenharmony_ci *****************************************************************************/
628c2ecf20Sopenharmony_ci#include "mvm.h"
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci/* For counting bound interfaces */
658c2ecf20Sopenharmony_cistruct iwl_mvm_active_iface_iterator_data {
668c2ecf20Sopenharmony_ci	struct ieee80211_vif *ignore_vif;
678c2ecf20Sopenharmony_ci	u8 sta_vif_ap_sta_id;
688c2ecf20Sopenharmony_ci	enum iwl_sf_state sta_vif_state;
698c2ecf20Sopenharmony_ci	u32 num_active_macs;
708c2ecf20Sopenharmony_ci};
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci/*
738c2ecf20Sopenharmony_ci * Count bound interfaces which are not p2p, besides data->ignore_vif.
748c2ecf20Sopenharmony_ci * data->station_vif will point to one bound vif of type station, if exists.
758c2ecf20Sopenharmony_ci */
768c2ecf20Sopenharmony_cistatic void iwl_mvm_bound_iface_iterator(void *_data, u8 *mac,
778c2ecf20Sopenharmony_ci					 struct ieee80211_vif *vif)
788c2ecf20Sopenharmony_ci{
798c2ecf20Sopenharmony_ci	struct iwl_mvm_active_iface_iterator_data *data = _data;
808c2ecf20Sopenharmony_ci	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci	if (vif == data->ignore_vif || !mvmvif->phy_ctxt ||
838c2ecf20Sopenharmony_ci	    vif->type == NL80211_IFTYPE_P2P_DEVICE)
848c2ecf20Sopenharmony_ci		return;
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci	data->num_active_macs++;
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci	if (vif->type == NL80211_IFTYPE_STATION) {
898c2ecf20Sopenharmony_ci		data->sta_vif_ap_sta_id = mvmvif->ap_sta_id;
908c2ecf20Sopenharmony_ci		if (vif->bss_conf.assoc)
918c2ecf20Sopenharmony_ci			data->sta_vif_state = SF_FULL_ON;
928c2ecf20Sopenharmony_ci		else
938c2ecf20Sopenharmony_ci			data->sta_vif_state = SF_INIT_OFF;
948c2ecf20Sopenharmony_ci	}
958c2ecf20Sopenharmony_ci}
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci/*
988c2ecf20Sopenharmony_ci * Aging and idle timeouts for the different possible scenarios
998c2ecf20Sopenharmony_ci * in default configuration
1008c2ecf20Sopenharmony_ci */
1018c2ecf20Sopenharmony_cistatic const
1028c2ecf20Sopenharmony_ci__le32 sf_full_timeout_def[SF_NUM_SCENARIO][SF_NUM_TIMEOUT_TYPES] = {
1038c2ecf20Sopenharmony_ci	{
1048c2ecf20Sopenharmony_ci		cpu_to_le32(SF_SINGLE_UNICAST_AGING_TIMER_DEF),
1058c2ecf20Sopenharmony_ci		cpu_to_le32(SF_SINGLE_UNICAST_IDLE_TIMER_DEF)
1068c2ecf20Sopenharmony_ci	},
1078c2ecf20Sopenharmony_ci	{
1088c2ecf20Sopenharmony_ci		cpu_to_le32(SF_AGG_UNICAST_AGING_TIMER_DEF),
1098c2ecf20Sopenharmony_ci		cpu_to_le32(SF_AGG_UNICAST_IDLE_TIMER_DEF)
1108c2ecf20Sopenharmony_ci	},
1118c2ecf20Sopenharmony_ci	{
1128c2ecf20Sopenharmony_ci		cpu_to_le32(SF_MCAST_AGING_TIMER_DEF),
1138c2ecf20Sopenharmony_ci		cpu_to_le32(SF_MCAST_IDLE_TIMER_DEF)
1148c2ecf20Sopenharmony_ci	},
1158c2ecf20Sopenharmony_ci	{
1168c2ecf20Sopenharmony_ci		cpu_to_le32(SF_BA_AGING_TIMER_DEF),
1178c2ecf20Sopenharmony_ci		cpu_to_le32(SF_BA_IDLE_TIMER_DEF)
1188c2ecf20Sopenharmony_ci	},
1198c2ecf20Sopenharmony_ci	{
1208c2ecf20Sopenharmony_ci		cpu_to_le32(SF_TX_RE_AGING_TIMER_DEF),
1218c2ecf20Sopenharmony_ci		cpu_to_le32(SF_TX_RE_IDLE_TIMER_DEF)
1228c2ecf20Sopenharmony_ci	},
1238c2ecf20Sopenharmony_ci};
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci/*
1268c2ecf20Sopenharmony_ci * Aging and idle timeouts for the different possible scenarios
1278c2ecf20Sopenharmony_ci * in single BSS MAC configuration.
1288c2ecf20Sopenharmony_ci */
1298c2ecf20Sopenharmony_cistatic const __le32 sf_full_timeout[SF_NUM_SCENARIO][SF_NUM_TIMEOUT_TYPES] = {
1308c2ecf20Sopenharmony_ci	{
1318c2ecf20Sopenharmony_ci		cpu_to_le32(SF_SINGLE_UNICAST_AGING_TIMER),
1328c2ecf20Sopenharmony_ci		cpu_to_le32(SF_SINGLE_UNICAST_IDLE_TIMER)
1338c2ecf20Sopenharmony_ci	},
1348c2ecf20Sopenharmony_ci	{
1358c2ecf20Sopenharmony_ci		cpu_to_le32(SF_AGG_UNICAST_AGING_TIMER),
1368c2ecf20Sopenharmony_ci		cpu_to_le32(SF_AGG_UNICAST_IDLE_TIMER)
1378c2ecf20Sopenharmony_ci	},
1388c2ecf20Sopenharmony_ci	{
1398c2ecf20Sopenharmony_ci		cpu_to_le32(SF_MCAST_AGING_TIMER),
1408c2ecf20Sopenharmony_ci		cpu_to_le32(SF_MCAST_IDLE_TIMER)
1418c2ecf20Sopenharmony_ci	},
1428c2ecf20Sopenharmony_ci	{
1438c2ecf20Sopenharmony_ci		cpu_to_le32(SF_BA_AGING_TIMER),
1448c2ecf20Sopenharmony_ci		cpu_to_le32(SF_BA_IDLE_TIMER)
1458c2ecf20Sopenharmony_ci	},
1468c2ecf20Sopenharmony_ci	{
1478c2ecf20Sopenharmony_ci		cpu_to_le32(SF_TX_RE_AGING_TIMER),
1488c2ecf20Sopenharmony_ci		cpu_to_le32(SF_TX_RE_IDLE_TIMER)
1498c2ecf20Sopenharmony_ci	},
1508c2ecf20Sopenharmony_ci};
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_cistatic void iwl_mvm_fill_sf_command(struct iwl_mvm *mvm,
1538c2ecf20Sopenharmony_ci				    struct iwl_sf_cfg_cmd *sf_cmd,
1548c2ecf20Sopenharmony_ci				    struct ieee80211_sta *sta)
1558c2ecf20Sopenharmony_ci{
1568c2ecf20Sopenharmony_ci	int i, j, watermark;
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci	sf_cmd->watermark[SF_LONG_DELAY_ON] = cpu_to_le32(SF_W_MARK_SCAN);
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci	/*
1618c2ecf20Sopenharmony_ci	 * If we are in association flow - check antenna configuration
1628c2ecf20Sopenharmony_ci	 * capabilities of the AP station, and choose the watermark accordingly.
1638c2ecf20Sopenharmony_ci	 */
1648c2ecf20Sopenharmony_ci	if (sta) {
1658c2ecf20Sopenharmony_ci		if (sta->ht_cap.ht_supported ||
1668c2ecf20Sopenharmony_ci		    sta->vht_cap.vht_supported ||
1678c2ecf20Sopenharmony_ci		    sta->he_cap.has_he) {
1688c2ecf20Sopenharmony_ci			switch (sta->rx_nss) {
1698c2ecf20Sopenharmony_ci			case 1:
1708c2ecf20Sopenharmony_ci				watermark = SF_W_MARK_SISO;
1718c2ecf20Sopenharmony_ci				break;
1728c2ecf20Sopenharmony_ci			case 2:
1738c2ecf20Sopenharmony_ci				watermark = SF_W_MARK_MIMO2;
1748c2ecf20Sopenharmony_ci				break;
1758c2ecf20Sopenharmony_ci			default:
1768c2ecf20Sopenharmony_ci				watermark = SF_W_MARK_MIMO3;
1778c2ecf20Sopenharmony_ci				break;
1788c2ecf20Sopenharmony_ci			}
1798c2ecf20Sopenharmony_ci		} else {
1808c2ecf20Sopenharmony_ci			watermark = SF_W_MARK_LEGACY;
1818c2ecf20Sopenharmony_ci		}
1828c2ecf20Sopenharmony_ci	/* default watermark value for unassociated mode. */
1838c2ecf20Sopenharmony_ci	} else {
1848c2ecf20Sopenharmony_ci		watermark = SF_W_MARK_MIMO2;
1858c2ecf20Sopenharmony_ci	}
1868c2ecf20Sopenharmony_ci	sf_cmd->watermark[SF_FULL_ON] = cpu_to_le32(watermark);
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci	for (i = 0; i < SF_NUM_SCENARIO; i++) {
1898c2ecf20Sopenharmony_ci		for (j = 0; j < SF_NUM_TIMEOUT_TYPES; j++) {
1908c2ecf20Sopenharmony_ci			sf_cmd->long_delay_timeouts[i][j] =
1918c2ecf20Sopenharmony_ci					cpu_to_le32(SF_LONG_DELAY_AGING_TIMER);
1928c2ecf20Sopenharmony_ci		}
1938c2ecf20Sopenharmony_ci	}
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci	if (sta) {
1968c2ecf20Sopenharmony_ci		BUILD_BUG_ON(sizeof(sf_full_timeout) !=
1978c2ecf20Sopenharmony_ci			     sizeof(__le32) * SF_NUM_SCENARIO *
1988c2ecf20Sopenharmony_ci			     SF_NUM_TIMEOUT_TYPES);
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci		memcpy(sf_cmd->full_on_timeouts, sf_full_timeout,
2018c2ecf20Sopenharmony_ci		       sizeof(sf_full_timeout));
2028c2ecf20Sopenharmony_ci	} else {
2038c2ecf20Sopenharmony_ci		BUILD_BUG_ON(sizeof(sf_full_timeout_def) !=
2048c2ecf20Sopenharmony_ci			     sizeof(__le32) * SF_NUM_SCENARIO *
2058c2ecf20Sopenharmony_ci			     SF_NUM_TIMEOUT_TYPES);
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci		memcpy(sf_cmd->full_on_timeouts, sf_full_timeout_def,
2088c2ecf20Sopenharmony_ci		       sizeof(sf_full_timeout_def));
2098c2ecf20Sopenharmony_ci	}
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci}
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_cistatic int iwl_mvm_sf_config(struct iwl_mvm *mvm, u8 sta_id,
2148c2ecf20Sopenharmony_ci			     enum iwl_sf_state new_state)
2158c2ecf20Sopenharmony_ci{
2168c2ecf20Sopenharmony_ci	struct iwl_sf_cfg_cmd sf_cmd = {
2178c2ecf20Sopenharmony_ci		.state = cpu_to_le32(new_state),
2188c2ecf20Sopenharmony_ci	};
2198c2ecf20Sopenharmony_ci	struct ieee80211_sta *sta;
2208c2ecf20Sopenharmony_ci	int ret = 0;
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci	if (mvm->cfg->disable_dummy_notification)
2238c2ecf20Sopenharmony_ci		sf_cmd.state |= cpu_to_le32(SF_CFG_DUMMY_NOTIF_OFF);
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci	/*
2268c2ecf20Sopenharmony_ci	 * If an associated AP sta changed its antenna configuration, the state
2278c2ecf20Sopenharmony_ci	 * will remain FULL_ON but SF parameters need to be reconsidered.
2288c2ecf20Sopenharmony_ci	 */
2298c2ecf20Sopenharmony_ci	if (new_state != SF_FULL_ON && mvm->sf_state == new_state)
2308c2ecf20Sopenharmony_ci		return 0;
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci	switch (new_state) {
2338c2ecf20Sopenharmony_ci	case SF_UNINIT:
2348c2ecf20Sopenharmony_ci		iwl_mvm_fill_sf_command(mvm, &sf_cmd, NULL);
2358c2ecf20Sopenharmony_ci		break;
2368c2ecf20Sopenharmony_ci	case SF_FULL_ON:
2378c2ecf20Sopenharmony_ci		if (sta_id == IWL_MVM_INVALID_STA) {
2388c2ecf20Sopenharmony_ci			IWL_ERR(mvm,
2398c2ecf20Sopenharmony_ci				"No station: Cannot switch SF to FULL_ON\n");
2408c2ecf20Sopenharmony_ci			return -EINVAL;
2418c2ecf20Sopenharmony_ci		}
2428c2ecf20Sopenharmony_ci		rcu_read_lock();
2438c2ecf20Sopenharmony_ci		sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]);
2448c2ecf20Sopenharmony_ci		if (IS_ERR_OR_NULL(sta)) {
2458c2ecf20Sopenharmony_ci			IWL_ERR(mvm, "Invalid station id\n");
2468c2ecf20Sopenharmony_ci			rcu_read_unlock();
2478c2ecf20Sopenharmony_ci			return -EINVAL;
2488c2ecf20Sopenharmony_ci		}
2498c2ecf20Sopenharmony_ci		iwl_mvm_fill_sf_command(mvm, &sf_cmd, sta);
2508c2ecf20Sopenharmony_ci		rcu_read_unlock();
2518c2ecf20Sopenharmony_ci		break;
2528c2ecf20Sopenharmony_ci	case SF_INIT_OFF:
2538c2ecf20Sopenharmony_ci		iwl_mvm_fill_sf_command(mvm, &sf_cmd, NULL);
2548c2ecf20Sopenharmony_ci		break;
2558c2ecf20Sopenharmony_ci	default:
2568c2ecf20Sopenharmony_ci		WARN_ONCE(1, "Invalid state: %d. not sending Smart Fifo cmd\n",
2578c2ecf20Sopenharmony_ci			  new_state);
2588c2ecf20Sopenharmony_ci		return -EINVAL;
2598c2ecf20Sopenharmony_ci	}
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ci	ret = iwl_mvm_send_cmd_pdu(mvm, REPLY_SF_CFG_CMD, CMD_ASYNC,
2628c2ecf20Sopenharmony_ci				   sizeof(sf_cmd), &sf_cmd);
2638c2ecf20Sopenharmony_ci	if (!ret)
2648c2ecf20Sopenharmony_ci		mvm->sf_state = new_state;
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_ci	return ret;
2678c2ecf20Sopenharmony_ci}
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ci/*
2708c2ecf20Sopenharmony_ci * Update Smart fifo:
2718c2ecf20Sopenharmony_ci * Count bound interfaces that are not to be removed, ignoring p2p devices,
2728c2ecf20Sopenharmony_ci * and set new state accordingly.
2738c2ecf20Sopenharmony_ci */
2748c2ecf20Sopenharmony_ciint iwl_mvm_sf_update(struct iwl_mvm *mvm, struct ieee80211_vif *changed_vif,
2758c2ecf20Sopenharmony_ci		      bool remove_vif)
2768c2ecf20Sopenharmony_ci{
2778c2ecf20Sopenharmony_ci	enum iwl_sf_state new_state;
2788c2ecf20Sopenharmony_ci	u8 sta_id = IWL_MVM_INVALID_STA;
2798c2ecf20Sopenharmony_ci	struct iwl_mvm_vif *mvmvif = NULL;
2808c2ecf20Sopenharmony_ci	struct iwl_mvm_active_iface_iterator_data data = {
2818c2ecf20Sopenharmony_ci		.ignore_vif = changed_vif,
2828c2ecf20Sopenharmony_ci		.sta_vif_state = SF_UNINIT,
2838c2ecf20Sopenharmony_ci		.sta_vif_ap_sta_id = IWL_MVM_INVALID_STA,
2848c2ecf20Sopenharmony_ci	};
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_ci	/*
2878c2ecf20Sopenharmony_ci	 * Ignore the call if we are in HW Restart flow, or if the handled
2888c2ecf20Sopenharmony_ci	 * vif is a p2p device.
2898c2ecf20Sopenharmony_ci	 */
2908c2ecf20Sopenharmony_ci	if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status) ||
2918c2ecf20Sopenharmony_ci	    (changed_vif && changed_vif->type == NL80211_IFTYPE_P2P_DEVICE))
2928c2ecf20Sopenharmony_ci		return 0;
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_ci	ieee80211_iterate_active_interfaces_atomic(mvm->hw,
2958c2ecf20Sopenharmony_ci						   IEEE80211_IFACE_ITER_NORMAL,
2968c2ecf20Sopenharmony_ci						   iwl_mvm_bound_iface_iterator,
2978c2ecf20Sopenharmony_ci						   &data);
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ci	/* If changed_vif exists and is not to be removed, add to the count */
3008c2ecf20Sopenharmony_ci	if (changed_vif && !remove_vif)
3018c2ecf20Sopenharmony_ci		data.num_active_macs++;
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_ci	switch (data.num_active_macs) {
3048c2ecf20Sopenharmony_ci	case 0:
3058c2ecf20Sopenharmony_ci		/* If there are no active macs - change state to SF_INIT_OFF */
3068c2ecf20Sopenharmony_ci		new_state = SF_INIT_OFF;
3078c2ecf20Sopenharmony_ci		break;
3088c2ecf20Sopenharmony_ci	case 1:
3098c2ecf20Sopenharmony_ci		if (remove_vif) {
3108c2ecf20Sopenharmony_ci			/* The one active mac left is of type station
3118c2ecf20Sopenharmony_ci			 * and we filled the relevant data during iteration
3128c2ecf20Sopenharmony_ci			 */
3138c2ecf20Sopenharmony_ci			new_state = data.sta_vif_state;
3148c2ecf20Sopenharmony_ci			sta_id = data.sta_vif_ap_sta_id;
3158c2ecf20Sopenharmony_ci		} else {
3168c2ecf20Sopenharmony_ci			if (WARN_ON(!changed_vif))
3178c2ecf20Sopenharmony_ci				return -EINVAL;
3188c2ecf20Sopenharmony_ci			if (changed_vif->type != NL80211_IFTYPE_STATION) {
3198c2ecf20Sopenharmony_ci				new_state = SF_UNINIT;
3208c2ecf20Sopenharmony_ci			} else if (changed_vif->bss_conf.assoc &&
3218c2ecf20Sopenharmony_ci				   changed_vif->bss_conf.dtim_period) {
3228c2ecf20Sopenharmony_ci				mvmvif = iwl_mvm_vif_from_mac80211(changed_vif);
3238c2ecf20Sopenharmony_ci				sta_id = mvmvif->ap_sta_id;
3248c2ecf20Sopenharmony_ci				new_state = SF_FULL_ON;
3258c2ecf20Sopenharmony_ci			} else {
3268c2ecf20Sopenharmony_ci				new_state = SF_INIT_OFF;
3278c2ecf20Sopenharmony_ci			}
3288c2ecf20Sopenharmony_ci		}
3298c2ecf20Sopenharmony_ci		break;
3308c2ecf20Sopenharmony_ci	default:
3318c2ecf20Sopenharmony_ci		/* If there are multiple active macs - change to SF_UNINIT */
3328c2ecf20Sopenharmony_ci		new_state = SF_UNINIT;
3338c2ecf20Sopenharmony_ci	}
3348c2ecf20Sopenharmony_ci	return iwl_mvm_sf_config(mvm, sta_id, new_state);
3358c2ecf20Sopenharmony_ci}
336