cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

coex.c (18489B)


      1// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
      2/*
      3 * Copyright (C) 2013-2014, 2018-2020 Intel Corporation
      4 * Copyright (C) 2013-2015 Intel Mobile Communications GmbH
      5 */
      6#include <linux/ieee80211.h>
      7#include <linux/etherdevice.h>
      8#include <net/mac80211.h>
      9
     10#include "fw/api/coex.h"
     11#include "iwl-modparams.h"
     12#include "mvm.h"
     13#include "iwl-debug.h"
     14
     15/* 20MHz / 40MHz below / 40Mhz above*/
     16static const __le64 iwl_ci_mask[][3] = {
     17	/* dummy entry for channel 0 */
     18	{cpu_to_le64(0), cpu_to_le64(0), cpu_to_le64(0)},
     19	{
     20		cpu_to_le64(0x0000001FFFULL),
     21		cpu_to_le64(0x0ULL),
     22		cpu_to_le64(0x00007FFFFFULL),
     23	},
     24	{
     25		cpu_to_le64(0x000000FFFFULL),
     26		cpu_to_le64(0x0ULL),
     27		cpu_to_le64(0x0003FFFFFFULL),
     28	},
     29	{
     30		cpu_to_le64(0x000003FFFCULL),
     31		cpu_to_le64(0x0ULL),
     32		cpu_to_le64(0x000FFFFFFCULL),
     33	},
     34	{
     35		cpu_to_le64(0x00001FFFE0ULL),
     36		cpu_to_le64(0x0ULL),
     37		cpu_to_le64(0x007FFFFFE0ULL),
     38	},
     39	{
     40		cpu_to_le64(0x00007FFF80ULL),
     41		cpu_to_le64(0x00007FFFFFULL),
     42		cpu_to_le64(0x01FFFFFF80ULL),
     43	},
     44	{
     45		cpu_to_le64(0x0003FFFC00ULL),
     46		cpu_to_le64(0x0003FFFFFFULL),
     47		cpu_to_le64(0x0FFFFFFC00ULL),
     48	},
     49	{
     50		cpu_to_le64(0x000FFFF000ULL),
     51		cpu_to_le64(0x000FFFFFFCULL),
     52		cpu_to_le64(0x3FFFFFF000ULL),
     53	},
     54	{
     55		cpu_to_le64(0x007FFF8000ULL),
     56		cpu_to_le64(0x007FFFFFE0ULL),
     57		cpu_to_le64(0xFFFFFF8000ULL),
     58	},
     59	{
     60		cpu_to_le64(0x01FFFE0000ULL),
     61		cpu_to_le64(0x01FFFFFF80ULL),
     62		cpu_to_le64(0xFFFFFE0000ULL),
     63	},
     64	{
     65		cpu_to_le64(0x0FFFF00000ULL),
     66		cpu_to_le64(0x0FFFFFFC00ULL),
     67		cpu_to_le64(0x0ULL),
     68	},
     69	{
     70		cpu_to_le64(0x3FFFC00000ULL),
     71		cpu_to_le64(0x3FFFFFF000ULL),
     72		cpu_to_le64(0x0)
     73	},
     74	{
     75		cpu_to_le64(0xFFFE000000ULL),
     76		cpu_to_le64(0xFFFFFF8000ULL),
     77		cpu_to_le64(0x0)
     78	},
     79	{
     80		cpu_to_le64(0xFFF8000000ULL),
     81		cpu_to_le64(0xFFFFFE0000ULL),
     82		cpu_to_le64(0x0)
     83	},
     84	{
     85		cpu_to_le64(0xFE00000000ULL),
     86		cpu_to_le64(0x0ULL),
     87		cpu_to_le64(0x0ULL)
     88	},
     89};
     90
     91static enum iwl_bt_coex_lut_type
     92iwl_get_coex_type(struct iwl_mvm *mvm, const struct ieee80211_vif *vif)
     93{
     94	struct ieee80211_chanctx_conf *chanctx_conf;
     95	enum iwl_bt_coex_lut_type ret;
     96	u16 phy_ctx_id;
     97	u32 primary_ch_phy_id, secondary_ch_phy_id;
     98
     99	/*
    100	 * Checking that we hold mvm->mutex is a good idea, but the rate
    101	 * control can't acquire the mutex since it runs in Tx path.
    102	 * So this is racy in that case, but in the worst case, the AMPDU
    103	 * size limit will be wrong for a short time which is not a big
    104	 * issue.
    105	 */
    106
    107	rcu_read_lock();
    108
    109	chanctx_conf = rcu_dereference(vif->chanctx_conf);
    110
    111	if (!chanctx_conf ||
    112	     chanctx_conf->def.chan->band != NL80211_BAND_2GHZ) {
    113		rcu_read_unlock();
    114		return BT_COEX_INVALID_LUT;
    115	}
    116
    117	ret = BT_COEX_TX_DIS_LUT;
    118
    119	if (mvm->cfg->bt_shared_single_ant) {
    120		rcu_read_unlock();
    121		return ret;
    122	}
    123
    124	phy_ctx_id = *((u16 *)chanctx_conf->drv_priv);
    125	primary_ch_phy_id = le32_to_cpu(mvm->last_bt_ci_cmd.primary_ch_phy_id);
    126	secondary_ch_phy_id =
    127		le32_to_cpu(mvm->last_bt_ci_cmd.secondary_ch_phy_id);
    128
    129	if (primary_ch_phy_id == phy_ctx_id)
    130		ret = le32_to_cpu(mvm->last_bt_notif.primary_ch_lut);
    131	else if (secondary_ch_phy_id == phy_ctx_id)
    132		ret = le32_to_cpu(mvm->last_bt_notif.secondary_ch_lut);
    133	/* else - default = TX TX disallowed */
    134
    135	rcu_read_unlock();
    136
    137	return ret;
    138}
    139
    140int iwl_mvm_send_bt_init_conf(struct iwl_mvm *mvm)
    141{
    142	struct iwl_bt_coex_cmd bt_cmd = {};
    143	u32 mode;
    144
    145	lockdep_assert_held(&mvm->mutex);
    146
    147	if (unlikely(mvm->bt_force_ant_mode != BT_FORCE_ANT_DIS)) {
    148		switch (mvm->bt_force_ant_mode) {
    149		case BT_FORCE_ANT_BT:
    150			mode = BT_COEX_BT;
    151			break;
    152		case BT_FORCE_ANT_WIFI:
    153			mode = BT_COEX_WIFI;
    154			break;
    155		default:
    156			WARN_ON(1);
    157			mode = 0;
    158		}
    159
    160		bt_cmd.mode = cpu_to_le32(mode);
    161		goto send_cmd;
    162	}
    163
    164	bt_cmd.mode = cpu_to_le32(BT_COEX_NW);
    165
    166	if (IWL_MVM_BT_COEX_SYNC2SCO)
    167		bt_cmd.enabled_modules |=
    168			cpu_to_le32(BT_COEX_SYNC2SCO_ENABLED);
    169
    170	if (iwl_mvm_is_mplut_supported(mvm))
    171		bt_cmd.enabled_modules |= cpu_to_le32(BT_COEX_MPLUT_ENABLED);
    172
    173	bt_cmd.enabled_modules |= cpu_to_le32(BT_COEX_HIGH_BAND_RET);
    174
    175send_cmd:
    176	memset(&mvm->last_bt_notif, 0, sizeof(mvm->last_bt_notif));
    177	memset(&mvm->last_bt_ci_cmd, 0, sizeof(mvm->last_bt_ci_cmd));
    178
    179	return iwl_mvm_send_cmd_pdu(mvm, BT_CONFIG, 0, sizeof(bt_cmd), &bt_cmd);
    180}
    181
    182static int iwl_mvm_bt_coex_reduced_txp(struct iwl_mvm *mvm, u8 sta_id,
    183				       bool enable)
    184{
    185	struct iwl_bt_coex_reduced_txp_update_cmd cmd = {};
    186	struct iwl_mvm_sta *mvmsta;
    187	u32 value;
    188
    189	mvmsta = iwl_mvm_sta_from_staid_protected(mvm, sta_id);
    190	if (!mvmsta)
    191		return 0;
    192
    193	/* nothing to do */
    194	if (mvmsta->bt_reduced_txpower == enable)
    195		return 0;
    196
    197	value = mvmsta->sta_id;
    198
    199	if (enable)
    200		value |= BT_REDUCED_TX_POWER_BIT;
    201
    202	IWL_DEBUG_COEX(mvm, "%sable reduced Tx Power for sta %d\n",
    203		       enable ? "en" : "dis", sta_id);
    204
    205	cmd.reduced_txp = cpu_to_le32(value);
    206	mvmsta->bt_reduced_txpower = enable;
    207
    208	return iwl_mvm_send_cmd_pdu(mvm, BT_COEX_UPDATE_REDUCED_TXP,
    209				    CMD_ASYNC, sizeof(cmd), &cmd);
    210}
    211
    212struct iwl_bt_iterator_data {
    213	struct iwl_bt_coex_profile_notif *notif;
    214	struct iwl_mvm *mvm;
    215	struct ieee80211_chanctx_conf *primary;
    216	struct ieee80211_chanctx_conf *secondary;
    217	bool primary_ll;
    218	u8 primary_load;
    219	u8 secondary_load;
    220};
    221
    222static inline
    223void iwl_mvm_bt_coex_enable_rssi_event(struct iwl_mvm *mvm,
    224				       struct ieee80211_vif *vif,
    225				       bool enable, int rssi)
    226{
    227	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
    228
    229	mvmvif->bf_data.last_bt_coex_event = rssi;
    230	mvmvif->bf_data.bt_coex_max_thold =
    231		enable ? -IWL_MVM_BT_COEX_EN_RED_TXP_THRESH : 0;
    232	mvmvif->bf_data.bt_coex_min_thold =
    233		enable ? -IWL_MVM_BT_COEX_DIS_RED_TXP_THRESH : 0;
    234}
    235
    236#define MVM_COEX_TCM_PERIOD (HZ * 10)
    237
    238static void iwl_mvm_bt_coex_tcm_based_ci(struct iwl_mvm *mvm,
    239					 struct iwl_bt_iterator_data *data)
    240{
    241	unsigned long now = jiffies;
    242
    243	if (!time_after(now, mvm->bt_coex_last_tcm_ts + MVM_COEX_TCM_PERIOD))
    244		return;
    245
    246	mvm->bt_coex_last_tcm_ts = now;
    247
    248	/* We assume here that we don't have more than 2 vifs on 2.4GHz */
    249
    250	/* if the primary is low latency, it will stay primary */
    251	if (data->primary_ll)
    252		return;
    253
    254	if (data->primary_load >= data->secondary_load)
    255		return;
    256
    257	swap(data->primary, data->secondary);
    258}
    259
    260/* must be called under rcu_read_lock */
    261static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac,
    262				      struct ieee80211_vif *vif)
    263{
    264	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
    265	struct iwl_bt_iterator_data *data = _data;
    266	struct iwl_mvm *mvm = data->mvm;
    267	struct ieee80211_chanctx_conf *chanctx_conf;
    268	/* default smps_mode is AUTOMATIC - only used for client modes */
    269	enum ieee80211_smps_mode smps_mode = IEEE80211_SMPS_AUTOMATIC;
    270	u32 bt_activity_grading, min_ag_for_static_smps;
    271	int ave_rssi;
    272
    273	lockdep_assert_held(&mvm->mutex);
    274
    275	switch (vif->type) {
    276	case NL80211_IFTYPE_STATION:
    277		break;
    278	case NL80211_IFTYPE_AP:
    279		if (!mvmvif->ap_ibss_active)
    280			return;
    281		break;
    282	default:
    283		return;
    284	}
    285
    286	chanctx_conf = rcu_dereference(vif->chanctx_conf);
    287
    288	/* If channel context is invalid or not on 2.4GHz .. */
    289	if ((!chanctx_conf ||
    290	     chanctx_conf->def.chan->band != NL80211_BAND_2GHZ)) {
    291		if (vif->type == NL80211_IFTYPE_STATION) {
    292			/* ... relax constraints and disable rssi events */
    293			iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX,
    294					    smps_mode);
    295			iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id,
    296						    false);
    297			iwl_mvm_bt_coex_enable_rssi_event(mvm, vif, false, 0);
    298		}
    299		return;
    300	}
    301
    302	if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_COEX_SCHEMA_2))
    303		min_ag_for_static_smps = BT_VERY_HIGH_TRAFFIC;
    304	else
    305		min_ag_for_static_smps = BT_HIGH_TRAFFIC;
    306
    307	bt_activity_grading = le32_to_cpu(data->notif->bt_activity_grading);
    308	if (bt_activity_grading >= min_ag_for_static_smps)
    309		smps_mode = IEEE80211_SMPS_STATIC;
    310	else if (bt_activity_grading >= BT_LOW_TRAFFIC)
    311		smps_mode = IEEE80211_SMPS_DYNAMIC;
    312
    313	/* relax SMPS constraints for next association */
    314	if (!vif->bss_conf.assoc)
    315		smps_mode = IEEE80211_SMPS_AUTOMATIC;
    316
    317	if (mvmvif->phy_ctxt &&
    318	    (mvm->last_bt_notif.rrc_status & BIT(mvmvif->phy_ctxt->id)))
    319		smps_mode = IEEE80211_SMPS_AUTOMATIC;
    320
    321	IWL_DEBUG_COEX(data->mvm,
    322		       "mac %d: bt_activity_grading %d smps_req %d\n",
    323		       mvmvif->id, bt_activity_grading, smps_mode);
    324
    325	if (vif->type == NL80211_IFTYPE_STATION)
    326		iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX,
    327				    smps_mode);
    328
    329	/* low latency is always primary */
    330	if (iwl_mvm_vif_low_latency(mvmvif)) {
    331		data->primary_ll = true;
    332
    333		data->secondary = data->primary;
    334		data->primary = chanctx_conf;
    335	}
    336
    337	if (vif->type == NL80211_IFTYPE_AP) {
    338		if (!mvmvif->ap_ibss_active)
    339			return;
    340
    341		if (chanctx_conf == data->primary)
    342			return;
    343
    344		if (!data->primary_ll) {
    345			/*
    346			 * downgrade the current primary no matter what its
    347			 * type is.
    348			 */
    349			data->secondary = data->primary;
    350			data->primary = chanctx_conf;
    351		} else {
    352			/* there is low latency vif - we will be secondary */
    353			data->secondary = chanctx_conf;
    354		}
    355
    356		if (data->primary == chanctx_conf)
    357			data->primary_load = mvm->tcm.result.load[mvmvif->id];
    358		else if (data->secondary == chanctx_conf)
    359			data->secondary_load = mvm->tcm.result.load[mvmvif->id];
    360		return;
    361	}
    362
    363	/*
    364	 * STA / P2P Client, try to be primary if first vif. If we are in low
    365	 * latency mode, we are already in primary and just don't do much
    366	 */
    367	if (!data->primary || data->primary == chanctx_conf)
    368		data->primary = chanctx_conf;
    369	else if (!data->secondary)
    370		/* if secondary is not NULL, it might be a GO */
    371		data->secondary = chanctx_conf;
    372
    373	if (data->primary == chanctx_conf)
    374		data->primary_load = mvm->tcm.result.load[mvmvif->id];
    375	else if (data->secondary == chanctx_conf)
    376		data->secondary_load = mvm->tcm.result.load[mvmvif->id];
    377	/*
    378	 * don't reduce the Tx power if one of these is true:
    379	 *  we are in LOOSE
    380	 *  single share antenna product
    381	 *  BT is inactive
    382	 *  we are not associated
    383	 */
    384	if (iwl_get_coex_type(mvm, vif) == BT_COEX_LOOSE_LUT ||
    385	    mvm->cfg->bt_shared_single_ant || !vif->bss_conf.assoc ||
    386	    le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) == BT_OFF) {
    387		iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, false);
    388		iwl_mvm_bt_coex_enable_rssi_event(mvm, vif, false, 0);
    389		return;
    390	}
    391
    392	/* try to get the avg rssi from fw */
    393	ave_rssi = mvmvif->bf_data.ave_beacon_signal;
    394
    395	/* if the RSSI isn't valid, fake it is very low */
    396	if (!ave_rssi)
    397		ave_rssi = -100;
    398	if (ave_rssi > -IWL_MVM_BT_COEX_EN_RED_TXP_THRESH) {
    399		if (iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, true))
    400			IWL_ERR(mvm, "Couldn't send BT_CONFIG cmd\n");
    401	} else if (ave_rssi < -IWL_MVM_BT_COEX_DIS_RED_TXP_THRESH) {
    402		if (iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, false))
    403			IWL_ERR(mvm, "Couldn't send BT_CONFIG cmd\n");
    404	}
    405
    406	/* Begin to monitor the RSSI: it may influence the reduced Tx power */
    407	iwl_mvm_bt_coex_enable_rssi_event(mvm, vif, true, ave_rssi);
    408}
    409
    410static void iwl_mvm_bt_coex_notif_handle(struct iwl_mvm *mvm)
    411{
    412	struct iwl_bt_iterator_data data = {
    413		.mvm = mvm,
    414		.notif = &mvm->last_bt_notif,
    415	};
    416	struct iwl_bt_coex_ci_cmd cmd = {};
    417	u8 ci_bw_idx;
    418
    419	/* Ignore updates if we are in force mode */
    420	if (unlikely(mvm->bt_force_ant_mode != BT_FORCE_ANT_DIS))
    421		return;
    422
    423	rcu_read_lock();
    424	ieee80211_iterate_active_interfaces_atomic(
    425					mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
    426					iwl_mvm_bt_notif_iterator, &data);
    427
    428	iwl_mvm_bt_coex_tcm_based_ci(mvm, &data);
    429
    430	if (data.primary) {
    431		struct ieee80211_chanctx_conf *chan = data.primary;
    432		if (WARN_ON(!chan->def.chan)) {
    433			rcu_read_unlock();
    434			return;
    435		}
    436
    437		if (chan->def.width < NL80211_CHAN_WIDTH_40) {
    438			ci_bw_idx = 0;
    439		} else {
    440			if (chan->def.center_freq1 >
    441			    chan->def.chan->center_freq)
    442				ci_bw_idx = 2;
    443			else
    444				ci_bw_idx = 1;
    445		}
    446
    447		cmd.bt_primary_ci =
    448			iwl_ci_mask[chan->def.chan->hw_value][ci_bw_idx];
    449		cmd.primary_ch_phy_id =
    450			cpu_to_le32(*((u16 *)data.primary->drv_priv));
    451	}
    452
    453	if (data.secondary) {
    454		struct ieee80211_chanctx_conf *chan = data.secondary;
    455		if (WARN_ON(!data.secondary->def.chan)) {
    456			rcu_read_unlock();
    457			return;
    458		}
    459
    460		if (chan->def.width < NL80211_CHAN_WIDTH_40) {
    461			ci_bw_idx = 0;
    462		} else {
    463			if (chan->def.center_freq1 >
    464			    chan->def.chan->center_freq)
    465				ci_bw_idx = 2;
    466			else
    467				ci_bw_idx = 1;
    468		}
    469
    470		cmd.bt_secondary_ci =
    471			iwl_ci_mask[chan->def.chan->hw_value][ci_bw_idx];
    472		cmd.secondary_ch_phy_id =
    473			cpu_to_le32(*((u16 *)data.secondary->drv_priv));
    474	}
    475
    476	rcu_read_unlock();
    477
    478	/* Don't spam the fw with the same command over and over */
    479	if (memcmp(&cmd, &mvm->last_bt_ci_cmd, sizeof(cmd))) {
    480		if (iwl_mvm_send_cmd_pdu(mvm, BT_COEX_CI, 0,
    481					 sizeof(cmd), &cmd))
    482			IWL_ERR(mvm, "Failed to send BT_CI cmd\n");
    483		memcpy(&mvm->last_bt_ci_cmd, &cmd, sizeof(cmd));
    484	}
    485}
    486
    487void iwl_mvm_rx_bt_coex_notif(struct iwl_mvm *mvm,
    488			      struct iwl_rx_cmd_buffer *rxb)
    489{
    490	struct iwl_rx_packet *pkt = rxb_addr(rxb);
    491	struct iwl_bt_coex_profile_notif *notif = (void *)pkt->data;
    492
    493	IWL_DEBUG_COEX(mvm, "BT Coex Notification received\n");
    494	IWL_DEBUG_COEX(mvm, "\tBT ci compliance %d\n", notif->bt_ci_compliance);
    495	IWL_DEBUG_COEX(mvm, "\tBT primary_ch_lut %d\n",
    496		       le32_to_cpu(notif->primary_ch_lut));
    497	IWL_DEBUG_COEX(mvm, "\tBT secondary_ch_lut %d\n",
    498		       le32_to_cpu(notif->secondary_ch_lut));
    499	IWL_DEBUG_COEX(mvm, "\tBT activity grading %d\n",
    500		       le32_to_cpu(notif->bt_activity_grading));
    501
    502	/* remember this notification for future use: rssi fluctuations */
    503	memcpy(&mvm->last_bt_notif, notif, sizeof(mvm->last_bt_notif));
    504
    505	iwl_mvm_bt_coex_notif_handle(mvm);
    506}
    507
    508void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
    509			   enum ieee80211_rssi_event_data rssi_event)
    510{
    511	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
    512	int ret;
    513
    514	lockdep_assert_held(&mvm->mutex);
    515
    516	/* Ignore updates if we are in force mode */
    517	if (unlikely(mvm->bt_force_ant_mode != BT_FORCE_ANT_DIS))
    518		return;
    519
    520	/*
    521	 * Rssi update while not associated - can happen since the statistics
    522	 * are handled asynchronously
    523	 */
    524	if (mvmvif->ap_sta_id == IWL_MVM_INVALID_STA)
    525		return;
    526
    527	/* No BT - reports should be disabled */
    528	if (le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) == BT_OFF)
    529		return;
    530
    531	IWL_DEBUG_COEX(mvm, "RSSI for %pM is now %s\n", vif->bss_conf.bssid,
    532		       rssi_event == RSSI_EVENT_HIGH ? "HIGH" : "LOW");
    533
    534	/*
    535	 * Check if rssi is good enough for reduced Tx power, but not in loose
    536	 * scheme.
    537	 */
    538	if (rssi_event == RSSI_EVENT_LOW || mvm->cfg->bt_shared_single_ant ||
    539	    iwl_get_coex_type(mvm, vif) == BT_COEX_LOOSE_LUT)
    540		ret = iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id,
    541						  false);
    542	else
    543		ret = iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, true);
    544
    545	if (ret)
    546		IWL_ERR(mvm, "couldn't send BT_CONFIG HCMD upon RSSI event\n");
    547}
    548
    549#define LINK_QUAL_AGG_TIME_LIMIT_DEF	(4000)
    550#define LINK_QUAL_AGG_TIME_LIMIT_BT_ACT	(1200)
    551
    552u16 iwl_mvm_coex_agg_time_limit(struct iwl_mvm *mvm,
    553				struct ieee80211_sta *sta)
    554{
    555	struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
    556	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(mvmsta->vif);
    557	struct iwl_mvm_phy_ctxt *phy_ctxt = mvmvif->phy_ctxt;
    558	enum iwl_bt_coex_lut_type lut_type;
    559
    560	if (mvm->last_bt_notif.ttc_status & BIT(phy_ctxt->id))
    561		return LINK_QUAL_AGG_TIME_LIMIT_DEF;
    562
    563	if (le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) <
    564	    BT_HIGH_TRAFFIC)
    565		return LINK_QUAL_AGG_TIME_LIMIT_DEF;
    566
    567	lut_type = iwl_get_coex_type(mvm, mvmsta->vif);
    568
    569	if (lut_type == BT_COEX_LOOSE_LUT || lut_type == BT_COEX_INVALID_LUT)
    570		return LINK_QUAL_AGG_TIME_LIMIT_DEF;
    571
    572	/* tight coex, high bt traffic, reduce AGG time limit */
    573	return LINK_QUAL_AGG_TIME_LIMIT_BT_ACT;
    574}
    575
    576bool iwl_mvm_bt_coex_is_mimo_allowed(struct iwl_mvm *mvm,
    577				     struct ieee80211_sta *sta)
    578{
    579	struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
    580	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(mvmsta->vif);
    581	struct iwl_mvm_phy_ctxt *phy_ctxt = mvmvif->phy_ctxt;
    582	enum iwl_bt_coex_lut_type lut_type;
    583
    584	if (mvm->last_bt_notif.ttc_status & BIT(phy_ctxt->id))
    585		return true;
    586
    587	if (le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) <
    588	    BT_HIGH_TRAFFIC)
    589		return true;
    590
    591	/*
    592	 * In Tight / TxTxDis, BT can't Rx while we Tx, so use both antennas
    593	 * since BT is already killed.
    594	 * In Loose, BT can Rx while we Tx, so forbid MIMO to let BT Rx while
    595	 * we Tx.
    596	 * When we are in 5GHz, we'll get BT_COEX_INVALID_LUT allowing MIMO.
    597	 */
    598	lut_type = iwl_get_coex_type(mvm, mvmsta->vif);
    599	return lut_type != BT_COEX_LOOSE_LUT;
    600}
    601
    602bool iwl_mvm_bt_coex_is_ant_avail(struct iwl_mvm *mvm, u8 ant)
    603{
    604	/* there is no other antenna, shared antenna is always available */
    605	if (mvm->cfg->bt_shared_single_ant)
    606		return true;
    607
    608	if (ant & mvm->cfg->non_shared_ant)
    609		return true;
    610
    611	return le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) <
    612		BT_HIGH_TRAFFIC;
    613}
    614
    615bool iwl_mvm_bt_coex_is_shared_ant_avail(struct iwl_mvm *mvm)
    616{
    617	/* there is no other antenna, shared antenna is always available */
    618	if (mvm->cfg->bt_shared_single_ant)
    619		return true;
    620
    621	return le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) < BT_HIGH_TRAFFIC;
    622}
    623
    624bool iwl_mvm_bt_coex_is_tpc_allowed(struct iwl_mvm *mvm,
    625				    enum nl80211_band band)
    626{
    627	u32 bt_activity = le32_to_cpu(mvm->last_bt_notif.bt_activity_grading);
    628
    629	if (band != NL80211_BAND_2GHZ)
    630		return false;
    631
    632	return bt_activity >= BT_LOW_TRAFFIC;
    633}
    634
    635u8 iwl_mvm_bt_coex_get_single_ant_msk(struct iwl_mvm *mvm, u8 enabled_ants)
    636{
    637	if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_COEX_SCHEMA_2) &&
    638	    (mvm->cfg->non_shared_ant & enabled_ants))
    639		return mvm->cfg->non_shared_ant;
    640
    641	return first_antenna(enabled_ants);
    642}
    643
    644u8 iwl_mvm_bt_coex_tx_prio(struct iwl_mvm *mvm, struct ieee80211_hdr *hdr,
    645			   struct ieee80211_tx_info *info, u8 ac)
    646{
    647	__le16 fc = hdr->frame_control;
    648	bool mplut_enabled = iwl_mvm_is_mplut_supported(mvm);
    649
    650	if (info->band != NL80211_BAND_2GHZ)
    651		return 0;
    652
    653	if (unlikely(mvm->bt_tx_prio))
    654		return mvm->bt_tx_prio - 1;
    655
    656	if (likely(ieee80211_is_data(fc))) {
    657		if (likely(ieee80211_is_data_qos(fc))) {
    658			switch (ac) {
    659			case IEEE80211_AC_BE:
    660				return mplut_enabled ? 1 : 0;
    661			case IEEE80211_AC_VI:
    662				return mplut_enabled ? 2 : 3;
    663			case IEEE80211_AC_VO:
    664				return 3;
    665			default:
    666				return 0;
    667			}
    668		} else if (is_multicast_ether_addr(hdr->addr1)) {
    669			return 3;
    670		} else
    671			return 0;
    672	} else if (ieee80211_is_mgmt(fc)) {
    673		return ieee80211_is_disassoc(fc) ? 0 : 3;
    674	} else if (ieee80211_is_ctl(fc)) {
    675		/* ignore cfend and cfendack frames as we never send those */
    676		return 3;
    677	}
    678
    679	return 0;
    680}
    681
    682void iwl_mvm_bt_coex_vif_change(struct iwl_mvm *mvm)
    683{
    684	iwl_mvm_bt_coex_notif_handle(mvm);
    685}