1 /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ 2 /* 3 * Copyright (C) 2024-2025 Intel Corporation 4 */ 5 #ifndef __iwl_mld_mlo_h__ 6 #define __iwl_mld_mlo_h__ 7 8 #include <linux/ieee80211.h> 9 #include <linux/types.h> 10 #include <net/mac80211.h> 11 #include "iwl-config.h" 12 #include "iwl-trans.h" 13 #include "iface.h" 14 #include "phy.h" 15 16 struct iwl_mld; 17 18 void iwl_mld_emlsr_prevent_done_wk(struct wiphy *wiphy, struct wiphy_work *wk); 19 void iwl_mld_emlsr_tmp_non_bss_done_wk(struct wiphy *wiphy, 20 struct wiphy_work *wk); 21 22 static inline bool iwl_mld_emlsr_active(struct ieee80211_vif *vif) 23 { 24 /* Set on phy context activation, so should be a good proxy */ 25 return !!(vif->driver_flags & IEEE80211_VIF_EML_ACTIVE); 26 } 27 28 static inline bool iwl_mld_vif_has_emlsr_cap(struct ieee80211_vif *vif) 29 { 30 struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif); 31 32 /* We only track/permit EMLSR state once authorized */ 33 if (!mld_vif->authorized) 34 return false; 35 36 /* No EMLSR on dual radio devices */ 37 return ieee80211_vif_type_p2p(vif) == NL80211_IFTYPE_STATION && 38 ieee80211_vif_is_mld(vif) && 39 vif->cfg.eml_cap & IEEE80211_EML_CAP_EMLSR_SUPP && 40 !CSR_HW_RFID_IS_CDB(mld_vif->mld->trans->hw_rf_id); 41 } 42 43 static inline int 44 iwl_mld_max_active_links(struct iwl_mld *mld, struct ieee80211_vif *vif) 45 { 46 if (vif->type == NL80211_IFTYPE_AP) 47 return mld->fw->ucode_capa.num_beacons; 48 49 if (ieee80211_vif_type_p2p(vif) == NL80211_IFTYPE_STATION) 50 return IWL_FW_MAX_ACTIVE_LINKS_NUM; 51 52 /* For now, do not accept more links on other interface types */ 53 return 1; 54 } 55 56 static inline int 57 iwl_mld_count_active_links(struct iwl_mld *mld, struct ieee80211_vif *vif) 58 { 59 struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif); 60 struct iwl_mld_link *mld_link; 61 int n_active = 0; 62 63 for_each_mld_vif_valid_link(mld_vif, mld_link) { 64 if (rcu_access_pointer(mld_link->chan_ctx)) 65 n_active++; 66 } 67 68 return n_active; 69 } 70 71 static inline u8 iwl_mld_get_primary_link(struct ieee80211_vif *vif) 72 { 73 struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif); 74 75 lockdep_assert_wiphy(mld_vif->mld->wiphy); 76 77 if (!ieee80211_vif_is_mld(vif) || WARN_ON(!vif->active_links)) 78 return 0; 79 80 /* In AP mode, there is no primary link */ 81 if (vif->type == NL80211_IFTYPE_AP) 82 return __ffs(vif->active_links); 83 84 if (iwl_mld_emlsr_active(vif) && 85 !WARN_ON(!(BIT(mld_vif->emlsr.primary) & vif->active_links))) 86 return mld_vif->emlsr.primary; 87 88 return __ffs(vif->active_links); 89 } 90 91 /* 92 * For non-MLO/single link, this will return the deflink/single active link, 93 * respectively 94 */ 95 static inline u8 iwl_mld_get_other_link(struct ieee80211_vif *vif, u8 link_id) 96 { 97 switch (hweight16(vif->active_links)) { 98 case 0: 99 return 0; 100 default: 101 WARN_ON(1); 102 fallthrough; 103 case 1: 104 return __ffs(vif->active_links); 105 case 2: 106 return __ffs(vif->active_links & ~BIT(link_id)); 107 } 108 } 109 110 s8 iwl_mld_get_emlsr_rssi_thresh(struct iwl_mld *mld, 111 const struct cfg80211_chan_def *chandef, 112 bool low); 113 114 /* EMLSR block/unblock and exit */ 115 void iwl_mld_block_emlsr(struct iwl_mld *mld, struct ieee80211_vif *vif, 116 enum iwl_mld_emlsr_blocked reason, u8 link_to_keep); 117 int iwl_mld_block_emlsr_sync(struct iwl_mld *mld, struct ieee80211_vif *vif, 118 enum iwl_mld_emlsr_blocked reason, u8 link_to_keep); 119 void iwl_mld_unblock_emlsr(struct iwl_mld *mld, struct ieee80211_vif *vif, 120 enum iwl_mld_emlsr_blocked reason); 121 void iwl_mld_exit_emlsr(struct iwl_mld *mld, struct ieee80211_vif *vif, 122 enum iwl_mld_emlsr_exit exit, u8 link_to_keep); 123 124 int iwl_mld_emlsr_check_non_bss_block(struct iwl_mld *mld, 125 int pending_link_changes); 126 127 void iwl_mld_handle_emlsr_mode_notif(struct iwl_mld *mld, 128 struct iwl_rx_packet *pkt); 129 void iwl_mld_handle_emlsr_trans_fail_notif(struct iwl_mld *mld, 130 struct iwl_rx_packet *pkt); 131 132 void iwl_mld_emlsr_check_tpt(struct wiphy *wiphy, struct wiphy_work *wk); 133 void iwl_mld_emlsr_unblock_tpt_wk(struct wiphy *wiphy, struct wiphy_work *wk); 134 135 void iwl_mld_select_links(struct iwl_mld *mld); 136 137 void iwl_mld_emlsr_check_bt(struct iwl_mld *mld); 138 139 void iwl_mld_emlsr_check_chan_load(struct ieee80211_hw *hw, 140 struct iwl_mld_phy *phy, 141 u32 prev_chan_load_not_by_us); 142 143 /** 144 * iwl_mld_retry_emlsr - Retry entering EMLSR 145 * @mld: MLD context 146 * @vif: VIF to retry EMLSR on 147 * 148 * Retry entering EMLSR on the given VIF. 149 * Use this if one of the parameters that can prevent EMLSR has changed. 150 */ 151 void iwl_mld_retry_emlsr(struct iwl_mld *mld, struct ieee80211_vif *vif); 152 153 #endif /* __iwl_mld_mlo_h__ */ 154