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