summaryrefslogtreecommitdiff
path: root/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c')
-rw-r--r--drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c176
1 files changed, 108 insertions, 68 deletions
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c
index 6d19de3058d2..720193d16539 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c
@@ -1,65 +1,9 @@
-/******************************************************************************
- *
- * This file is provided under a dual BSD/GPLv2 license. When using or
- * redistributing this file, you may do so under either license.
- *
- * GPL LICENSE SUMMARY
- *
- * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
- * Copyright(c) 2016 - 2017 Intel Deutschland GmbH
- * Copyright(c) 2018 - 2019 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
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * The full GNU General Public License is included in this distribution
- * in the file called COPYING.
- *
- * Contact Information:
- * Intel Linux Wireless <linuxwifi@intel.com>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *
- * BSD LICENSE
- *
- * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
- * Copyright(c) 2016 - 2017 Intel Deutschland GmbH
- * Copyright(c) 2018 - 2019 Intel Corporation
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name Intel Corporation nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *****************************************************************************/
+// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
+/*
+ * Copyright (C) 2005-2014, 2018-2020 Intel Corporation
+ * Copyright (C) 2013-2015 Intel Mobile Communications GmbH
+ * Copyright (C) 2016-2017 Intel Deutschland GmbH
+ */
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/export.h>
@@ -107,9 +51,11 @@ enum ext_nvm_offsets {
/* NVM SW-Section offset (in words) definitions */
NVM_VERSION_EXT_NVM = 0,
+ N_HW_ADDRS_FAMILY_8000 = 3,
+
+ /* NVM PHY_SKU-Section offset (in words) definitions */
RADIO_CFG_FAMILY_EXT_NVM = 0,
SKU_FAMILY_8000 = 2,
- N_HW_ADDRS_FAMILY_8000 = 3,
/* NVM REGULATORY -Section offset (in words) definitions */
NVM_CHANNELS_EXTENDED = 0,
@@ -166,6 +112,7 @@ static const u16 iwl_uhb_nvm_channels[] = {
#define IWL_NVM_NUM_CHANNELS_EXT ARRAY_SIZE(iwl_ext_nvm_channels)
#define IWL_NVM_NUM_CHANNELS_UHB ARRAY_SIZE(iwl_uhb_nvm_channels)
#define NUM_2GHZ_CHANNELS 14
+#define NUM_5GHZ_CHANNELS 37
#define FIRST_2GHZ_HT_MINUS 5
#define LAST_2GHZ_HT_PLUS 9
#define N_HW_ADDR_MASK 0xF
@@ -389,6 +336,10 @@ static u32 iwl_get_channel_flags(u8 ch_num, int ch_idx, enum nl80211_band band,
static enum nl80211_band iwl_nl80211_band_from_channel_idx(int ch_idx)
{
+ if (ch_idx >= NUM_2GHZ_CHANNELS + NUM_5GHZ_CHANNELS) {
+ return NL80211_BAND_6GHZ;
+ }
+
if (ch_idx >= NUM_2GHZ_CHANNELS)
return NL80211_BAND_5GHZ;
return NL80211_BAND_2GHZ;
@@ -480,6 +431,11 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg,
else
channel->flags = 0;
+ /* TODO: Don't put limitations on UHB devices as we still don't
+ * have NVM for them
+ */
+ if (cfg->uhb_supported)
+ channel->flags = 0;
iwl_nvm_print_channel_flags(dev, IWL_DL_EEPROM,
channel->hw_value, ch_flags);
IWL_DEBUG_EEPROM(dev, "Ch. %d: %ddBm\n",
@@ -580,7 +536,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[] = {
{
.types_mask = BIT(NL80211_IFTYPE_STATION),
.he_cap = {
@@ -743,12 +699,82 @@ static struct ieee80211_sband_iftype_data iwl_he_capa[] = {
},
};
+static void iwl_init_he_6ghz_capa(struct iwl_trans *trans,
+ struct iwl_nvm_data *data,
+ struct ieee80211_supported_band *sband,
+ u8 tx_chains, u8 rx_chains)
+{
+ struct ieee80211_sta_ht_cap ht_cap;
+ struct ieee80211_sta_vht_cap vht_cap = {};
+ struct ieee80211_sband_iftype_data *iftype_data;
+ u16 he_6ghz_capa = 0;
+ u32 exp;
+ int i;
+
+ if (sband->band != NL80211_BAND_6GHZ)
+ return;
+
+ /* grab HT/VHT capabilities and calculate HE 6 GHz capabilities */
+ iwl_init_ht_hw_capab(trans, data, &ht_cap, NL80211_BAND_5GHZ,
+ tx_chains, rx_chains);
+ WARN_ON(!ht_cap.ht_supported);
+ iwl_init_vht_hw_capab(trans, data, &vht_cap, tx_chains, rx_chains);
+ WARN_ON(!vht_cap.vht_supported);
+
+ he_6ghz_capa |=
+ u16_encode_bits(ht_cap.ampdu_density,
+ IEEE80211_HE_6GHZ_CAP_MIN_MPDU_START);
+ exp = u32_get_bits(vht_cap.cap,
+ IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK);
+ he_6ghz_capa |=
+ u16_encode_bits(exp, IEEE80211_HE_6GHZ_CAP_MAX_AMPDU_LEN_EXP);
+ exp = u32_get_bits(vht_cap.cap, IEEE80211_VHT_CAP_MAX_MPDU_MASK);
+ he_6ghz_capa |=
+ u16_encode_bits(exp, IEEE80211_HE_6GHZ_CAP_MAX_MPDU_LEN);
+ /* we don't support extended_ht_cap_info anywhere, so no RD_RESPONDER */
+ if (vht_cap.cap & IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN)
+ he_6ghz_capa |= IEEE80211_HE_6GHZ_CAP_TX_ANTPAT_CONS;
+ if (vht_cap.cap & IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN)
+ he_6ghz_capa |= IEEE80211_HE_6GHZ_CAP_RX_ANTPAT_CONS;
+
+ IWL_DEBUG_EEPROM(trans->dev, "he_6ghz_capa=0x%x\n", he_6ghz_capa);
+
+ /* we know it's writable - we set it before ourselves */
+ iftype_data = (void *)sband->iftype_data;
+ for (i = 0; i < sband->n_iftype_data; i++)
+ iftype_data[i].he_6ghz_capa.capa = cpu_to_le16(he_6ghz_capa);
+}
+
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;
+ struct ieee80211_sband_iftype_data *iftype_data;
+
+ /* should only initialize once */
+ if (WARN_ON(sband->iftype_data))
+ return;
+
+ BUILD_BUG_ON(sizeof(data->iftd.low) != sizeof(iwl_he_capa));
+ BUILD_BUG_ON(sizeof(data->iftd.high) != sizeof(iwl_he_capa));
+
+ switch (sband->band) {
+ case NL80211_BAND_2GHZ:
+ iftype_data = data->iftd.low;
+ break;
+ case NL80211_BAND_5GHZ:
+ case NL80211_BAND_6GHZ:
+ iftype_data = data->iftd.high;
+ break;
+ default:
+ WARN_ON(1);
+ return;
+ }
+
+ memcpy(iftype_data, iwl_he_capa, sizeof(iwl_he_capa));
+
+ sband->iftype_data = iftype_data;
sband->n_iftype_data = ARRAY_SIZE(iwl_he_capa);
/* If not 2x2, we need to indicate 1x1 in the Midamble RX Max NSTS */
@@ -756,14 +782,15 @@ static void iwl_init_he_hw_capab(struct iwl_trans *trans,
int i;
for (i = 0; i < sband->n_iftype_data; i++) {
- iwl_he_capa[i].he_cap.he_cap_elem.phy_cap_info[1] &=
+ iftype_data[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] &=
+ iftype_data[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] &=
+ iftype_data[i].he_cap.he_cap_elem.phy_cap_info[7] &=
~IEEE80211_HE_PHY_CAP7_MAX_NC_MASK;
}
}
+ iwl_init_he_6ghz_capa(trans, data, sband, tx_chains, rx_chains);
}
static void iwl_init_sbands(struct iwl_trans *trans,
@@ -806,6 +833,19 @@ static void iwl_init_sbands(struct iwl_trans *trans,
if (data->sku_cap_11ax_enable && !iwlwifi_mod_params.disable_11ax)
iwl_init_he_hw_capab(trans, data, sband, tx_chains, rx_chains);
+ /* 6GHz band. */
+ sband = &data->bands[NL80211_BAND_6GHZ];
+ sband->band = NL80211_BAND_6GHZ;
+ /* use the same rates as 5GHz band */
+ sband->bitrates = &iwl_cfg80211_rates[RATES_52_OFFS];
+ sband->n_bitrates = N_RATES_52;
+ n_used += iwl_init_sband_channels(data, sband, n_channels,
+ 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);
+ else
+ sband->n_channels = 0;
if (n_channels != n_used)
IWL_ERR_DEV(dev, "NVM: used only %d of %d channels\n",
n_used, n_channels);