1 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
3 * Copyright (C) 2013-2014, 2018-2019, 2022-2024 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
;
11 struct ieee80211_sta
*sta_vif_ap_sta
;
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
->deflink
.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
= mvmvif
->ap_sta
;
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 bool is_legacy
= true;
103 struct ieee80211_link_sta
*link_sta
;
104 unsigned int link_id
;
106 sf_cmd
->watermark
[SF_LONG_DELAY_ON
] = cpu_to_le32(SF_W_MARK_SCAN
);
109 * If we are in association flow - check antenna configuration
110 * capabilities of the AP station, and choose the watermark accordingly.
113 /* find the maximal NSS number among all links (if relevant) */
115 for (link_id
= 0; link_id
< ARRAY_SIZE(sta
->link
); link_id
++) {
116 link_sta
= rcu_dereference(sta
->link
[link_id
]);
120 if (link_sta
->ht_cap
.ht_supported
||
121 link_sta
->vht_cap
.vht_supported
||
122 link_sta
->eht_cap
.has_eht
||
123 link_sta
->he_cap
.has_he
) {
125 max_rx_nss
= max(max_rx_nss
, link_sta
->rx_nss
);
131 switch (max_rx_nss
) {
133 watermark
= SF_W_MARK_SISO
;
136 watermark
= SF_W_MARK_MIMO2
;
139 watermark
= SF_W_MARK_MIMO3
;
143 watermark
= SF_W_MARK_LEGACY
;
145 /* default watermark value for unassociated mode. */
147 watermark
= SF_W_MARK_MIMO2
;
149 sf_cmd
->watermark
[SF_FULL_ON
] = cpu_to_le32(watermark
);
151 for (i
= 0; i
< SF_NUM_SCENARIO
; i
++) {
152 for (j
= 0; j
< SF_NUM_TIMEOUT_TYPES
; j
++) {
153 sf_cmd
->long_delay_timeouts
[i
][j
] =
154 cpu_to_le32(SF_LONG_DELAY_AGING_TIMER
);
159 BUILD_BUG_ON(sizeof(sf_full_timeout
) !=
160 sizeof(__le32
) * SF_NUM_SCENARIO
*
161 SF_NUM_TIMEOUT_TYPES
);
163 memcpy(sf_cmd
->full_on_timeouts
, sf_full_timeout
,
164 sizeof(sf_full_timeout
));
166 BUILD_BUG_ON(sizeof(sf_full_timeout_def
) !=
167 sizeof(__le32
) * SF_NUM_SCENARIO
*
168 SF_NUM_TIMEOUT_TYPES
);
170 memcpy(sf_cmd
->full_on_timeouts
, sf_full_timeout_def
,
171 sizeof(sf_full_timeout_def
));
175 static int iwl_mvm_sf_config(struct iwl_mvm
*mvm
, struct ieee80211_sta
*sta
,
176 enum iwl_sf_state new_state
)
178 struct iwl_sf_cfg_cmd sf_cmd
= {
179 .state
= cpu_to_le32(new_state
),
184 * If an associated AP sta changed its antenna configuration, the state
185 * will remain FULL_ON but SF parameters need to be reconsidered.
187 if (new_state
!= SF_FULL_ON
&& mvm
->sf_state
== new_state
)
192 iwl_mvm_fill_sf_command(mvm
, &sf_cmd
, NULL
);
197 "No station: Cannot switch SF to FULL_ON\n");
200 iwl_mvm_fill_sf_command(mvm
, &sf_cmd
, sta
);
203 iwl_mvm_fill_sf_command(mvm
, &sf_cmd
, NULL
);
206 WARN_ONCE(1, "Invalid state: %d. not sending Smart Fifo cmd\n",
211 ret
= iwl_mvm_send_cmd_pdu(mvm
, REPLY_SF_CFG_CMD
, CMD_ASYNC
,
212 sizeof(sf_cmd
), &sf_cmd
);
214 mvm
->sf_state
= new_state
;
221 * Count bound interfaces that are not to be removed, ignoring p2p devices,
222 * and set new state accordingly.
224 int iwl_mvm_sf_update(struct iwl_mvm
*mvm
, struct ieee80211_vif
*changed_vif
,
227 enum iwl_sf_state new_state
;
228 struct iwl_mvm_vif
*mvmvif
= NULL
;
229 struct iwl_mvm_active_iface_iterator_data data
= {
230 .ignore_vif
= changed_vif
,
231 .sta_vif_state
= SF_UNINIT
,
233 struct ieee80211_sta
*sta
= NULL
;
235 if (fw_has_api(&mvm
->fw
->ucode_capa
,
236 IWL_UCODE_TLV_API_SMART_FIFO_OFFLOAD
))
239 * Ignore the call if we are in HW Restart flow, or if the handled
240 * vif is a p2p device.
242 if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART
, &mvm
->status
) ||
243 (changed_vif
&& changed_vif
->type
== NL80211_IFTYPE_P2P_DEVICE
))
246 ieee80211_iterate_active_interfaces_atomic(mvm
->hw
,
247 IEEE80211_IFACE_ITER_NORMAL
,
248 iwl_mvm_bound_iface_iterator
,
251 /* If changed_vif exists and is not to be removed, add to the count */
252 if (changed_vif
&& !remove_vif
)
253 data
.num_active_macs
++;
255 switch (data
.num_active_macs
) {
257 /* If there are no active macs - change state to SF_INIT_OFF */
258 new_state
= SF_INIT_OFF
;
262 /* The one active mac left is of type station
263 * and we filled the relevant data during iteration
265 new_state
= data
.sta_vif_state
;
266 sta
= data
.sta_vif_ap_sta
;
268 if (WARN_ON(!changed_vif
))
270 if (changed_vif
->type
!= NL80211_IFTYPE_STATION
) {
271 new_state
= SF_UNINIT
;
272 } else if (changed_vif
->cfg
.assoc
&&
273 changed_vif
->bss_conf
.dtim_period
) {
274 mvmvif
= iwl_mvm_vif_from_mac80211(changed_vif
);
275 sta
= mvmvif
->ap_sta
;
276 new_state
= SF_FULL_ON
;
278 new_state
= SF_INIT_OFF
;
283 /* If there are multiple active macs - change to SF_UNINIT */
284 new_state
= SF_UNINIT
;
287 return iwl_mvm_sf_config(mvm
, sta
, new_state
);