]> Git Repo - J-linux.git/blob - drivers/net/wireless/intel/iwlwifi/mvm/sf.c
Merge tag 'vfs-6.13-rc7.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs
[J-linux.git] / drivers / net / wireless / intel / iwlwifi / mvm / sf.c
1 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
2 /*
3  * Copyright (C) 2013-2014, 2018-2019, 2022-2024 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         struct ieee80211_sta *sta_vif_ap_sta;
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  */
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->deflink.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 = mvmvif->ap_sta;
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
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         u8 max_rx_nss = 0;
102         bool is_legacy = true;
103         struct ieee80211_link_sta *link_sta;
104         unsigned int link_id;
105
106         sf_cmd->watermark[SF_LONG_DELAY_ON] = cpu_to_le32(SF_W_MARK_SCAN);
107
108         /*
109          * If we are in association flow - check antenna configuration
110          * capabilities of the AP station, and choose the watermark accordingly.
111          */
112         if (sta) {
113                 /* find the maximal NSS number among all links (if relevant) */
114                 rcu_read_lock();
115                 for (link_id = 0; link_id < ARRAY_SIZE(sta->link); link_id++) {
116                         link_sta = rcu_dereference(sta->link[link_id]);
117                         if (!link_sta)
118                                 continue;
119
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) {
124                                 is_legacy = false;
125                                 max_rx_nss = max(max_rx_nss, link_sta->rx_nss);
126                         }
127                 }
128                 rcu_read_unlock();
129
130                 if (!is_legacy) {
131                         switch (max_rx_nss) {
132                         case 1:
133                                 watermark = SF_W_MARK_SISO;
134                                 break;
135                         case 2:
136                                 watermark = SF_W_MARK_MIMO2;
137                                 break;
138                         default:
139                                 watermark = SF_W_MARK_MIMO3;
140                                 break;
141                         }
142                 } else {
143                         watermark = SF_W_MARK_LEGACY;
144                 }
145         /* default watermark value for unassociated mode. */
146         } else {
147                 watermark = SF_W_MARK_MIMO2;
148         }
149         sf_cmd->watermark[SF_FULL_ON] = cpu_to_le32(watermark);
150
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);
155                 }
156         }
157
158         if (sta) {
159                 BUILD_BUG_ON(sizeof(sf_full_timeout) !=
160                              sizeof(__le32) * SF_NUM_SCENARIO *
161                              SF_NUM_TIMEOUT_TYPES);
162
163                 memcpy(sf_cmd->full_on_timeouts, sf_full_timeout,
164                        sizeof(sf_full_timeout));
165         } else {
166                 BUILD_BUG_ON(sizeof(sf_full_timeout_def) !=
167                              sizeof(__le32) * SF_NUM_SCENARIO *
168                              SF_NUM_TIMEOUT_TYPES);
169
170                 memcpy(sf_cmd->full_on_timeouts, sf_full_timeout_def,
171                        sizeof(sf_full_timeout_def));
172         }
173 }
174
175 static int iwl_mvm_sf_config(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
176                              enum iwl_sf_state new_state)
177 {
178         struct iwl_sf_cfg_cmd sf_cmd = {
179                 .state = cpu_to_le32(new_state),
180         };
181         int ret = 0;
182
183         /*
184          * If an associated AP sta changed its antenna configuration, the state
185          * will remain FULL_ON but SF parameters need to be reconsidered.
186          */
187         if (new_state != SF_FULL_ON && mvm->sf_state == new_state)
188                 return 0;
189
190         switch (new_state) {
191         case SF_UNINIT:
192                 iwl_mvm_fill_sf_command(mvm, &sf_cmd, NULL);
193                 break;
194         case SF_FULL_ON:
195                 if (!sta) {
196                         IWL_ERR(mvm,
197                                 "No station: Cannot switch SF to FULL_ON\n");
198                         return -EINVAL;
199                 }
200                 iwl_mvm_fill_sf_command(mvm, &sf_cmd, sta);
201                 break;
202         case SF_INIT_OFF:
203                 iwl_mvm_fill_sf_command(mvm, &sf_cmd, NULL);
204                 break;
205         default:
206                 WARN_ONCE(1, "Invalid state: %d. not sending Smart Fifo cmd\n",
207                           new_state);
208                 return -EINVAL;
209         }
210
211         ret = iwl_mvm_send_cmd_pdu(mvm, REPLY_SF_CFG_CMD, CMD_ASYNC,
212                                    sizeof(sf_cmd), &sf_cmd);
213         if (!ret)
214                 mvm->sf_state = new_state;
215
216         return ret;
217 }
218
219 /*
220  * Update Smart fifo:
221  * Count bound interfaces that are not to be removed, ignoring p2p devices,
222  * and set new state accordingly.
223  */
224 int iwl_mvm_sf_update(struct iwl_mvm *mvm, struct ieee80211_vif *changed_vif,
225                       bool remove_vif)
226 {
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,
232         };
233         struct ieee80211_sta *sta = NULL;
234
235         if (fw_has_api(&mvm->fw->ucode_capa,
236                        IWL_UCODE_TLV_API_SMART_FIFO_OFFLOAD))
237                 return 0;
238         /*
239          * Ignore the call if we are in HW Restart flow, or if the handled
240          * vif is a p2p device.
241          */
242         if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status) ||
243             (changed_vif && changed_vif->type == NL80211_IFTYPE_P2P_DEVICE))
244                 return 0;
245
246         ieee80211_iterate_active_interfaces_atomic(mvm->hw,
247                                                    IEEE80211_IFACE_ITER_NORMAL,
248                                                    iwl_mvm_bound_iface_iterator,
249                                                    &data);
250
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++;
254
255         switch (data.num_active_macs) {
256         case 0:
257                 /* If there are no active macs - change state to SF_INIT_OFF */
258                 new_state = SF_INIT_OFF;
259                 break;
260         case 1:
261                 if (remove_vif) {
262                         /* The one active mac left is of type station
263                          * and we filled the relevant data during iteration
264                          */
265                         new_state = data.sta_vif_state;
266                         sta = data.sta_vif_ap_sta;
267                 } else {
268                         if (WARN_ON(!changed_vif))
269                                 return -EINVAL;
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;
277                         } else {
278                                 new_state = SF_INIT_OFF;
279                         }
280                 }
281                 break;
282         default:
283                 /* If there are multiple active macs - change to SF_UNINIT */
284                 new_state = SF_UNINIT;
285         }
286
287         return iwl_mvm_sf_config(mvm, sta, new_state);
288 }
This page took 0.04294 seconds and 4 git commands to generate.