mirror of
https://github.com/torvalds/linux.git
synced 2026-06-03 03:53:37 +02:00
iwlwifi patches for v6.1
-----BEGIN PGP SIGNATURE----- iQJPBAABCAA5FiEE9cg2NujikJ5EMZusCDCCYA5zdzwFAmMnCRAbHGdyZWdvcnku Z3JlZW5tYW5AaW50ZWwuY29tAAoJEAgwgmAOc3c8kjAQAJA/BmLbUILxoFOAGpxV j4yiwUdQymPBuluK2cvnK3aMpAHDmB33MYN/ScRTnLgodmXH+Vf4jbv6Z9J0JOql sPdIQYUnCnD14+CcDcFTfKkHBckiTBVH/yamQnl7/WFI95rQ8QfUWLm7Sx33qjgJ eDApbTRZwfxlwwdXjYl7rIqHRkqIVDOiGC+jtgos5pthsX5haOFhPZsyLFksDVvd 2hkrszdCzH9lANZ9gZIc4VToaEHGffkLD4Xub9w58QxNWZ5YBVwAa0cvKx/6q9Nl VNdHpO4vnWBwxifif4puBd+s8X9ZZIiE9lMkZYwcu4DuLHJiCg8FlTEchPbKlMox J2U8woPSVff9Y300ptjgdnrQvwNakZWCu8WYtwQCBjM8TI9b2b02ZAElGvZR+ux3 FaVd3GMsDaACANUaQlLbU5bNeDa4zD/W7KartjI/AfFXcKrNxlzYsm14zkoLghA2 DEVOo4xDczb3YJUckbqwXDDryrBovsC8dw2xsJbMl7/Y9ZY7+qO0rMzOHMmWvjUd rh4vDUfiQtnaglQxPCYWAPA3cKlN2ze7anM0m0+HLW1kIEu7dyH4XNFozYxyBN6R 34qkXGoUKpo0GYirf6WXOKYdLyyN5Nj+9kK8SEDOOW2ZsMBkEuhtiWObV1W2I8yd DTowtgw/+M+SiCMdNDHogFiz =Pjml -----END PGP SIGNATURE----- Merge tag 'iwlwifi-next-for-kalle-2022-09-18' of git://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi/iwlwifi-next iwlwifi patches for v6.1
This commit is contained in:
commit
aa7a5f946f
|
|
@ -56,13 +56,16 @@
|
|||
#define IWL_BZ_A_GF4_A_FW_PRE "iwlwifi-bz-a0-gf4-a0-"
|
||||
#define IWL_BZ_A_MR_A_FW_PRE "iwlwifi-bz-a0-mr-a0-"
|
||||
#define IWL_BZ_A_FM_A_FW_PRE "iwlwifi-bz-a0-fm-a0-"
|
||||
#define IWL_BZ_A_FM4_A_FW_PRE "iwlwifi-bz-a0-fm4-a0-"
|
||||
#define IWL_GL_A_FM_A_FW_PRE "iwlwifi-gl-a0-fm-a0-"
|
||||
#define IWL_GL_B_FM_B_FW_PRE "iwlwifi-gl-b0-fm-b0-"
|
||||
#define IWL_BZ_Z_GF_A_FW_PRE "iwlwifi-bz-z0-gf-a0-"
|
||||
#define IWL_BNJ_A_FM_A_FW_PRE "iwlwifi-BzBnj-a0-fm-a0-"
|
||||
#define IWL_BNJ_A_FM4_A_FW_PRE "iwlwifi-BzBnj-a0-fm4-a0-"
|
||||
#define IWL_BNJ_A_GF_A_FW_PRE "iwlwifi-BzBnj-a0-gf-a0-"
|
||||
#define IWL_BNJ_A_GF4_A_FW_PRE "iwlwifi-BzBnj-a0-gf4-a0-"
|
||||
#define IWL_BNJ_A_HR_B_FW_PRE "iwlwifi-BzBnj-a0-hr-b0-"
|
||||
#define IWL_BNJ_B_FM_B_FW_PRE "iwlwifi-BzBnj-b0-fm-b0-"
|
||||
|
||||
|
||||
#define IWL_QU_B_HR_B_MODULE_FIRMWARE(api) \
|
||||
|
|
@ -119,8 +122,12 @@
|
|||
IWL_BZ_A_MR_A_FW_PRE __stringify(api) ".ucode"
|
||||
#define IWL_BZ_A_FM_A_MODULE_FIRMWARE(api) \
|
||||
IWL_BZ_A_FM_A_FW_PRE __stringify(api) ".ucode"
|
||||
#define IWL_BZ_A_FM4_A_MODULE_FIRMWARE(api) \
|
||||
IWL_BZ_A_FM4_A_FW_PRE __stringify(api) ".ucode"
|
||||
#define IWL_GL_A_FM_A_MODULE_FIRMWARE(api) \
|
||||
IWL_GL_A_FM_A_FW_PRE __stringify(api) ".ucode"
|
||||
#define IWL_GL_B_FM_B_MODULE_FIRMWARE(api) \
|
||||
IWL_GL_B_FM_B_FW_PRE __stringify(api) ".ucode"
|
||||
#define IWL_BNJ_A_FM_A_MODULE_FIRMWARE(api) \
|
||||
IWL_BNJ_A_FM_A_FW_PRE __stringify(api) ".ucode"
|
||||
#define IWL_BNJ_A_FM4_A_MODULE_FIRMWARE(api) \
|
||||
|
|
@ -131,6 +138,8 @@
|
|||
IWL_BNJ_A_GF4_A_FW_PRE __stringify(api) ".ucode"
|
||||
#define IWL_BNJ_A_HR_B_MODULE_FIRMWARE(api) \
|
||||
IWL_BNJ_A_HR_B_FW_PRE __stringify(api) ".ucode"
|
||||
#define IWL_BNJ_B_FM_B_MODULE_FIRMWARE(api) \
|
||||
IWL_BNJ_B_FM_B_FW_PRE __stringify(api) ".ucode"
|
||||
|
||||
static const struct iwl_base_params iwl_22000_base_params = {
|
||||
.eeprom_size = OTP_LOW_IMAGE_SIZE_32K,
|
||||
|
|
@ -240,7 +249,7 @@ static const struct iwl_ht_params iwl_22000_ht_params = {
|
|||
}, \
|
||||
}
|
||||
|
||||
#define IWL_DEVICE_BZ_COMMON \
|
||||
#define IWL_DEVICE_BZ \
|
||||
.ucode_api_max = IWL_22000_UCODE_API_MAX, \
|
||||
.ucode_api_min = IWL_22000_UCODE_API_MIN, \
|
||||
.led_mode = IWL_LED_RF_STATE, \
|
||||
|
|
@ -276,16 +285,13 @@ static const struct iwl_ht_params iwl_22000_ht_params = {
|
|||
.addr = LDBG_M2S_BUF_WRAP_CNT, \
|
||||
.mask = LDBG_M2S_BUF_WRAP_CNT_VAL_MSK, \
|
||||
}, \
|
||||
}
|
||||
|
||||
#define IWL_DEVICE_BZ \
|
||||
IWL_DEVICE_BZ_COMMON, \
|
||||
}, \
|
||||
.trans.umac_prph_offset = 0x300000, \
|
||||
.trans.device_family = IWL_DEVICE_FAMILY_BZ, \
|
||||
.trans.base_params = &iwl_ax210_base_params, \
|
||||
.min_txq_size = 128, \
|
||||
.gp2_reg_addr = 0xd02c68, \
|
||||
.min_ba_txq_size = IWL_DEFAULT_QUEUE_SIZE_EHT, \
|
||||
.min_ba_txq_size = IWL_DEFAULT_QUEUE_SIZE_EHT, \
|
||||
.mon_dram_regs = { \
|
||||
.write_ptr = { \
|
||||
.addr = DBGC_CUR_DBGBUF_STATUS, \
|
||||
|
|
@ -926,6 +932,13 @@ const struct iwl_cfg iwl_cfg_bz_a0_fm_a0 = {
|
|||
.num_rbds = IWL_NUM_RBDS_AX210_HE,
|
||||
};
|
||||
|
||||
const struct iwl_cfg iwl_cfg_bz_a0_fm4_a0 = {
|
||||
.fw_name_pre = IWL_BZ_A_FM4_A_FW_PRE,
|
||||
.uhb_supported = true,
|
||||
IWL_DEVICE_BZ,
|
||||
.num_rbds = IWL_NUM_RBDS_AX210_HE,
|
||||
};
|
||||
|
||||
const struct iwl_cfg iwl_cfg_gl_a0_fm_a0 = {
|
||||
.fw_name_pre = IWL_GL_A_FM_A_FW_PRE,
|
||||
.uhb_supported = true,
|
||||
|
|
@ -933,6 +946,13 @@ const struct iwl_cfg iwl_cfg_gl_a0_fm_a0 = {
|
|||
.num_rbds = IWL_NUM_RBDS_AX210_HE,
|
||||
};
|
||||
|
||||
const struct iwl_cfg iwl_cfg_gl_b0_fm_b0 = {
|
||||
.fw_name_pre = IWL_GL_B_FM_B_FW_PRE,
|
||||
.uhb_supported = true,
|
||||
IWL_DEVICE_BZ,
|
||||
.num_rbds = IWL_NUM_RBDS_AX210_HE,
|
||||
};
|
||||
|
||||
const struct iwl_cfg iwl_cfg_bz_z0_gf_a0 = {
|
||||
.fw_name_pre = IWL_BZ_Z_GF_A_FW_PRE,
|
||||
.uhb_supported = true,
|
||||
|
|
@ -974,6 +994,13 @@ const struct iwl_cfg iwl_cfg_bnj_a0_hr_b0 = {
|
|||
IWL_DEVICE_BZ,
|
||||
.num_rbds = IWL_NUM_RBDS_AX210_HE,
|
||||
};
|
||||
|
||||
const struct iwl_cfg iwl_cfg_bnj_b0_fm_b0 = {
|
||||
.fw_name_pre = IWL_BNJ_B_FM_B_FW_PRE,
|
||||
.uhb_supported = true,
|
||||
IWL_DEVICE_BZ,
|
||||
.num_rbds = IWL_NUM_RBDS_AX210_HE,
|
||||
};
|
||||
MODULE_FIRMWARE(IWL_QU_B_HR_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX));
|
||||
MODULE_FIRMWARE(IWL_QNJ_B_HR_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX));
|
||||
MODULE_FIRMWARE(IWL_QU_C_HR_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX));
|
||||
|
|
@ -1007,3 +1034,6 @@ MODULE_FIRMWARE(IWL_BNJ_A_FM4_A_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX));
|
|||
MODULE_FIRMWARE(IWL_BNJ_A_GF_A_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX));
|
||||
MODULE_FIRMWARE(IWL_BNJ_A_GF4_A_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX));
|
||||
MODULE_FIRMWARE(IWL_BNJ_A_HR_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX));
|
||||
MODULE_FIRMWARE(IWL_BZ_A_FM4_A_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX));
|
||||
MODULE_FIRMWARE(IWL_GL_B_FM_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX));
|
||||
MODULE_FIRMWARE(IWL_BNJ_B_FM_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX));
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
/*
|
||||
* Copyright (C) 2013-2015 Intel Mobile Communications GmbH
|
||||
* Copyright (C) 2016-2017 Intel Deutschland GmbH
|
||||
* Copyright (C) 2018-2020 Intel Corporation
|
||||
* Copyright (C) 2018-2022 Intel Corporation
|
||||
*/
|
||||
#ifndef __iwl_fw_api_commands_h__
|
||||
#define __iwl_fw_api_commands_h__
|
||||
|
|
@ -20,6 +20,8 @@
|
|||
* &enum iwl_phy_ops_subcmd_ids
|
||||
* @DATA_PATH_GROUP: data path group, uses command IDs from
|
||||
* &enum iwl_data_path_subcmd_ids
|
||||
* @SCAN_GROUP: scan group, uses command IDs from
|
||||
* &enum iwl_scan_subcmd_ids
|
||||
* @NAN_GROUP: NAN group, uses command IDs from &enum iwl_nan_subcmd_ids
|
||||
* @LOCATION_GROUP: location group, uses command IDs from
|
||||
* &enum iwl_location_subcmd_ids
|
||||
|
|
@ -36,6 +38,7 @@ enum iwl_mvm_command_groups {
|
|||
MAC_CONF_GROUP = 0x3,
|
||||
PHY_OPS_GROUP = 0x4,
|
||||
DATA_PATH_GROUP = 0x5,
|
||||
SCAN_GROUP = 0x6,
|
||||
NAN_GROUP = 0x7,
|
||||
LOCATION_GROUP = 0x8,
|
||||
PROT_OFFLOAD_GROUP = 0xb,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
|
||||
/*
|
||||
* Copyright (C) 2012-2014, 2018-2021 Intel Corporation
|
||||
* Copyright (C) 2012-2014, 2018-2022 Intel Corporation
|
||||
* Copyright (C) 2013-2014 Intel Mobile Communications GmbH
|
||||
* Copyright (C) 2015-2017 Intel Deutschland GmbH
|
||||
*/
|
||||
|
|
@ -766,6 +766,65 @@ struct iwl_wowlan_status_v12 {
|
|||
u8 wake_packet[]; /* can be truncated from _length to _bufsize */
|
||||
} __packed; /* WOWLAN_STATUSES_RSP_API_S_VER_12 */
|
||||
|
||||
/**
|
||||
* struct iwl_wowlan_info_notif - WoWLAN information notification
|
||||
* @gtk: GTK data
|
||||
* @igtk: IGTK data
|
||||
* @replay_ctr: GTK rekey replay counter
|
||||
* @pattern_number: number of the matched patterns
|
||||
* @reserved1: reserved
|
||||
* @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
|
||||
* @transmitted_ndps: number of transmitted neighbor discovery packets
|
||||
* @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
|
||||
* @station_id: station id
|
||||
* @reserved2: reserved
|
||||
*/
|
||||
struct iwl_wowlan_info_notif {
|
||||
struct iwl_wowlan_gtk_status_v3 gtk[WOWLAN_GTK_KEYS_NUM];
|
||||
struct iwl_wowlan_igtk_status igtk[WOWLAN_IGTK_KEYS_NUM];
|
||||
__le64 replay_ctr;
|
||||
__le16 pattern_number;
|
||||
__le16 reserved1;
|
||||
__le16 qos_seq_ctr[8];
|
||||
__le32 wakeup_reasons;
|
||||
__le32 num_of_gtk_rekeys;
|
||||
__le32 transmitted_ndps;
|
||||
__le32 received_beacons;
|
||||
__le32 wake_packet_length;
|
||||
__le32 wake_packet_bufsize;
|
||||
u8 tid_tear_down;
|
||||
u8 station_id;
|
||||
u8 reserved2[2];
|
||||
} __packed; /* WOWLAN_INFO_NTFY_API_S_VER_1 */
|
||||
|
||||
/**
|
||||
* struct iwl_wowlan_wake_pkt_notif - WoWLAN wake packet notification
|
||||
* @wake_packet_length: wakeup packet length
|
||||
* @station_id: station id
|
||||
* @reserved: unused
|
||||
* @wake_packet: wakeup packet
|
||||
*/
|
||||
struct iwl_wowlan_wake_pkt_notif {
|
||||
__le32 wake_packet_length;
|
||||
u8 station_id;
|
||||
u8 reserved[3];
|
||||
u8 wake_packet[1];
|
||||
} __packed; /* WOWLAN_WAKE_PKT_NTFY_API_S_VER_1 */
|
||||
|
||||
/**
|
||||
* struct iwl_mvm_d3_end_notif - d3 end notification
|
||||
* @flags: See &enum iwl_d0i3_flags
|
||||
*/
|
||||
struct iwl_mvm_d3_end_notif {
|
||||
__le32 flags;
|
||||
} __packed;
|
||||
|
||||
/* TODO: NetDetect API */
|
||||
|
||||
#endif /* __iwl_fw_api_d3_h__ */
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
* Copyright (C) 2012-2014 Intel Corporation
|
||||
* Copyright (C) 2013-2015 Intel Mobile Communications GmbH
|
||||
* Copyright (C) 2016-2017 Intel Deutschland GmbH
|
||||
* Copyright (C) 2021 Intel Corporation
|
||||
* Copyright (C) 2021-2022 Intel Corporation
|
||||
*/
|
||||
#ifndef __iwl_fw_api_offload_h__
|
||||
#define __iwl_fw_api_offload_h__
|
||||
|
|
@ -12,6 +12,21 @@
|
|||
* enum iwl_prot_offload_subcmd_ids - protocol offload commands
|
||||
*/
|
||||
enum iwl_prot_offload_subcmd_ids {
|
||||
/**
|
||||
* @WOWLAN_WAKE_PKT_NOTIFICATION: Notification in &struct iwl_wowlan_wake_pkt_notif
|
||||
*/
|
||||
WOWLAN_WAKE_PKT_NOTIFICATION = 0xFC,
|
||||
|
||||
/**
|
||||
* @WOWLAN_INFO_NOTIFICATION: Notification in &struct iwl_wowlan_info_notif
|
||||
*/
|
||||
WOWLAN_INFO_NOTIFICATION = 0xFD,
|
||||
|
||||
/**
|
||||
* @D3_END_NOTIFICATION: End D3 state notification
|
||||
*/
|
||||
D3_END_NOTIFICATION = 0xFE,
|
||||
|
||||
/**
|
||||
* @STORED_BEACON_NTF: &struct iwl_stored_beacon_notif
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
|
||||
/*
|
||||
* Copyright (C) 2012-2014, 2018-2021 Intel Corporation
|
||||
* Copyright (C) 2012-2014, 2018-2022 Intel Corporation
|
||||
* Copyright (C) 2013-2015 Intel Mobile Communications GmbH
|
||||
* Copyright (C) 2015-2017 Intel Deutschland GmbH
|
||||
*/
|
||||
|
|
@ -668,7 +668,7 @@ struct iwl_rx_no_data {
|
|||
__le32 phy_info[2];
|
||||
__le32 rx_vec[2];
|
||||
} __packed; /* RX_NO_DATA_NTFY_API_S_VER_1,
|
||||
TX_NO_DATA_NTFY_API_S_VER_2 */
|
||||
RX_NO_DATA_NTFY_API_S_VER_2 */
|
||||
|
||||
struct iwl_frame_release {
|
||||
u8 baid;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
|
||||
/*
|
||||
* Copyright (C) 2012-2014, 2018-2021 Intel Corporation
|
||||
* Copyright (C) 2012-2014, 2018-2022 Intel Corporation
|
||||
* Copyright (C) 2013-2015 Intel Mobile Communications GmbH
|
||||
* Copyright (C) 2016-2017 Intel Deutschland GmbH
|
||||
*/
|
||||
|
|
@ -9,6 +9,16 @@
|
|||
|
||||
/* Scan Commands, Responses, Notifications */
|
||||
|
||||
/**
|
||||
* enum iwl_scan_subcmd_ids - scan commands
|
||||
*/
|
||||
enum iwl_scan_subcmd_ids {
|
||||
/**
|
||||
* @OFFLOAD_MATCH_INFO_NOTIF: &struct iwl_scan_offload_match_info
|
||||
*/
|
||||
OFFLOAD_MATCH_INFO_NOTIF = 0xFC,
|
||||
};
|
||||
|
||||
/* Max number of IEs for direct SSID scans in a command */
|
||||
#define PROBE_OPTION_MAX 20
|
||||
|
||||
|
|
@ -1188,7 +1198,7 @@ struct iwl_scan_offload_profile_match {
|
|||
} __packed; /* SCAN_OFFLOAD_PROFILE_MATCH_RESULTS_S_VER_2 */
|
||||
|
||||
/**
|
||||
* struct iwl_scan_offload_profiles_query - match results query response
|
||||
* struct iwl_scan_offload_match_info - match results information
|
||||
* @matched_profiles: bitmap of matched profiles, referencing the
|
||||
* matches passed in the scan offload request
|
||||
* @last_scan_age: age of the last offloaded scan
|
||||
|
|
@ -1200,7 +1210,7 @@ struct iwl_scan_offload_profile_match {
|
|||
* @reserved: reserved
|
||||
* @matches: array of match information, one for each match
|
||||
*/
|
||||
struct iwl_scan_offload_profiles_query {
|
||||
struct iwl_scan_offload_match_info {
|
||||
__le32 matched_profiles;
|
||||
__le32 last_scan_age;
|
||||
__le32 n_scans_done;
|
||||
|
|
@ -1210,7 +1220,9 @@ struct iwl_scan_offload_profiles_query {
|
|||
u8 self_recovery;
|
||||
__le16 reserved;
|
||||
struct iwl_scan_offload_profile_match matches[];
|
||||
} __packed; /* SCAN_OFFLOAD_PROFILES_QUERY_RSP_S_VER_3 */
|
||||
} __packed; /* SCAN_OFFLOAD_PROFILES_QUERY_RSP_S_VER_3 and
|
||||
* SCAN_OFFLOAD_MATCH_INFO_NOTIFICATION_S_VER_1
|
||||
*/
|
||||
|
||||
/**
|
||||
* struct iwl_umac_scan_iter_complete_notif - notifies end of scanning iteration
|
||||
|
|
|
|||
|
|
@ -649,13 +649,16 @@ extern const struct iwl_cfg iwl_cfg_bz_a0_gf_a0;
|
|||
extern const struct iwl_cfg iwl_cfg_bz_a0_gf4_a0;
|
||||
extern const struct iwl_cfg iwl_cfg_bz_a0_mr_a0;
|
||||
extern const struct iwl_cfg iwl_cfg_bz_a0_fm_a0;
|
||||
extern const struct iwl_cfg iwl_cfg_bz_a0_fm4_a0;
|
||||
extern const struct iwl_cfg iwl_cfg_gl_a0_fm_a0;
|
||||
extern const struct iwl_cfg iwl_cfg_gl_b0_fm_b0;
|
||||
extern const struct iwl_cfg iwl_cfg_bz_z0_gf_a0;
|
||||
extern const struct iwl_cfg iwl_cfg_bnj_a0_fm_a0;
|
||||
extern const struct iwl_cfg iwl_cfg_bnj_a0_fm4_a0;
|
||||
extern const struct iwl_cfg iwl_cfg_bnj_a0_gf_a0;
|
||||
extern const struct iwl_cfg iwl_cfg_bnj_a0_gf4_a0;
|
||||
extern const struct iwl_cfg iwl_cfg_bnj_a0_hr_b0;
|
||||
extern const struct iwl_cfg iwl_cfg_bnj_b0_fm_b0;
|
||||
#endif /* CONFIG_IWLMVM */
|
||||
|
||||
#endif /* __IWL_CONFIG_H__ */
|
||||
|
|
|
|||
|
|
@ -1427,7 +1427,7 @@ struct iwl_wowlan_status_data {
|
|||
u8 flags;
|
||||
} igtk;
|
||||
|
||||
u8 wake_packet[];
|
||||
u8 *wake_packet;
|
||||
};
|
||||
|
||||
static void iwl_mvm_report_wakeup_reasons(struct iwl_mvm *mvm,
|
||||
|
|
@ -1480,7 +1480,7 @@ static void iwl_mvm_report_wakeup_reasons(struct iwl_mvm *mvm,
|
|||
if (reasons & IWL_WOWLAN_WAKEUP_BY_REM_WAKE_WAKEUP_PACKET)
|
||||
wakeup.tcp_match = true;
|
||||
|
||||
if (status->wake_packet_bufsize) {
|
||||
if (status->wake_packet) {
|
||||
int pktsize = status->wake_packet_bufsize;
|
||||
int pktlen = status->wake_packet_length;
|
||||
const u8 *pktdata = status->wake_packet;
|
||||
|
|
@ -1944,57 +1944,6 @@ static bool iwl_mvm_setup_connection_keep(struct iwl_mvm *mvm,
|
|||
return true;
|
||||
}
|
||||
|
||||
/* Occasionally, templates would be nice. This is one of those times ... */
|
||||
#define iwl_mvm_parse_wowlan_status_common(_ver) \
|
||||
static struct iwl_wowlan_status_data * \
|
||||
iwl_mvm_parse_wowlan_status_common_ ## _ver(struct iwl_mvm *mvm, \
|
||||
struct iwl_wowlan_status_ ##_ver *data,\
|
||||
int len) \
|
||||
{ \
|
||||
struct iwl_wowlan_status_data *status; \
|
||||
int data_size, i; \
|
||||
\
|
||||
if (len < sizeof(*data)) { \
|
||||
IWL_ERR(mvm, "Invalid WoWLAN status response!\n"); \
|
||||
return NULL; \
|
||||
} \
|
||||
\
|
||||
data_size = ALIGN(le32_to_cpu(data->wake_packet_bufsize), 4); \
|
||||
if (len != sizeof(*data) + data_size) { \
|
||||
IWL_ERR(mvm, "Invalid WoWLAN status response!\n"); \
|
||||
return NULL; \
|
||||
} \
|
||||
\
|
||||
status = kzalloc(sizeof(*status) + data_size, GFP_KERNEL); \
|
||||
if (!status) \
|
||||
return NULL; \
|
||||
\
|
||||
/* copy all the common fields */ \
|
||||
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, \
|
||||
status->wake_packet_bufsize); \
|
||||
\
|
||||
return status; \
|
||||
}
|
||||
|
||||
iwl_mvm_parse_wowlan_status_common(v6)
|
||||
iwl_mvm_parse_wowlan_status_common(v7)
|
||||
iwl_mvm_parse_wowlan_status_common(v9)
|
||||
iwl_mvm_parse_wowlan_status_common(v12)
|
||||
|
||||
static void iwl_mvm_convert_gtk_v2(struct iwl_wowlan_status_data *status,
|
||||
struct iwl_wowlan_gtk_status_v2 *data)
|
||||
{
|
||||
|
|
@ -2054,6 +2003,96 @@ static void iwl_mvm_convert_igtk(struct iwl_wowlan_status_data *status,
|
|||
((u64)ipn[0] << 40);
|
||||
}
|
||||
|
||||
static void iwl_mvm_parse_wowlan_info_notif(struct iwl_mvm *mvm,
|
||||
struct iwl_wowlan_info_notif *data,
|
||||
struct iwl_wowlan_status_data *status,
|
||||
u32 len)
|
||||
{
|
||||
u32 i;
|
||||
|
||||
if (len < sizeof(*data)) {
|
||||
IWL_ERR(mvm, "Invalid WoWLAN info notification!\n");
|
||||
status = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
iwl_mvm_convert_key_counters_v5(status, &data->gtk[0].sc);
|
||||
iwl_mvm_convert_gtk_v3(status, &data->gtk[0]);
|
||||
iwl_mvm_convert_igtk(status, &data->igtk[0]);
|
||||
|
||||
status->replay_ctr = le64_to_cpu(data->replay_ctr);
|
||||
status->pattern_number = le16_to_cpu(data->pattern_number);
|
||||
for (i = 0; i < IWL_MAX_TID_COUNT; 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->tid_tear_down = data->tid_tear_down;
|
||||
}
|
||||
|
||||
/* Occasionally, templates would be nice. This is one of those times ... */
|
||||
#define iwl_mvm_parse_wowlan_status_common(_ver) \
|
||||
static struct iwl_wowlan_status_data * \
|
||||
iwl_mvm_parse_wowlan_status_common_ ## _ver(struct iwl_mvm *mvm, \
|
||||
struct iwl_wowlan_status_ ##_ver *data,\
|
||||
int len) \
|
||||
{ \
|
||||
struct iwl_wowlan_status_data *status; \
|
||||
int data_size, i; \
|
||||
\
|
||||
if (len < sizeof(*data)) { \
|
||||
IWL_ERR(mvm, "Invalid WoWLAN status response!\n"); \
|
||||
return NULL; \
|
||||
} \
|
||||
\
|
||||
data_size = ALIGN(le32_to_cpu(data->wake_packet_bufsize), 4); \
|
||||
if (len != sizeof(*data) + data_size) { \
|
||||
IWL_ERR(mvm, "Invalid WoWLAN status response!\n"); \
|
||||
return NULL; \
|
||||
} \
|
||||
\
|
||||
status = kzalloc(sizeof(*status), GFP_KERNEL); \
|
||||
if (!status) \
|
||||
return NULL; \
|
||||
\
|
||||
/* copy all the common fields */ \
|
||||
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); \
|
||||
if (status->wake_packet_bufsize) { \
|
||||
status->wake_packet = \
|
||||
kmemdup(data->wake_packet, \
|
||||
status->wake_packet_bufsize, \
|
||||
GFP_KERNEL); \
|
||||
if (!status->wake_packet) { \
|
||||
kfree(status); \
|
||||
return NULL; \
|
||||
} \
|
||||
} else { \
|
||||
status->wake_packet = NULL; \
|
||||
} \
|
||||
\
|
||||
return status; \
|
||||
}
|
||||
|
||||
iwl_mvm_parse_wowlan_status_common(v6)
|
||||
iwl_mvm_parse_wowlan_status_common(v7)
|
||||
iwl_mvm_parse_wowlan_status_common(v9)
|
||||
iwl_mvm_parse_wowlan_status_common(v12)
|
||||
|
||||
static struct iwl_wowlan_status_data *
|
||||
iwl_mvm_send_wowlan_get_status(struct iwl_mvm *mvm, u8 sta_id)
|
||||
{
|
||||
|
|
@ -2173,36 +2212,15 @@ iwl_mvm_send_wowlan_get_status(struct iwl_mvm *mvm, u8 sta_id)
|
|||
return 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, OFFLOADS_QUERY_CMD,
|
||||
IWL_FW_CMD_VER_UNKNOWN);
|
||||
__le32 station_id = cpu_to_le32(sta_id);
|
||||
u32 cmd_size = cmd_ver != IWL_FW_CMD_VER_UNKNOWN ? sizeof(station_id) : 0;
|
||||
|
||||
if (!mvm->net_detect) {
|
||||
/* only for tracing for now */
|
||||
int ret = iwl_mvm_send_cmd_pdu(mvm, OFFLOADS_QUERY_CMD, 0,
|
||||
cmd_size, &station_id);
|
||||
if (ret)
|
||||
IWL_ERR(mvm, "failed to query offload statistics (%d)\n", ret);
|
||||
}
|
||||
|
||||
return iwl_mvm_send_wowlan_get_status(mvm, sta_id);
|
||||
}
|
||||
|
||||
/* releases the MVM mutex */
|
||||
static bool iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm,
|
||||
struct ieee80211_vif *vif)
|
||||
struct ieee80211_vif *vif,
|
||||
struct iwl_wowlan_status_data *status)
|
||||
{
|
||||
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
|
||||
struct iwl_wowlan_status_data *status;
|
||||
int i;
|
||||
bool keep;
|
||||
struct iwl_mvm_sta *mvm_ap_sta;
|
||||
|
||||
status = iwl_mvm_get_wakeup_status(mvm, mvmvif->ap_sta_id);
|
||||
if (!status)
|
||||
goto out_unlock;
|
||||
|
||||
|
|
@ -2212,7 +2230,7 @@ static bool iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm,
|
|||
/* still at hard-coded place 0 for D3 image */
|
||||
mvm_ap_sta = iwl_mvm_sta_from_staid_protected(mvm, 0);
|
||||
if (!mvm_ap_sta)
|
||||
goto out_free;
|
||||
goto out_unlock;
|
||||
|
||||
for (i = 0; i < IWL_MAX_TID_COUNT; i++) {
|
||||
u16 seq = status->qos_seq_ctr[i];
|
||||
|
|
@ -2235,11 +2253,8 @@ static bool iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm,
|
|||
|
||||
keep = iwl_mvm_setup_connection_keep(mvm, vif, status);
|
||||
|
||||
kfree(status);
|
||||
return keep;
|
||||
|
||||
out_free:
|
||||
kfree(status);
|
||||
out_unlock:
|
||||
mutex_unlock(&mvm->mutex);
|
||||
return false;
|
||||
|
|
@ -2248,16 +2263,16 @@ static bool iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm,
|
|||
#define ND_QUERY_BUF_LEN (sizeof(struct iwl_scan_offload_profile_match) * \
|
||||
IWL_SCAN_MAX_PROFILES)
|
||||
|
||||
struct iwl_mvm_nd_query_results {
|
||||
struct iwl_mvm_nd_results {
|
||||
u32 matched_profiles;
|
||||
u8 matches[ND_QUERY_BUF_LEN];
|
||||
};
|
||||
|
||||
static int
|
||||
iwl_mvm_netdetect_query_results(struct iwl_mvm *mvm,
|
||||
struct iwl_mvm_nd_query_results *results)
|
||||
struct iwl_mvm_nd_results *results)
|
||||
{
|
||||
struct iwl_scan_offload_profiles_query *query;
|
||||
struct iwl_scan_offload_match_info *query;
|
||||
struct iwl_host_cmd cmd = {
|
||||
.id = SCAN_OFFLOAD_PROFILES_QUERY_CMD,
|
||||
.flags = CMD_WANT_SKB,
|
||||
|
|
@ -2274,7 +2289,7 @@ iwl_mvm_netdetect_query_results(struct iwl_mvm *mvm,
|
|||
|
||||
if (fw_has_api(&mvm->fw->ucode_capa,
|
||||
IWL_UCODE_TLV_API_SCAN_OFFLOAD_CHANS)) {
|
||||
query_len = sizeof(struct iwl_scan_offload_profiles_query);
|
||||
query_len = sizeof(struct iwl_scan_offload_match_info);
|
||||
matches_len = sizeof(struct iwl_scan_offload_profile_match) *
|
||||
max_profiles;
|
||||
} else {
|
||||
|
|
@ -2305,7 +2320,7 @@ iwl_mvm_netdetect_query_results(struct iwl_mvm *mvm,
|
|||
}
|
||||
|
||||
static int iwl_mvm_query_num_match_chans(struct iwl_mvm *mvm,
|
||||
struct iwl_mvm_nd_query_results *query,
|
||||
struct iwl_mvm_nd_results *results,
|
||||
int idx)
|
||||
{
|
||||
int n_chans = 0, i;
|
||||
|
|
@ -2313,13 +2328,13 @@ static int iwl_mvm_query_num_match_chans(struct iwl_mvm *mvm,
|
|||
if (fw_has_api(&mvm->fw->ucode_capa,
|
||||
IWL_UCODE_TLV_API_SCAN_OFFLOAD_CHANS)) {
|
||||
struct iwl_scan_offload_profile_match *matches =
|
||||
(struct iwl_scan_offload_profile_match *)query->matches;
|
||||
(void *)results->matches;
|
||||
|
||||
for (i = 0; i < SCAN_OFFLOAD_MATCHING_CHANNELS_LEN; i++)
|
||||
n_chans += hweight8(matches[idx].matching_channels[i]);
|
||||
} else {
|
||||
struct iwl_scan_offload_profile_match_v1 *matches =
|
||||
(struct iwl_scan_offload_profile_match_v1 *)query->matches;
|
||||
(void *)results->matches;
|
||||
|
||||
for (i = 0; i < SCAN_OFFLOAD_MATCHING_CHANNELS_LEN_V1; i++)
|
||||
n_chans += hweight8(matches[idx].matching_channels[i]);
|
||||
|
|
@ -2329,7 +2344,7 @@ static int iwl_mvm_query_num_match_chans(struct iwl_mvm *mvm,
|
|||
}
|
||||
|
||||
static void iwl_mvm_query_set_freqs(struct iwl_mvm *mvm,
|
||||
struct iwl_mvm_nd_query_results *query,
|
||||
struct iwl_mvm_nd_results *results,
|
||||
struct cfg80211_wowlan_nd_match *match,
|
||||
int idx)
|
||||
{
|
||||
|
|
@ -2338,7 +2353,7 @@ static void iwl_mvm_query_set_freqs(struct iwl_mvm *mvm,
|
|||
if (fw_has_api(&mvm->fw->ucode_capa,
|
||||
IWL_UCODE_TLV_API_SCAN_OFFLOAD_CHANS)) {
|
||||
struct iwl_scan_offload_profile_match *matches =
|
||||
(struct iwl_scan_offload_profile_match *)query->matches;
|
||||
(void *)results->matches;
|
||||
|
||||
for (i = 0; i < SCAN_OFFLOAD_MATCHING_CHANNELS_LEN * 8; i++)
|
||||
if (matches[idx].matching_channels[i / 8] & (BIT(i % 8)))
|
||||
|
|
@ -2346,7 +2361,7 @@ static void iwl_mvm_query_set_freqs(struct iwl_mvm *mvm,
|
|||
mvm->nd_channels[i]->center_freq;
|
||||
} else {
|
||||
struct iwl_scan_offload_profile_match_v1 *matches =
|
||||
(struct iwl_scan_offload_profile_match_v1 *)query->matches;
|
||||
(void *)results->matches;
|
||||
|
||||
for (i = 0; i < SCAN_OFFLOAD_MATCHING_CHANNELS_LEN_V1 * 8; i++)
|
||||
if (matches[idx].matching_channels[i / 8] & (BIT(i % 8)))
|
||||
|
|
@ -2355,25 +2370,50 @@ static void iwl_mvm_query_set_freqs(struct iwl_mvm *mvm,
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* enum iwl_d3_notif - d3 notifications
|
||||
* @IWL_D3_NOTIF_WOWLAN_INFO: WOWLAN_INFO_NOTIF was received
|
||||
* @IWL_D3_NOTIF_WOWLAN_WAKE_PKT: WOWLAN_WAKE_PKT_NOTIF was received
|
||||
* @IWL_D3_NOTIF_PROT_OFFLOAD: PROT_OFFLOAD_NOTIF was received
|
||||
* @IWL_D3_ND_MATCH_INFO: OFFLOAD_MATCH_INFO_NOTIF was received
|
||||
* @IWL_D3_NOTIF_D3_END_NOTIF: D3_END_NOTIF was received
|
||||
*/
|
||||
enum iwl_d3_notif {
|
||||
IWL_D3_NOTIF_WOWLAN_INFO = BIT(0),
|
||||
IWL_D3_NOTIF_WOWLAN_WAKE_PKT = BIT(1),
|
||||
IWL_D3_NOTIF_PROT_OFFLOAD = BIT(2),
|
||||
IWL_D3_ND_MATCH_INFO = BIT(3),
|
||||
IWL_D3_NOTIF_D3_END_NOTIF = BIT(4)
|
||||
};
|
||||
|
||||
/* manage d3 resume data */
|
||||
struct iwl_d3_data {
|
||||
struct iwl_wowlan_status_data *status;
|
||||
bool test;
|
||||
u32 d3_end_flags;
|
||||
u32 notif_expected; /* bitmap - see &enum iwl_d3_notif */
|
||||
u32 notif_received; /* bitmap - see &enum iwl_d3_notif */
|
||||
struct iwl_mvm_nd_results *nd_results;
|
||||
bool nd_results_valid;
|
||||
};
|
||||
|
||||
static void iwl_mvm_query_netdetect_reasons(struct iwl_mvm *mvm,
|
||||
struct ieee80211_vif *vif)
|
||||
struct ieee80211_vif *vif,
|
||||
struct iwl_d3_data *d3_data)
|
||||
{
|
||||
struct cfg80211_wowlan_nd_info *net_detect = NULL;
|
||||
struct cfg80211_wowlan_wakeup wakeup = {
|
||||
.pattern_idx = -1,
|
||||
};
|
||||
struct cfg80211_wowlan_wakeup *wakeup_report = &wakeup;
|
||||
struct iwl_wowlan_status_data *status;
|
||||
struct iwl_mvm_nd_query_results query;
|
||||
unsigned long matched_profiles;
|
||||
u32 reasons = 0;
|
||||
int i, n_matches, ret;
|
||||
|
||||
status = iwl_mvm_get_wakeup_status(mvm, IWL_MVM_INVALID_STA);
|
||||
if (status) {
|
||||
reasons = status->wakeup_reasons;
|
||||
kfree(status);
|
||||
}
|
||||
if (WARN_ON(!d3_data || !d3_data->status))
|
||||
goto out;
|
||||
|
||||
reasons = d3_data->status->wakeup_reasons;
|
||||
|
||||
if (reasons & IWL_WOWLAN_WAKEUP_BY_RFKILL_DEASSERTED)
|
||||
wakeup.rfkill_release = true;
|
||||
|
|
@ -2381,13 +2421,22 @@ static void iwl_mvm_query_netdetect_reasons(struct iwl_mvm *mvm,
|
|||
if (reasons != IWL_WOWLAN_WAKEUP_BY_NON_WIRELESS)
|
||||
goto out;
|
||||
|
||||
ret = iwl_mvm_netdetect_query_results(mvm, &query);
|
||||
if (ret || !query.matched_profiles) {
|
||||
if (!iwl_fw_lookup_notif_ver(mvm->fw, PROT_OFFLOAD_GROUP,
|
||||
WOWLAN_INFO_NOTIFICATION, 0)) {
|
||||
IWL_INFO(mvm, "Query FW for ND results\n");
|
||||
ret = iwl_mvm_netdetect_query_results(mvm, d3_data->nd_results);
|
||||
|
||||
} else {
|
||||
IWL_INFO(mvm, "Notification based ND results\n");
|
||||
ret = d3_data->nd_results_valid ? 0 : -1;
|
||||
}
|
||||
|
||||
if (ret || !d3_data->nd_results->matched_profiles) {
|
||||
wakeup_report = NULL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
matched_profiles = query.matched_profiles;
|
||||
matched_profiles = d3_data->nd_results->matched_profiles;
|
||||
if (mvm->n_nd_match_sets) {
|
||||
n_matches = hweight_long(matched_profiles);
|
||||
} else {
|
||||
|
|
@ -2404,7 +2453,9 @@ static void iwl_mvm_query_netdetect_reasons(struct iwl_mvm *mvm,
|
|||
struct cfg80211_wowlan_nd_match *match;
|
||||
int idx, n_channels = 0;
|
||||
|
||||
n_channels = iwl_mvm_query_num_match_chans(mvm, &query, i);
|
||||
n_channels = iwl_mvm_query_num_match_chans(mvm,
|
||||
d3_data->nd_results,
|
||||
i);
|
||||
|
||||
match = kzalloc(struct_size(match, channels, n_channels),
|
||||
GFP_KERNEL);
|
||||
|
|
@ -2424,7 +2475,7 @@ static void iwl_mvm_query_netdetect_reasons(struct iwl_mvm *mvm,
|
|||
if (mvm->n_nd_channels < n_channels)
|
||||
continue;
|
||||
|
||||
iwl_mvm_query_set_freqs(mvm, &query, match, i);
|
||||
iwl_mvm_query_set_freqs(mvm, d3_data->nd_results, match, i);
|
||||
}
|
||||
|
||||
out_report_nd:
|
||||
|
|
@ -2504,16 +2555,317 @@ static bool iwl_mvm_check_rt_status(struct iwl_mvm *mvm,
|
|||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function assumes:
|
||||
* 1. The mutex is already held.
|
||||
* 2. The callee functions unlock the mutex.
|
||||
*/
|
||||
static bool
|
||||
iwl_mvm_choose_query_wakeup_reasons(struct iwl_mvm *mvm,
|
||||
struct ieee80211_vif *vif,
|
||||
struct iwl_d3_data *d3_data)
|
||||
{
|
||||
lockdep_assert_held(&mvm->mutex);
|
||||
|
||||
/* if FW uses status notification, status shouldn't be NULL here */
|
||||
if (!d3_data->status) {
|
||||
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
|
||||
u8 sta_id = mvm->net_detect ? IWL_MVM_INVALID_STA : mvmvif->ap_sta_id;
|
||||
|
||||
d3_data->status = iwl_mvm_send_wowlan_get_status(mvm, sta_id);
|
||||
}
|
||||
|
||||
if (mvm->net_detect) {
|
||||
iwl_mvm_query_netdetect_reasons(mvm, vif, d3_data);
|
||||
} else {
|
||||
bool keep = iwl_mvm_query_wakeup_reasons(mvm, vif,
|
||||
d3_data->status);
|
||||
|
||||
#ifdef CONFIG_IWLWIFI_DEBUGFS
|
||||
if (keep)
|
||||
mvm->keep_vif = vif;
|
||||
#endif
|
||||
|
||||
return keep;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#define IWL_WOWLAN_WAKEUP_REASON_HAS_WAKEUP_PKT (IWL_WOWLAN_WAKEUP_BY_MAGIC_PACKET | \
|
||||
IWL_WOWLAN_WAKEUP_BY_PATTERN | \
|
||||
IWL_WAKEUP_BY_PATTERN_IPV4_TCP_SYN |\
|
||||
IWL_WAKEUP_BY_PATTERN_IPV4_TCP_SYN_WILDCARD |\
|
||||
IWL_WAKEUP_BY_PATTERN_IPV6_TCP_SYN |\
|
||||
IWL_WAKEUP_BY_PATTERN_IPV6_TCP_SYN_WILDCARD)
|
||||
|
||||
static int iwl_mvm_wowlan_store_wake_pkt(struct iwl_mvm *mvm,
|
||||
struct iwl_wowlan_wake_pkt_notif *notif,
|
||||
struct iwl_wowlan_status_data *status,
|
||||
u32 len)
|
||||
{
|
||||
u32 data_size, packet_len = le32_to_cpu(notif->wake_packet_length);
|
||||
|
||||
if (len < sizeof(*notif)) {
|
||||
IWL_ERR(mvm, "Invalid WoWLAN wake packet notification!\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (WARN_ON(!status)) {
|
||||
IWL_ERR(mvm, "Got wake packet notification but wowlan status data is NULL\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (WARN_ON(!(status->wakeup_reasons &
|
||||
IWL_WOWLAN_WAKEUP_REASON_HAS_WAKEUP_PKT))) {
|
||||
IWL_ERR(mvm, "Got wakeup packet but wakeup reason is %x\n",
|
||||
status->wakeup_reasons);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
data_size = len - offsetof(struct iwl_wowlan_wake_pkt_notif, wake_packet);
|
||||
|
||||
/* data_size got the padding from the notification, remove it. */
|
||||
if (packet_len < data_size)
|
||||
data_size = packet_len;
|
||||
|
||||
status->wake_packet = kmemdup(notif->wake_packet, data_size,
|
||||
GFP_ATOMIC);
|
||||
|
||||
if (!status->wake_packet)
|
||||
return -ENOMEM;
|
||||
|
||||
status->wake_packet_length = packet_len;
|
||||
status->wake_packet_bufsize = data_size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void iwl_mvm_nd_match_info_handler(struct iwl_mvm *mvm,
|
||||
struct iwl_d3_data *d3_data,
|
||||
struct iwl_scan_offload_match_info *notif,
|
||||
u32 len)
|
||||
{
|
||||
struct iwl_wowlan_status_data *status = d3_data->status;
|
||||
struct ieee80211_vif *vif = iwl_mvm_get_bss_vif(mvm);
|
||||
struct iwl_mvm_nd_results *results = d3_data->nd_results;
|
||||
size_t i, matches_len = sizeof(struct iwl_scan_offload_profile_match) *
|
||||
iwl_umac_scan_get_max_profiles(mvm->fw);
|
||||
|
||||
if (IS_ERR_OR_NULL(vif))
|
||||
return;
|
||||
|
||||
if (len < sizeof(struct iwl_scan_offload_match_info)) {
|
||||
IWL_ERR(mvm, "Invalid scan match info notification\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mvm->net_detect) {
|
||||
IWL_ERR(mvm, "Unexpected scan match info notification\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!status || status->wakeup_reasons != IWL_WOWLAN_WAKEUP_BY_NON_WIRELESS) {
|
||||
IWL_ERR(mvm,
|
||||
"Ignore scan match info notification: no reason\n");
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IWLWIFI_DEBUGFS
|
||||
mvm->last_netdetect_scans = le32_to_cpu(notif->n_scans_done);
|
||||
#endif
|
||||
|
||||
results->matched_profiles = le32_to_cpu(notif->matched_profiles);
|
||||
IWL_INFO(mvm, "number of matched profiles=%u\n",
|
||||
results->matched_profiles);
|
||||
|
||||
if (results->matched_profiles) {
|
||||
memcpy(results->matches, notif->matches, matches_len);
|
||||
d3_data->nd_results_valid = TRUE;
|
||||
}
|
||||
|
||||
/* no scan should be active at this point */
|
||||
mvm->scan_status = 0;
|
||||
for (i = 0; i < mvm->max_scans; i++)
|
||||
mvm->scan_uid_status[i] = 0;
|
||||
}
|
||||
|
||||
static bool iwl_mvm_wait_d3_notif(struct iwl_notif_wait_data *notif_wait,
|
||||
struct iwl_rx_packet *pkt, void *data)
|
||||
{
|
||||
struct iwl_mvm *mvm =
|
||||
container_of(notif_wait, struct iwl_mvm, notif_wait);
|
||||
struct iwl_d3_data *d3_data = data;
|
||||
u32 len;
|
||||
int ret;
|
||||
|
||||
switch (WIDE_ID(pkt->hdr.group_id, pkt->hdr.cmd)) {
|
||||
case WIDE_ID(PROT_OFFLOAD_GROUP, WOWLAN_INFO_NOTIFICATION): {
|
||||
struct iwl_wowlan_info_notif *notif = (void *)pkt->data;
|
||||
|
||||
if (d3_data->notif_received & IWL_D3_NOTIF_WOWLAN_INFO) {
|
||||
/* We might get two notifications due to dual bss */
|
||||
IWL_DEBUG_WOWLAN(mvm,
|
||||
"Got additional wowlan info notification\n");
|
||||
break;
|
||||
}
|
||||
|
||||
d3_data->notif_received |= IWL_D3_NOTIF_WOWLAN_INFO;
|
||||
len = iwl_rx_packet_payload_len(pkt);
|
||||
iwl_mvm_parse_wowlan_info_notif(mvm, notif, d3_data->status,
|
||||
len);
|
||||
if (d3_data->status &&
|
||||
d3_data->status->wakeup_reasons & IWL_WOWLAN_WAKEUP_REASON_HAS_WAKEUP_PKT)
|
||||
/* We are supposed to get also wake packet notif */
|
||||
d3_data->notif_expected |= IWL_D3_NOTIF_WOWLAN_WAKE_PKT;
|
||||
|
||||
break;
|
||||
}
|
||||
case WIDE_ID(PROT_OFFLOAD_GROUP, WOWLAN_WAKE_PKT_NOTIFICATION): {
|
||||
struct iwl_wowlan_wake_pkt_notif *notif = (void *)pkt->data;
|
||||
|
||||
if (d3_data->notif_received & IWL_D3_NOTIF_WOWLAN_WAKE_PKT) {
|
||||
/* We shouldn't get two wake packet notifications */
|
||||
IWL_ERR(mvm,
|
||||
"Got additional wowlan wake packet notification\n");
|
||||
} else {
|
||||
d3_data->notif_received |= IWL_D3_NOTIF_WOWLAN_WAKE_PKT;
|
||||
len = iwl_rx_packet_payload_len(pkt);
|
||||
ret = iwl_mvm_wowlan_store_wake_pkt(mvm, notif,
|
||||
d3_data->status,
|
||||
len);
|
||||
if (ret)
|
||||
IWL_ERR(mvm,
|
||||
"Can't parse WOWLAN_WAKE_PKT_NOTIFICATION\n");
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case WIDE_ID(SCAN_GROUP, OFFLOAD_MATCH_INFO_NOTIF): {
|
||||
struct iwl_scan_offload_match_info *notif = (void *)pkt->data;
|
||||
|
||||
if (d3_data->notif_received & IWL_D3_ND_MATCH_INFO) {
|
||||
IWL_ERR(mvm,
|
||||
"Got additional netdetect match info\n");
|
||||
break;
|
||||
}
|
||||
|
||||
d3_data->notif_received |= IWL_D3_ND_MATCH_INFO;
|
||||
|
||||
/* explicitly set this in the 'expected' as well */
|
||||
d3_data->notif_expected |= IWL_D3_ND_MATCH_INFO;
|
||||
|
||||
len = iwl_rx_packet_payload_len(pkt);
|
||||
iwl_mvm_nd_match_info_handler(mvm, d3_data, notif, len);
|
||||
break;
|
||||
}
|
||||
case WIDE_ID(PROT_OFFLOAD_GROUP, D3_END_NOTIFICATION): {
|
||||
struct iwl_mvm_d3_end_notif *notif = (void *)pkt->data;
|
||||
|
||||
d3_data->d3_end_flags = __le32_to_cpu(notif->flags);
|
||||
d3_data->notif_received |= IWL_D3_NOTIF_D3_END_NOTIF;
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
WARN_ON(1);
|
||||
}
|
||||
|
||||
return d3_data->notif_received == d3_data->notif_expected;
|
||||
}
|
||||
|
||||
static int iwl_mvm_resume_firmware(struct iwl_mvm *mvm, bool test)
|
||||
{
|
||||
int ret;
|
||||
enum iwl_d3_status d3_status;
|
||||
struct iwl_host_cmd cmd = {
|
||||
.id = D0I3_END_CMD,
|
||||
.flags = CMD_WANT_SKB | CMD_SEND_IN_D3,
|
||||
};
|
||||
bool reset = fw_has_capa(&mvm->fw->ucode_capa,
|
||||
IWL_UCODE_TLV_CAPA_CNSLDTD_D3_D0_IMG);
|
||||
|
||||
ret = iwl_trans_d3_resume(mvm->trans, &d3_status, test, !reset);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (d3_status != IWL_D3_STATUS_ALIVE) {
|
||||
IWL_INFO(mvm, "Device was reset during suspend\n");
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
/*
|
||||
* We should trigger resume flow using command only for 22000 family
|
||||
* AX210 and above don't need the command since they have
|
||||
* the doorbell interrupt.
|
||||
*/
|
||||
if (mvm->trans->trans_cfg->device_family <= IWL_DEVICE_FAMILY_22000 &&
|
||||
fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_D0I3_END_FIRST)) {
|
||||
ret = iwl_mvm_send_cmd(mvm, &cmd);
|
||||
if (ret < 0)
|
||||
IWL_ERR(mvm, "Failed to send D0I3_END_CMD first (%d)\n",
|
||||
ret);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define IWL_MVM_D3_NOTIF_TIMEOUT (HZ / 5)
|
||||
|
||||
static int iwl_mvm_d3_notif_wait(struct iwl_mvm *mvm,
|
||||
struct iwl_d3_data *d3_data)
|
||||
{
|
||||
static const u16 d3_resume_notif[] = {
|
||||
WIDE_ID(PROT_OFFLOAD_GROUP, WOWLAN_INFO_NOTIFICATION),
|
||||
WIDE_ID(PROT_OFFLOAD_GROUP, WOWLAN_WAKE_PKT_NOTIFICATION),
|
||||
WIDE_ID(SCAN_GROUP, OFFLOAD_MATCH_INFO_NOTIF),
|
||||
WIDE_ID(PROT_OFFLOAD_GROUP, D3_END_NOTIFICATION)
|
||||
};
|
||||
struct iwl_notification_wait wait_d3_notif;
|
||||
int ret;
|
||||
|
||||
iwl_init_notification_wait(&mvm->notif_wait, &wait_d3_notif,
|
||||
d3_resume_notif, ARRAY_SIZE(d3_resume_notif),
|
||||
iwl_mvm_wait_d3_notif, d3_data);
|
||||
|
||||
ret = iwl_mvm_resume_firmware(mvm, d3_data->test);
|
||||
if (ret) {
|
||||
iwl_remove_notification(&mvm->notif_wait, &wait_d3_notif);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return iwl_wait_notification(&mvm->notif_wait, &wait_d3_notif,
|
||||
IWL_MVM_D3_NOTIF_TIMEOUT);
|
||||
}
|
||||
|
||||
static inline bool iwl_mvm_d3_resume_notif_based(struct iwl_mvm *mvm)
|
||||
{
|
||||
return iwl_fw_lookup_notif_ver(mvm->fw, PROT_OFFLOAD_GROUP,
|
||||
WOWLAN_INFO_NOTIFICATION, 0) &&
|
||||
iwl_fw_lookup_notif_ver(mvm->fw, PROT_OFFLOAD_GROUP,
|
||||
WOWLAN_WAKE_PKT_NOTIFICATION, 0) &&
|
||||
iwl_fw_lookup_notif_ver(mvm->fw, PROT_OFFLOAD_GROUP,
|
||||
D3_END_NOTIFICATION, 0);
|
||||
}
|
||||
|
||||
static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test)
|
||||
{
|
||||
struct ieee80211_vif *vif = NULL;
|
||||
int ret = 1;
|
||||
enum iwl_d3_status d3_status;
|
||||
bool keep = false;
|
||||
struct iwl_mvm_nd_results results = {};
|
||||
struct iwl_d3_data d3_data = {
|
||||
.test = test,
|
||||
.notif_expected =
|
||||
IWL_D3_NOTIF_WOWLAN_INFO |
|
||||
IWL_D3_NOTIF_D3_END_NOTIF,
|
||||
.nd_results_valid = false,
|
||||
.nd_results = &results,
|
||||
};
|
||||
bool unified_image = fw_has_capa(&mvm->fw->ucode_capa,
|
||||
IWL_UCODE_TLV_CAPA_CNSLDTD_D3_D0_IMG);
|
||||
bool d0i3_first = fw_has_capa(&mvm->fw->ucode_capa,
|
||||
IWL_UCODE_TLV_CAPA_D0I3_END_FIRST);
|
||||
bool resume_notif_based = iwl_mvm_d3_resume_notif_based(mvm);
|
||||
bool keep = false;
|
||||
|
||||
mutex_lock(&mvm->mutex);
|
||||
|
||||
|
|
@ -2537,54 +2889,30 @@ static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test)
|
|||
goto err;
|
||||
}
|
||||
|
||||
ret = iwl_trans_d3_resume(mvm->trans, &d3_status, test, !unified_image);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
if (d3_status != IWL_D3_STATUS_ALIVE) {
|
||||
IWL_INFO(mvm, "Device was reset during suspend\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (d0i3_first) {
|
||||
struct iwl_host_cmd cmd = {
|
||||
.id = D0I3_END_CMD,
|
||||
.flags = CMD_WANT_SKB | CMD_SEND_IN_D3,
|
||||
};
|
||||
int len;
|
||||
|
||||
ret = iwl_mvm_send_cmd(mvm, &cmd);
|
||||
if (ret < 0) {
|
||||
IWL_ERR(mvm, "Failed to send D0I3_END_CMD first (%d)\n",
|
||||
ret);
|
||||
if (resume_notif_based) {
|
||||
d3_data.status = kzalloc(sizeof(*d3_data.status), GFP_KERNEL);
|
||||
if (!d3_data.status) {
|
||||
IWL_ERR(mvm, "Failed to allocate wowlan status\n");
|
||||
ret = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
switch (mvm->cmd_ver.d0i3_resp) {
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
len = iwl_rx_packet_payload_len(cmd.resp_pkt);
|
||||
if (len != sizeof(u32)) {
|
||||
IWL_ERR(mvm,
|
||||
"Error with D0I3_END_CMD response size (%d)\n",
|
||||
len);
|
||||
goto err;
|
||||
}
|
||||
if (IWL_D0I3_RESET_REQUIRE &
|
||||
le32_to_cpu(*(__le32 *)cmd.resp_pkt->data)) {
|
||||
iwl_write32(mvm->trans, CSR_RESET,
|
||||
CSR_RESET_REG_FLAG_FORCE_NMI);
|
||||
iwl_free_resp(&cmd);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
WARN_ON(1);
|
||||
}
|
||||
|
||||
ret = iwl_mvm_d3_notif_wait(mvm, &d3_data);
|
||||
if (ret)
|
||||
goto err;
|
||||
} else {
|
||||
ret = iwl_mvm_resume_firmware(mvm, test);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* after the successful handshake, we're out of D3 */
|
||||
mvm->trans->system_pm_mode = IWL_PLAT_PM_MODE_DISABLED;
|
||||
|
||||
/* when reset is required we can't send these following commands */
|
||||
if (d3_data.d3_end_flags & IWL_D0I3_RESET_REQUIRE)
|
||||
goto query_wakeup_reasons;
|
||||
|
||||
/*
|
||||
* Query the current location and source from the D3 firmware so we
|
||||
* can play it back when we re-intiailize the D0 firmware
|
||||
|
|
@ -2598,41 +2926,36 @@ static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test)
|
|||
/* Re-configure default SAR profile */
|
||||
iwl_mvm_sar_select_profile(mvm, 1, 1);
|
||||
|
||||
if (mvm->net_detect) {
|
||||
if (mvm->net_detect && unified_image) {
|
||||
/* If this is a non-unified image, we restart the FW,
|
||||
* so no need to stop the netdetect scan. If that
|
||||
* fails, continue and try to get the wake-up reasons,
|
||||
* but trigger a HW restart by keeping a failure code
|
||||
* in ret.
|
||||
*/
|
||||
if (unified_image)
|
||||
ret = iwl_mvm_scan_stop(mvm, IWL_MVM_SCAN_NETDETECT,
|
||||
false);
|
||||
|
||||
iwl_mvm_query_netdetect_reasons(mvm, vif);
|
||||
/* has unlocked the mutex, so skip that */
|
||||
goto out;
|
||||
} else {
|
||||
keep = iwl_mvm_query_wakeup_reasons(mvm, vif);
|
||||
#ifdef CONFIG_IWLWIFI_DEBUGFS
|
||||
if (keep)
|
||||
mvm->keep_vif = vif;
|
||||
#endif
|
||||
/* has unlocked the mutex, so skip that */
|
||||
goto out_iterate;
|
||||
ret = iwl_mvm_scan_stop(mvm, IWL_MVM_SCAN_NETDETECT,
|
||||
false);
|
||||
}
|
||||
|
||||
query_wakeup_reasons:
|
||||
keep = iwl_mvm_choose_query_wakeup_reasons(mvm, vif, &d3_data);
|
||||
/* has unlocked the mutex, so skip that */
|
||||
goto out;
|
||||
|
||||
err:
|
||||
iwl_mvm_free_nd(mvm);
|
||||
mutex_unlock(&mvm->mutex);
|
||||
|
||||
out_iterate:
|
||||
if (!test)
|
||||
ieee80211_iterate_active_interfaces_mtx(mvm->hw,
|
||||
IEEE80211_IFACE_ITER_NORMAL,
|
||||
iwl_mvm_d3_disconnect_iter, keep ? vif : NULL);
|
||||
|
||||
out:
|
||||
if (d3_data.status)
|
||||
kfree(d3_data.status->wake_packet);
|
||||
kfree(d3_data.status);
|
||||
iwl_mvm_free_nd(mvm);
|
||||
|
||||
if (!d3_data.test && !mvm->net_detect)
|
||||
ieee80211_iterate_active_interfaces_mtx(mvm->hw,
|
||||
IEEE80211_IFACE_ITER_NORMAL,
|
||||
iwl_mvm_d3_disconnect_iter,
|
||||
keep ? vif : NULL);
|
||||
|
||||
clear_bit(IWL_MVM_STATUS_IN_D3, &mvm->status);
|
||||
|
||||
/* no need to reset the device in unified images, if successful */
|
||||
|
|
@ -2641,9 +2964,14 @@ static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test)
|
|||
if (d0i3_first)
|
||||
return 0;
|
||||
|
||||
ret = iwl_mvm_send_cmd_pdu(mvm, D0I3_END_CMD, 0, 0, NULL);
|
||||
if (!ret)
|
||||
if (!iwl_fw_lookup_notif_ver(mvm->fw, PROT_OFFLOAD_GROUP,
|
||||
D3_END_NOTIFICATION, 0)) {
|
||||
ret = iwl_mvm_send_cmd_pdu(mvm, D0I3_END_CMD, 0, 0, NULL);
|
||||
if (!ret)
|
||||
return 0;
|
||||
} else if (!(d3_data.d3_end_flags & IWL_D0I3_RESET_REQUIRE)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -4949,6 +4949,7 @@ static int iwl_mvm_mac_get_survey(struct ieee80211_hw *hw, int idx,
|
|||
static void iwl_mvm_set_sta_rate(u32 rate_n_flags, struct rate_info *rinfo)
|
||||
{
|
||||
u32 format = rate_n_flags & RATE_MCS_MOD_TYPE_MSK;
|
||||
u32 gi_ltf;
|
||||
|
||||
switch (rate_n_flags & RATE_MCS_CHAN_WIDTH_MSK) {
|
||||
case RATE_MCS_CHAN_WIDTH_20:
|
||||
|
|
@ -5019,9 +5020,12 @@ static void iwl_mvm_set_sta_rate(u32 rate_n_flags, struct rate_info *rinfo)
|
|||
RATE_HT_MCS_INDEX(rate_n_flags) :
|
||||
u32_get_bits(rate_n_flags, RATE_MCS_CODE_MSK);
|
||||
|
||||
if (format == RATE_MCS_HE_MSK) {
|
||||
u32 gi_ltf = u32_get_bits(rate_n_flags,
|
||||
RATE_MCS_HE_GI_LTF_MSK);
|
||||
if (rate_n_flags & RATE_MCS_SGI_MSK)
|
||||
rinfo->flags |= RATE_INFO_FLAGS_SHORT_GI;
|
||||
|
||||
switch (format) {
|
||||
case RATE_MCS_HE_MSK:
|
||||
gi_ltf = u32_get_bits(rate_n_flags, RATE_MCS_HE_GI_LTF_MSK);
|
||||
|
||||
rinfo->flags |= RATE_INFO_FLAGS_HE_MCS;
|
||||
|
||||
|
|
@ -5060,19 +5064,14 @@ static void iwl_mvm_set_sta_rate(u32 rate_n_flags, struct rate_info *rinfo)
|
|||
|
||||
if (rate_n_flags & RATE_HE_DUAL_CARRIER_MODE_MSK)
|
||||
rinfo->he_dcm = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
if (rate_n_flags & RATE_MCS_SGI_MSK)
|
||||
rinfo->flags |= RATE_INFO_FLAGS_SHORT_GI;
|
||||
|
||||
if (format == RATE_MCS_HT_MSK) {
|
||||
break;
|
||||
case RATE_MCS_HT_MSK:
|
||||
rinfo->flags |= RATE_INFO_FLAGS_MCS;
|
||||
|
||||
} else if (format == RATE_MCS_VHT_MSK) {
|
||||
break;
|
||||
case RATE_MCS_VHT_MSK:
|
||||
rinfo->flags |= RATE_INFO_FLAGS_VHT_MCS;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void iwl_mvm_mac_sta_statistics(struct ieee80211_hw *hw,
|
||||
|
|
|
|||
|
|
@ -1079,7 +1079,6 @@ struct iwl_mvm {
|
|||
struct list_head resp_pasn_list;
|
||||
|
||||
struct {
|
||||
u8 d0i3_resp;
|
||||
u8 range_resp;
|
||||
} cmd_ver;
|
||||
|
||||
|
|
|
|||
|
|
@ -554,6 +554,13 @@ static const struct iwl_hcmd_names iwl_mvm_data_path_names[] = {
|
|||
HCMD_NAME(RX_QUEUES_NOTIFICATION),
|
||||
};
|
||||
|
||||
/* Please keep this array *SORTED* by hex value.
|
||||
* Access is done through binary search
|
||||
*/
|
||||
static const struct iwl_hcmd_names iwl_mvm_scan_names[] = {
|
||||
HCMD_NAME(OFFLOAD_MATCH_INFO_NOTIF),
|
||||
};
|
||||
|
||||
/* Please keep this array *SORTED* by hex value.
|
||||
* Access is done through binary search
|
||||
*/
|
||||
|
|
@ -574,6 +581,9 @@ static const struct iwl_hcmd_names iwl_mvm_location_names[] = {
|
|||
* Access is done through binary search
|
||||
*/
|
||||
static const struct iwl_hcmd_names iwl_mvm_prot_offload_names[] = {
|
||||
HCMD_NAME(WOWLAN_WAKE_PKT_NOTIFICATION),
|
||||
HCMD_NAME(WOWLAN_INFO_NOTIFICATION),
|
||||
HCMD_NAME(D3_END_NOTIFICATION),
|
||||
HCMD_NAME(STORED_BEACON_NTF),
|
||||
};
|
||||
|
||||
|
|
@ -593,6 +603,7 @@ static const struct iwl_hcmd_arr iwl_mvm_groups[] = {
|
|||
[MAC_CONF_GROUP] = HCMD_ARR(iwl_mvm_mac_conf_names),
|
||||
[PHY_OPS_GROUP] = HCMD_ARR(iwl_mvm_phy_names),
|
||||
[DATA_PATH_GROUP] = HCMD_ARR(iwl_mvm_data_path_names),
|
||||
[SCAN_GROUP] = HCMD_ARR(iwl_mvm_scan_names),
|
||||
[LOCATION_GROUP] = HCMD_ARR(iwl_mvm_location_names),
|
||||
[PROT_OFFLOAD_GROUP] = HCMD_ARR(iwl_mvm_prot_offload_names),
|
||||
[REGULATORY_AND_NVM_GROUP] =
|
||||
|
|
@ -1188,13 +1199,6 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
|
|||
|
||||
INIT_DELAYED_WORK(&mvm->cs_tx_unblock_dwork, iwl_mvm_tx_unblock_dwork);
|
||||
|
||||
mvm->cmd_ver.d0i3_resp =
|
||||
iwl_fw_lookup_notif_ver(mvm->fw, LEGACY_GROUP, D0I3_END_CMD,
|
||||
0);
|
||||
/* we only support version 1 */
|
||||
if (WARN_ON_ONCE(mvm->cmd_ver.d0i3_resp > 1))
|
||||
goto out_free;
|
||||
|
||||
mvm->cmd_ver.range_resp =
|
||||
iwl_fw_lookup_notif_ver(mvm->fw, LOCATION_GROUP,
|
||||
TOF_RANGE_RESPONSE_NOTIF, 5);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
|
||||
/*
|
||||
* Copyright (C) 2012-2014, 2018-2021 Intel Corporation
|
||||
* Copyright (C) 2012-2014, 2018-2022 Intel Corporation
|
||||
* Copyright (C) 2013-2015 Intel Mobile Communications GmbH
|
||||
* Copyright (C) 2015-2017 Intel Deutschland GmbH
|
||||
*/
|
||||
|
|
@ -1191,16 +1191,22 @@ struct iwl_mvm_rx_phy_data {
|
|||
enum iwl_rx_phy_info_type info_type;
|
||||
__le32 d0, d1, d2, d3;
|
||||
__le16 d4;
|
||||
|
||||
u32 rate_n_flags;
|
||||
u32 gp2_on_air_rise;
|
||||
u16 phy_info;
|
||||
u8 energy_a, energy_b;
|
||||
u8 channel;
|
||||
};
|
||||
|
||||
static void iwl_mvm_decode_he_mu_ext(struct iwl_mvm *mvm,
|
||||
struct iwl_mvm_rx_phy_data *phy_data,
|
||||
u32 rate_n_flags,
|
||||
struct ieee80211_radiotap_he_mu *he_mu)
|
||||
{
|
||||
u32 phy_data2 = le32_to_cpu(phy_data->d2);
|
||||
u32 phy_data3 = le32_to_cpu(phy_data->d3);
|
||||
u16 phy_data4 = le16_to_cpu(phy_data->d4);
|
||||
u32 rate_n_flags = phy_data->rate_n_flags;
|
||||
|
||||
if (FIELD_GET(IWL_RX_PHY_DATA4_HE_MU_EXT_CH1_CRC_OK, phy_data4)) {
|
||||
he_mu->flags1 |=
|
||||
|
|
@ -1246,7 +1252,6 @@ static void iwl_mvm_decode_he_mu_ext(struct iwl_mvm *mvm,
|
|||
|
||||
static void
|
||||
iwl_mvm_decode_he_phy_ru_alloc(struct iwl_mvm_rx_phy_data *phy_data,
|
||||
u32 rate_n_flags,
|
||||
struct ieee80211_radiotap_he *he,
|
||||
struct ieee80211_radiotap_he_mu *he_mu,
|
||||
struct ieee80211_rx_status *rx_status)
|
||||
|
|
@ -1260,6 +1265,7 @@ iwl_mvm_decode_he_phy_ru_alloc(struct iwl_mvm_rx_phy_data *phy_data,
|
|||
* the TSF/timers are not be transmitted in HE-MU.
|
||||
*/
|
||||
u8 ru = le32_get_bits(phy_data->d1, IWL_RX_PHY_DATA1_HE_RU_ALLOC_MASK);
|
||||
u32 rate_n_flags = phy_data->rate_n_flags;
|
||||
u32 he_type = rate_n_flags & RATE_MCS_HE_TYPE_MSK_V1;
|
||||
u8 offs = 0;
|
||||
|
||||
|
|
@ -1331,7 +1337,7 @@ static void iwl_mvm_decode_he_phy_data(struct iwl_mvm *mvm,
|
|||
struct ieee80211_radiotap_he *he,
|
||||
struct ieee80211_radiotap_he_mu *he_mu,
|
||||
struct ieee80211_rx_status *rx_status,
|
||||
u32 rate_n_flags, int queue)
|
||||
int queue)
|
||||
{
|
||||
switch (phy_data->info_type) {
|
||||
case IWL_RX_PHY_INFO_TYPE_NONE:
|
||||
|
|
@ -1430,7 +1436,7 @@ static void iwl_mvm_decode_he_phy_data(struct iwl_mvm *mvm,
|
|||
le16_encode_bits(le16_get_bits(phy_data->d4,
|
||||
IWL_RX_PHY_DATA4_HE_MU_EXT_PREAMBLE_PUNC_TYPE_MASK),
|
||||
IEEE80211_RADIOTAP_HE_MU_FLAGS2_PUNC_FROM_SIG_A_BW);
|
||||
iwl_mvm_decode_he_mu_ext(mvm, phy_data, rate_n_flags, he_mu);
|
||||
iwl_mvm_decode_he_mu_ext(mvm, phy_data, he_mu);
|
||||
fallthrough;
|
||||
case IWL_RX_PHY_INFO_TYPE_HE_MU:
|
||||
he_mu->flags2 |=
|
||||
|
|
@ -1444,8 +1450,7 @@ static void iwl_mvm_decode_he_phy_data(struct iwl_mvm *mvm,
|
|||
fallthrough;
|
||||
case IWL_RX_PHY_INFO_TYPE_HE_TB:
|
||||
case IWL_RX_PHY_INFO_TYPE_HE_TB_EXT:
|
||||
iwl_mvm_decode_he_phy_ru_alloc(phy_data, rate_n_flags,
|
||||
he, he_mu, rx_status);
|
||||
iwl_mvm_decode_he_phy_ru_alloc(phy_data, he, he_mu, rx_status);
|
||||
break;
|
||||
case IWL_RX_PHY_INFO_TYPE_HE_SU:
|
||||
he->data1 |= cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA1_BEAM_CHANGE_KNOWN);
|
||||
|
|
@ -1461,13 +1466,14 @@ static void iwl_mvm_decode_he_phy_data(struct iwl_mvm *mvm,
|
|||
|
||||
static void iwl_mvm_rx_he(struct iwl_mvm *mvm, struct sk_buff *skb,
|
||||
struct iwl_mvm_rx_phy_data *phy_data,
|
||||
u32 rate_n_flags, u16 phy_info, int queue)
|
||||
int queue)
|
||||
{
|
||||
struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb);
|
||||
struct ieee80211_radiotap_he *he = NULL;
|
||||
struct ieee80211_radiotap_he_mu *he_mu = NULL;
|
||||
u32 rate_n_flags = phy_data->rate_n_flags;
|
||||
u32 he_type = rate_n_flags & RATE_MCS_HE_TYPE_MSK;
|
||||
u8 stbc, ltf;
|
||||
u8 ltf;
|
||||
static const struct ieee80211_radiotap_he known = {
|
||||
.data1 = cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA1_DATA_MCS_KNOWN |
|
||||
IEEE80211_RADIOTAP_HE_DATA1_DATA_DCM_KNOWN |
|
||||
|
|
@ -1484,6 +1490,7 @@ static void iwl_mvm_rx_he(struct iwl_mvm *mvm, struct sk_buff *skb,
|
|||
.flags2 = cpu_to_le16(IEEE80211_RADIOTAP_HE_MU_FLAGS2_PUNC_FROM_SIG_A_BW_KNOWN |
|
||||
IEEE80211_RADIOTAP_HE_MU_FLAGS2_BW_FROM_SIG_A_BW_KNOWN),
|
||||
};
|
||||
u16 phy_info = phy_data->phy_info;
|
||||
|
||||
he = skb_put_data(skb, &known, sizeof(known));
|
||||
rx_status->flag |= RX_FLAG_RADIOTAP_HE;
|
||||
|
|
@ -1504,7 +1511,7 @@ static void iwl_mvm_rx_he(struct iwl_mvm *mvm, struct sk_buff *skb,
|
|||
|
||||
if (phy_info & IWL_RX_MPDU_PHY_TSF_OVERLOAD)
|
||||
iwl_mvm_decode_he_phy_data(mvm, phy_data, he, he_mu, rx_status,
|
||||
rate_n_flags, queue);
|
||||
queue);
|
||||
|
||||
/* update aggregation data for monitor sake on default queue */
|
||||
if (!queue && (phy_info & IWL_RX_MPDU_PHY_TSF_OVERLOAD) &&
|
||||
|
|
@ -1531,19 +1538,6 @@ static void iwl_mvm_rx_he(struct iwl_mvm *mvm, struct sk_buff *skb,
|
|||
he->data1 |=
|
||||
cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA1_BW_RU_ALLOC_KNOWN);
|
||||
|
||||
stbc = (rate_n_flags & RATE_MCS_STBC_MSK) >> RATE_MCS_STBC_POS;
|
||||
rx_status->nss =
|
||||
((rate_n_flags & RATE_MCS_NSS_MSK) >>
|
||||
RATE_MCS_NSS_POS) + 1;
|
||||
rx_status->rate_idx = rate_n_flags & RATE_MCS_CODE_MSK;
|
||||
rx_status->encoding = RX_ENC_HE;
|
||||
rx_status->enc_flags |= stbc << RX_ENC_FLAG_STBC_SHIFT;
|
||||
if (rate_n_flags & RATE_MCS_BF_MSK)
|
||||
rx_status->enc_flags |= RX_ENC_FLAG_BF;
|
||||
|
||||
rx_status->he_dcm =
|
||||
!!(rate_n_flags & RATE_HE_DUAL_CARRIER_MODE_MSK);
|
||||
|
||||
#define CHECK_TYPE(F) \
|
||||
BUILD_BUG_ON(IEEE80211_RADIOTAP_HE_DATA1_FORMAT_ ## F != \
|
||||
(RATE_MCS_HE_TYPE_ ## F >> RATE_MCS_HE_TYPE_POS))
|
||||
|
|
@ -1661,6 +1655,107 @@ static void iwl_mvm_rx_get_sta_block_tx(void *data, struct ieee80211_sta *sta)
|
|||
rx_sta_csa->all_sta_unblocked = false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Note: requires also rx_status->band to be prefilled, as well
|
||||
* as phy_data (apart from phy_data->info_type)
|
||||
*/
|
||||
static void iwl_mvm_rx_fill_status(struct iwl_mvm *mvm,
|
||||
struct sk_buff *skb,
|
||||
struct iwl_mvm_rx_phy_data *phy_data,
|
||||
int queue)
|
||||
{
|
||||
struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb);
|
||||
u32 rate_n_flags = phy_data->rate_n_flags;
|
||||
u8 stbc = u32_get_bits(rate_n_flags, RATE_MCS_STBC_MSK);
|
||||
u32 format = rate_n_flags & RATE_MCS_MOD_TYPE_MSK;
|
||||
bool is_sgi;
|
||||
|
||||
phy_data->info_type = IWL_RX_PHY_INFO_TYPE_NONE;
|
||||
|
||||
if (phy_data->phy_info & IWL_RX_MPDU_PHY_TSF_OVERLOAD)
|
||||
phy_data->info_type =
|
||||
le32_get_bits(phy_data->d1,
|
||||
IWL_RX_PHY_DATA1_INFO_TYPE_MASK);
|
||||
|
||||
/* This may be overridden by iwl_mvm_rx_he() to HE_RU */
|
||||
switch (rate_n_flags & RATE_MCS_CHAN_WIDTH_MSK) {
|
||||
case RATE_MCS_CHAN_WIDTH_20:
|
||||
break;
|
||||
case RATE_MCS_CHAN_WIDTH_40:
|
||||
rx_status->bw = RATE_INFO_BW_40;
|
||||
break;
|
||||
case RATE_MCS_CHAN_WIDTH_80:
|
||||
rx_status->bw = RATE_INFO_BW_80;
|
||||
break;
|
||||
case RATE_MCS_CHAN_WIDTH_160:
|
||||
rx_status->bw = RATE_INFO_BW_160;
|
||||
break;
|
||||
}
|
||||
|
||||
/* must be before L-SIG data */
|
||||
if (format == RATE_MCS_HE_MSK)
|
||||
iwl_mvm_rx_he(mvm, skb, phy_data, queue);
|
||||
|
||||
iwl_mvm_decode_lsig(skb, phy_data);
|
||||
|
||||
rx_status->device_timestamp = phy_data->gp2_on_air_rise;
|
||||
rx_status->freq = ieee80211_channel_to_frequency(phy_data->channel,
|
||||
rx_status->band);
|
||||
iwl_mvm_get_signal_strength(mvm, rx_status, rate_n_flags,
|
||||
phy_data->energy_a, phy_data->energy_b);
|
||||
|
||||
if (unlikely(mvm->monitor_on))
|
||||
iwl_mvm_add_rtap_sniffer_config(mvm, skb);
|
||||
|
||||
is_sgi = format == RATE_MCS_HE_MSK ?
|
||||
iwl_he_is_sgi(rate_n_flags) :
|
||||
rate_n_flags & RATE_MCS_SGI_MSK;
|
||||
|
||||
if (!(format == RATE_MCS_CCK_MSK) && is_sgi)
|
||||
rx_status->enc_flags |= RX_ENC_FLAG_SHORT_GI;
|
||||
|
||||
if (rate_n_flags & RATE_MCS_LDPC_MSK)
|
||||
rx_status->enc_flags |= RX_ENC_FLAG_LDPC;
|
||||
|
||||
switch (format) {
|
||||
case RATE_MCS_VHT_MSK:
|
||||
rx_status->encoding = RX_ENC_VHT;
|
||||
break;
|
||||
case RATE_MCS_HE_MSK:
|
||||
rx_status->encoding = RX_ENC_HE;
|
||||
rx_status->he_dcm =
|
||||
!!(rate_n_flags & RATE_HE_DUAL_CARRIER_MODE_MSK);
|
||||
break;
|
||||
}
|
||||
|
||||
switch (format) {
|
||||
case RATE_MCS_HT_MSK:
|
||||
rx_status->encoding = RX_ENC_HT;
|
||||
rx_status->rate_idx = RATE_HT_MCS_INDEX(rate_n_flags);
|
||||
rx_status->enc_flags |= stbc << RX_ENC_FLAG_STBC_SHIFT;
|
||||
break;
|
||||
case RATE_MCS_VHT_MSK:
|
||||
case RATE_MCS_HE_MSK:
|
||||
rx_status->nss =
|
||||
u32_get_bits(rate_n_flags, RATE_MCS_NSS_MSK) + 1;
|
||||
rx_status->rate_idx = rate_n_flags & RATE_MCS_CODE_MSK;
|
||||
rx_status->enc_flags |= stbc << RX_ENC_FLAG_STBC_SHIFT;
|
||||
break;
|
||||
default: {
|
||||
int rate = iwl_mvm_legacy_hw_idx_to_mac80211_idx(rate_n_flags,
|
||||
rx_status->band);
|
||||
|
||||
rx_status->rate_idx = rate;
|
||||
|
||||
if (WARN_ONCE(rate < 0 || rate > 0xFF,
|
||||
"Invalid rate flags 0x%x, band %d,\n",
|
||||
rate_n_flags, rx_status->band))
|
||||
rx_status->rate_idx = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
|
||||
struct iwl_rx_cmd_buffer *rxb, int queue)
|
||||
{
|
||||
|
|
@ -1670,17 +1765,12 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
|
|||
struct ieee80211_hdr *hdr;
|
||||
u32 len;
|
||||
u32 pkt_len = iwl_rx_packet_payload_len(pkt);
|
||||
u32 rate_n_flags, gp2_on_air_rise;
|
||||
u16 phy_info;
|
||||
struct ieee80211_sta *sta = NULL;
|
||||
struct sk_buff *skb;
|
||||
u8 crypt_len = 0, channel, energy_a, energy_b;
|
||||
u8 crypt_len = 0;
|
||||
size_t desc_size;
|
||||
struct iwl_mvm_rx_phy_data phy_data = {
|
||||
.info_type = IWL_RX_PHY_INFO_TYPE_NONE,
|
||||
};
|
||||
struct iwl_mvm_rx_phy_data phy_data = {};
|
||||
u32 format;
|
||||
bool is_sgi;
|
||||
|
||||
if (unlikely(test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)))
|
||||
return;
|
||||
|
|
@ -1696,35 +1786,37 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
|
|||
}
|
||||
|
||||
if (mvm->trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_AX210) {
|
||||
rate_n_flags = le32_to_cpu(desc->v3.rate_n_flags);
|
||||
channel = desc->v3.channel;
|
||||
gp2_on_air_rise = le32_to_cpu(desc->v3.gp2_on_air_rise);
|
||||
energy_a = desc->v3.energy_a;
|
||||
energy_b = desc->v3.energy_b;
|
||||
phy_data.rate_n_flags = le32_to_cpu(desc->v3.rate_n_flags);
|
||||
phy_data.channel = desc->v3.channel;
|
||||
phy_data.gp2_on_air_rise = le32_to_cpu(desc->v3.gp2_on_air_rise);
|
||||
phy_data.energy_a = desc->v3.energy_a;
|
||||
phy_data.energy_b = desc->v3.energy_b;
|
||||
|
||||
phy_data.d0 = desc->v3.phy_data0;
|
||||
phy_data.d1 = desc->v3.phy_data1;
|
||||
phy_data.d2 = desc->v3.phy_data2;
|
||||
phy_data.d3 = desc->v3.phy_data3;
|
||||
} else {
|
||||
rate_n_flags = le32_to_cpu(desc->v1.rate_n_flags);
|
||||
channel = desc->v1.channel;
|
||||
gp2_on_air_rise = le32_to_cpu(desc->v1.gp2_on_air_rise);
|
||||
energy_a = desc->v1.energy_a;
|
||||
energy_b = desc->v1.energy_b;
|
||||
phy_data.rate_n_flags = le32_to_cpu(desc->v1.rate_n_flags);
|
||||
phy_data.channel = desc->v1.channel;
|
||||
phy_data.gp2_on_air_rise = le32_to_cpu(desc->v1.gp2_on_air_rise);
|
||||
phy_data.energy_a = desc->v1.energy_a;
|
||||
phy_data.energy_b = desc->v1.energy_b;
|
||||
|
||||
phy_data.d0 = desc->v1.phy_data0;
|
||||
phy_data.d1 = desc->v1.phy_data1;
|
||||
phy_data.d2 = desc->v1.phy_data2;
|
||||
phy_data.d3 = desc->v1.phy_data3;
|
||||
}
|
||||
|
||||
if (iwl_fw_lookup_notif_ver(mvm->fw, LEGACY_GROUP,
|
||||
REPLY_RX_MPDU_CMD, 0) < 4) {
|
||||
rate_n_flags = iwl_new_rate_from_v1(rate_n_flags);
|
||||
phy_data.rate_n_flags = iwl_new_rate_from_v1(phy_data.rate_n_flags);
|
||||
IWL_DEBUG_DROP(mvm, "Got old format rate, converting. New rate: 0x%x\n",
|
||||
rate_n_flags);
|
||||
phy_data.rate_n_flags);
|
||||
}
|
||||
format = rate_n_flags & RATE_MCS_MOD_TYPE_MSK;
|
||||
|
||||
format = phy_data.rate_n_flags & RATE_MCS_MOD_TYPE_MSK;
|
||||
|
||||
len = le16_to_cpu(desc->mpdu_len);
|
||||
|
||||
|
|
@ -1733,14 +1825,9 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
|
|||
return;
|
||||
}
|
||||
|
||||
phy_info = le16_to_cpu(desc->phy_info);
|
||||
phy_data.phy_info = le16_to_cpu(desc->phy_info);
|
||||
phy_data.d4 = desc->phy_data4;
|
||||
|
||||
if (phy_info & IWL_RX_MPDU_PHY_TSF_OVERLOAD)
|
||||
phy_data.info_type =
|
||||
le32_get_bits(phy_data.d1,
|
||||
IWL_RX_PHY_DATA1_INFO_TYPE_MASK);
|
||||
|
||||
hdr = (void *)(pkt->data + desc_size);
|
||||
/* Dont use dev_alloc_skb(), we'll have enough headroom once
|
||||
* ieee80211_hdr pulled.
|
||||
|
|
@ -1763,27 +1850,6 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
|
|||
|
||||
rx_status = IEEE80211_SKB_RXCB(skb);
|
||||
|
||||
/* This may be overridden by iwl_mvm_rx_he() to HE_RU */
|
||||
switch (rate_n_flags & RATE_MCS_CHAN_WIDTH_MSK) {
|
||||
case RATE_MCS_CHAN_WIDTH_20:
|
||||
break;
|
||||
case RATE_MCS_CHAN_WIDTH_40:
|
||||
rx_status->bw = RATE_INFO_BW_40;
|
||||
break;
|
||||
case RATE_MCS_CHAN_WIDTH_80:
|
||||
rx_status->bw = RATE_INFO_BW_80;
|
||||
break;
|
||||
case RATE_MCS_CHAN_WIDTH_160:
|
||||
rx_status->bw = RATE_INFO_BW_160;
|
||||
break;
|
||||
}
|
||||
|
||||
if (format == RATE_MCS_HE_MSK)
|
||||
iwl_mvm_rx_he(mvm, skb, &phy_data, rate_n_flags,
|
||||
phy_info, queue);
|
||||
|
||||
iwl_mvm_decode_lsig(skb, &phy_data);
|
||||
|
||||
/*
|
||||
* Keep packets with CRC errors (and with overrun) for monitor mode
|
||||
* (otherwise the firmware discards them) but mark them as bad.
|
||||
|
|
@ -1794,12 +1860,13 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
|
|||
le32_to_cpu(desc->status));
|
||||
rx_status->flag |= RX_FLAG_FAILED_FCS_CRC;
|
||||
}
|
||||
|
||||
/* set the preamble flag if appropriate */
|
||||
if (format == RATE_MCS_CCK_MSK &&
|
||||
phy_info & IWL_RX_MPDU_PHY_SHORT_PREAMBLE)
|
||||
phy_data.phy_info & IWL_RX_MPDU_PHY_SHORT_PREAMBLE)
|
||||
rx_status->enc_flags |= RX_ENC_FLAG_SHORTPRE;
|
||||
|
||||
if (likely(!(phy_info & IWL_RX_MPDU_PHY_TSF_OVERLOAD))) {
|
||||
if (likely(!(phy_data.phy_info & IWL_RX_MPDU_PHY_TSF_OVERLOAD))) {
|
||||
u64 tsf_on_air_rise;
|
||||
|
||||
if (mvm->trans->trans_cfg->device_family >=
|
||||
|
|
@ -1813,24 +1880,20 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
|
|||
rx_status->flag |= RX_FLAG_MACTIME_PLCP_START;
|
||||
}
|
||||
|
||||
rx_status->device_timestamp = gp2_on_air_rise;
|
||||
if (iwl_mvm_is_band_in_rx_supported(mvm)) {
|
||||
u8 band = BAND_IN_RX_STATUS(desc->mac_phy_idx);
|
||||
|
||||
rx_status->band = iwl_mvm_nl80211_band_from_rx_msdu(band);
|
||||
} else {
|
||||
rx_status->band = channel > 14 ? NL80211_BAND_5GHZ :
|
||||
rx_status->band = phy_data.channel > 14 ? NL80211_BAND_5GHZ :
|
||||
NL80211_BAND_2GHZ;
|
||||
}
|
||||
rx_status->freq = ieee80211_channel_to_frequency(channel,
|
||||
rx_status->band);
|
||||
iwl_mvm_get_signal_strength(mvm, rx_status, rate_n_flags, energy_a,
|
||||
energy_b);
|
||||
|
||||
/* update aggregation data for monitor sake on default queue */
|
||||
if (!queue && (phy_info & IWL_RX_MPDU_PHY_AMPDU)) {
|
||||
bool toggle_bit = phy_info & IWL_RX_MPDU_PHY_AMPDU_TOGGLE;
|
||||
if (!queue && (phy_data.phy_info & IWL_RX_MPDU_PHY_AMPDU)) {
|
||||
bool toggle_bit;
|
||||
|
||||
toggle_bit = phy_data.phy_info & IWL_RX_MPDU_PHY_AMPDU_TOGGLE;
|
||||
rx_status->flag |= RX_FLAG_AMPDU_DETAILS;
|
||||
/*
|
||||
* Toggle is switched whenever new aggregation starts. Make
|
||||
|
|
@ -1846,9 +1909,6 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
|
|||
rx_status->ampdu_reference = mvm->ampdu_ref;
|
||||
}
|
||||
|
||||
if (unlikely(mvm->monitor_on))
|
||||
iwl_mvm_add_rtap_sniffer_config(mvm, skb);
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
if (desc->status & cpu_to_le32(IWL_RX_MPDU_STATUS_SRC_STA_FOUND)) {
|
||||
|
|
@ -1867,13 +1927,15 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
|
|||
sta = ieee80211_find_sta_by_ifaddr(mvm->hw, hdr->addr2, NULL);
|
||||
}
|
||||
|
||||
if (iwl_mvm_rx_crypto(mvm, sta, hdr, rx_status, phy_info, desc,
|
||||
if (iwl_mvm_rx_crypto(mvm, sta, hdr, rx_status, phy_data.phy_info, desc,
|
||||
le32_to_cpu(pkt->len_n_flags), queue,
|
||||
&crypt_len)) {
|
||||
kfree_skb(skb);
|
||||
goto out;
|
||||
}
|
||||
|
||||
iwl_mvm_rx_fill_status(mvm, skb, &phy_data, queue);
|
||||
|
||||
if (sta) {
|
||||
struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
|
||||
struct ieee80211_vif *tx_blocked_vif =
|
||||
|
|
@ -1971,43 +2033,6 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
|
|||
}
|
||||
}
|
||||
|
||||
is_sgi = format == RATE_MCS_HE_MSK ?
|
||||
iwl_he_is_sgi(rate_n_flags) :
|
||||
rate_n_flags & RATE_MCS_SGI_MSK;
|
||||
|
||||
if (!(format == RATE_MCS_CCK_MSK) && is_sgi)
|
||||
rx_status->enc_flags |= RX_ENC_FLAG_SHORT_GI;
|
||||
if (rate_n_flags & RATE_MCS_LDPC_MSK)
|
||||
rx_status->enc_flags |= RX_ENC_FLAG_LDPC;
|
||||
if (format == RATE_MCS_HT_MSK) {
|
||||
u8 stbc = (rate_n_flags & RATE_MCS_STBC_MSK) >>
|
||||
RATE_MCS_STBC_POS;
|
||||
rx_status->encoding = RX_ENC_HT;
|
||||
rx_status->rate_idx = RATE_HT_MCS_INDEX(rate_n_flags);
|
||||
rx_status->enc_flags |= stbc << RX_ENC_FLAG_STBC_SHIFT;
|
||||
} else if (format == RATE_MCS_VHT_MSK) {
|
||||
u8 stbc = (rate_n_flags & RATE_MCS_STBC_MSK) >>
|
||||
RATE_MCS_STBC_POS;
|
||||
rx_status->nss = ((rate_n_flags & RATE_MCS_NSS_MSK) >>
|
||||
RATE_MCS_NSS_POS) + 1;
|
||||
rx_status->rate_idx = rate_n_flags & RATE_MCS_CODE_MSK;
|
||||
rx_status->encoding = RX_ENC_VHT;
|
||||
rx_status->enc_flags |= stbc << RX_ENC_FLAG_STBC_SHIFT;
|
||||
if (rate_n_flags & RATE_MCS_BF_MSK)
|
||||
rx_status->enc_flags |= RX_ENC_FLAG_BF;
|
||||
} else if (!(format == RATE_MCS_HE_MSK)) {
|
||||
int rate = iwl_mvm_legacy_hw_idx_to_mac80211_idx(rate_n_flags,
|
||||
rx_status->band);
|
||||
|
||||
if (WARN(rate < 0 || rate > 0xFF,
|
||||
"Invalid rate flags 0x%x, band %d,\n",
|
||||
rate_n_flags, rx_status->band)) {
|
||||
kfree_skb(skb);
|
||||
goto out;
|
||||
}
|
||||
rx_status->rate_idx = rate;
|
||||
}
|
||||
|
||||
/* management stuff on default queue */
|
||||
if (!queue) {
|
||||
if (unlikely((ieee80211_is_beacon(hdr->frame_control) ||
|
||||
|
|
@ -2039,32 +2064,32 @@ void iwl_mvm_rx_monitor_no_data(struct iwl_mvm *mvm, struct napi_struct *napi,
|
|||
struct ieee80211_rx_status *rx_status;
|
||||
struct iwl_rx_packet *pkt = rxb_addr(rxb);
|
||||
struct iwl_rx_no_data *desc = (void *)pkt->data;
|
||||
u32 rate_n_flags = le32_to_cpu(desc->rate);
|
||||
u32 gp2_on_air_rise = le32_to_cpu(desc->on_air_rise_time);
|
||||
u32 rssi = le32_to_cpu(desc->rssi);
|
||||
u32 info_type = le32_to_cpu(desc->info) & RX_NO_DATA_INFO_TYPE_MSK;
|
||||
u16 phy_info = IWL_RX_MPDU_PHY_TSF_OVERLOAD;
|
||||
struct ieee80211_sta *sta = NULL;
|
||||
struct sk_buff *skb;
|
||||
u8 channel, energy_a, energy_b;
|
||||
u32 format;
|
||||
struct iwl_mvm_rx_phy_data phy_data = {
|
||||
.info_type = le32_get_bits(desc->phy_info[1],
|
||||
IWL_RX_PHY_DATA1_INFO_TYPE_MASK),
|
||||
.d0 = desc->phy_info[0],
|
||||
.d1 = desc->phy_info[1],
|
||||
.phy_info = IWL_RX_MPDU_PHY_TSF_OVERLOAD,
|
||||
.gp2_on_air_rise = le32_to_cpu(desc->on_air_rise_time),
|
||||
.rate_n_flags = le32_to_cpu(desc->rate),
|
||||
.energy_a = u32_get_bits(rssi, RX_NO_DATA_CHAIN_A_MSK),
|
||||
.energy_b = u32_get_bits(rssi, RX_NO_DATA_CHAIN_B_MSK),
|
||||
.channel = u32_get_bits(rssi, RX_NO_DATA_CHANNEL_MSK),
|
||||
};
|
||||
bool is_sgi;
|
||||
u32 format;
|
||||
|
||||
if (iwl_fw_lookup_notif_ver(mvm->fw, DATA_PATH_GROUP,
|
||||
RX_NO_DATA_NOTIF, 0) < 2) {
|
||||
IWL_DEBUG_DROP(mvm, "Got an old rate format. Old rate: 0x%x\n",
|
||||
rate_n_flags);
|
||||
rate_n_flags = iwl_new_rate_from_v1(rate_n_flags);
|
||||
phy_data.rate_n_flags);
|
||||
phy_data.rate_n_flags = iwl_new_rate_from_v1(phy_data.rate_n_flags);
|
||||
IWL_DEBUG_DROP(mvm, " Rate after conversion to the new format: 0x%x\n",
|
||||
rate_n_flags);
|
||||
phy_data.rate_n_flags);
|
||||
}
|
||||
format = rate_n_flags & RATE_MCS_MOD_TYPE_MSK;
|
||||
|
||||
format = phy_data.rate_n_flags & RATE_MCS_MOD_TYPE_MSK;
|
||||
|
||||
if (unlikely(iwl_rx_packet_payload_len(pkt) < sizeof(*desc)))
|
||||
return;
|
||||
|
|
@ -2072,10 +2097,6 @@ void iwl_mvm_rx_monitor_no_data(struct iwl_mvm *mvm, struct napi_struct *napi,
|
|||
if (unlikely(test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)))
|
||||
return;
|
||||
|
||||
energy_a = (rssi & RX_NO_DATA_CHAIN_A_MSK) >> RX_NO_DATA_CHAIN_A_POS;
|
||||
energy_b = (rssi & RX_NO_DATA_CHAIN_B_MSK) >> RX_NO_DATA_CHAIN_B_POS;
|
||||
channel = (rssi & RX_NO_DATA_CHANNEL_MSK) >> RX_NO_DATA_CHANNEL_POS;
|
||||
|
||||
/* Dont use dev_alloc_skb(), we'll have enough headroom once
|
||||
* ieee80211_hdr pulled.
|
||||
*/
|
||||
|
|
@ -2106,86 +2127,31 @@ void iwl_mvm_rx_monitor_no_data(struct iwl_mvm *mvm, struct napi_struct *napi,
|
|||
break;
|
||||
}
|
||||
|
||||
/* This may be overridden by iwl_mvm_rx_he() to HE_RU */
|
||||
switch (rate_n_flags & RATE_MCS_CHAN_WIDTH_MSK) {
|
||||
case RATE_MCS_CHAN_WIDTH_20:
|
||||
break;
|
||||
case RATE_MCS_CHAN_WIDTH_40:
|
||||
rx_status->bw = RATE_INFO_BW_40;
|
||||
break;
|
||||
case RATE_MCS_CHAN_WIDTH_80:
|
||||
rx_status->bw = RATE_INFO_BW_80;
|
||||
break;
|
||||
case RATE_MCS_CHAN_WIDTH_160:
|
||||
rx_status->bw = RATE_INFO_BW_160;
|
||||
break;
|
||||
}
|
||||
|
||||
if (format == RATE_MCS_HE_MSK)
|
||||
iwl_mvm_rx_he(mvm, skb, &phy_data, rate_n_flags,
|
||||
phy_info, queue);
|
||||
|
||||
iwl_mvm_decode_lsig(skb, &phy_data);
|
||||
|
||||
rx_status->device_timestamp = gp2_on_air_rise;
|
||||
rx_status->band = channel > 14 ? NL80211_BAND_5GHZ :
|
||||
rx_status->band = phy_data.channel > 14 ? NL80211_BAND_5GHZ :
|
||||
NL80211_BAND_2GHZ;
|
||||
rx_status->freq = ieee80211_channel_to_frequency(channel,
|
||||
rx_status->band);
|
||||
iwl_mvm_get_signal_strength(mvm, rx_status, rate_n_flags, energy_a,
|
||||
energy_b);
|
||||
|
||||
rcu_read_lock();
|
||||
iwl_mvm_rx_fill_status(mvm, skb, &phy_data, queue);
|
||||
|
||||
is_sgi = format == RATE_MCS_HE_MSK ?
|
||||
iwl_he_is_sgi(rate_n_flags) :
|
||||
rate_n_flags & RATE_MCS_SGI_MSK;
|
||||
|
||||
if (!(format == RATE_MCS_CCK_MSK) && is_sgi)
|
||||
rx_status->enc_flags |= RX_ENC_FLAG_SHORT_GI;
|
||||
if (rate_n_flags & RATE_MCS_LDPC_MSK)
|
||||
rx_status->enc_flags |= RX_ENC_FLAG_LDPC;
|
||||
if (format == RATE_MCS_HT_MSK) {
|
||||
u8 stbc = (rate_n_flags & RATE_MCS_STBC_MSK) >>
|
||||
RATE_MCS_STBC_POS;
|
||||
rx_status->encoding = RX_ENC_HT;
|
||||
rx_status->rate_idx = RATE_HT_MCS_INDEX(rate_n_flags);
|
||||
rx_status->enc_flags |= stbc << RX_ENC_FLAG_STBC_SHIFT;
|
||||
} else if (format == RATE_MCS_VHT_MSK) {
|
||||
u8 stbc = (rate_n_flags & RATE_MCS_STBC_MSK) >>
|
||||
RATE_MCS_STBC_POS;
|
||||
rx_status->rate_idx = rate_n_flags & RATE_MCS_CODE_MSK;
|
||||
rx_status->encoding = RX_ENC_VHT;
|
||||
rx_status->enc_flags |= stbc << RX_ENC_FLAG_STBC_SHIFT;
|
||||
if (rate_n_flags & RATE_MCS_BF_MSK)
|
||||
rx_status->enc_flags |= RX_ENC_FLAG_BF;
|
||||
/*
|
||||
* take the nss from the rx_vec since the rate_n_flags has
|
||||
* only 2 bits for the nss which gives a max of 4 ss but
|
||||
* there may be up to 8 spatial streams
|
||||
*/
|
||||
/*
|
||||
* Override the nss from the rx_vec since the rate_n_flags has
|
||||
* only 2 bits for the nss which gives a max of 4 ss but there
|
||||
* may be up to 8 spatial streams.
|
||||
*/
|
||||
switch (format) {
|
||||
case RATE_MCS_VHT_MSK:
|
||||
rx_status->nss =
|
||||
le32_get_bits(desc->rx_vec[0],
|
||||
RX_NO_DATA_RX_VEC0_VHT_NSTS_MSK) + 1;
|
||||
} else if (format == RATE_MCS_HE_MSK) {
|
||||
break;
|
||||
case RATE_MCS_HE_MSK:
|
||||
rx_status->nss =
|
||||
le32_get_bits(desc->rx_vec[0],
|
||||
RX_NO_DATA_RX_VEC0_HE_NSTS_MSK) + 1;
|
||||
} else {
|
||||
int rate = iwl_mvm_legacy_hw_idx_to_mac80211_idx(rate_n_flags,
|
||||
rx_status->band);
|
||||
|
||||
if (WARN(rate < 0 || rate > 0xFF,
|
||||
"Invalid rate flags 0x%x, band %d,\n",
|
||||
rate_n_flags, rx_status->band)) {
|
||||
kfree_skb(skb);
|
||||
goto out;
|
||||
}
|
||||
rx_status->rate_idx = rate;
|
||||
break;
|
||||
}
|
||||
|
||||
rcu_read_lock();
|
||||
ieee80211_rx_napi(mvm->hw, sta, skb, napi);
|
||||
out:
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1155,10 +1155,20 @@ static const struct iwl_dev_info iwl_dev_info_table[] = {
|
|||
IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, IWL_CFG_ANY,
|
||||
iwl_cfg_bz_a0_fm_a0, iwl_bz_name),
|
||||
_IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY,
|
||||
IWL_CFG_MAC_TYPE_GL, IWL_CFG_ANY,
|
||||
IWL_CFG_MAC_TYPE_BZ, IWL_CFG_ANY,
|
||||
IWL_CFG_RF_TYPE_FM, IWL_CFG_ANY,
|
||||
IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_CDB, IWL_CFG_NO_JACKET,
|
||||
iwl_cfg_bz_a0_fm4_a0, iwl_bz_name),
|
||||
_IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY,
|
||||
IWL_CFG_MAC_TYPE_GL, SILICON_A_STEP,
|
||||
IWL_CFG_RF_TYPE_FM, IWL_CFG_ANY,
|
||||
IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, IWL_CFG_NO_JACKET,
|
||||
iwl_cfg_gl_a0_fm_a0, iwl_bz_name),
|
||||
_IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY,
|
||||
IWL_CFG_MAC_TYPE_GL, SILICON_B_STEP,
|
||||
IWL_CFG_RF_TYPE_FM, IWL_CFG_ANY,
|
||||
IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, IWL_CFG_NO_JACKET,
|
||||
iwl_cfg_gl_b0_fm_b0, iwl_bz_name),
|
||||
|
||||
/* BZ Z step */
|
||||
_IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY,
|
||||
|
|
@ -1169,10 +1179,15 @@ static const struct iwl_dev_info iwl_dev_info_table[] = {
|
|||
|
||||
/* BNJ */
|
||||
_IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY,
|
||||
IWL_CFG_MAC_TYPE_GL, IWL_CFG_ANY,
|
||||
IWL_CFG_MAC_TYPE_GL, SILICON_A_STEP,
|
||||
IWL_CFG_RF_TYPE_FM, IWL_CFG_ANY,
|
||||
IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, IWL_CFG_IS_JACKET,
|
||||
iwl_cfg_bnj_a0_fm_a0, iwl_bz_name),
|
||||
_IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY,
|
||||
IWL_CFG_MAC_TYPE_GL, SILICON_B_STEP,
|
||||
IWL_CFG_RF_TYPE_FM, IWL_CFG_ANY,
|
||||
IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, IWL_CFG_IS_JACKET,
|
||||
iwl_cfg_bnj_b0_fm_b0, iwl_bz_name),
|
||||
_IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY,
|
||||
IWL_CFG_MAC_TYPE_GL, IWL_CFG_ANY,
|
||||
IWL_CFG_RF_TYPE_FM, IWL_CFG_ANY,
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user