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