1 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
3 * Copyright (C) 2013-2014, 2018-2019 Intel Corporation
4 * Copyright (C) 2013-2014 Intel Mobile Communications GmbH
8 /* For counting bound interfaces */
9 struct iwl_mvm_active_iface_iterator_data
{
10 struct ieee80211_vif
*ignore_vif
;
12 enum iwl_sf_state sta_vif_state
;
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.
20 static void iwl_mvm_bound_iface_iterator(void *_data
, u8
*mac
,
21 struct ieee80211_vif
*vif
)
23 struct iwl_mvm_active_iface_iterator_data
*data
= _data
;
24 struct iwl_mvm_vif
*mvmvif
= iwl_mvm_vif_from_mac80211(vif
);
26 if (vif
== data
->ignore_vif
|| !mvmvif
->phy_ctxt
||
27 vif
->type
== NL80211_IFTYPE_P2P_DEVICE
)
30 data
->num_active_macs
++;
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
;
37 data
->sta_vif_state
= SF_INIT_OFF
;
42 * Aging and idle timeouts for the different possible scenarios
43 * in default configuration
46 __le32 sf_full_timeout_def
[SF_NUM_SCENARIO
][SF_NUM_TIMEOUT_TYPES
] = {
48 cpu_to_le32(SF_SINGLE_UNICAST_AGING_TIMER_DEF
),
49 cpu_to_le32(SF_SINGLE_UNICAST_IDLE_TIMER_DEF
)
52 cpu_to_le32(SF_AGG_UNICAST_AGING_TIMER_DEF
),
53 cpu_to_le32(SF_AGG_UNICAST_IDLE_TIMER_DEF
)
56 cpu_to_le32(SF_MCAST_AGING_TIMER_DEF
),
57 cpu_to_le32(SF_MCAST_IDLE_TIMER_DEF
)
60 cpu_to_le32(SF_BA_AGING_TIMER_DEF
),
61 cpu_to_le32(SF_BA_IDLE_TIMER_DEF
)
64 cpu_to_le32(SF_TX_RE_AGING_TIMER_DEF
),
65 cpu_to_le32(SF_TX_RE_IDLE_TIMER_DEF
)
70 * Aging and idle timeouts for the different possible scenarios
71 * in single BSS MAC configuration.
73 static const __le32 sf_full_timeout
[SF_NUM_SCENARIO
][SF_NUM_TIMEOUT_TYPES
] = {
75 cpu_to_le32(SF_SINGLE_UNICAST_AGING_TIMER
),
76 cpu_to_le32(SF_SINGLE_UNICAST_IDLE_TIMER
)
79 cpu_to_le32(SF_AGG_UNICAST_AGING_TIMER
),
80 cpu_to_le32(SF_AGG_UNICAST_IDLE_TIMER
)
83 cpu_to_le32(SF_MCAST_AGING_TIMER
),
84 cpu_to_le32(SF_MCAST_IDLE_TIMER
)
87 cpu_to_le32(SF_BA_AGING_TIMER
),
88 cpu_to_le32(SF_BA_IDLE_TIMER
)
91 cpu_to_le32(SF_TX_RE_AGING_TIMER
),
92 cpu_to_le32(SF_TX_RE_IDLE_TIMER
)
96 static void iwl_mvm_fill_sf_command(struct iwl_mvm
*mvm
,
97 struct iwl_sf_cfg_cmd
*sf_cmd
,
98 struct ieee80211_sta
*sta
)
102 sf_cmd
->watermark
[SF_LONG_DELAY_ON
] = cpu_to_le32(SF_W_MARK_SCAN
);
105 * If we are in association flow - check antenna configuration
106 * capabilities of the AP station, and choose the watermark accordingly.
109 if (sta
->ht_cap
.ht_supported
||
110 sta
->vht_cap
.vht_supported
||
111 sta
->he_cap
.has_he
) {
112 switch (sta
->rx_nss
) {
114 watermark
= SF_W_MARK_SISO
;
117 watermark
= SF_W_MARK_MIMO2
;
120 watermark
= SF_W_MARK_MIMO3
;
124 watermark
= SF_W_MARK_LEGACY
;
126 /* default watermark value for unassociated mode. */
128 watermark
= SF_W_MARK_MIMO2
;
130 sf_cmd
->watermark
[SF_FULL_ON
] = cpu_to_le32(watermark
);
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
);
140 BUILD_BUG_ON(sizeof(sf_full_timeout
) !=
141 sizeof(__le32
) * SF_NUM_SCENARIO
*
142 SF_NUM_TIMEOUT_TYPES
);
144 memcpy(sf_cmd
->full_on_timeouts
, sf_full_timeout
,
145 sizeof(sf_full_timeout
));
147 BUILD_BUG_ON(sizeof(sf_full_timeout_def
) !=
148 sizeof(__le32
) * SF_NUM_SCENARIO
*
149 SF_NUM_TIMEOUT_TYPES
);
151 memcpy(sf_cmd
->full_on_timeouts
, sf_full_timeout_def
,
152 sizeof(sf_full_timeout_def
));
157 static int iwl_mvm_sf_config(struct iwl_mvm
*mvm
, u8 sta_id
,
158 enum iwl_sf_state new_state
)
160 struct iwl_sf_cfg_cmd sf_cmd
= {
161 .state
= cpu_to_le32(new_state
),
163 struct ieee80211_sta
*sta
;
166 if (mvm
->cfg
->disable_dummy_notification
)
167 sf_cmd
.state
|= cpu_to_le32(SF_CFG_DUMMY_NOTIF_OFF
);
170 * If an associated AP sta changed its antenna configuration, the state
171 * will remain FULL_ON but SF parameters need to be reconsidered.
173 if (new_state
!= SF_FULL_ON
&& mvm
->sf_state
== new_state
)
178 iwl_mvm_fill_sf_command(mvm
, &sf_cmd
, NULL
);
181 if (sta_id
== IWL_MVM_INVALID_STA
) {
183 "No station: Cannot switch SF to FULL_ON\n");
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");
193 iwl_mvm_fill_sf_command(mvm
, &sf_cmd
, sta
);
197 iwl_mvm_fill_sf_command(mvm
, &sf_cmd
, NULL
);
200 WARN_ONCE(1, "Invalid state: %d. not sending Smart Fifo cmd\n",
205 ret
= iwl_mvm_send_cmd_pdu(mvm
, REPLY_SF_CFG_CMD
, CMD_ASYNC
,
206 sizeof(sf_cmd
), &sf_cmd
);
208 mvm
->sf_state
= new_state
;
215 * Count bound interfaces that are not to be removed, ignoring p2p devices,
216 * and set new state accordingly.
218 int iwl_mvm_sf_update(struct iwl_mvm
*mvm
, struct ieee80211_vif
*changed_vif
,
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
,
231 * Ignore the call if we are in HW Restart flow, or if the handled
232 * vif is a p2p device.
234 if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART
, &mvm
->status
) ||
235 (changed_vif
&& changed_vif
->type
== NL80211_IFTYPE_P2P_DEVICE
))
238 ieee80211_iterate_active_interfaces_atomic(mvm
->hw
,
239 IEEE80211_IFACE_ITER_NORMAL
,
240 iwl_mvm_bound_iface_iterator
,
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
++;
247 switch (data
.num_active_macs
) {
249 /* If there are no active macs - change state to SF_INIT_OFF */
250 new_state
= SF_INIT_OFF
;
254 /* The one active mac left is of type station
255 * and we filled the relevant data during iteration
257 new_state
= data
.sta_vif_state
;
258 sta_id
= data
.sta_vif_ap_sta_id
;
260 if (WARN_ON(!changed_vif
))
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
;
270 new_state
= SF_INIT_OFF
;
275 /* If there are multiple active macs - change to SF_UNINIT */
276 new_state
= SF_UNINIT
;
278 return iwl_mvm_sf_config(mvm
, sta_id
, new_state
);