162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/******************************************************************************
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Copyright(c) 2008 - 2014, 2022 Intel Corporation. All rights reserved.
562306a36Sopenharmony_ci *****************************************************************************/
662306a36Sopenharmony_ci#include <linux/etherdevice.h>
762306a36Sopenharmony_ci#include <linux/kernel.h>
862306a36Sopenharmony_ci#include <linux/module.h>
962306a36Sopenharmony_ci#include <linux/sched.h>
1062306a36Sopenharmony_ci#include <net/mac80211.h>
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#include "iwl-io.h"
1362306a36Sopenharmony_ci#include "iwl-agn-hw.h"
1462306a36Sopenharmony_ci#include "iwl-trans.h"
1562306a36Sopenharmony_ci#include "iwl-modparams.h"
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#include "dev.h"
1862306a36Sopenharmony_ci#include "agn.h"
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ciint iwlagn_hw_valid_rtc_data_addr(u32 addr)
2162306a36Sopenharmony_ci{
2262306a36Sopenharmony_ci	return (addr >= IWLAGN_RTC_DATA_LOWER_BOUND) &&
2362306a36Sopenharmony_ci		(addr < IWLAGN_RTC_DATA_UPPER_BOUND);
2462306a36Sopenharmony_ci}
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ciint iwlagn_send_tx_power(struct iwl_priv *priv)
2762306a36Sopenharmony_ci{
2862306a36Sopenharmony_ci	struct iwlagn_tx_power_dbm_cmd tx_power_cmd;
2962306a36Sopenharmony_ci	u8 tx_ant_cfg_cmd;
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci	if (WARN_ONCE(test_bit(STATUS_SCAN_HW, &priv->status),
3262306a36Sopenharmony_ci		      "TX Power requested while scanning!\n"))
3362306a36Sopenharmony_ci		return -EAGAIN;
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci	/* half dBm need to multiply */
3662306a36Sopenharmony_ci	tx_power_cmd.global_lmt = (s8)(2 * priv->tx_power_user_lmt);
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci	if (tx_power_cmd.global_lmt > priv->nvm_data->max_tx_pwr_half_dbm) {
3962306a36Sopenharmony_ci		/*
4062306a36Sopenharmony_ci		 * For the newer devices which using enhanced/extend tx power
4162306a36Sopenharmony_ci		 * table in EEPROM, the format is in half dBm. driver need to
4262306a36Sopenharmony_ci		 * convert to dBm format before report to mac80211.
4362306a36Sopenharmony_ci		 * By doing so, there is a possibility of 1/2 dBm resolution
4462306a36Sopenharmony_ci		 * lost. driver will perform "round-up" operation before
4562306a36Sopenharmony_ci		 * reporting, but it will cause 1/2 dBm tx power over the
4662306a36Sopenharmony_ci		 * regulatory limit. Perform the checking here, if the
4762306a36Sopenharmony_ci		 * "tx_power_user_lmt" is higher than EEPROM value (in
4862306a36Sopenharmony_ci		 * half-dBm format), lower the tx power based on EEPROM
4962306a36Sopenharmony_ci		 */
5062306a36Sopenharmony_ci		tx_power_cmd.global_lmt =
5162306a36Sopenharmony_ci			priv->nvm_data->max_tx_pwr_half_dbm;
5262306a36Sopenharmony_ci	}
5362306a36Sopenharmony_ci	tx_power_cmd.flags = IWLAGN_TX_POWER_NO_CLOSED;
5462306a36Sopenharmony_ci	tx_power_cmd.srv_chan_lmt = IWLAGN_TX_POWER_AUTO;
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci	if (IWL_UCODE_API(priv->fw->ucode_ver) == 1)
5762306a36Sopenharmony_ci		tx_ant_cfg_cmd = REPLY_TX_POWER_DBM_CMD_V1;
5862306a36Sopenharmony_ci	else
5962306a36Sopenharmony_ci		tx_ant_cfg_cmd = REPLY_TX_POWER_DBM_CMD;
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci	return iwl_dvm_send_cmd_pdu(priv, tx_ant_cfg_cmd, 0,
6262306a36Sopenharmony_ci			sizeof(tx_power_cmd), &tx_power_cmd);
6362306a36Sopenharmony_ci}
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_civoid iwlagn_temperature(struct iwl_priv *priv)
6662306a36Sopenharmony_ci{
6762306a36Sopenharmony_ci	lockdep_assert_held(&priv->statistics.lock);
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci	/* store temperature from correct statistics (in Celsius) */
7062306a36Sopenharmony_ci	priv->temperature = le32_to_cpu(priv->statistics.common.temperature);
7162306a36Sopenharmony_ci	iwl_tt_handler(priv);
7262306a36Sopenharmony_ci}
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ciint iwlagn_hwrate_to_mac80211_idx(u32 rate_n_flags, enum nl80211_band band)
7562306a36Sopenharmony_ci{
7662306a36Sopenharmony_ci	int idx = 0;
7762306a36Sopenharmony_ci	int band_offset = 0;
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci	/* HT rate format: mac80211 wants an MCS number, which is just LSB */
8062306a36Sopenharmony_ci	if (rate_n_flags & RATE_MCS_HT_MSK) {
8162306a36Sopenharmony_ci		idx = (rate_n_flags & 0xff);
8262306a36Sopenharmony_ci		return idx;
8362306a36Sopenharmony_ci	/* Legacy rate format, search for match in table */
8462306a36Sopenharmony_ci	} else {
8562306a36Sopenharmony_ci		if (band == NL80211_BAND_5GHZ)
8662306a36Sopenharmony_ci			band_offset = IWL_FIRST_OFDM_RATE;
8762306a36Sopenharmony_ci		for (idx = band_offset; idx < IWL_RATE_COUNT_LEGACY; idx++)
8862306a36Sopenharmony_ci			if (iwl_rates[idx].plcp == (rate_n_flags & 0xFF))
8962306a36Sopenharmony_ci				return idx - band_offset;
9062306a36Sopenharmony_ci	}
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci	return -1;
9362306a36Sopenharmony_ci}
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ciint iwlagn_manage_ibss_station(struct iwl_priv *priv,
9662306a36Sopenharmony_ci			       struct ieee80211_vif *vif, bool add)
9762306a36Sopenharmony_ci{
9862306a36Sopenharmony_ci	struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci	if (add)
10162306a36Sopenharmony_ci		return iwlagn_add_bssid_station(priv, vif_priv->ctx,
10262306a36Sopenharmony_ci						vif->bss_conf.bssid,
10362306a36Sopenharmony_ci						&vif_priv->ibss_bssid_sta_id);
10462306a36Sopenharmony_ci	return iwl_remove_station(priv, vif_priv->ibss_bssid_sta_id,
10562306a36Sopenharmony_ci				  vif->bss_conf.bssid);
10662306a36Sopenharmony_ci}
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci/*
10962306a36Sopenharmony_ci * iwlagn_txfifo_flush: send REPLY_TXFIFO_FLUSH command to uCode
11062306a36Sopenharmony_ci *
11162306a36Sopenharmony_ci * pre-requirements:
11262306a36Sopenharmony_ci *  1. acquire mutex before calling
11362306a36Sopenharmony_ci *  2. make sure rf is on and not in exit state
11462306a36Sopenharmony_ci */
11562306a36Sopenharmony_ciint iwlagn_txfifo_flush(struct iwl_priv *priv, u32 scd_q_msk)
11662306a36Sopenharmony_ci{
11762306a36Sopenharmony_ci	struct iwl_txfifo_flush_cmd_v3 flush_cmd_v3 = {
11862306a36Sopenharmony_ci		.flush_control = cpu_to_le16(IWL_DROP_ALL),
11962306a36Sopenharmony_ci	};
12062306a36Sopenharmony_ci	struct iwl_txfifo_flush_cmd_v2 flush_cmd_v2 = {
12162306a36Sopenharmony_ci		.flush_control = cpu_to_le16(IWL_DROP_ALL),
12262306a36Sopenharmony_ci	};
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci	u32 queue_control = IWL_SCD_VO_MSK | IWL_SCD_VI_MSK |
12562306a36Sopenharmony_ci			    IWL_SCD_BE_MSK | IWL_SCD_BK_MSK | IWL_SCD_MGMT_MSK;
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci	if ((priv->valid_contexts != BIT(IWL_RXON_CTX_BSS)))
12862306a36Sopenharmony_ci		queue_control |= IWL_PAN_SCD_VO_MSK | IWL_PAN_SCD_VI_MSK |
12962306a36Sopenharmony_ci				 IWL_PAN_SCD_BE_MSK | IWL_PAN_SCD_BK_MSK |
13062306a36Sopenharmony_ci				 IWL_PAN_SCD_MGMT_MSK |
13162306a36Sopenharmony_ci				 IWL_PAN_SCD_MULTICAST_MSK;
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci	if (priv->nvm_data->sku_cap_11n_enable)
13462306a36Sopenharmony_ci		queue_control |= IWL_AGG_TX_QUEUE_MSK;
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	if (scd_q_msk)
13762306a36Sopenharmony_ci		queue_control = scd_q_msk;
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci	IWL_DEBUG_INFO(priv, "queue control: 0x%x\n", queue_control);
14062306a36Sopenharmony_ci	flush_cmd_v3.queue_control = cpu_to_le32(queue_control);
14162306a36Sopenharmony_ci	flush_cmd_v2.queue_control = cpu_to_le16((u16)queue_control);
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci	if (IWL_UCODE_API(priv->fw->ucode_ver) > 2)
14462306a36Sopenharmony_ci		return iwl_dvm_send_cmd_pdu(priv, REPLY_TXFIFO_FLUSH, 0,
14562306a36Sopenharmony_ci					    sizeof(flush_cmd_v3),
14662306a36Sopenharmony_ci					    &flush_cmd_v3);
14762306a36Sopenharmony_ci	return iwl_dvm_send_cmd_pdu(priv, REPLY_TXFIFO_FLUSH, 0,
14862306a36Sopenharmony_ci				    sizeof(flush_cmd_v2), &flush_cmd_v2);
14962306a36Sopenharmony_ci}
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_civoid iwlagn_dev_txfifo_flush(struct iwl_priv *priv)
15262306a36Sopenharmony_ci{
15362306a36Sopenharmony_ci	mutex_lock(&priv->mutex);
15462306a36Sopenharmony_ci	ieee80211_stop_queues(priv->hw);
15562306a36Sopenharmony_ci	if (iwlagn_txfifo_flush(priv, 0)) {
15662306a36Sopenharmony_ci		IWL_ERR(priv, "flush request fail\n");
15762306a36Sopenharmony_ci		goto done;
15862306a36Sopenharmony_ci	}
15962306a36Sopenharmony_ci	IWL_DEBUG_INFO(priv, "wait transmit/flush all frames\n");
16062306a36Sopenharmony_ci	iwl_trans_wait_tx_queues_empty(priv->trans, 0xffffffff);
16162306a36Sopenharmony_cidone:
16262306a36Sopenharmony_ci	ieee80211_wake_queues(priv->hw);
16362306a36Sopenharmony_ci	mutex_unlock(&priv->mutex);
16462306a36Sopenharmony_ci}
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci/*
16762306a36Sopenharmony_ci * BT coex
16862306a36Sopenharmony_ci */
16962306a36Sopenharmony_ci/* Notmal TDM */
17062306a36Sopenharmony_cistatic const __le32 iwlagn_def_3w_lookup[IWLAGN_BT_DECISION_LUT_SIZE] = {
17162306a36Sopenharmony_ci	cpu_to_le32(0xaaaaaaaa),
17262306a36Sopenharmony_ci	cpu_to_le32(0xaaaaaaaa),
17362306a36Sopenharmony_ci	cpu_to_le32(0xaeaaaaaa),
17462306a36Sopenharmony_ci	cpu_to_le32(0xaaaaaaaa),
17562306a36Sopenharmony_ci	cpu_to_le32(0xcc00ff28),
17662306a36Sopenharmony_ci	cpu_to_le32(0x0000aaaa),
17762306a36Sopenharmony_ci	cpu_to_le32(0xcc00aaaa),
17862306a36Sopenharmony_ci	cpu_to_le32(0x0000aaaa),
17962306a36Sopenharmony_ci	cpu_to_le32(0xc0004000),
18062306a36Sopenharmony_ci	cpu_to_le32(0x00004000),
18162306a36Sopenharmony_ci	cpu_to_le32(0xf0005000),
18262306a36Sopenharmony_ci	cpu_to_le32(0xf0005000),
18362306a36Sopenharmony_ci};
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci/* Full concurrency */
18662306a36Sopenharmony_cistatic const __le32 iwlagn_concurrent_lookup[IWLAGN_BT_DECISION_LUT_SIZE] = {
18762306a36Sopenharmony_ci	cpu_to_le32(0xaaaaaaaa),
18862306a36Sopenharmony_ci	cpu_to_le32(0xaaaaaaaa),
18962306a36Sopenharmony_ci	cpu_to_le32(0xaaaaaaaa),
19062306a36Sopenharmony_ci	cpu_to_le32(0xaaaaaaaa),
19162306a36Sopenharmony_ci	cpu_to_le32(0xaaaaaaaa),
19262306a36Sopenharmony_ci	cpu_to_le32(0xaaaaaaaa),
19362306a36Sopenharmony_ci	cpu_to_le32(0xaaaaaaaa),
19462306a36Sopenharmony_ci	cpu_to_le32(0xaaaaaaaa),
19562306a36Sopenharmony_ci	cpu_to_le32(0x00000000),
19662306a36Sopenharmony_ci	cpu_to_le32(0x00000000),
19762306a36Sopenharmony_ci	cpu_to_le32(0x00000000),
19862306a36Sopenharmony_ci	cpu_to_le32(0x00000000),
19962306a36Sopenharmony_ci};
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_civoid iwlagn_send_advance_bt_config(struct iwl_priv *priv)
20262306a36Sopenharmony_ci{
20362306a36Sopenharmony_ci	struct iwl_basic_bt_cmd basic = {
20462306a36Sopenharmony_ci		.max_kill = IWLAGN_BT_MAX_KILL_DEFAULT,
20562306a36Sopenharmony_ci		.bt3_timer_t7_value = IWLAGN_BT3_T7_DEFAULT,
20662306a36Sopenharmony_ci		.bt3_prio_sample_time = IWLAGN_BT3_PRIO_SAMPLE_DEFAULT,
20762306a36Sopenharmony_ci		.bt3_timer_t2_value = IWLAGN_BT3_T2_DEFAULT,
20862306a36Sopenharmony_ci	};
20962306a36Sopenharmony_ci	struct iwl_bt_cmd_v1 bt_cmd_v1;
21062306a36Sopenharmony_ci	struct iwl_bt_cmd_v2 bt_cmd_v2;
21162306a36Sopenharmony_ci	int ret;
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci	BUILD_BUG_ON(sizeof(iwlagn_def_3w_lookup) !=
21462306a36Sopenharmony_ci			sizeof(basic.bt3_lookup_table));
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci	if (priv->lib->bt_params) {
21762306a36Sopenharmony_ci		/*
21862306a36Sopenharmony_ci		 * newer generation of devices (2000 series and newer)
21962306a36Sopenharmony_ci		 * use the version 2 of the bt command
22062306a36Sopenharmony_ci		 * we need to make sure sending the host command
22162306a36Sopenharmony_ci		 * with correct data structure to avoid uCode assert
22262306a36Sopenharmony_ci		 */
22362306a36Sopenharmony_ci		if (priv->lib->bt_params->bt_session_2) {
22462306a36Sopenharmony_ci			bt_cmd_v2.prio_boost = cpu_to_le32(
22562306a36Sopenharmony_ci				priv->lib->bt_params->bt_prio_boost);
22662306a36Sopenharmony_ci			bt_cmd_v2.tx_prio_boost = 0;
22762306a36Sopenharmony_ci			bt_cmd_v2.rx_prio_boost = 0;
22862306a36Sopenharmony_ci		} else {
22962306a36Sopenharmony_ci			/* older version only has 8 bits */
23062306a36Sopenharmony_ci			WARN_ON(priv->lib->bt_params->bt_prio_boost & ~0xFF);
23162306a36Sopenharmony_ci			bt_cmd_v1.prio_boost =
23262306a36Sopenharmony_ci				priv->lib->bt_params->bt_prio_boost;
23362306a36Sopenharmony_ci			bt_cmd_v1.tx_prio_boost = 0;
23462306a36Sopenharmony_ci			bt_cmd_v1.rx_prio_boost = 0;
23562306a36Sopenharmony_ci		}
23662306a36Sopenharmony_ci	} else {
23762306a36Sopenharmony_ci		IWL_ERR(priv, "failed to construct BT Coex Config\n");
23862306a36Sopenharmony_ci		return;
23962306a36Sopenharmony_ci	}
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci	/*
24262306a36Sopenharmony_ci	 * Possible situations when BT needs to take over for receive,
24362306a36Sopenharmony_ci	 * at the same time where STA needs to response to AP's frame(s),
24462306a36Sopenharmony_ci	 * reduce the tx power of the required response frames, by that,
24562306a36Sopenharmony_ci	 * allow the concurrent BT receive & WiFi transmit
24662306a36Sopenharmony_ci	 * (BT - ANT A, WiFi -ANT B), without interference to one another
24762306a36Sopenharmony_ci	 *
24862306a36Sopenharmony_ci	 * Reduced tx power apply to control frames only (ACK/Back/CTS)
24962306a36Sopenharmony_ci	 * when indicated by the BT config command
25062306a36Sopenharmony_ci	 */
25162306a36Sopenharmony_ci	basic.kill_ack_mask = priv->kill_ack_mask;
25262306a36Sopenharmony_ci	basic.kill_cts_mask = priv->kill_cts_mask;
25362306a36Sopenharmony_ci	if (priv->reduced_txpower)
25462306a36Sopenharmony_ci		basic.reduce_txpower = IWLAGN_BT_REDUCED_TX_PWR;
25562306a36Sopenharmony_ci	basic.valid = priv->bt_valid;
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci	/*
25862306a36Sopenharmony_ci	 * Configure BT coex mode to "no coexistence" when the
25962306a36Sopenharmony_ci	 * user disabled BT coexistence, we have no interface
26062306a36Sopenharmony_ci	 * (might be in monitor mode), or the interface is in
26162306a36Sopenharmony_ci	 * IBSS mode (no proper uCode support for coex then).
26262306a36Sopenharmony_ci	 */
26362306a36Sopenharmony_ci	if (!iwlwifi_mod_params.bt_coex_active ||
26462306a36Sopenharmony_ci	    priv->iw_mode == NL80211_IFTYPE_ADHOC) {
26562306a36Sopenharmony_ci		basic.flags = IWLAGN_BT_FLAG_COEX_MODE_DISABLED;
26662306a36Sopenharmony_ci	} else {
26762306a36Sopenharmony_ci		basic.flags = IWLAGN_BT_FLAG_COEX_MODE_3W <<
26862306a36Sopenharmony_ci					IWLAGN_BT_FLAG_COEX_MODE_SHIFT;
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci		if (!priv->bt_enable_pspoll)
27162306a36Sopenharmony_ci			basic.flags |= IWLAGN_BT_FLAG_SYNC_2_BT_DISABLE;
27262306a36Sopenharmony_ci		else
27362306a36Sopenharmony_ci			basic.flags &= ~IWLAGN_BT_FLAG_SYNC_2_BT_DISABLE;
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci		if (priv->bt_ch_announce)
27662306a36Sopenharmony_ci			basic.flags |= IWLAGN_BT_FLAG_CHANNEL_INHIBITION;
27762306a36Sopenharmony_ci		IWL_DEBUG_COEX(priv, "BT coex flag: 0X%x\n", basic.flags);
27862306a36Sopenharmony_ci	}
27962306a36Sopenharmony_ci	priv->bt_enable_flag = basic.flags;
28062306a36Sopenharmony_ci	if (priv->bt_full_concurrent)
28162306a36Sopenharmony_ci		memcpy(basic.bt3_lookup_table, iwlagn_concurrent_lookup,
28262306a36Sopenharmony_ci			sizeof(iwlagn_concurrent_lookup));
28362306a36Sopenharmony_ci	else
28462306a36Sopenharmony_ci		memcpy(basic.bt3_lookup_table, iwlagn_def_3w_lookup,
28562306a36Sopenharmony_ci			sizeof(iwlagn_def_3w_lookup));
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ci	IWL_DEBUG_COEX(priv, "BT coex %s in %s mode\n",
28862306a36Sopenharmony_ci		       basic.flags ? "active" : "disabled",
28962306a36Sopenharmony_ci		       priv->bt_full_concurrent ?
29062306a36Sopenharmony_ci		       "full concurrency" : "3-wire");
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci	if (priv->lib->bt_params->bt_session_2) {
29362306a36Sopenharmony_ci		memcpy(&bt_cmd_v2.basic, &basic,
29462306a36Sopenharmony_ci			sizeof(basic));
29562306a36Sopenharmony_ci		ret = iwl_dvm_send_cmd_pdu(priv, REPLY_BT_CONFIG,
29662306a36Sopenharmony_ci			0, sizeof(bt_cmd_v2), &bt_cmd_v2);
29762306a36Sopenharmony_ci	} else {
29862306a36Sopenharmony_ci		memcpy(&bt_cmd_v1.basic, &basic,
29962306a36Sopenharmony_ci			sizeof(basic));
30062306a36Sopenharmony_ci		ret = iwl_dvm_send_cmd_pdu(priv, REPLY_BT_CONFIG,
30162306a36Sopenharmony_ci			0, sizeof(bt_cmd_v1), &bt_cmd_v1);
30262306a36Sopenharmony_ci	}
30362306a36Sopenharmony_ci	if (ret)
30462306a36Sopenharmony_ci		IWL_ERR(priv, "failed to send BT Coex Config\n");
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci}
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_civoid iwlagn_bt_adjust_rssi_monitor(struct iwl_priv *priv, bool rssi_ena)
30962306a36Sopenharmony_ci{
31062306a36Sopenharmony_ci	struct iwl_rxon_context *ctx, *found_ctx = NULL;
31162306a36Sopenharmony_ci	bool found_ap = false;
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci	lockdep_assert_held(&priv->mutex);
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci	/* Check whether AP or GO mode is active. */
31662306a36Sopenharmony_ci	if (rssi_ena) {
31762306a36Sopenharmony_ci		for_each_context(priv, ctx) {
31862306a36Sopenharmony_ci			if (ctx->vif && ctx->vif->type == NL80211_IFTYPE_AP &&
31962306a36Sopenharmony_ci			    iwl_is_associated_ctx(ctx)) {
32062306a36Sopenharmony_ci				found_ap = true;
32162306a36Sopenharmony_ci				break;
32262306a36Sopenharmony_ci			}
32362306a36Sopenharmony_ci		}
32462306a36Sopenharmony_ci	}
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci	/*
32762306a36Sopenharmony_ci	 * If disable was received or If GO/AP mode, disable RSSI
32862306a36Sopenharmony_ci	 * measurements.
32962306a36Sopenharmony_ci	 */
33062306a36Sopenharmony_ci	if (!rssi_ena || found_ap) {
33162306a36Sopenharmony_ci		if (priv->cur_rssi_ctx) {
33262306a36Sopenharmony_ci			ctx = priv->cur_rssi_ctx;
33362306a36Sopenharmony_ci			ieee80211_disable_rssi_reports(ctx->vif);
33462306a36Sopenharmony_ci			priv->cur_rssi_ctx = NULL;
33562306a36Sopenharmony_ci		}
33662306a36Sopenharmony_ci		return;
33762306a36Sopenharmony_ci	}
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ci	/*
34062306a36Sopenharmony_ci	 * If rssi measurements need to be enabled, consider all cases now.
34162306a36Sopenharmony_ci	 * Figure out how many contexts are active.
34262306a36Sopenharmony_ci	 */
34362306a36Sopenharmony_ci	for_each_context(priv, ctx) {
34462306a36Sopenharmony_ci		if (ctx->vif && ctx->vif->type == NL80211_IFTYPE_STATION &&
34562306a36Sopenharmony_ci		    iwl_is_associated_ctx(ctx)) {
34662306a36Sopenharmony_ci			found_ctx = ctx;
34762306a36Sopenharmony_ci			break;
34862306a36Sopenharmony_ci		}
34962306a36Sopenharmony_ci	}
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci	/*
35262306a36Sopenharmony_ci	 * rssi monitor already enabled for the correct interface...nothing
35362306a36Sopenharmony_ci	 * to do.
35462306a36Sopenharmony_ci	 */
35562306a36Sopenharmony_ci	if (found_ctx == priv->cur_rssi_ctx)
35662306a36Sopenharmony_ci		return;
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci	/*
35962306a36Sopenharmony_ci	 * Figure out if rssi monitor is currently enabled, and needs
36062306a36Sopenharmony_ci	 * to be changed. If rssi monitor is already enabled, disable
36162306a36Sopenharmony_ci	 * it first else just enable rssi measurements on the
36262306a36Sopenharmony_ci	 * interface found above.
36362306a36Sopenharmony_ci	 */
36462306a36Sopenharmony_ci	if (priv->cur_rssi_ctx) {
36562306a36Sopenharmony_ci		ctx = priv->cur_rssi_ctx;
36662306a36Sopenharmony_ci		if (ctx->vif)
36762306a36Sopenharmony_ci			ieee80211_disable_rssi_reports(ctx->vif);
36862306a36Sopenharmony_ci	}
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci	priv->cur_rssi_ctx = found_ctx;
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci	if (!found_ctx)
37362306a36Sopenharmony_ci		return;
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci	ieee80211_enable_rssi_reports(found_ctx->vif,
37662306a36Sopenharmony_ci			IWLAGN_BT_PSP_MIN_RSSI_THRESHOLD,
37762306a36Sopenharmony_ci			IWLAGN_BT_PSP_MAX_RSSI_THRESHOLD);
37862306a36Sopenharmony_ci}
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_cistatic bool iwlagn_bt_traffic_is_sco(struct iwl_bt_uart_msg *uart_msg)
38162306a36Sopenharmony_ci{
38262306a36Sopenharmony_ci	return (BT_UART_MSG_FRAME3SCOESCO_MSK & uart_msg->frame3) >>
38362306a36Sopenharmony_ci		BT_UART_MSG_FRAME3SCOESCO_POS;
38462306a36Sopenharmony_ci}
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_cistatic void iwlagn_bt_traffic_change_work(struct work_struct *work)
38762306a36Sopenharmony_ci{
38862306a36Sopenharmony_ci	struct iwl_priv *priv =
38962306a36Sopenharmony_ci		container_of(work, struct iwl_priv, bt_traffic_change_work);
39062306a36Sopenharmony_ci	struct iwl_rxon_context *ctx;
39162306a36Sopenharmony_ci	int smps_request = -1;
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci	if (priv->bt_enable_flag == IWLAGN_BT_FLAG_COEX_MODE_DISABLED) {
39462306a36Sopenharmony_ci		/* bt coex disabled */
39562306a36Sopenharmony_ci		return;
39662306a36Sopenharmony_ci	}
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci	/*
39962306a36Sopenharmony_ci	 * Note: bt_traffic_load can be overridden by scan complete and
40062306a36Sopenharmony_ci	 * coex profile notifications. Ignore that since only bad consequence
40162306a36Sopenharmony_ci	 * can be not matching debug print with actual state.
40262306a36Sopenharmony_ci	 */
40362306a36Sopenharmony_ci	IWL_DEBUG_COEX(priv, "BT traffic load changes: %d\n",
40462306a36Sopenharmony_ci		       priv->bt_traffic_load);
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_ci	switch (priv->bt_traffic_load) {
40762306a36Sopenharmony_ci	case IWL_BT_COEX_TRAFFIC_LOAD_NONE:
40862306a36Sopenharmony_ci		if (priv->bt_status)
40962306a36Sopenharmony_ci			smps_request = IEEE80211_SMPS_DYNAMIC;
41062306a36Sopenharmony_ci		else
41162306a36Sopenharmony_ci			smps_request = IEEE80211_SMPS_AUTOMATIC;
41262306a36Sopenharmony_ci		break;
41362306a36Sopenharmony_ci	case IWL_BT_COEX_TRAFFIC_LOAD_LOW:
41462306a36Sopenharmony_ci		smps_request = IEEE80211_SMPS_DYNAMIC;
41562306a36Sopenharmony_ci		break;
41662306a36Sopenharmony_ci	case IWL_BT_COEX_TRAFFIC_LOAD_HIGH:
41762306a36Sopenharmony_ci	case IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS:
41862306a36Sopenharmony_ci		smps_request = IEEE80211_SMPS_STATIC;
41962306a36Sopenharmony_ci		break;
42062306a36Sopenharmony_ci	default:
42162306a36Sopenharmony_ci		IWL_ERR(priv, "Invalid BT traffic load: %d\n",
42262306a36Sopenharmony_ci			priv->bt_traffic_load);
42362306a36Sopenharmony_ci		break;
42462306a36Sopenharmony_ci	}
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci	mutex_lock(&priv->mutex);
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_ci	/*
42962306a36Sopenharmony_ci	 * We can not send command to firmware while scanning. When the scan
43062306a36Sopenharmony_ci	 * complete we will schedule this work again. We do check with mutex
43162306a36Sopenharmony_ci	 * locked to prevent new scan request to arrive. We do not check
43262306a36Sopenharmony_ci	 * STATUS_SCANNING to avoid race when queue_work two times from
43362306a36Sopenharmony_ci	 * different notifications, but quit and not perform any work at all.
43462306a36Sopenharmony_ci	 */
43562306a36Sopenharmony_ci	if (test_bit(STATUS_SCAN_HW, &priv->status))
43662306a36Sopenharmony_ci		goto out;
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci	iwl_update_chain_flags(priv);
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_ci	if (smps_request != -1) {
44162306a36Sopenharmony_ci		priv->current_ht_config.smps = smps_request;
44262306a36Sopenharmony_ci		for_each_context(priv, ctx) {
44362306a36Sopenharmony_ci			if (ctx->vif && ctx->vif->type == NL80211_IFTYPE_STATION)
44462306a36Sopenharmony_ci				ieee80211_request_smps(ctx->vif, 0, smps_request);
44562306a36Sopenharmony_ci		}
44662306a36Sopenharmony_ci	}
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_ci	/*
44962306a36Sopenharmony_ci	 * Dynamic PS poll related functionality. Adjust RSSI measurements if
45062306a36Sopenharmony_ci	 * necessary.
45162306a36Sopenharmony_ci	 */
45262306a36Sopenharmony_ci	iwlagn_bt_coex_rssi_monitor(priv);
45362306a36Sopenharmony_ciout:
45462306a36Sopenharmony_ci	mutex_unlock(&priv->mutex);
45562306a36Sopenharmony_ci}
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ci/*
45862306a36Sopenharmony_ci * If BT sco traffic, and RSSI monitor is enabled, move measurements to the
45962306a36Sopenharmony_ci * correct interface or disable it if this is the last interface to be
46062306a36Sopenharmony_ci * removed.
46162306a36Sopenharmony_ci */
46262306a36Sopenharmony_civoid iwlagn_bt_coex_rssi_monitor(struct iwl_priv *priv)
46362306a36Sopenharmony_ci{
46462306a36Sopenharmony_ci	if (priv->bt_is_sco &&
46562306a36Sopenharmony_ci	    priv->bt_traffic_load == IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS)
46662306a36Sopenharmony_ci		iwlagn_bt_adjust_rssi_monitor(priv, true);
46762306a36Sopenharmony_ci	else
46862306a36Sopenharmony_ci		iwlagn_bt_adjust_rssi_monitor(priv, false);
46962306a36Sopenharmony_ci}
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_cistatic void iwlagn_print_uartmsg(struct iwl_priv *priv,
47262306a36Sopenharmony_ci				struct iwl_bt_uart_msg *uart_msg)
47362306a36Sopenharmony_ci{
47462306a36Sopenharmony_ci	IWL_DEBUG_COEX(priv, "Message Type = 0x%X, SSN = 0x%X, "
47562306a36Sopenharmony_ci			"Update Req = 0x%X\n",
47662306a36Sopenharmony_ci		(BT_UART_MSG_FRAME1MSGTYPE_MSK & uart_msg->frame1) >>
47762306a36Sopenharmony_ci			BT_UART_MSG_FRAME1MSGTYPE_POS,
47862306a36Sopenharmony_ci		(BT_UART_MSG_FRAME1SSN_MSK & uart_msg->frame1) >>
47962306a36Sopenharmony_ci			BT_UART_MSG_FRAME1SSN_POS,
48062306a36Sopenharmony_ci		(BT_UART_MSG_FRAME1UPDATEREQ_MSK & uart_msg->frame1) >>
48162306a36Sopenharmony_ci			BT_UART_MSG_FRAME1UPDATEREQ_POS);
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_ci	IWL_DEBUG_COEX(priv, "Open connections = 0x%X, Traffic load = 0x%X, "
48462306a36Sopenharmony_ci			"Chl_SeqN = 0x%X, In band = 0x%X\n",
48562306a36Sopenharmony_ci		(BT_UART_MSG_FRAME2OPENCONNECTIONS_MSK & uart_msg->frame2) >>
48662306a36Sopenharmony_ci			BT_UART_MSG_FRAME2OPENCONNECTIONS_POS,
48762306a36Sopenharmony_ci		(BT_UART_MSG_FRAME2TRAFFICLOAD_MSK & uart_msg->frame2) >>
48862306a36Sopenharmony_ci			BT_UART_MSG_FRAME2TRAFFICLOAD_POS,
48962306a36Sopenharmony_ci		(BT_UART_MSG_FRAME2CHLSEQN_MSK & uart_msg->frame2) >>
49062306a36Sopenharmony_ci			BT_UART_MSG_FRAME2CHLSEQN_POS,
49162306a36Sopenharmony_ci		(BT_UART_MSG_FRAME2INBAND_MSK & uart_msg->frame2) >>
49262306a36Sopenharmony_ci			BT_UART_MSG_FRAME2INBAND_POS);
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_ci	IWL_DEBUG_COEX(priv, "SCO/eSCO = 0x%X, Sniff = 0x%X, A2DP = 0x%X, "
49562306a36Sopenharmony_ci			"ACL = 0x%X, Master = 0x%X, OBEX = 0x%X\n",
49662306a36Sopenharmony_ci		(BT_UART_MSG_FRAME3SCOESCO_MSK & uart_msg->frame3) >>
49762306a36Sopenharmony_ci			BT_UART_MSG_FRAME3SCOESCO_POS,
49862306a36Sopenharmony_ci		(BT_UART_MSG_FRAME3SNIFF_MSK & uart_msg->frame3) >>
49962306a36Sopenharmony_ci			BT_UART_MSG_FRAME3SNIFF_POS,
50062306a36Sopenharmony_ci		(BT_UART_MSG_FRAME3A2DP_MSK & uart_msg->frame3) >>
50162306a36Sopenharmony_ci			BT_UART_MSG_FRAME3A2DP_POS,
50262306a36Sopenharmony_ci		(BT_UART_MSG_FRAME3ACL_MSK & uart_msg->frame3) >>
50362306a36Sopenharmony_ci			BT_UART_MSG_FRAME3ACL_POS,
50462306a36Sopenharmony_ci		(BT_UART_MSG_FRAME3MASTER_MSK & uart_msg->frame3) >>
50562306a36Sopenharmony_ci			BT_UART_MSG_FRAME3MASTER_POS,
50662306a36Sopenharmony_ci		(BT_UART_MSG_FRAME3OBEX_MSK & uart_msg->frame3) >>
50762306a36Sopenharmony_ci			BT_UART_MSG_FRAME3OBEX_POS);
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci	IWL_DEBUG_COEX(priv, "Idle duration = 0x%X\n",
51062306a36Sopenharmony_ci		(BT_UART_MSG_FRAME4IDLEDURATION_MSK & uart_msg->frame4) >>
51162306a36Sopenharmony_ci			BT_UART_MSG_FRAME4IDLEDURATION_POS);
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_ci	IWL_DEBUG_COEX(priv, "Tx Activity = 0x%X, Rx Activity = 0x%X, "
51462306a36Sopenharmony_ci			"eSCO Retransmissions = 0x%X\n",
51562306a36Sopenharmony_ci		(BT_UART_MSG_FRAME5TXACTIVITY_MSK & uart_msg->frame5) >>
51662306a36Sopenharmony_ci			BT_UART_MSG_FRAME5TXACTIVITY_POS,
51762306a36Sopenharmony_ci		(BT_UART_MSG_FRAME5RXACTIVITY_MSK & uart_msg->frame5) >>
51862306a36Sopenharmony_ci			BT_UART_MSG_FRAME5RXACTIVITY_POS,
51962306a36Sopenharmony_ci		(BT_UART_MSG_FRAME5ESCORETRANSMIT_MSK & uart_msg->frame5) >>
52062306a36Sopenharmony_ci			BT_UART_MSG_FRAME5ESCORETRANSMIT_POS);
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_ci	IWL_DEBUG_COEX(priv, "Sniff Interval = 0x%X, Discoverable = 0x%X\n",
52362306a36Sopenharmony_ci		(BT_UART_MSG_FRAME6SNIFFINTERVAL_MSK & uart_msg->frame6) >>
52462306a36Sopenharmony_ci			BT_UART_MSG_FRAME6SNIFFINTERVAL_POS,
52562306a36Sopenharmony_ci		(BT_UART_MSG_FRAME6DISCOVERABLE_MSK & uart_msg->frame6) >>
52662306a36Sopenharmony_ci			BT_UART_MSG_FRAME6DISCOVERABLE_POS);
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_ci	IWL_DEBUG_COEX(priv, "Sniff Activity = 0x%X, Page = "
52962306a36Sopenharmony_ci			"0x%X, Inquiry = 0x%X, Connectable = 0x%X\n",
53062306a36Sopenharmony_ci		(BT_UART_MSG_FRAME7SNIFFACTIVITY_MSK & uart_msg->frame7) >>
53162306a36Sopenharmony_ci			BT_UART_MSG_FRAME7SNIFFACTIVITY_POS,
53262306a36Sopenharmony_ci		(BT_UART_MSG_FRAME7PAGE_MSK & uart_msg->frame7) >>
53362306a36Sopenharmony_ci			BT_UART_MSG_FRAME7PAGE_POS,
53462306a36Sopenharmony_ci		(BT_UART_MSG_FRAME7INQUIRY_MSK & uart_msg->frame7) >>
53562306a36Sopenharmony_ci			BT_UART_MSG_FRAME7INQUIRY_POS,
53662306a36Sopenharmony_ci		(BT_UART_MSG_FRAME7CONNECTABLE_MSK & uart_msg->frame7) >>
53762306a36Sopenharmony_ci			BT_UART_MSG_FRAME7CONNECTABLE_POS);
53862306a36Sopenharmony_ci}
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_cistatic bool iwlagn_set_kill_msk(struct iwl_priv *priv,
54162306a36Sopenharmony_ci				struct iwl_bt_uart_msg *uart_msg)
54262306a36Sopenharmony_ci{
54362306a36Sopenharmony_ci	bool need_update = false;
54462306a36Sopenharmony_ci	u8 kill_msk = IWL_BT_KILL_REDUCE;
54562306a36Sopenharmony_ci	static const __le32 bt_kill_ack_msg[3] = {
54662306a36Sopenharmony_ci		IWLAGN_BT_KILL_ACK_MASK_DEFAULT,
54762306a36Sopenharmony_ci		IWLAGN_BT_KILL_ACK_CTS_MASK_SCO,
54862306a36Sopenharmony_ci		IWLAGN_BT_KILL_ACK_CTS_MASK_REDUCE};
54962306a36Sopenharmony_ci	static const __le32 bt_kill_cts_msg[3] = {
55062306a36Sopenharmony_ci		IWLAGN_BT_KILL_CTS_MASK_DEFAULT,
55162306a36Sopenharmony_ci		IWLAGN_BT_KILL_ACK_CTS_MASK_SCO,
55262306a36Sopenharmony_ci		IWLAGN_BT_KILL_ACK_CTS_MASK_REDUCE};
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_ci	if (!priv->reduced_txpower)
55562306a36Sopenharmony_ci		kill_msk = (BT_UART_MSG_FRAME3SCOESCO_MSK & uart_msg->frame3)
55662306a36Sopenharmony_ci			? IWL_BT_KILL_OVERRIDE : IWL_BT_KILL_DEFAULT;
55762306a36Sopenharmony_ci	if (priv->kill_ack_mask != bt_kill_ack_msg[kill_msk] ||
55862306a36Sopenharmony_ci	    priv->kill_cts_mask != bt_kill_cts_msg[kill_msk]) {
55962306a36Sopenharmony_ci		priv->bt_valid |= IWLAGN_BT_VALID_KILL_ACK_MASK;
56062306a36Sopenharmony_ci		priv->kill_ack_mask = bt_kill_ack_msg[kill_msk];
56162306a36Sopenharmony_ci		priv->bt_valid |= IWLAGN_BT_VALID_KILL_CTS_MASK;
56262306a36Sopenharmony_ci		priv->kill_cts_mask = bt_kill_cts_msg[kill_msk];
56362306a36Sopenharmony_ci		need_update = true;
56462306a36Sopenharmony_ci	}
56562306a36Sopenharmony_ci	return need_update;
56662306a36Sopenharmony_ci}
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_ci/*
56962306a36Sopenharmony_ci * Upon RSSI changes, sends a bt config command with following changes
57062306a36Sopenharmony_ci *  1. enable/disable "reduced control frames tx power
57162306a36Sopenharmony_ci *  2. update the "kill)ack_mask" and "kill_cts_mask"
57262306a36Sopenharmony_ci *
57362306a36Sopenharmony_ci * If "reduced tx power" is enabled, uCode shall
57462306a36Sopenharmony_ci *  1. ACK/Back/CTS rate shall reduced to 6Mbps
57562306a36Sopenharmony_ci *  2. not use duplciate 20/40MHz mode
57662306a36Sopenharmony_ci */
57762306a36Sopenharmony_cistatic bool iwlagn_fill_txpower_mode(struct iwl_priv *priv,
57862306a36Sopenharmony_ci				struct iwl_bt_uart_msg *uart_msg)
57962306a36Sopenharmony_ci{
58062306a36Sopenharmony_ci	bool need_update = false;
58162306a36Sopenharmony_ci	struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
58262306a36Sopenharmony_ci	int ave_rssi;
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci	if (!ctx->vif || (ctx->vif->type != NL80211_IFTYPE_STATION)) {
58562306a36Sopenharmony_ci		IWL_DEBUG_INFO(priv, "BSS ctx not active or not in sta mode\n");
58662306a36Sopenharmony_ci		return false;
58762306a36Sopenharmony_ci	}
58862306a36Sopenharmony_ci
58962306a36Sopenharmony_ci	ave_rssi = ieee80211_ave_rssi(ctx->vif);
59062306a36Sopenharmony_ci	if (!ave_rssi) {
59162306a36Sopenharmony_ci		/* no rssi data, no changes to reduce tx power */
59262306a36Sopenharmony_ci		IWL_DEBUG_COEX(priv, "no rssi data available\n");
59362306a36Sopenharmony_ci		return need_update;
59462306a36Sopenharmony_ci	}
59562306a36Sopenharmony_ci	if (!priv->reduced_txpower &&
59662306a36Sopenharmony_ci	    !iwl_is_associated(priv, IWL_RXON_CTX_PAN) &&
59762306a36Sopenharmony_ci	    (ave_rssi > BT_ENABLE_REDUCED_TXPOWER_THRESHOLD) &&
59862306a36Sopenharmony_ci	    (uart_msg->frame3 & (BT_UART_MSG_FRAME3ACL_MSK |
59962306a36Sopenharmony_ci	    BT_UART_MSG_FRAME3OBEX_MSK)) &&
60062306a36Sopenharmony_ci	    !(uart_msg->frame3 & (BT_UART_MSG_FRAME3SCOESCO_MSK |
60162306a36Sopenharmony_ci	    BT_UART_MSG_FRAME3SNIFF_MSK | BT_UART_MSG_FRAME3A2DP_MSK))) {
60262306a36Sopenharmony_ci		/* enabling reduced tx power */
60362306a36Sopenharmony_ci		priv->reduced_txpower = true;
60462306a36Sopenharmony_ci		priv->bt_valid |= IWLAGN_BT_VALID_REDUCED_TX_PWR;
60562306a36Sopenharmony_ci		need_update = true;
60662306a36Sopenharmony_ci	} else if (priv->reduced_txpower &&
60762306a36Sopenharmony_ci		   (iwl_is_associated(priv, IWL_RXON_CTX_PAN) ||
60862306a36Sopenharmony_ci		   (ave_rssi < BT_DISABLE_REDUCED_TXPOWER_THRESHOLD) ||
60962306a36Sopenharmony_ci		   (uart_msg->frame3 & (BT_UART_MSG_FRAME3SCOESCO_MSK |
61062306a36Sopenharmony_ci		   BT_UART_MSG_FRAME3SNIFF_MSK | BT_UART_MSG_FRAME3A2DP_MSK)) ||
61162306a36Sopenharmony_ci		   !(uart_msg->frame3 & (BT_UART_MSG_FRAME3ACL_MSK |
61262306a36Sopenharmony_ci		   BT_UART_MSG_FRAME3OBEX_MSK)))) {
61362306a36Sopenharmony_ci		/* disable reduced tx power */
61462306a36Sopenharmony_ci		priv->reduced_txpower = false;
61562306a36Sopenharmony_ci		priv->bt_valid |= IWLAGN_BT_VALID_REDUCED_TX_PWR;
61662306a36Sopenharmony_ci		need_update = true;
61762306a36Sopenharmony_ci	}
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_ci	return need_update;
62062306a36Sopenharmony_ci}
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_cistatic void iwlagn_bt_coex_profile_notif(struct iwl_priv *priv,
62362306a36Sopenharmony_ci					 struct iwl_rx_cmd_buffer *rxb)
62462306a36Sopenharmony_ci{
62562306a36Sopenharmony_ci	struct iwl_rx_packet *pkt = rxb_addr(rxb);
62662306a36Sopenharmony_ci	struct iwl_bt_coex_profile_notif *coex = (void *)pkt->data;
62762306a36Sopenharmony_ci	struct iwl_bt_uart_msg *uart_msg = &coex->last_bt_uart_msg;
62862306a36Sopenharmony_ci
62962306a36Sopenharmony_ci	if (priv->bt_enable_flag == IWLAGN_BT_FLAG_COEX_MODE_DISABLED) {
63062306a36Sopenharmony_ci		/* bt coex disabled */
63162306a36Sopenharmony_ci		return;
63262306a36Sopenharmony_ci	}
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_ci	IWL_DEBUG_COEX(priv, "BT Coex notification:\n");
63562306a36Sopenharmony_ci	IWL_DEBUG_COEX(priv, "    status: %d\n", coex->bt_status);
63662306a36Sopenharmony_ci	IWL_DEBUG_COEX(priv, "    traffic load: %d\n", coex->bt_traffic_load);
63762306a36Sopenharmony_ci	IWL_DEBUG_COEX(priv, "    CI compliance: %d\n",
63862306a36Sopenharmony_ci			coex->bt_ci_compliance);
63962306a36Sopenharmony_ci	iwlagn_print_uartmsg(priv, uart_msg);
64062306a36Sopenharmony_ci
64162306a36Sopenharmony_ci	priv->last_bt_traffic_load = priv->bt_traffic_load;
64262306a36Sopenharmony_ci	priv->bt_is_sco = iwlagn_bt_traffic_is_sco(uart_msg);
64362306a36Sopenharmony_ci
64462306a36Sopenharmony_ci	if (priv->iw_mode != NL80211_IFTYPE_ADHOC) {
64562306a36Sopenharmony_ci		if (priv->bt_status != coex->bt_status ||
64662306a36Sopenharmony_ci		    priv->last_bt_traffic_load != coex->bt_traffic_load) {
64762306a36Sopenharmony_ci			if (coex->bt_status) {
64862306a36Sopenharmony_ci				/* BT on */
64962306a36Sopenharmony_ci				if (!priv->bt_ch_announce)
65062306a36Sopenharmony_ci					priv->bt_traffic_load =
65162306a36Sopenharmony_ci						IWL_BT_COEX_TRAFFIC_LOAD_HIGH;
65262306a36Sopenharmony_ci				else
65362306a36Sopenharmony_ci					priv->bt_traffic_load =
65462306a36Sopenharmony_ci						coex->bt_traffic_load;
65562306a36Sopenharmony_ci			} else {
65662306a36Sopenharmony_ci				/* BT off */
65762306a36Sopenharmony_ci				priv->bt_traffic_load =
65862306a36Sopenharmony_ci					IWL_BT_COEX_TRAFFIC_LOAD_NONE;
65962306a36Sopenharmony_ci			}
66062306a36Sopenharmony_ci			priv->bt_status = coex->bt_status;
66162306a36Sopenharmony_ci			queue_work(priv->workqueue,
66262306a36Sopenharmony_ci				   &priv->bt_traffic_change_work);
66362306a36Sopenharmony_ci		}
66462306a36Sopenharmony_ci	}
66562306a36Sopenharmony_ci
66662306a36Sopenharmony_ci	/* schedule to send runtime bt_config */
66762306a36Sopenharmony_ci	/* check reduce power before change ack/cts kill mask */
66862306a36Sopenharmony_ci	if (iwlagn_fill_txpower_mode(priv, uart_msg) ||
66962306a36Sopenharmony_ci	    iwlagn_set_kill_msk(priv, uart_msg))
67062306a36Sopenharmony_ci		queue_work(priv->workqueue, &priv->bt_runtime_config);
67162306a36Sopenharmony_ci
67262306a36Sopenharmony_ci
67362306a36Sopenharmony_ci	/* FIXME: based on notification, adjust the prio_boost */
67462306a36Sopenharmony_ci
67562306a36Sopenharmony_ci	priv->bt_ci_compliance = coex->bt_ci_compliance;
67662306a36Sopenharmony_ci}
67762306a36Sopenharmony_ci
67862306a36Sopenharmony_civoid iwlagn_bt_rx_handler_setup(struct iwl_priv *priv)
67962306a36Sopenharmony_ci{
68062306a36Sopenharmony_ci	priv->rx_handlers[REPLY_BT_COEX_PROFILE_NOTIF] =
68162306a36Sopenharmony_ci		iwlagn_bt_coex_profile_notif;
68262306a36Sopenharmony_ci}
68362306a36Sopenharmony_ci
68462306a36Sopenharmony_civoid iwlagn_bt_setup_deferred_work(struct iwl_priv *priv)
68562306a36Sopenharmony_ci{
68662306a36Sopenharmony_ci	INIT_WORK(&priv->bt_traffic_change_work,
68762306a36Sopenharmony_ci		  iwlagn_bt_traffic_change_work);
68862306a36Sopenharmony_ci}
68962306a36Sopenharmony_ci
69062306a36Sopenharmony_civoid iwlagn_bt_cancel_deferred_work(struct iwl_priv *priv)
69162306a36Sopenharmony_ci{
69262306a36Sopenharmony_ci	cancel_work_sync(&priv->bt_traffic_change_work);
69362306a36Sopenharmony_ci}
69462306a36Sopenharmony_ci
69562306a36Sopenharmony_cistatic bool is_single_rx_stream(struct iwl_priv *priv)
69662306a36Sopenharmony_ci{
69762306a36Sopenharmony_ci	return priv->current_ht_config.smps == IEEE80211_SMPS_STATIC ||
69862306a36Sopenharmony_ci	       priv->current_ht_config.single_chain_sufficient;
69962306a36Sopenharmony_ci}
70062306a36Sopenharmony_ci
70162306a36Sopenharmony_ci#define IWL_NUM_RX_CHAINS_MULTIPLE	3
70262306a36Sopenharmony_ci#define IWL_NUM_RX_CHAINS_SINGLE	2
70362306a36Sopenharmony_ci#define IWL_NUM_IDLE_CHAINS_DUAL	2
70462306a36Sopenharmony_ci#define IWL_NUM_IDLE_CHAINS_SINGLE	1
70562306a36Sopenharmony_ci
70662306a36Sopenharmony_ci/*
70762306a36Sopenharmony_ci * Determine how many receiver/antenna chains to use.
70862306a36Sopenharmony_ci *
70962306a36Sopenharmony_ci * More provides better reception via diversity.  Fewer saves power
71062306a36Sopenharmony_ci * at the expense of throughput, but only when not in powersave to
71162306a36Sopenharmony_ci * start with.
71262306a36Sopenharmony_ci *
71362306a36Sopenharmony_ci * MIMO (dual stream) requires at least 2, but works better with 3.
71462306a36Sopenharmony_ci * This does not determine *which* chains to use, just how many.
71562306a36Sopenharmony_ci */
71662306a36Sopenharmony_cistatic int iwl_get_active_rx_chain_count(struct iwl_priv *priv)
71762306a36Sopenharmony_ci{
71862306a36Sopenharmony_ci	if (priv->lib->bt_params &&
71962306a36Sopenharmony_ci	    priv->lib->bt_params->advanced_bt_coexist &&
72062306a36Sopenharmony_ci	    (priv->bt_full_concurrent ||
72162306a36Sopenharmony_ci	     priv->bt_traffic_load >= IWL_BT_COEX_TRAFFIC_LOAD_HIGH)) {
72262306a36Sopenharmony_ci		/*
72362306a36Sopenharmony_ci		 * only use chain 'A' in bt high traffic load or
72462306a36Sopenharmony_ci		 * full concurrency mode
72562306a36Sopenharmony_ci		 */
72662306a36Sopenharmony_ci		return IWL_NUM_RX_CHAINS_SINGLE;
72762306a36Sopenharmony_ci	}
72862306a36Sopenharmony_ci	/* # of Rx chains to use when expecting MIMO. */
72962306a36Sopenharmony_ci	if (is_single_rx_stream(priv))
73062306a36Sopenharmony_ci		return IWL_NUM_RX_CHAINS_SINGLE;
73162306a36Sopenharmony_ci	else
73262306a36Sopenharmony_ci		return IWL_NUM_RX_CHAINS_MULTIPLE;
73362306a36Sopenharmony_ci}
73462306a36Sopenharmony_ci
73562306a36Sopenharmony_ci/*
73662306a36Sopenharmony_ci * When we are in power saving mode, unless device support spatial
73762306a36Sopenharmony_ci * multiplexing power save, use the active count for rx chain count.
73862306a36Sopenharmony_ci */
73962306a36Sopenharmony_cistatic int iwl_get_idle_rx_chain_count(struct iwl_priv *priv, int active_cnt)
74062306a36Sopenharmony_ci{
74162306a36Sopenharmony_ci	/* # Rx chains when idling, depending on SMPS mode */
74262306a36Sopenharmony_ci	switch (priv->current_ht_config.smps) {
74362306a36Sopenharmony_ci	case IEEE80211_SMPS_STATIC:
74462306a36Sopenharmony_ci	case IEEE80211_SMPS_DYNAMIC:
74562306a36Sopenharmony_ci		return IWL_NUM_IDLE_CHAINS_SINGLE;
74662306a36Sopenharmony_ci	case IEEE80211_SMPS_AUTOMATIC:
74762306a36Sopenharmony_ci	case IEEE80211_SMPS_OFF:
74862306a36Sopenharmony_ci		return active_cnt;
74962306a36Sopenharmony_ci	default:
75062306a36Sopenharmony_ci		WARN(1, "invalid SMPS mode %d",
75162306a36Sopenharmony_ci		     priv->current_ht_config.smps);
75262306a36Sopenharmony_ci		return active_cnt;
75362306a36Sopenharmony_ci	}
75462306a36Sopenharmony_ci}
75562306a36Sopenharmony_ci
75662306a36Sopenharmony_ci/* up to 4 chains */
75762306a36Sopenharmony_cistatic u8 iwl_count_chain_bitmap(u32 chain_bitmap)
75862306a36Sopenharmony_ci{
75962306a36Sopenharmony_ci	u8 res;
76062306a36Sopenharmony_ci	res = (chain_bitmap & BIT(0)) >> 0;
76162306a36Sopenharmony_ci	res += (chain_bitmap & BIT(1)) >> 1;
76262306a36Sopenharmony_ci	res += (chain_bitmap & BIT(2)) >> 2;
76362306a36Sopenharmony_ci	res += (chain_bitmap & BIT(3)) >> 3;
76462306a36Sopenharmony_ci	return res;
76562306a36Sopenharmony_ci}
76662306a36Sopenharmony_ci
76762306a36Sopenharmony_ci/*
76862306a36Sopenharmony_ci * iwlagn_set_rxon_chain - Set up Rx chain usage in "staging" RXON image
76962306a36Sopenharmony_ci *
77062306a36Sopenharmony_ci * Selects how many and which Rx receivers/antennas/chains to use.
77162306a36Sopenharmony_ci * This should not be used for scan command ... it puts data in wrong place.
77262306a36Sopenharmony_ci */
77362306a36Sopenharmony_civoid iwlagn_set_rxon_chain(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
77462306a36Sopenharmony_ci{
77562306a36Sopenharmony_ci	bool is_single = is_single_rx_stream(priv);
77662306a36Sopenharmony_ci	bool is_cam = !test_bit(STATUS_POWER_PMI, &priv->status);
77762306a36Sopenharmony_ci	u8 idle_rx_cnt, active_rx_cnt, valid_rx_cnt;
77862306a36Sopenharmony_ci	u32 active_chains;
77962306a36Sopenharmony_ci	u16 rx_chain;
78062306a36Sopenharmony_ci
78162306a36Sopenharmony_ci	/* Tell uCode which antennas are actually connected.
78262306a36Sopenharmony_ci	 * Before first association, we assume all antennas are connected.
78362306a36Sopenharmony_ci	 * Just after first association, iwl_chain_noise_calibration()
78462306a36Sopenharmony_ci	 *    checks which antennas actually *are* connected. */
78562306a36Sopenharmony_ci	if (priv->chain_noise_data.active_chains)
78662306a36Sopenharmony_ci		active_chains = priv->chain_noise_data.active_chains;
78762306a36Sopenharmony_ci	else
78862306a36Sopenharmony_ci		active_chains = priv->nvm_data->valid_rx_ant;
78962306a36Sopenharmony_ci
79062306a36Sopenharmony_ci	if (priv->lib->bt_params &&
79162306a36Sopenharmony_ci	    priv->lib->bt_params->advanced_bt_coexist &&
79262306a36Sopenharmony_ci	    (priv->bt_full_concurrent ||
79362306a36Sopenharmony_ci	     priv->bt_traffic_load >= IWL_BT_COEX_TRAFFIC_LOAD_HIGH)) {
79462306a36Sopenharmony_ci		/*
79562306a36Sopenharmony_ci		 * only use chain 'A' in bt high traffic load or
79662306a36Sopenharmony_ci		 * full concurrency mode
79762306a36Sopenharmony_ci		 */
79862306a36Sopenharmony_ci		active_chains = first_antenna(active_chains);
79962306a36Sopenharmony_ci	}
80062306a36Sopenharmony_ci
80162306a36Sopenharmony_ci	rx_chain = active_chains << RXON_RX_CHAIN_VALID_POS;
80262306a36Sopenharmony_ci
80362306a36Sopenharmony_ci	/* How many receivers should we use? */
80462306a36Sopenharmony_ci	active_rx_cnt = iwl_get_active_rx_chain_count(priv);
80562306a36Sopenharmony_ci	idle_rx_cnt = iwl_get_idle_rx_chain_count(priv, active_rx_cnt);
80662306a36Sopenharmony_ci
80762306a36Sopenharmony_ci
80862306a36Sopenharmony_ci	/* correct rx chain count according hw settings
80962306a36Sopenharmony_ci	 * and chain noise calibration
81062306a36Sopenharmony_ci	 */
81162306a36Sopenharmony_ci	valid_rx_cnt = iwl_count_chain_bitmap(active_chains);
81262306a36Sopenharmony_ci	if (valid_rx_cnt < active_rx_cnt)
81362306a36Sopenharmony_ci		active_rx_cnt = valid_rx_cnt;
81462306a36Sopenharmony_ci
81562306a36Sopenharmony_ci	if (valid_rx_cnt < idle_rx_cnt)
81662306a36Sopenharmony_ci		idle_rx_cnt = valid_rx_cnt;
81762306a36Sopenharmony_ci
81862306a36Sopenharmony_ci	rx_chain |= active_rx_cnt << RXON_RX_CHAIN_MIMO_CNT_POS;
81962306a36Sopenharmony_ci	rx_chain |= idle_rx_cnt  << RXON_RX_CHAIN_CNT_POS;
82062306a36Sopenharmony_ci
82162306a36Sopenharmony_ci	ctx->staging.rx_chain = cpu_to_le16(rx_chain);
82262306a36Sopenharmony_ci
82362306a36Sopenharmony_ci	if (!is_single && (active_rx_cnt >= IWL_NUM_RX_CHAINS_SINGLE) && is_cam)
82462306a36Sopenharmony_ci		ctx->staging.rx_chain |= RXON_RX_CHAIN_MIMO_FORCE_MSK;
82562306a36Sopenharmony_ci	else
82662306a36Sopenharmony_ci		ctx->staging.rx_chain &= ~RXON_RX_CHAIN_MIMO_FORCE_MSK;
82762306a36Sopenharmony_ci
82862306a36Sopenharmony_ci	IWL_DEBUG_ASSOC(priv, "rx_chain=0x%X active=%d idle=%d\n",
82962306a36Sopenharmony_ci			ctx->staging.rx_chain,
83062306a36Sopenharmony_ci			active_rx_cnt, idle_rx_cnt);
83162306a36Sopenharmony_ci
83262306a36Sopenharmony_ci	WARN_ON(active_rx_cnt == 0 || idle_rx_cnt == 0 ||
83362306a36Sopenharmony_ci		active_rx_cnt < idle_rx_cnt);
83462306a36Sopenharmony_ci}
83562306a36Sopenharmony_ci
83662306a36Sopenharmony_ciu8 iwl_toggle_tx_ant(struct iwl_priv *priv, u8 ant, u8 valid)
83762306a36Sopenharmony_ci{
83862306a36Sopenharmony_ci	int i;
83962306a36Sopenharmony_ci	u8 ind = ant;
84062306a36Sopenharmony_ci
84162306a36Sopenharmony_ci	if (priv->band == NL80211_BAND_2GHZ &&
84262306a36Sopenharmony_ci	    priv->bt_traffic_load >= IWL_BT_COEX_TRAFFIC_LOAD_HIGH)
84362306a36Sopenharmony_ci		return 0;
84462306a36Sopenharmony_ci
84562306a36Sopenharmony_ci	for (i = 0; i < RATE_ANT_NUM - 1; i++) {
84662306a36Sopenharmony_ci		ind = (ind + 1) < RATE_ANT_NUM ?  ind + 1 : 0;
84762306a36Sopenharmony_ci		if (valid & BIT(ind))
84862306a36Sopenharmony_ci			return ind;
84962306a36Sopenharmony_ci	}
85062306a36Sopenharmony_ci	return ant;
85162306a36Sopenharmony_ci}
85262306a36Sopenharmony_ci
85362306a36Sopenharmony_ci#ifdef CONFIG_PM_SLEEP
85462306a36Sopenharmony_cistatic void iwlagn_convert_p1k(u16 *p1k, __le16 *out)
85562306a36Sopenharmony_ci{
85662306a36Sopenharmony_ci	int i;
85762306a36Sopenharmony_ci
85862306a36Sopenharmony_ci	for (i = 0; i < IWLAGN_P1K_SIZE; i++)
85962306a36Sopenharmony_ci		out[i] = cpu_to_le16(p1k[i]);
86062306a36Sopenharmony_ci}
86162306a36Sopenharmony_ci
86262306a36Sopenharmony_cistruct wowlan_key_data {
86362306a36Sopenharmony_ci	struct iwl_rxon_context *ctx;
86462306a36Sopenharmony_ci	struct iwlagn_wowlan_rsc_tsc_params_cmd *rsc_tsc;
86562306a36Sopenharmony_ci	struct iwlagn_wowlan_tkip_params_cmd *tkip;
86662306a36Sopenharmony_ci	const u8 *bssid;
86762306a36Sopenharmony_ci	bool error, use_rsc_tsc, use_tkip;
86862306a36Sopenharmony_ci};
86962306a36Sopenharmony_ci
87062306a36Sopenharmony_ci
87162306a36Sopenharmony_cistatic void iwlagn_wowlan_program_keys(struct ieee80211_hw *hw,
87262306a36Sopenharmony_ci			       struct ieee80211_vif *vif,
87362306a36Sopenharmony_ci			       struct ieee80211_sta *sta,
87462306a36Sopenharmony_ci			       struct ieee80211_key_conf *key,
87562306a36Sopenharmony_ci			       void *_data)
87662306a36Sopenharmony_ci{
87762306a36Sopenharmony_ci	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
87862306a36Sopenharmony_ci	struct wowlan_key_data *data = _data;
87962306a36Sopenharmony_ci	struct iwl_rxon_context *ctx = data->ctx;
88062306a36Sopenharmony_ci	struct aes_sc *aes_sc, *aes_tx_sc = NULL;
88162306a36Sopenharmony_ci	struct tkip_sc *tkip_sc, *tkip_tx_sc = NULL;
88262306a36Sopenharmony_ci	struct iwlagn_p1k_cache *rx_p1ks;
88362306a36Sopenharmony_ci	u8 *rx_mic_key;
88462306a36Sopenharmony_ci	struct ieee80211_key_seq seq;
88562306a36Sopenharmony_ci	u32 cur_rx_iv32 = 0;
88662306a36Sopenharmony_ci	u16 p1k[IWLAGN_P1K_SIZE];
88762306a36Sopenharmony_ci	int ret, i;
88862306a36Sopenharmony_ci
88962306a36Sopenharmony_ci	mutex_lock(&priv->mutex);
89062306a36Sopenharmony_ci
89162306a36Sopenharmony_ci	if ((key->cipher == WLAN_CIPHER_SUITE_WEP40 ||
89262306a36Sopenharmony_ci	     key->cipher == WLAN_CIPHER_SUITE_WEP104) &&
89362306a36Sopenharmony_ci	     !sta && !ctx->key_mapping_keys)
89462306a36Sopenharmony_ci		ret = iwl_set_default_wep_key(priv, ctx, key);
89562306a36Sopenharmony_ci	else
89662306a36Sopenharmony_ci		ret = iwl_set_dynamic_key(priv, ctx, key, sta);
89762306a36Sopenharmony_ci
89862306a36Sopenharmony_ci	if (ret) {
89962306a36Sopenharmony_ci		IWL_ERR(priv, "Error setting key during suspend!\n");
90062306a36Sopenharmony_ci		data->error = true;
90162306a36Sopenharmony_ci	}
90262306a36Sopenharmony_ci
90362306a36Sopenharmony_ci	switch (key->cipher) {
90462306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_TKIP:
90562306a36Sopenharmony_ci		if (sta) {
90662306a36Sopenharmony_ci			u64 pn64;
90762306a36Sopenharmony_ci
90862306a36Sopenharmony_ci			tkip_sc = data->rsc_tsc->all_tsc_rsc.tkip.unicast_rsc;
90962306a36Sopenharmony_ci			tkip_tx_sc = &data->rsc_tsc->all_tsc_rsc.tkip.tsc;
91062306a36Sopenharmony_ci
91162306a36Sopenharmony_ci			rx_p1ks = data->tkip->rx_uni;
91262306a36Sopenharmony_ci
91362306a36Sopenharmony_ci			pn64 = atomic64_read(&key->tx_pn);
91462306a36Sopenharmony_ci			tkip_tx_sc->iv16 = cpu_to_le16(TKIP_PN_TO_IV16(pn64));
91562306a36Sopenharmony_ci			tkip_tx_sc->iv32 = cpu_to_le32(TKIP_PN_TO_IV32(pn64));
91662306a36Sopenharmony_ci
91762306a36Sopenharmony_ci			ieee80211_get_tkip_p1k_iv(key, seq.tkip.iv32, p1k);
91862306a36Sopenharmony_ci			iwlagn_convert_p1k(p1k, data->tkip->tx.p1k);
91962306a36Sopenharmony_ci
92062306a36Sopenharmony_ci			memcpy(data->tkip->mic_keys.tx,
92162306a36Sopenharmony_ci			       &key->key[NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY],
92262306a36Sopenharmony_ci			       IWLAGN_MIC_KEY_SIZE);
92362306a36Sopenharmony_ci
92462306a36Sopenharmony_ci			rx_mic_key = data->tkip->mic_keys.rx_unicast;
92562306a36Sopenharmony_ci		} else {
92662306a36Sopenharmony_ci			tkip_sc =
92762306a36Sopenharmony_ci				data->rsc_tsc->all_tsc_rsc.tkip.multicast_rsc;
92862306a36Sopenharmony_ci			rx_p1ks = data->tkip->rx_multi;
92962306a36Sopenharmony_ci			rx_mic_key = data->tkip->mic_keys.rx_mcast;
93062306a36Sopenharmony_ci		}
93162306a36Sopenharmony_ci
93262306a36Sopenharmony_ci		/*
93362306a36Sopenharmony_ci		 * For non-QoS this relies on the fact that both the uCode and
93462306a36Sopenharmony_ci		 * mac80211 use TID 0 (as they need to to avoid replay attacks)
93562306a36Sopenharmony_ci		 * for checking the IV in the frames.
93662306a36Sopenharmony_ci		 */
93762306a36Sopenharmony_ci		for (i = 0; i < IWLAGN_NUM_RSC; i++) {
93862306a36Sopenharmony_ci			ieee80211_get_key_rx_seq(key, i, &seq);
93962306a36Sopenharmony_ci			tkip_sc[i].iv16 = cpu_to_le16(seq.tkip.iv16);
94062306a36Sopenharmony_ci			tkip_sc[i].iv32 = cpu_to_le32(seq.tkip.iv32);
94162306a36Sopenharmony_ci			/* wrapping isn't allowed, AP must rekey */
94262306a36Sopenharmony_ci			if (seq.tkip.iv32 > cur_rx_iv32)
94362306a36Sopenharmony_ci				cur_rx_iv32 = seq.tkip.iv32;
94462306a36Sopenharmony_ci		}
94562306a36Sopenharmony_ci
94662306a36Sopenharmony_ci		ieee80211_get_tkip_rx_p1k(key, data->bssid, cur_rx_iv32, p1k);
94762306a36Sopenharmony_ci		iwlagn_convert_p1k(p1k, rx_p1ks[0].p1k);
94862306a36Sopenharmony_ci		ieee80211_get_tkip_rx_p1k(key, data->bssid,
94962306a36Sopenharmony_ci					  cur_rx_iv32 + 1, p1k);
95062306a36Sopenharmony_ci		iwlagn_convert_p1k(p1k, rx_p1ks[1].p1k);
95162306a36Sopenharmony_ci
95262306a36Sopenharmony_ci		memcpy(rx_mic_key,
95362306a36Sopenharmony_ci		       &key->key[NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY],
95462306a36Sopenharmony_ci		       IWLAGN_MIC_KEY_SIZE);
95562306a36Sopenharmony_ci
95662306a36Sopenharmony_ci		data->use_tkip = true;
95762306a36Sopenharmony_ci		data->use_rsc_tsc = true;
95862306a36Sopenharmony_ci		break;
95962306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_CCMP:
96062306a36Sopenharmony_ci		if (sta) {
96162306a36Sopenharmony_ci			u64 pn64;
96262306a36Sopenharmony_ci
96362306a36Sopenharmony_ci			aes_sc = data->rsc_tsc->all_tsc_rsc.aes.unicast_rsc;
96462306a36Sopenharmony_ci			aes_tx_sc = &data->rsc_tsc->all_tsc_rsc.aes.tsc;
96562306a36Sopenharmony_ci
96662306a36Sopenharmony_ci			pn64 = atomic64_read(&key->tx_pn);
96762306a36Sopenharmony_ci			aes_tx_sc->pn = cpu_to_le64(pn64);
96862306a36Sopenharmony_ci		} else
96962306a36Sopenharmony_ci			aes_sc = data->rsc_tsc->all_tsc_rsc.aes.multicast_rsc;
97062306a36Sopenharmony_ci
97162306a36Sopenharmony_ci		/*
97262306a36Sopenharmony_ci		 * For non-QoS this relies on the fact that both the uCode and
97362306a36Sopenharmony_ci		 * mac80211 use TID 0 for checking the IV in the frames.
97462306a36Sopenharmony_ci		 */
97562306a36Sopenharmony_ci		for (i = 0; i < IWLAGN_NUM_RSC; i++) {
97662306a36Sopenharmony_ci			u8 *pn = seq.ccmp.pn;
97762306a36Sopenharmony_ci
97862306a36Sopenharmony_ci			ieee80211_get_key_rx_seq(key, i, &seq);
97962306a36Sopenharmony_ci			aes_sc[i].pn = cpu_to_le64(
98062306a36Sopenharmony_ci					(u64)pn[5] |
98162306a36Sopenharmony_ci					((u64)pn[4] << 8) |
98262306a36Sopenharmony_ci					((u64)pn[3] << 16) |
98362306a36Sopenharmony_ci					((u64)pn[2] << 24) |
98462306a36Sopenharmony_ci					((u64)pn[1] << 32) |
98562306a36Sopenharmony_ci					((u64)pn[0] << 40));
98662306a36Sopenharmony_ci		}
98762306a36Sopenharmony_ci		data->use_rsc_tsc = true;
98862306a36Sopenharmony_ci		break;
98962306a36Sopenharmony_ci	}
99062306a36Sopenharmony_ci
99162306a36Sopenharmony_ci	mutex_unlock(&priv->mutex);
99262306a36Sopenharmony_ci}
99362306a36Sopenharmony_ci
99462306a36Sopenharmony_ciint iwlagn_send_patterns(struct iwl_priv *priv,
99562306a36Sopenharmony_ci			struct cfg80211_wowlan *wowlan)
99662306a36Sopenharmony_ci{
99762306a36Sopenharmony_ci	struct iwlagn_wowlan_patterns_cmd *pattern_cmd;
99862306a36Sopenharmony_ci	struct iwl_host_cmd cmd = {
99962306a36Sopenharmony_ci		.id = REPLY_WOWLAN_PATTERNS,
100062306a36Sopenharmony_ci		.dataflags[0] = IWL_HCMD_DFL_NOCOPY,
100162306a36Sopenharmony_ci	};
100262306a36Sopenharmony_ci	int i, err;
100362306a36Sopenharmony_ci
100462306a36Sopenharmony_ci	if (!wowlan->n_patterns)
100562306a36Sopenharmony_ci		return 0;
100662306a36Sopenharmony_ci
100762306a36Sopenharmony_ci	cmd.len[0] = struct_size(pattern_cmd, patterns, wowlan->n_patterns);
100862306a36Sopenharmony_ci
100962306a36Sopenharmony_ci	pattern_cmd = kmalloc(cmd.len[0], GFP_KERNEL);
101062306a36Sopenharmony_ci	if (!pattern_cmd)
101162306a36Sopenharmony_ci		return -ENOMEM;
101262306a36Sopenharmony_ci
101362306a36Sopenharmony_ci	pattern_cmd->n_patterns = cpu_to_le32(wowlan->n_patterns);
101462306a36Sopenharmony_ci
101562306a36Sopenharmony_ci	for (i = 0; i < wowlan->n_patterns; i++) {
101662306a36Sopenharmony_ci		int mask_len = DIV_ROUND_UP(wowlan->patterns[i].pattern_len, 8);
101762306a36Sopenharmony_ci
101862306a36Sopenharmony_ci		memcpy(&pattern_cmd->patterns[i].mask,
101962306a36Sopenharmony_ci			wowlan->patterns[i].mask, mask_len);
102062306a36Sopenharmony_ci		memcpy(&pattern_cmd->patterns[i].pattern,
102162306a36Sopenharmony_ci			wowlan->patterns[i].pattern,
102262306a36Sopenharmony_ci			wowlan->patterns[i].pattern_len);
102362306a36Sopenharmony_ci		pattern_cmd->patterns[i].mask_size = mask_len;
102462306a36Sopenharmony_ci		pattern_cmd->patterns[i].pattern_size =
102562306a36Sopenharmony_ci			wowlan->patterns[i].pattern_len;
102662306a36Sopenharmony_ci	}
102762306a36Sopenharmony_ci
102862306a36Sopenharmony_ci	cmd.data[0] = pattern_cmd;
102962306a36Sopenharmony_ci	err = iwl_dvm_send_cmd(priv, &cmd);
103062306a36Sopenharmony_ci	kfree(pattern_cmd);
103162306a36Sopenharmony_ci	return err;
103262306a36Sopenharmony_ci}
103362306a36Sopenharmony_ci
103462306a36Sopenharmony_ciint iwlagn_suspend(struct iwl_priv *priv, struct cfg80211_wowlan *wowlan)
103562306a36Sopenharmony_ci{
103662306a36Sopenharmony_ci	struct iwlagn_wowlan_wakeup_filter_cmd wakeup_filter_cmd;
103762306a36Sopenharmony_ci	struct iwl_rxon_cmd rxon;
103862306a36Sopenharmony_ci	struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
103962306a36Sopenharmony_ci	struct iwlagn_wowlan_kek_kck_material_cmd kek_kck_cmd;
104062306a36Sopenharmony_ci	struct iwlagn_wowlan_tkip_params_cmd tkip_cmd = {};
104162306a36Sopenharmony_ci	struct iwlagn_d3_config_cmd d3_cfg_cmd = {
104262306a36Sopenharmony_ci		/*
104362306a36Sopenharmony_ci		 * Program the minimum sleep time to 10 seconds, as many
104462306a36Sopenharmony_ci		 * platforms have issues processing a wakeup signal while
104562306a36Sopenharmony_ci		 * still being in the process of suspending.
104662306a36Sopenharmony_ci		 */
104762306a36Sopenharmony_ci		.min_sleep_time = cpu_to_le32(10 * 1000 * 1000),
104862306a36Sopenharmony_ci	};
104962306a36Sopenharmony_ci	struct wowlan_key_data key_data = {
105062306a36Sopenharmony_ci		.ctx = ctx,
105162306a36Sopenharmony_ci		.bssid = ctx->active.bssid_addr,
105262306a36Sopenharmony_ci		.use_rsc_tsc = false,
105362306a36Sopenharmony_ci		.tkip = &tkip_cmd,
105462306a36Sopenharmony_ci		.use_tkip = false,
105562306a36Sopenharmony_ci	};
105662306a36Sopenharmony_ci	int ret, i;
105762306a36Sopenharmony_ci	u16 seq;
105862306a36Sopenharmony_ci
105962306a36Sopenharmony_ci	key_data.rsc_tsc = kzalloc(sizeof(*key_data.rsc_tsc), GFP_KERNEL);
106062306a36Sopenharmony_ci	if (!key_data.rsc_tsc)
106162306a36Sopenharmony_ci		return -ENOMEM;
106262306a36Sopenharmony_ci
106362306a36Sopenharmony_ci	memset(&wakeup_filter_cmd, 0, sizeof(wakeup_filter_cmd));
106462306a36Sopenharmony_ci
106562306a36Sopenharmony_ci	/*
106662306a36Sopenharmony_ci	 * We know the last used seqno, and the uCode expects to know that
106762306a36Sopenharmony_ci	 * one, it will increment before TX.
106862306a36Sopenharmony_ci	 */
106962306a36Sopenharmony_ci	seq = le16_to_cpu(priv->last_seq_ctl) & IEEE80211_SCTL_SEQ;
107062306a36Sopenharmony_ci	wakeup_filter_cmd.non_qos_seq = cpu_to_le16(seq);
107162306a36Sopenharmony_ci
107262306a36Sopenharmony_ci	/*
107362306a36Sopenharmony_ci	 * For QoS counters, we store the one to use next, so subtract 0x10
107462306a36Sopenharmony_ci	 * since the uCode will add 0x10 before using the value.
107562306a36Sopenharmony_ci	 */
107662306a36Sopenharmony_ci	for (i = 0; i < IWL_MAX_TID_COUNT; i++) {
107762306a36Sopenharmony_ci		seq = priv->tid_data[IWL_AP_ID][i].seq_number;
107862306a36Sopenharmony_ci		seq -= 0x10;
107962306a36Sopenharmony_ci		wakeup_filter_cmd.qos_seq[i] = cpu_to_le16(seq);
108062306a36Sopenharmony_ci	}
108162306a36Sopenharmony_ci
108262306a36Sopenharmony_ci	if (wowlan->disconnect)
108362306a36Sopenharmony_ci		wakeup_filter_cmd.enabled |=
108462306a36Sopenharmony_ci			cpu_to_le32(IWLAGN_WOWLAN_WAKEUP_BEACON_MISS |
108562306a36Sopenharmony_ci				    IWLAGN_WOWLAN_WAKEUP_LINK_CHANGE);
108662306a36Sopenharmony_ci	if (wowlan->magic_pkt)
108762306a36Sopenharmony_ci		wakeup_filter_cmd.enabled |=
108862306a36Sopenharmony_ci			cpu_to_le32(IWLAGN_WOWLAN_WAKEUP_MAGIC_PACKET);
108962306a36Sopenharmony_ci	if (wowlan->gtk_rekey_failure)
109062306a36Sopenharmony_ci		wakeup_filter_cmd.enabled |=
109162306a36Sopenharmony_ci			cpu_to_le32(IWLAGN_WOWLAN_WAKEUP_GTK_REKEY_FAIL);
109262306a36Sopenharmony_ci	if (wowlan->eap_identity_req)
109362306a36Sopenharmony_ci		wakeup_filter_cmd.enabled |=
109462306a36Sopenharmony_ci			cpu_to_le32(IWLAGN_WOWLAN_WAKEUP_EAP_IDENT_REQ);
109562306a36Sopenharmony_ci	if (wowlan->four_way_handshake)
109662306a36Sopenharmony_ci		wakeup_filter_cmd.enabled |=
109762306a36Sopenharmony_ci			cpu_to_le32(IWLAGN_WOWLAN_WAKEUP_4WAY_HANDSHAKE);
109862306a36Sopenharmony_ci	if (wowlan->n_patterns)
109962306a36Sopenharmony_ci		wakeup_filter_cmd.enabled |=
110062306a36Sopenharmony_ci			cpu_to_le32(IWLAGN_WOWLAN_WAKEUP_PATTERN_MATCH);
110162306a36Sopenharmony_ci
110262306a36Sopenharmony_ci	if (wowlan->rfkill_release)
110362306a36Sopenharmony_ci		d3_cfg_cmd.wakeup_flags |=
110462306a36Sopenharmony_ci			cpu_to_le32(IWLAGN_D3_WAKEUP_RFKILL);
110562306a36Sopenharmony_ci
110662306a36Sopenharmony_ci	iwl_scan_cancel_timeout(priv, 200);
110762306a36Sopenharmony_ci
110862306a36Sopenharmony_ci	memcpy(&rxon, &ctx->active, sizeof(rxon));
110962306a36Sopenharmony_ci
111062306a36Sopenharmony_ci	priv->ucode_loaded = false;
111162306a36Sopenharmony_ci	iwl_trans_stop_device(priv->trans);
111262306a36Sopenharmony_ci	ret = iwl_trans_start_hw(priv->trans);
111362306a36Sopenharmony_ci	if (ret)
111462306a36Sopenharmony_ci		goto out;
111562306a36Sopenharmony_ci
111662306a36Sopenharmony_ci	priv->wowlan = true;
111762306a36Sopenharmony_ci
111862306a36Sopenharmony_ci	ret = iwl_load_ucode_wait_alive(priv, IWL_UCODE_WOWLAN);
111962306a36Sopenharmony_ci	if (ret)
112062306a36Sopenharmony_ci		goto out;
112162306a36Sopenharmony_ci
112262306a36Sopenharmony_ci	/* now configure WoWLAN ucode */
112362306a36Sopenharmony_ci	ret = iwl_alive_start(priv);
112462306a36Sopenharmony_ci	if (ret)
112562306a36Sopenharmony_ci		goto out;
112662306a36Sopenharmony_ci
112762306a36Sopenharmony_ci	memcpy(&ctx->staging, &rxon, sizeof(rxon));
112862306a36Sopenharmony_ci	ret = iwlagn_commit_rxon(priv, ctx);
112962306a36Sopenharmony_ci	if (ret)
113062306a36Sopenharmony_ci		goto out;
113162306a36Sopenharmony_ci
113262306a36Sopenharmony_ci	ret = iwl_power_update_mode(priv, true);
113362306a36Sopenharmony_ci	if (ret)
113462306a36Sopenharmony_ci		goto out;
113562306a36Sopenharmony_ci
113662306a36Sopenharmony_ci	if (!iwlwifi_mod_params.swcrypto) {
113762306a36Sopenharmony_ci		/* mark all keys clear */
113862306a36Sopenharmony_ci		priv->ucode_key_table = 0;
113962306a36Sopenharmony_ci		ctx->key_mapping_keys = 0;
114062306a36Sopenharmony_ci
114162306a36Sopenharmony_ci		/*
114262306a36Sopenharmony_ci		 * This needs to be unlocked due to lock ordering
114362306a36Sopenharmony_ci		 * constraints. Since we're in the suspend path
114462306a36Sopenharmony_ci		 * that isn't really a problem though.
114562306a36Sopenharmony_ci		 */
114662306a36Sopenharmony_ci		mutex_unlock(&priv->mutex);
114762306a36Sopenharmony_ci		ieee80211_iter_keys(priv->hw, ctx->vif,
114862306a36Sopenharmony_ci				    iwlagn_wowlan_program_keys,
114962306a36Sopenharmony_ci				    &key_data);
115062306a36Sopenharmony_ci		mutex_lock(&priv->mutex);
115162306a36Sopenharmony_ci		if (key_data.error) {
115262306a36Sopenharmony_ci			ret = -EIO;
115362306a36Sopenharmony_ci			goto out;
115462306a36Sopenharmony_ci		}
115562306a36Sopenharmony_ci
115662306a36Sopenharmony_ci		if (key_data.use_rsc_tsc) {
115762306a36Sopenharmony_ci			struct iwl_host_cmd rsc_tsc_cmd = {
115862306a36Sopenharmony_ci				.id = REPLY_WOWLAN_TSC_RSC_PARAMS,
115962306a36Sopenharmony_ci				.data[0] = key_data.rsc_tsc,
116062306a36Sopenharmony_ci				.dataflags[0] = IWL_HCMD_DFL_NOCOPY,
116162306a36Sopenharmony_ci				.len[0] = sizeof(*key_data.rsc_tsc),
116262306a36Sopenharmony_ci			};
116362306a36Sopenharmony_ci
116462306a36Sopenharmony_ci			ret = iwl_dvm_send_cmd(priv, &rsc_tsc_cmd);
116562306a36Sopenharmony_ci			if (ret)
116662306a36Sopenharmony_ci				goto out;
116762306a36Sopenharmony_ci		}
116862306a36Sopenharmony_ci
116962306a36Sopenharmony_ci		if (key_data.use_tkip) {
117062306a36Sopenharmony_ci			ret = iwl_dvm_send_cmd_pdu(priv,
117162306a36Sopenharmony_ci						 REPLY_WOWLAN_TKIP_PARAMS,
117262306a36Sopenharmony_ci						 0, sizeof(tkip_cmd),
117362306a36Sopenharmony_ci						 &tkip_cmd);
117462306a36Sopenharmony_ci			if (ret)
117562306a36Sopenharmony_ci				goto out;
117662306a36Sopenharmony_ci		}
117762306a36Sopenharmony_ci
117862306a36Sopenharmony_ci		if (priv->have_rekey_data) {
117962306a36Sopenharmony_ci			memset(&kek_kck_cmd, 0, sizeof(kek_kck_cmd));
118062306a36Sopenharmony_ci			memcpy(kek_kck_cmd.kck, priv->kck, NL80211_KCK_LEN);
118162306a36Sopenharmony_ci			kek_kck_cmd.kck_len = cpu_to_le16(NL80211_KCK_LEN);
118262306a36Sopenharmony_ci			memcpy(kek_kck_cmd.kek, priv->kek, NL80211_KEK_LEN);
118362306a36Sopenharmony_ci			kek_kck_cmd.kek_len = cpu_to_le16(NL80211_KEK_LEN);
118462306a36Sopenharmony_ci			kek_kck_cmd.replay_ctr = priv->replay_ctr;
118562306a36Sopenharmony_ci
118662306a36Sopenharmony_ci			ret = iwl_dvm_send_cmd_pdu(priv,
118762306a36Sopenharmony_ci						 REPLY_WOWLAN_KEK_KCK_MATERIAL,
118862306a36Sopenharmony_ci						 0, sizeof(kek_kck_cmd),
118962306a36Sopenharmony_ci						 &kek_kck_cmd);
119062306a36Sopenharmony_ci			if (ret)
119162306a36Sopenharmony_ci				goto out;
119262306a36Sopenharmony_ci		}
119362306a36Sopenharmony_ci	}
119462306a36Sopenharmony_ci
119562306a36Sopenharmony_ci	ret = iwl_dvm_send_cmd_pdu(priv, REPLY_D3_CONFIG, 0,
119662306a36Sopenharmony_ci				     sizeof(d3_cfg_cmd), &d3_cfg_cmd);
119762306a36Sopenharmony_ci	if (ret)
119862306a36Sopenharmony_ci		goto out;
119962306a36Sopenharmony_ci
120062306a36Sopenharmony_ci	ret = iwl_dvm_send_cmd_pdu(priv, REPLY_WOWLAN_WAKEUP_FILTER,
120162306a36Sopenharmony_ci				 0, sizeof(wakeup_filter_cmd),
120262306a36Sopenharmony_ci				 &wakeup_filter_cmd);
120362306a36Sopenharmony_ci	if (ret)
120462306a36Sopenharmony_ci		goto out;
120562306a36Sopenharmony_ci
120662306a36Sopenharmony_ci	ret = iwlagn_send_patterns(priv, wowlan);
120762306a36Sopenharmony_ci out:
120862306a36Sopenharmony_ci	kfree(key_data.rsc_tsc);
120962306a36Sopenharmony_ci	return ret;
121062306a36Sopenharmony_ci}
121162306a36Sopenharmony_ci#endif
121262306a36Sopenharmony_ci
121362306a36Sopenharmony_ciint iwl_dvm_send_cmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
121462306a36Sopenharmony_ci{
121562306a36Sopenharmony_ci	if (iwl_is_rfkill(priv) || iwl_is_ctkill(priv)) {
121662306a36Sopenharmony_ci		IWL_WARN(priv, "Not sending command - %s KILL\n",
121762306a36Sopenharmony_ci			 iwl_is_rfkill(priv) ? "RF" : "CT");
121862306a36Sopenharmony_ci		return -EIO;
121962306a36Sopenharmony_ci	}
122062306a36Sopenharmony_ci
122162306a36Sopenharmony_ci	if (test_bit(STATUS_FW_ERROR, &priv->status)) {
122262306a36Sopenharmony_ci		IWL_ERR(priv, "Command %s failed: FW Error\n",
122362306a36Sopenharmony_ci			iwl_get_cmd_string(priv->trans, cmd->id));
122462306a36Sopenharmony_ci		return -EIO;
122562306a36Sopenharmony_ci	}
122662306a36Sopenharmony_ci
122762306a36Sopenharmony_ci	/*
122862306a36Sopenharmony_ci	 * This can happen upon FW ASSERT: we clear the STATUS_FW_ERROR flag
122962306a36Sopenharmony_ci	 * in iwl_down but cancel the workers only later.
123062306a36Sopenharmony_ci	 */
123162306a36Sopenharmony_ci	if (!priv->ucode_loaded) {
123262306a36Sopenharmony_ci		IWL_ERR(priv, "Fw not loaded - dropping CMD: %x\n", cmd->id);
123362306a36Sopenharmony_ci		return -EIO;
123462306a36Sopenharmony_ci	}
123562306a36Sopenharmony_ci
123662306a36Sopenharmony_ci	/*
123762306a36Sopenharmony_ci	 * Synchronous commands from this op-mode must hold
123862306a36Sopenharmony_ci	 * the mutex, this ensures we don't try to send two
123962306a36Sopenharmony_ci	 * (or more) synchronous commands at a time.
124062306a36Sopenharmony_ci	 */
124162306a36Sopenharmony_ci	if (!(cmd->flags & CMD_ASYNC))
124262306a36Sopenharmony_ci		lockdep_assert_held(&priv->mutex);
124362306a36Sopenharmony_ci
124462306a36Sopenharmony_ci	return iwl_trans_send_cmd(priv->trans, cmd);
124562306a36Sopenharmony_ci}
124662306a36Sopenharmony_ci
124762306a36Sopenharmony_ciint iwl_dvm_send_cmd_pdu(struct iwl_priv *priv, u8 id,
124862306a36Sopenharmony_ci			 u32 flags, u16 len, const void *data)
124962306a36Sopenharmony_ci{
125062306a36Sopenharmony_ci	struct iwl_host_cmd cmd = {
125162306a36Sopenharmony_ci		.id = id,
125262306a36Sopenharmony_ci		.len = { len, },
125362306a36Sopenharmony_ci		.data = { data, },
125462306a36Sopenharmony_ci		.flags = flags,
125562306a36Sopenharmony_ci	};
125662306a36Sopenharmony_ci
125762306a36Sopenharmony_ci	return iwl_dvm_send_cmd(priv, &cmd);
125862306a36Sopenharmony_ci}
1259