|
@@ -36,6 +36,7 @@
|
|
|
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
|
|
|
* Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
|
|
|
* Copyright(c) 2016 - 2017 Intel Deutschland GmbH
|
|
|
+ * Copyright(c) 2018 Intel Corporation
|
|
|
* All rights reserved.
|
|
|
*
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
@@ -914,7 +915,7 @@ static int iwl_mvm_mac_ampdu_action(struct ieee80211_hw *hw,
|
|
|
enum ieee80211_ampdu_mlme_action action = params->action;
|
|
|
u16 tid = params->tid;
|
|
|
u16 *ssn = ¶ms->ssn;
|
|
|
- u8 buf_size = params->buf_size;
|
|
|
+ u16 buf_size = params->buf_size;
|
|
|
bool amsdu = params->amsdu;
|
|
|
u16 timeout = params->timeout;
|
|
|
|
|
@@ -1897,6 +1898,194 @@ void iwl_mvm_mu_mimo_grp_notif(struct iwl_mvm *mvm,
|
|
|
iwl_mvm_mu_mimo_iface_iterator, notif);
|
|
|
}
|
|
|
|
|
|
+static u8 iwl_mvm_he_get_ppe_val(u8 *ppe, u8 ppe_pos_bit)
|
|
|
+{
|
|
|
+ u8 byte_num = ppe_pos_bit / 8;
|
|
|
+ u8 bit_num = ppe_pos_bit % 8;
|
|
|
+ u8 residue_bits;
|
|
|
+ u8 res;
|
|
|
+
|
|
|
+ if (bit_num <= 5)
|
|
|
+ return (ppe[byte_num] >> bit_num) &
|
|
|
+ (BIT(IEEE80211_PPE_THRES_INFO_PPET_SIZE) - 1);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * If bit_num > 5, we have to combine bits with next byte.
|
|
|
+ * Calculate how many bits we need to take from current byte (called
|
|
|
+ * here "residue_bits"), and add them to bits from next byte.
|
|
|
+ */
|
|
|
+
|
|
|
+ residue_bits = 8 - bit_num;
|
|
|
+
|
|
|
+ res = (ppe[byte_num + 1] &
|
|
|
+ (BIT(IEEE80211_PPE_THRES_INFO_PPET_SIZE - residue_bits) - 1)) <<
|
|
|
+ residue_bits;
|
|
|
+ res += (ppe[byte_num] >> bit_num) & (BIT(residue_bits) - 1);
|
|
|
+
|
|
|
+ return res;
|
|
|
+}
|
|
|
+
|
|
|
+static void iwl_mvm_cfg_he_sta(struct iwl_mvm *mvm,
|
|
|
+ struct ieee80211_vif *vif, u8 sta_id)
|
|
|
+{
|
|
|
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
|
|
|
+ struct iwl_he_sta_context_cmd sta_ctxt_cmd = {
|
|
|
+ .sta_id = sta_id,
|
|
|
+ .tid_limit = IWL_MAX_TID_COUNT,
|
|
|
+ .bss_color = vif->bss_conf.bss_color,
|
|
|
+ .htc_trig_based_pkt_ext = vif->bss_conf.htc_trig_based_pkt_ext,
|
|
|
+ .frame_time_rts_th =
|
|
|
+ cpu_to_le16(vif->bss_conf.frame_time_rts_th),
|
|
|
+ };
|
|
|
+ struct ieee80211_sta *sta;
|
|
|
+ u32 flags;
|
|
|
+ int i;
|
|
|
+
|
|
|
+ rcu_read_lock();
|
|
|
+
|
|
|
+ sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_ctxt_cmd.sta_id]);
|
|
|
+ if (IS_ERR(sta)) {
|
|
|
+ rcu_read_unlock();
|
|
|
+ WARN(1, "Can't find STA to configure HE\n");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!sta->he_cap.has_he) {
|
|
|
+ rcu_read_unlock();
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ flags = 0;
|
|
|
+
|
|
|
+ /* HTC flags */
|
|
|
+ if (sta->he_cap.he_cap_elem.mac_cap_info[0] &
|
|
|
+ IEEE80211_HE_MAC_CAP0_HTC_HE)
|
|
|
+ sta_ctxt_cmd.htc_flags |= cpu_to_le32(IWL_HE_HTC_SUPPORT);
|
|
|
+ if ((sta->he_cap.he_cap_elem.mac_cap_info[1] &
|
|
|
+ IEEE80211_HE_MAC_CAP1_LINK_ADAPTATION) ||
|
|
|
+ (sta->he_cap.he_cap_elem.mac_cap_info[2] &
|
|
|
+ IEEE80211_HE_MAC_CAP2_LINK_ADAPTATION)) {
|
|
|
+ u8 link_adap =
|
|
|
+ ((sta->he_cap.he_cap_elem.mac_cap_info[2] &
|
|
|
+ IEEE80211_HE_MAC_CAP2_LINK_ADAPTATION) << 1) +
|
|
|
+ (sta->he_cap.he_cap_elem.mac_cap_info[1] &
|
|
|
+ IEEE80211_HE_MAC_CAP1_LINK_ADAPTATION);
|
|
|
+
|
|
|
+ if (link_adap == 2)
|
|
|
+ sta_ctxt_cmd.htc_flags |=
|
|
|
+ cpu_to_le32(IWL_HE_HTC_LINK_ADAP_UNSOLICITED);
|
|
|
+ else if (link_adap == 3)
|
|
|
+ sta_ctxt_cmd.htc_flags |=
|
|
|
+ cpu_to_le32(IWL_HE_HTC_LINK_ADAP_BOTH);
|
|
|
+ }
|
|
|
+ if (sta->he_cap.he_cap_elem.mac_cap_info[2] &
|
|
|
+ IEEE80211_HE_MAC_CAP2_UL_MU_RESP_SCHED)
|
|
|
+ sta_ctxt_cmd.htc_flags |=
|
|
|
+ cpu_to_le32(IWL_HE_HTC_UL_MU_RESP_SCHED);
|
|
|
+ if (sta->he_cap.he_cap_elem.mac_cap_info[2] & IEEE80211_HE_MAC_CAP2_BSR)
|
|
|
+ sta_ctxt_cmd.htc_flags |= cpu_to_le32(IWL_HE_HTC_BSR_SUPP);
|
|
|
+ if (sta->he_cap.he_cap_elem.mac_cap_info[3] &
|
|
|
+ IEEE80211_HE_MAC_CAP3_OMI_CONTROL)
|
|
|
+ sta_ctxt_cmd.htc_flags |= cpu_to_le32(IWL_HE_HTC_OMI_SUPP);
|
|
|
+ if (sta->he_cap.he_cap_elem.mac_cap_info[4] & IEEE80211_HE_MAC_CAP4_BQR)
|
|
|
+ sta_ctxt_cmd.htc_flags |= cpu_to_le32(IWL_HE_HTC_BQR_SUPP);
|
|
|
+
|
|
|
+ /* If PPE Thresholds exist, parse them into a FW-familiar format */
|
|
|
+ if (sta->he_cap.he_cap_elem.phy_cap_info[6] &
|
|
|
+ IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT) {
|
|
|
+ u8 nss = (sta->he_cap.ppe_thres[0] &
|
|
|
+ IEEE80211_PPE_THRES_NSS_MASK) + 1;
|
|
|
+ u8 ru_index_bitmap =
|
|
|
+ (sta->he_cap.ppe_thres[0] &
|
|
|
+ IEEE80211_PPE_THRES_RU_INDEX_BITMASK_MASK) >>
|
|
|
+ IEEE80211_PPE_THRES_RU_INDEX_BITMASK_POS;
|
|
|
+ u8 *ppe = &sta->he_cap.ppe_thres[0];
|
|
|
+ u8 ppe_pos_bit = 7; /* Starting after PPE header */
|
|
|
+
|
|
|
+ /*
|
|
|
+ * FW currently supports only nss == MAX_HE_SUPP_NSS
|
|
|
+ *
|
|
|
+ * If nss > MAX: we can ignore values we don't support
|
|
|
+ * If nss < MAX: we can set zeros in other streams
|
|
|
+ */
|
|
|
+ if (nss > MAX_HE_SUPP_NSS) {
|
|
|
+ IWL_INFO(mvm, "Got NSS = %d - trimming to %d\n", nss,
|
|
|
+ MAX_HE_SUPP_NSS);
|
|
|
+ nss = MAX_HE_SUPP_NSS;
|
|
|
+ }
|
|
|
+
|
|
|
+ for (i = 0; i < nss; i++) {
|
|
|
+ u8 ru_index_tmp = ru_index_bitmap << 1;
|
|
|
+ u8 bw;
|
|
|
+
|
|
|
+ for (bw = 0; bw < MAX_HE_CHANNEL_BW_INDX; bw++) {
|
|
|
+ ru_index_tmp >>= 1;
|
|
|
+ if (!(ru_index_tmp & 1))
|
|
|
+ continue;
|
|
|
+
|
|
|
+ sta_ctxt_cmd.pkt_ext.pkt_ext_qam_th[i][bw][1] =
|
|
|
+ iwl_mvm_he_get_ppe_val(ppe,
|
|
|
+ ppe_pos_bit);
|
|
|
+ ppe_pos_bit +=
|
|
|
+ IEEE80211_PPE_THRES_INFO_PPET_SIZE;
|
|
|
+ sta_ctxt_cmd.pkt_ext.pkt_ext_qam_th[i][bw][0] =
|
|
|
+ iwl_mvm_he_get_ppe_val(ppe,
|
|
|
+ ppe_pos_bit);
|
|
|
+ ppe_pos_bit +=
|
|
|
+ IEEE80211_PPE_THRES_INFO_PPET_SIZE;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ flags |= STA_CTXT_HE_PACKET_EXT;
|
|
|
+ }
|
|
|
+ rcu_read_unlock();
|
|
|
+
|
|
|
+ /* Mark MU EDCA as enabled, unless none detected on some AC */
|
|
|
+ flags |= STA_CTXT_HE_MU_EDCA_CW;
|
|
|
+ for (i = 0; i < AC_NUM; i++) {
|
|
|
+ struct ieee80211_he_mu_edca_param_ac_rec *mu_edca =
|
|
|
+ &mvmvif->queue_params[i].mu_edca_param_rec;
|
|
|
+
|
|
|
+ if (!mvmvif->queue_params[i].mu_edca) {
|
|
|
+ flags &= ~STA_CTXT_HE_MU_EDCA_CW;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ sta_ctxt_cmd.trig_based_txf[i].cwmin =
|
|
|
+ cpu_to_le16(mu_edca->ecw_min_max & 0xf);
|
|
|
+ sta_ctxt_cmd.trig_based_txf[i].cwmax =
|
|
|
+ cpu_to_le16((mu_edca->ecw_min_max & 0xf0) >> 4);
|
|
|
+ sta_ctxt_cmd.trig_based_txf[i].aifsn =
|
|
|
+ cpu_to_le16(mu_edca->aifsn);
|
|
|
+ sta_ctxt_cmd.trig_based_txf[i].mu_time =
|
|
|
+ cpu_to_le16(mu_edca->mu_edca_timer);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (vif->bss_conf.multi_sta_back_32bit)
|
|
|
+ flags |= STA_CTXT_HE_32BIT_BA_BITMAP;
|
|
|
+
|
|
|
+ if (vif->bss_conf.ack_enabled)
|
|
|
+ flags |= STA_CTXT_HE_ACK_ENABLED;
|
|
|
+
|
|
|
+ if (vif->bss_conf.uora_exists) {
|
|
|
+ flags |= STA_CTXT_HE_TRIG_RND_ALLOC;
|
|
|
+
|
|
|
+ sta_ctxt_cmd.rand_alloc_ecwmin =
|
|
|
+ vif->bss_conf.uora_ocw_range & 0x7;
|
|
|
+ sta_ctxt_cmd.rand_alloc_ecwmax =
|
|
|
+ (vif->bss_conf.uora_ocw_range >> 3) & 0x7;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* TODO: support Multi BSSID IE */
|
|
|
+
|
|
|
+ sta_ctxt_cmd.flags = cpu_to_le32(flags);
|
|
|
+
|
|
|
+ if (iwl_mvm_send_cmd_pdu(mvm, iwl_cmd_id(STA_HE_CTXT_CMD,
|
|
|
+ DATA_PATH_GROUP, 0),
|
|
|
+ 0, sizeof(sta_ctxt_cmd), &sta_ctxt_cmd))
|
|
|
+ IWL_ERR(mvm, "Failed to config FW to work HE!\n");
|
|
|
+}
|
|
|
+
|
|
|
static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
|
|
|
struct ieee80211_vif *vif,
|
|
|
struct ieee80211_bss_conf *bss_conf,
|
|
@@ -1910,8 +2099,12 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
|
|
|
* beacon interval, which was not known when the station interface was
|
|
|
* added.
|
|
|
*/
|
|
|
- if (changes & BSS_CHANGED_ASSOC && bss_conf->assoc)
|
|
|
+ if (changes & BSS_CHANGED_ASSOC && bss_conf->assoc) {
|
|
|
+ if (vif->bss_conf.he_support)
|
|
|
+ iwl_mvm_cfg_he_sta(mvm, vif, mvmvif->ap_sta_id);
|
|
|
+
|
|
|
iwl_mvm_mac_ctxt_recalc_tsf_id(mvm, vif);
|
|
|
+ }
|
|
|
|
|
|
/*
|
|
|
* If we're not associated yet, take the (new) BSSID before associating
|