brintos

brintos / linux-shallow public Read only

0
0
Text · 28.5 KiB · bc363e8 Raw
990 lines · c
1// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause2/*3 * Copyright (C) 2012-2014, 2018-2019, 2021-2024 Intel Corporation4 * Copyright (C) 2013-2014 Intel Mobile Communications GmbH5 * Copyright (C) 2015-2017 Intel Deutschland GmbH6 */7#include <linux/kernel.h>8#include <linux/module.h>9#include <linux/slab.h>10#include <linux/etherdevice.h>11 12#include <net/mac80211.h>13 14#include "iwl-debug.h"15#include "mvm.h"16#include "iwl-modparams.h"17#include "fw/api/power.h"18 19#define POWER_KEEP_ALIVE_PERIOD_SEC    2520 21static22int iwl_mvm_beacon_filter_send_cmd(struct iwl_mvm *mvm,23				   struct iwl_beacon_filter_cmd *cmd)24{25	u16 len;26 27	IWL_DEBUG_POWER(mvm, "ba_enable_beacon_abort is: %d\n",28			le32_to_cpu(cmd->ba_enable_beacon_abort));29	IWL_DEBUG_POWER(mvm, "ba_escape_timer is: %d\n",30			le32_to_cpu(cmd->ba_escape_timer));31	IWL_DEBUG_POWER(mvm, "bf_debug_flag is: %d\n",32			le32_to_cpu(cmd->bf_debug_flag));33	IWL_DEBUG_POWER(mvm, "bf_enable_beacon_filter is: %d\n",34			le32_to_cpu(cmd->bf_enable_beacon_filter));35	IWL_DEBUG_POWER(mvm, "bf_energy_delta is: %d\n",36			le32_to_cpu(cmd->bf_energy_delta));37	IWL_DEBUG_POWER(mvm, "bf_escape_timer is: %d\n",38			le32_to_cpu(cmd->bf_escape_timer));39	IWL_DEBUG_POWER(mvm, "bf_roaming_energy_delta is: %d\n",40			le32_to_cpu(cmd->bf_roaming_energy_delta));41	IWL_DEBUG_POWER(mvm, "bf_roaming_state is: %d\n",42			le32_to_cpu(cmd->bf_roaming_state));43	IWL_DEBUG_POWER(mvm, "bf_temp_threshold is: %d\n",44			le32_to_cpu(cmd->bf_temp_threshold));45	IWL_DEBUG_POWER(mvm, "bf_temp_fast_filter is: %d\n",46			le32_to_cpu(cmd->bf_temp_fast_filter));47	IWL_DEBUG_POWER(mvm, "bf_temp_slow_filter is: %d\n",48			le32_to_cpu(cmd->bf_temp_slow_filter));49	IWL_DEBUG_POWER(mvm, "bf_threshold_absolute_low is: %d, %d\n",50			le32_to_cpu(cmd->bf_threshold_absolute_low[0]),51			le32_to_cpu(cmd->bf_threshold_absolute_low[1]));52 53	IWL_DEBUG_POWER(mvm, "bf_threshold_absolute_high is: %d, %d\n",54			le32_to_cpu(cmd->bf_threshold_absolute_high[0]),55			le32_to_cpu(cmd->bf_threshold_absolute_high[1]));56 57	if (fw_has_api(&mvm->fw->ucode_capa,58		       IWL_UCODE_TLV_API_BEACON_FILTER_V4))59		len = sizeof(struct iwl_beacon_filter_cmd);60	else61		len = offsetof(struct iwl_beacon_filter_cmd,62			       bf_threshold_absolute_low);63 64	return iwl_mvm_send_cmd_pdu(mvm, REPLY_BEACON_FILTERING_CMD, 0,65				    len, cmd);66}67 68static69void iwl_mvm_beacon_filter_set_cqm_params(struct iwl_mvm *mvm,70					  struct ieee80211_vif *vif,71					  struct iwl_beacon_filter_cmd *cmd)72{73	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);74 75	if (vif->bss_conf.cqm_rssi_thold) {76		cmd->bf_energy_delta =77			cpu_to_le32(vif->bss_conf.cqm_rssi_hyst);78		/* fw uses an absolute value for this */79		cmd->bf_roaming_state =80			cpu_to_le32(-vif->bss_conf.cqm_rssi_thold);81	}82	cmd->ba_enable_beacon_abort = cpu_to_le32(mvmvif->ba_enabled);83}84 85static void iwl_mvm_power_log(struct iwl_mvm *mvm,86			      struct iwl_mac_power_cmd *cmd)87{88	IWL_DEBUG_POWER(mvm,89			"Sending power table command on mac id 0x%X for power level %d, flags = 0x%X\n",90			cmd->id_and_color, iwlmvm_mod_params.power_scheme,91			le16_to_cpu(cmd->flags));92	IWL_DEBUG_POWER(mvm, "Keep alive = %u sec\n",93			le16_to_cpu(cmd->keep_alive_seconds));94 95	if (!(cmd->flags & cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK))) {96		IWL_DEBUG_POWER(mvm, "Disable power management\n");97		return;98	}99 100	IWL_DEBUG_POWER(mvm, "Rx timeout = %u usec\n",101			le32_to_cpu(cmd->rx_data_timeout));102	IWL_DEBUG_POWER(mvm, "Tx timeout = %u usec\n",103			le32_to_cpu(cmd->tx_data_timeout));104	if (cmd->flags & cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK))105		IWL_DEBUG_POWER(mvm, "DTIM periods to skip = %u\n",106				cmd->skip_dtim_periods);107	if (cmd->flags & cpu_to_le16(POWER_FLAGS_LPRX_ENA_MSK))108		IWL_DEBUG_POWER(mvm, "LP RX RSSI threshold = %u\n",109				cmd->lprx_rssi_threshold);110	if (cmd->flags & cpu_to_le16(POWER_FLAGS_ADVANCE_PM_ENA_MSK)) {111		IWL_DEBUG_POWER(mvm, "uAPSD enabled\n");112		IWL_DEBUG_POWER(mvm, "Rx timeout (uAPSD) = %u usec\n",113				le32_to_cpu(cmd->rx_data_timeout_uapsd));114		IWL_DEBUG_POWER(mvm, "Tx timeout (uAPSD) = %u usec\n",115				le32_to_cpu(cmd->tx_data_timeout_uapsd));116		IWL_DEBUG_POWER(mvm, "QNDP TID = %d\n", cmd->qndp_tid);117		IWL_DEBUG_POWER(mvm, "ACs flags = 0x%x\n", cmd->uapsd_ac_flags);118		IWL_DEBUG_POWER(mvm, "Max SP = %d\n", cmd->uapsd_max_sp);119	}120}121 122static void iwl_mvm_power_configure_uapsd(struct iwl_mvm *mvm,123					  struct ieee80211_vif *vif,124					  struct iwl_mac_power_cmd *cmd)125{126	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);127	enum ieee80211_ac_numbers ac;128	bool tid_found = false;129 130	if (test_bit(IWL_MVM_STATUS_IN_D3, &mvm->status) ||131	    cmd->flags & cpu_to_le16(POWER_FLAGS_SNOOZE_ENA_MSK)) {132		cmd->rx_data_timeout_uapsd =133			cpu_to_le32(IWL_MVM_WOWLAN_PS_RX_DATA_TIMEOUT);134		cmd->tx_data_timeout_uapsd =135			cpu_to_le32(IWL_MVM_WOWLAN_PS_TX_DATA_TIMEOUT);136	} else {137		cmd->rx_data_timeout_uapsd =138			cpu_to_le32(IWL_MVM_UAPSD_RX_DATA_TIMEOUT);139		cmd->tx_data_timeout_uapsd =140			cpu_to_le32(IWL_MVM_UAPSD_TX_DATA_TIMEOUT);141	}142 143#ifdef CONFIG_IWLWIFI_DEBUGFS144	/* set advanced pm flag with no uapsd ACs to enable ps-poll */145	if (mvmvif->dbgfs_pm.use_ps_poll) {146		cmd->flags |= cpu_to_le16(POWER_FLAGS_ADVANCE_PM_ENA_MSK);147		return;148	}149#endif150 151	for (ac = IEEE80211_AC_VO; ac <= IEEE80211_AC_BK; ac++) {152		if (!mvmvif->deflink.queue_params[ac].uapsd)153			continue;154 155		if (!test_bit(IWL_MVM_STATUS_IN_D3, &mvm->status))156			cmd->flags |=157				cpu_to_le16(POWER_FLAGS_ADVANCE_PM_ENA_MSK);158 159		cmd->uapsd_ac_flags |= BIT(ac);160 161		/* QNDP TID - the highest TID with no admission control */162		if (!tid_found && !mvmvif->deflink.queue_params[ac].acm) {163			tid_found = true;164			switch (ac) {165			case IEEE80211_AC_VO:166				cmd->qndp_tid = 6;167				break;168			case IEEE80211_AC_VI:169				cmd->qndp_tid = 5;170				break;171			case IEEE80211_AC_BE:172				cmd->qndp_tid = 0;173				break;174			case IEEE80211_AC_BK:175				cmd->qndp_tid = 1;176				break;177			}178		}179	}180 181	cmd->flags |= cpu_to_le16(POWER_FLAGS_UAPSD_MISBEHAVING_ENA_MSK);182 183	if (cmd->uapsd_ac_flags == (BIT(IEEE80211_AC_VO) |184				    BIT(IEEE80211_AC_VI) |185				    BIT(IEEE80211_AC_BE) |186				    BIT(IEEE80211_AC_BK))) {187		cmd->flags |= cpu_to_le16(POWER_FLAGS_SNOOZE_ENA_MSK);188		cmd->snooze_interval = cpu_to_le16(IWL_MVM_PS_SNOOZE_INTERVAL);189		cmd->snooze_window =190			test_bit(IWL_MVM_STATUS_IN_D3, &mvm->status) ?191				cpu_to_le16(IWL_MVM_WOWLAN_PS_SNOOZE_WINDOW) :192				cpu_to_le16(IWL_MVM_PS_SNOOZE_WINDOW);193	}194 195	cmd->uapsd_max_sp = mvm->hw->uapsd_max_sp_len;196 197	if (cmd->flags & cpu_to_le16(POWER_FLAGS_SNOOZE_ENA_MSK)) {198		cmd->heavy_tx_thld_packets =199			IWL_MVM_PS_SNOOZE_HEAVY_TX_THLD_PACKETS;200		cmd->heavy_rx_thld_packets =201			IWL_MVM_PS_SNOOZE_HEAVY_RX_THLD_PACKETS;202	} else {203		cmd->heavy_tx_thld_packets =204			IWL_MVM_PS_HEAVY_TX_THLD_PACKETS;205		cmd->heavy_rx_thld_packets =206			IWL_MVM_PS_HEAVY_RX_THLD_PACKETS;207	}208	cmd->heavy_tx_thld_percentage =209		IWL_MVM_PS_HEAVY_TX_THLD_PERCENT;210	cmd->heavy_rx_thld_percentage =211		IWL_MVM_PS_HEAVY_RX_THLD_PERCENT;212}213 214struct iwl_allow_uapsd_iface_iterator_data {215	struct ieee80211_vif *current_vif;216	bool allow_uapsd;217};218 219static void iwl_mvm_allow_uapsd_iterator(void *_data, u8 *mac,220					 struct ieee80211_vif *vif)221{222	struct iwl_allow_uapsd_iface_iterator_data *data = _data;223	struct iwl_mvm_vif *other_mvmvif = iwl_mvm_vif_from_mac80211(vif);224	struct iwl_mvm_vif *curr_mvmvif =225		iwl_mvm_vif_from_mac80211(data->current_vif);226 227	/* exclude the given vif */228	if (vif == data->current_vif)229		return;230 231	switch (vif->type) {232	case NL80211_IFTYPE_AP:233	case NL80211_IFTYPE_ADHOC:234	case NL80211_IFTYPE_NAN:235		data->allow_uapsd = false;236		break;237	case NL80211_IFTYPE_STATION:238		/* allow UAPSD if P2P interface and BSS station interface share239		 * the same channel.240		 */241		if (vif->cfg.assoc && other_mvmvif->deflink.phy_ctxt &&242		    curr_mvmvif->deflink.phy_ctxt &&243		    other_mvmvif->deflink.phy_ctxt->id != curr_mvmvif->deflink.phy_ctxt->id)244			data->allow_uapsd = false;245		break;246 247	default:248		break;249	}250}251 252static bool iwl_mvm_power_allow_uapsd(struct iwl_mvm *mvm,253				       struct ieee80211_vif *vif)254{255	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);256	struct iwl_allow_uapsd_iface_iterator_data data = {257		.current_vif = vif,258		.allow_uapsd = true,259	};260 261	if (ether_addr_equal(mvmvif->uapsd_misbehaving_ap_addr,262			     vif->cfg.ap_addr))263		return false;264 265	/*266	 * Avoid using uAPSD if P2P client is associated to GO that uses267	 * opportunistic power save. This is due to current FW limitation.268	 */269	if (vif->p2p &&270	    (vif->bss_conf.p2p_noa_attr.oppps_ctwindow &271	    IEEE80211_P2P_OPPPS_ENABLE_BIT))272		return false;273 274	if (vif->p2p && !iwl_mvm_is_p2p_scm_uapsd_supported(mvm))275		return false;276 277	ieee80211_iterate_active_interfaces_atomic(mvm->hw,278				IEEE80211_IFACE_ITER_NORMAL,279				iwl_mvm_allow_uapsd_iterator,280				&data);281 282	return data.allow_uapsd;283}284 285static bool iwl_mvm_power_is_radar(struct ieee80211_bss_conf *link_conf)286{287	struct ieee80211_chanctx_conf *chanctx_conf;288 289	chanctx_conf = rcu_dereference(link_conf->chanctx_conf);290 291	/* this happens on link switching, just ignore inactive ones */292	if (!chanctx_conf)293		return false;294 295	return chanctx_conf->def.chan->flags & IEEE80211_CHAN_RADAR;296}297 298static void iwl_mvm_power_config_skip_dtim(struct iwl_mvm *mvm,299					   struct ieee80211_vif *vif,300					   struct iwl_mac_power_cmd *cmd)301{302	struct ieee80211_bss_conf *link_conf;303	unsigned int min_link_skip = ~0;304	unsigned int link_id;305 306	/* disable, in case we're supposed to override */307	cmd->skip_dtim_periods = 0;308	cmd->flags &= ~cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK);309 310	if (!test_bit(IWL_MVM_STATUS_IN_D3, &mvm->status)) {311		if (iwlmvm_mod_params.power_scheme != IWL_POWER_SCHEME_LP)312			return;313		cmd->skip_dtim_periods = 2;314		cmd->flags |= cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK);315		return;316	}317 318	rcu_read_lock();319	for_each_vif_active_link(vif, link_conf, link_id) {320		unsigned int dtimper = link_conf->dtim_period ?: 1;321		unsigned int dtimper_tu = dtimper * link_conf->beacon_int;322		unsigned int skip;323 324		if (dtimper >= 10 || iwl_mvm_power_is_radar(link_conf)) {325			rcu_read_unlock();326			return;327		}328 329		if (WARN_ON(!dtimper_tu))330			continue;331 332		/* configure skip over dtim up to 900 TU DTIM interval */333		skip = max_t(int, 1, 900 / dtimper_tu);334		min_link_skip = min(min_link_skip, skip);335	}336	rcu_read_unlock();337 338	/* no WARN_ON, can only happen with WARN_ON above */339	if (min_link_skip == ~0)340		return;341 342	cmd->skip_dtim_periods = min_link_skip;343	cmd->flags |= cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK);344}345 346static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm,347				    struct ieee80211_vif *vif,348				    struct iwl_mac_power_cmd *cmd)349{350	int dtimper, bi;351	int keep_alive;352	struct iwl_mvm_vif *mvmvif __maybe_unused =353		iwl_mvm_vif_from_mac80211(vif);354 355	cmd->id_and_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id,356							    mvmvif->color));357	dtimper = vif->bss_conf.dtim_period;358	bi = vif->bss_conf.beacon_int;359 360	/*361	 * Regardless of power management state the driver must set362	 * keep alive period. FW will use it for sending keep alive NDPs363	 * immediately after association. Check that keep alive period364	 * is at least 3 * DTIM365	 */366	keep_alive = DIV_ROUND_UP(ieee80211_tu_to_usec(3 * dtimper * bi),367				  USEC_PER_SEC);368	keep_alive = max(keep_alive, POWER_KEEP_ALIVE_PERIOD_SEC);369	cmd->keep_alive_seconds = cpu_to_le16(keep_alive);370 371	if (mvm->ps_disabled)372		return;373 374	cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_SAVE_ENA_MSK);375 376	if (!vif->cfg.ps || !mvmvif->pm_enabled)377		return;378 379	if (iwl_mvm_vif_low_latency(mvmvif) && vif->p2p &&380	    (!fw_has_capa(&mvm->fw->ucode_capa,381			 IWL_UCODE_TLV_CAPA_SHORT_PM_TIMEOUTS) ||382	     !IWL_MVM_P2P_LOWLATENCY_PS_ENABLE))383		return;384 385	cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK);386 387	if (vif->bss_conf.beacon_rate &&388	    (vif->bss_conf.beacon_rate->bitrate == 10 ||389	     vif->bss_conf.beacon_rate->bitrate == 60)) {390		cmd->flags |= cpu_to_le16(POWER_FLAGS_LPRX_ENA_MSK);391		cmd->lprx_rssi_threshold = POWER_LPRX_RSSI_THRESHOLD;392	}393 394	iwl_mvm_power_config_skip_dtim(mvm, vif, cmd);395 396	if (test_bit(IWL_MVM_STATUS_IN_D3, &mvm->status)) {397		cmd->rx_data_timeout =398			cpu_to_le32(IWL_MVM_WOWLAN_PS_RX_DATA_TIMEOUT);399		cmd->tx_data_timeout =400			cpu_to_le32(IWL_MVM_WOWLAN_PS_TX_DATA_TIMEOUT);401	} else if (iwl_mvm_vif_low_latency(mvmvif) && vif->p2p &&402		   fw_has_capa(&mvm->fw->ucode_capa,403			       IWL_UCODE_TLV_CAPA_SHORT_PM_TIMEOUTS)) {404		cmd->tx_data_timeout =405			cpu_to_le32(IWL_MVM_SHORT_PS_TX_DATA_TIMEOUT);406		cmd->rx_data_timeout =407			cpu_to_le32(IWL_MVM_SHORT_PS_RX_DATA_TIMEOUT);408	} else {409		cmd->rx_data_timeout =410			cpu_to_le32(IWL_MVM_DEFAULT_PS_RX_DATA_TIMEOUT);411		cmd->tx_data_timeout =412			cpu_to_le32(IWL_MVM_DEFAULT_PS_TX_DATA_TIMEOUT);413	}414 415	if (iwl_mvm_power_allow_uapsd(mvm, vif))416		iwl_mvm_power_configure_uapsd(mvm, vif, cmd);417 418#ifdef CONFIG_IWLWIFI_DEBUGFS419	if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_KEEP_ALIVE)420		cmd->keep_alive_seconds =421			cpu_to_le16(mvmvif->dbgfs_pm.keep_alive_seconds);422	if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_SKIP_OVER_DTIM) {423		if (mvmvif->dbgfs_pm.skip_over_dtim)424			cmd->flags |=425				cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK);426		else427			cmd->flags &=428				cpu_to_le16(~POWER_FLAGS_SKIP_OVER_DTIM_MSK);429	}430	if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_RX_DATA_TIMEOUT)431		cmd->rx_data_timeout =432			cpu_to_le32(mvmvif->dbgfs_pm.rx_data_timeout);433	if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_TX_DATA_TIMEOUT)434		cmd->tx_data_timeout =435			cpu_to_le32(mvmvif->dbgfs_pm.tx_data_timeout);436	if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_SKIP_DTIM_PERIODS)437		cmd->skip_dtim_periods = mvmvif->dbgfs_pm.skip_dtim_periods;438	if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_LPRX_ENA) {439		if (mvmvif->dbgfs_pm.lprx_ena)440			cmd->flags |= cpu_to_le16(POWER_FLAGS_LPRX_ENA_MSK);441		else442			cmd->flags &= cpu_to_le16(~POWER_FLAGS_LPRX_ENA_MSK);443	}444	if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_LPRX_RSSI_THRESHOLD)445		cmd->lprx_rssi_threshold = mvmvif->dbgfs_pm.lprx_rssi_threshold;446	if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_SNOOZE_ENABLE) {447		if (mvmvif->dbgfs_pm.snooze_ena)448			cmd->flags |=449				cpu_to_le16(POWER_FLAGS_SNOOZE_ENA_MSK);450		else451			cmd->flags &=452				cpu_to_le16(~POWER_FLAGS_SNOOZE_ENA_MSK);453	}454	if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_UAPSD_MISBEHAVING) {455		u16 flag = POWER_FLAGS_UAPSD_MISBEHAVING_ENA_MSK;456		if (mvmvif->dbgfs_pm.uapsd_misbehaving)457			cmd->flags |= cpu_to_le16(flag);458		else459			cmd->flags &= cpu_to_le16(flag);460	}461#endif /* CONFIG_IWLWIFI_DEBUGFS */462}463 464static int iwl_mvm_power_send_cmd(struct iwl_mvm *mvm,465					 struct ieee80211_vif *vif)466{467	struct iwl_mac_power_cmd cmd = {};468 469	iwl_mvm_power_build_cmd(mvm, vif, &cmd);470	iwl_mvm_power_log(mvm, &cmd);471#ifdef CONFIG_IWLWIFI_DEBUGFS472	memcpy(&iwl_mvm_vif_from_mac80211(vif)->mac_pwr_cmd, &cmd, sizeof(cmd));473#endif474 475	return iwl_mvm_send_cmd_pdu(mvm, MAC_PM_POWER_TABLE, 0,476				    sizeof(cmd), &cmd);477}478 479int iwl_mvm_power_update_device(struct iwl_mvm *mvm)480{481	struct iwl_device_power_cmd cmd = {482		.flags = 0,483	};484 485	if (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM)486		mvm->ps_disabled = true;487 488	if (!mvm->ps_disabled)489		cmd.flags |= cpu_to_le16(DEVICE_POWER_FLAGS_POWER_SAVE_ENA_MSK);490 491#ifdef CONFIG_IWLWIFI_DEBUGFS492	if (test_bit(IWL_MVM_STATUS_IN_D3, &mvm->status) ?493			mvm->disable_power_off_d3 : mvm->disable_power_off)494		cmd.flags &=495			cpu_to_le16(~DEVICE_POWER_FLAGS_POWER_SAVE_ENA_MSK);496#endif497	if (mvm->ext_clock_valid)498		cmd.flags |= cpu_to_le16(DEVICE_POWER_FLAGS_32K_CLK_VALID_MSK);499 500	if (iwl_fw_lookup_cmd_ver(mvm->fw, POWER_TABLE_CMD, 0) >= 7 &&501	    test_bit(IWL_MVM_STATUS_IN_D3, &mvm->status))502		cmd.flags |=503			cpu_to_le16(DEVICE_POWER_FLAGS_NO_SLEEP_TILL_D3_MSK);504 505	IWL_DEBUG_POWER(mvm,506			"Sending device power command with flags = 0x%X\n",507			cmd.flags);508 509	return iwl_mvm_send_cmd_pdu(mvm, POWER_TABLE_CMD, 0, sizeof(cmd),510				    &cmd);511}512 513void iwl_mvm_power_vif_assoc(struct iwl_mvm *mvm, struct ieee80211_vif *vif)514{515	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);516 517	if (!ether_addr_equal(mvmvif->uapsd_misbehaving_ap_addr,518			      vif->cfg.ap_addr))519		eth_zero_addr(mvmvif->uapsd_misbehaving_ap_addr);520}521 522static void iwl_mvm_power_uapsd_misbehav_ap_iterator(void *_data, u8 *mac,523						     struct ieee80211_vif *vif)524{525	u8 *ap_sta_id = _data;526	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);527	struct ieee80211_bss_conf *link_conf;528	unsigned int link_id;529 530	rcu_read_lock();531	for_each_vif_active_link(vif, link_conf, link_id) {532		struct iwl_mvm_vif_link_info *link_info = mvmvif->link[link_id];533 534		/* The ap_sta_id is not expected to change during current535		 * association so no explicit protection is needed536		 */537		if (link_info->ap_sta_id == *ap_sta_id) {538			ether_addr_copy(mvmvif->uapsd_misbehaving_ap_addr,539					vif->cfg.ap_addr);540			break;541		}542	}543	rcu_read_unlock();544}545 546void iwl_mvm_power_uapsd_misbehaving_ap_notif(struct iwl_mvm *mvm,547					      struct iwl_rx_cmd_buffer *rxb)548{549	struct iwl_rx_packet *pkt = rxb_addr(rxb);550	struct iwl_uapsd_misbehaving_ap_notif *notif = (void *)pkt->data;551	u8 ap_sta_id = le32_to_cpu(notif->sta_id);552 553	ieee80211_iterate_active_interfaces_atomic(554		mvm->hw, IEEE80211_IFACE_ITER_NORMAL,555		iwl_mvm_power_uapsd_misbehav_ap_iterator, &ap_sta_id);556}557 558struct iwl_power_vifs {559	struct iwl_mvm *mvm;560	struct ieee80211_vif *bss_vif;561	struct ieee80211_vif *p2p_vif;562	struct ieee80211_vif *ap_vif;563	struct ieee80211_vif *monitor_vif;564	bool p2p_active;565	bool bss_active;566	bool ap_active;567	bool monitor_active;568};569 570static void iwl_mvm_power_disable_pm_iterator(void *_data, u8* mac,571					      struct ieee80211_vif *vif)572{573	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);574 575	mvmvif->pm_enabled = false;576}577 578static void iwl_mvm_power_ps_disabled_iterator(void *_data, u8* mac,579					       struct ieee80211_vif *vif)580{581	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);582	bool *disable_ps = _data;583 584	if (iwl_mvm_vif_is_active(mvmvif))585		*disable_ps |= mvmvif->ps_disabled;586}587 588static void iwl_mvm_power_get_vifs_iterator(void *_data, u8 *mac,589					    struct ieee80211_vif *vif)590{591	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);592	struct iwl_power_vifs *power_iterator = _data;593	bool active;594 595	if (!mvmvif->uploaded)596		return;597 598	active = iwl_mvm_vif_is_active(mvmvif);599 600	switch (ieee80211_vif_type_p2p(vif)) {601	case NL80211_IFTYPE_P2P_DEVICE:602		break;603 604	case NL80211_IFTYPE_P2P_GO:605	case NL80211_IFTYPE_AP:606		/* only a single MAC of the same type */607		WARN_ON(power_iterator->ap_vif);608		power_iterator->ap_vif = vif;609		if (active)610			power_iterator->ap_active = true;611		break;612 613	case NL80211_IFTYPE_MONITOR:614		/* only a single MAC of the same type */615		WARN_ON(power_iterator->monitor_vif);616		power_iterator->monitor_vif = vif;617		if (active)618			power_iterator->monitor_active = true;619		break;620 621	case NL80211_IFTYPE_P2P_CLIENT:622		/* only a single MAC of the same type */623		WARN_ON(power_iterator->p2p_vif);624		power_iterator->p2p_vif = vif;625		if (active)626			power_iterator->p2p_active = true;627		break;628 629	case NL80211_IFTYPE_STATION:630		power_iterator->bss_vif = vif;631		if (active)632			power_iterator->bss_active = true;633		break;634 635	default:636		break;637	}638}639 640static void iwl_mvm_power_set_pm(struct iwl_mvm *mvm,641				 struct iwl_power_vifs *vifs)642{643	struct iwl_mvm_vif *bss_mvmvif = NULL;644	struct iwl_mvm_vif *p2p_mvmvif = NULL;645	struct iwl_mvm_vif *ap_mvmvif = NULL;646	bool client_same_channel = false;647	bool ap_same_channel = false;648 649	lockdep_assert_held(&mvm->mutex);650 651	/* set pm_enable to false */652	ieee80211_iterate_active_interfaces_atomic(mvm->hw,653					IEEE80211_IFACE_ITER_NORMAL,654					iwl_mvm_power_disable_pm_iterator,655					NULL);656 657	if (vifs->bss_vif)658		bss_mvmvif = iwl_mvm_vif_from_mac80211(vifs->bss_vif);659 660	if (vifs->p2p_vif)661		p2p_mvmvif = iwl_mvm_vif_from_mac80211(vifs->p2p_vif);662 663	if (vifs->ap_vif)664		ap_mvmvif = iwl_mvm_vif_from_mac80211(vifs->ap_vif);665 666	/* don't allow PM if any TDLS stations exist */667	if (iwl_mvm_tdls_sta_count(mvm, NULL))668		return;669 670	/* enable PM on bss if bss stand alone */671	if (bss_mvmvif && vifs->bss_active && !vifs->p2p_active &&672	    !vifs->ap_active) {673		bss_mvmvif->pm_enabled = true;674		return;675	}676 677	/* enable PM on p2p if p2p stand alone */678	if (p2p_mvmvif && vifs->p2p_active && !vifs->bss_active &&679	    !vifs->ap_active) {680		p2p_mvmvif->pm_enabled = true;681		return;682	}683 684	if (p2p_mvmvif && bss_mvmvif && vifs->bss_active && vifs->p2p_active)685		client_same_channel =686			iwl_mvm_have_links_same_channel(bss_mvmvif, p2p_mvmvif);687 688	if (bss_mvmvif && ap_mvmvif && vifs->bss_active && vifs->ap_active)689		ap_same_channel =690			iwl_mvm_have_links_same_channel(bss_mvmvif, ap_mvmvif);691 692	/* clients are not stand alone: enable PM if DCM */693	if (!(client_same_channel || ap_same_channel)) {694		if (bss_mvmvif && vifs->bss_active)695			bss_mvmvif->pm_enabled = true;696		if (p2p_mvmvif && vifs->p2p_active)697			p2p_mvmvif->pm_enabled = true;698		return;699	}700 701	/*702	 * There is only one channel in the system and there are only703	 * bss and p2p clients that share it704	 */705	if (client_same_channel && !vifs->ap_active) {706		/* share same channel*/707		bss_mvmvif->pm_enabled = true;708		p2p_mvmvif->pm_enabled = true;709	}710}711 712#ifdef CONFIG_IWLWIFI_DEBUGFS713int iwl_mvm_power_mac_dbgfs_read(struct iwl_mvm *mvm,714				 struct ieee80211_vif *vif, char *buf,715				 int bufsz)716{717	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);718	struct iwl_mac_power_cmd cmd = {};719	int pos = 0;720 721	mutex_lock(&mvm->mutex);722	memcpy(&cmd, &mvmvif->mac_pwr_cmd, sizeof(cmd));723	mutex_unlock(&mvm->mutex);724 725	pos += scnprintf(buf+pos, bufsz-pos, "power_scheme = %d\n",726			 iwlmvm_mod_params.power_scheme);727	pos += scnprintf(buf+pos, bufsz-pos, "flags = 0x%x\n",728			 le16_to_cpu(cmd.flags));729	pos += scnprintf(buf+pos, bufsz-pos, "keep_alive = %d\n",730			 le16_to_cpu(cmd.keep_alive_seconds));731 732	if (!(cmd.flags & cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK)))733		return pos;734 735	pos += scnprintf(buf+pos, bufsz-pos, "skip_over_dtim = %d\n",736			 (cmd.flags &737			 cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK)) ? 1 : 0);738	pos += scnprintf(buf+pos, bufsz-pos, "skip_dtim_periods = %d\n",739			 cmd.skip_dtim_periods);740	if (!(cmd.flags & cpu_to_le16(POWER_FLAGS_ADVANCE_PM_ENA_MSK))) {741		pos += scnprintf(buf+pos, bufsz-pos, "rx_data_timeout = %d\n",742				 le32_to_cpu(cmd.rx_data_timeout));743		pos += scnprintf(buf+pos, bufsz-pos, "tx_data_timeout = %d\n",744				 le32_to_cpu(cmd.tx_data_timeout));745	}746	if (cmd.flags & cpu_to_le16(POWER_FLAGS_LPRX_ENA_MSK))747		pos += scnprintf(buf+pos, bufsz-pos,748				 "lprx_rssi_threshold = %d\n",749				 cmd.lprx_rssi_threshold);750 751	if (!(cmd.flags & cpu_to_le16(POWER_FLAGS_ADVANCE_PM_ENA_MSK)))752		return pos;753 754	pos += scnprintf(buf+pos, bufsz-pos, "rx_data_timeout_uapsd = %d\n",755			 le32_to_cpu(cmd.rx_data_timeout_uapsd));756	pos += scnprintf(buf+pos, bufsz-pos, "tx_data_timeout_uapsd = %d\n",757			 le32_to_cpu(cmd.tx_data_timeout_uapsd));758	pos += scnprintf(buf+pos, bufsz-pos, "qndp_tid = %d\n", cmd.qndp_tid);759	pos += scnprintf(buf+pos, bufsz-pos, "uapsd_ac_flags = 0x%x\n",760			 cmd.uapsd_ac_flags);761	pos += scnprintf(buf+pos, bufsz-pos, "uapsd_max_sp = %d\n",762			 cmd.uapsd_max_sp);763	pos += scnprintf(buf+pos, bufsz-pos, "heavy_tx_thld_packets = %d\n",764			 cmd.heavy_tx_thld_packets);765	pos += scnprintf(buf+pos, bufsz-pos, "heavy_rx_thld_packets = %d\n",766			 cmd.heavy_rx_thld_packets);767	pos += scnprintf(buf+pos, bufsz-pos, "heavy_tx_thld_percentage = %d\n",768			 cmd.heavy_tx_thld_percentage);769	pos += scnprintf(buf+pos, bufsz-pos, "heavy_rx_thld_percentage = %d\n",770			 cmd.heavy_rx_thld_percentage);771	pos += scnprintf(buf+pos, bufsz-pos, "uapsd_misbehaving_enable = %d\n",772			 (cmd.flags &773			  cpu_to_le16(POWER_FLAGS_UAPSD_MISBEHAVING_ENA_MSK)) ?774			 1 : 0);775 776	if (!(cmd.flags & cpu_to_le16(POWER_FLAGS_SNOOZE_ENA_MSK)))777		return pos;778 779	pos += scnprintf(buf+pos, bufsz-pos, "snooze_interval = %d\n",780			 cmd.snooze_interval);781	pos += scnprintf(buf+pos, bufsz-pos, "snooze_window = %d\n",782			 cmd.snooze_window);783 784	return pos;785}786 787void788iwl_mvm_beacon_filter_debugfs_parameters(struct ieee80211_vif *vif,789					 struct iwl_beacon_filter_cmd *cmd)790{791	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);792	struct iwl_dbgfs_bf *dbgfs_bf = &mvmvif->dbgfs_bf;793 794	if (dbgfs_bf->mask & MVM_DEBUGFS_BF_ENERGY_DELTA)795		cmd->bf_energy_delta = cpu_to_le32(dbgfs_bf->bf_energy_delta);796	if (dbgfs_bf->mask & MVM_DEBUGFS_BF_ROAMING_ENERGY_DELTA)797		cmd->bf_roaming_energy_delta =798				cpu_to_le32(dbgfs_bf->bf_roaming_energy_delta);799	if (dbgfs_bf->mask & MVM_DEBUGFS_BF_ROAMING_STATE)800		cmd->bf_roaming_state = cpu_to_le32(dbgfs_bf->bf_roaming_state);801	if (dbgfs_bf->mask & MVM_DEBUGFS_BF_TEMP_THRESHOLD)802		cmd->bf_temp_threshold =803				cpu_to_le32(dbgfs_bf->bf_temp_threshold);804	if (dbgfs_bf->mask & MVM_DEBUGFS_BF_TEMP_FAST_FILTER)805		cmd->bf_temp_fast_filter =806				cpu_to_le32(dbgfs_bf->bf_temp_fast_filter);807	if (dbgfs_bf->mask & MVM_DEBUGFS_BF_TEMP_SLOW_FILTER)808		cmd->bf_temp_slow_filter =809				cpu_to_le32(dbgfs_bf->bf_temp_slow_filter);810	if (dbgfs_bf->mask & MVM_DEBUGFS_BF_DEBUG_FLAG)811		cmd->bf_debug_flag = cpu_to_le32(dbgfs_bf->bf_debug_flag);812	if (dbgfs_bf->mask & MVM_DEBUGFS_BF_ESCAPE_TIMER)813		cmd->bf_escape_timer = cpu_to_le32(dbgfs_bf->bf_escape_timer);814	if (dbgfs_bf->mask & MVM_DEBUGFS_BA_ESCAPE_TIMER)815		cmd->ba_escape_timer = cpu_to_le32(dbgfs_bf->ba_escape_timer);816	if (dbgfs_bf->mask & MVM_DEBUGFS_BA_ENABLE_BEACON_ABORT)817		cmd->ba_enable_beacon_abort =818				cpu_to_le32(dbgfs_bf->ba_enable_beacon_abort);819}820#endif821 822static int _iwl_mvm_enable_beacon_filter(struct iwl_mvm *mvm,823					 struct ieee80211_vif *vif,824					 struct iwl_beacon_filter_cmd *cmd)825{826	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);827	int ret;828 829	if (mvmvif != mvm->bf_allowed_vif || !vif->bss_conf.dtim_period ||830	    vif->type != NL80211_IFTYPE_STATION || vif->p2p)831		return 0;832 833	iwl_mvm_beacon_filter_set_cqm_params(mvm, vif, cmd);834	iwl_mvm_beacon_filter_debugfs_parameters(vif, cmd);835	ret = iwl_mvm_beacon_filter_send_cmd(mvm, cmd);836 837	if (!ret)838		mvmvif->bf_enabled = true;839 840	return ret;841}842 843int iwl_mvm_enable_beacon_filter(struct iwl_mvm *mvm,844				 struct ieee80211_vif *vif)845{846	struct iwl_beacon_filter_cmd cmd = {847		IWL_BF_CMD_CONFIG_DEFAULTS,848		.bf_enable_beacon_filter = cpu_to_le32(1),849	};850 851	return _iwl_mvm_enable_beacon_filter(mvm, vif, &cmd);852}853 854static int _iwl_mvm_disable_beacon_filter(struct iwl_mvm *mvm,855					  struct ieee80211_vif *vif)856{857	struct iwl_beacon_filter_cmd cmd = {};858	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);859	int ret;860 861	if (vif->type != NL80211_IFTYPE_STATION || vif->p2p)862		return 0;863 864	ret = iwl_mvm_beacon_filter_send_cmd(mvm, &cmd);865 866	if (!ret)867		mvmvif->bf_enabled = false;868 869	return ret;870}871 872int iwl_mvm_disable_beacon_filter(struct iwl_mvm *mvm,873				  struct ieee80211_vif *vif)874{875	return _iwl_mvm_disable_beacon_filter(mvm, vif);876}877 878static int iwl_mvm_power_set_ps(struct iwl_mvm *mvm)879{880	bool disable_ps;881	int ret;882 883	/* disable PS if CAM */884	disable_ps = (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM);885	/* ...or if any of the vifs require PS to be off */886	ieee80211_iterate_active_interfaces_atomic(mvm->hw,887					IEEE80211_IFACE_ITER_NORMAL,888					iwl_mvm_power_ps_disabled_iterator,889					&disable_ps);890 891	/* update device power state if it has changed */892	if (mvm->ps_disabled != disable_ps) {893		bool old_ps_disabled = mvm->ps_disabled;894 895		mvm->ps_disabled = disable_ps;896		ret = iwl_mvm_power_update_device(mvm);897		if (ret) {898			mvm->ps_disabled = old_ps_disabled;899			return ret;900		}901	}902 903	return 0;904}905 906static int iwl_mvm_power_set_ba(struct iwl_mvm *mvm,907				struct ieee80211_vif *vif)908{909	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);910	struct iwl_beacon_filter_cmd cmd = {911		IWL_BF_CMD_CONFIG_DEFAULTS,912		.bf_enable_beacon_filter = cpu_to_le32(1),913	};914 915	if (!mvmvif->bf_enabled)916		return 0;917 918	if (test_bit(IWL_MVM_STATUS_IN_D3, &mvm->status))919		cmd.ba_escape_timer = cpu_to_le32(IWL_BA_ESCAPE_TIMER_D3);920 921	mvmvif->ba_enabled = !(!mvmvif->pm_enabled ||922			       mvm->ps_disabled ||923			       !vif->cfg.ps ||924			       iwl_mvm_vif_low_latency(mvmvif));925 926	return _iwl_mvm_enable_beacon_filter(mvm, vif, &cmd);927}928 929int iwl_mvm_power_update_ps(struct iwl_mvm *mvm)930{931	struct iwl_power_vifs vifs = {932		.mvm = mvm,933	};934	int ret;935 936	lockdep_assert_held(&mvm->mutex);937 938	/* get vifs info */939	ieee80211_iterate_active_interfaces_atomic(mvm->hw,940					IEEE80211_IFACE_ITER_NORMAL,941					iwl_mvm_power_get_vifs_iterator, &vifs);942 943	ret = iwl_mvm_power_set_ps(mvm);944	if (ret)945		return ret;946 947	if (vifs.bss_vif)948		return iwl_mvm_power_set_ba(mvm, vifs.bss_vif);949 950	return 0;951}952 953int iwl_mvm_power_update_mac(struct iwl_mvm *mvm)954{955	struct iwl_power_vifs vifs = {956		.mvm = mvm,957	};958	int ret;959 960	lockdep_assert_held(&mvm->mutex);961 962	/* get vifs info */963	ieee80211_iterate_active_interfaces_atomic(mvm->hw,964					IEEE80211_IFACE_ITER_NORMAL,965					iwl_mvm_power_get_vifs_iterator, &vifs);966 967	iwl_mvm_power_set_pm(mvm, &vifs);968 969	ret = iwl_mvm_power_set_ps(mvm);970	if (ret)971		return ret;972 973	if (vifs.bss_vif) {974		ret = iwl_mvm_power_send_cmd(mvm, vifs.bss_vif);975		if (ret)976			return ret;977	}978 979	if (vifs.p2p_vif) {980		ret = iwl_mvm_power_send_cmd(mvm, vifs.p2p_vif);981		if (ret)982			return ret;983	}984 985	if (vifs.bss_vif)986		return iwl_mvm_power_set_ba(mvm, vifs.bss_vif);987 988	return 0;989}990