forked from mirrors/linux
		
	iwlwifi: add support for IEEE802.11ax
Add support for the HE in the iwlwifi driver conforming with P802.11ax_D2.0. Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
This commit is contained in:
		
							parent
							
								
									8a6171a7b6
								
							
						
					
					
						commit
						514c30696f
					
				
					 12 changed files with 525 additions and 23 deletions
				
			
		|  | @ -463,6 +463,101 @@ static void iwl_init_vht_hw_capab(const struct iwl_cfg *cfg, | |||
| 	vht_cap->vht_mcs.tx_mcs_map = vht_cap->vht_mcs.rx_mcs_map; | ||||
| } | ||||
| 
 | ||||
| static struct ieee80211_sband_iftype_data iwl_he_capa = { | ||||
| 	.types_mask = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_AP), | ||||
| 	.he_cap = { | ||||
| 		.has_he = true, | ||||
| 		.he_cap_elem = { | ||||
| 			.mac_cap_info[0] = | ||||
| 				IEEE80211_HE_MAC_CAP0_HTC_HE, | ||||
| 			.mac_cap_info[1] = | ||||
| 				IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_16US | | ||||
| 				IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_QOS_8, | ||||
| 			.mac_cap_info[2] = | ||||
| 				IEEE80211_HE_MAC_CAP2_32BIT_BA_BITMAP | | ||||
| 				IEEE80211_HE_MAC_CAP2_ACK_EN, | ||||
| 			.mac_cap_info[3] = | ||||
| 				IEEE80211_HE_MAC_CAP3_GRP_ADDR_MULTI_STA_BA_DL_MU | | ||||
| 				IEEE80211_HE_MAC_CAP3_MAX_A_AMPDU_LEN_EXP_VHT_2, | ||||
| 			.mac_cap_info[4] = IEEE80211_HE_MAC_CAP4_AMDSU_IN_AMPDU, | ||||
| 			.phy_cap_info[0] = | ||||
| 				IEEE80211_HE_PHY_CAP0_DUAL_BAND | | ||||
| 				IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G | | ||||
| 				IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G | | ||||
| 				IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G, | ||||
| 			.phy_cap_info[1] = | ||||
| 				IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A | | ||||
| 				IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD | | ||||
| 				IEEE80211_HE_PHY_CAP1_MIDAMBLE_RX_MAX_NSTS, | ||||
| 			.phy_cap_info[2] = | ||||
| 				IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US | | ||||
| 				IEEE80211_HE_PHY_CAP2_STBC_TX_UNDER_80MHZ | | ||||
| 				IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ, | ||||
| 			.phy_cap_info[3] = | ||||
| 				IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_BPSK | | ||||
| 				IEEE80211_HE_PHY_CAP3_DCM_MAX_TX_NSS_1 | | ||||
| 				IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_BPSK | | ||||
| 				IEEE80211_HE_PHY_CAP3_DCM_MAX_RX_NSS_1, | ||||
| 			.phy_cap_info[4] = | ||||
| 				IEEE80211_HE_PHY_CAP4_SU_BEAMFORMEE | | ||||
| 				IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_8 | | ||||
| 				IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_8, | ||||
| 			.phy_cap_info[5] = | ||||
| 				IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_2 | | ||||
| 				IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_2, | ||||
| 			.phy_cap_info[6] = | ||||
| 				IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT, | ||||
| 			.phy_cap_info[7] = | ||||
| 				IEEE80211_HE_PHY_CAP7_POWER_BOOST_FACTOR_AR | | ||||
| 				IEEE80211_HE_PHY_CAP7_HE_SU_MU_PPDU_4XLTF_AND_08_US_GI | | ||||
| 				IEEE80211_HE_PHY_CAP7_MAX_NC_7, | ||||
| 			.phy_cap_info[8] = | ||||
| 				IEEE80211_HE_PHY_CAP8_HE_ER_SU_PPDU_4XLTF_AND_08_US_GI | | ||||
| 				IEEE80211_HE_PHY_CAP8_20MHZ_IN_40MHZ_HE_PPDU_IN_2G | | ||||
| 				IEEE80211_HE_PHY_CAP8_20MHZ_IN_160MHZ_HE_PPDU | | ||||
| 				IEEE80211_HE_PHY_CAP8_80MHZ_IN_160MHZ_HE_PPDU, | ||||
| 		}, | ||||
| 		/*
 | ||||
| 		 * Set default Tx/Rx HE MCS NSS Support field. Indicate support | ||||
| 		 * for up to 2 spatial streams and all MCS, without any special | ||||
| 		 * cases | ||||
| 		 */ | ||||
| 		.he_mcs_nss_supp = { | ||||
| 			.rx_mcs_80 = cpu_to_le16(0xfffa), | ||||
| 			.tx_mcs_80 = cpu_to_le16(0xfffa), | ||||
| 			.rx_mcs_160 = cpu_to_le16(0xfffa), | ||||
| 			.tx_mcs_160 = cpu_to_le16(0xfffa), | ||||
| 			.rx_mcs_80p80 = cpu_to_le16(0xffff), | ||||
| 			.tx_mcs_80p80 = cpu_to_le16(0xffff), | ||||
| 		}, | ||||
| 		/*
 | ||||
| 		 * Set default PPE thresholds, with PPET16 set to 0, PPET8 set | ||||
| 		 * to 7 | ||||
| 		 */ | ||||
| 		.ppe_thres = {0x61, 0x1c, 0xc7, 0x71}, | ||||
| 	}, | ||||
| }; | ||||
| 
 | ||||
| static void iwl_init_he_hw_capab(struct ieee80211_supported_band *sband, | ||||
| 				 u8 tx_chains, u8 rx_chains) | ||||
| { | ||||
| 	if (sband->band == NL80211_BAND_2GHZ || | ||||
| 	    sband->band == NL80211_BAND_5GHZ) | ||||
| 		sband->iftype_data = &iwl_he_capa; | ||||
| 	else | ||||
| 		return; | ||||
| 
 | ||||
| 	sband->n_iftype_data = 1; | ||||
| 
 | ||||
| 	/* If not 2x2, we need to indicate 1x1 in the Midamble RX Max NSTS */ | ||||
| 	if ((tx_chains & rx_chains) != ANT_AB) { | ||||
| 		iwl_he_capa.he_cap.he_cap_elem.phy_cap_info[1] &= | ||||
| 			~IEEE80211_HE_PHY_CAP1_MIDAMBLE_RX_MAX_NSTS; | ||||
| 		iwl_he_capa.he_cap.he_cap_elem.phy_cap_info[2] &= | ||||
| 			~IEEE80211_HE_PHY_CAP2_MIDAMBLE_RX_MAX_NSTS; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static void iwl_init_sbands(struct device *dev, const struct iwl_cfg *cfg, | ||||
| 			    struct iwl_nvm_data *data, | ||||
| 			    const __le16 *nvm_ch_flags, u8 tx_chains, | ||||
|  | @ -483,6 +578,9 @@ static void iwl_init_sbands(struct device *dev, const struct iwl_cfg *cfg, | |||
| 	iwl_init_ht_hw_capab(cfg, data, &sband->ht_cap, NL80211_BAND_2GHZ, | ||||
| 			     tx_chains, rx_chains); | ||||
| 
 | ||||
| 	if (data->sku_cap_11ax_enable) | ||||
| 		iwl_init_he_hw_capab(sband, tx_chains, rx_chains); | ||||
| 
 | ||||
| 	sband = &data->bands[NL80211_BAND_5GHZ]; | ||||
| 	sband->band = NL80211_BAND_5GHZ; | ||||
| 	sband->bitrates = &iwl_cfg80211_rates[RATES_52_OFFS]; | ||||
|  | @ -495,6 +593,9 @@ static void iwl_init_sbands(struct device *dev, const struct iwl_cfg *cfg, | |||
| 		iwl_init_vht_hw_capab(cfg, data, &sband->vht_cap, | ||||
| 				      tx_chains, rx_chains); | ||||
| 
 | ||||
| 	if (data->sku_cap_11ax_enable) | ||||
| 		iwl_init_he_hw_capab(sband, tx_chains, rx_chains); | ||||
| 
 | ||||
| 	if (n_channels != n_used) | ||||
| 		IWL_ERR_DEV(dev, "NVM: used only %d of %d channels\n", | ||||
| 			    n_used, n_channels); | ||||
|  | @ -1293,6 +1394,8 @@ struct iwl_nvm_data *iwl_get_nvm(struct iwl_trans *trans, | |||
| 		!!(mac_flags & NVM_MAC_SKU_FLAGS_802_11AC_ENABLED); | ||||
| 	nvm->sku_cap_11n_enable = | ||||
| 		!!(mac_flags & NVM_MAC_SKU_FLAGS_802_11N_ENABLED); | ||||
| 	nvm->sku_cap_11ax_enable = | ||||
| 		!!(mac_flags & NVM_MAC_SKU_FLAGS_802_11AX_ENABLED); | ||||
| 	nvm->sku_cap_band_24ghz_enable = | ||||
| 		!!(mac_flags & NVM_MAC_SKU_FLAGS_BAND_2_4_ENABLED); | ||||
| 	nvm->sku_cap_band_52ghz_enable = | ||||
|  |  | |||
|  | @ -780,6 +780,9 @@ static int iwl_mvm_mac_ctxt_cmd_sta(struct iwl_mvm *mvm, | |||
| 	if (vif->probe_req_reg && vif->bss_conf.assoc && vif->p2p) | ||||
| 		cmd.filter_flags |= cpu_to_le32(MAC_FILTER_IN_PROBE_REQUEST); | ||||
| 
 | ||||
| 	if (vif->bss_conf.assoc && vif->bss_conf.he_support) | ||||
| 		cmd.filter_flags |= cpu_to_le32(MAC_FILTER_IN_11AX); | ||||
| 
 | ||||
| 	return iwl_mvm_mac_ctxt_send_cmd(mvm, &cmd); | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -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 | ||||
|  |  | |||
|  | @ -654,7 +654,7 @@ struct iwl_mvm_tcm { | |||
| struct iwl_mvm_reorder_buffer { | ||||
| 	u16 head_sn; | ||||
| 	u16 num_stored; | ||||
| 	u8 buf_size; | ||||
| 	u16 buf_size; | ||||
| 	int queue; | ||||
| 	u16 last_amsdu; | ||||
| 	u8 last_sub_index; | ||||
|  |  | |||
|  | @ -448,6 +448,7 @@ static const struct iwl_hcmd_names iwl_mvm_data_path_names[] = { | |||
| 	HCMD_NAME(DQA_ENABLE_CMD), | ||||
| 	HCMD_NAME(UPDATE_MU_GROUPS_CMD), | ||||
| 	HCMD_NAME(TRIGGER_RX_QUEUES_NOTIF_CMD), | ||||
| 	HCMD_NAME(STA_HE_CTXT_CMD), | ||||
| 	HCMD_NAME(STA_PM_NOTIF), | ||||
| 	HCMD_NAME(MU_GROUP_MGMT_NOTIF), | ||||
| 	HCMD_NAME(RX_QUEUES_NOTIFICATION), | ||||
|  |  | |||
|  | @ -183,6 +183,43 @@ rs_fw_vht_set_enabled_rates(const struct ieee80211_sta *sta, | |||
| 	} | ||||
| } | ||||
| 
 | ||||
| static u16 rs_fw_he_ieee80211_mcs_to_rs_mcs(u16 mcs) | ||||
| { | ||||
| 	switch (mcs) { | ||||
| 	case IEEE80211_HE_MCS_SUPPORT_0_7: | ||||
| 		return BIT(IWL_TLC_MNG_HT_RATE_MCS7 + 1) - 1; | ||||
| 	case IEEE80211_HE_MCS_SUPPORT_0_9: | ||||
| 		return BIT(IWL_TLC_MNG_HT_RATE_MCS9 + 1) - 1; | ||||
| 	case IEEE80211_HE_MCS_SUPPORT_0_11: | ||||
| 		return BIT(IWL_TLC_MNG_HT_RATE_MCS11 + 1) - 1; | ||||
| 	case IEEE80211_HE_MCS_NOT_SUPPORTED: | ||||
| 		return 0; | ||||
| 	} | ||||
| 
 | ||||
| 	WARN(1, "invalid HE MCS %d\n", mcs); | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| rs_fw_he_set_enabled_rates(const struct ieee80211_sta *sta, | ||||
| 			   const struct ieee80211_sta_he_cap *he_cap, | ||||
| 			   struct iwl_tlc_config_cmd *cmd) | ||||
| { | ||||
| 	u16 mcs_160 = le16_to_cpu(sta->he_cap.he_mcs_nss_supp.rx_mcs_160); | ||||
| 	u16 mcs_80 = le16_to_cpu(sta->he_cap.he_mcs_nss_supp.rx_mcs_80); | ||||
| 	int i; | ||||
| 
 | ||||
| 	for (i = 0; i < sta->rx_nss && i < MAX_NSS; i++) { | ||||
| 		u16 _mcs_160 = (mcs_160 >> (2 * i)) & 0x3; | ||||
| 		u16 _mcs_80 = (mcs_80 >> (2 * i)) & 0x3; | ||||
| 
 | ||||
| 		cmd->ht_rates[i][0] = | ||||
| 			cpu_to_le16(rs_fw_he_ieee80211_mcs_to_rs_mcs(_mcs_80)); | ||||
| 		cmd->ht_rates[i][1] = | ||||
| 			cpu_to_le16(rs_fw_he_ieee80211_mcs_to_rs_mcs(_mcs_160)); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static void rs_fw_set_supp_rates(struct ieee80211_sta *sta, | ||||
| 				 struct ieee80211_supported_band *sband, | ||||
| 				 struct iwl_tlc_config_cmd *cmd) | ||||
|  | @ -192,6 +229,7 @@ static void rs_fw_set_supp_rates(struct ieee80211_sta *sta, | |||
| 	unsigned long supp; /* must be unsigned long for for_each_set_bit */ | ||||
| 	const struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap; | ||||
| 	const struct ieee80211_sta_vht_cap *vht_cap = &sta->vht_cap; | ||||
| 	const struct ieee80211_sta_he_cap *he_cap = &sta->he_cap; | ||||
| 
 | ||||
| 	/* non HT rates */ | ||||
| 	supp = 0; | ||||
|  | @ -202,7 +240,11 @@ static void rs_fw_set_supp_rates(struct ieee80211_sta *sta, | |||
| 	cmd->non_ht_rates = cpu_to_le16(supp); | ||||
| 	cmd->mode = IWL_TLC_MNG_MODE_NON_HT; | ||||
| 
 | ||||
| 	if (vht_cap && vht_cap->vht_supported) { | ||||
| 	/* HT/VHT rates */ | ||||
| 	if (he_cap && he_cap->has_he) { | ||||
| 		cmd->mode = IWL_TLC_MNG_MODE_HE; | ||||
| 		rs_fw_he_set_enabled_rates(sta, he_cap, cmd); | ||||
| 	} else if (vht_cap && vht_cap->vht_supported) { | ||||
| 		cmd->mode = IWL_TLC_MNG_MODE_VHT; | ||||
| 		rs_fw_vht_set_enabled_rates(sta, vht_cap, cmd); | ||||
| 	} else if (ht_cap && ht_cap->ht_supported) { | ||||
|  |  | |||
|  | @ -363,7 +363,8 @@ static int iwl_hwrate_to_plcp_idx(u32 rate_n_flags) | |||
| 			idx += 1; | ||||
| 		if ((idx >= IWL_FIRST_HT_RATE) && (idx <= IWL_LAST_HT_RATE)) | ||||
| 			return idx; | ||||
| 	} else if (rate_n_flags & RATE_MCS_VHT_MSK) { | ||||
| 	} else if (rate_n_flags & RATE_MCS_VHT_MSK || | ||||
| 		   rate_n_flags & RATE_MCS_HE_MSK) { | ||||
| 		idx = rate_n_flags & RATE_VHT_MCS_RATE_CODE_MSK; | ||||
| 		idx += IWL_RATE_MCS_0_INDEX; | ||||
| 
 | ||||
|  | @ -372,6 +373,9 @@ static int iwl_hwrate_to_plcp_idx(u32 rate_n_flags) | |||
| 			idx++; | ||||
| 		if ((idx >= IWL_FIRST_VHT_RATE) && (idx <= IWL_LAST_VHT_RATE)) | ||||
| 			return idx; | ||||
| 		if ((rate_n_flags & RATE_MCS_HE_MSK) && | ||||
| 		    (idx <= IWL_LAST_HE_RATE)) | ||||
| 			return idx; | ||||
| 	} else { | ||||
| 		/* legacy rate format, search for match in table */ | ||||
| 
 | ||||
|  | @ -516,6 +520,8 @@ static const char *rs_pretty_lq_type(enum iwl_table_type type) | |||
| 		[LQ_HT_MIMO2] = "HT MIMO", | ||||
| 		[LQ_VHT_SISO] = "VHT SISO", | ||||
| 		[LQ_VHT_MIMO2] = "VHT MIMO", | ||||
| 		[LQ_HE_SISO] = "HE SISO", | ||||
| 		[LQ_HE_MIMO2] = "HE MIMO", | ||||
| 	}; | ||||
| 
 | ||||
| 	if (type < LQ_NONE || type >= LQ_MAX) | ||||
|  | @ -900,7 +906,8 @@ static int rs_rate_from_ucode_rate(const u32 ucode_rate, | |||
| 
 | ||||
| 	/* Legacy */ | ||||
| 	if (!(ucode_rate & RATE_MCS_HT_MSK) && | ||||
| 	    !(ucode_rate & RATE_MCS_VHT_MSK)) { | ||||
| 	    !(ucode_rate & RATE_MCS_VHT_MSK) && | ||||
| 	    !(ucode_rate & RATE_MCS_HE_MSK)) { | ||||
| 		if (num_of_ant == 1) { | ||||
| 			if (band == NL80211_BAND_5GHZ) | ||||
| 				rate->type = LQ_LEGACY_A; | ||||
|  | @ -911,7 +918,7 @@ static int rs_rate_from_ucode_rate(const u32 ucode_rate, | |||
| 		return 0; | ||||
| 	} | ||||
| 
 | ||||
| 	/* HT or VHT */ | ||||
| 	/* HT, VHT or HE */ | ||||
| 	if (ucode_rate & RATE_MCS_SGI_MSK) | ||||
| 		rate->sgi = true; | ||||
| 	if (ucode_rate & RATE_MCS_LDPC_MSK) | ||||
|  | @ -953,10 +960,24 @@ static int rs_rate_from_ucode_rate(const u32 ucode_rate, | |||
| 		} else { | ||||
| 			WARN_ON_ONCE(1); | ||||
| 		} | ||||
| 	} else if (ucode_rate & RATE_MCS_HE_MSK) { | ||||
| 		nss = ((ucode_rate & RATE_VHT_MCS_NSS_MSK) >> | ||||
| 		      RATE_VHT_MCS_NSS_POS) + 1; | ||||
| 
 | ||||
| 		if (nss == 1) { | ||||
| 			rate->type = LQ_HE_SISO; | ||||
| 			WARN_ONCE(!rate->stbc && !rate->bfer && num_of_ant != 1, | ||||
| 				  "stbc %d bfer %d", rate->stbc, rate->bfer); | ||||
| 		} else if (nss == 2) { | ||||
| 			rate->type = LQ_HE_MIMO2; | ||||
| 			WARN_ON_ONCE(num_of_ant != 2); | ||||
| 		} else { | ||||
| 			WARN_ON_ONCE(1); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	WARN_ON_ONCE(rate->bw == RATE_MCS_CHAN_WIDTH_80 && | ||||
| 		     !is_vht(rate)); | ||||
| 		     !is_he(rate) && !is_vht(rate)); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
|  | @ -3606,7 +3627,8 @@ int rs_pretty_print_rate(char *buf, int bufsz, const u32 rate) | |||
| 	u8 ant = (rate & RATE_MCS_ANT_ABC_MSK) >> RATE_MCS_ANT_POS; | ||||
| 
 | ||||
| 	if (!(rate & RATE_MCS_HT_MSK) && | ||||
| 	    !(rate & RATE_MCS_VHT_MSK)) { | ||||
| 	    !(rate & RATE_MCS_VHT_MSK) && | ||||
| 	    !(rate & RATE_MCS_HE_MSK)) { | ||||
| 		int index = iwl_hwrate_to_plcp_idx(rate); | ||||
| 
 | ||||
| 		return scnprintf(buf, bufsz, "Legacy | ANT: %s Rate: %s Mbps\n", | ||||
|  | @ -3625,6 +3647,11 @@ int rs_pretty_print_rate(char *buf, int bufsz, const u32 rate) | |||
| 		mcs = rate & RATE_HT_MCS_INDEX_MSK; | ||||
| 		nss = ((rate & RATE_HT_MCS_NSS_MSK) | ||||
| 		       >> RATE_HT_MCS_NSS_POS) + 1; | ||||
| 	} else if (rate & RATE_MCS_HE_MSK) { | ||||
| 		type = "HE"; | ||||
| 		mcs = rate & RATE_VHT_MCS_RATE_CODE_MSK; | ||||
| 		nss = ((rate & RATE_VHT_MCS_NSS_MSK) | ||||
| 		       >> RATE_VHT_MCS_NSS_POS) + 1; | ||||
| 	} else { | ||||
| 		type = "Unknown"; /* shouldn't happen */ | ||||
| 	} | ||||
|  | @ -3886,6 +3913,8 @@ static ssize_t rs_sta_dbgfs_drv_tx_stats_read(struct file *file, | |||
| 		[IWL_RATE_MCS_7_INDEX] = "MCS7", | ||||
| 		[IWL_RATE_MCS_8_INDEX] = "MCS8", | ||||
| 		[IWL_RATE_MCS_9_INDEX] = "MCS9", | ||||
| 		[IWL_RATE_MCS_10_INDEX] = "MCS10", | ||||
| 		[IWL_RATE_MCS_11_INDEX] = "MCS11", | ||||
| 	}; | ||||
| 
 | ||||
| 	char *buff, *pos, *endpos; | ||||
|  |  | |||
|  | @ -144,8 +144,13 @@ enum { | |||
| 
 | ||||
| #define LINK_QUAL_AGG_FRAME_LIMIT_DEF	(63) | ||||
| #define LINK_QUAL_AGG_FRAME_LIMIT_MAX	(63) | ||||
| #define LINK_QUAL_AGG_FRAME_LIMIT_GEN2_DEF	(64) | ||||
| #define LINK_QUAL_AGG_FRAME_LIMIT_GEN2_MAX	(64) | ||||
| /*
 | ||||
|  * FIXME - various places in firmware API still use u8, | ||||
|  * e.g. LQ command and SCD config command. | ||||
|  * This should be 256 instead. | ||||
|  */ | ||||
| #define LINK_QUAL_AGG_FRAME_LIMIT_GEN2_DEF	(255) | ||||
| #define LINK_QUAL_AGG_FRAME_LIMIT_GEN2_MAX	(255) | ||||
| #define LINK_QUAL_AGG_FRAME_LIMIT_MIN	(0) | ||||
| 
 | ||||
| #define LQ_SIZE		2	/* 2 mode tables:  "Active" and "Search" */ | ||||
|  | @ -162,6 +167,8 @@ enum iwl_table_type { | |||
| 	LQ_HT_MIMO2, | ||||
| 	LQ_VHT_SISO,    /* VHT types */ | ||||
| 	LQ_VHT_MIMO2, | ||||
| 	LQ_HE_SISO,     /* HE types */ | ||||
| 	LQ_HE_MIMO2, | ||||
| 	LQ_MAX, | ||||
| }; | ||||
| 
 | ||||
|  | @ -183,11 +190,16 @@ struct rs_rate { | |||
| #define is_type_ht_mimo2(type) ((type) == LQ_HT_MIMO2) | ||||
| #define is_type_vht_siso(type) ((type) == LQ_VHT_SISO) | ||||
| #define is_type_vht_mimo2(type) ((type) == LQ_VHT_MIMO2) | ||||
| #define is_type_siso(type) (is_type_ht_siso(type) || is_type_vht_siso(type)) | ||||
| #define is_type_mimo2(type) (is_type_ht_mimo2(type) || is_type_vht_mimo2(type)) | ||||
| #define is_type_he_siso(type) ((type) == LQ_HE_SISO) | ||||
| #define is_type_he_mimo2(type) ((type) == LQ_HE_MIMO2) | ||||
| #define is_type_siso(type) (is_type_ht_siso(type) || is_type_vht_siso(type) || \ | ||||
| 			    is_type_he_siso(type)) | ||||
| #define is_type_mimo2(type) (is_type_ht_mimo2(type) || \ | ||||
| 			     is_type_vht_mimo2(type) || is_type_he_mimo2(type)) | ||||
| #define is_type_mimo(type) (is_type_mimo2(type)) | ||||
| #define is_type_ht(type) (is_type_ht_siso(type) || is_type_ht_mimo2(type)) | ||||
| #define is_type_vht(type) (is_type_vht_siso(type) || is_type_vht_mimo2(type)) | ||||
| #define is_type_he(type) (is_type_he_siso(type) || is_type_he_mimo2(type)) | ||||
| #define is_type_a_band(type) ((type) == LQ_LEGACY_A) | ||||
| #define is_type_g_band(type) ((type) == LQ_LEGACY_G) | ||||
| 
 | ||||
|  | @ -201,6 +213,7 @@ struct rs_rate { | |||
| #define is_mimo(rate)         is_type_mimo((rate)->type) | ||||
| #define is_ht(rate)           is_type_ht((rate)->type) | ||||
| #define is_vht(rate)          is_type_vht((rate)->type) | ||||
| #define is_he(rate)           is_type_he((rate)->type) | ||||
| #define is_a_band(rate)       is_type_a_band((rate)->type) | ||||
| #define is_g_band(rate)       is_type_g_band((rate)->type) | ||||
| 
 | ||||
|  |  | |||
|  | @ -8,6 +8,7 @@ | |||
|  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. | ||||
|  * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH | ||||
|  * Copyright(c) 2015 - 2017 Intel Deutschland GmbH | ||||
|  * Copyright(c) 2018 Intel Corporation | ||||
|  * | ||||
|  * This program is free software; you can redistribute it and/or modify | ||||
|  * it under the terms of version 2 of the GNU General Public License as | ||||
|  | @ -30,6 +31,7 @@ | |||
|  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. | ||||
|  * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH | ||||
|  * Copyright(c) 2015 - 2017 Intel Deutschland GmbH | ||||
|  * Copyright(c) 2018 Intel Corporation | ||||
|  * All rights reserved. | ||||
|  * | ||||
|  * Redistribution and use in source and binary forms, with or without | ||||
|  | @ -857,6 +859,10 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, | |||
| 	struct ieee80211_sta *sta = NULL; | ||||
| 	struct sk_buff *skb; | ||||
| 	u8 crypt_len = 0; | ||||
| 	u32 he_type = 0xffffffff; | ||||
| 	/* this is invalid e.g. because puncture type doesn't allow 0b11 */ | ||||
| #define HE_PHY_DATA_INVAL ((u64)-1) | ||||
| 	u64 he_phy_data = HE_PHY_DATA_INVAL; | ||||
| 
 | ||||
| 	if (unlikely(test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status))) | ||||
| 		return; | ||||
|  | @ -882,6 +888,13 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, | |||
| 
 | ||||
| 	rx_status = IEEE80211_SKB_RXCB(skb); | ||||
| 
 | ||||
| 	if (rate_n_flags & RATE_MCS_HE_MSK) { | ||||
| 		if (phy_info & IWL_RX_MPDU_PHY_TSF_OVERLOAD) | ||||
| 			he_phy_data = | ||||
| 				le64_to_cpu(desc->he_phy_data); | ||||
| 		he_type = rate_n_flags & RATE_MCS_HE_TYPE_MSK; | ||||
| 	} | ||||
| 
 | ||||
| 	if (iwl_mvm_rx_crypto(mvm, hdr, rx_status, phy_info, desc, | ||||
| 			      le32_to_cpu(pkt->len_n_flags), queue, | ||||
| 			      &crypt_len)) { | ||||
|  | @ -907,7 +920,19 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, | |||
| 		rx_status->mactime = le64_to_cpu(desc->tsf_on_air_rise); | ||||
| 		/* TSF as indicated by the firmware is at INA time */ | ||||
| 		rx_status->flag |= RX_FLAG_MACTIME_PLCP_START; | ||||
| 	} else if (he_type == RATE_MCS_HE_TYPE_SU) { | ||||
| 		if (!queue && !(phy_info & IWL_RX_MPDU_PHY_AMPDU)) { | ||||
| 			rx_status->ampdu_reference = mvm->ampdu_ref; | ||||
| 			mvm->ampdu_ref++; | ||||
| 
 | ||||
| 			rx_status->flag |= RX_FLAG_AMPDU_DETAILS; | ||||
| 			rx_status->flag |= RX_FLAG_AMPDU_EOF_BIT_KNOWN; | ||||
| 			if (FIELD_GET(IWL_RX_HE_PHY_DELIM_EOF, | ||||
| 				      le64_to_cpu(desc->he_phy_data))) | ||||
| 				rx_status->flag |= RX_FLAG_AMPDU_EOF_BIT; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	rx_status->device_timestamp = le32_to_cpu(desc->gp2_on_air_rise); | ||||
| 	rx_status->band = desc->channel > 14 ? NL80211_BAND_5GHZ : | ||||
| 					       NL80211_BAND_2GHZ; | ||||
|  | @ -925,6 +950,15 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, | |||
| 		if (toggle_bit != mvm->ampdu_toggle) { | ||||
| 			mvm->ampdu_ref++; | ||||
| 			mvm->ampdu_toggle = toggle_bit; | ||||
| 
 | ||||
| 			if (he_phy_data != HE_PHY_DATA_INVAL && | ||||
| 			    he_type == RATE_MCS_HE_TYPE_MU) { | ||||
| 				rx_status->flag |= RX_FLAG_AMPDU_EOF_BIT_KNOWN; | ||||
| 				if (FIELD_GET(IWL_RX_HE_PHY_DELIM_EOF, | ||||
| 					      le64_to_cpu(desc->he_phy_data))) | ||||
| 					rx_status->flag |= | ||||
| 						RX_FLAG_AMPDU_EOF_BIT; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
|  | @ -1033,7 +1067,6 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, | |||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	/* Set up the HT phy flags */ | ||||
| 	switch (rate_n_flags & RATE_MCS_CHAN_WIDTH_MSK) { | ||||
| 	case RATE_MCS_CHAN_WIDTH_20: | ||||
| 		break; | ||||
|  | @ -1048,6 +1081,59 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, | |||
| 		break; | ||||
| 	} | ||||
| 
 | ||||
| 	if (he_type == RATE_MCS_HE_TYPE_EXT_SU && | ||||
| 	    rate_n_flags & RATE_MCS_HE_106T_MSK) { | ||||
| 		rx_status->bw = RATE_INFO_BW_HE_RU; | ||||
| 		rx_status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_106; | ||||
| 	} | ||||
| 
 | ||||
| 	if (rate_n_flags & RATE_MCS_HE_MSK && | ||||
| 	    phy_info & IWL_RX_MPDU_PHY_TSF_OVERLOAD && | ||||
| 	    he_type == RATE_MCS_HE_TYPE_MU) { | ||||
| 		/*
 | ||||
| 		 * Unfortunately, we have to leave the mac80211 data | ||||
| 		 * incorrect for the case that we receive an HE-MU | ||||
| 		 * transmission and *don't* have the he_mu pointer, | ||||
| 		 * i.e. we don't have the phy data (due to the bits | ||||
| 		 * being used for TSF). This shouldn't happen though | ||||
| 		 * as management frames where we need the TSF/timers | ||||
| 		 * are not be transmitted in HE-MU, I think. | ||||
| 		 */ | ||||
| 		u8 ru = FIELD_GET(IWL_RX_HE_PHY_RU_ALLOC_MASK, he_phy_data); | ||||
| 		u8 offs = 0; | ||||
| 
 | ||||
| 		rx_status->bw = RATE_INFO_BW_HE_RU; | ||||
| 
 | ||||
| 		switch (ru) { | ||||
| 		case 0 ... 36: | ||||
| 			rx_status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_26; | ||||
| 			offs = ru; | ||||
| 			break; | ||||
| 		case 37 ... 52: | ||||
| 			rx_status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_52; | ||||
| 			offs = ru - 37; | ||||
| 			break; | ||||
| 		case 53 ... 60: | ||||
| 			rx_status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_106; | ||||
| 			offs = ru - 53; | ||||
| 			break; | ||||
| 		case 61 ... 64: | ||||
| 			rx_status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_242; | ||||
| 			offs = ru - 61; | ||||
| 			break; | ||||
| 		case 65 ... 66: | ||||
| 			rx_status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_484; | ||||
| 			offs = ru - 65; | ||||
| 			break; | ||||
| 		case 67: | ||||
| 			rx_status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_996; | ||||
| 			break; | ||||
| 		case 68: | ||||
| 			rx_status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_2x996; | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if (!(rate_n_flags & RATE_MCS_CCK_MSK) && | ||||
| 	    rate_n_flags & RATE_MCS_SGI_MSK) | ||||
| 		rx_status->enc_flags |= RX_ENC_FLAG_SHORT_GI; | ||||
|  | @ -1072,6 +1158,39 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, | |||
| 		rx_status->enc_flags |= stbc << RX_ENC_FLAG_STBC_SHIFT; | ||||
| 		if (rate_n_flags & RATE_MCS_BF_MSK) | ||||
| 			rx_status->enc_flags |= RX_ENC_FLAG_BF; | ||||
| 	} else if (rate_n_flags & RATE_MCS_HE_MSK) { | ||||
| 		u8 stbc = (rate_n_flags & RATE_MCS_STBC_MSK) >> | ||||
| 				RATE_MCS_STBC_POS; | ||||
| 		rx_status->nss = | ||||
| 			((rate_n_flags & RATE_VHT_MCS_NSS_MSK) >> | ||||
| 						RATE_VHT_MCS_NSS_POS) + 1; | ||||
| 		rx_status->rate_idx = rate_n_flags & RATE_VHT_MCS_RATE_CODE_MSK; | ||||
| 		rx_status->encoding = RX_ENC_HE; | ||||
| 		rx_status->enc_flags |= stbc << RX_ENC_FLAG_STBC_SHIFT; | ||||
| 		if (rate_n_flags & RATE_MCS_BF_MSK) | ||||
| 			rx_status->enc_flags |= RX_ENC_FLAG_BF; | ||||
| 
 | ||||
| 		rx_status->he_dcm = | ||||
| 			!!(rate_n_flags & RATE_HE_DUAL_CARRIER_MODE_MSK); | ||||
| 
 | ||||
| 		switch ((rate_n_flags & RATE_MCS_HE_GI_LTF_MSK) >> | ||||
| 			RATE_MCS_HE_GI_LTF_POS) { | ||||
| 		case 0: | ||||
| 			rx_status->he_gi = NL80211_RATE_INFO_HE_GI_0_8; | ||||
| 			break; | ||||
| 		case 1: | ||||
| 			rx_status->he_gi = NL80211_RATE_INFO_HE_GI_0_8; | ||||
| 			break; | ||||
| 		case 2: | ||||
| 			rx_status->he_gi = NL80211_RATE_INFO_HE_GI_1_6; | ||||
| 			break; | ||||
| 		case 3: | ||||
| 			if (rate_n_flags & RATE_MCS_SGI_MSK) | ||||
| 				rx_status->he_gi = NL80211_RATE_INFO_HE_GI_0_8; | ||||
| 			else | ||||
| 				rx_status->he_gi = NL80211_RATE_INFO_HE_GI_3_2; | ||||
| 			break; | ||||
| 		} | ||||
| 	} else { | ||||
| 		int rate = iwl_mvm_legacy_rate_to_mac80211_idx(rate_n_flags, | ||||
| 							       rx_status->band); | ||||
|  | @ -1083,7 +1202,6 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, | |||
| 			goto out; | ||||
| 		} | ||||
| 		rx_status->rate_idx = rate; | ||||
| 
 | ||||
| 	} | ||||
| 
 | ||||
| 	/* management stuff on default queue */ | ||||
|  |  | |||
|  | @ -2184,7 +2184,7 @@ static void iwl_mvm_free_reorder(struct iwl_mvm *mvm, | |||
| 
 | ||||
| static void iwl_mvm_init_reorder_buffer(struct iwl_mvm *mvm, | ||||
| 					struct iwl_mvm_baid_data *data, | ||||
| 					u16 ssn, u8 buf_size) | ||||
| 					u16 ssn, u16 buf_size) | ||||
| { | ||||
| 	int i; | ||||
| 
 | ||||
|  | @ -2211,7 +2211,7 @@ static void iwl_mvm_init_reorder_buffer(struct iwl_mvm *mvm, | |||
| } | ||||
| 
 | ||||
| int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta, | ||||
| 		       int tid, u16 ssn, bool start, u8 buf_size, u16 timeout) | ||||
| 		       int tid, u16 ssn, bool start, u16 buf_size, u16 timeout) | ||||
| { | ||||
| 	struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta); | ||||
| 	struct iwl_mvm_add_sta_cmd cmd = {}; | ||||
|  | @ -2273,7 +2273,7 @@ int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta, | |||
| 	if (start) { | ||||
| 		cmd.add_immediate_ba_tid = (u8) tid; | ||||
| 		cmd.add_immediate_ba_ssn = cpu_to_le16(ssn); | ||||
| 		cmd.rx_ba_window = cpu_to_le16((u16)buf_size); | ||||
| 		cmd.rx_ba_window = cpu_to_le16(buf_size); | ||||
| 	} else { | ||||
| 		cmd.remove_immediate_ba_tid = (u8) tid; | ||||
| 	} | ||||
|  | @ -2559,7 +2559,7 @@ int iwl_mvm_sta_tx_agg_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | |||
| } | ||||
| 
 | ||||
| int iwl_mvm_sta_tx_agg_oper(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | ||||
| 			    struct ieee80211_sta *sta, u16 tid, u8 buf_size, | ||||
| 			    struct ieee80211_sta *sta, u16 tid, u16 buf_size, | ||||
| 			    bool amsdu) | ||||
| { | ||||
| 	struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); | ||||
|  |  | |||
|  | @ -412,7 +412,7 @@ struct iwl_mvm_sta { | |||
| 	u32 tfd_queue_msk; | ||||
| 	u32 mac_id_n_color; | ||||
| 	u16 tid_disable_agg; | ||||
| 	u8 max_agg_bufsize; | ||||
| 	u16 max_agg_bufsize; | ||||
| 	enum iwl_sta_type sta_type; | ||||
| 	enum ieee80211_sta_state sta_state; | ||||
| 	bool bt_reduced_txpower; | ||||
|  | @ -518,11 +518,11 @@ void iwl_mvm_rx_eosp_notif(struct iwl_mvm *mvm, | |||
| 
 | ||||
| /* AMPDU */ | ||||
| int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta, | ||||
| 		       int tid, u16 ssn, bool start, u8 buf_size, u16 timeout); | ||||
| 		       int tid, u16 ssn, bool start, u16 buf_size, u16 timeout); | ||||
| int iwl_mvm_sta_tx_agg_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | ||||
| 			struct ieee80211_sta *sta, u16 tid, u16 *ssn); | ||||
| int iwl_mvm_sta_tx_agg_oper(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | ||||
| 			    struct ieee80211_sta *sta, u16 tid, u8 buf_size, | ||||
| 			    struct ieee80211_sta *sta, u16 tid, u16 buf_size, | ||||
| 			    bool amsdu); | ||||
| int iwl_mvm_sta_tx_agg_stop(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | ||||
| 			    struct ieee80211_sta *sta, u16 tid); | ||||
|  |  | |||
|  | @ -2934,7 +2934,7 @@ static struct iwl_trans_dump_data | |||
| 	struct iwl_txq *cmdq = trans_pcie->txq[trans_pcie->cmd_queue]; | ||||
| 	struct iwl_fw_error_dump_txcmd *txcmd; | ||||
| 	struct iwl_trans_dump_data *dump_data; | ||||
| 	u32 len, num_rbs; | ||||
| 	u32 len, num_rbs = 0; | ||||
| 	u32 monitor_len; | ||||
| 	int i, ptr; | ||||
| 	bool dump_rbs = test_bit(STATUS_FW_ERROR, &trans->status) && | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue
	
	 Luca Coelho
						Luca Coelho