diff options
Diffstat (limited to 'drivers/net/wireless/iwlwifi/mvm/coex.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/coex.c | 513 |
1 files changed, 229 insertions, 284 deletions
diff --git a/drivers/net/wireless/iwlwifi/mvm/coex.c b/drivers/net/wireless/iwlwifi/mvm/coex.c index c8c3b38..2291bbc 100644 --- a/drivers/net/wireless/iwlwifi/mvm/coex.c +++ b/drivers/net/wireless/iwlwifi/mvm/coex.c @@ -70,57 +70,58 @@ #include "mvm.h" #include "iwl-debug.h" -#define EVENT_PRIO_ANT(_evt, _prio, _shrd_ant) \ - [(_evt)] = (((_prio) << BT_COEX_PRIO_TBL_PRIO_POS) | \ - ((_shrd_ant) << BT_COEX_PRIO_TBL_SHRD_ANT_POS)) - -static const u8 iwl_bt_prio_tbl[BT_COEX_PRIO_TBL_EVT_MAX] = { - EVENT_PRIO_ANT(BT_COEX_PRIO_TBL_EVT_INIT_CALIB1, - BT_COEX_PRIO_TBL_PRIO_BYPASS, 0), - EVENT_PRIO_ANT(BT_COEX_PRIO_TBL_EVT_INIT_CALIB2, - BT_COEX_PRIO_TBL_PRIO_BYPASS, 1), - EVENT_PRIO_ANT(BT_COEX_PRIO_TBL_EVT_PERIODIC_CALIB_LOW1, - BT_COEX_PRIO_TBL_PRIO_LOW, 0), - EVENT_PRIO_ANT(BT_COEX_PRIO_TBL_EVT_PERIODIC_CALIB_LOW2, - BT_COEX_PRIO_TBL_PRIO_LOW, 1), - EVENT_PRIO_ANT(BT_COEX_PRIO_TBL_EVT_PERIODIC_CALIB_HIGH1, - BT_COEX_PRIO_TBL_PRIO_HIGH, 0), - EVENT_PRIO_ANT(BT_COEX_PRIO_TBL_EVT_PERIODIC_CALIB_HIGH2, - BT_COEX_PRIO_TBL_PRIO_HIGH, 1), - EVENT_PRIO_ANT(BT_COEX_PRIO_TBL_EVT_DTIM, - BT_COEX_PRIO_TBL_DISABLED, 0), - EVENT_PRIO_ANT(BT_COEX_PRIO_TBL_EVT_SCAN52, - BT_COEX_PRIO_TBL_PRIO_COEX_OFF, 0), - EVENT_PRIO_ANT(BT_COEX_PRIO_TBL_EVT_SCAN24, - BT_COEX_PRIO_TBL_PRIO_COEX_ON, 0), - EVENT_PRIO_ANT(BT_COEX_PRIO_TBL_EVT_IDLE, - BT_COEX_PRIO_TBL_PRIO_COEX_IDLE, 0), - 0, 0, 0, 0, 0, 0, -}; - -#undef EVENT_PRIO_ANT - -#define BT_ENABLE_REDUCED_TXPOWER_THRESHOLD (-62) -#define BT_DISABLE_REDUCED_TXPOWER_THRESHOLD (-65) #define BT_ANTENNA_COUPLING_THRESHOLD (30) -static int iwl_send_bt_prio_tbl(struct iwl_mvm *mvm) -{ - return iwl_mvm_send_cmd_pdu(mvm, BT_COEX_PRIO_TABLE, 0, - sizeof(struct iwl_bt_coex_prio_tbl_cmd), - &iwl_bt_prio_tbl); -} +const u32 iwl_bt_ctl_kill_msk[BT_KILL_MSK_MAX] = { + [BT_KILL_MSK_DEFAULT] = 0xfffffc00, + [BT_KILL_MSK_NEVER] = 0xffffffff, + [BT_KILL_MSK_ALWAYS] = 0, +}; -const u32 iwl_bt_ack_kill_msk[BT_KILL_MSK_MAX] = { - [BT_KILL_MSK_DEFAULT] = 0xffff0000, - [BT_KILL_MSK_SCO_HID_A2DP] = 0xffffffff, - [BT_KILL_MSK_REDUCED_TXPOW] = 0, +const u8 iwl_bt_cts_kill_msk[BT_MAX_AG][BT_COEX_MAX_LUT] = { + { + BT_KILL_MSK_ALWAYS, + BT_KILL_MSK_ALWAYS, + BT_KILL_MSK_ALWAYS, + }, + { + BT_KILL_MSK_NEVER, + BT_KILL_MSK_NEVER, + BT_KILL_MSK_NEVER, + }, + { + BT_KILL_MSK_NEVER, + BT_KILL_MSK_NEVER, + BT_KILL_MSK_NEVER, + }, + { + BT_KILL_MSK_DEFAULT, + BT_KILL_MSK_NEVER, + BT_KILL_MSK_DEFAULT, + }, }; -const u32 iwl_bt_cts_kill_msk[BT_KILL_MSK_MAX] = { - [BT_KILL_MSK_DEFAULT] = 0xffff0000, - [BT_KILL_MSK_SCO_HID_A2DP] = 0xffffffff, - [BT_KILL_MSK_REDUCED_TXPOW] = 0, +const u8 iwl_bt_ack_kill_msk[BT_MAX_AG][BT_COEX_MAX_LUT] = { + { + BT_KILL_MSK_ALWAYS, + BT_KILL_MSK_ALWAYS, + BT_KILL_MSK_ALWAYS, + }, + { + BT_KILL_MSK_ALWAYS, + BT_KILL_MSK_ALWAYS, + BT_KILL_MSK_ALWAYS, + }, + { + BT_KILL_MSK_ALWAYS, + BT_KILL_MSK_ALWAYS, + BT_KILL_MSK_ALWAYS, + }, + { + BT_KILL_MSK_DEFAULT, + BT_KILL_MSK_ALWAYS, + BT_KILL_MSK_DEFAULT, + }, }; static const __le32 iwl_bt_prio_boost[BT_COEX_BOOST_SIZE] = { @@ -519,6 +520,7 @@ iwl_get_coex_type(struct iwl_mvm *mvm, const struct ieee80211_vif *vif) struct ieee80211_chanctx_conf *chanctx_conf; enum iwl_bt_coex_lut_type ret; u16 phy_ctx_id; + u32 primary_ch_phy_id, secondary_ch_phy_id; /* * Checking that we hold mvm->mutex is a good idea, but the rate @@ -535,7 +537,7 @@ iwl_get_coex_type(struct iwl_mvm *mvm, const struct ieee80211_vif *vif) if (!chanctx_conf || chanctx_conf->def.chan->band != IEEE80211_BAND_2GHZ) { rcu_read_unlock(); - return BT_COEX_LOOSE_LUT; + return BT_COEX_INVALID_LUT; } ret = BT_COEX_TX_DIS_LUT; @@ -546,10 +548,13 @@ iwl_get_coex_type(struct iwl_mvm *mvm, const struct ieee80211_vif *vif) } phy_ctx_id = *((u16 *)chanctx_conf->drv_priv); + primary_ch_phy_id = le32_to_cpu(mvm->last_bt_ci_cmd.primary_ch_phy_id); + secondary_ch_phy_id = + le32_to_cpu(mvm->last_bt_ci_cmd.secondary_ch_phy_id); - if (mvm->last_bt_ci_cmd.primary_ch_phy_id == phy_ctx_id) + if (primary_ch_phy_id == phy_ctx_id) ret = le32_to_cpu(mvm->last_bt_notif.primary_ch_lut); - else if (mvm->last_bt_ci_cmd.secondary_ch_phy_id == phy_ctx_id) + else if (secondary_ch_phy_id == phy_ctx_id) ret = le32_to_cpu(mvm->last_bt_notif.secondary_ch_lut); /* else - default = TX TX disallowed */ @@ -567,59 +572,63 @@ int iwl_send_bt_init_conf(struct iwl_mvm *mvm) .dataflags = { IWL_HCMD_DFL_NOCOPY, }, }; int ret; - u32 flags; + u32 mode; - ret = iwl_send_bt_prio_tbl(mvm); - if (ret) - return ret; + if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BT_COEX_SPLIT)) + return iwl_send_bt_init_conf_old(mvm); bt_cmd = kzalloc(sizeof(*bt_cmd), GFP_KERNEL); if (!bt_cmd) return -ENOMEM; cmd.data[0] = bt_cmd; - bt_cmd->max_kill = 5; - bt_cmd->bt4_antenna_isolation_thr = BT_ANTENNA_COUPLING_THRESHOLD; - bt_cmd->bt4_antenna_isolation = iwlwifi_mod_params.ant_coupling; - bt_cmd->bt4_tx_tx_delta_freq_thr = 15; - bt_cmd->bt4_tx_rx_max_freq0 = 15; - bt_cmd->override_primary_lut = BT_COEX_INVALID_LUT; - bt_cmd->override_secondary_lut = BT_COEX_INVALID_LUT; - - flags = iwlwifi_mod_params.bt_coex_active ? - BT_COEX_NW : BT_COEX_DISABLE; - bt_cmd->flags = cpu_to_le32(flags); - - bt_cmd->valid_bit_msk = cpu_to_le32(BT_VALID_ENABLE | - BT_VALID_BT_PRIO_BOOST | - BT_VALID_MAX_KILL | - BT_VALID_3W_TMRS | - BT_VALID_KILL_ACK | - BT_VALID_KILL_CTS | - BT_VALID_REDUCED_TX_POWER | - BT_VALID_LUT | - BT_VALID_WIFI_RX_SW_PRIO_BOOST | - BT_VALID_WIFI_TX_SW_PRIO_BOOST | - BT_VALID_ANT_ISOLATION | - BT_VALID_ANT_ISOLATION_THRS | - BT_VALID_TXTX_DELTA_FREQ_THRS | - BT_VALID_TXRX_MAX_FREQ_0 | - BT_VALID_SYNC_TO_SCO); + lockdep_assert_held(&mvm->mutex); - if (IWL_MVM_BT_COEX_SYNC2SCO) - bt_cmd->flags |= cpu_to_le32(BT_COEX_SYNC2SCO); + if (unlikely(mvm->bt_force_ant_mode != BT_FORCE_ANT_DIS)) { + u32 mode; - if (IWL_MVM_BT_COEX_CORUNNING) { - bt_cmd->valid_bit_msk |= cpu_to_le32(BT_VALID_CORUN_LUT_20 | - BT_VALID_CORUN_LUT_40); - bt_cmd->flags |= cpu_to_le32(BT_COEX_CORUNNING); + switch (mvm->bt_force_ant_mode) { + case BT_FORCE_ANT_BT: + mode = BT_COEX_BT; + break; + case BT_FORCE_ANT_WIFI: + mode = BT_COEX_WIFI; + break; + default: + WARN_ON(1); + mode = 0; + } + + bt_cmd->mode = cpu_to_le32(mode); + goto send_cmd; } + bt_cmd->max_kill = cpu_to_le32(5); + bt_cmd->bt4_antenna_isolation_thr = + cpu_to_le32(BT_ANTENNA_COUPLING_THRESHOLD); + bt_cmd->bt4_tx_tx_delta_freq_thr = cpu_to_le32(15); + bt_cmd->bt4_tx_rx_max_freq0 = cpu_to_le32(15); + bt_cmd->override_primary_lut = cpu_to_le32(BT_COEX_INVALID_LUT); + bt_cmd->override_secondary_lut = cpu_to_le32(BT_COEX_INVALID_LUT); + + mode = iwlwifi_mod_params.bt_coex_active ? BT_COEX_NW : BT_COEX_DISABLE; + bt_cmd->mode = cpu_to_le32(mode); + + if (IWL_MVM_BT_COEX_SYNC2SCO) + bt_cmd->enabled_modules |= + cpu_to_le32(BT_COEX_SYNC2SCO_ENABLED); + + if (IWL_MVM_BT_COEX_CORUNNING) + bt_cmd->enabled_modules |= cpu_to_le32(BT_COEX_CORUN_ENABLED); + if (IWL_MVM_BT_COEX_MPLUT) { - bt_cmd->flags |= cpu_to_le32(BT_COEX_MPLUT); - bt_cmd->valid_bit_msk |= cpu_to_le32(BT_VALID_MULTI_PRIO_LUT); + bt_cmd->enabled_modules |= cpu_to_le32(BT_COEX_MPLUT_ENABLED); + bt_cmd->enabled_modules |= + cpu_to_le32(BT_COEX_MPLUT_BOOST_ENABLED); } + bt_cmd->enabled_modules |= cpu_to_le32(BT_COEX_HIGH_BAND_RET); + if (mvm->cfg->bt_shared_single_ant) memcpy(&bt_cmd->decision_lut, iwl_single_shared_ant, sizeof(iwl_single_shared_ant)); @@ -627,21 +636,12 @@ int iwl_send_bt_init_conf(struct iwl_mvm *mvm) memcpy(&bt_cmd->decision_lut, iwl_combined_lookup, sizeof(iwl_combined_lookup)); - /* Take first Co-running block LUT to get started */ - memcpy(bt_cmd->bt4_corun_lut20, antenna_coupling_ranges[0].lut20, - sizeof(bt_cmd->bt4_corun_lut20)); - memcpy(bt_cmd->bt4_corun_lut40, antenna_coupling_ranges[0].lut20, - sizeof(bt_cmd->bt4_corun_lut40)); - - memcpy(&bt_cmd->bt_prio_boost, iwl_bt_prio_boost, + memcpy(&bt_cmd->mplut_prio_boost, iwl_bt_prio_boost, sizeof(iwl_bt_prio_boost)); - memcpy(&bt_cmd->bt4_multiprio_lut, iwl_bt_mprio_lut, + memcpy(&bt_cmd->multiprio_lut, iwl_bt_mprio_lut, sizeof(iwl_bt_mprio_lut)); - bt_cmd->kill_ack_msk = - cpu_to_le32(iwl_bt_ack_kill_msk[BT_KILL_MSK_DEFAULT]); - bt_cmd->kill_cts_msk = - cpu_to_le32(iwl_bt_cts_kill_msk[BT_KILL_MSK_DEFAULT]); +send_cmd: memset(&mvm->last_bt_notif, 0, sizeof(mvm->last_bt_notif)); memset(&mvm->last_bt_ci_cmd, 0, sizeof(mvm->last_bt_ci_cmd)); @@ -651,82 +651,54 @@ int iwl_send_bt_init_conf(struct iwl_mvm *mvm) return ret; } -static int iwl_mvm_bt_udpate_ctrl_kill_msk(struct iwl_mvm *mvm, - bool reduced_tx_power) +static int iwl_mvm_bt_udpate_sw_boost(struct iwl_mvm *mvm) { - enum iwl_bt_kill_msk bt_kill_msk; - struct iwl_bt_coex_cmd *bt_cmd; struct iwl_bt_coex_profile_notif *notif = &mvm->last_bt_notif; - struct iwl_host_cmd cmd = { - .id = BT_CONFIG, - .data[0] = &bt_cmd, - .len = { sizeof(*bt_cmd), }, - .dataflags = { IWL_HCMD_DFL_NOCOPY, }, - }; - int ret = 0; + u32 primary_lut = le32_to_cpu(notif->primary_ch_lut); + u32 secondary_lut = le32_to_cpu(notif->secondary_ch_lut); + u32 ag = le32_to_cpu(notif->bt_activity_grading); + struct iwl_bt_coex_sw_boost_update_cmd cmd = {}; + u8 ack_kill_msk[NUM_PHY_CTX] = {}; + u8 cts_kill_msk[NUM_PHY_CTX] = {}; + int i; lockdep_assert_held(&mvm->mutex); - if (reduced_tx_power) { - /* Reduced Tx power has precedence on the type of the profile */ - bt_kill_msk = BT_KILL_MSK_REDUCED_TXPOW; - } else { - /* Low latency BT profile is active: give higher prio to BT */ - if (BT_MBOX_MSG(notif, 3, SCO_STATE) || - BT_MBOX_MSG(notif, 3, A2DP_STATE) || - BT_MBOX_MSG(notif, 3, SNIFF_STATE)) - bt_kill_msk = BT_KILL_MSK_SCO_HID_A2DP; - else - bt_kill_msk = BT_KILL_MSK_DEFAULT; - } + ack_kill_msk[0] = iwl_bt_ack_kill_msk[ag][primary_lut]; + cts_kill_msk[0] = iwl_bt_cts_kill_msk[ag][primary_lut]; - IWL_DEBUG_COEX(mvm, - "Update kill_msk: %d - SCO %sactive A2DP %sactive SNIFF %sactive\n", - bt_kill_msk, - BT_MBOX_MSG(notif, 3, SCO_STATE) ? "" : "in", - BT_MBOX_MSG(notif, 3, A2DP_STATE) ? "" : "in", - BT_MBOX_MSG(notif, 3, SNIFF_STATE) ? "" : "in"); + ack_kill_msk[1] = iwl_bt_ack_kill_msk[ag][secondary_lut]; + cts_kill_msk[1] = iwl_bt_cts_kill_msk[ag][secondary_lut]; /* Don't send HCMD if there is no update */ - if (bt_kill_msk == mvm->bt_kill_msk) + if (!memcmp(ack_kill_msk, mvm->bt_ack_kill_msk, sizeof(ack_kill_msk)) || + !memcmp(cts_kill_msk, mvm->bt_cts_kill_msk, sizeof(cts_kill_msk))) return 0; - mvm->bt_kill_msk = bt_kill_msk; - - bt_cmd = kzalloc(sizeof(*bt_cmd), GFP_KERNEL); - if (!bt_cmd) - return -ENOMEM; - cmd.data[0] = bt_cmd; - bt_cmd->flags = cpu_to_le32(BT_COEX_NW); - - bt_cmd->kill_ack_msk = cpu_to_le32(iwl_bt_ack_kill_msk[bt_kill_msk]); - bt_cmd->kill_cts_msk = cpu_to_le32(iwl_bt_cts_kill_msk[bt_kill_msk]); - bt_cmd->valid_bit_msk |= cpu_to_le32(BT_VALID_ENABLE | - BT_VALID_KILL_ACK | - BT_VALID_KILL_CTS); + memcpy(mvm->bt_ack_kill_msk, ack_kill_msk, + sizeof(mvm->bt_ack_kill_msk)); + memcpy(mvm->bt_cts_kill_msk, cts_kill_msk, + sizeof(mvm->bt_cts_kill_msk)); - IWL_DEBUG_COEX(mvm, "ACK Kill msk = 0x%08x, CTS Kill msk = 0x%08x\n", - iwl_bt_ack_kill_msk[bt_kill_msk], - iwl_bt_cts_kill_msk[bt_kill_msk]); + BUILD_BUG_ON(ARRAY_SIZE(ack_kill_msk) < ARRAY_SIZE(cmd.boost_values)); - ret = iwl_mvm_send_cmd(mvm, &cmd); + for (i = 0; i < ARRAY_SIZE(cmd.boost_values); i++) { + cmd.boost_values[i].kill_ack_msk = + cpu_to_le32(iwl_bt_ctl_kill_msk[ack_kill_msk[i]]); + cmd.boost_values[i].kill_cts_msk = + cpu_to_le32(iwl_bt_ctl_kill_msk[cts_kill_msk[i]]); + } - kfree(bt_cmd); - return ret; + return iwl_mvm_send_cmd_pdu(mvm, BT_COEX_UPDATE_SW_BOOST, 0, + sizeof(cmd), &cmd); } static int iwl_mvm_bt_coex_reduced_txp(struct iwl_mvm *mvm, u8 sta_id, bool enable) { - struct iwl_bt_coex_cmd *bt_cmd; - /* Send ASYNC since this can be sent from an atomic context */ - struct iwl_host_cmd cmd = { - .id = BT_CONFIG, - .len = { sizeof(*bt_cmd), }, - .dataflags = { IWL_HCMD_DFL_NOCOPY, }, - .flags = CMD_ASYNC, - }; + struct iwl_bt_coex_reduced_txp_update_cmd cmd = {}; struct iwl_mvm_sta *mvmsta; + u32 value; int ret; mvmsta = iwl_mvm_sta_from_staid_protected(mvm, sta_id); @@ -737,35 +709,26 @@ static int iwl_mvm_bt_coex_reduced_txp(struct iwl_mvm *mvm, u8 sta_id, if (mvmsta->bt_reduced_txpower == enable) return 0; - bt_cmd = kzalloc(sizeof(*bt_cmd), GFP_ATOMIC); - if (!bt_cmd) - return -ENOMEM; - cmd.data[0] = bt_cmd; - bt_cmd->flags = cpu_to_le32(BT_COEX_NW); - - bt_cmd->valid_bit_msk = - cpu_to_le32(BT_VALID_ENABLE | BT_VALID_REDUCED_TX_POWER); - bt_cmd->bt_reduced_tx_power = sta_id; + value = mvmsta->sta_id; if (enable) - bt_cmd->bt_reduced_tx_power |= BT_REDUCED_TX_POWER_BIT; + value |= BT_REDUCED_TX_POWER_BIT; IWL_DEBUG_COEX(mvm, "%sable reduced Tx Power for sta %d\n", enable ? "en" : "dis", sta_id); + cmd.reduced_txp = cpu_to_le32(value); mvmsta->bt_reduced_txpower = enable; - ret = iwl_mvm_send_cmd(mvm, &cmd); + ret = iwl_mvm_send_cmd_pdu(mvm, BT_COEX_UPDATE_REDUCED_TXP, CMD_ASYNC, + sizeof(cmd), &cmd); - kfree(bt_cmd); return ret; } struct iwl_bt_iterator_data { struct iwl_bt_coex_profile_notif *notif; struct iwl_mvm *mvm; - u32 num_bss_ifaces; - bool reduced_tx_power; struct ieee80211_chanctx_conf *primary; struct ieee80211_chanctx_conf *secondary; bool primary_ll; @@ -780,9 +743,9 @@ void iwl_mvm_bt_coex_enable_rssi_event(struct iwl_mvm *mvm, mvmvif->bf_data.last_bt_coex_event = rssi; mvmvif->bf_data.bt_coex_max_thold = - enable ? BT_ENABLE_REDUCED_TXPOWER_THRESHOLD : 0; + enable ? -IWL_MVM_BT_COEX_EN_RED_TXP_THRESH : 0; mvmvif->bf_data.bt_coex_min_thold = - enable ? BT_DISABLE_REDUCED_TXPOWER_THRESHOLD : 0; + enable ? -IWL_MVM_BT_COEX_DIS_RED_TXP_THRESH : 0; } /* must be called under rcu_read_lock */ @@ -801,22 +764,12 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac, switch (vif->type) { case NL80211_IFTYPE_STATION: - /* Count BSSes vifs */ - data->num_bss_ifaces++; /* default smps_mode for BSS / P2P client is AUTOMATIC */ smps_mode = IEEE80211_SMPS_AUTOMATIC; break; case NL80211_IFTYPE_AP: - /* default smps_mode for AP / GO is OFF */ - smps_mode = IEEE80211_SMPS_OFF; - if (!mvmvif->ap_ibss_active) { - iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX, - smps_mode); + if (!mvmvif->ap_ibss_active) return; - } - - /* the Ack / Cts kill mask must be default if AP / GO */ - data->reduced_tx_power = false; break; default: return; @@ -827,11 +780,10 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac, /* If channel context is invalid or not on 2.4GHz .. */ if ((!chanctx_conf || chanctx_conf->def.chan->band != IEEE80211_BAND_2GHZ)) { - /* ... relax constraints and disable rssi events */ - iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX, - smps_mode); - data->reduced_tx_power = false; if (vif->type == NL80211_IFTYPE_STATION) { + /* ... relax constraints and disable rssi events */ + iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX, + smps_mode); iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, false); iwl_mvm_bt_coex_enable_rssi_event(mvm, vif, false, 0); @@ -843,20 +795,23 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac, if (bt_activity_grading >= BT_HIGH_TRAFFIC) smps_mode = IEEE80211_SMPS_STATIC; else if (bt_activity_grading >= BT_LOW_TRAFFIC) - smps_mode = vif->type == NL80211_IFTYPE_AP ? - IEEE80211_SMPS_OFF : - IEEE80211_SMPS_DYNAMIC; + smps_mode = IEEE80211_SMPS_DYNAMIC; /* relax SMPS contraints for next association */ if (!vif->bss_conf.assoc) smps_mode = IEEE80211_SMPS_AUTOMATIC; + if (IWL_COEX_IS_RRC_ON(mvm->last_bt_notif.ttc_rrc_status, + mvmvif->phy_ctxt->id)) + smps_mode = IEEE80211_SMPS_AUTOMATIC; + IWL_DEBUG_COEX(data->mvm, - "mac %d: bt_status %d bt_activity_grading %d smps_req %d\n", - mvmvif->id, data->notif->bt_status, bt_activity_grading, - smps_mode); + "mac %d: bt_activity_grading %d smps_req %d\n", + mvmvif->id, bt_activity_grading, smps_mode); - iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX, smps_mode); + if (vif->type == NL80211_IFTYPE_STATION) + iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX, + smps_mode); /* low latency is always primary */ if (iwl_mvm_vif_low_latency(mvmvif)) { @@ -906,8 +861,7 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac, */ if (iwl_get_coex_type(mvm, vif) == BT_COEX_LOOSE_LUT || mvm->cfg->bt_shared_single_ant || !vif->bss_conf.assoc || - !data->notif->bt_status) { - data->reduced_tx_power = false; + le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) == BT_OFF) { iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, false); iwl_mvm_bt_coex_enable_rssi_event(mvm, vif, false, 0); return; @@ -919,26 +873,12 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac, /* if the RSSI isn't valid, fake it is very low */ if (!ave_rssi) ave_rssi = -100; - if (ave_rssi > BT_ENABLE_REDUCED_TXPOWER_THRESHOLD) { + if (ave_rssi > -IWL_MVM_BT_COEX_EN_RED_TXP_THRESH) { if (iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, true)) IWL_ERR(mvm, "Couldn't send BT_CONFIG cmd\n"); - - /* - * bt_kill_msk can be BT_KILL_MSK_REDUCED_TXPOW only if all the - * BSS / P2P clients have rssi above threshold. - * We set the bt_kill_msk to BT_KILL_MSK_REDUCED_TXPOW before - * the iteration, if one interface's rssi isn't good enough, - * bt_kill_msk will be set to default values. - */ - } else if (ave_rssi < BT_DISABLE_REDUCED_TXPOWER_THRESHOLD) { + } else if (ave_rssi < -IWL_MVM_BT_COEX_DIS_RED_TXP_THRESH) { if (iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, false)) IWL_ERR(mvm, "Couldn't send BT_CONFIG cmd\n"); - - /* - * One interface hasn't rssi above threshold, bt_kill_msk must - * be set to default values. - */ - data->reduced_tx_power = false; } /* Begin to monitor the RSSI: it may influence the reduced Tx power */ @@ -950,11 +890,14 @@ static void iwl_mvm_bt_coex_notif_handle(struct iwl_mvm *mvm) struct iwl_bt_iterator_data data = { .mvm = mvm, .notif = &mvm->last_bt_notif, - .reduced_tx_power = true, }; struct iwl_bt_coex_ci_cmd cmd = {}; u8 ci_bw_idx; + /* Ignore updates if we are in force mode */ + if (unlikely(mvm->bt_force_ant_mode != BT_FORCE_ANT_DIS)) + return; + rcu_read_lock(); ieee80211_iterate_active_interfaces_atomic( mvm->hw, IEEE80211_IFACE_ITER_NORMAL, @@ -969,9 +912,7 @@ static void iwl_mvm_bt_coex_notif_handle(struct iwl_mvm *mvm) if (chan->def.width < NL80211_CHAN_WIDTH_40) { ci_bw_idx = 0; - cmd.co_run_bw_primary = 0; } else { - cmd.co_run_bw_primary = 1; if (chan->def.center_freq1 > chan->def.chan->center_freq) ci_bw_idx = 2; @@ -981,7 +922,8 @@ static void iwl_mvm_bt_coex_notif_handle(struct iwl_mvm *mvm) cmd.bt_primary_ci = iwl_ci_mask[chan->def.chan->hw_value][ci_bw_idx]; - cmd.primary_ch_phy_id = *((u16 *)data.primary->drv_priv); + cmd.primary_ch_phy_id = + cpu_to_le32(*((u16 *)data.primary->drv_priv)); } if (data.secondary) { @@ -993,9 +935,7 @@ static void iwl_mvm_bt_coex_notif_handle(struct iwl_mvm *mvm) if (chan->def.width < NL80211_CHAN_WIDTH_40) { ci_bw_idx = 0; - cmd.co_run_bw_secondary = 0; } else { - cmd.co_run_bw_secondary = 1; if (chan->def.center_freq1 > chan->def.chan->center_freq) ci_bw_idx = 2; @@ -1005,7 +945,8 @@ static void iwl_mvm_bt_coex_notif_handle(struct iwl_mvm *mvm) cmd.bt_secondary_ci = iwl_ci_mask[chan->def.chan->hw_value][ci_bw_idx]; - cmd.secondary_ch_phy_id = *((u16 *)data.secondary->drv_priv); + cmd.secondary_ch_phy_id = + cpu_to_le32(*((u16 *)data.secondary->drv_priv)); } rcu_read_unlock(); @@ -1018,14 +959,7 @@ static void iwl_mvm_bt_coex_notif_handle(struct iwl_mvm *mvm) memcpy(&mvm->last_bt_ci_cmd, &cmd, sizeof(cmd)); } - /* - * If there are no BSS / P2P client interfaces, reduced Tx Power is - * irrelevant since it is based on the RSSI coming from the beacon. - * Use BT_KILL_MSK_DEFAULT in that case. - */ - data.reduced_tx_power = data.reduced_tx_power && data.num_bss_ifaces; - - if (iwl_mvm_bt_udpate_ctrl_kill_msk(mvm, data.reduced_tx_power)) + if (iwl_mvm_bt_udpate_sw_boost(mvm)) IWL_ERR(mvm, "Failed to update the ctrl_kill_msk\n"); } @@ -1036,11 +970,10 @@ int iwl_mvm_rx_bt_coex_notif(struct iwl_mvm *mvm, struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_bt_coex_profile_notif *notif = (void *)pkt->data; + if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BT_COEX_SPLIT)) + return iwl_mvm_rx_bt_coex_notif_old(mvm, rxb, dev_cmd); IWL_DEBUG_COEX(mvm, "BT Coex Notification received\n"); - IWL_DEBUG_COEX(mvm, "\tBT status: %s\n", - notif->bt_status ? "ON" : "OFF"); - IWL_DEBUG_COEX(mvm, "\tBT open conn %d\n", notif->bt_open_conn); IWL_DEBUG_COEX(mvm, "\tBT ci compliance %d\n", notif->bt_ci_compliance); IWL_DEBUG_COEX(mvm, "\tBT primary_ch_lut %d\n", le32_to_cpu(notif->primary_ch_lut)); @@ -1048,8 +981,6 @@ int iwl_mvm_rx_bt_coex_notif(struct iwl_mvm *mvm, le32_to_cpu(notif->secondary_ch_lut)); IWL_DEBUG_COEX(mvm, "\tBT activity grading %d\n", le32_to_cpu(notif->bt_activity_grading)); - IWL_DEBUG_COEX(mvm, "\tBT agg traffic load %d\n", - notif->bt_agg_traffic_load); /* remember this notification for future use: rssi fluctuations */ memcpy(&mvm->last_bt_notif, notif, sizeof(mvm->last_bt_notif)); @@ -1097,16 +1028,6 @@ static void iwl_mvm_bt_rssi_iterator(void *_data, u8 *mac, return; mvmsta = iwl_mvm_sta_from_mac80211(sta); - - data->num_bss_ifaces++; - - /* - * This interface doesn't support reduced Tx power (because of low - * RSSI probably), then set bt_kill_msk to default values. - */ - if (!mvmsta->bt_reduced_txpower) - data->reduced_tx_power = false; - /* else - possibly leave it to BT_KILL_MSK_REDUCED_TXPOW */ } void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif, @@ -1115,12 +1036,20 @@ void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct iwl_mvm_vif *mvmvif = (void *)vif->drv_priv; struct iwl_bt_iterator_data data = { .mvm = mvm, - .reduced_tx_power = true, }; int ret; + if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BT_COEX_SPLIT)) { + iwl_mvm_bt_rssi_event_old(mvm, vif, rssi_event); + return; + } + lockdep_assert_held(&mvm->mutex); + /* Ignore updates if we are in force mode */ + if (unlikely(mvm->bt_force_ant_mode != BT_FORCE_ANT_DIS)) + return; + /* * Rssi update while not associated - can happen since the statistics * are handled asynchronously @@ -1129,7 +1058,7 @@ void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif, return; /* No BT - reports should be disabled */ - if (!mvm->last_bt_notif.bt_status) + if (le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) == BT_OFF) return; IWL_DEBUG_COEX(mvm, "RSSI for %pM is now %s\n", vif->bss_conf.bssid, @@ -1153,14 +1082,7 @@ void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif, mvm->hw, IEEE80211_IFACE_ITER_NORMAL, iwl_mvm_bt_rssi_iterator, &data); - /* - * If there are no BSS / P2P client interfaces, reduced Tx Power is - * irrelevant since it is based on the RSSI coming from the beacon. - * Use BT_KILL_MSK_DEFAULT in that case. - */ - data.reduced_tx_power = data.reduced_tx_power && data.num_bss_ifaces; - - if (iwl_mvm_bt_udpate_ctrl_kill_msk(mvm, data.reduced_tx_power)) + if (iwl_mvm_bt_udpate_sw_boost(mvm)) IWL_ERR(mvm, "Failed to update the ctrl_kill_msk\n"); } @@ -1171,15 +1093,23 @@ u16 iwl_mvm_coex_agg_time_limit(struct iwl_mvm *mvm, struct ieee80211_sta *sta) { struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(mvmsta->vif); + struct iwl_mvm_phy_ctxt *phy_ctxt = mvmvif->phy_ctxt; enum iwl_bt_coex_lut_type lut_type; + if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BT_COEX_SPLIT)) + return iwl_mvm_coex_agg_time_limit_old(mvm, sta); + + if (IWL_COEX_IS_TTC_ON(mvm->last_bt_notif.ttc_rrc_status, phy_ctxt->id)) + return LINK_QUAL_AGG_TIME_LIMIT_DEF; + if (le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) < BT_HIGH_TRAFFIC) return LINK_QUAL_AGG_TIME_LIMIT_DEF; lut_type = iwl_get_coex_type(mvm, mvmsta->vif); - if (lut_type == BT_COEX_LOOSE_LUT) + if (lut_type == BT_COEX_LOOSE_LUT || lut_type == BT_COEX_INVALID_LUT) return LINK_QUAL_AGG_TIME_LIMIT_DEF; /* tight coex, high bt traffic, reduce AGG time limit */ @@ -1190,18 +1120,37 @@ bool iwl_mvm_bt_coex_is_mimo_allowed(struct iwl_mvm *mvm, struct ieee80211_sta *sta) { struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(mvmsta->vif); + struct iwl_mvm_phy_ctxt *phy_ctxt = mvmvif->phy_ctxt; + enum iwl_bt_coex_lut_type lut_type; + + if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BT_COEX_SPLIT)) + return iwl_mvm_bt_coex_is_mimo_allowed_old(mvm, sta); + + if (IWL_COEX_IS_TTC_ON(mvm->last_bt_notif.ttc_rrc_status, phy_ctxt->id)) + return true; if (le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) < BT_HIGH_TRAFFIC) return true; /* - * In Tight, BT can't Rx while we Tx, so use both antennas since BT is - * already killed. - * In Loose, BT can Rx while we Tx, so forbid MIMO to let BT Rx while we - * Tx. + * In Tight / TxTxDis, BT can't Rx while we Tx, so use both antennas + * since BT is already killed. + * In Loose, BT can Rx while we Tx, so forbid MIMO to let BT Rx while + * we Tx. + * When we are in 5GHz, we'll get BT_COEX_INVALID_LUT allowing MIMO. */ - return iwl_get_coex_type(mvm, mvmsta->vif) == BT_COEX_TIGHT_LUT; + lut_type = iwl_get_coex_type(mvm, mvmsta->vif); + return lut_type != BT_COEX_LOOSE_LUT; +} + +bool iwl_mvm_bt_coex_is_shared_ant_avail(struct iwl_mvm *mvm) +{ + if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BT_COEX_SPLIT)) + return iwl_mvm_bt_coex_is_shared_ant_avail_old(mvm); + + return le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) == BT_OFF; } bool iwl_mvm_bt_coex_is_tpc_allowed(struct iwl_mvm *mvm, @@ -1209,6 +1158,9 @@ bool iwl_mvm_bt_coex_is_tpc_allowed(struct iwl_mvm *mvm, { u32 bt_activity = le32_to_cpu(mvm->last_bt_notif.bt_activity_grading); + if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BT_COEX_SPLIT)) + return iwl_mvm_bt_coex_is_tpc_allowed_old(mvm, band); + if (band != IEEE80211_BAND_2GHZ) return false; @@ -1249,6 +1201,11 @@ u8 iwl_mvm_bt_coex_tx_prio(struct iwl_mvm *mvm, struct ieee80211_hdr *hdr, void iwl_mvm_bt_coex_vif_change(struct iwl_mvm *mvm) { + if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BT_COEX_SPLIT)) { + iwl_mvm_bt_coex_vif_change_old(mvm); + return; + } + iwl_mvm_bt_coex_notif_handle(mvm); } @@ -1258,22 +1215,22 @@ int iwl_mvm_rx_ant_coupling_notif(struct iwl_mvm *mvm, { struct iwl_rx_packet *pkt = rxb_addr(rxb); u32 ant_isolation = le32_to_cpup((void *)pkt->data); + struct iwl_bt_coex_corun_lut_update_cmd cmd = {}; u8 __maybe_unused lower_bound, upper_bound; - int ret; u8 lut; - struct iwl_bt_coex_cmd *bt_cmd; - struct iwl_host_cmd cmd = { - .id = BT_CONFIG, - .len = { sizeof(*bt_cmd), }, - .dataflags = { IWL_HCMD_DFL_NOCOPY, }, - }; + if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BT_COEX_SPLIT)) + return iwl_mvm_rx_ant_coupling_notif_old(mvm, rxb, dev_cmd); if (!IWL_MVM_BT_COEX_CORUNNING) return 0; lockdep_assert_held(&mvm->mutex); + /* Ignore updates if we are in force mode */ + if (unlikely(mvm->bt_force_ant_mode != BT_FORCE_ANT_DIS)) + return 0; + if (ant_isolation == mvm->last_ant_isol) return 0; @@ -1298,25 +1255,13 @@ int iwl_mvm_rx_ant_coupling_notif(struct iwl_mvm *mvm, mvm->last_corun_lut = lut; - bt_cmd = kzalloc(sizeof(*bt_cmd), GFP_KERNEL); - if (!bt_cmd) - return 0; - cmd.data[0] = bt_cmd; - - bt_cmd->flags = cpu_to_le32(BT_COEX_NW); - bt_cmd->valid_bit_msk |= cpu_to_le32(BT_VALID_ENABLE | - BT_VALID_CORUN_LUT_20 | - BT_VALID_CORUN_LUT_40); - /* For the moment, use the same LUT for 20GHz and 40GHz */ - memcpy(bt_cmd->bt4_corun_lut20, antenna_coupling_ranges[lut].lut20, - sizeof(bt_cmd->bt4_corun_lut20)); + memcpy(&cmd.corun_lut20, antenna_coupling_ranges[lut].lut20, + sizeof(cmd.corun_lut20)); - memcpy(bt_cmd->bt4_corun_lut40, antenna_coupling_ranges[lut].lut20, - sizeof(bt_cmd->bt4_corun_lut40)); + memcpy(&cmd.corun_lut40, antenna_coupling_ranges[lut].lut20, + sizeof(cmd.corun_lut40)); - ret = iwl_mvm_send_cmd(mvm, &cmd); - - kfree(bt_cmd); - return ret; + return iwl_mvm_send_cmd_pdu(mvm, BT_COEX_UPDATE_CORUN_LUT, 0, + sizeof(cmd), &cmd); } |