summaryrefslogtreecommitdiff
path: root/drivers/net/wireless
diff options
context:
space:
mode:
authorKalle Valo <kvalo@codeaurora.org>2021-10-28 16:29:15 +0300
committerKalle Valo <kvalo@codeaurora.org>2021-10-28 16:29:15 +0300
commit2619f904b25cd056fba9b4694c57647d6782b1af (patch)
tree64a5efbc781b33c492c27d0b67e6328ffe7553b6 /drivers/net/wireless
parent89f8765a11d8df49296d92c404067f9b5c58ee26 (diff)
parentcbaa6aeedee5f92dafa5982eceea2a1f98ce4f7d (diff)
Merge tag 'iwlwifi-next-for-kalle-2021-10-28' of git://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi/iwlwifi-next
iwlwifi patches for v5.16 * Support a new ACPI table revision; * Improvements in the device selection code; * New HW support; * Some fixes in the Geographic SAR implementation; * Support for WiFi 6E enablement via BIOS; * Support FW API version 67; * Improve debugging support; * Some fixes in session protection; * Some other small fixes, clean-ups and improvements. # gpg: Signature made Thu 28 Oct 2021 12:11:27 PM EEST # gpg: using RSA key 1772CD7E06F604F5A6EBCB26A1479CA21A3CC5FA # gpg: Good signature from "Luciano Roth Coelho (Luca) <luca@coelho.fi>" [full] # gpg: aka "Luciano Roth Coelho (Intel) <luciano.coelho@intel.com>" [full]
Diffstat (limited to 'drivers/net/wireless')
-rw-r--r--drivers/net/wireless/intel/iwlwifi/cfg/22000.c2
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/acpi.c150
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/acpi.h40
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/api/d3.h43
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/api/debug.h17
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h10
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/api/phy.h6
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/api/power.h55
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/api/sta.h2
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/file.h2
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/runtime.h2
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/uefi.h5
-rw-r--r--drivers/net/wireless/intel/iwlwifi/iwl-csr.h1
-rw-r--r--drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c92
-rw-r--r--drivers/net/wireless/intel/iwlwifi/iwl-io.c46
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/d3.c357
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/fw.c72
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c6
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c67
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/mvm.h4
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/nvm.c5
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/ops.c10
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/scan.c8
-rw-r--r--drivers/net/wireless/intel/iwlwifi/pcie/drv.c149
-rw-r--r--drivers/net/wireless/intel/iwlwifi/pcie/rx.c9
-rw-r--r--drivers/net/wireless/intel/iwlwifi/pcie/trans.c45
26 files changed, 804 insertions, 401 deletions
diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c
index 0f18ff990a9c..1572097bccf1 100644
--- a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c
+++ b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c
@@ -9,7 +9,7 @@
#include "iwl-prph.h"
/* Highest firmware API version supported */
-#define IWL_22000_UCODE_API_MAX 66
+#define IWL_22000_UCODE_API_MAX 67
/* Lowest firmware API version supported */
#define IWL_22000_UCODE_API_MIN 39
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c
index 1efac0b2a94d..bf431fa4fe81 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c
+++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c
@@ -184,9 +184,11 @@ int iwl_acpi_get_dsm_u32(struct device *dev, int rev, int func,
}
IWL_EXPORT_SYMBOL(iwl_acpi_get_dsm_u32);
-union acpi_object *iwl_acpi_get_wifi_pkg(struct device *dev,
- union acpi_object *data,
- int data_size, int *tbl_rev)
+union acpi_object *iwl_acpi_get_wifi_pkg_range(struct device *dev,
+ union acpi_object *data,
+ int min_data_size,
+ int max_data_size,
+ int *tbl_rev)
{
int i;
union acpi_object *wifi_pkg;
@@ -196,7 +198,7 @@ union acpi_object *iwl_acpi_get_wifi_pkg(struct device *dev,
* describes the domain, and one more entry, otherwise there's
* no point in reading it.
*/
- if (WARN_ON_ONCE(data_size < 2))
+ if (WARN_ON_ONCE(min_data_size < 2 || min_data_size > max_data_size))
return ERR_PTR(-EINVAL);
/*
@@ -222,7 +224,8 @@ union acpi_object *iwl_acpi_get_wifi_pkg(struct device *dev,
/* skip entries that are not a package with the right size */
if (wifi_pkg->type != ACPI_TYPE_PACKAGE ||
- wifi_pkg->package.count != data_size)
+ wifi_pkg->package.count < min_data_size ||
+ wifi_pkg->package.count > max_data_size)
continue;
domain = &wifi_pkg->package.elements[0];
@@ -236,7 +239,7 @@ union acpi_object *iwl_acpi_get_wifi_pkg(struct device *dev,
found:
return wifi_pkg;
}
-IWL_EXPORT_SYMBOL(iwl_acpi_get_wifi_pkg);
+IWL_EXPORT_SYMBOL(iwl_acpi_get_wifi_pkg_range);
int iwl_acpi_get_tas(struct iwl_fw_runtime *fwrt,
__le32 *block_list_array,
@@ -707,49 +710,103 @@ int iwl_sar_get_wgds_table(struct iwl_fw_runtime *fwrt)
{
union acpi_object *wifi_pkg, *data;
int i, j, k, ret, tbl_rev;
- int idx = 1; /* start from one to skip the domain */
- u8 num_bands;
+ u8 num_bands, num_profiles;
+ static const struct {
+ u8 revisions;
+ u8 bands;
+ u8 profiles;
+ u8 min_profiles;
+ } rev_data[] = {
+ {
+ .revisions = BIT(3),
+ .bands = ACPI_GEO_NUM_BANDS_REV2,
+ .profiles = ACPI_NUM_GEO_PROFILES_REV3,
+ .min_profiles = 3,
+ },
+ {
+ .revisions = BIT(2),
+ .bands = ACPI_GEO_NUM_BANDS_REV2,
+ .profiles = ACPI_NUM_GEO_PROFILES,
+ },
+ {
+ .revisions = BIT(0) | BIT(1),
+ .bands = ACPI_GEO_NUM_BANDS_REV0,
+ .profiles = ACPI_NUM_GEO_PROFILES,
+ },
+ };
+ int idx;
+ /* start from one to skip the domain */
+ int entry_idx = 1;
+
+ BUILD_BUG_ON(ACPI_NUM_GEO_PROFILES_REV3 != IWL_NUM_GEO_PROFILES_V3);
+ BUILD_BUG_ON(ACPI_NUM_GEO_PROFILES != IWL_NUM_GEO_PROFILES);
data = iwl_acpi_get_object(fwrt->dev, ACPI_WGDS_METHOD);
if (IS_ERR(data))
return PTR_ERR(data);
- /* start by trying to read revision 2 */
- wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data,
- ACPI_WGDS_WIFI_DATA_SIZE_REV2,
- &tbl_rev);
- if (!IS_ERR(wifi_pkg)) {
- if (tbl_rev != 2) {
- ret = PTR_ERR(wifi_pkg);
- goto out_free;
- }
-
- num_bands = ACPI_GEO_NUM_BANDS_REV2;
-
- goto read_table;
- }
-
- /* then try revision 0 (which is the same as 1) */
- wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data,
- ACPI_WGDS_WIFI_DATA_SIZE_REV0,
- &tbl_rev);
- if (!IS_ERR(wifi_pkg)) {
- if (tbl_rev != 0 && tbl_rev != 1) {
- ret = PTR_ERR(wifi_pkg);
- goto out_free;
+ /* read the highest revision we understand first */
+ for (idx = 0; idx < ARRAY_SIZE(rev_data); idx++) {
+ /* min_profiles != 0 requires num_profiles header */
+ u32 hdr_size = 1 + !!rev_data[idx].min_profiles;
+ u32 profile_size = ACPI_GEO_PER_CHAIN_SIZE *
+ rev_data[idx].bands;
+ u32 max_size = hdr_size + profile_size * rev_data[idx].profiles;
+ u32 min_size;
+
+ if (!rev_data[idx].min_profiles)
+ min_size = max_size;
+ else
+ min_size = hdr_size +
+ profile_size * rev_data[idx].min_profiles;
+
+ wifi_pkg = iwl_acpi_get_wifi_pkg_range(fwrt->dev, data,
+ min_size, max_size,
+ &tbl_rev);
+ if (!IS_ERR(wifi_pkg)) {
+ if (!(BIT(tbl_rev) & rev_data[idx].revisions))
+ continue;
+
+ num_bands = rev_data[idx].bands;
+ num_profiles = rev_data[idx].profiles;
+
+ if (rev_data[idx].min_profiles) {
+ /* read header that says # of profiles */
+ union acpi_object *entry;
+
+ entry = &wifi_pkg->package.elements[entry_idx];
+ entry_idx++;
+ if (entry->type != ACPI_TYPE_INTEGER ||
+ entry->integer.value > num_profiles) {
+ ret = -EINVAL;
+ goto out_free;
+ }
+ num_profiles = entry->integer.value;
+
+ /*
+ * this also validates >= min_profiles since we
+ * otherwise wouldn't have gotten the data when
+ * looking up in ACPI
+ */
+ if (wifi_pkg->package.count !=
+ min_size + profile_size * num_profiles) {
+ ret = -EINVAL;
+ goto out_free;
+ }
+ }
+ goto read_table;
}
-
- num_bands = ACPI_GEO_NUM_BANDS_REV0;
-
- goto read_table;
}
- ret = PTR_ERR(wifi_pkg);
+ if (idx < ARRAY_SIZE(rev_data))
+ ret = PTR_ERR(wifi_pkg);
+ else
+ ret = -ENOENT;
goto out_free;
read_table:
fwrt->geo_rev = tbl_rev;
- for (i = 0; i < ACPI_NUM_GEO_PROFILES; i++) {
+ for (i = 0; i < num_profiles; i++) {
for (j = 0; j < ACPI_GEO_NUM_BANDS_REV2; j++) {
union acpi_object *entry;
@@ -762,7 +819,8 @@ read_table:
fwrt->geo_profiles[i].bands[j].max =
fwrt->geo_profiles[i].bands[1].max;
} else {
- entry = &wifi_pkg->package.elements[idx++];
+ entry = &wifi_pkg->package.elements[entry_idx];
+ entry_idx++;
if (entry->type != ACPI_TYPE_INTEGER ||
entry->integer.value > U8_MAX) {
ret = -EINVAL;
@@ -779,7 +837,8 @@ read_table:
fwrt->geo_profiles[i].bands[j].chains[k] =
fwrt->geo_profiles[i].bands[1].chains[k];
} else {
- entry = &wifi_pkg->package.elements[idx++];
+ entry = &wifi_pkg->package.elements[entry_idx];
+ entry_idx++;
if (entry->type != ACPI_TYPE_INTEGER ||
entry->integer.value > U8_MAX) {
ret = -EINVAL;
@@ -803,10 +862,10 @@ IWL_EXPORT_SYMBOL(iwl_sar_get_wgds_table);
bool iwl_sar_geo_support(struct iwl_fw_runtime *fwrt)
{
/*
- * The GEO_TX_POWER_LIMIT command is not supported on earlier
- * firmware versions. Unfortunately, we don't have a TLV API
- * flag to rely on, so rely on the major version which is in
- * the first byte of ucode_ver. This was implemented
+ * The PER_CHAIN_LIMIT_OFFSET_CMD command is not supported on
+ * earlier firmware versions. Unfortunately, we don't have a
+ * TLV API flag to rely on, so rely on the major version which
+ * is in the first byte of ucode_ver. This was implemented
* initially on version 38 and then backported to 17. It was
* also backported to 29, but only for 7265D devices. The
* intention was to have it in 36 as well, but not all 8000
@@ -822,14 +881,15 @@ bool iwl_sar_geo_support(struct iwl_fw_runtime *fwrt)
IWL_EXPORT_SYMBOL(iwl_sar_geo_support);
int iwl_sar_geo_init(struct iwl_fw_runtime *fwrt,
- struct iwl_per_chain_offset *table, u32 n_bands)
+ struct iwl_per_chain_offset *table,
+ u32 n_bands, u32 n_profiles)
{
int i, j;
if (!iwl_sar_geo_support(fwrt))
return -EOPNOTSUPP;
- for (i = 0; i < ACPI_NUM_GEO_PROFILES; i++) {
+ for (i = 0; i < n_profiles; i++) {
for (j = 0; j < n_bands; j++) {
struct iwl_per_chain_offset *chain =
&table[i * n_bands + j];
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h
index 0822c6b15c43..4aaa8a6b071b 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h
@@ -29,6 +29,7 @@
#define ACPI_SAR_PROFILE_NUM 4
#define ACPI_NUM_GEO_PROFILES 3
+#define ACPI_NUM_GEO_PROFILES_REV3 8
#define ACPI_GEO_PER_CHAIN_SIZE 3
#define ACPI_SAR_NUM_CHAINS_REV0 2
@@ -59,13 +60,6 @@
#define ACPI_GEO_NUM_BANDS_REV2 3
#define ACPI_GEO_NUM_CHAINS 2
-#define ACPI_WGDS_WIFI_DATA_SIZE_REV0 (ACPI_NUM_GEO_PROFILES * \
- ACPI_GEO_NUM_BANDS_REV0 * \
- ACPI_GEO_PER_CHAIN_SIZE + 1)
-#define ACPI_WGDS_WIFI_DATA_SIZE_REV2 (ACPI_NUM_GEO_PROFILES * \
- ACPI_GEO_NUM_BANDS_REV2 * \
- ACPI_GEO_PER_CHAIN_SIZE + 1)
-
#define ACPI_WRDD_WIFI_DATA_SIZE 2
#define ACPI_SPLC_WIFI_DATA_SIZE 2
#define ACPI_ECKV_WIFI_DATA_SIZE 2
@@ -115,6 +109,7 @@ enum iwl_dsm_funcs_rev_0 {
DSM_FUNC_QUERY = 0,
DSM_FUNC_DISABLE_SRD = 1,
DSM_FUNC_ENABLE_INDONESIA_5G2 = 2,
+ DSM_FUNC_ENABLE_6E = 3,
DSM_FUNC_11AX_ENABLEMENT = 6,
DSM_FUNC_ENABLE_UNII4_CHAN = 7,
DSM_FUNC_ACTIVATE_CHANNEL = 8
@@ -159,10 +154,11 @@ int iwl_acpi_get_dsm_u8(struct device *dev, int rev, int func,
int iwl_acpi_get_dsm_u32(struct device *dev, int rev, int func,
const guid_t *guid, u32 *value);
-union acpi_object *iwl_acpi_get_wifi_pkg(struct device *dev,
- union acpi_object *data,
- int data_size, int *tbl_rev);
-
+union acpi_object *iwl_acpi_get_wifi_pkg_range(struct device *dev,
+ union acpi_object *data,
+ int min_data_size,
+ int max_data_size,
+ int *tbl_rev);
/**
* iwl_acpi_get_mcc - read MCC from ACPI, if available
*
@@ -199,7 +195,8 @@ int iwl_sar_get_wgds_table(struct iwl_fw_runtime *fwrt);
bool iwl_sar_geo_support(struct iwl_fw_runtime *fwrt);
int iwl_sar_geo_init(struct iwl_fw_runtime *fwrt,
- struct iwl_per_chain_offset *table, u32 n_bands);
+ struct iwl_per_chain_offset *table,
+ u32 n_bands, u32 n_profiles);
int iwl_acpi_get_tas(struct iwl_fw_runtime *fwrt, __le32 *block_list_array,
int *block_list_size);
@@ -231,10 +228,11 @@ static inline int iwl_acpi_get_dsm_u32(struct device *dev, int rev, int func,
return -ENOENT;
}
-static inline union acpi_object *iwl_acpi_get_wifi_pkg(struct device *dev,
- union acpi_object *data,
- int data_size,
- int *tbl_rev)
+static inline union acpi_object *
+iwl_acpi_get_wifi_pkg_range(struct device *dev,
+ union acpi_object *data,
+ int min_data_size, int max_data_size,
+ int *tbl_rev)
{
return ERR_PTR(-ENOENT);
}
@@ -294,4 +292,14 @@ static inline __le32 iwl_acpi_get_lari_config_bitmap(struct iwl_fw_runtime *fwrt
}
#endif /* CONFIG_ACPI */
+
+static inline union acpi_object *
+iwl_acpi_get_wifi_pkg(struct device *dev,
+ union acpi_object *data,
+ int data_size, int *tbl_rev)
+{
+ return iwl_acpi_get_wifi_pkg_range(dev, data, data_size, data_size,
+ tbl_rev);
+}
+
#endif /* __iwl_fw_acpi__ */
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h b/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h
index e199d1813a61..1503119ea910 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h
@@ -693,49 +693,6 @@ struct iwl_wowlan_status_v9 {
u8 wake_packet[]; /* can be truncated from _length to _bufsize */
} __packed; /* WOWLAN_STATUSES_RSP_API_S_VER_9 */
-/**
- * struct iwl_wowlan_status - WoWLAN status
- * @gtk: GTK data
- * @igtk: IGTK data
- * @bigtk: BIGTK data
- * @replay_ctr: GTK rekey replay counter
- * @pattern_number: number of the matched pattern
- * @non_qos_seq_ctr: non-QoS sequence counter to use next
- * @qos_seq_ctr: QoS sequence counters to use next
- * @wakeup_reasons: wakeup reasons, see &enum iwl_wowlan_wakeup_reason
- * @num_of_gtk_rekeys: number of GTK rekeys
- * @tid_tear_down: bitmap of TIDs torn down
- * @reserved: reserved
- * @received_beacons: number of received beacons
- * @wake_packet_length: wakeup packet length
- * @wake_packet_bufsize: wakeup packet buffer size
- * @tid_tear_down: bit mask of tids whose BA sessions were closed
- * in suspend state
- * @wake_packet: wakeup packet
- */
-struct iwl_wowlan_status {
- struct iwl_wowlan_gtk_status gtk[1];
- struct iwl_wowlan_igtk_status igtk[1];
- struct iwl_wowlan_igtk_status bigtk[WOWLAN_IGTK_KEYS_NUM];
- __le64 replay_ctr;
- __le16 pattern_number;
- __le16 non_qos_seq_ctr;
- __le16 qos_seq_ctr[8];
- __le32 wakeup_reasons;
- __le32 num_of_gtk_rekeys;
- u8 tid_tear_down;
- u8 reserved[3];
- __le32 received_beacons;
- __le32 wake_packet_length;
- __le32 wake_packet_bufsize;
- u8 wake_packet[]; /* can be truncated from _length to _bufsize */
-} __packed; /* WOWLAN_STATUSES_API_S_VER_11 */
-
-static inline u8 iwlmvm_wowlan_gtk_idx(struct iwl_wowlan_gtk_status *gtk)
-{
- return gtk->key_flags & IWL_WOWLAN_GTK_IDX_MASK;
-}
-
/* TODO: NetDetect API */
#endif /* __iwl_fw_api_d3_h__ */
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/debug.h b/drivers/net/wireless/intel/iwlwifi/fw/api/debug.h
index 0abed12df2cb..029ae64bf2b2 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/api/debug.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/api/debug.h
@@ -380,6 +380,23 @@ struct iwl_dram_info {
} __packed; /* INIT_DRAM_FRAGS_ALLOCATIONS_S_VER_1 */
/**
+ * struct iwl_dbgc1_info - DBGC1 address and size
+ *
+ * Driver will fill the dbcg1 address and size at address based on config TLV.
+ *
+ * @first_word: all 0 set as identifier
+ * @dbgc1_add_lsb: LSB bits of DBGC1 physical address
+ * @dbgc1_add_msb: MSB bits of DBGC1 physical address
+ * @dbgc1_size: DBGC1 size
+*/
+struct iwl_dbgc1_info {
+ __le32 first_word;
+ __le32 dbgc1_add_lsb;
+ __le32 dbgc1_add_msb;
+ __le32 dbgc1_size;
+} __packed; /* INIT_DRAM_FRAGS_ALLOCATIONS_S_VER_1 */
+
+/**
* struct iwl_dbg_host_event_cfg_cmd
* @enabled_severities: enabled severities
*/
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h b/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h
index 6610d1234f74..d088c820b1a9 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
/*
- * Copyright (C) 2012-2014, 2018-2019 Intel Corporation
+ * Copyright (C) 2012-2014, 2018-2019, 2021 Intel Corporation
* Copyright (C) 2013-2015 Intel Mobile Communications GmbH
* Copyright (C) 2016-2017 Intel Deutschland GmbH
*/
@@ -39,9 +39,9 @@ enum iwl_mac_conf_subcmd_ids {
PROBE_RESPONSE_DATA_NOTIF = 0xFC,
/**
- * @CHANNEL_SWITCH_NOA_NOTIF: &struct iwl_channel_switch_noa_notif
+ * @CHANNEL_SWITCH_START_NOTIF: &struct iwl_channel_switch_start_notif
*/
- CHANNEL_SWITCH_NOA_NOTIF = 0xFF,
+ CHANNEL_SWITCH_START_NOTIF = 0xFF,
};
#define IWL_P2P_NOA_DESC_COUNT (2)
@@ -102,11 +102,11 @@ struct iwl_missed_vap_notif {
} __packed; /* MISSED_VAP_NTFY_API_S_VER_1 */
/**
- * struct iwl_channel_switch_noa_notif - Channel switch NOA notification
+ * struct iwl_channel_switch_start_notif - Channel switch start notification
*
* @id_and_color: ID and color of the MAC
*/
-struct iwl_channel_switch_noa_notif {
+struct iwl_channel_switch_start_notif {
__le32 id_and_color;
} __packed; /* CHANNEL_SWITCH_START_NTFY_API_S_VER_1 */
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/phy.h b/drivers/net/wireless/intel/iwlwifi/fw/api/phy.h
index d07a632f1af7..c04f2521fcb3 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/api/phy.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/api/phy.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
/*
- * Copyright (C) 2012-2014, 2019-2020 Intel Corporation
+ * Copyright (C) 2012-2014, 2019-2021 Intel Corporation
* Copyright (C) 2013-2015 Intel Mobile Communications GmbH
* Copyright (C) 2016-2017 Intel Deutschland GmbH
*/
@@ -29,9 +29,9 @@ enum iwl_phy_ops_subcmd_ids {
TEMP_REPORTING_THRESHOLDS_CMD = 0x04,
/**
- * @GEO_TX_POWER_LIMIT: &struct iwl_geo_tx_power_profiles_cmd
+ * @PER_CHAIN_LIMIT_OFFSET_CMD: &struct iwl_geo_tx_power_profiles_cmd
*/
- GEO_TX_POWER_LIMIT = 0x05,
+ PER_CHAIN_LIMIT_OFFSET_CMD = 0x05,
/**
* @PER_PLATFORM_ANT_GAIN_CMD: &struct iwl_ppag_table_cmd
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/power.h b/drivers/net/wireless/intel/iwlwifi/fw/api/power.h
index 86445385f072..4d671c878bb7 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/api/power.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/api/power.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
/*
- * Copyright (C) 2012-2014, 2018-2020 Intel Corporation
+ * Copyright (C) 2012-2014, 2018-2021 Intel Corporation
* Copyright (C) 2013-2014 Intel Mobile Communications GmbH
* Copyright (C) 2015-2017 Intel Deutschland GmbH
*/
@@ -378,9 +378,10 @@ struct iwl_dev_tx_power_cmd {
};
};
-#define IWL_NUM_GEO_PROFILES 3
-#define IWL_NUM_BANDS_PER_CHAIN_V1 2
-#define IWL_NUM_BANDS_PER_CHAIN_V2 3
+#define IWL_NUM_GEO_PROFILES 3
+#define IWL_NUM_GEO_PROFILES_V3 8
+#define IWL_NUM_BANDS_PER_CHAIN_V1 2
+#define IWL_NUM_BANDS_PER_CHAIN_V2 3
/**
* enum iwl_geo_per_chain_offset_operation - type of operation
@@ -390,10 +391,10 @@ struct iwl_dev_tx_power_cmd {
enum iwl_geo_per_chain_offset_operation {
IWL_PER_CHAIN_OFFSET_SET_TABLES,
IWL_PER_CHAIN_OFFSET_GET_CURRENT_TABLE,
-}; /* GEO_TX_POWER_LIMIT FLAGS TYPE */
+}; /* PER_CHAIN_OFFSET_OPERATION_E */
/**
- * struct iwl_per_chain_offset - embedded struct for GEO_TX_POWER_LIMIT.
+ * struct iwl_per_chain_offset - embedded struct for PER_CHAIN_LIMIT_OFFSET_CMD.
* @max_tx_power: maximum allowed tx power.
* @chain_a: tx power offset for chain a.
* @chain_b: tx power offset for chain b.
@@ -405,17 +406,17 @@ struct iwl_per_chain_offset {
} __packed; /* PER_CHAIN_LIMIT_OFFSET_PER_CHAIN_S_VER_1 */
/**
- * struct iwl_geo_tx_power_profile_cmd_v1 - struct for GEO_TX_POWER_LIMIT cmd.
+ * struct iwl_geo_tx_power_profile_cmd_v1 - struct for PER_CHAIN_LIMIT_OFFSET_CMD cmd.
* @ops: operations, value from &enum iwl_geo_per_chain_offset_operation
* @table: offset profile per band.
*/
struct iwl_geo_tx_power_profiles_cmd_v1 {
__le32 ops;
struct iwl_per_chain_offset table[IWL_NUM_GEO_PROFILES][IWL_NUM_BANDS_PER_CHAIN_V1];
-} __packed; /* GEO_TX_POWER_LIMIT_VER_1 */
+} __packed; /* PER_CHAIN_LIMIT_OFFSET_CMD_VER_1 */
/**
- * struct iwl_geo_tx_power_profile_cmd_v2 - struct for GEO_TX_POWER_LIMIT cmd.
+ * struct iwl_geo_tx_power_profile_cmd_v2 - struct for PER_CHAIN_LIMIT_OFFSET_CMD cmd.
* @ops: operations, value from &enum iwl_geo_per_chain_offset_operation
* @table: offset profile per band.
* @table_revision: BIOS table revision.
@@ -424,10 +425,10 @@ struct iwl_geo_tx_power_profiles_cmd_v2 {
__le32 ops;
struct iwl_per_chain_offset table[IWL_NUM_GEO_PROFILES][IWL_NUM_BANDS_PER_CHAIN_V1];
__le32 table_revision;
-} __packed; /* GEO_TX_POWER_LIMIT_VER_2 */
+} __packed; /* PER_CHAIN_LIMIT_OFFSET_CMD_VER_2 */
/**
- * struct iwl_geo_tx_power_profile_cmd_v3 - struct for GEO_TX_POWER_LIMIT cmd.
+ * struct iwl_geo_tx_power_profile_cmd_v3 - struct for PER_CHAIN_LIMIT_OFFSET_CMD cmd.
* @ops: operations, value from &enum iwl_geo_per_chain_offset_operation
* @table: offset profile per band.
* @table_revision: BIOS table revision.
@@ -436,21 +437,47 @@ struct iwl_geo_tx_power_profiles_cmd_v3 {
__le32 ops;
struct iwl_per_chain_offset table[IWL_NUM_GEO_PROFILES][IWL_NUM_BANDS_PER_CHAIN_V2];
__le32 table_revision;
-} __packed; /* GEO_TX_POWER_LIMIT_VER_3 */
+} __packed; /* PER_CHAIN_LIMIT_OFFSET_CMD_VER_3 */
+
+/**
+ * struct iwl_geo_tx_power_profile_cmd_v4 - struct for PER_CHAIN_LIMIT_OFFSET_CMD cmd.
+ * @ops: operations, value from &enum iwl_geo_per_chain_offset_operation
+ * @table: offset profile per band.
+ * @table_revision: BIOS table revision.
+ */
+struct iwl_geo_tx_power_profiles_cmd_v4 {
+ __le32 ops;
+ struct iwl_per_chain_offset table[IWL_NUM_GEO_PROFILES_V3][IWL_NUM_BANDS_PER_CHAIN_V1];
+ __le32 table_revision;
+} __packed; /* PER_CHAIN_LIMIT_OFFSET_CMD_VER_4 */
+
+/**
+ * struct iwl_geo_tx_power_profile_cmd_v5 - struct for PER_CHAIN_LIMIT_OFFSET_CMD cmd.
+ * @ops: operations, value from &enum iwl_geo_per_chain_offset_operation
+ * @table: offset profile per band.
+ * @table_revision: BIOS table revision.
+ */
+struct iwl_geo_tx_power_profiles_cmd_v5 {
+ __le32 ops;
+ struct iwl_per_chain_offset table[IWL_NUM_GEO_PROFILES_V3][IWL_NUM_BANDS_PER_CHAIN_V2];
+ __le32 table_revision;
+} __packed; /* PER_CHAIN_LIMIT_OFFSET_CMD_VER_5 */
union iwl_geo_tx_power_profiles_cmd {
struct iwl_geo_tx_power_profiles_cmd_v1 v1;
struct iwl_geo_tx_power_profiles_cmd_v2 v2;
struct iwl_geo_tx_power_profiles_cmd_v3 v3;
+ struct iwl_geo_tx_power_profiles_cmd_v4 v4;
+ struct iwl_geo_tx_power_profiles_cmd_v5 v5;
};
/**
- * struct iwl_geo_tx_power_profiles_resp - response to GEO_TX_POWER_LIMIT cmd
+ * struct iwl_geo_tx_power_profiles_resp - response to PER_CHAIN_LIMIT_OFFSET_CMD cmd
* @profile_idx: current geo profile in use
*/
struct iwl_geo_tx_power_profiles_resp {
__le32 profile_idx;
-} __packed; /* GEO_TX_POWER_LIMIT_RESP */
+} __packed; /* PER_CHAIN_LIMIT_OFFSET_RSP */
/**
* union iwl_ppag_table_cmd - union for all versions of PPAG command
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/sta.h b/drivers/net/wireless/intel/iwlwifi/fw/api/sta.h
index f1a3e14880e7..5edbe27c0922 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/api/sta.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/api/sta.h
@@ -28,6 +28,8 @@
* @STA_FLG_MAX_AGG_SIZE_256K: maximal size for A-MPDU (256k supported)
* @STA_FLG_MAX_AGG_SIZE_512K: maximal size for A-MPDU (512k supported)
* @STA_FLG_MAX_AGG_SIZE_1024K: maximal size for A-MPDU (1024k supported)
+ * @STA_FLG_MAX_AGG_SIZE_2M: maximal size for A-MPDU (2M supported)
+ * @STA_FLG_MAX_AGG_SIZE_4M: maximal size for A-MPDU (4M supported)
* @STA_FLG_AGG_MPDU_DENS_MSK: maximal MPDU density for Tx aggregation
* @STA_FLG_FAT_EN_MSK: support for channel width (for Tx). This flag is
* initialised by driver and can be updated by fw upon reception of
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/file.h b/drivers/net/wireless/intel/iwlwifi/fw/file.h
index 565918054ed1..3d572f5024bb 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/file.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/file.h
@@ -421,6 +421,7 @@ enum iwl_ucode_tlv_capa {
IWL_UCODE_TLV_CAPA_HIDDEN_6GHZ_SCAN = (__force iwl_ucode_tlv_capa_t)59,
IWL_UCODE_TLV_CAPA_BROADCAST_TWT = (__force iwl_ucode_tlv_capa_t)60,
IWL_UCODE_TLV_CAPA_COEX_HIGH_PRIO = (__force iwl_ucode_tlv_capa_t)61,
+ IWL_UCODE_TLV_CAPA_RFIM_SUPPORT = (__force iwl_ucode_tlv_capa_t)62,
/* set 2 */
IWL_UCODE_TLV_CAPA_EXTENDED_DTS_MEASURE = (__force iwl_ucode_tlv_capa_t)64,
@@ -454,7 +455,6 @@ enum iwl_ucode_tlv_capa {
IWL_UCODE_TLV_CAPA_PSC_CHAN_SUPPORT = (__force iwl_ucode_tlv_capa_t)98,
IWL_UCODE_TLV_CAPA_BIGTK_SUPPORT = (__force iwl_ucode_tlv_capa_t)100,
- IWL_UCODE_TLV_CAPA_RFIM_SUPPORT = (__force iwl_ucode_tlv_capa_t)102,
IWL_UCODE_TLV_CAPA_DRAM_FRAG_SUPPORT = (__force iwl_ucode_tlv_capa_t)104,
#ifdef __CHECKER__
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/runtime.h b/drivers/net/wireless/intel/iwlwifi/fw/runtime.h
index a569ce3c5e96..69799f1ed2c4 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/runtime.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/runtime.h
@@ -154,7 +154,7 @@ struct iwl_fw_runtime {
struct iwl_sar_profile sar_profiles[ACPI_SAR_PROFILE_NUM];
u8 sar_chain_a_profile;
u8 sar_chain_b_profile;
- struct iwl_geo_profile geo_profiles[ACPI_NUM_GEO_PROFILES];
+ struct iwl_geo_profile geo_profiles[ACPI_NUM_GEO_PROFILES_REV3];
u32 geo_rev;
union iwl_ppag_table_cmd ppag_table;
u32 ppag_ver;
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/uefi.h b/drivers/net/wireless/intel/iwlwifi/fw/uefi.h
index 45d0b36d79b5..d552c656ac9f 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/uefi.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/uefi.h
@@ -2,7 +2,8 @@
/*
* Copyright(c) 2021 Intel Corporation
*/
-
+#ifndef __iwl_fw_uefi__
+#define __iwl_fw_uefi__
#define IWL_UEFI_OEM_PNVM_NAME L"UefiCnvWlanOemSignedPnvm"
#define IWL_UEFI_REDUCED_POWER_NAME L"UefiCnvWlanReducedPower"
@@ -40,3 +41,5 @@ void *iwl_uefi_get_reduced_power(struct iwl_trans *trans, size_t *len)
return ERR_PTR(-EOPNOTSUPP);
}
#endif /* CONFIG_EFI */
+
+#endif /* __iwl_fw_uefi__ */
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-csr.h b/drivers/net/wireless/intel/iwlwifi/iwl-csr.h
index 2c4d70fb32fa..ff79a2ecb242 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-csr.h
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-csr.h
@@ -605,6 +605,7 @@ enum msix_hw_int_causes {
MSIX_HW_INT_CAUSES_REG_WAKEUP = BIT(1),
MSIX_HW_INT_CAUSES_REG_IML = BIT(1),
MSIX_HW_INT_CAUSES_REG_RESET_DONE = BIT(2),
+ MSIX_HW_INT_CAUSES_REG_SW_ERR_BZ = BIT(5),
MSIX_HW_INT_CAUSES_REG_CT_KILL = BIT(6),
MSIX_HW_INT_CAUSES_REG_RF_KILL = BIT(7),
MSIX_HW_INT_CAUSES_REG_PERIODIC = BIT(8),
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c
index f487cc8b9fe0..7ab98b419cc1 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c
@@ -284,13 +284,6 @@ static int iwl_dbg_tlv_config_set(struct iwl_trans *trans,
return -EINVAL;
}
- if (type != IWL_FW_INI_CONFIG_SET_TYPE_PERIPH_SCRATCH_HWM ||
- trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_AX210) {
- IWL_DEBUG_FW(trans,
- "WRT: Config set type %u is not supported\n", type);
- return -EINVAL;
- }
-
return iwl_dbg_tlv_add(tlv, &trans->dbg.time_point[tp].config_list);
}
@@ -812,18 +805,84 @@ static void iwl_dbg_tlv_apply_config(struct iwl_fw_runtime *fwrt,
list_for_each_entry(node, config_list, list) {
struct iwl_fw_ini_conf_set_tlv *config_list = (void *)node->tlv.data;
+ u32 count, address, value;
+ u32 len = (le32_to_cpu(node->tlv.length) - sizeof(*config_list)) / 8;
u32 type = le32_to_cpu(config_list->set_type);
+ u32 offset = le32_to_cpu(config_list->addr_offset);
switch (type) {
- case IWL_FW_INI_CONFIG_SET_TYPE_PERIPH_SCRATCH_HWM: {
- u32 debug_token_config =
- le32_to_cpu(config_list->addr_val[0].value);
-
- IWL_DEBUG_FW(fwrt, "WRT: Setting HWM debug token config: %u\n",
- debug_token_config);
- fwrt->trans->dbg.ucode_preset = debug_token_config;
- break;
+ case IWL_FW_INI_CONFIG_SET_TYPE_DEVICE_PERIPHERY_MAC: {
+ if (!iwl_trans_grab_nic_access(fwrt->trans)) {
+ IWL_DEBUG_FW(fwrt, "WRT: failed to get nic access\n");
+ IWL_DEBUG_FW(fwrt, "WRT: skipping MAC PERIPHERY config\n");
+ continue;
+ }
+ IWL_DEBUG_FW(fwrt, "WRT: MAC PERIPHERY config len: len %u\n", len);
+ for (count = 0; count < len; count++) {
+ address = le32_to_cpu(config_list->addr_val[count].address);
+ value = le32_to_cpu(config_list->addr_val[count].value);
+ iwl_trans_write_prph(fwrt->trans, address + offset, value);
+ }
+ iwl_trans_release_nic_access(fwrt->trans);
+ break;
+ }
+ case IWL_FW_INI_CONFIG_SET_TYPE_DEVICE_MEMORY: {
+ for (count = 0; count < len; count++) {
+ address = le32_to_cpu(config_list->addr_val[count].address);
+ value = le32_to_cpu(config_list->addr_val[count].value);
+ iwl_trans_write_mem32(fwrt->trans, address + offset, value);
+ IWL_DEBUG_FW(fwrt, "WRT: DEV_MEM: count %u, add: %u val: %u\n",
+ count, address, value);
+ }
+ break;
+ }
+ case IWL_FW_INI_CONFIG_SET_TYPE_CSR: {
+ for (count = 0; count < len; count++) {
+ address = le32_to_cpu(config_list->addr_val[count].address);
+ value = le32_to_cpu(config_list->addr_val[count].value);
+ iwl_write32(fwrt->trans, address + offset, value);
+ IWL_DEBUG_FW(fwrt, "WRT: CSR: count %u, add: %u val: %u\n",
+ count, address, value);
+ }
+ break;
+ }
+ case IWL_FW_INI_CONFIG_SET_TYPE_DBGC_DRAM_ADDR: {
+ struct iwl_dbgc1_info dram_info = {};
+ struct iwl_dram_data *frags = &fwrt->trans->dbg.fw_mon_ini[1].frags[0];
+ __le64 dram_base_addr = cpu_to_le64(frags->physical);
+ __le32 dram_size = cpu_to_le32(frags->size);
+ u64 dram_addr = le64_to_cpu(dram_base_addr);
+ u32 ret;
+
+ IWL_DEBUG_FW(fwrt, "WRT: dram_base_addr 0x%016llx, dram_size 0x%x\n",
+ dram_base_addr, dram_size);
+ IWL_DEBUG_FW(fwrt, "WRT: config_list->addr_offset: %u\n",
+ le32_to_cpu(config_list->addr_offset));
+ for (count = 0; count < len; count++) {
+ address = le32_to_cpu(config_list->addr_val[count].address);
+ dram_info.dbgc1_add_lsb =
+ cpu_to_le32((dram_addr & 0x00000000FFFFFFFFULL) + 0x400);
+ dram_info.dbgc1_add_msb =
+ cpu_to_le32((dram_addr & 0xFFFFFFFF00000000ULL) >> 32);
+ dram_info.dbgc1_size = cpu_to_le32(le32_to_cpu(dram_size) - 0x400);
+ ret = iwl_trans_write_mem(fwrt->trans,
+ address + offset, &dram_info, 4);
+ if (ret) {
+ IWL_ERR(fwrt, "Failed to write dram_info to HW_SMEM\n");
+ break;
+ }
}
+ break;
+ }
+ case IWL_FW_INI_CONFIG_SET_TYPE_PERIPH_SCRATCH_HWM: {
+ u32 debug_token_config =
+ le32_to_cpu(config_list->addr_val[0].value);
+
+ IWL_DEBUG_FW(fwrt, "WRT: Setting HWM debug token config: %u\n",
+ debug_token_config);
+ fwrt->trans->dbg.ucode_preset = debug_token_config;
+ break;
+ }
default:
break;
}
@@ -1229,6 +1288,7 @@ void _iwl_dbg_tlv_time_point(struct iwl_fw_runtime *fwrt,
case IWL_FW_INI_TIME_POINT_AFTER_ALIVE:
iwl_dbg_tlv_apply_buffers(fwrt);
iwl_dbg_tlv_send_hcmds(fwrt, hcmd_list);
+ iwl_dbg_tlv_apply_config(fwrt, conf_list);
iwl_dbg_tlv_tp_trigger(fwrt, sync, trig_list, tp_data, NULL);
break;
case IWL_FW_INI_TIME_POINT_PERIODIC:
@@ -1239,11 +1299,13 @@ void _iwl_dbg_tlv_time_point(struct iwl_fw_runtime *fwrt,
case IWL_FW_INI_TIME_POINT_MISSED_BEACONS:
case IWL_FW_INI_TIME_POINT_FW_DHC_NOTIFICATION:
iwl_dbg_tlv_send_hcmds(fwrt, hcmd_list);
+ iwl_dbg_tlv_apply_config(fwrt, conf_list);
iwl_dbg_tlv_tp_trigger(fwrt, sync, trig_list, tp_data,
iwl_dbg_tlv_check_fw_pkt);
break;
default:
iwl_dbg_tlv_send_hcmds(fwrt, hcmd_list);
+ iwl_dbg_tlv_apply_config(fwrt, conf_list);
iwl_dbg_tlv_tp_trigger(fwrt, sync, trig_list, tp_data, NULL);
break;
}
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-io.c b/drivers/net/wireless/intel/iwlwifi/iwl-io.c
index 6e96ee5bc261..46917b4216b3 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-io.c
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-io.c
@@ -398,6 +398,47 @@ int iwl_dump_fh(struct iwl_trans *trans, char **buf)
return 0;
}
+#define IWL_HOST_MON_BLOCK_PEMON 0x00
+#define IWL_HOST_MON_BLOCK_HIPM 0x22
+
+#define IWL_HOST_MON_BLOCK_PEMON_VEC0 0x00
+#define IWL_HOST_MON_BLOCK_PEMON_VEC1 0x01
+#define IWL_HOST_MON_BLOCK_PEMON_WFPM 0x06
+
+static void iwl_dump_host_monitor_block(struct iwl_trans *trans,
+ u32 block, u32 vec, u32 iter)
+{
+ int i;
+
+ IWL_ERR(trans, "Host monitor block 0x%x vector 0x%x\n", block, vec);
+ iwl_write32(trans, CSR_MONITOR_CFG_REG, (block << 8) | vec);
+ for (i = 0; i < iter; i++)
+ IWL_ERR(trans, " value [iter %d]: 0x%08x\n",
+ i, iwl_read32(trans, CSR_MONITOR_STATUS_REG));
+}
+
+static void iwl_dump_host_monitor(struct iwl_trans *trans)
+{
+ switch (trans->trans_cfg->device_family) {
+ case IWL_DEVICE_FAMILY_22000:
+ case IWL_DEVICE_FAMILY_AX210:
+ IWL_ERR(trans, "CSR_RESET = 0x%x\n",
+ iwl_read32(trans, CSR_RESET));
+ iwl_dump_host_monitor_block(trans, IWL_HOST_MON_BLOCK_PEMON,
+ IWL_HOST_MON_BLOCK_PEMON_VEC0, 15);
+ iwl_dump_host_monitor_block(trans, IWL_HOST_MON_BLOCK_PEMON,
+ IWL_HOST_MON_BLOCK_PEMON_VEC1, 15);
+ iwl_dump_host_monitor_block(trans, IWL_HOST_MON_BLOCK_PEMON,
+ IWL_HOST_MON_BLOCK_PEMON_WFPM, 15);
+ iwl_dump_host_monitor_block(trans, IWL_HOST_MON_BLOCK_HIPM,
+ IWL_HOST_MON_BLOCK_PEMON_VEC0, 1);
+ break;
+ default:
+ /* not supported yet */
+ return;
+ }
+}
+
int iwl_finish_nic_init(struct iwl_trans *trans)
{
const struct iwl_cfg_trans_params *cfg_trans = trans->trans_cfg;
@@ -433,9 +474,12 @@ int iwl_finish_nic_init(struct iwl_trans *trans)
* and accesses to uCode SRAM.
*/
err = iwl_poll_bit(trans, CSR_GP_CNTRL, poll_ready, poll_ready, 25000);
- if (err < 0)
+ if (err < 0) {
IWL_DEBUG_INFO(trans, "Failed to wake NIC\n");
+ iwl_dump_host_monitor(trans);
+ }
+
if (cfg_trans->bisr_workaround) {
/* ensure BISR shift has finished */
udelay(200);
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c
index d3013a51a509..a19f646a324f 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c
@@ -1379,12 +1379,49 @@ int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
/* converted data from the different status responses */
struct iwl_wowlan_status_data {
- u16 pattern_number;
- u16 qos_seq_ctr[8];
+ u64 replay_ctr;
+ u32 num_of_gtk_rekeys;
+ u32 received_beacons;
u32 wakeup_reasons;
u32 wake_packet_length;
u32 wake_packet_bufsize;
- const u8 *wake_packet;
+ u16 pattern_number;
+ u16 non_qos_seq_ctr;
+ u16 qos_seq_ctr[8];
+ u8 tid_tear_down;
+
+ struct {
+ /*
+ * We store both the TKIP and AES representations
+ * coming from the firmware because we decode the
+ * data from there before we iterate the keys and
+ * know which one we need.
+ */
+ struct {
+ struct ieee80211_key_seq seq[IWL_MAX_TID_COUNT];
+ } tkip, aes;
+ /* including RX MIC key for TKIP */
+ u8 key[WOWLAN_KEY_MAX_SIZE];
+ u8 len;
+ u8 flags;
+ } gtk;
+
+ struct {
+ /* Same as above */
+ struct {
+ struct ieee80211_key_seq seq[IWL_MAX_TID_COUNT];
+ u64 tx_pn;
+ } tkip, aes;
+ } ptk;
+
+ struct {
+ u64 ipn;
+ u8 key[WOWLAN_KEY_MAX_SIZE];
+ u8 len;
+ u8 flags;
+ } igtk;
+
+ u8 wake_packet[];
};
static void iwl_mvm_report_wakeup_reasons(struct iwl_mvm *mvm,
@@ -1540,77 +1577,90 @@ static void iwl_mvm_tkip_sc_to_seq(struct tkip_sc *sc,
seq->tkip.iv16 = le16_to_cpu(sc->iv16);
}
-static void iwl_mvm_set_aes_rx_seq(struct iwl_mvm *mvm, struct aes_sc *scs,
- struct ieee80211_sta *sta,
- struct ieee80211_key_conf *key)
+static void iwl_mvm_set_key_rx_seq_tids(struct ieee80211_key_conf *key,
+ struct ieee80211_key_seq *seq)
{
int tid;
- BUILD_BUG_ON(IWL_NUM_RSC != IEEE80211_NUM_TIDS);
+ for (tid = 0; tid < IWL_MAX_TID_COUNT; tid++)
+ ieee80211_set_key_rx_seq(key, tid, &seq[tid]);
+}
- if (sta && iwl_mvm_has_new_rx_api(mvm)) {
- struct iwl_mvm_sta *mvmsta;
- struct iwl_mvm_key_pn *ptk_pn;
+static void iwl_mvm_set_aes_ptk_rx_seq(struct iwl_mvm *mvm,
+ struct iwl_wowlan_status_data *status,
+ struct ieee80211_sta *sta,
+ struct ieee80211_key_conf *key)
+{
+ struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
+ struct iwl_mvm_key_pn *ptk_pn;
+ int tid;
- mvmsta = iwl_mvm_sta_from_mac80211(sta);
+ iwl_mvm_set_key_rx_seq_tids(key, status->ptk.aes.seq);
- rcu_read_lock();
- ptk_pn = rcu_dereference(mvmsta->ptk_pn[key->keyidx]);
- if (WARN_ON(!ptk_pn)) {
- rcu_read_unlock();
- return;
- }
+ if (!iwl_mvm_has_new_rx_api(mvm))
+ return;
- for (tid = 0; tid < IWL_MAX_TID_COUNT; tid++) {
- struct ieee80211_key_seq seq = {};
- int i;
- iwl_mvm_aes_sc_to_seq(&scs[tid], &seq);
- ieee80211_set_key_rx_seq(key, tid, &seq);
- for (i = 1; i < mvm->trans->num_rx_queues; i++)
- memcpy(ptk_pn->q[i].pn[tid],
- seq.ccmp.pn, IEEE80211_CCMP_PN_LEN);
- }
+ rcu_read_lock();
+ ptk_pn = rcu_dereference(mvmsta->ptk_pn[key->keyidx]);
+ if (WARN_ON(!ptk_pn)) {
rcu_read_unlock();
- } else {
- for (tid = 0; tid < IWL_NUM_RSC; tid++) {
- struct ieee80211_key_seq seq = {};
+ return;
+ }
- iwl_mvm_aes_sc_to_seq(&scs[tid], &seq);
- ieee80211_set_key_rx_seq(key, tid, &seq);
- }
+ for (tid = 0; tid < IWL_MAX_TID_COUNT; tid++) {
+ int i;
+
+ for (i = 1; i < mvm->trans->num_rx_queues; i++)
+ memcpy(ptk_pn->q[i].pn[tid],
+ status->ptk.aes.seq[tid].ccmp.pn,
+ IEEE80211_CCMP_PN_LEN);
}
+ rcu_read_unlock();
}
-static void iwl_mvm_set_tkip_rx_seq(struct tkip_sc *scs,
- struct ieee80211_key_conf *key)
+static void iwl_mvm_convert_key_counters(struct iwl_wowlan_status_data *status,
+ union iwl_all_tsc_rsc *sc)
{
- int tid;
+ int i;
- BUILD_BUG_ON(IWL_NUM_RSC != IEEE80211_NUM_TIDS);
+ BUILD_BUG_ON(IWL_MAX_TID_COUNT > IWL_MAX_TID_COUNT);
+ BUILD_BUG_ON(IWL_MAX_TID_COUNT > IWL_NUM_RSC);
- for (tid = 0; tid < IWL_NUM_RSC; tid++) {
- struct ieee80211_key_seq seq = {};
+ /* GTK RX counters */
+ for (i = 0; i < IWL_MAX_TID_COUNT; i++) {
+ iwl_mvm_tkip_sc_to_seq(&sc->tkip.multicast_rsc[i],
+ &status->gtk.tkip.seq[i]);
+ iwl_mvm_aes_sc_to_seq(&sc->aes.multicast_rsc[i],
+ &status->gtk.aes.seq[i]);
+ }
- iwl_mvm_tkip_sc_to_seq(&scs[tid], &seq);
- ieee80211_set_key_rx_seq(key, tid, &seq);
+ /* PTK TX counter */
+ status->ptk.tkip.tx_pn = (u64)le16_to_cpu(sc->tkip.tsc.iv16) |
+ ((u64)le32_to_cpu(sc->tkip.tsc.iv32) << 16);
+ status->ptk.aes.tx_pn = le64_to_cpu(sc->aes.tsc.pn);
+
+ /* PTK RX counters */
+ for (i = 0; i < IWL_MAX_TID_COUNT; i++) {
+ iwl_mvm_tkip_sc_to_seq(&sc->tkip.unicast_rsc[i],
+ &status->ptk.tkip.seq[i]);
+ iwl_mvm_aes_sc_to_seq(&sc->aes.unicast_rsc[i],
+ &status->ptk.aes.seq[i]);
}
}
static void iwl_mvm_set_key_rx_seq(struct iwl_mvm *mvm,
struct ieee80211_key_conf *key,
- struct iwl_wowlan_status *status)
+ struct iwl_wowlan_status_data *status)
{
- union iwl_all_tsc_rsc *rsc = &status->gtk[0].rsc.all_tsc_rsc;
-
switch (key->cipher) {
case WLAN_CIPHER_SUITE_CCMP:
case WLAN_CIPHER_SUITE_GCMP:
case WLAN_CIPHER_SUITE_GCMP_256:
- iwl_mvm_set_aes_rx_seq(mvm, rsc->aes.multicast_rsc, NULL, key);
+ iwl_mvm_set_key_rx_seq_tids(key, status->gtk.aes.seq);
break;
case WLAN_CIPHER_SUITE_TKIP:
- iwl_mvm_set_tkip_rx_seq(rsc->tkip.multicast_rsc, key);
+ iwl_mvm_set_key_rx_seq_tids(key, status->gtk.tkip.seq);
break;
default:
WARN_ON(1);
@@ -1619,7 +1669,7 @@ static void iwl_mvm_set_key_rx_seq(struct iwl_mvm *mvm,
struct iwl_mvm_d3_gtk_iter_data {
struct iwl_mvm *mvm;
- struct iwl_wowlan_status *status;
+ struct iwl_wowlan_status_data *status;
void *last_gtk;
u32 cipher;
bool find_phase, unhandled_cipher;
@@ -1633,6 +1683,7 @@ static void iwl_mvm_d3_update_keys(struct ieee80211_hw *hw,
void *_data)
{
struct iwl_mvm_d3_gtk_iter_data *data = _data;
+ struct iwl_wowlan_status_data *status = data->status;
if (data->unhandled_cipher)
return;
@@ -1661,10 +1712,6 @@ static void iwl_mvm_d3_update_keys(struct ieee80211_hw *hw,
* note that this assumes no TDLS sessions are active
*/
if (sta) {
- struct ieee80211_key_seq seq = {};
- union iwl_all_tsc_rsc *sc =
- &data->status->gtk[0].rsc.all_tsc_rsc;
-
if (data->find_phase)
return;
@@ -1672,16 +1719,12 @@ static void iwl_mvm_d3_update_keys(struct ieee80211_hw *hw,
case WLAN_CIPHER_SUITE_CCMP:
case WLAN_CIPHER_SUITE_GCMP:
case WLAN_CIPHER_SUITE_GCMP_256:
- iwl_mvm_set_aes_rx_seq(data->mvm, sc->aes.unicast_rsc,
- sta, key);
- atomic64_set(&key->tx_pn, le64_to_cpu(sc->aes.tsc.pn));
+ atomic64_set(&key->tx_pn, status->ptk.aes.tx_pn);
+ iwl_mvm_set_aes_ptk_rx_seq(data->mvm, status, sta, key);
break;
case WLAN_CIPHER_SUITE_TKIP:
- iwl_mvm_tkip_sc_to_seq(&sc->tkip.tsc, &seq);
- iwl_mvm_set_tkip_rx_seq(sc->tkip.unicast_rsc, key);
- atomic64_set(&key->tx_pn,
- (u64)seq.tkip.iv16 |
- ((u64)seq.tkip.iv32 << 16));
+ atomic64_set(&key->tx_pn, status->ptk.tkip.tx_pn);
+ iwl_mvm_set_key_rx_seq_tids(key, status->ptk.tkip.seq);
break;
}
@@ -1703,7 +1746,7 @@ static void iwl_mvm_d3_update_keys(struct ieee80211_hw *hw,
static bool iwl_mvm_setup_connection_keep(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
- struct iwl_wowlan_status *status)
+ struct iwl_wowlan_status_data *status)
{
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
struct iwl_mvm_d3_gtk_iter_data gtkdata = {
@@ -1717,7 +1760,7 @@ static bool iwl_mvm_setup_connection_keep(struct iwl_mvm *mvm,
if (!status || !vif->bss_conf.bssid)
return false;
- if (le32_to_cpu(status->wakeup_reasons) & disconnection_reasons)
+ if (status->wakeup_reasons & disconnection_reasons)
return false;
/* find last GTK that we used initially, if any */
@@ -1741,7 +1784,7 @@ static bool iwl_mvm_setup_connection_keep(struct iwl_mvm *mvm,
iwl_mvm_d3_update_keys, &gtkdata);
IWL_DEBUG_WOWLAN(mvm, "num of GTK rekeying %d\n",
- le32_to_cpu(status->num_of_gtk_rekeys));
+ status->num_of_gtk_rekeys);
if (status->num_of_gtk_rekeys) {
struct ieee80211_key_conf *key;
struct {
@@ -1750,36 +1793,32 @@ static bool iwl_mvm_setup_connection_keep(struct iwl_mvm *mvm,
} conf = {
.conf.cipher = gtkdata.cipher,
.conf.keyidx =
- iwlmvm_wowlan_gtk_idx(&status->gtk[0]),
+ status->gtk.flags & IWL_WOWLAN_GTK_IDX_MASK,
};
__be64 replay_ctr;
IWL_DEBUG_WOWLAN(mvm,
"Received from FW GTK cipher %d, key index %d\n",
conf.conf.cipher, conf.conf.keyidx);
+
+ BUILD_BUG_ON(WLAN_KEY_LEN_CCMP != WLAN_KEY_LEN_GCMP);
+ BUILD_BUG_ON(sizeof(conf.key) < WLAN_KEY_LEN_CCMP);
+ BUILD_BUG_ON(sizeof(conf.key) < WLAN_KEY_LEN_GCMP_256);
+ BUILD_BUG_ON(sizeof(conf.key) < WLAN_KEY_LEN_TKIP);
+ BUILD_BUG_ON(sizeof(conf.key) < sizeof(status->gtk.key));
+
+ memcpy(conf.conf.key, status->gtk.key, sizeof(status->gtk.key));
+
switch (gtkdata.cipher) {
case WLAN_CIPHER_SUITE_CCMP:
case WLAN_CIPHER_SUITE_GCMP:
- BUILD_BUG_ON(WLAN_KEY_LEN_CCMP != WLAN_KEY_LEN_GCMP);
- BUILD_BUG_ON(sizeof(conf.key) < WLAN_KEY_LEN_CCMP);
conf.conf.keylen = WLAN_KEY_LEN_CCMP;
- memcpy(conf.conf.key, status->gtk[0].key,
- WLAN_KEY_LEN_CCMP);
break;
case WLAN_CIPHER_SUITE_GCMP_256:
- BUILD_BUG_ON(sizeof(conf.key) < WLAN_KEY_LEN_GCMP_256);
conf.conf.keylen = WLAN_KEY_LEN_GCMP_256;
- memcpy(conf.conf.key, status->gtk[0].key,
- WLAN_KEY_LEN_GCMP_256);
break;
case WLAN_CIPHER_SUITE_TKIP:
- BUILD_BUG_ON(sizeof(conf.key) < WLAN_KEY_LEN_TKIP);
conf.conf.keylen = WLAN_KEY_LEN_TKIP;
- memcpy(conf.conf.key, status->gtk[0].key, 16);
- /* leave TX MIC key zeroed, we don't use it anyway */
- memcpy(conf.conf.key +
- NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY,
- status->gtk[0].tkip_mic_key, 8);
break;
}
@@ -1788,8 +1827,7 @@ static bool iwl_mvm_setup_connection_keep(struct iwl_mvm *mvm,
return false;
iwl_mvm_set_key_rx_seq(mvm, key, status);
- replay_ctr =
- cpu_to_be64(le64_to_cpu(status->replay_ctr));
+ replay_ctr = cpu_to_be64(status->replay_ctr);
ieee80211_gtk_rekey_notify(vif, vif->bss_conf.bssid,
(void *)&replay_ctr, GFP_KERNEL);
@@ -1800,7 +1838,7 @@ out:
WOWLAN_GET_STATUSES, 0) < 10) {
mvmvif->seqno_valid = true;
/* +0x10 because the set API expects next-to-use, not last-used */
- mvmvif->seqno = le16_to_cpu(status->non_qos_seq_ctr) + 0x10;
+ mvmvif->seqno = status->non_qos_seq_ctr + 0x10;
}
return true;
@@ -1808,13 +1846,13 @@ out:
/* Occasionally, templates would be nice. This is one of those times ... */
#define iwl_mvm_parse_wowlan_status_common(_ver) \
-static struct iwl_wowlan_status * \
+static struct iwl_wowlan_status_data * \
iwl_mvm_parse_wowlan_status_common_ ## _ver(struct iwl_mvm *mvm, \
- void *_data, int len) \
+ struct iwl_wowlan_status_ ##_ver *data,\
+ int len) \
{ \
- struct iwl_wowlan_status *status; \
- struct iwl_wowlan_status_ ##_ver *data = _data; \
- int data_size; \
+ struct iwl_wowlan_status_data *status; \
+ int data_size, i; \
\
if (len < sizeof(*data)) { \
IWL_ERR(mvm, "Invalid WoWLAN status response!\n"); \
@@ -1832,18 +1870,22 @@ iwl_mvm_parse_wowlan_status_common_ ## _ver(struct iwl_mvm *mvm, \
return ERR_PTR(-ENOMEM); \
\
/* copy all the common fields */ \
- status->replay_ctr = data->replay_ctr; \
- status->pattern_number = data->pattern_number; \
- status->non_qos_seq_ctr = data->non_qos_seq_ctr; \
- memcpy(status->qos_seq_ctr, data->qos_seq_ctr, \
- sizeof(status->qos_seq_ctr)); \
- status->wakeup_reasons = data->wakeup_reasons; \
- status->num_of_gtk_rekeys = data->num_of_gtk_rekeys; \
- status->received_beacons = data->received_beacons; \
- status->wake_packet_length = data->wake_packet_length; \
- status->wake_packet_bufsize = data->wake_packet_bufsize; \
+ status->replay_ctr = le64_to_cpu(data->replay_ctr); \
+ status->pattern_number = le16_to_cpu(data->pattern_number); \
+ status->non_qos_seq_ctr = le16_to_cpu(data->non_qos_seq_ctr); \
+ for (i = 0; i < 8; i++) \
+ status->qos_seq_ctr[i] = \
+ le16_to_cpu(data->qos_seq_ctr[i]); \
+ status->wakeup_reasons = le32_to_cpu(data->wakeup_reasons); \
+ status->num_of_gtk_rekeys = \
+ le32_to_cpu(data->num_of_gtk_rekeys); \
+ status->received_beacons = le32_to_cpu(data->received_beacons); \
+ status->wake_packet_length = \
+ le32_to_cpu(data->wake_packet_length); \
+ status->wake_packet_bufsize = \
+ le32_to_cpu(data->wake_packet_bufsize); \
memcpy(status->wake_packet, data->wake_packet, \
- le32_to_cpu(status->wake_packet_bufsize)); \
+ status->wake_packet_bufsize); \
\
return status; \
}
@@ -1852,10 +1894,49 @@ iwl_mvm_parse_wowlan_status_common(v6)
iwl_mvm_parse_wowlan_status_common(v7)
iwl_mvm_parse_wowlan_status_common(v9)
-static struct iwl_wowlan_status *
+static void iwl_mvm_convert_gtk(struct iwl_wowlan_status_data *status,
+ struct iwl_wowlan_gtk_status *data)
+{
+ BUILD_BUG_ON(sizeof(status->gtk.key) < sizeof(data->key));
+ BUILD_BUG_ON(NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY +
+ sizeof(data->tkip_mic_key) >
+ sizeof(status->gtk.key));
+
+ status->gtk.len = data->key_len;
+ status->gtk.flags = data->key_flags;
+
+ memcpy(status->gtk.key, data->key, sizeof(data->key));
+
+ /* if it's as long as the TKIP encryption key, copy MIC key */
+ if (status->gtk.len == NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY)
+ memcpy(status->gtk.key + NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY,
+ data->tkip_mic_key, sizeof(data->tkip_mic_key));
+}
+
+static void iwl_mvm_convert_igtk(struct iwl_wowlan_status_data *status,
+ struct iwl_wowlan_igtk_status *data)
+{
+ const u8 *ipn = data->ipn;
+
+ BUILD_BUG_ON(sizeof(status->igtk.key) < sizeof(data->key));
+
+ status->igtk.len = data->key_len;
+ status->igtk.flags = data->key_flags;
+
+ memcpy(status->igtk.key, data->key, sizeof(data->key));
+
+ status->igtk.ipn = ((u64)ipn[5] << 0) |
+ ((u64)ipn[4] << 8) |
+ ((u64)ipn[3] << 16) |
+ ((u64)ipn[2] << 24) |
+ ((u64)ipn[1] << 32) |
+ ((u64)ipn[0] << 40);
+}
+
+static struct iwl_wowlan_status_data *
iwl_mvm_send_wowlan_get_status(struct iwl_mvm *mvm, u8 sta_id)
{
- struct iwl_wowlan_status *status;
+ struct iwl_wowlan_status_data *status;
struct iwl_wowlan_get_status_cmd get_status_cmd = {
.sta_id = cpu_to_le32(sta_id),
};
@@ -1895,59 +1976,57 @@ iwl_mvm_send_wowlan_get_status(struct iwl_mvm *mvm, u8 sta_id)
IWL_UCODE_TLV_API_WOWLAN_KEY_MATERIAL)) {
struct iwl_wowlan_status_v6 *v6 = (void *)cmd.resp_pkt->data;
- status = iwl_mvm_parse_wowlan_status_common_v6(mvm,
- cmd.resp_pkt->data,
- len);
+ status = iwl_mvm_parse_wowlan_status_common_v6(mvm, v6, len);
if (IS_ERR(status))
goto out_free_resp;
BUILD_BUG_ON(sizeof(v6->gtk.decrypt_key) >
- sizeof(status->gtk[0].key));
- BUILD_BUG_ON(sizeof(v6->gtk.tkip_mic_key) >
- sizeof(status->gtk[0].tkip_mic_key));
+ sizeof(status->gtk.key));
+ BUILD_BUG_ON(NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY +
+ sizeof(v6->gtk.tkip_mic_key) >
+ sizeof(status->gtk.key));
/* copy GTK info to the right place */
- memcpy(status->gtk[0].key, v6->gtk.decrypt_key,
+ memcpy(status->gtk.key, v6->gtk.decrypt_key,
sizeof(v6->gtk.decrypt_key));
- memcpy(status->gtk[0].tkip_mic_key, v6->gtk.tkip_mic_key,
+ memcpy(status->gtk.key + NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY,
+ v6->gtk.tkip_mic_key,
sizeof(v6->gtk.tkip_mic_key));
- memcpy(&status->gtk[0].rsc, &v6->gtk.rsc,
- sizeof(status->gtk[0].rsc));
+
+ iwl_mvm_convert_key_counters(status, &v6->gtk.rsc.all_tsc_rsc);
/* hardcode the key length to 16 since v6 only supports 16 */
- status->gtk[0].key_len = 16;
+ status->gtk.len = 16;
/*
* The key index only uses 2 bits (values 0 to 3) and
* we always set bit 7 which means this is the
* currently used key.
*/
- status->gtk[0].key_flags = v6->gtk.key_index | BIT(7);
+ status->gtk.flags = v6->gtk.key_index | BIT(7);
} else if (notif_ver == 7) {
struct iwl_wowlan_status_v7 *v7 = (void *)cmd.resp_pkt->data;
- status = iwl_mvm_parse_wowlan_status_common_v7(mvm,
- cmd.resp_pkt->data,
- len);
+ status = iwl_mvm_parse_wowlan_status_common_v7(mvm, v7, len);
if (IS_ERR(status))
goto out_free_resp;
- status->gtk[0] = v7->gtk[0];
- status->igtk[0] = v7->igtk[0];
+ iwl_mvm_convert_key_counters(status, &v7->gtk[0].rsc.all_tsc_rsc);
+ iwl_mvm_convert_gtk(status, &v7->gtk[0]);
+ iwl_mvm_convert_igtk(status, &v7->igtk[0]);
} else if (notif_ver == 9 || notif_ver == 10 || notif_ver == 11) {
struct iwl_wowlan_status_v9 *v9 = (void *)cmd.resp_pkt->data;
/* these three command versions have same layout and size, the
* difference is only in a few not used (reserved) fields.
*/
- status = iwl_mvm_parse_wowlan_status_common_v9(mvm,
- cmd.resp_pkt->data,
- len);
+ status = iwl_mvm_parse_wowlan_status_common_v9(mvm, v9, len);
if (IS_ERR(status))
goto out_free_resp;
- status->gtk[0] = v9->gtk[0];
- status->igtk[0] = v9->igtk[0];
+ iwl_mvm_convert_key_counters(status, &v9->gtk[0].rsc.all_tsc_rsc);
+ iwl_mvm_convert_gtk(status, &v9->gtk[0]);
+ iwl_mvm_convert_igtk(status, &v9->igtk[0]);
status->tid_tear_down = v9->tid_tear_down;
} else {
@@ -1962,7 +2041,7 @@ out_free_resp:
return status;
}
-static struct iwl_wowlan_status *
+static struct iwl_wowlan_status_data *
iwl_mvm_get_wakeup_status(struct iwl_mvm *mvm, u8 sta_id)
{
u8 cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw, LONG_GROUP,
@@ -1987,29 +2066,17 @@ static bool iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm,
struct ieee80211_vif *vif)
{
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
- struct iwl_wowlan_status_data status;
- struct iwl_wowlan_status *fw_status;
+ struct iwl_wowlan_status_data *status;
int i;
bool keep;
struct iwl_mvm_sta *mvm_ap_sta;
- fw_status = iwl_mvm_get_wakeup_status(mvm, mvmvif->ap_sta_id);
- if (IS_ERR_OR_NULL(fw_status))
+ status = iwl_mvm_get_wakeup_status(mvm, mvmvif->ap_sta_id);
+ if (IS_ERR(status))
goto out_unlock;
IWL_DEBUG_WOWLAN(mvm, "wakeup reason 0x%x\n",
- le32_to_cpu(fw_status->wakeup_reasons));
-
- status.pattern_number = le16_to_cpu(fw_status->pattern_number);
- for (i = 0; i < 8; i++)
- status.qos_seq_ctr[i] =
- le16_to_cpu(fw_status->qos_seq_ctr[i]);
- status.wakeup_reasons = le32_to_cpu(fw_status->wakeup_reasons);
- status.wake_packet_length =
- le32_to_cpu(fw_status->wake_packet_length);
- status.wake_packet_bufsize =
- le32_to_cpu(fw_status->wake_packet_bufsize);
- status.wake_packet = fw_status->wake_packet;
+ status->wakeup_reasons);
/* still at hard-coded place 0 for D3 image */
mvm_ap_sta = iwl_mvm_sta_from_staid_protected(mvm, 0);
@@ -2017,7 +2084,7 @@ static bool iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm,
goto out_free;
for (i = 0; i < IWL_MAX_TID_COUNT; i++) {
- u16 seq = status.qos_seq_ctr[i];
+ u16 seq = status->qos_seq_ctr[i];
/* firmware stores last-used value, we store next value */
seq += 0x10;
mvm_ap_sta->tid_data[i].seq_number = seq;
@@ -2033,15 +2100,15 @@ static bool iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm,
/* now we have all the data we need, unlock to avoid mac80211 issues */
mutex_unlock(&mvm->mutex);
- iwl_mvm_report_wakeup_reasons(mvm, vif, &status);
+ iwl_mvm_report_wakeup_reasons(mvm, vif, status);
- keep = iwl_mvm_setup_connection_keep(mvm, vif, fw_status);
+ keep = iwl_mvm_setup_connection_keep(mvm, vif, status);
- kfree(fw_status);
+ kfree(status);
return keep;
out_free:
- kfree(fw_status);
+ kfree(status);
out_unlock:
mutex_unlock(&mvm->mutex);
return false;
@@ -2165,16 +2232,16 @@ static void iwl_mvm_query_netdetect_reasons(struct iwl_mvm *mvm,
.pattern_idx = -1,
};
struct cfg80211_wowlan_wakeup *wakeup_report = &wakeup;
+ struct iwl_wowlan_status_data *status;
struct iwl_mvm_nd_query_results query;
- struct iwl_wowlan_status *fw_status;
unsigned long matched_profiles;
u32 reasons = 0;
int i, n_matches, ret;
- fw_status = iwl_mvm_get_wakeup_status(mvm, IWL_MVM_INVALID_STA);
- if (!IS_ERR_OR_NULL(fw_status)) {
- reasons = le32_to_cpu(fw_status->wakeup_reasons);
- kfree(fw_status);
+ status = iwl_mvm_get_wakeup_status(mvm, IWL_MVM_INVALID_STA);
+ if (!IS_ERR(status)) {
+ reasons = status->wakeup_reasons;
+ kfree(status);
}
if (reasons & IWL_WOWLAN_WAKEUP_BY_RFKILL_DEASSERTED)
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
index 410a8d20d56e..863fec150e53 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
@@ -769,14 +769,18 @@ int iwl_mvm_get_sar_geo_profile(struct iwl_mvm *mvm)
int ret;
struct iwl_host_cmd cmd;
u8 cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw, PHY_OPS_GROUP,
- GEO_TX_POWER_LIMIT,
+ PER_CHAIN_LIMIT_OFFSET_CMD,
IWL_FW_CMD_VER_UNKNOWN);
/* the ops field is at the same spot for all versions, so set in v1 */
geo_tx_cmd.v1.ops =
cpu_to_le32(IWL_PER_CHAIN_OFFSET_GET_CURRENT_TABLE);
- if (cmd_ver == 3)
+ if (cmd_ver == 5)
+ len = sizeof(geo_tx_cmd.v5);
+ else if (cmd_ver == 4)
+ len = sizeof(geo_tx_cmd.v4);
+ else if (cmd_ver == 3)
len = sizeof(geo_tx_cmd.v3);
else if (fw_has_api(&mvm->fwrt.fw->ucode_capa,
IWL_UCODE_TLV_API_SAR_TABLE_VER))
@@ -788,7 +792,7 @@ int iwl_mvm_get_sar_geo_profile(struct iwl_mvm *mvm)
return -EOPNOTSUPP;
cmd = (struct iwl_host_cmd){
- .id = WIDE_ID(PHY_OPS_GROUP, GEO_TX_POWER_LIMIT),
+ .id = WIDE_ID(PHY_OPS_GROUP, PER_CHAIN_LIMIT_OFFSET_CMD),
.len = { len, },
.flags = CMD_WANT_SKB,
.data = { &geo_tx_cmd },
@@ -803,7 +807,7 @@ int iwl_mvm_get_sar_geo_profile(struct iwl_mvm *mvm)
resp = (void *)cmd.resp_pkt->data;
ret = le32_to_cpu(resp->profile_idx);
- if (WARN_ON(ret > ACPI_NUM_GEO_PROFILES))
+ if (WARN_ON(ret > ACPI_NUM_GEO_PROFILES_REV3))
ret = -EIO;
iwl_free_resp(&cmd);
@@ -815,36 +819,58 @@ static int iwl_mvm_sar_geo_init(struct iwl_mvm *mvm)
union iwl_geo_tx_power_profiles_cmd cmd;
u16 len;
u32 n_bands;
+ u32 n_profiles;
int ret;
u8 cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw, PHY_OPS_GROUP,
- GEO_TX_POWER_LIMIT,
+ PER_CHAIN_LIMIT_OFFSET_CMD,
IWL_FW_CMD_VER_UNKNOWN);
BUILD_BUG_ON(offsetof(struct iwl_geo_tx_power_profiles_cmd_v1, ops) !=
offsetof(struct iwl_geo_tx_power_profiles_cmd_v2, ops) ||
offsetof(struct iwl_geo_tx_power_profiles_cmd_v2, ops) !=
- offsetof(struct iwl_geo_tx_power_profiles_cmd_v3, ops));
+ offsetof(struct iwl_geo_tx_power_profiles_cmd_v3, ops) ||
+ offsetof(struct iwl_geo_tx_power_profiles_cmd_v3, ops) !=
+ offsetof(struct iwl_geo_tx_power_profiles_cmd_v4, ops) ||
+ offsetof(struct iwl_geo_tx_power_profiles_cmd_v4, ops) !=
+ offsetof(struct iwl_geo_tx_power_profiles_cmd_v5, ops));
+
/* the ops field is at the same spot for all versions, so set in v1 */
cmd.v1.ops = cpu_to_le32(IWL_PER_CHAIN_OFFSET_SET_TABLES);
- if (cmd_ver == 3) {
+ if (cmd_ver == 5) {
+ len = sizeof(cmd.v5);
+ n_bands = ARRAY_SIZE(cmd.v5.table[0]);
+ n_profiles = ACPI_NUM_GEO_PROFILES_REV3;
+ } else if (cmd_ver == 4) {
+ len = sizeof(cmd.v4);
+ n_bands = ARRAY_SIZE(cmd.v4.table[0]);
+ n_profiles = ACPI_NUM_GEO_PROFILES_REV3;
+ } else if (cmd_ver == 3) {
len = sizeof(cmd.v3);
n_bands = ARRAY_SIZE(cmd.v3.table[0]);
+ n_profiles = ACPI_NUM_GEO_PROFILES;
} else if (fw_has_api(&mvm->fwrt.fw->ucode_capa,
IWL_UCODE_TLV_API_SAR_TABLE_VER)) {
len = sizeof(cmd.v2);
n_bands = ARRAY_SIZE(cmd.v2.table[0]);
+ n_profiles = ACPI_NUM_GEO_PROFILES;
} else {
len = sizeof(cmd.v1);
n_bands = ARRAY_SIZE(cmd.v1.table[0]);
+ n_profiles = ACPI_NUM_GEO_PROFILES;
}
BUILD_BUG_ON(offsetof(struct iwl_geo_tx_power_profiles_cmd_v1, table) !=
offsetof(struct iwl_geo_tx_power_profiles_cmd_v2, table) ||
offsetof(struct iwl_geo_tx_power_profiles_cmd_v2, table) !=
- offsetof(struct iwl_geo_tx_power_profiles_cmd_v3, table));
+ offsetof(struct iwl_geo_tx_power_profiles_cmd_v3, table) ||
+ offsetof(struct iwl_geo_tx_power_profiles_cmd_v3, table) !=
+ offsetof(struct iwl_geo_tx_power_profiles_cmd_v4, table) ||
+ offsetof(struct iwl_geo_tx_power_profiles_cmd_v4, table) !=
+ offsetof(struct iwl_geo_tx_power_profiles_cmd_v5, table));
/* the table is at the same position for all versions, so set use v1 */
- ret = iwl_sar_geo_init(&mvm->fwrt, &cmd.v1.table[0][0], n_bands);
+ ret = iwl_sar_geo_init(&mvm->fwrt, &cmd.v1.table[0][0],
+ n_bands, n_profiles);
/*
* It is a valid scenario to not support SAR, or miss wgds table,
@@ -857,14 +883,19 @@ static int iwl_mvm_sar_geo_init(struct iwl_mvm *mvm)
* Set the revision on versions that contain it.
* This must be done after calling iwl_sar_geo_init().
*/
- if (cmd_ver == 3)
+ if (cmd_ver == 5)
+ cmd.v5.table_revision = cpu_to_le32(mvm->fwrt.geo_rev);
+ else if (cmd_ver == 4)
+ cmd.v4.table_revision = cpu_to_le32(mvm->fwrt.geo_rev);
+ else if (cmd_ver == 3)
cmd.v3.table_revision = cpu_to_le32(mvm->fwrt.geo_rev);
else if (fw_has_api(&mvm->fwrt.fw->ucode_capa,
IWL_UCODE_TLV_API_SAR_TABLE_VER))
cmd.v2.table_revision = cpu_to_le32(mvm->fwrt.geo_rev);
return iwl_mvm_send_cmd_pdu(mvm,
- WIDE_ID(PHY_OPS_GROUP, GEO_TX_POWER_LIMIT),
+ WIDE_ID(PHY_OPS_GROUP,
+ PER_CHAIN_LIMIT_OFFSET_CMD),
0, len, &cmd);
}
@@ -1114,7 +1145,7 @@ static void iwl_mvm_tas_init(struct iwl_mvm *mvm)
static u8 iwl_mvm_eval_dsm_rfi(struct iwl_mvm *mvm)
{
u8 value;
- int ret = iwl_acpi_get_dsm_u8((&mvm->fwrt)->dev, 0, DSM_RFI_FUNC_ENABLE,
+ int ret = iwl_acpi_get_dsm_u8(mvm->fwrt.dev, 0, DSM_RFI_FUNC_ENABLE,
&iwl_rfi_guid, &value);
if (ret < 0) {
@@ -1143,25 +1174,31 @@ static void iwl_mvm_lari_cfg(struct iwl_mvm *mvm)
cmd.config_bitmap = iwl_acpi_get_lari_config_bitmap(&mvm->fwrt);
- ret = iwl_acpi_get_dsm_u32((&mvm->fwrt)->dev, 0, DSM_FUNC_11AX_ENABLEMENT,
+ ret = iwl_acpi_get_dsm_u32(mvm->fwrt.dev, 0, DSM_FUNC_11AX_ENABLEMENT,
&iwl_guid, &value);
if (!ret)
cmd.oem_11ax_allow_bitmap = cpu_to_le32(value);
- /* apply more config masks here */
- ret = iwl_acpi_get_dsm_u32((&mvm->fwrt)->dev, 0,
+ ret = iwl_acpi_get_dsm_u32(mvm->fwrt.dev, 0,
DSM_FUNC_ENABLE_UNII4_CHAN,
&iwl_guid, &value);
if (!ret)
cmd.oem_unii4_allow_bitmap = cpu_to_le32(value);
- ret = iwl_acpi_get_dsm_u32((&mvm->fwrt)->dev, 0,
+ ret = iwl_acpi_get_dsm_u32(mvm->fwrt.dev, 0,
DSM_FUNC_ACTIVATE_CHANNEL,
&iwl_guid, &value);
if (!ret)
cmd.chan_state_active_bitmap = cpu_to_le32(value);
+ ret = iwl_acpi_get_dsm_u32(mvm->fwrt.dev, 0,
+ DSM_FUNC_ENABLE_6E,
+ &iwl_guid, &value);
+ if (!ret)
+ cmd.oem_uhb_allow_bitmap = cpu_to_le32(value);
+
if (cmd.config_bitmap ||
+ cmd.oem_uhb_allow_bitmap ||
cmd.oem_11ax_allow_bitmap ||
cmd.oem_unii4_allow_bitmap ||
cmd.chan_state_active_bitmap) {
@@ -1189,6 +1226,9 @@ static void iwl_mvm_lari_cfg(struct iwl_mvm *mvm)
le32_to_cpu(cmd.oem_unii4_allow_bitmap),
le32_to_cpu(cmd.chan_state_active_bitmap),
cmd_ver);
+ IWL_DEBUG_RADIO(mvm,
+ "sending LARI_CONFIG_CHANGE, oem_uhb_allow_bitmap=0x%x\n",
+ le32_to_cpu(cmd.oem_uhb_allow_bitmap));
ret = iwl_mvm_send_cmd_pdu(mvm,
WIDE_ID(REGULATORY_AND_NVM_GROUP,
LARI_CONFIG_CHANGE),
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c
index cfb69e49a687..fd7d4abfb454 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c
@@ -1557,11 +1557,11 @@ void iwl_mvm_probe_resp_data_notif(struct iwl_mvm *mvm,
ieee80211_beacon_set_cntdwn(vif, notif->csa_counter);
}
-void iwl_mvm_channel_switch_noa_notif(struct iwl_mvm *mvm,
- struct iwl_rx_cmd_buffer *rxb)
+void iwl_mvm_channel_switch_start_notif(struct iwl_mvm *mvm,
+ struct iwl_rx_cmd_buffer *rxb)
{
struct iwl_rx_packet *pkt = rxb_addr(rxb);
- struct iwl_channel_switch_noa_notif *notif = (void *)pkt->data;
+ struct iwl_channel_switch_start_notif *notif = (void *)pkt->data;
struct ieee80211_vif *csa_vif, *vif;
struct iwl_mvm_vif *mvmvif;
u32 id_n_color, csa_id, mac_id;
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
index 2645dd8fef83..9fb9c7dad314 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
@@ -2236,6 +2236,34 @@ static void iwl_mvm_cfg_he_sta(struct iwl_mvm *mvm,
IWL_ERR(mvm, "Failed to config FW to work HE!\n");
}
+static void iwl_mvm_protect_assoc(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif,
+ u32 duration_override)
+{
+ u32 duration = IWL_MVM_TE_SESSION_PROTECTION_MAX_TIME_MS;
+ u32 min_duration = IWL_MVM_TE_SESSION_PROTECTION_MIN_TIME_MS;
+
+ if (duration_override > duration)
+ duration = duration_override;
+
+ /* Try really hard to protect the session and hear a beacon
+ * The new session protection command allows us to protect the
+ * session for a much longer time since the firmware will internally
+ * create two events: a 300TU one with a very high priority that
+ * won't be fragmented which should be enough for 99% of the cases,
+ * and another one (which we configure here to be 900TU long) which
+ * will have a slightly lower priority, but more importantly, can be
+ * fragmented so that it'll allow other activities to run.
+ */
+ if (fw_has_capa(&mvm->fw->ucode_capa,
+ IWL_UCODE_TLV_CAPA_SESSION_PROT_CMD))
+ iwl_mvm_schedule_session_protection(mvm, vif, 900,
+ min_duration, false);
+ else
+ iwl_mvm_protect_session(mvm, vif, duration,
+ min_duration, 500, false);
+}
+
static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *bss_conf,
@@ -2319,6 +2347,20 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
u32 dur = (11 * vif->bss_conf.beacon_int) / 10;
iwl_mvm_protect_session(mvm, vif, dur, dur,
5 * dur, false);
+ } else if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART,
+ &mvm->status) &&
+ !vif->bss_conf.dtim_period) {
+ /*
+ * If we're not restarting and still haven't
+ * heard a beacon (dtim period unknown) then
+ * make sure we still have enough minimum time
+ * remaining in the time event, since the auth
+ * might actually have taken quite a while
+ * (especially for SAE) and so the remaining
+ * time could be small without us having heard
+ * a beacon yet.
+ */
+ iwl_mvm_protect_assoc(mvm, vif, 0);
}
iwl_mvm_sf_update(mvm, vif, false);
@@ -3237,6 +3279,9 @@ static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw,
if (vif->type == NL80211_IFTYPE_AP) {
mvmvif->ap_assoc_sta_count--;
iwl_mvm_mac_ctxt_changed(mvm, vif, false, NULL);
+ } else if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls) {
+ /* remove session protection if still running */
+ iwl_mvm_stop_session_protection(mvm, vif);
}
ret = 0;
} else if (old_state == IEEE80211_STA_AUTH &&
@@ -3329,29 +3374,9 @@ static void iwl_mvm_mac_mgd_prepare_tx(struct ieee80211_hw *hw,
struct ieee80211_prep_tx_info *info)
{
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
- u32 duration = IWL_MVM_TE_SESSION_PROTECTION_MAX_TIME_MS;
- u32 min_duration = IWL_MVM_TE_SESSION_PROTECTION_MIN_TIME_MS;
-
- if (info->duration > duration)
- duration = info->duration;
mutex_lock(&mvm->mutex);
- /* Try really hard to protect the session and hear a beacon
- * The new session protection command allows us to protect the
- * session for a much longer time since the firmware will internally
- * create two events: a 300TU one with a very high priority that
- * won't be fragmented which should be enough for 99% of the cases,
- * and another one (which we configure here to be 900TU long) which
- * will have a slightly lower priority, but more importantly, can be
- * fragmented so that it'll allow other activities to run.
- */
- if (fw_has_capa(&mvm->fw->ucode_capa,
- IWL_UCODE_TLV_CAPA_SESSION_PROT_CMD))
- iwl_mvm_schedule_session_protection(mvm, vif, 900,
- min_duration, false);
- else
- iwl_mvm_protect_session(mvm, vif, duration,
- min_duration, 500, false);
+ iwl_mvm_protect_assoc(mvm, vif, info->duration);
mutex_unlock(&mvm->mutex);
}
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
index 4277536e31c3..2b1dcd60e00f 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
@@ -1658,8 +1658,8 @@ void iwl_mvm_probe_resp_data_notif(struct iwl_mvm *mvm,
struct iwl_rx_cmd_buffer *rxb);
void iwl_mvm_rx_missed_vap_notif(struct iwl_mvm *mvm,
struct iwl_rx_cmd_buffer *rxb);
-void iwl_mvm_channel_switch_noa_notif(struct iwl_mvm *mvm,
- struct iwl_rx_cmd_buffer *rxb);
+void iwl_mvm_channel_switch_start_notif(struct iwl_mvm *mvm,
+ struct iwl_rx_cmd_buffer *rxb);
/* Bindings */
int iwl_mvm_binding_add_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
int iwl_mvm_binding_remove_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c b/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c
index da705fcaf0fc..6d18a1fd649b 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c
@@ -583,8 +583,9 @@ void iwl_mvm_rx_chub_update_mcc(struct iwl_mvm *mvm,
return;
wgds_tbl_idx = iwl_mvm_get_sar_geo_profile(mvm);
- if (wgds_tbl_idx < 0)
- IWL_DEBUG_INFO(mvm, "SAR WGDS is disabled (%d)\n",
+ if (wgds_tbl_idx < 1)
+ IWL_DEBUG_INFO(mvm,
+ "SAR WGDS is disabled or error received (%d)\n",
wgds_tbl_idx);
else
IWL_DEBUG_INFO(mvm, "SAR WGDS: geo profile %d is configured\n",
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c
index e331e18b9ab1..232ad531d612 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c
@@ -383,9 +383,9 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = {
iwl_mvm_probe_resp_data_notif,
RX_HANDLER_ASYNC_LOCKED,
struct iwl_probe_resp_data_notif),
- RX_HANDLER_GRP(MAC_CONF_GROUP, CHANNEL_SWITCH_NOA_NOTIF,
- iwl_mvm_channel_switch_noa_notif,
- RX_HANDLER_SYNC, struct iwl_channel_switch_noa_notif),
+ RX_HANDLER_GRP(MAC_CONF_GROUP, CHANNEL_SWITCH_START_NOTIF,
+ iwl_mvm_channel_switch_start_notif,
+ RX_HANDLER_SYNC, struct iwl_channel_switch_start_notif),
RX_HANDLER_GRP(DATA_PATH_GROUP, MONITOR_NOTIF,
iwl_mvm_rx_monitor_notif, RX_HANDLER_ASYNC_LOCKED,
struct iwl_datapath_monitor_notif),
@@ -511,7 +511,7 @@ static const struct iwl_hcmd_names iwl_mvm_mac_conf_names[] = {
HCMD_NAME(CHANNEL_SWITCH_TIME_EVENT_CMD),
HCMD_NAME(SESSION_PROTECTION_CMD),
HCMD_NAME(SESSION_PROTECTION_NOTIF),
- HCMD_NAME(CHANNEL_SWITCH_NOA_NOTIF),
+ HCMD_NAME(CHANNEL_SWITCH_START_NOTIF),
};
/* Please keep this array *SORTED* by hex value.
@@ -521,7 +521,7 @@ static const struct iwl_hcmd_names iwl_mvm_phy_names[] = {
HCMD_NAME(CMD_DTS_MEASUREMENT_TRIGGER_WIDE),
HCMD_NAME(CTDP_CONFIG_CMD),
HCMD_NAME(TEMP_REPORTING_THRESHOLDS_CMD),
- HCMD_NAME(GEO_TX_POWER_LIMIT),
+ HCMD_NAME(PER_CHAIN_LIMIT_OFFSET_CMD),
HCMD_NAME(CT_KILL_NOTIFICATION),
HCMD_NAME(DTS_MEASUREMENT_NOTIF_WIDE),
};
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c
index ce8bdbc70b7e..a138b5c4cce8 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c
@@ -1995,8 +1995,16 @@ static u16 iwl_mvm_scan_umac_flags_v2(struct iwl_mvm *mvm,
{
u16 flags = 0;
+ /*
+ * If no direct SSIDs are provided perform a passive scan. Otherwise,
+ * if there is a single SSID which is not the broadcast SSID, assume
+ * that the scan is intended for roaming purposes and thus enable Rx on
+ * all chains to improve chances of hearing the beacons/probe responses.
+ */
if (params->n_ssids == 0)
flags |= IWL_UMAC_SCAN_GEN_FLAGS_V2_FORCE_PASSIVE;
+ else if (params->n_ssids == 1 && params->ssids[0].ssid_len)
+ flags |= IWL_UMAC_SCAN_GEN_FLAGS_V2_USE_ALL_RX_CHAINS;
if (iwl_mvm_is_scan_fragmented(params->type))
flags |= IWL_UMAC_SCAN_GEN_FLAGS_V2_FRAGMENTED_LMAC1;
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c
index 37a1ef868e6f..c574f041f096 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c
@@ -519,7 +519,7 @@ MODULE_DEVICE_TABLE(pci, iwl_hw_card_ids);
#define IWL_DEV_INFO(_device, _subdevice, _cfg, _name) \
_IWL_DEV_INFO(_device, _subdevice, IWL_CFG_ANY, IWL_CFG_ANY, \
IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_ANY, \
- IWL_CFG_NO_CDB, _cfg, _name)
+ IWL_CFG_ANY, _cfg, _name)
static const struct iwl_dev_info iwl_dev_info_table[] = {
#if IS_ENABLED(CONFIG_IWLMVM)
@@ -549,9 +549,9 @@ static const struct iwl_dev_info iwl_dev_info_table[] = {
IWL_DEV_INFO(0x7E40, 0x1692, iwl_cfg_ma_a0_gf4_a0, iwl_ax411_killer_1690i_name),
/* AX200 */
+ IWL_DEV_INFO(0x2723, IWL_CFG_ANY, iwl_ax200_cfg_cc, iwl_ax200_name),
IWL_DEV_INFO(0x2723, 0x1653, iwl_ax200_cfg_cc, iwl_ax200_killer_1650w_name),
IWL_DEV_INFO(0x2723, 0x1654, iwl_ax200_cfg_cc, iwl_ax200_killer_1650x_name),
- IWL_DEV_INFO(0x2723, IWL_CFG_ANY, iwl_ax200_cfg_cc, iwl_ax200_name),
/* Qu with Hr */
IWL_DEV_INFO(0x43F0, 0x0070, iwl_ax201_cfg_qu_hr, NULL),
@@ -726,17 +726,6 @@ static const struct iwl_dev_info iwl_dev_info_table[] = {
iwl9260_2ac_cfg, iwl9462_name),
_IWL_DEV_INFO(0x2526, IWL_CFG_ANY,
- IWL_CFG_MAC_TYPE_PNJ, IWL_CFG_ANY,
- IWL_CFG_RF_TYPE_JF2, IWL_CFG_RF_ID_JF,
- IWL_CFG_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB,
- iwl9260_2ac_cfg, iwl9560_160_name),
- _IWL_DEV_INFO(0x2526, IWL_CFG_ANY,
- IWL_CFG_MAC_TYPE_PNJ, IWL_CFG_ANY,
- IWL_CFG_RF_TYPE_JF2, IWL_CFG_RF_ID_JF,
- IWL_CFG_NO_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB,
- iwl9260_2ac_cfg, iwl9560_name),
-
- _IWL_DEV_INFO(0x2526, IWL_CFG_ANY,
IWL_CFG_MAC_TYPE_TH, IWL_CFG_ANY,
IWL_CFG_RF_TYPE_TH, IWL_CFG_ANY,
IWL_CFG_160, IWL_CFG_CORES_BT_GNSS, IWL_CFG_NO_CDB,
@@ -1076,11 +1065,6 @@ static const struct iwl_dev_info iwl_dev_info_table[] = {
iwl_cfg_so_a0_hr_a0, iwl_ax203_name),
_IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY,
IWL_CFG_MAC_TYPE_SO, IWL_CFG_ANY,
- IWL_CFG_RF_TYPE_HR2, IWL_CFG_ANY,
- IWL_CFG_NO_160, IWL_CFG_ANY, IWL_CFG_NO_CDB,
- iwl_cfg_so_a0_hr_a0, iwl_ax203_name),
- _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY,
- IWL_CFG_MAC_TYPE_SO, IWL_CFG_ANY,
IWL_CFG_RF_TYPE_HR1, IWL_CFG_ANY,
IWL_CFG_160, IWL_CFG_ANY, IWL_CFG_NO_CDB,
iwl_cfg_so_a0_hr_a0, iwl_ax101_name),
@@ -1146,6 +1130,39 @@ static const struct iwl_dev_info iwl_dev_info_table[] = {
IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB,
iwl_cfg_gl_a0_fm_a0, iwl_bz_name),
+/* SoF with JF2 */
+ _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY,
+ IWL_CFG_MAC_TYPE_SOF, IWL_CFG_ANY,
+ IWL_CFG_RF_TYPE_JF2, IWL_CFG_RF_ID_JF,
+ IWL_CFG_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB,
+ iwlax210_2ax_cfg_so_jf_b0, iwl9560_160_name),
+ _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY,
+ IWL_CFG_MAC_TYPE_SOF, IWL_CFG_ANY,
+ IWL_CFG_RF_TYPE_JF2, IWL_CFG_RF_ID_JF,
+ IWL_CFG_NO_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB,
+ iwlax210_2ax_cfg_so_jf_b0, iwl9560_name),
+
+/* SoF with JF */
+ _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY,
+ IWL_CFG_MAC_TYPE_SOF, IWL_CFG_ANY,
+ IWL_CFG_RF_TYPE_JF1, IWL_CFG_RF_ID_JF1,
+ IWL_CFG_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB,
+ iwlax210_2ax_cfg_so_jf_b0, iwl9461_160_name),
+ _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY,
+ IWL_CFG_MAC_TYPE_SOF, IWL_CFG_ANY,
+ IWL_CFG_RF_TYPE_JF1, IWL_CFG_RF_ID_JF1_DIV,
+ IWL_CFG_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB,
+ iwlax210_2ax_cfg_so_jf_b0, iwl9462_160_name),
+ _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY,
+ IWL_CFG_MAC_TYPE_SOF, IWL_CFG_ANY,
+ IWL_CFG_RF_TYPE_JF1, IWL_CFG_RF_ID_JF1,
+ IWL_CFG_NO_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB,
+ iwlax210_2ax_cfg_so_jf_b0, iwl9461_name),
+ _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY,
+ IWL_CFG_MAC_TYPE_SOF, IWL_CFG_ANY,
+ IWL_CFG_RF_TYPE_JF1, IWL_CFG_RF_ID_JF1_DIV,
+ IWL_CFG_NO_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB,
+ iwlax210_2ax_cfg_so_jf_b0, iwl9462_name),
/* SoF with JF2 */
_IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY,
@@ -1317,13 +1334,66 @@ out:
/* PCI registers */
#define PCI_CFG_RETRY_TIMEOUT 0x041
+static const struct iwl_dev_info *
+iwl_pci_find_dev_info(u16 device, u16 subsystem_device,
+ u16 mac_type, u8 mac_step,
+ u16 rf_type, u8 cdb, u8 rf_id, u8 no_160, u8 cores)
+{
+ int i;
+
+ for (i = ARRAY_SIZE(iwl_dev_info_table) - 1; i >= 0; i--) {
+ const struct iwl_dev_info *dev_info = &iwl_dev_info_table[i];
+
+ if (dev_info->device != (u16)IWL_CFG_ANY &&
+ dev_info->device != device)
+ continue;
+
+ if (dev_info->subdevice != (u16)IWL_CFG_ANY &&
+ dev_info->subdevice != subsystem_device)
+ continue;
+
+ if (dev_info->mac_type != (u16)IWL_CFG_ANY &&
+ dev_info->mac_type != mac_type)
+ continue;
+
+ if (dev_info->mac_step != (u8)IWL_CFG_ANY &&
+ dev_info->mac_step != mac_step)
+ continue;
+
+ if (dev_info->rf_type != (u16)IWL_CFG_ANY &&
+ dev_info->rf_type != rf_type)
+ continue;
+
+ if (dev_info->cdb != (u8)IWL_CFG_ANY &&
+ dev_info->cdb != cdb)
+ continue;
+
+ if (dev_info->rf_id != (u8)IWL_CFG_ANY &&
+ dev_info->rf_id != rf_id)
+ continue;
+
+ if (dev_info->no_160 != (u8)IWL_CFG_ANY &&
+ dev_info->no_160 != no_160)
+ continue;
+
+ if (dev_info->cores != (u8)IWL_CFG_ANY &&
+ dev_info->cores != cores)
+ continue;
+
+ return dev_info;
+ }
+
+ return NULL;
+}
+
static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{
const struct iwl_cfg_trans_params *trans;
const struct iwl_cfg *cfg_7265d __maybe_unused = NULL;
+ const struct iwl_dev_info *dev_info;
struct iwl_trans *iwl_trans;
struct iwl_trans_pcie *trans_pcie;
- int i, ret;
+ int ret;
const struct iwl_cfg *cfg;
trans = (void *)(ent->driver_data & ~TRANS_CFG_MARKER);
@@ -1375,35 +1445,18 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
!CSR_HW_RFID_TYPE(iwl_trans->hw_rf_id) && get_crf_id(iwl_trans))
goto out_free_trans;
- for (i = 0; i < ARRAY_SIZE(iwl_dev_info_table); i++) {
- const struct iwl_dev_info *dev_info = &iwl_dev_info_table[i];
- if ((dev_info->device == (u16)IWL_CFG_ANY ||
- dev_info->device == pdev->device) &&
- (dev_info->subdevice == (u16)IWL_CFG_ANY ||
- dev_info->subdevice == pdev->subsystem_device) &&
- (dev_info->mac_type == (u16)IWL_CFG_ANY ||
- dev_info->mac_type ==
- CSR_HW_REV_TYPE(iwl_trans->hw_rev)) &&
- (dev_info->mac_step == (u8)IWL_CFG_ANY ||
- dev_info->mac_step ==
- CSR_HW_REV_STEP(iwl_trans->hw_rev)) &&
- (dev_info->rf_type == (u16)IWL_CFG_ANY ||
- dev_info->rf_type ==
- CSR_HW_RFID_TYPE(iwl_trans->hw_rf_id)) &&
- (dev_info->cdb == IWL_CFG_NO_CDB ||
- CSR_HW_RFID_IS_CDB(iwl_trans->hw_rf_id)) &&
- (dev_info->rf_id == (u8)IWL_CFG_ANY ||
- dev_info->rf_id ==
- IWL_SUBDEVICE_RF_ID(pdev->subsystem_device)) &&
- (dev_info->no_160 == (u8)IWL_CFG_ANY ||
- dev_info->no_160 ==
- IWL_SUBDEVICE_NO_160(pdev->subsystem_device)) &&
- (dev_info->cores == (u8)IWL_CFG_ANY ||
- dev_info->cores ==
- IWL_SUBDEVICE_CORES(pdev->subsystem_device))) {
- iwl_trans->cfg = dev_info->cfg;
- iwl_trans->name = dev_info->name;
- }
+ dev_info = iwl_pci_find_dev_info(pdev->device, pdev->subsystem_device,
+ CSR_HW_REV_TYPE(iwl_trans->hw_rev),
+ CSR_HW_REV_STEP(iwl_trans->hw_rev),
+ CSR_HW_RFID_TYPE(iwl_trans->hw_rf_id),
+ CSR_HW_RFID_IS_CDB(iwl_trans->hw_rf_id),
+ IWL_SUBDEVICE_RF_ID(pdev->subsystem_device),
+ IWL_SUBDEVICE_NO_160(pdev->subsystem_device),
+ IWL_SUBDEVICE_CORES(pdev->subsystem_device));
+
+ if (dev_info) {
+ iwl_trans->cfg = dev_info->cfg;
+ iwl_trans->name = dev_info->name;
}
#if IS_ENABLED(CONFIG_IWLMVM)
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c
index 8e45eb38304b..14602d6d6699 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c
@@ -2149,6 +2149,7 @@ irqreturn_t iwl_pcie_irq_msix_handler(int irq, void *dev_id)
u32 inta_fh_msk = ~MSIX_FH_INT_CAUSES_DATA_QUEUE;
u32 inta_fh, inta_hw;
bool polling = false;
+ bool sw_err;
if (trans_pcie->shared_vec_mask & IWL_SHARED_IRQ_NON_RX)
inta_fh_msk |= MSIX_FH_INT_CAUSES_Q0;
@@ -2221,9 +2222,13 @@ irqreturn_t iwl_pcie_irq_msix_handler(int irq, void *dev_id)
wake_up(&trans_pcie->ucode_write_waitq);
}
+ if (trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_BZ)
+ sw_err = inta_hw & MSIX_HW_INT_CAUSES_REG_SW_ERR_BZ;
+ else
+ sw_err = inta_hw & MSIX_HW_INT_CAUSES_REG_SW_ERR;
+
/* Error detected by uCode */
- if ((inta_fh & MSIX_FH_INT_CAUSES_FH_ERR) ||
- (inta_hw & MSIX_HW_INT_CAUSES_REG_SW_ERR)) {
+ if ((inta_fh & MSIX_FH_INT_CAUSES_FH_ERR) || sw_err) {
IWL_ERR(trans,
"Microcode SW error detected. Restarting 0x%X.\n",
inta_fh);
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c
index 262795368bfe..1efb53f78a62 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c
@@ -1062,7 +1062,7 @@ struct iwl_causes_list {
u8 addr;
};
-static struct iwl_causes_list causes_list[] = {
+static const struct iwl_causes_list causes_list_common[] = {
{MSIX_FH_INT_CAUSES_D2S_CH0_NUM, CSR_MSIX_FH_INT_MASK_AD, 0},
{MSIX_FH_INT_CAUSES_D2S_CH1_NUM, CSR_MSIX_FH_INT_MASK_AD, 0x1},
{MSIX_FH_INT_CAUSES_S2D, CSR_MSIX_FH_INT_MASK_AD, 0x3},
@@ -1073,30 +1073,50 @@ static struct iwl_causes_list causes_list[] = {
{MSIX_HW_INT_CAUSES_REG_CT_KILL, CSR_MSIX_HW_INT_MASK_AD, 0x16},
{MSIX_HW_INT_CAUSES_REG_RF_KILL, CSR_MSIX_HW_INT_MASK_AD, 0x17},
{MSIX_HW_INT_CAUSES_REG_PERIODIC, CSR_MSIX_HW_INT_MASK_AD, 0x18},
- {MSIX_HW_INT_CAUSES_REG_SW_ERR, CSR_MSIX_HW_INT_MASK_AD, 0x29},
{MSIX_HW_INT_CAUSES_REG_SCD, CSR_MSIX_HW_INT_MASK_AD, 0x2A},
{MSIX_HW_INT_CAUSES_REG_FH_TX, CSR_MSIX_HW_INT_MASK_AD, 0x2B},
{MSIX_HW_INT_CAUSES_REG_HW_ERR, CSR_MSIX_HW_INT_MASK_AD, 0x2D},
{MSIX_HW_INT_CAUSES_REG_HAP, CSR_MSIX_HW_INT_MASK_AD, 0x2E},
};
+static const struct iwl_causes_list causes_list_pre_bz[] = {
+ {MSIX_HW_INT_CAUSES_REG_SW_ERR, CSR_MSIX_HW_INT_MASK_AD, 0x29},
+};
+
+static const struct iwl_causes_list causes_list_bz[] = {
+ {MSIX_HW_INT_CAUSES_REG_SW_ERR_BZ, CSR_MSIX_HW_INT_MASK_AD, 0x29},
+};
+
+static void iwl_pcie_map_list(struct iwl_trans *trans,
+ const struct iwl_causes_list *causes,
+ int arr_size, int val)
+{
+ int i;
+
+ for (i = 0; i < arr_size; i++) {
+ iwl_write8(trans, CSR_MSIX_IVAR(causes[i].addr), val);
+ iwl_clear_bit(trans, causes[i].mask_reg,
+ causes[i].cause_num);
+ }
+}
+
static void iwl_pcie_map_non_rx_causes(struct iwl_trans *trans)
{
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
int val = trans_pcie->def_irq | MSIX_NON_AUTO_CLEAR_CAUSE;
- int i, arr_size = ARRAY_SIZE(causes_list);
- struct iwl_causes_list *causes = causes_list;
-
/*
* Access all non RX causes and map them to the default irq.
* In case we are missing at least one interrupt vector,
* the first interrupt vector will serve non-RX and FBQ causes.
*/
- for (i = 0; i < arr_size; i++) {
- iwl_write8(trans, CSR_MSIX_IVAR(causes[i].addr), val);
- iwl_clear_bit(trans, causes[i].mask_reg,
- causes[i].cause_num);
- }
+ iwl_pcie_map_list(trans, causes_list_common,
+ ARRAY_SIZE(causes_list_common), val);
+ if (trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_BZ)
+ iwl_pcie_map_list(trans, causes_list_bz,
+ ARRAY_SIZE(causes_list_bz), val);
+ else
+ iwl_pcie_map_list(trans, causes_list_pre_bz,
+ ARRAY_SIZE(causes_list_pre_bz), val);
}
static void iwl_pcie_map_rx_causes(struct iwl_trans *trans)
@@ -3384,7 +3404,10 @@ static void iwl_trans_pcie_sync_nmi(struct iwl_trans *trans)
if (trans_pcie->msix_enabled) {
inta_addr = CSR_MSIX_HW_INT_CAUSES_AD;
- sw_err_bit = MSIX_HW_INT_CAUSES_REG_SW_ERR;
+ if (trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_BZ)
+ sw_err_bit = MSIX_HW_INT_CAUSES_REG_SW_ERR_BZ;
+ else
+ sw_err_bit = MSIX_HW_INT_CAUSES_REG_SW_ERR;
} else {
inta_addr = CSR_INT;
sw_err_bit = CSR_INT_BIT_SW_ERR;