@@ -83,8 +83,13 @@ void iwl_init_ht_hw_capab(struct iwl_trans *trans,
ht_info->mcs.rx_mask[0] = 0xFF;
if (rx_chains >= 2)
ht_info->mcs.rx_mask[1] = 0xFF;
+ else
+ ht_info->mcs.rx_mask[1] = 0;
+
if (rx_chains >= 3)
ht_info->mcs.rx_mask[2] = 0xFF;
+ else
+ ht_info->mcs.rx_mask[2] = 0;
if (cfg->ht_params->ht_greenfield_support)
ht_info->cap |= IEEE80211_HT_CAP_GRN_FLD;
@@ -964,6 +964,12 @@ iwl_nvm_fixup_sband_iftd(struct iwl_trans *trans,
iftype_data->eht_cap.eht_cap_elem.phy_cap_info[4] |= 0x10;
}
}
+ if (iftype_data->eht_cap.has_eht) {
+ struct ieee80211_eht_mcs_nss_supp *mcs_nss =
+ &iftype_data->eht_cap.eht_mcs_nss_supp;
+
+ memset(mcs_nss, 0x22, sizeof(*mcs_nss));
+ }
} else {
if (iftype_data->eht_cap.has_eht) {
struct ieee80211_eht_mcs_nss_supp *mcs_nss =
@@ -983,6 +989,26 @@ iwl_nvm_fixup_sband_iftd(struct iwl_trans *trans,
iftype_data->he_cap.he_cap_elem.phy_cap_info[7] |=
IEEE80211_HE_PHY_CAP7_MAX_NC_1;
}
+
+ /* If antennas were forced - make sure not declaring MIMO when
+ * we actually are SISO
+ * Recall that there are 2 bits per stream in the "HE Tx/Rx HE
+ * MCS NSS Support Field", so if some antenna is forced on but
+ * not both A and B - we should work in SISO mode, so mark the
+ * 2nd SS as not supported
+ */
+ iftype_data->he_cap.he_mcs_nss_supp.rx_mcs_80 |=
+ cpu_to_le16(IEEE80211_HE_MCS_NOT_SUPPORTED << 2);
+ iftype_data->he_cap.he_mcs_nss_supp.tx_mcs_80 |=
+ cpu_to_le16(IEEE80211_HE_MCS_NOT_SUPPORTED << 2);
+ iftype_data->he_cap.he_mcs_nss_supp.rx_mcs_160 |=
+ cpu_to_le16(IEEE80211_HE_MCS_NOT_SUPPORTED << 2);
+ iftype_data->he_cap.he_mcs_nss_supp.tx_mcs_160 |=
+ cpu_to_le16(IEEE80211_HE_MCS_NOT_SUPPORTED << 2);
+ iftype_data->he_cap.he_mcs_nss_supp.rx_mcs_80p80 |=
+ cpu_to_le16(IEEE80211_HE_MCS_NOT_SUPPORTED << 2);
+ iftype_data->he_cap.he_mcs_nss_supp.tx_mcs_80p80 |=
+ cpu_to_le16(IEEE80211_HE_MCS_NOT_SUPPORTED << 2);
}
if (trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_AX210 && !is_ap)
@@ -1058,10 +1084,6 @@ static void iwl_init_he_hw_capab(struct iwl_trans *trans,
struct ieee80211_sband_iftype_data *iftype_data;
int i;
- /* should only initialize once */
- if (WARN_ON(sband->iftype_data))
- return;
-
BUILD_BUG_ON(sizeof(data->iftd.low) != sizeof(iwl_he_eht_capa));
BUILD_BUG_ON(sizeof(data->iftd.high) != sizeof(iwl_he_eht_capa));
BUILD_BUG_ON(sizeof(data->iftd.uhb) != sizeof(iwl_he_eht_capa));
@@ -1244,6 +1266,8 @@ static void iwl_init_eht_band_override(struct iwl_trans *trans,
int i;
for (i = 0; i < sband->n_iftype_data; i++) {
+ struct ieee80211_eht_mcs_nss_supp *mcs_nss;
+
/* we know it's writable - we set it before ourselves */
iftype_data = (void *)(uintptr_t)&sband->iftype_data[i];
@@ -1251,16 +1275,16 @@ static void iwl_init_eht_band_override(struct iwl_trans *trans,
if (!iftype_data->eht_cap.has_eht)
continue;
+ mcs_nss = &iftype_data->eht_cap.eht_mcs_nss_supp;
if (trans->dbg_cfg.valid_ants &&
(trans->dbg_cfg.valid_ants & ANT_AB) != ANT_AB) {
/* For all MCS and bandwidth, set 1 NSS for both Tx and
* Rx - note we don't set the only_20mhz, but due to this
* being a union, it gets set correctly anyway.
*/
- struct ieee80211_eht_mcs_nss_supp *mcs_nss =
- &iftype_data->eht_cap.eht_mcs_nss_supp;
-
memset(mcs_nss, 0x11, sizeof(*mcs_nss));
+ } else {
+ memset(mcs_nss, 0x22, sizeof(*mcs_nss));
}
IWL_COPY_BIN(eht_ppe_thres, eht_cap.eht_ppe_thres);
@@ -1302,6 +1326,45 @@ static void iwl_init_he_eht_override(struct iwl_trans *trans,
}
#endif
+/* This is a subsection of the logic in iwl_init_bands */
+void iwl_reinit_capab(struct iwl_trans *trans,
+ struct iwl_nvm_data *data,
+ u8 tx_chains, u8 rx_chains, const struct iwl_fw *fw)
+{
+ struct ieee80211_supported_band *sband;
+
+ sband = &data->bands[NL80211_BAND_2GHZ];
+ iwl_init_ht_hw_capab(trans, data, &sband->ht_cap, NL80211_BAND_2GHZ,
+ tx_chains, rx_chains);
+
+ if (data->sku_cap_11ax_enable && !iwlwifi_mod_params.disable_11ax)
+ iwl_init_he_hw_capab(trans, data, sband, tx_chains, rx_chains, fw);
+ else
+ sband->iftype_data = NULL;
+
+ sband = &data->bands[NL80211_BAND_5GHZ];
+ iwl_init_ht_hw_capab(trans, data, &sband->ht_cap, NL80211_BAND_5GHZ,
+ tx_chains, rx_chains);
+ if (data->sku_cap_11ac_enable && !iwlwifi_mod_params.disable_11ac)
+ iwl_init_vht_hw_capab(trans, data, &sband->vht_cap,
+ tx_chains, rx_chains);
+ else
+ sband->vht_cap.vht_supported = false;
+
+ if (data->sku_cap_11ax_enable && !iwlwifi_mod_params.disable_11ax)
+ iwl_init_he_hw_capab(trans, data, sband, tx_chains, rx_chains, fw);
+ else
+ sband->iftype_data = NULL;
+
+ sband = &data->bands[NL80211_BAND_6GHZ];
+
+ if (data->sku_cap_11ax_enable && !iwlwifi_mod_params.disable_11ax)
+ iwl_init_he_hw_capab(trans, data, sband, tx_chains, rx_chains, fw);
+ else
+ sband->iftype_data = NULL;
+}
+IWL_EXPORT_SYMBOL(iwl_reinit_capab);
+
static void iwl_init_sbands(struct iwl_trans *trans,
struct iwl_nvm_data *data,
const void *nvm_ch_flags, u8 tx_chains,
@@ -90,4 +90,14 @@ iwl_parse_mei_nvm_data(struct iwl_trans *trans, const struct iwl_cfg *cfg,
const struct iwl_mei_nvm *mei_nvm,
const struct iwl_fw *fw);
+/**
+ * iwl_reinit_capab - Re-initialize the current HT, VHT and/or HE capabilities
+ *
+ * This should be called when changing values that affect the capabilities, such
+ * as number of spatial streams.
+ */
+void iwl_reinit_capab(struct iwl_trans *trans,
+ struct iwl_nvm_data *data,
+ u8 tx_chains, u8 rx_chains, const struct iwl_fw *fw);
+
#endif /* __iwl_nvm_parse_h__ */
@@ -319,6 +319,14 @@ int iwl_mvm_op_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant)
return 0;
}
+int
+iwl_mvm_op_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant)
+{
+ struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+
+ return iwl_mvm_set_valid_ant(mvm, tx_ant, rx_ant);
+}
+
int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
{
struct ieee80211_hw *hw = mvm->hw;
@@ -6443,6 +6451,7 @@ const struct ieee80211_ops iwl_mvm_hw_ops = {
.wake_tx_queue = iwl_mvm_mac_wake_tx_queue,
.ampdu_action = iwl_mvm_mac_ampdu_action,
.get_antenna = iwl_mvm_op_get_antenna,
+ .set_antenna = iwl_mvm_op_set_antenna,
.start = iwl_mvm_mac_start,
.reconfig_complete = iwl_mvm_mac_reconfig_complete,
.stop = iwl_mvm_mac_stop,
@@ -1164,6 +1164,7 @@ const struct ieee80211_ops iwl_mvm_mld_hw_ops = {
.wake_tx_queue = iwl_mvm_mac_wake_tx_queue,
.ampdu_action = iwl_mvm_mac_ampdu_action,
.get_antenna = iwl_mvm_op_get_antenna,
+ .set_antenna = iwl_mvm_op_set_antenna,
.start = iwl_mvm_mac_start,
.reconfig_complete = iwl_mvm_mac_reconfig_complete,
.stop = iwl_mvm_mac_stop,
@@ -1779,6 +1779,8 @@ static inline u8 iwl_mvm_get_valid_rx_ant(struct iwl_mvm *mvm)
mvm->fw->valid_rx_ant;
}
+int iwl_mvm_set_valid_ant(struct iwl_mvm *mvm, u32 tx_ant, u32 rx_ant);
+
static inline void iwl_mvm_toggle_tx_ant(struct iwl_mvm *mvm, u8 *ant)
{
*ant = iwl_mvm_next_antenna(mvm, iwl_mvm_get_valid_tx_ant(mvm), *ant);
@@ -2694,6 +2696,7 @@ int iwl_mvm_mac_ampdu_action(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_ampdu_params *params);
int iwl_mvm_op_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant);
+int iwl_mvm_op_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant);
int iwl_mvm_mac_start(struct ieee80211_hw *hw);
void iwl_mvm_mac_reconfig_complete(struct ieee80211_hw *hw,
enum ieee80211_reconfig_type reconfig_type);
@@ -150,6 +150,22 @@ int iwl_mvm_legacy_hw_idx_to_mac80211_idx(u32 rate_n_flags,
return is_LB ? rate : -1;
}
+int iwl_mvm_set_valid_ant(struct iwl_mvm *mvm, u32 tx_ant, u32 rx_ant)
+{
+ if (mvm->nvm_data) {
+ mvm->nvm_data->valid_rx_ant = (rx_ant & ANT_ABC);
+ mvm->nvm_data->valid_tx_ant = (tx_ant & ANT_ABC);
+
+ iwl_reinit_capab(mvm->trans, mvm->nvm_data, mvm->nvm_data->valid_tx_ant,
+ mvm->nvm_data->valid_rx_ant, mvm->fw);
+
+ return 0;
+ } else {
+ pr_err("ERROR: iwl-mvm-set-valid-ant: mvm->nvm_data is NULL\n");
+ return -EINVAL;
+ }
+}
+
int iwl_mvm_legacy_rate_to_mac80211_idx(u32 rate_n_flags,
enum nl80211_band band)
{