1 /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
2 /*
3 * Copyright (C) 2024-2025 Intel Corporation
4 */
5 #ifndef __iwl_mld_iface_h__
6 #define __iwl_mld_iface_h__
7
8 #include <net/mac80211.h>
9
10 #include "link.h"
11 #include "session-protect.h"
12 #include "d3.h"
13 #include "fw/api/time-event.h"
14
15 enum iwl_mld_cca_40mhz_wa_status {
16 CCA_40_MHZ_WA_NONE,
17 CCA_40_MHZ_WA_RESET,
18 CCA_40_MHZ_WA_RECONNECT,
19 };
20
21 /**
22 * enum iwl_mld_emlsr_blocked - defines reasons for which EMLSR is blocked
23 *
24 * These blocks are applied/stored per-VIF.
25 *
26 * @IWL_MLD_EMLSR_BLOCKED_PREVENTION: Prevent repeated EMLSR enter/exit
27 * @IWL_MLD_EMLSR_BLOCKED_WOWLAN: WOWLAN is preventing EMLSR
28 * @IWL_MLD_EMLSR_BLOCKED_ROC: remain-on-channel is preventing EMLSR
29 * @IWL_MLD_EMLSR_BLOCKED_NON_BSS: An active non-BSS interface's link is
30 * preventing EMLSR
31 * @IWL_MLD_EMLSR_BLOCKED_TMP_NON_BSS: An expected active non-BSS interface's
32 * link is preventing EMLSR. This is a temporary blocking that is set when
33 * there is an indication that a non-BSS interface is to be added.
34 * @IWL_MLD_EMLSR_BLOCKED_TPT: throughput is too low to make EMLSR worthwhile
35 */
36 enum iwl_mld_emlsr_blocked {
37 IWL_MLD_EMLSR_BLOCKED_PREVENTION = 0x1,
38 IWL_MLD_EMLSR_BLOCKED_WOWLAN = 0x2,
39 IWL_MLD_EMLSR_BLOCKED_ROC = 0x4,
40 IWL_MLD_EMLSR_BLOCKED_NON_BSS = 0x8,
41 IWL_MLD_EMLSR_BLOCKED_TMP_NON_BSS = 0x10,
42 IWL_MLD_EMLSR_BLOCKED_TPT = 0x20,
43 };
44
45 /**
46 * enum iwl_mld_emlsr_exit - defines reasons for exiting EMLSR
47 *
48 * Reasons to exit EMLSR may be either link specific or even specific to a
49 * combination of links.
50 *
51 * @IWL_MLD_EMLSR_EXIT_BLOCK: Exit due to a block reason being set
52 * @IWL_MLD_EMLSR_EXIT_MISSED_BEACON: Exit due to missed beacons
53 * @IWL_MLD_EMLSR_EXIT_FAIL_ENTRY: FW failed to enter EMLSR
54 * @IWL_MLD_EMLSR_EXIT_CSA: EMLSR prevented due to channel switch on link
55 * @IWL_MLD_EMLSR_EXIT_EQUAL_BAND: EMLSR prevented as both links share the band
56 * @IWL_MLD_EMLSR_EXIT_LOW_RSSI: Link RSSI is unsuitable for EMLSR
57 * @IWL_MLD_EMLSR_EXIT_LINK_USAGE: Exit EMLSR due to low TPT on secondary link
58 * @IWL_MLD_EMLSR_EXIT_BT_COEX: Exit EMLSR due to BT coexistence
59 * @IWL_MLD_EMLSR_EXIT_CHAN_LOAD: Exit EMLSR because the primary channel is not
60 * loaded enough to justify EMLSR.
61 * @IWL_MLD_EMLSR_EXIT_RFI: Exit EMLSR due to RFI
62 * @IWL_MLD_EMLSR_EXIT_FW_REQUEST: Exit EMLSR because the FW requested it
63 * @IWL_MLD_EMLSR_EXIT_INVALID: internal exit reason due to invalid data
64 */
65 enum iwl_mld_emlsr_exit {
66 IWL_MLD_EMLSR_EXIT_BLOCK = 0x1,
67 IWL_MLD_EMLSR_EXIT_MISSED_BEACON = 0x2,
68 IWL_MLD_EMLSR_EXIT_FAIL_ENTRY = 0x4,
69 IWL_MLD_EMLSR_EXIT_CSA = 0x8,
70 IWL_MLD_EMLSR_EXIT_EQUAL_BAND = 0x10,
71 IWL_MLD_EMLSR_EXIT_LOW_RSSI = 0x20,
72 IWL_MLD_EMLSR_EXIT_LINK_USAGE = 0x40,
73 IWL_MLD_EMLSR_EXIT_BT_COEX = 0x80,
74 IWL_MLD_EMLSR_EXIT_CHAN_LOAD = 0x100,
75 IWL_MLD_EMLSR_EXIT_RFI = 0x200,
76 IWL_MLD_EMLSR_EXIT_FW_REQUEST = 0x400,
77 IWL_MLD_EMLSR_EXIT_INVALID = 0x800,
78 };
79
80 /**
81 * struct iwl_mld_emlsr - per-VIF data about EMLSR operation
82 *
83 * @primary: The current primary link
84 * @selected_primary: Primary link as selected during the last link selection
85 * @selected_links: Links as selected during the last link selection
86 * @blocked_reasons: Reasons preventing EMLSR from being enabled
87 * @last_exit_reason: Reason for the last EMLSR exit
88 * @last_exit_ts: Time of the last EMLSR exit (if @last_exit_reason is non-zero)
89 * @exit_repeat_count: Number of times EMLSR was exited for the same reason
90 * @unblock_tpt_wk: Unblock EMLSR because the throughput limit was reached
91 * @check_tpt_wk: a worker to check if IWL_MLD_EMLSR_BLOCKED_TPT should be
92 * added, for example if there is no longer enough traffic.
93 * @prevent_done_wk: Worker to remove %IWL_MLD_EMLSR_BLOCKED_PREVENTION
94 * @tmp_non_bss_done_wk: Worker to remove %IWL_MLD_EMLSR_BLOCKED_TMP_NON_BSS
95 */
96 struct iwl_mld_emlsr {
97 struct_group(zeroed_on_not_authorized,
98 u8 primary;
99
100 u8 selected_primary;
101 u16 selected_links;
102
103 enum iwl_mld_emlsr_blocked blocked_reasons;
104
105 enum iwl_mld_emlsr_exit last_exit_reason;
106 unsigned long last_exit_ts;
107 u8 exit_repeat_count;
108 );
109
110 struct wiphy_work unblock_tpt_wk;
111 struct wiphy_delayed_work check_tpt_wk;
112
113 struct wiphy_delayed_work prevent_done_wk;
114 struct wiphy_delayed_work tmp_non_bss_done_wk;
115 };
116
117 /**
118 * struct iwl_mld_vif - virtual interface (MAC context) configuration parameters
119 *
120 * @fw_id: fw id of the mac context.
121 * @session_protect: session protection parameters
122 * @ap_sta: pointer to AP sta, for easier access to it.
123 * Relevant only for STA vifs.
124 * @authorized: indicates the AP station was set to authorized
125 * @bigtks: BIGTKs of the AP, for beacon protection.
126 * Only valid for STA. (FIXME: needs to be per link)
127 * @num_associated_stas: number of associated STAs. Relevant only for AP mode.
128 * @ap_ibss_active: whether the AP/IBSS was started
129 * @cca_40mhz_workaround: When we are connected in 2.4 GHz and 40 MHz, and the
130 * environment is too loaded, we work around this by reconnecting to the
131 * same AP with 20 MHz. This manages the status of the workaround.
132 * @beacon_inject_active: indicates an active debugfs beacon ie injection
133 * @low_latency_causes: bit flags, indicating the causes for low-latency,
134 * see @iwl_mld_low_latency_cause.
135 * @ps_disabled: indicates that PS is disabled for this interface
136 * @mld: pointer to the mld structure.
137 * @deflink: default link data, for use in non-MLO,
138 * @link: reference to link data for each valid link, for use in MLO.
139 * @emlsr: information related to EMLSR
140 * @wowlan_data: data used by the wowlan suspend flow
141 * @use_ps_poll: use ps_poll frames
142 * @disable_bf: disable beacon filter
143 * @dbgfs_slink: debugfs symlink for this interface
144 * @roc_activity: the id of the roc_activity running. Relevant for STA and
145 * p2p device only. Set to %ROC_NUM_ACTIVITIES when not in use.
146 * @aux_sta: station used for remain on channel. Used in P2P device.
147 */
148 struct iwl_mld_vif {
149 /* Add here fields that need clean up on restart */
150 struct_group(zeroed_on_hw_restart,
151 u8 fw_id;
152 struct iwl_mld_session_protect session_protect;
153 struct ieee80211_sta *ap_sta;
154 bool authorized;
155 struct ieee80211_key_conf __rcu *bigtks[2];
156 u8 num_associated_stas;
157 bool ap_ibss_active;
158 enum iwl_mld_cca_40mhz_wa_status cca_40mhz_workaround;
159 #ifdef CONFIG_IWLWIFI_DEBUGFS
160 bool beacon_inject_active;
161 #endif
162 u8 low_latency_causes;
163 bool ps_disabled;
164 );
165 /* And here fields that survive a fw restart */
166 struct iwl_mld *mld;
167 struct iwl_mld_link deflink;
168 struct iwl_mld_link __rcu *link[IEEE80211_MLD_MAX_NUM_LINKS];
169
170 struct iwl_mld_emlsr emlsr;
171
172 #ifdef CONFIG_PM_SLEEP
173 struct iwl_mld_wowlan_data wowlan_data;
174 #endif
175 #ifdef CONFIG_IWLWIFI_DEBUGFS
176 bool use_ps_poll;
177 bool disable_bf;
178 struct dentry *dbgfs_slink;
179 #endif
180 enum iwl_roc_activity roc_activity;
181 struct iwl_mld_int_sta aux_sta;
182 };
183
184 static inline struct iwl_mld_vif *
iwl_mld_vif_from_mac80211(struct ieee80211_vif * vif)185 iwl_mld_vif_from_mac80211(struct ieee80211_vif *vif)
186 {
187 return (void *)vif->drv_priv;
188 }
189
190 #define iwl_mld_link_dereference_check(mld_vif, link_id) \
191 rcu_dereference_check((mld_vif)->link[link_id], \
192 lockdep_is_held(&mld_vif->mld->wiphy->mtx))
193
194 #define for_each_mld_vif_valid_link(mld_vif, mld_link) \
195 for (int link_id = 0; link_id < ARRAY_SIZE((mld_vif)->link); \
196 link_id++) \
197 if ((mld_link = iwl_mld_link_dereference_check(mld_vif, link_id)))
198
199 /* Retrieve pointer to mld link from mac80211 structures */
200 static inline struct iwl_mld_link *
iwl_mld_link_from_mac80211(struct ieee80211_bss_conf * bss_conf)201 iwl_mld_link_from_mac80211(struct ieee80211_bss_conf *bss_conf)
202 {
203 struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(bss_conf->vif);
204
205 return iwl_mld_link_dereference_check(mld_vif, bss_conf->link_id);
206 }
207
208 int iwl_mld_mac80211_iftype_to_fw(const struct ieee80211_vif *vif);
209
210 /* Cleanup function for struct iwl_mld_vif, will be called in restart */
211 void iwl_mld_cleanup_vif(void *data, u8 *mac, struct ieee80211_vif *vif);
212 int iwl_mld_mac_fw_action(struct iwl_mld *mld, struct ieee80211_vif *vif,
213 u32 action);
214 int iwl_mld_add_vif(struct iwl_mld *mld, struct ieee80211_vif *vif);
215 int iwl_mld_rm_vif(struct iwl_mld *mld, struct ieee80211_vif *vif);
216 void iwl_mld_set_vif_associated(struct iwl_mld *mld,
217 struct ieee80211_vif *vif);
218 u8 iwl_mld_get_fw_bss_vifs_ids(struct iwl_mld *mld);
219 void iwl_mld_handle_probe_resp_data_notif(struct iwl_mld *mld,
220 struct iwl_rx_packet *pkt);
221
222 void iwl_mld_handle_datapath_monitor_notif(struct iwl_mld *mld,
223 struct iwl_rx_packet *pkt);
224
225 void iwl_mld_handle_uapsd_misbehaving_ap_notif(struct iwl_mld *mld,
226 struct iwl_rx_packet *pkt);
227
228 void iwl_mld_reset_cca_40mhz_workaround(struct iwl_mld *mld,
229 struct ieee80211_vif *vif);
230
iwl_mld_vif_low_latency(const struct iwl_mld_vif * mld_vif)231 static inline bool iwl_mld_vif_low_latency(const struct iwl_mld_vif *mld_vif)
232 {
233 return !!mld_vif->low_latency_causes;
234 }
235
236 struct ieee80211_vif *iwl_mld_get_bss_vif(struct iwl_mld *mld);
237
238 #endif /* __iwl_mld_iface_h__ */
239