xref: /OK3568_Linux_fs/kernel/drivers/net/wireless/intel/iwlwifi/mvm/sf.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /******************************************************************************
2*4882a593Smuzhiyun  *
3*4882a593Smuzhiyun  * This file is provided under a dual BSD/GPLv2 license.  When using or
4*4882a593Smuzhiyun  * redistributing this file, you may do so under either license.
5*4882a593Smuzhiyun  *
6*4882a593Smuzhiyun  * GPL LICENSE SUMMARY
7*4882a593Smuzhiyun  *
8*4882a593Smuzhiyun  * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved.
9*4882a593Smuzhiyun  * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
10*4882a593Smuzhiyun  * Copyright (C) 2018-2019 Intel Corporation
11*4882a593Smuzhiyun  *
12*4882a593Smuzhiyun  * This program is free software; you can redistribute it and/or modify
13*4882a593Smuzhiyun  * it under the terms of version 2 of the GNU General Public License as
14*4882a593Smuzhiyun  * published by the Free Software Foundation.
15*4882a593Smuzhiyun  *
16*4882a593Smuzhiyun  * This program is distributed in the hope that it will be useful, but
17*4882a593Smuzhiyun  * WITHOUT ANY WARRANTY; without even the implied warranty of
18*4882a593Smuzhiyun  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19*4882a593Smuzhiyun  * General Public License for more details.
20*4882a593Smuzhiyun  *
21*4882a593Smuzhiyun  * The full GNU General Public License is included in this distribution
22*4882a593Smuzhiyun  * in the file called COPYING.
23*4882a593Smuzhiyun  *
24*4882a593Smuzhiyun  * Contact Information:
25*4882a593Smuzhiyun  *  Intel Linux Wireless <linuxwifi@intel.com>
26*4882a593Smuzhiyun  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
27*4882a593Smuzhiyun  *
28*4882a593Smuzhiyun  * BSD LICENSE
29*4882a593Smuzhiyun  *
30*4882a593Smuzhiyun  * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved.
31*4882a593Smuzhiyun  * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
32*4882a593Smuzhiyun  * Copyright (C) 2018-2019 Intel Corporation
33*4882a593Smuzhiyun  * All rights reserved.
34*4882a593Smuzhiyun  *
35*4882a593Smuzhiyun  * Redistribution and use in source and binary forms, with or without
36*4882a593Smuzhiyun  * modification, are permitted provided that the following conditions
37*4882a593Smuzhiyun  * are met:
38*4882a593Smuzhiyun  *
39*4882a593Smuzhiyun  *  * Redistributions of source code must retain the above copyright
40*4882a593Smuzhiyun  *    notice, this list of conditions and the following disclaimer.
41*4882a593Smuzhiyun  *  * Redistributions in binary form must reproduce the above copyright
42*4882a593Smuzhiyun  *    notice, this list of conditions and the following disclaimer in
43*4882a593Smuzhiyun  *    the documentation and/or other materials provided with the
44*4882a593Smuzhiyun  *    distribution.
45*4882a593Smuzhiyun  *  * Neither the name Intel Corporation nor the names of its
46*4882a593Smuzhiyun  *    contributors may be used to endorse or promote products derived
47*4882a593Smuzhiyun  *    from this software without specific prior written permission.
48*4882a593Smuzhiyun  *
49*4882a593Smuzhiyun  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
50*4882a593Smuzhiyun  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
51*4882a593Smuzhiyun  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
52*4882a593Smuzhiyun  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
53*4882a593Smuzhiyun  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
54*4882a593Smuzhiyun  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
55*4882a593Smuzhiyun  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
56*4882a593Smuzhiyun  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
57*4882a593Smuzhiyun  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
58*4882a593Smuzhiyun  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
59*4882a593Smuzhiyun  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
60*4882a593Smuzhiyun  *
61*4882a593Smuzhiyun  *****************************************************************************/
62*4882a593Smuzhiyun #include "mvm.h"
63*4882a593Smuzhiyun 
64*4882a593Smuzhiyun /* For counting bound interfaces */
65*4882a593Smuzhiyun struct iwl_mvm_active_iface_iterator_data {
66*4882a593Smuzhiyun 	struct ieee80211_vif *ignore_vif;
67*4882a593Smuzhiyun 	u8 sta_vif_ap_sta_id;
68*4882a593Smuzhiyun 	enum iwl_sf_state sta_vif_state;
69*4882a593Smuzhiyun 	u32 num_active_macs;
70*4882a593Smuzhiyun };
71*4882a593Smuzhiyun 
72*4882a593Smuzhiyun /*
73*4882a593Smuzhiyun  * Count bound interfaces which are not p2p, besides data->ignore_vif.
74*4882a593Smuzhiyun  * data->station_vif will point to one bound vif of type station, if exists.
75*4882a593Smuzhiyun  */
iwl_mvm_bound_iface_iterator(void * _data,u8 * mac,struct ieee80211_vif * vif)76*4882a593Smuzhiyun static void iwl_mvm_bound_iface_iterator(void *_data, u8 *mac,
77*4882a593Smuzhiyun 					 struct ieee80211_vif *vif)
78*4882a593Smuzhiyun {
79*4882a593Smuzhiyun 	struct iwl_mvm_active_iface_iterator_data *data = _data;
80*4882a593Smuzhiyun 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
81*4882a593Smuzhiyun 
82*4882a593Smuzhiyun 	if (vif == data->ignore_vif || !mvmvif->phy_ctxt ||
83*4882a593Smuzhiyun 	    vif->type == NL80211_IFTYPE_P2P_DEVICE)
84*4882a593Smuzhiyun 		return;
85*4882a593Smuzhiyun 
86*4882a593Smuzhiyun 	data->num_active_macs++;
87*4882a593Smuzhiyun 
88*4882a593Smuzhiyun 	if (vif->type == NL80211_IFTYPE_STATION) {
89*4882a593Smuzhiyun 		data->sta_vif_ap_sta_id = mvmvif->ap_sta_id;
90*4882a593Smuzhiyun 		if (vif->bss_conf.assoc)
91*4882a593Smuzhiyun 			data->sta_vif_state = SF_FULL_ON;
92*4882a593Smuzhiyun 		else
93*4882a593Smuzhiyun 			data->sta_vif_state = SF_INIT_OFF;
94*4882a593Smuzhiyun 	}
95*4882a593Smuzhiyun }
96*4882a593Smuzhiyun 
97*4882a593Smuzhiyun /*
98*4882a593Smuzhiyun  * Aging and idle timeouts for the different possible scenarios
99*4882a593Smuzhiyun  * in default configuration
100*4882a593Smuzhiyun  */
101*4882a593Smuzhiyun static const
102*4882a593Smuzhiyun __le32 sf_full_timeout_def[SF_NUM_SCENARIO][SF_NUM_TIMEOUT_TYPES] = {
103*4882a593Smuzhiyun 	{
104*4882a593Smuzhiyun 		cpu_to_le32(SF_SINGLE_UNICAST_AGING_TIMER_DEF),
105*4882a593Smuzhiyun 		cpu_to_le32(SF_SINGLE_UNICAST_IDLE_TIMER_DEF)
106*4882a593Smuzhiyun 	},
107*4882a593Smuzhiyun 	{
108*4882a593Smuzhiyun 		cpu_to_le32(SF_AGG_UNICAST_AGING_TIMER_DEF),
109*4882a593Smuzhiyun 		cpu_to_le32(SF_AGG_UNICAST_IDLE_TIMER_DEF)
110*4882a593Smuzhiyun 	},
111*4882a593Smuzhiyun 	{
112*4882a593Smuzhiyun 		cpu_to_le32(SF_MCAST_AGING_TIMER_DEF),
113*4882a593Smuzhiyun 		cpu_to_le32(SF_MCAST_IDLE_TIMER_DEF)
114*4882a593Smuzhiyun 	},
115*4882a593Smuzhiyun 	{
116*4882a593Smuzhiyun 		cpu_to_le32(SF_BA_AGING_TIMER_DEF),
117*4882a593Smuzhiyun 		cpu_to_le32(SF_BA_IDLE_TIMER_DEF)
118*4882a593Smuzhiyun 	},
119*4882a593Smuzhiyun 	{
120*4882a593Smuzhiyun 		cpu_to_le32(SF_TX_RE_AGING_TIMER_DEF),
121*4882a593Smuzhiyun 		cpu_to_le32(SF_TX_RE_IDLE_TIMER_DEF)
122*4882a593Smuzhiyun 	},
123*4882a593Smuzhiyun };
124*4882a593Smuzhiyun 
125*4882a593Smuzhiyun /*
126*4882a593Smuzhiyun  * Aging and idle timeouts for the different possible scenarios
127*4882a593Smuzhiyun  * in single BSS MAC configuration.
128*4882a593Smuzhiyun  */
129*4882a593Smuzhiyun static const __le32 sf_full_timeout[SF_NUM_SCENARIO][SF_NUM_TIMEOUT_TYPES] = {
130*4882a593Smuzhiyun 	{
131*4882a593Smuzhiyun 		cpu_to_le32(SF_SINGLE_UNICAST_AGING_TIMER),
132*4882a593Smuzhiyun 		cpu_to_le32(SF_SINGLE_UNICAST_IDLE_TIMER)
133*4882a593Smuzhiyun 	},
134*4882a593Smuzhiyun 	{
135*4882a593Smuzhiyun 		cpu_to_le32(SF_AGG_UNICAST_AGING_TIMER),
136*4882a593Smuzhiyun 		cpu_to_le32(SF_AGG_UNICAST_IDLE_TIMER)
137*4882a593Smuzhiyun 	},
138*4882a593Smuzhiyun 	{
139*4882a593Smuzhiyun 		cpu_to_le32(SF_MCAST_AGING_TIMER),
140*4882a593Smuzhiyun 		cpu_to_le32(SF_MCAST_IDLE_TIMER)
141*4882a593Smuzhiyun 	},
142*4882a593Smuzhiyun 	{
143*4882a593Smuzhiyun 		cpu_to_le32(SF_BA_AGING_TIMER),
144*4882a593Smuzhiyun 		cpu_to_le32(SF_BA_IDLE_TIMER)
145*4882a593Smuzhiyun 	},
146*4882a593Smuzhiyun 	{
147*4882a593Smuzhiyun 		cpu_to_le32(SF_TX_RE_AGING_TIMER),
148*4882a593Smuzhiyun 		cpu_to_le32(SF_TX_RE_IDLE_TIMER)
149*4882a593Smuzhiyun 	},
150*4882a593Smuzhiyun };
151*4882a593Smuzhiyun 
iwl_mvm_fill_sf_command(struct iwl_mvm * mvm,struct iwl_sf_cfg_cmd * sf_cmd,struct ieee80211_sta * sta)152*4882a593Smuzhiyun static void iwl_mvm_fill_sf_command(struct iwl_mvm *mvm,
153*4882a593Smuzhiyun 				    struct iwl_sf_cfg_cmd *sf_cmd,
154*4882a593Smuzhiyun 				    struct ieee80211_sta *sta)
155*4882a593Smuzhiyun {
156*4882a593Smuzhiyun 	int i, j, watermark;
157*4882a593Smuzhiyun 
158*4882a593Smuzhiyun 	sf_cmd->watermark[SF_LONG_DELAY_ON] = cpu_to_le32(SF_W_MARK_SCAN);
159*4882a593Smuzhiyun 
160*4882a593Smuzhiyun 	/*
161*4882a593Smuzhiyun 	 * If we are in association flow - check antenna configuration
162*4882a593Smuzhiyun 	 * capabilities of the AP station, and choose the watermark accordingly.
163*4882a593Smuzhiyun 	 */
164*4882a593Smuzhiyun 	if (sta) {
165*4882a593Smuzhiyun 		if (sta->ht_cap.ht_supported ||
166*4882a593Smuzhiyun 		    sta->vht_cap.vht_supported ||
167*4882a593Smuzhiyun 		    sta->he_cap.has_he) {
168*4882a593Smuzhiyun 			switch (sta->rx_nss) {
169*4882a593Smuzhiyun 			case 1:
170*4882a593Smuzhiyun 				watermark = SF_W_MARK_SISO;
171*4882a593Smuzhiyun 				break;
172*4882a593Smuzhiyun 			case 2:
173*4882a593Smuzhiyun 				watermark = SF_W_MARK_MIMO2;
174*4882a593Smuzhiyun 				break;
175*4882a593Smuzhiyun 			default:
176*4882a593Smuzhiyun 				watermark = SF_W_MARK_MIMO3;
177*4882a593Smuzhiyun 				break;
178*4882a593Smuzhiyun 			}
179*4882a593Smuzhiyun 		} else {
180*4882a593Smuzhiyun 			watermark = SF_W_MARK_LEGACY;
181*4882a593Smuzhiyun 		}
182*4882a593Smuzhiyun 	/* default watermark value for unassociated mode. */
183*4882a593Smuzhiyun 	} else {
184*4882a593Smuzhiyun 		watermark = SF_W_MARK_MIMO2;
185*4882a593Smuzhiyun 	}
186*4882a593Smuzhiyun 	sf_cmd->watermark[SF_FULL_ON] = cpu_to_le32(watermark);
187*4882a593Smuzhiyun 
188*4882a593Smuzhiyun 	for (i = 0; i < SF_NUM_SCENARIO; i++) {
189*4882a593Smuzhiyun 		for (j = 0; j < SF_NUM_TIMEOUT_TYPES; j++) {
190*4882a593Smuzhiyun 			sf_cmd->long_delay_timeouts[i][j] =
191*4882a593Smuzhiyun 					cpu_to_le32(SF_LONG_DELAY_AGING_TIMER);
192*4882a593Smuzhiyun 		}
193*4882a593Smuzhiyun 	}
194*4882a593Smuzhiyun 
195*4882a593Smuzhiyun 	if (sta) {
196*4882a593Smuzhiyun 		BUILD_BUG_ON(sizeof(sf_full_timeout) !=
197*4882a593Smuzhiyun 			     sizeof(__le32) * SF_NUM_SCENARIO *
198*4882a593Smuzhiyun 			     SF_NUM_TIMEOUT_TYPES);
199*4882a593Smuzhiyun 
200*4882a593Smuzhiyun 		memcpy(sf_cmd->full_on_timeouts, sf_full_timeout,
201*4882a593Smuzhiyun 		       sizeof(sf_full_timeout));
202*4882a593Smuzhiyun 	} else {
203*4882a593Smuzhiyun 		BUILD_BUG_ON(sizeof(sf_full_timeout_def) !=
204*4882a593Smuzhiyun 			     sizeof(__le32) * SF_NUM_SCENARIO *
205*4882a593Smuzhiyun 			     SF_NUM_TIMEOUT_TYPES);
206*4882a593Smuzhiyun 
207*4882a593Smuzhiyun 		memcpy(sf_cmd->full_on_timeouts, sf_full_timeout_def,
208*4882a593Smuzhiyun 		       sizeof(sf_full_timeout_def));
209*4882a593Smuzhiyun 	}
210*4882a593Smuzhiyun 
211*4882a593Smuzhiyun }
212*4882a593Smuzhiyun 
iwl_mvm_sf_config(struct iwl_mvm * mvm,u8 sta_id,enum iwl_sf_state new_state)213*4882a593Smuzhiyun static int iwl_mvm_sf_config(struct iwl_mvm *mvm, u8 sta_id,
214*4882a593Smuzhiyun 			     enum iwl_sf_state new_state)
215*4882a593Smuzhiyun {
216*4882a593Smuzhiyun 	struct iwl_sf_cfg_cmd sf_cmd = {
217*4882a593Smuzhiyun 		.state = cpu_to_le32(new_state),
218*4882a593Smuzhiyun 	};
219*4882a593Smuzhiyun 	struct ieee80211_sta *sta;
220*4882a593Smuzhiyun 	int ret = 0;
221*4882a593Smuzhiyun 
222*4882a593Smuzhiyun 	if (mvm->cfg->disable_dummy_notification)
223*4882a593Smuzhiyun 		sf_cmd.state |= cpu_to_le32(SF_CFG_DUMMY_NOTIF_OFF);
224*4882a593Smuzhiyun 
225*4882a593Smuzhiyun 	/*
226*4882a593Smuzhiyun 	 * If an associated AP sta changed its antenna configuration, the state
227*4882a593Smuzhiyun 	 * will remain FULL_ON but SF parameters need to be reconsidered.
228*4882a593Smuzhiyun 	 */
229*4882a593Smuzhiyun 	if (new_state != SF_FULL_ON && mvm->sf_state == new_state)
230*4882a593Smuzhiyun 		return 0;
231*4882a593Smuzhiyun 
232*4882a593Smuzhiyun 	switch (new_state) {
233*4882a593Smuzhiyun 	case SF_UNINIT:
234*4882a593Smuzhiyun 		iwl_mvm_fill_sf_command(mvm, &sf_cmd, NULL);
235*4882a593Smuzhiyun 		break;
236*4882a593Smuzhiyun 	case SF_FULL_ON:
237*4882a593Smuzhiyun 		if (sta_id == IWL_MVM_INVALID_STA) {
238*4882a593Smuzhiyun 			IWL_ERR(mvm,
239*4882a593Smuzhiyun 				"No station: Cannot switch SF to FULL_ON\n");
240*4882a593Smuzhiyun 			return -EINVAL;
241*4882a593Smuzhiyun 		}
242*4882a593Smuzhiyun 		rcu_read_lock();
243*4882a593Smuzhiyun 		sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]);
244*4882a593Smuzhiyun 		if (IS_ERR_OR_NULL(sta)) {
245*4882a593Smuzhiyun 			IWL_ERR(mvm, "Invalid station id\n");
246*4882a593Smuzhiyun 			rcu_read_unlock();
247*4882a593Smuzhiyun 			return -EINVAL;
248*4882a593Smuzhiyun 		}
249*4882a593Smuzhiyun 		iwl_mvm_fill_sf_command(mvm, &sf_cmd, sta);
250*4882a593Smuzhiyun 		rcu_read_unlock();
251*4882a593Smuzhiyun 		break;
252*4882a593Smuzhiyun 	case SF_INIT_OFF:
253*4882a593Smuzhiyun 		iwl_mvm_fill_sf_command(mvm, &sf_cmd, NULL);
254*4882a593Smuzhiyun 		break;
255*4882a593Smuzhiyun 	default:
256*4882a593Smuzhiyun 		WARN_ONCE(1, "Invalid state: %d. not sending Smart Fifo cmd\n",
257*4882a593Smuzhiyun 			  new_state);
258*4882a593Smuzhiyun 		return -EINVAL;
259*4882a593Smuzhiyun 	}
260*4882a593Smuzhiyun 
261*4882a593Smuzhiyun 	ret = iwl_mvm_send_cmd_pdu(mvm, REPLY_SF_CFG_CMD, CMD_ASYNC,
262*4882a593Smuzhiyun 				   sizeof(sf_cmd), &sf_cmd);
263*4882a593Smuzhiyun 	if (!ret)
264*4882a593Smuzhiyun 		mvm->sf_state = new_state;
265*4882a593Smuzhiyun 
266*4882a593Smuzhiyun 	return ret;
267*4882a593Smuzhiyun }
268*4882a593Smuzhiyun 
269*4882a593Smuzhiyun /*
270*4882a593Smuzhiyun  * Update Smart fifo:
271*4882a593Smuzhiyun  * Count bound interfaces that are not to be removed, ignoring p2p devices,
272*4882a593Smuzhiyun  * and set new state accordingly.
273*4882a593Smuzhiyun  */
iwl_mvm_sf_update(struct iwl_mvm * mvm,struct ieee80211_vif * changed_vif,bool remove_vif)274*4882a593Smuzhiyun int iwl_mvm_sf_update(struct iwl_mvm *mvm, struct ieee80211_vif *changed_vif,
275*4882a593Smuzhiyun 		      bool remove_vif)
276*4882a593Smuzhiyun {
277*4882a593Smuzhiyun 	enum iwl_sf_state new_state;
278*4882a593Smuzhiyun 	u8 sta_id = IWL_MVM_INVALID_STA;
279*4882a593Smuzhiyun 	struct iwl_mvm_vif *mvmvif = NULL;
280*4882a593Smuzhiyun 	struct iwl_mvm_active_iface_iterator_data data = {
281*4882a593Smuzhiyun 		.ignore_vif = changed_vif,
282*4882a593Smuzhiyun 		.sta_vif_state = SF_UNINIT,
283*4882a593Smuzhiyun 		.sta_vif_ap_sta_id = IWL_MVM_INVALID_STA,
284*4882a593Smuzhiyun 	};
285*4882a593Smuzhiyun 
286*4882a593Smuzhiyun 	/*
287*4882a593Smuzhiyun 	 * Ignore the call if we are in HW Restart flow, or if the handled
288*4882a593Smuzhiyun 	 * vif is a p2p device.
289*4882a593Smuzhiyun 	 */
290*4882a593Smuzhiyun 	if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status) ||
291*4882a593Smuzhiyun 	    (changed_vif && changed_vif->type == NL80211_IFTYPE_P2P_DEVICE))
292*4882a593Smuzhiyun 		return 0;
293*4882a593Smuzhiyun 
294*4882a593Smuzhiyun 	ieee80211_iterate_active_interfaces_atomic(mvm->hw,
295*4882a593Smuzhiyun 						   IEEE80211_IFACE_ITER_NORMAL,
296*4882a593Smuzhiyun 						   iwl_mvm_bound_iface_iterator,
297*4882a593Smuzhiyun 						   &data);
298*4882a593Smuzhiyun 
299*4882a593Smuzhiyun 	/* If changed_vif exists and is not to be removed, add to the count */
300*4882a593Smuzhiyun 	if (changed_vif && !remove_vif)
301*4882a593Smuzhiyun 		data.num_active_macs++;
302*4882a593Smuzhiyun 
303*4882a593Smuzhiyun 	switch (data.num_active_macs) {
304*4882a593Smuzhiyun 	case 0:
305*4882a593Smuzhiyun 		/* If there are no active macs - change state to SF_INIT_OFF */
306*4882a593Smuzhiyun 		new_state = SF_INIT_OFF;
307*4882a593Smuzhiyun 		break;
308*4882a593Smuzhiyun 	case 1:
309*4882a593Smuzhiyun 		if (remove_vif) {
310*4882a593Smuzhiyun 			/* The one active mac left is of type station
311*4882a593Smuzhiyun 			 * and we filled the relevant data during iteration
312*4882a593Smuzhiyun 			 */
313*4882a593Smuzhiyun 			new_state = data.sta_vif_state;
314*4882a593Smuzhiyun 			sta_id = data.sta_vif_ap_sta_id;
315*4882a593Smuzhiyun 		} else {
316*4882a593Smuzhiyun 			if (WARN_ON(!changed_vif))
317*4882a593Smuzhiyun 				return -EINVAL;
318*4882a593Smuzhiyun 			if (changed_vif->type != NL80211_IFTYPE_STATION) {
319*4882a593Smuzhiyun 				new_state = SF_UNINIT;
320*4882a593Smuzhiyun 			} else if (changed_vif->bss_conf.assoc &&
321*4882a593Smuzhiyun 				   changed_vif->bss_conf.dtim_period) {
322*4882a593Smuzhiyun 				mvmvif = iwl_mvm_vif_from_mac80211(changed_vif);
323*4882a593Smuzhiyun 				sta_id = mvmvif->ap_sta_id;
324*4882a593Smuzhiyun 				new_state = SF_FULL_ON;
325*4882a593Smuzhiyun 			} else {
326*4882a593Smuzhiyun 				new_state = SF_INIT_OFF;
327*4882a593Smuzhiyun 			}
328*4882a593Smuzhiyun 		}
329*4882a593Smuzhiyun 		break;
330*4882a593Smuzhiyun 	default:
331*4882a593Smuzhiyun 		/* If there are multiple active macs - change to SF_UNINIT */
332*4882a593Smuzhiyun 		new_state = SF_UNINIT;
333*4882a593Smuzhiyun 	}
334*4882a593Smuzhiyun 	return iwl_mvm_sf_config(mvm, sta_id, new_state);
335*4882a593Smuzhiyun }
336