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 /* firmware supports LPRX for beacons at rate 1 Mbps or 6 Mbps only */ 257 if (link_conf->beacon_rate && 258 (link_conf->beacon_rate->bitrate == 10 || 259 link_conf->beacon_rate->bitrate == 60)) { 260 cmd->flags |= cpu_to_le16(POWER_FLAGS_LPRX_ENA_MSK); 261 cmd->lprx_rssi_threshold = POWER_LPRX_RSSI_THRESHOLD; 262 } 263 264 if (d3) { 265 iwl_mld_power_config_skip_dtim(mld, link_conf, cmd); 266 cmd->rx_data_timeout = 267 cpu_to_le32(IWL_MLD_WOWLAN_PS_RX_DATA_TIMEOUT); 268 cmd->tx_data_timeout = 269 cpu_to_le32(IWL_MLD_WOWLAN_PS_TX_DATA_TIMEOUT); 270 } else if (iwl_mld_vif_low_latency(mld_vif) && vif->p2p) { 271 cmd->tx_data_timeout = 272 cpu_to_le32(IWL_MLD_SHORT_PS_TX_DATA_TIMEOUT); 273 cmd->rx_data_timeout = 274 cpu_to_le32(IWL_MLD_SHORT_PS_RX_DATA_TIMEOUT); 275 } else { 276 cmd->rx_data_timeout = 277 cpu_to_le32(IWL_MLD_DEFAULT_PS_RX_DATA_TIMEOUT); 278 cmd->tx_data_timeout = 279 cpu_to_le32(IWL_MLD_DEFAULT_PS_TX_DATA_TIMEOUT); 280 } 281 282 /* uAPSD is only enabled for specific certifications. For those cases, 283 * mac80211 will allow uAPSD. Always call iwl_mld_power_configure_uapsd 284 * which will look at what mac80211 is saying. 285 */ 286 #ifdef CONFIG_IWLWIFI_DEBUGFS 287 ps_poll = mld_vif->use_ps_poll; 288 #endif 289 iwl_mld_power_configure_uapsd(mld, link, cmd, ps_poll); 290 } 291 292 int iwl_mld_update_mac_power(struct iwl_mld *mld, struct ieee80211_vif *vif, 293 bool d3) 294 { 295 struct iwl_mac_power_cmd cmd = {}; 296 297 iwl_mld_power_build_cmd(mld, vif, &cmd, d3); 298 299 return iwl_mld_send_cmd_pdu(mld, MAC_PM_POWER_TABLE, &cmd); 300 } 301 302 static void 303 iwl_mld_tpe_sta_cmd_data(struct iwl_txpower_constraints_cmd *cmd, 304 const struct ieee80211_bss_conf *link) 305 { 306 u8 i; 307 308 /* NOTE: the 0 here is IEEE80211_TPE_CAT_6GHZ_DEFAULT, 309 * we fully ignore IEEE80211_TPE_CAT_6GHZ_SUBORDINATE 310 */ 311 312 BUILD_BUG_ON(ARRAY_SIZE(cmd->psd_pwr) != 313 ARRAY_SIZE(link->tpe.psd_local[0].power)); 314 315 /* if not valid, mac80211 puts default (max value) */ 316 for (i = 0; i < ARRAY_SIZE(cmd->psd_pwr); i++) 317 cmd->psd_pwr[i] = min(link->tpe.psd_local[0].power[i], 318 link->tpe.psd_reg_client[0].power[i]); 319 320 BUILD_BUG_ON(ARRAY_SIZE(cmd->eirp_pwr) != 321 ARRAY_SIZE(link->tpe.max_local[0].power)); 322 323 for (i = 0; i < ARRAY_SIZE(cmd->eirp_pwr); i++) 324 cmd->eirp_pwr[i] = min(link->tpe.max_local[0].power[i], 325 link->tpe.max_reg_client[0].power[i]); 326 } 327 328 void 329 iwl_mld_send_ap_tx_power_constraint_cmd(struct iwl_mld *mld, 330 struct ieee80211_vif *vif, 331 struct ieee80211_bss_conf *link) 332 { 333 struct iwl_txpower_constraints_cmd cmd = {}; 334 struct iwl_mld_link *mld_link = iwl_mld_link_from_mac80211(link); 335 int ret; 336 337 lockdep_assert_wiphy(mld->wiphy); 338 339 if (!mld_link->active) 340 return; 341 342 if (link->chanreq.oper.chan->band != NL80211_BAND_6GHZ) 343 return; 344 345 cmd.link_id = cpu_to_le16(mld_link->fw_id); 346 memset(cmd.psd_pwr, DEFAULT_TPE_TX_POWER, sizeof(cmd.psd_pwr)); 347 memset(cmd.eirp_pwr, DEFAULT_TPE_TX_POWER, sizeof(cmd.eirp_pwr)); 348 349 if (vif->type == NL80211_IFTYPE_AP) { 350 cmd.ap_type = cpu_to_le16(IWL_6GHZ_AP_TYPE_VLP); 351 } else if (link->power_type == IEEE80211_REG_UNSET_AP) { 352 return; 353 } else { 354 cmd.ap_type = cpu_to_le16(link->power_type - 1); 355 iwl_mld_tpe_sta_cmd_data(&cmd, link); 356 } 357 358 ret = iwl_mld_send_cmd_pdu(mld, 359 WIDE_ID(PHY_OPS_GROUP, 360 AP_TX_POWER_CONSTRAINTS_CMD), 361 &cmd); 362 if (ret) 363 IWL_ERR(mld, 364 "failed to send AP_TX_POWER_CONSTRAINTS_CMD (%d)\n", 365 ret); 366 } 367 368 int iwl_mld_set_tx_power(struct iwl_mld *mld, 369 struct ieee80211_bss_conf *link_conf, 370 s16 tx_power) 371 { 372 u32 cmd_id = REDUCE_TX_POWER_CMD; 373 struct iwl_mld_link *mld_link = iwl_mld_link_from_mac80211(link_conf); 374 u16 u_tx_power = tx_power == IWL_DEFAULT_MAX_TX_POWER ? 375 IWL_DEV_MAX_TX_POWER : 8 * tx_power; 376 struct iwl_dev_tx_power_cmd cmd = { 377 /* Those fields sit on the same place for v9 and v10 */ 378 .common.set_mode = cpu_to_le32(IWL_TX_POWER_MODE_SET_LINK), 379 .common.pwr_restriction = cpu_to_le16(u_tx_power), 380 }; 381 u8 cmd_ver = iwl_fw_lookup_cmd_ver(mld->fw, cmd_id, 382 IWL_FW_CMD_VER_UNKNOWN); 383 int len = sizeof(cmd.common); 384 385 if (WARN_ON(!mld_link)) 386 return -ENODEV; 387 388 cmd.common.link_id = cpu_to_le32(mld_link->fw_id); 389 390 if (cmd_ver == 10) 391 len += sizeof(cmd.v10); 392 else if (cmd_ver == 9) 393 len += sizeof(cmd.v9); 394 395 return iwl_mld_send_cmd_pdu(mld, cmd_id, &cmd, len); 396 } 397