1 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
2 /*
3 * Copyright (C) 2013-2014, 2018-2019, 2022 Intel Corporation
4 * Copyright (C) 2013-2014 Intel Mobile Communications GmbH
5 */
6 #include "mvm.h"
7
8 /* For counting bound interfaces */
9 struct 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 */
iwl_mvm_bound_iface_iterator(void * _data,u8 * mac,struct ieee80211_vif * vif)20 static 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->cfg.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 */
45 static 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 */
73 static 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
iwl_mvm_fill_sf_command(struct iwl_mvm * mvm,struct iwl_sf_cfg_cmd * sf_cmd,struct ieee80211_sta * sta)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)
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->deflink.ht_cap.ht_supported ||
110 sta->deflink.vht_cap.vht_supported ||
111 sta->deflink.he_cap.has_he) {
112 switch (sta->deflink.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
iwl_mvm_sf_config(struct iwl_mvm * mvm,u8 sta_id,enum iwl_sf_state new_state)157 static 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 */
iwl_mvm_sf_update(struct iwl_mvm * mvm,struct ieee80211_vif * changed_vif,bool remove_vif)218 int 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->cfg.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 }
280