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