@@ -784,8 +784,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;
@@ -591,7 +591,7 @@ static void iwl_init_vht_hw_capab(struct iwl_trans *trans,
cpu_to_le16(IEEE80211_VHT_EXT_NSS_BW_CAPABLE);
}
-static struct ieee80211_sband_iftype_data iwl_he_capa[] = {
+static const struct ieee80211_sband_iftype_data iwl_he_capa_const[] = {
{
.types_mask = BIT(NL80211_IFTYPE_STATION),
.he_cap = {
@@ -754,31 +754,62 @@ static struct ieee80211_sband_iftype_data iwl_he_capa[] = {
},
};
+static struct ieee80211_sband_iftype_data iwl_he_capa_cur[2];
+
static void iwl_init_he_hw_capab(struct iwl_trans *trans,
struct iwl_nvm_data *data,
struct ieee80211_supported_band *sband,
u8 tx_chains, u8 rx_chains)
{
- sband->iftype_data = iwl_he_capa;
- sband->n_iftype_data = ARRAY_SIZE(iwl_he_capa);
-
- /* If not 2x2, we need to indicate 1x1 in the Midamble RX Max NSTS */
- if ((tx_chains & rx_chains) != ANT_AB) {
- int i;
-
- for (i = 0; i < sband->n_iftype_data; i++) {
- iwl_he_capa[i].he_cap.he_cap_elem.phy_cap_info[1] &=
- ~IEEE80211_HE_PHY_CAP1_MIDAMBLE_RX_TX_MAX_NSTS;
- iwl_he_capa[i].he_cap.he_cap_elem.phy_cap_info[2] &=
- ~IEEE80211_HE_PHY_CAP2_MIDAMBLE_RX_TX_MAX_NSTS;
- iwl_he_capa[i].he_cap.he_cap_elem.phy_cap_info[7] &=
- ~IEEE80211_HE_PHY_CAP7_MAX_NC_MASK;
- }
+ int i;
+
+ BUILD_BUG_ON(sizeof(iwl_he_capa_cur) != sizeof(iwl_he_capa_const));
+ memcpy(iwl_he_capa_cur, iwl_he_capa_const, sizeof(iwl_he_capa_cur));
+
+ sband->iftype_data = iwl_he_capa_cur;
+ sband->n_iftype_data = ARRAY_SIZE(iwl_he_capa_cur);
+
+ if ((tx_chains & rx_chains) == ANT_AB)
+ return;
+
+ for (i = 0; i < sband->n_iftype_data; i++) {
+ /* If not 2x2, we need to indicate 1x1 in the Midamble RX Max NSTS */
+ iwl_he_capa_cur[i].he_cap.he_cap_elem.phy_cap_info[1] &=
+ ~IEEE80211_HE_PHY_CAP1_MIDAMBLE_RX_TX_MAX_NSTS;
+ iwl_he_capa_cur[i].he_cap.he_cap_elem.phy_cap_info[2] &=
+ ~IEEE80211_HE_PHY_CAP2_MIDAMBLE_RX_TX_MAX_NSTS;
+ iwl_he_capa_cur[i].he_cap.he_cap_elem.phy_cap_info[7] &=
+ ~IEEE80211_HE_PHY_CAP7_MAX_NC_MASK;
+
+ /*
+ * 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
+ */
+ iwl_he_capa_cur[i].he_cap.he_mcs_nss_supp.rx_mcs_80 |=
+ cpu_to_le16(IEEE80211_HE_MCS_NOT_SUPPORTED << 2);
+ iwl_he_capa_cur[i].he_cap.he_mcs_nss_supp.tx_mcs_80 |=
+ cpu_to_le16(IEEE80211_HE_MCS_NOT_SUPPORTED << 2);
+ iwl_he_capa_cur[i].he_cap.he_mcs_nss_supp.rx_mcs_160 |=
+ cpu_to_le16(IEEE80211_HE_MCS_NOT_SUPPORTED << 2);
+ iwl_he_capa_cur[i].he_cap.he_mcs_nss_supp.tx_mcs_160 |=
+ cpu_to_le16(IEEE80211_HE_MCS_NOT_SUPPORTED << 2);
+ iwl_he_capa_cur[i].he_cap.he_mcs_nss_supp.rx_mcs_80p80 |=
+ cpu_to_le16(IEEE80211_HE_MCS_NOT_SUPPORTED << 2);
+ iwl_he_capa_cur[i].he_cap.he_mcs_nss_supp.tx_mcs_80p80 |=
+ cpu_to_le16(IEEE80211_HE_MCS_NOT_SUPPORTED << 2);
+
+
#ifdef CONFIG_IWLWIFI_SUPPORT_DEBUG_OVERRIDES
if (trans->dbg_cfg.ampdu_exponent_p1) {
/* Use whatever is set in the VHT element. */
- iwl_he_capa[i].he_cap.he_cap_elem.mac_cap_info[3] &= ~IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_MASK;
- iwl_he_capa[i].he_cap.he_cap_elem.mac_cap_info[3] |= IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_USE_VHT;
+ iwl_he_capa_cur[i].he_cap.he_cap_elem.mac_cap_info[3] &=
+ ~IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_MASK;
+ iwl_he_capa_cur[i].he_cap.he_cap_elem.mac_cap_info[3] |=
+ IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_USE_VHT;
}
#endif
}
@@ -797,14 +828,14 @@ static bool iwl_he_mcs_greater(u16 a, u16 b)
return false;
}
-static void iwl_init_he_override(struct iwl_trans *trans,
- struct ieee80211_supported_band *sband)
+void iwl_init_he_override(struct iwl_trans *trans,
+ struct ieee80211_supported_band *sband)
{
struct ieee80211_sband_iftype_data *iftype_data;
int i;
- for (i = 0; i < ARRAY_SIZE(iwl_he_capa); i++) {
- iftype_data = &iwl_he_capa[i];
+ for (i = 0; i < ARRAY_SIZE(iwl_he_capa_cur); i++) {
+ iftype_data = &iwl_he_capa_cur[i];
if (trans->dbg_cfg.rx_mcs_80) {
if (iwl_he_mcs_greater(trans->dbg_cfg.rx_mcs_80,
@@ -847,30 +878,6 @@ static void iwl_init_he_override(struct iwl_trans *trans,
cpu_to_le16(trans->dbg_cfg.tx_mcs_160);
}
- /*
- * 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
- */
- if (trans->dbg_cfg.valid_ants &&
- (trans->dbg_cfg.valid_ants & ANT_AB) != ANT_AB) {
- 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->dbg_cfg.no_ldpc)
iftype_data->he_cap.he_cap_elem.phy_cap_info[1] &=
~IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD;
@@ -926,10 +933,51 @@ static void iwl_init_he_override(struct iwl_trans *trans,
}
#endif
-static void iwl_init_sbands(struct iwl_trans *trans,
- struct iwl_nvm_data *data,
- const void *nvm_ch_flags, u8 tx_chains,
- u8 rx_chains, u32 sbands_flags, bool v4)
+void iwl_reinit_capab(struct iwl_trans *trans,
+ struct iwl_nvm_data *data,
+ u8 tx_chains, u8 rx_chains) {
+ 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);
+#ifdef CONFIG_IWLWIFI_SUPPORT_DEBUG_OVERRIDES
+ iwl_init_he_override(trans, sband);
+#endif
+ }
+ 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);
+
+#ifdef CONFIG_IWLWIFI_SUPPORT_DEBUG_OVERRIDES
+ iwl_init_he_override(trans, sband);
+#endif
+ }
+ else {
+ sband->iftype_data = NULL;
+ }
+}
+IWL_EXPORT_SYMBOL(iwl_reinit_capab);
+
+void iwl_init_sbands(struct iwl_trans *trans,
+ struct iwl_nvm_data *data,
+ const void *nvm_ch_flags, u8 tx_chains,
+ u8 rx_chains, u32 sbands_flags, bool v4)
{
struct device *dev = trans->dev;
const struct iwl_cfg *cfg = trans->cfg;
@@ -135,4 +135,15 @@ void iwl_nvm_fixups(u32 hw_id, unsigned int section, u8 *data,
*/
struct iwl_nvm_data *iwl_get_nvm(struct iwl_trans *trans,
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);
+
#endif /* __iwl_nvm_parse_h__ */
@@ -370,6 +370,13 @@ iwl_mvm_op_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant)
return 0;
}
+static 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;
@@ -5247,6 +5254,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,
@@ -1574,6 +1574,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);
@@ -208,6 +208,23 @@ static const u8 fw_rate_idx_to_plcp[IWL_RATE_COUNT] = {
IWL_DECLARE_RATE_INFO(54),
};
+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);
+
+ 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)
{