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 * @last_entry_ts: the time of the last EMLSR entry (if iwl_mld_emlsr_active() 91 * is true) 92 * @unblock_tpt_wk: Unblock EMLSR because the throughput limit was reached 93 * @check_tpt_wk: a worker to check if IWL_MLD_EMLSR_BLOCKED_TPT should be 94 * added, for example if there is no longer enough traffic. 95 * @prevent_done_wk: Worker to remove %IWL_MLD_EMLSR_BLOCKED_PREVENTION 96 * @tmp_non_bss_done_wk: Worker to remove %IWL_MLD_EMLSR_BLOCKED_TMP_NON_BSS 97 */ 98 struct iwl_mld_emlsr { 99 struct_group(zeroed_on_not_authorized, 100 u8 primary; 101 102 u8 selected_primary; 103 u16 selected_links; 104 105 enum iwl_mld_emlsr_blocked blocked_reasons; 106 107 enum iwl_mld_emlsr_exit last_exit_reason; 108 unsigned long last_exit_ts; 109 u8 exit_repeat_count; 110 unsigned long last_entry_ts; 111 ); 112 113 struct wiphy_work unblock_tpt_wk; 114 struct wiphy_delayed_work check_tpt_wk; 115 116 struct wiphy_delayed_work prevent_done_wk; 117 struct wiphy_delayed_work tmp_non_bss_done_wk; 118 }; 119 120 /** 121 * struct iwl_mld_vif - virtual interface (MAC context) configuration parameters 122 * 123 * @fw_id: fw id of the mac context. 124 * @session_protect: session protection parameters 125 * @ap_sta: pointer to AP sta, for easier access to it. 126 * Relevant only for STA vifs. 127 * @authorized: indicates the AP station was set to authorized 128 * @bigtks: BIGTKs of the AP, for beacon protection. 129 * Only valid for STA. (FIXME: needs to be per link) 130 * @num_associated_stas: number of associated STAs. Relevant only for AP mode. 131 * @ap_ibss_active: whether the AP/IBSS was started 132 * @cca_40mhz_workaround: When we are connected in 2.4 GHz and 40 MHz, and the 133 * environment is too loaded, we work around this by reconnecting to the 134 * same AP with 20 MHz. This manages the status of the workaround. 135 * @beacon_inject_active: indicates an active debugfs beacon ie injection 136 * @low_latency_causes: bit flags, indicating the causes for low-latency, 137 * see @iwl_mld_low_latency_cause. 138 * @ps_disabled: indicates that PS is disabled for this interface 139 * @last_link_activation_time: last time a link was activated, for 140 * deferring MLO scans (to make them more reliable) 141 * @mld: pointer to the mld structure. 142 * @deflink: default link data, for use in non-MLO, 143 * @link: reference to link data for each valid link, for use in MLO. 144 * @emlsr: information related to EMLSR 145 * @wowlan_data: data used by the wowlan suspend flow 146 * @use_ps_poll: use ps_poll frames 147 * @disable_bf: disable beacon filter 148 * @dbgfs_slink: debugfs symlink for this interface 149 * @roc_activity: the id of the roc_activity running. Relevant for STA and 150 * p2p device only. Set to %ROC_NUM_ACTIVITIES when not in use. 151 * @aux_sta: station used for remain on channel. Used in P2P device. 152 * @mlo_scan_start_wk: worker to start a deferred MLO scan 153 */ 154 struct iwl_mld_vif { 155 /* Add here fields that need clean up on restart */ 156 struct_group(zeroed_on_hw_restart, 157 u8 fw_id; 158 struct iwl_mld_session_protect session_protect; 159 struct ieee80211_sta *ap_sta; 160 bool authorized; 161 struct ieee80211_key_conf __rcu *bigtks[2]; 162 u8 num_associated_stas; 163 bool ap_ibss_active; 164 enum iwl_mld_cca_40mhz_wa_status cca_40mhz_workaround; 165 #ifdef CONFIG_IWLWIFI_DEBUGFS 166 bool beacon_inject_active; 167 #endif 168 u8 low_latency_causes; 169 bool ps_disabled; 170 time64_t last_link_activation_time; 171 ); 172 /* And here fields that survive a fw restart */ 173 struct iwl_mld *mld; 174 struct iwl_mld_link deflink; 175 struct iwl_mld_link __rcu *link[IEEE80211_MLD_MAX_NUM_LINKS]; 176 177 struct iwl_mld_emlsr emlsr; 178 179 #ifdef CONFIG_PM_SLEEP 180 struct iwl_mld_wowlan_data wowlan_data; 181 #endif 182 #ifdef CONFIG_IWLWIFI_DEBUGFS 183 bool use_ps_poll; 184 bool disable_bf; 185 struct dentry *dbgfs_slink; 186 #endif 187 enum iwl_roc_activity roc_activity; 188 struct iwl_mld_int_sta aux_sta; 189 190 struct wiphy_delayed_work mlo_scan_start_wk; 191 }; 192 193 static inline struct iwl_mld_vif * 194 iwl_mld_vif_from_mac80211(struct ieee80211_vif *vif) 195 { 196 return (void *)vif->drv_priv; 197 } 198 199 static inline struct ieee80211_vif * 200 iwl_mld_vif_to_mac80211(struct iwl_mld_vif *mld_vif) 201 { 202 return container_of((void *)mld_vif, struct ieee80211_vif, drv_priv); 203 } 204 205 #define iwl_mld_link_dereference_check(mld_vif, link_id) \ 206 rcu_dereference_check((mld_vif)->link[link_id], \ 207 lockdep_is_held(&mld_vif->mld->wiphy->mtx)) 208 209 #define for_each_mld_vif_valid_link(mld_vif, mld_link) \ 210 for (int link_id = 0; link_id < ARRAY_SIZE((mld_vif)->link); \ 211 link_id++) \ 212 if ((mld_link = iwl_mld_link_dereference_check(mld_vif, link_id))) 213 214 /* Retrieve pointer to mld link from mac80211 structures */ 215 static inline struct iwl_mld_link * 216 iwl_mld_link_from_mac80211(struct ieee80211_bss_conf *bss_conf) 217 { 218 struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(bss_conf->vif); 219 220 return iwl_mld_link_dereference_check(mld_vif, bss_conf->link_id); 221 } 222 223 int iwl_mld_mac80211_iftype_to_fw(const struct ieee80211_vif *vif); 224 225 /* Cleanup function for struct iwl_mld_vif, will be called in restart */ 226 void iwl_mld_cleanup_vif(void *data, u8 *mac, struct ieee80211_vif *vif); 227 int iwl_mld_mac_fw_action(struct iwl_mld *mld, struct ieee80211_vif *vif, 228 u32 action); 229 int iwl_mld_add_vif(struct iwl_mld *mld, struct ieee80211_vif *vif); 230 int iwl_mld_rm_vif(struct iwl_mld *mld, struct ieee80211_vif *vif); 231 void iwl_mld_set_vif_associated(struct iwl_mld *mld, 232 struct ieee80211_vif *vif); 233 u8 iwl_mld_get_fw_bss_vifs_ids(struct iwl_mld *mld); 234 void iwl_mld_handle_probe_resp_data_notif(struct iwl_mld *mld, 235 struct iwl_rx_packet *pkt); 236 237 void iwl_mld_handle_datapath_monitor_notif(struct iwl_mld *mld, 238 struct iwl_rx_packet *pkt); 239 240 void iwl_mld_handle_uapsd_misbehaving_ap_notif(struct iwl_mld *mld, 241 struct iwl_rx_packet *pkt); 242 243 void iwl_mld_reset_cca_40mhz_workaround(struct iwl_mld *mld, 244 struct ieee80211_vif *vif); 245 246 static inline bool iwl_mld_vif_low_latency(const struct iwl_mld_vif *mld_vif) 247 { 248 return !!mld_vif->low_latency_causes; 249 } 250 251 struct ieee80211_vif *iwl_mld_get_bss_vif(struct iwl_mld *mld); 252 253 #endif /* __iwl_mld_iface_h__ */ 254