mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-08-05 16:54:27 +00:00

There is a requirement to exit EMLSR if there wasn't enough throughput in the secondary link. This is checked in check_tpt_wk, which runs every 5 seconds in a high throughput scenario (when the throughput blocker isn't set) It can happen that this worker is running immediately after we entered EMLSR, and in that case the secondary link didn't have a chance to have throughput. In that case we will exit EMLSR for no good reason. Fix this by tracking the time we entered EMLSR, and in the worker make sure that 5 seconds passed from when we entered EMLSR. If not, don't check the secondary link throughput. Reviewed-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com> Link: https://patch.msgid.link/20250612144708.c680f8d7dc37.I8a02d1e8d99df3789da8d5714f19b31a865a61ff@changeid
253 lines
9.2 KiB
C
253 lines
9.2 KiB
C
/* 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
|
|
* @last_link_activation_time: last time a link was activated, for
|
|
* deferring MLO scans (to make them more reliable)
|
|
* @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.
|
|
* @mlo_scan_start_wk: worker to start a deferred MLO scan
|
|
*/
|
|
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;
|
|
time64_t last_link_activation_time;
|
|
);
|
|
/* 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;
|
|
|
|
struct wiphy_delayed_work mlo_scan_start_wk;
|
|
};
|
|
|
|
static inline struct iwl_mld_vif *
|
|
iwl_mld_vif_from_mac80211(struct ieee80211_vif *vif)
|
|
{
|
|
return (void *)vif->drv_priv;
|
|
}
|
|
|
|
static inline struct ieee80211_vif *
|
|
iwl_mld_vif_to_mac80211(struct iwl_mld_vif *mld_vif)
|
|
{
|
|
return container_of((void *)mld_vif, struct ieee80211_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__ */
|