1*a4128aadSBjoern A. Zeeb // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause 2*a4128aadSBjoern A. Zeeb /* 3*a4128aadSBjoern A. Zeeb * Copyright (C) 2005-2014, 2018-2021, 2023 Intel Corporation 4*a4128aadSBjoern A. Zeeb * Copyright (C) 2015 Intel Mobile Communications GmbH 5*a4128aadSBjoern A. Zeeb */ 6*a4128aadSBjoern A. Zeeb #include <linux/types.h> 7*a4128aadSBjoern A. Zeeb #include <linux/slab.h> 8*a4128aadSBjoern A. Zeeb #include <linux/export.h> 9*a4128aadSBjoern A. Zeeb #include "iwl-drv.h" 10*a4128aadSBjoern A. Zeeb #include "iwl-modparams.h" 11*a4128aadSBjoern A. Zeeb #include "iwl-nvm-utils.h" 12*a4128aadSBjoern A. Zeeb 13*a4128aadSBjoern A. Zeeb int iwl_init_sband_channels(struct iwl_nvm_data *data, 14*a4128aadSBjoern A. Zeeb struct ieee80211_supported_band *sband, 15*a4128aadSBjoern A. Zeeb int n_channels, enum nl80211_band band) 16*a4128aadSBjoern A. Zeeb { 17*a4128aadSBjoern A. Zeeb struct ieee80211_channel *chan = &data->channels[0]; 18*a4128aadSBjoern A. Zeeb int n = 0, idx = 0; 19*a4128aadSBjoern A. Zeeb 20*a4128aadSBjoern A. Zeeb while (idx < n_channels && chan->band != band) 21*a4128aadSBjoern A. Zeeb chan = &data->channels[++idx]; 22*a4128aadSBjoern A. Zeeb 23*a4128aadSBjoern A. Zeeb sband->channels = &data->channels[idx]; 24*a4128aadSBjoern A. Zeeb 25*a4128aadSBjoern A. Zeeb while (idx < n_channels && chan->band == band) { 26*a4128aadSBjoern A. Zeeb chan = &data->channels[++idx]; 27*a4128aadSBjoern A. Zeeb n++; 28*a4128aadSBjoern A. Zeeb } 29*a4128aadSBjoern A. Zeeb 30*a4128aadSBjoern A. Zeeb sband->n_channels = n; 31*a4128aadSBjoern A. Zeeb 32*a4128aadSBjoern A. Zeeb return n; 33*a4128aadSBjoern A. Zeeb } 34*a4128aadSBjoern A. Zeeb IWL_EXPORT_SYMBOL(iwl_init_sband_channels); 35*a4128aadSBjoern A. Zeeb 36*a4128aadSBjoern A. Zeeb #define MAX_BIT_RATE_40_MHZ 150 /* Mbps */ 37*a4128aadSBjoern A. Zeeb #define MAX_BIT_RATE_20_MHZ 72 /* Mbps */ 38*a4128aadSBjoern A. Zeeb 39*a4128aadSBjoern A. Zeeb void iwl_init_ht_hw_capab(struct iwl_trans *trans, 40*a4128aadSBjoern A. Zeeb struct iwl_nvm_data *data, 41*a4128aadSBjoern A. Zeeb struct ieee80211_sta_ht_cap *ht_info, 42*a4128aadSBjoern A. Zeeb enum nl80211_band band, 43*a4128aadSBjoern A. Zeeb u8 tx_chains, u8 rx_chains) 44*a4128aadSBjoern A. Zeeb { 45*a4128aadSBjoern A. Zeeb const struct iwl_cfg *cfg = trans->cfg; 46*a4128aadSBjoern A. Zeeb int max_bit_rate = 0; 47*a4128aadSBjoern A. Zeeb 48*a4128aadSBjoern A. Zeeb tx_chains = hweight8(tx_chains); 49*a4128aadSBjoern A. Zeeb if (cfg->rx_with_siso_diversity) 50*a4128aadSBjoern A. Zeeb rx_chains = 1; 51*a4128aadSBjoern A. Zeeb else 52*a4128aadSBjoern A. Zeeb rx_chains = hweight8(rx_chains); 53*a4128aadSBjoern A. Zeeb 54*a4128aadSBjoern A. Zeeb if (!(data->sku_cap_11n_enable) || 55*a4128aadSBjoern A. Zeeb (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_ALL) || 56*a4128aadSBjoern A. Zeeb !cfg->ht_params) { 57*a4128aadSBjoern A. Zeeb ht_info->ht_supported = false; 58*a4128aadSBjoern A. Zeeb return; 59*a4128aadSBjoern A. Zeeb } 60*a4128aadSBjoern A. Zeeb 61*a4128aadSBjoern A. Zeeb if (data->sku_cap_mimo_disabled) 62*a4128aadSBjoern A. Zeeb rx_chains = 1; 63*a4128aadSBjoern A. Zeeb 64*a4128aadSBjoern A. Zeeb ht_info->ht_supported = true; 65*a4128aadSBjoern A. Zeeb ht_info->cap = IEEE80211_HT_CAP_DSSSCCK40; 66*a4128aadSBjoern A. Zeeb 67*a4128aadSBjoern A. Zeeb if (cfg->ht_params->stbc) { 68*a4128aadSBjoern A. Zeeb ht_info->cap |= (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT); 69*a4128aadSBjoern A. Zeeb 70*a4128aadSBjoern A. Zeeb if (tx_chains > 1) 71*a4128aadSBjoern A. Zeeb ht_info->cap |= IEEE80211_HT_CAP_TX_STBC; 72*a4128aadSBjoern A. Zeeb } 73*a4128aadSBjoern A. Zeeb 74*a4128aadSBjoern A. Zeeb if (cfg->ht_params->ldpc) 75*a4128aadSBjoern A. Zeeb ht_info->cap |= IEEE80211_HT_CAP_LDPC_CODING; 76*a4128aadSBjoern A. Zeeb 77*a4128aadSBjoern A. Zeeb if (trans->trans_cfg->mq_rx_supported || 78*a4128aadSBjoern A. Zeeb iwlwifi_mod_params.amsdu_size >= IWL_AMSDU_8K) 79*a4128aadSBjoern A. Zeeb ht_info->cap |= IEEE80211_HT_CAP_MAX_AMSDU; 80*a4128aadSBjoern A. Zeeb 81*a4128aadSBjoern A. Zeeb ht_info->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; 82*a4128aadSBjoern A. Zeeb ht_info->ampdu_density = IEEE80211_HT_MPDU_DENSITY_4; 83*a4128aadSBjoern A. Zeeb 84*a4128aadSBjoern A. Zeeb ht_info->mcs.rx_mask[0] = 0xFF; 85*a4128aadSBjoern A. Zeeb ht_info->mcs.rx_mask[1] = 0x00; 86*a4128aadSBjoern A. Zeeb ht_info->mcs.rx_mask[2] = 0x00; 87*a4128aadSBjoern A. Zeeb 88*a4128aadSBjoern A. Zeeb if (rx_chains >= 2) 89*a4128aadSBjoern A. Zeeb ht_info->mcs.rx_mask[1] = 0xFF; 90*a4128aadSBjoern A. Zeeb if (rx_chains >= 3) 91*a4128aadSBjoern A. Zeeb ht_info->mcs.rx_mask[2] = 0xFF; 92*a4128aadSBjoern A. Zeeb 93*a4128aadSBjoern A. Zeeb if (cfg->ht_params->ht_greenfield_support) 94*a4128aadSBjoern A. Zeeb ht_info->cap |= IEEE80211_HT_CAP_GRN_FLD; 95*a4128aadSBjoern A. Zeeb ht_info->cap |= IEEE80211_HT_CAP_SGI_20; 96*a4128aadSBjoern A. Zeeb 97*a4128aadSBjoern A. Zeeb max_bit_rate = MAX_BIT_RATE_20_MHZ; 98*a4128aadSBjoern A. Zeeb 99*a4128aadSBjoern A. Zeeb if (cfg->ht_params->ht40_bands & BIT(band)) { 100*a4128aadSBjoern A. Zeeb ht_info->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40; 101*a4128aadSBjoern A. Zeeb ht_info->cap |= IEEE80211_HT_CAP_SGI_40; 102*a4128aadSBjoern A. Zeeb max_bit_rate = MAX_BIT_RATE_40_MHZ; 103*a4128aadSBjoern A. Zeeb } 104*a4128aadSBjoern A. Zeeb 105*a4128aadSBjoern A. Zeeb /* Highest supported Rx data rate */ 106*a4128aadSBjoern A. Zeeb max_bit_rate *= rx_chains; 107*a4128aadSBjoern A. Zeeb WARN_ON(max_bit_rate & ~IEEE80211_HT_MCS_RX_HIGHEST_MASK); 108*a4128aadSBjoern A. Zeeb ht_info->mcs.rx_highest = cpu_to_le16(max_bit_rate); 109*a4128aadSBjoern A. Zeeb 110*a4128aadSBjoern A. Zeeb /* Tx MCS capabilities */ 111*a4128aadSBjoern A. Zeeb ht_info->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; 112*a4128aadSBjoern A. Zeeb if (tx_chains != rx_chains) { 113*a4128aadSBjoern A. Zeeb ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_RX_DIFF; 114*a4128aadSBjoern A. Zeeb ht_info->mcs.tx_params |= ((tx_chains - 1) << 115*a4128aadSBjoern A. Zeeb IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT); 116*a4128aadSBjoern A. Zeeb } 117*a4128aadSBjoern A. Zeeb } 118*a4128aadSBjoern A. Zeeb IWL_EXPORT_SYMBOL(iwl_init_ht_hw_capab); 119