1 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause 2 /* 3 * Copyright (C) 2024-2025 Intel Corporation 4 */ 5 #include <net/mac80211.h> 6 7 #include "mld.h" 8 #include "hcmd.h" 9 #include "power.h" 10 #include "iface.h" 11 #include "link.h" 12 #include "constants.h" 13 14 static void iwl_mld_vif_ps_iterator(void *data, u8 *mac, 15 struct ieee80211_vif *vif) 16 { 17 bool *ps_enable = (bool *)data; 18 struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif); 19 20 if (vif->type != NL80211_IFTYPE_STATION) 21 return; 22 23 *ps_enable &= !mld_vif->ps_disabled; 24 } 25 26 int iwl_mld_update_device_power(struct iwl_mld *mld, bool d3) 27 { 28 struct iwl_device_power_cmd cmd = {}; 29 bool enable_ps = false; 30 31 if (iwlmld_mod_params.power_scheme != IWL_POWER_SCHEME_CAM) { 32 enable_ps = true; 33 34 /* Disable power save if any STA interface has 35 * power save turned off 36 */ 37 ieee80211_iterate_active_interfaces_mtx(mld->hw, 38 IEEE80211_IFACE_ITER_NORMAL, 39 iwl_mld_vif_ps_iterator, 40 &enable_ps); 41 } 42 43 if (enable_ps) 44 cmd.flags |= 45 cpu_to_le16(DEVICE_POWER_FLAGS_POWER_SAVE_ENA_MSK); 46 47 if (d3) 48 cmd.flags |= 49 cpu_to_le16(DEVICE_POWER_FLAGS_NO_SLEEP_TILL_D3_MSK); 50 51 IWL_DEBUG_POWER(mld, 52 "Sending device power command with flags = 0x%X\n", 53 cmd.flags); 54 55 return iwl_mld_send_cmd_pdu(mld, POWER_TABLE_CMD, &cmd); 56 } 57 58 int iwl_mld_enable_beacon_filter(struct iwl_mld *mld, 59 const struct ieee80211_bss_conf *link_conf, 60 bool d3) 61 { 62 struct iwl_beacon_filter_cmd cmd = { 63 IWL_BF_CMD_CONFIG_DEFAULTS, 64 .bf_enable_beacon_filter = cpu_to_le32(1), 65 .ba_enable_beacon_abort = cpu_to_le32(1), 66 }; 67 68 if (ieee80211_vif_type_p2p(link_conf->vif) != NL80211_IFTYPE_STATION) 69 return 0; 70 71 #ifdef CONFIG_IWLWIFI_DEBUGFS 72 if (iwl_mld_vif_from_mac80211(link_conf->vif)->disable_bf) 73 return 0; 74 #endif 75 76 if (link_conf->cqm_rssi_thold) { 77 cmd.bf_energy_delta = 78 cpu_to_le32(link_conf->cqm_rssi_hyst); 79 /* fw uses an absolute value for this */ 80 cmd.bf_roaming_state = 81 cpu_to_le32(-link_conf->cqm_rssi_thold); 82 } 83 84 if (d3) 85 cmd.ba_escape_timer = cpu_to_le32(IWL_BA_ESCAPE_TIMER_D3); 86 87 return iwl_mld_send_cmd_pdu(mld, REPLY_BEACON_FILTERING_CMD, 88 &cmd); 89 } 90 91 int iwl_mld_disable_beacon_filter(struct iwl_mld *mld, 92 struct ieee80211_vif *vif) 93 { 94 struct iwl_beacon_filter_cmd cmd = {}; 95 96 if (ieee80211_vif_type_p2p(vif) != NL80211_IFTYPE_STATION) 97 return 0; 98 99 return iwl_mld_send_cmd_pdu(mld, REPLY_BEACON_FILTERING_CMD, 100 &cmd); 101 } 102 103 static bool iwl_mld_power_is_radar(struct iwl_mld *mld, 104 const struct ieee80211_bss_conf *link_conf) 105 { 106 const struct ieee80211_chanctx_conf *chanctx_conf; 107 108 chanctx_conf = wiphy_dereference(mld->wiphy, link_conf->chanctx_conf); 109 110 if (WARN_ON(!chanctx_conf)) 111 return false; 112 113 return chanctx_conf->def.chan->flags & IEEE80211_CHAN_RADAR; 114 } 115 116 static void iwl_mld_power_configure_uapsd(struct iwl_mld *mld, 117 struct iwl_mld_link *link, 118 struct iwl_mac_power_cmd *cmd, 119 bool ps_poll) 120 { 121 bool tid_found = false; 122 123 cmd->rx_data_timeout_uapsd = 124 cpu_to_le32(IWL_MLD_UAPSD_RX_DATA_TIMEOUT); 125 cmd->tx_data_timeout_uapsd = 126 cpu_to_le32(IWL_MLD_UAPSD_TX_DATA_TIMEOUT); 127 128 /* set advanced pm flag with no uapsd ACs to enable ps-poll */ 129 if (ps_poll) { 130 cmd->flags |= cpu_to_le16(POWER_FLAGS_ADVANCE_PM_ENA_MSK); 131 return; 132 } 133 134 for (enum ieee80211_ac_numbers ac = IEEE80211_AC_VO; 135 ac <= IEEE80211_AC_BK; 136 ac++) { 137 if (!link->queue_params[ac].uapsd) 138 continue; 139 140 cmd->flags |= 141 cpu_to_le16(POWER_FLAGS_ADVANCE_PM_ENA_MSK | 142 POWER_FLAGS_UAPSD_MISBEHAVING_ENA_MSK); 143 144 cmd->uapsd_ac_flags |= BIT(ac); 145 146 /* QNDP TID - the highest TID with no admission control */ 147 if (!tid_found && !link->queue_params[ac].acm) { 148 tid_found = true; 149 switch (ac) { 150 case IEEE80211_AC_VO: 151 cmd->qndp_tid = 6; 152 break; 153 case IEEE80211_AC_VI: 154 cmd->qndp_tid = 5; 155 break; 156 case IEEE80211_AC_BE: 157 cmd->qndp_tid = 0; 158 break; 159 case IEEE80211_AC_BK: 160 cmd->qndp_tid = 1; 161 break; 162 } 163 } 164 } 165 166 if (cmd->uapsd_ac_flags == (BIT(IEEE80211_AC_VO) | 167 BIT(IEEE80211_AC_VI) | 168 BIT(IEEE80211_AC_BE) | 169 BIT(IEEE80211_AC_BK))) { 170 cmd->flags |= cpu_to_le16(POWER_FLAGS_SNOOZE_ENA_MSK); 171 cmd->snooze_interval = cpu_to_le16(IWL_MLD_PS_SNOOZE_INTERVAL); 172 cmd->snooze_window = cpu_to_le16(IWL_MLD_PS_SNOOZE_WINDOW); 173 } 174 175 cmd->uapsd_max_sp = mld->hw->uapsd_max_sp_len; 176 } 177 178 static void 179 iwl_mld_power_config_skip_dtim(struct iwl_mld *mld, 180 const struct ieee80211_bss_conf *link_conf, 181 struct iwl_mac_power_cmd *cmd) 182 { 183 unsigned int dtimper_tu; 184 unsigned int dtimper; 185 unsigned int skip; 186 187 dtimper = link_conf->dtim_period ?: 1; 188 dtimper_tu = dtimper * link_conf->beacon_int; 189 190 if (dtimper >= 10 || iwl_mld_power_is_radar(mld, link_conf)) 191 return; 192 193 if (WARN_ON(!dtimper_tu)) 194 return; 195 196 /* configure skip over dtim up to 900 TU DTIM interval */ 197 skip = max_t(int, 1, 900 / dtimper_tu); 198 199 cmd->skip_dtim_periods = skip; 200 cmd->flags |= cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK); 201 } 202 203 #define POWER_KEEP_ALIVE_PERIOD_SEC 25 204 static void iwl_mld_power_build_cmd(struct iwl_mld *mld, 205 struct ieee80211_vif *vif, 206 struct iwl_mac_power_cmd *cmd, 207 bool d3) 208 { 209 int dtimper, bi; 210 int keep_alive; 211 struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif); 212 struct ieee80211_bss_conf *link_conf = &vif->bss_conf; 213 struct iwl_mld_link *link = &mld_vif->deflink; 214 bool ps_poll = false; 215 216 cmd->id_and_color = cpu_to_le32(mld_vif->fw_id); 217 218 if (ieee80211_vif_is_mld(vif)) { 219 int link_id; 220 221 if (WARN_ON(!vif->active_links)) 222 return; 223 224 /* The firmware consumes one single configuration for the vif 225 * and can't differentiate between links, just pick the lowest 226 * link_id's configuration and use that. 227 */ 228 link_id = __ffs(vif->active_links); 229 link_conf = link_conf_dereference_check(vif, link_id); 230 link = iwl_mld_link_dereference_check(mld_vif, link_id); 231 232 if (WARN_ON(!link_conf || !link)) 233 return; 234 } 235 dtimper = link_conf->dtim_period; 236 bi = link_conf->beacon_int; 237 238 /* Regardless of power management state the driver must set 239 * keep alive period. FW will use it for sending keep alive NDPs 240 * immediately after association. Check that keep alive period 241 * is at least 3 * DTIM 242 */ 243 keep_alive = DIV_ROUND_UP(ieee80211_tu_to_usec(3 * dtimper * bi), 244 USEC_PER_SEC); 245 keep_alive = max(keep_alive, POWER_KEEP_ALIVE_PERIOD_SEC); 246 cmd->keep_alive_seconds = cpu_to_le16(keep_alive); 247 248 if (iwlmld_mod_params.power_scheme != IWL_POWER_SCHEME_CAM) 249 cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_SAVE_ENA_MSK); 250 251 if (!vif->cfg.ps || iwl_mld_tdls_sta_count(mld) > 0) 252 return; 253 254 cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK); 255 256 if (iwl_fw_lookup_cmd_ver(mld->fw, MAC_PM_POWER_TABLE, 0) >= 2) 257 cmd->flags |= cpu_to_le16(POWER_FLAGS_ENABLE_SMPS_MSK); 258 259 /* firmware supports LPRX for beacons at rate 1 Mbps or 6 Mbps only */ 260 if (link_conf->beacon_rate && 261 (link_conf->beacon_rate->bitrate == 10 || 262 link_conf->beacon_rate->bitrate == 60)) { 263 cmd->flags |= cpu_to_le16(POWER_FLAGS_LPRX_ENA_MSK); 264 cmd->lprx_rssi_threshold = POWER_LPRX_RSSI_THRESHOLD; 265 } 266 267 if (d3) { 268 iwl_mld_power_config_skip_dtim(mld, link_conf, cmd); 269 cmd->rx_data_timeout = 270 cpu_to_le32(IWL_MLD_WOWLAN_PS_RX_DATA_TIMEOUT); 271 cmd->tx_data_timeout = 272 cpu_to_le32(IWL_MLD_WOWLAN_PS_TX_DATA_TIMEOUT); 273 } else if (iwl_mld_vif_low_latency(mld_vif) && vif->p2p) { 274 cmd->tx_data_timeout = 275 cpu_to_le32(IWL_MLD_SHORT_PS_TX_DATA_TIMEOUT); 276 cmd->rx_data_timeout = 277 cpu_to_le32(IWL_MLD_SHORT_PS_RX_DATA_TIMEOUT); 278 } else { 279 cmd->rx_data_timeout = 280 cpu_to_le32(IWL_MLD_DEFAULT_PS_RX_DATA_TIMEOUT); 281 cmd->tx_data_timeout = 282 cpu_to_le32(IWL_MLD_DEFAULT_PS_TX_DATA_TIMEOUT); 283 } 284 285 /* uAPSD is only enabled for specific certifications. For those cases, 286 * mac80211 will allow uAPSD. Always call iwl_mld_power_configure_uapsd 287 * which will look at what mac80211 is saying. 288 */ 289 #ifdef CONFIG_IWLWIFI_DEBUGFS 290 ps_poll = mld_vif->use_ps_poll; 291 #endif 292 iwl_mld_power_configure_uapsd(mld, link, cmd, ps_poll); 293 } 294 295 int iwl_mld_update_mac_power(struct iwl_mld *mld, struct ieee80211_vif *vif, 296 bool d3) 297 { 298 struct iwl_mac_power_cmd cmd = {}; 299 300 iwl_mld_power_build_cmd(mld, vif, &cmd, d3); 301 302 return iwl_mld_send_cmd_pdu(mld, MAC_PM_POWER_TABLE, &cmd); 303 } 304 305 static void 306 iwl_mld_tpe_sta_cmd_data(struct iwl_txpower_constraints_cmd *cmd, 307 const struct ieee80211_bss_conf *link) 308 { 309 u8 i; 310 311 /* NOTE: the 0 here is IEEE80211_TPE_CAT_6GHZ_DEFAULT, 312 * we fully ignore IEEE80211_TPE_CAT_6GHZ_SUBORDINATE 313 */ 314 315 BUILD_BUG_ON(ARRAY_SIZE(cmd->psd_pwr) != 316 ARRAY_SIZE(link->tpe.psd_local[0].power)); 317 318 /* if not valid, mac80211 puts default (max value) */ 319 for (i = 0; i < ARRAY_SIZE(cmd->psd_pwr); i++) 320 cmd->psd_pwr[i] = min(link->tpe.psd_local[0].power[i], 321 link->tpe.psd_reg_client[0].power[i]); 322 323 BUILD_BUG_ON(ARRAY_SIZE(cmd->eirp_pwr) != 324 ARRAY_SIZE(link->tpe.max_local[0].power)); 325 326 for (i = 0; i < ARRAY_SIZE(cmd->eirp_pwr); i++) 327 cmd->eirp_pwr[i] = min(link->tpe.max_local[0].power[i], 328 link->tpe.max_reg_client[0].power[i]); 329 } 330 331 void 332 iwl_mld_send_ap_tx_power_constraint_cmd(struct iwl_mld *mld, 333 struct ieee80211_vif *vif, 334 struct ieee80211_bss_conf *link) 335 { 336 struct iwl_txpower_constraints_cmd cmd = {}; 337 struct iwl_mld_link *mld_link = iwl_mld_link_from_mac80211(link); 338 int ret; 339 340 lockdep_assert_wiphy(mld->wiphy); 341 342 if (!mld_link->active) 343 return; 344 345 if (link->chanreq.oper.chan->band != NL80211_BAND_6GHZ) 346 return; 347 348 cmd.link_id = cpu_to_le16(mld_link->fw_id); 349 memset(cmd.psd_pwr, DEFAULT_TPE_TX_POWER, sizeof(cmd.psd_pwr)); 350 memset(cmd.eirp_pwr, DEFAULT_TPE_TX_POWER, sizeof(cmd.eirp_pwr)); 351 352 if (vif->type == NL80211_IFTYPE_AP) { 353 cmd.ap_type = cpu_to_le16(IWL_6GHZ_AP_TYPE_VLP); 354 } else if (link->power_type == IEEE80211_REG_UNSET_AP) { 355 return; 356 } else { 357 cmd.ap_type = cpu_to_le16(link->power_type - 1); 358 iwl_mld_tpe_sta_cmd_data(&cmd, link); 359 } 360 361 ret = iwl_mld_send_cmd_pdu(mld, 362 WIDE_ID(PHY_OPS_GROUP, 363 AP_TX_POWER_CONSTRAINTS_CMD), 364 &cmd); 365 if (ret) 366 IWL_ERR(mld, 367 "failed to send AP_TX_POWER_CONSTRAINTS_CMD (%d)\n", 368 ret); 369 } 370 371 int iwl_mld_set_tx_power(struct iwl_mld *mld, 372 struct ieee80211_bss_conf *link_conf, 373 s16 tx_power) 374 { 375 u32 cmd_id = REDUCE_TX_POWER_CMD; 376 struct iwl_mld_link *mld_link = iwl_mld_link_from_mac80211(link_conf); 377 u16 u_tx_power = tx_power == IWL_DEFAULT_MAX_TX_POWER ? 378 IWL_DEV_MAX_TX_POWER : 8 * tx_power; 379 struct iwl_dev_tx_power_cmd cmd = { 380 /* Those fields sit on the same place for v9 and v10 */ 381 .common.set_mode = cpu_to_le32(IWL_TX_POWER_MODE_SET_LINK), 382 .common.pwr_restriction = cpu_to_le16(u_tx_power), 383 }; 384 u8 cmd_ver = iwl_fw_lookup_cmd_ver(mld->fw, cmd_id, 385 IWL_FW_CMD_VER_UNKNOWN); 386 int len = sizeof(cmd.common); 387 388 if (WARN_ON(!mld_link)) 389 return -ENODEV; 390 391 cmd.common.link_id = cpu_to_le32(mld_link->fw_id); 392 393 if (cmd_ver == 10) 394 len += sizeof(cmd.v10); 395 else if (cmd_ver == 9) 396 len += sizeof(cmd.v9); 397 398 return iwl_mld_send_cmd_pdu(mld, cmd_id, &cmd, len); 399 } 400