Third set of iwlwifi patches for 4.20
* Fix for a race condition that caused the FW to crash; * HE radiotap cleanup and improvements; * Reorder channel optimization for scans; * Bumped the FW API version supported after the last API change for this release; * Debugging improvements; * A few bug fixes; * Some cleanups in preparation for a new implementation; * Other small improvements, cleanups and fixes. -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEF3LNfgb2BPWm68smoUecoho8xfoFAlu4Y9QACgkQoUecoho8 xfpbbg//ROojnO1p/BmZVNfSsZQJFTTr/DwFmuAntHD6OOXZON4k3FB2fudL3FLq HV0SNOJ2e6M+yyTgsGlOp5eKyqW9avm9pR3kFTtcDm7l8y+drivqeFiWovjzGqOu C6/28QAsuqqzipyYJ0TDQhQUO6ErGZa1CmZnhRRb0hECvnMN52QPa3t7nIBiBhfp +0sNwS16zKMbMTuY6FTnKRN28O80/aDae0Had+n9Ok0EeFosuBYmT+Ic7fEXrFnp J5tMGRvFZPGZ6uGqj3smi6Hv8/0nKlMg7kpXCWVSVSadm1KyTrIX6hHI7xFIQpOx FlxFKS6X0w1WVIW8vXVH0uCwBcNKYwKEc0U5997k0T5gyRPh+L8PLwrMpAl4LBsJ cifhoTMraoeCLeOztSjIMNOocnQ+azAuu3wtyn2lfyjJzc/C0mYfu6S2uatGz/H+ c28Mx8jRUsy0d58TckE+vlfx8bCbySrf6x8UL9MDXTQvPTMrpm4nXDGRNT1FxQ61 iLKFYDbBxvmaEFdynXhaigPvOXxfpNG+0gsx8ye9XPu0jb+bkJ2NMCfKPDyDkWIu dvvlR2Rngoa1RScw9aHpv9FzwJGOh639gFZ130uyE+27xzb7x5+ymKInfaVOvlW0 S2muIVP4dofIwYxAD5eaUlgpaEqW7OT+hDLT1MWsSja+ivyrpyU= =Dg0M -----END PGP SIGNATURE----- Merge tag 'iwlwifi-next-for-kalle-2018-10-06' of git://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi/iwlwifi-next Third set of iwlwifi patches for 4.20 * Fix for a race condition that caused the FW to crash; * HE radiotap cleanup and improvements; * Reorder channel optimization for scans; * Bumped the FW API version supported after the last API change for this release; * Debugging improvements; * A few bug fixes; * Some cleanups in preparation for a new implementation; * Other small improvements, cleanups and fixes.
This commit is contained in:
commit
2a45501226
@ -56,7 +56,7 @@
|
||||
#include "iwl-config.h"
|
||||
|
||||
/* Highest firmware API version supported */
|
||||
#define IWL_22000_UCODE_API_MAX 38
|
||||
#define IWL_22000_UCODE_API_MAX 41
|
||||
|
||||
/* Lowest firmware API version supported */
|
||||
#define IWL_22000_UCODE_API_MIN 39
|
||||
|
@ -57,7 +57,7 @@
|
||||
#include "fw/file.h"
|
||||
|
||||
/* Highest firmware API version supported */
|
||||
#define IWL9000_UCODE_API_MAX 38
|
||||
#define IWL9000_UCODE_API_MAX 41
|
||||
|
||||
/* Lowest firmware API version supported */
|
||||
#define IWL9000_UCODE_API_MIN 30
|
||||
|
@ -165,7 +165,7 @@ struct iwl_nvm_access_resp {
|
||||
*/
|
||||
struct iwl_nvm_get_info {
|
||||
__le32 reserved;
|
||||
} __packed; /* GRP_REGULATORY_NVM_GET_INFO_CMD_S_VER_1 */
|
||||
} __packed; /* REGULATORY_NVM_GET_INFO_CMD_API_S_VER_1 */
|
||||
|
||||
/**
|
||||
* enum iwl_nvm_info_general_flags - flags in NVM_GET_INFO resp
|
||||
@ -180,14 +180,14 @@ enum iwl_nvm_info_general_flags {
|
||||
* @flags: bit 0: 1 - empty, 0 - non-empty
|
||||
* @nvm_version: nvm version
|
||||
* @board_type: board type
|
||||
* @reserved: reserved
|
||||
* @n_hw_addrs: number of reserved MAC addresses
|
||||
*/
|
||||
struct iwl_nvm_get_info_general {
|
||||
__le32 flags;
|
||||
__le16 nvm_version;
|
||||
u8 board_type;
|
||||
u8 reserved;
|
||||
} __packed; /* GRP_REGULATORY_NVM_GET_INFO_GENERAL_S_VER_1 */
|
||||
u8 n_hw_addrs;
|
||||
} __packed; /* REGULATORY_NVM_GET_INFO_GENERAL_S_VER_2 */
|
||||
|
||||
/**
|
||||
* enum iwl_nvm_mac_sku_flags - flags in &iwl_nvm_get_info_sku
|
||||
@ -231,7 +231,7 @@ struct iwl_nvm_get_info_sku {
|
||||
struct iwl_nvm_get_info_phy {
|
||||
__le32 tx_chains;
|
||||
__le32 rx_chains;
|
||||
} __packed; /* GRP_REGULATORY_NVM_GET_INFO_PHY_SKU_SECTION_S_VER_1 */
|
||||
} __packed; /* REGULATORY_NVM_GET_INFO_PHY_SKU_SECTION_S_VER_1 */
|
||||
|
||||
#define IWL_NUM_CHANNELS (51)
|
||||
|
||||
@ -245,7 +245,7 @@ struct iwl_nvm_get_info_regulatory {
|
||||
__le32 lar_enabled;
|
||||
__le16 channel_profile[IWL_NUM_CHANNELS];
|
||||
__le16 reserved;
|
||||
} __packed; /* GRP_REGULATORY_NVM_GET_INFO_REGULATORY_S_VER_1 */
|
||||
} __packed; /* REGULATORY_NVM_GET_INFO_REGULATORY_S_VER_1 */
|
||||
|
||||
/**
|
||||
* struct iwl_nvm_get_info_rsp - response to get NVM data
|
||||
@ -259,7 +259,7 @@ struct iwl_nvm_get_info_rsp {
|
||||
struct iwl_nvm_get_info_sku mac_sku;
|
||||
struct iwl_nvm_get_info_phy phy_sku;
|
||||
struct iwl_nvm_get_info_regulatory regulatory;
|
||||
} __packed; /* GRP_REGULATORY_NVM_GET_INFO_CMD_RSP_S_VER_2 */
|
||||
} __packed; /* REGULATORY_NVM_GET_INFO_RSP_API_S_VER_3 */
|
||||
|
||||
/**
|
||||
* struct iwl_nvm_access_complete_cmd - NVM_ACCESS commands are completed
|
||||
@ -269,22 +269,6 @@ struct iwl_nvm_access_complete_cmd {
|
||||
__le32 reserved;
|
||||
} __packed; /* NVM_ACCESS_COMPLETE_CMD_API_S_VER_1 */
|
||||
|
||||
/**
|
||||
* struct iwl_mcc_update_cmd_v1 - Request the device to update geographic
|
||||
* regulatory profile according to the given MCC (Mobile Country Code).
|
||||
* The MCC is two letter-code, ascii upper case[A-Z] or '00' for world domain.
|
||||
* 'ZZ' MCC will be used to switch to NVM default profile; in this case, the
|
||||
* MCC in the cmd response will be the relevant MCC in the NVM.
|
||||
* @mcc: given mobile country code
|
||||
* @source_id: the source from where we got the MCC, see iwl_mcc_source
|
||||
* @reserved: reserved for alignment
|
||||
*/
|
||||
struct iwl_mcc_update_cmd_v1 {
|
||||
__le16 mcc;
|
||||
u8 source_id;
|
||||
u8 reserved;
|
||||
} __packed; /* LAR_UPDATE_MCC_CMD_API_S_VER_1 */
|
||||
|
||||
/**
|
||||
* struct iwl_mcc_update_cmd - Request the device to update geographic
|
||||
* regulatory profile according to the given MCC (Mobile Country Code).
|
||||
@ -305,29 +289,6 @@ struct iwl_mcc_update_cmd {
|
||||
u8 reserved2[20];
|
||||
} __packed; /* LAR_UPDATE_MCC_CMD_API_S_VER_2 */
|
||||
|
||||
/**
|
||||
* struct iwl_mcc_update_resp_v1 - response to MCC_UPDATE_CMD.
|
||||
* Contains the new channel control profile map, if changed, and the new MCC
|
||||
* (mobile country code).
|
||||
* The new MCC may be different than what was requested in MCC_UPDATE_CMD.
|
||||
* @status: see &enum iwl_mcc_update_status
|
||||
* @mcc: the new applied MCC
|
||||
* @cap: capabilities for all channels which matches the MCC
|
||||
* @source_id: the MCC source, see iwl_mcc_source
|
||||
* @n_channels: number of channels in @channels_data (may be 14, 39, 50 or 51
|
||||
* channels, depending on platform)
|
||||
* @channels: channel control data map, DWORD for each channel. Only the first
|
||||
* 16bits are used.
|
||||
*/
|
||||
struct iwl_mcc_update_resp_v1 {
|
||||
__le32 status;
|
||||
__le16 mcc;
|
||||
u8 cap;
|
||||
u8 source_id;
|
||||
__le32 n_channels;
|
||||
__le32 channels[0];
|
||||
} __packed; /* LAR_UPDATE_MCC_CMD_RESP_S_VER_1 */
|
||||
|
||||
/**
|
||||
* enum iwl_geo_information - geographic information.
|
||||
* @GEO_NO_INFO: no special info for this geo profile.
|
||||
@ -340,7 +301,7 @@ enum iwl_geo_information {
|
||||
};
|
||||
|
||||
/**
|
||||
* struct iwl_mcc_update_resp - response to MCC_UPDATE_CMD.
|
||||
* struct iwl_mcc_update_resp_v3 - response to MCC_UPDATE_CMD.
|
||||
* Contains the new channel control profile map, if changed, and the new MCC
|
||||
* (mobile country code).
|
||||
* The new MCC may be different than what was requested in MCC_UPDATE_CMD.
|
||||
@ -348,15 +309,14 @@ enum iwl_geo_information {
|
||||
* @mcc: the new applied MCC
|
||||
* @cap: capabilities for all channels which matches the MCC
|
||||
* @source_id: the MCC source, see iwl_mcc_source
|
||||
* @time: time elapsed from the MCC test start (in 30 seconds TU)
|
||||
* @time: time elapsed from the MCC test start (in units of 30 seconds)
|
||||
* @geo_info: geographic specific profile information
|
||||
* see &enum iwl_geo_information.
|
||||
* @n_channels: number of channels in @channels_data (may be 14, 39, 50 or 51
|
||||
* channels, depending on platform)
|
||||
* @n_channels: number of channels in @channels_data.
|
||||
* @channels: channel control data map, DWORD for each channel. Only the first
|
||||
* 16bits are used.
|
||||
*/
|
||||
struct iwl_mcc_update_resp {
|
||||
struct iwl_mcc_update_resp_v3 {
|
||||
__le32 status;
|
||||
__le16 mcc;
|
||||
u8 cap;
|
||||
@ -367,6 +327,35 @@ struct iwl_mcc_update_resp {
|
||||
__le32 channels[0];
|
||||
} __packed; /* LAR_UPDATE_MCC_CMD_RESP_S_VER_3 */
|
||||
|
||||
/**
|
||||
* struct iwl_mcc_update_resp - response to MCC_UPDATE_CMD.
|
||||
* Contains the new channel control profile map, if changed, and the new MCC
|
||||
* (mobile country code).
|
||||
* The new MCC may be different than what was requested in MCC_UPDATE_CMD.
|
||||
* @status: see &enum iwl_mcc_update_status
|
||||
* @mcc: the new applied MCC
|
||||
* @cap: capabilities for all channels which matches the MCC
|
||||
* @time: time elapsed from the MCC test start (in units of 30 seconds)
|
||||
* @geo_info: geographic specific profile information
|
||||
* see &enum iwl_geo_information.
|
||||
* @source_id: the MCC source, see iwl_mcc_source
|
||||
* @reserved: for four bytes alignment.
|
||||
* @n_channels: number of channels in @channels_data.
|
||||
* @channels: channel control data map, DWORD for each channel. Only the first
|
||||
* 16bits are used.
|
||||
*/
|
||||
struct iwl_mcc_update_resp {
|
||||
__le32 status;
|
||||
__le16 mcc;
|
||||
__le16 cap;
|
||||
__le16 time;
|
||||
__le16 geo_info;
|
||||
u8 source_id;
|
||||
u8 reserved[3];
|
||||
__le32 n_channels;
|
||||
__le32 channels[0];
|
||||
} __packed; /* LAR_UPDATE_MCC_CMD_RESP_S_VER_4 */
|
||||
|
||||
/**
|
||||
* struct iwl_mcc_chub_notif - chub notifies of mcc change
|
||||
* (MCC_CHUB_UPDATE_CMD = 0xc9)
|
||||
|
@ -368,10 +368,10 @@ enum iwl_rx_he_phy {
|
||||
/* trigger encoded */
|
||||
IWL_RX_HE_PHY_RU_ALLOC_MASK = 0xfe0000000000ULL,
|
||||
IWL_RX_HE_PHY_INFO_TYPE_MASK = 0xf000000000000000ULL,
|
||||
IWL_RX_HE_PHY_INFO_TYPE_SU = 0x0,
|
||||
IWL_RX_HE_PHY_INFO_TYPE_MU = 0x1,
|
||||
IWL_RX_HE_PHY_INFO_TYPE_MU_EXT_INFO = 0x2,
|
||||
IWL_RX_HE_PHY_INFO_TYPE_TB_EXT_INFO = 0x3,
|
||||
IWL_RX_HE_PHY_INFO_TYPE_SU = 0x0, /* TSF low valid (first DW) */
|
||||
IWL_RX_HE_PHY_INFO_TYPE_MU = 0x1, /* TSF low/high valid (both DWs) */
|
||||
IWL_RX_HE_PHY_INFO_TYPE_MU_EXT_INFO = 0x2, /* same + SIGB-common0/1/2 valid */
|
||||
IWL_RX_HE_PHY_INFO_TYPE_TB = 0x3, /* TSF low/high valid (both DWs) */
|
||||
|
||||
/* second dword - MU data */
|
||||
IWL_RX_HE_PHY_MU_SIGB_COMPRESSION = BIT_ULL(32 + 0),
|
||||
|
@ -596,9 +596,12 @@ enum iwl_umac_scan_general_flags {
|
||||
* enum iwl_umac_scan_general_flags2 - UMAC scan general flags #2
|
||||
* @IWL_UMAC_SCAN_GEN_FLAGS2_NOTIF_PER_CHNL: Whether to send a complete
|
||||
* notification per channel or not.
|
||||
* @IWL_UMAC_SCAN_GEN_FLAGS2_ALLOW_CHNL_REORDER: Whether to allow channel
|
||||
* reorder optimization or not.
|
||||
*/
|
||||
enum iwl_umac_scan_general_flags2 {
|
||||
IWL_UMAC_SCAN_GEN_FLAGS2_NOTIF_PER_CHNL = BIT(0),
|
||||
IWL_UMAC_SCAN_GEN_FLAGS2_NOTIF_PER_CHNL = BIT(0),
|
||||
IWL_UMAC_SCAN_GEN_FLAGS2_ALLOW_CHNL_REORDER = BIT(1),
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -240,7 +240,7 @@ static void iwl_fw_dump_fifos(struct iwl_fw_runtime *fwrt,
|
||||
if (!iwl_trans_grab_nic_access(fwrt->trans, &flags))
|
||||
return;
|
||||
|
||||
if (fwrt->fw->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_RXF)) {
|
||||
if (fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_RXF)) {
|
||||
/* Pull RXF1 */
|
||||
iwl_fwrt_dump_rxf(fwrt, dump_data,
|
||||
cfg->lmac[0].rxfifo1_size, 0, 0);
|
||||
@ -254,7 +254,7 @@ static void iwl_fw_dump_fifos(struct iwl_fw_runtime *fwrt,
|
||||
LMAC2_PRPH_OFFSET, 2);
|
||||
}
|
||||
|
||||
if (fwrt->fw->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_TXF)) {
|
||||
if (fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_TXF)) {
|
||||
/* Pull TXF data from LMAC1 */
|
||||
for (i = 0; i < fwrt->smem_cfg.num_txfifo_entries; i++) {
|
||||
/* Mark the number of TXF we're pulling now */
|
||||
@ -279,7 +279,7 @@ static void iwl_fw_dump_fifos(struct iwl_fw_runtime *fwrt,
|
||||
}
|
||||
}
|
||||
|
||||
if (fwrt->fw->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_INTERNAL_TXF) &&
|
||||
if (fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_INTERNAL_TXF) &&
|
||||
fw_has_capa(&fwrt->fw->ucode_capa,
|
||||
IWL_UCODE_TLV_CAPA_EXTEND_SHARED_MEM_CFG)) {
|
||||
/* Pull UMAC internal TXF data from all TXFs */
|
||||
@ -573,103 +573,95 @@ static int iwl_fw_get_prph_len(struct iwl_fw_runtime *fwrt)
|
||||
|
||||
static void iwl_fw_dump_mem(struct iwl_fw_runtime *fwrt,
|
||||
struct iwl_fw_error_dump_data **dump_data,
|
||||
u32 sram_len, u32 sram_ofs, u32 smem_len,
|
||||
u32 sram2_len)
|
||||
u32 len, u32 ofs, u32 type)
|
||||
{
|
||||
const struct iwl_fw_dbg_mem_seg_tlv *fw_dbg_mem = fwrt->fw->dbg_mem_tlv;
|
||||
struct iwl_fw_error_dump_mem *dump_mem;
|
||||
int i;
|
||||
|
||||
if (!fwrt->fw->n_dbg_mem_tlv) {
|
||||
(*dump_data)->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM);
|
||||
(*dump_data)->len = cpu_to_le32(sram_len + sizeof(*dump_mem));
|
||||
dump_mem = (void *)(*dump_data)->data;
|
||||
dump_mem->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM_SRAM);
|
||||
dump_mem->offset = cpu_to_le32(sram_ofs);
|
||||
iwl_trans_read_mem_bytes(fwrt->trans, sram_ofs, dump_mem->data,
|
||||
sram_len);
|
||||
*dump_data = iwl_fw_error_next_data(*dump_data);
|
||||
}
|
||||
if (!len)
|
||||
return;
|
||||
|
||||
for (i = 0; i < fwrt->fw->n_dbg_mem_tlv; i++) {
|
||||
u32 len = le32_to_cpu(fw_dbg_mem[i].len);
|
||||
u32 ofs = le32_to_cpu(fw_dbg_mem[i].ofs);
|
||||
(*dump_data)->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM);
|
||||
(*dump_data)->len = cpu_to_le32(len + sizeof(*dump_mem));
|
||||
dump_mem = (void *)(*dump_data)->data;
|
||||
dump_mem->type = cpu_to_le32(type);
|
||||
dump_mem->offset = cpu_to_le32(ofs);
|
||||
iwl_trans_read_mem_bytes(fwrt->trans, ofs, dump_mem->data, len);
|
||||
*dump_data = iwl_fw_error_next_data(*dump_data);
|
||||
|
||||
(*dump_data)->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM);
|
||||
(*dump_data)->len = cpu_to_le32(len + sizeof(*dump_mem));
|
||||
dump_mem = (void *)(*dump_data)->data;
|
||||
dump_mem->type = fw_dbg_mem[i].data_type;
|
||||
dump_mem->offset = cpu_to_le32(ofs);
|
||||
|
||||
IWL_DEBUG_INFO(fwrt, "WRT memory dump. Type=%u\n",
|
||||
dump_mem->type);
|
||||
|
||||
iwl_trans_read_mem_bytes(fwrt->trans, ofs, dump_mem->data, len);
|
||||
*dump_data = iwl_fw_error_next_data(*dump_data);
|
||||
}
|
||||
|
||||
if (smem_len) {
|
||||
IWL_DEBUG_INFO(fwrt, "WRT SMEM dump\n");
|
||||
(*dump_data)->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM);
|
||||
(*dump_data)->len = cpu_to_le32(smem_len + sizeof(*dump_mem));
|
||||
dump_mem = (void *)(*dump_data)->data;
|
||||
dump_mem->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM_SMEM);
|
||||
dump_mem->offset = cpu_to_le32(fwrt->trans->cfg->smem_offset);
|
||||
iwl_trans_read_mem_bytes(fwrt->trans,
|
||||
fwrt->trans->cfg->smem_offset,
|
||||
dump_mem->data, smem_len);
|
||||
*dump_data = iwl_fw_error_next_data(*dump_data);
|
||||
}
|
||||
|
||||
if (sram2_len) {
|
||||
IWL_DEBUG_INFO(fwrt, "WRT SRAM dump\n");
|
||||
(*dump_data)->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM);
|
||||
(*dump_data)->len = cpu_to_le32(sram2_len + sizeof(*dump_mem));
|
||||
dump_mem = (void *)(*dump_data)->data;
|
||||
dump_mem->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM_SRAM);
|
||||
dump_mem->offset = cpu_to_le32(fwrt->trans->cfg->dccm2_offset);
|
||||
iwl_trans_read_mem_bytes(fwrt->trans,
|
||||
fwrt->trans->cfg->dccm2_offset,
|
||||
dump_mem->data, sram2_len);
|
||||
*dump_data = iwl_fw_error_next_data(*dump_data);
|
||||
}
|
||||
IWL_DEBUG_INFO(fwrt, "WRT memory dump. Type=%u\n", dump_mem->type);
|
||||
}
|
||||
|
||||
void iwl_fw_error_dump(struct iwl_fw_runtime *fwrt)
|
||||
#define ADD_LEN(len, item_len, const_len) \
|
||||
do {size_t item = item_len; len += (!!item) * const_len + item; } \
|
||||
while (0)
|
||||
|
||||
static int iwl_fw_fifo_len(struct iwl_fw_runtime *fwrt,
|
||||
struct iwl_fwrt_shared_mem_cfg *mem_cfg)
|
||||
{
|
||||
size_t hdr_len = sizeof(struct iwl_fw_error_dump_data) +
|
||||
sizeof(struct iwl_fw_error_dump_fifo);
|
||||
u32 fifo_len = 0;
|
||||
int i;
|
||||
|
||||
if (!(fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_RXF)))
|
||||
goto dump_txf;
|
||||
|
||||
/* Count RXF2 size */
|
||||
ADD_LEN(fifo_len, mem_cfg->rxfifo2_size, hdr_len);
|
||||
|
||||
/* Count RXF1 sizes */
|
||||
for (i = 0; i < mem_cfg->num_lmacs; i++)
|
||||
ADD_LEN(fifo_len, mem_cfg->lmac[i].rxfifo1_size, hdr_len);
|
||||
|
||||
dump_txf:
|
||||
if (!(fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_TXF)))
|
||||
goto dump_internal_txf;
|
||||
|
||||
/* Count TXF sizes */
|
||||
for (i = 0; i < mem_cfg->num_lmacs; i++) {
|
||||
int j;
|
||||
|
||||
for (j = 0; j < mem_cfg->num_txfifo_entries; j++)
|
||||
ADD_LEN(fifo_len, mem_cfg->lmac[i].txfifo_size[j],
|
||||
hdr_len);
|
||||
}
|
||||
|
||||
dump_internal_txf:
|
||||
if (!((fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_INTERNAL_TXF)) &&
|
||||
fw_has_capa(&fwrt->fw->ucode_capa,
|
||||
IWL_UCODE_TLV_CAPA_EXTEND_SHARED_MEM_CFG)))
|
||||
goto out;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(mem_cfg->internal_txfifo_size); i++)
|
||||
ADD_LEN(fifo_len, mem_cfg->internal_txfifo_size[i], hdr_len);
|
||||
|
||||
out:
|
||||
return fifo_len;
|
||||
}
|
||||
|
||||
static struct iwl_fw_error_dump_file *
|
||||
_iwl_fw_error_dump(struct iwl_fw_runtime *fwrt,
|
||||
struct iwl_fw_dump_ptrs *fw_error_dump)
|
||||
{
|
||||
struct iwl_fw_error_dump_file *dump_file;
|
||||
struct iwl_fw_error_dump_data *dump_data;
|
||||
struct iwl_fw_error_dump_info *dump_info;
|
||||
struct iwl_fw_error_dump_smem_cfg *dump_smem_cfg;
|
||||
struct iwl_fw_error_dump_trigger_desc *dump_trig;
|
||||
struct iwl_fw_dump_ptrs *fw_error_dump;
|
||||
struct scatterlist *sg_dump_data;
|
||||
u32 sram_len, sram_ofs;
|
||||
const struct iwl_fw_dbg_mem_seg_tlv *fw_dbg_mem = fwrt->fw->dbg_mem_tlv;
|
||||
const struct iwl_fw_dbg_mem_seg_tlv *fw_mem = fwrt->fw->dbg.mem_tlv;
|
||||
struct iwl_fwrt_shared_mem_cfg *mem_cfg = &fwrt->smem_cfg;
|
||||
u32 file_len, fifo_data_len = 0, prph_len = 0, radio_len = 0;
|
||||
u32 smem_len = fwrt->fw->n_dbg_mem_tlv ? 0 : fwrt->trans->cfg->smem_len;
|
||||
u32 sram2_len = fwrt->fw->n_dbg_mem_tlv ?
|
||||
u32 file_len, fifo_len = 0, prph_len = 0, radio_len = 0;
|
||||
u32 smem_len = fwrt->fw->dbg.n_mem_tlv ? 0 : fwrt->trans->cfg->smem_len;
|
||||
u32 sram2_len = fwrt->fw->dbg.n_mem_tlv ?
|
||||
0 : fwrt->trans->cfg->dccm2_len;
|
||||
bool monitor_dump_only = false;
|
||||
int i;
|
||||
|
||||
IWL_DEBUG_INFO(fwrt, "WRT dump start\n");
|
||||
|
||||
/* there's no point in fw dump if the bus is dead */
|
||||
if (test_bit(STATUS_TRANS_DEAD, &fwrt->trans->status)) {
|
||||
IWL_ERR(fwrt, "Skip fw error dump since bus is dead\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (fwrt->dump.trig &&
|
||||
fwrt->dump.trig->mode & IWL_FW_DBG_TRIGGER_MONITOR_ONLY)
|
||||
monitor_dump_only = true;
|
||||
|
||||
fw_error_dump = kzalloc(sizeof(*fw_error_dump), GFP_KERNEL);
|
||||
if (!fw_error_dump)
|
||||
goto out;
|
||||
|
||||
/* SRAM - include stack CCM if driver knows the values for it */
|
||||
if (!fwrt->trans->cfg->dccm_offset || !fwrt->trans->cfg->dccm_len) {
|
||||
const struct fw_img *img;
|
||||
@ -684,112 +676,43 @@ void iwl_fw_error_dump(struct iwl_fw_runtime *fwrt)
|
||||
|
||||
/* reading RXF/TXF sizes */
|
||||
if (test_bit(STATUS_FW_ERROR, &fwrt->trans->status)) {
|
||||
fifo_data_len = 0;
|
||||
|
||||
if (fwrt->fw->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_RXF)) {
|
||||
|
||||
/* Count RXF2 size */
|
||||
if (mem_cfg->rxfifo2_size) {
|
||||
/* Add header info */
|
||||
fifo_data_len +=
|
||||
mem_cfg->rxfifo2_size +
|
||||
sizeof(*dump_data) +
|
||||
sizeof(struct iwl_fw_error_dump_fifo);
|
||||
}
|
||||
|
||||
/* Count RXF1 sizes */
|
||||
for (i = 0; i < mem_cfg->num_lmacs; i++) {
|
||||
if (!mem_cfg->lmac[i].rxfifo1_size)
|
||||
continue;
|
||||
|
||||
/* Add header info */
|
||||
fifo_data_len +=
|
||||
mem_cfg->lmac[i].rxfifo1_size +
|
||||
sizeof(*dump_data) +
|
||||
sizeof(struct iwl_fw_error_dump_fifo);
|
||||
}
|
||||
}
|
||||
|
||||
if (fwrt->fw->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_TXF)) {
|
||||
size_t fifo_const_len = sizeof(*dump_data) +
|
||||
sizeof(struct iwl_fw_error_dump_fifo);
|
||||
|
||||
/* Count TXF sizes */
|
||||
for (i = 0; i < mem_cfg->num_lmacs; i++) {
|
||||
int j;
|
||||
|
||||
for (j = 0; j < mem_cfg->num_txfifo_entries;
|
||||
j++) {
|
||||
if (!mem_cfg->lmac[i].txfifo_size[j])
|
||||
continue;
|
||||
|
||||
/* Add header info */
|
||||
fifo_data_len +=
|
||||
fifo_const_len +
|
||||
mem_cfg->lmac[i].txfifo_size[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((fwrt->fw->dbg_dump_mask &
|
||||
BIT(IWL_FW_ERROR_DUMP_INTERNAL_TXF)) &&
|
||||
fw_has_capa(&fwrt->fw->ucode_capa,
|
||||
IWL_UCODE_TLV_CAPA_EXTEND_SHARED_MEM_CFG)) {
|
||||
for (i = 0;
|
||||
i < ARRAY_SIZE(mem_cfg->internal_txfifo_size);
|
||||
i++) {
|
||||
if (!mem_cfg->internal_txfifo_size[i])
|
||||
continue;
|
||||
|
||||
/* Add header info */
|
||||
fifo_data_len +=
|
||||
mem_cfg->internal_txfifo_size[i] +
|
||||
sizeof(*dump_data) +
|
||||
sizeof(struct iwl_fw_error_dump_fifo);
|
||||
}
|
||||
}
|
||||
fifo_len = iwl_fw_fifo_len(fwrt, mem_cfg);
|
||||
|
||||
/* Make room for PRPH registers */
|
||||
if (!fwrt->trans->cfg->gen2 &&
|
||||
fwrt->fw->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_PRPH))
|
||||
fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_PRPH))
|
||||
prph_len += iwl_fw_get_prph_len(fwrt);
|
||||
|
||||
if (fwrt->trans->cfg->device_family == IWL_DEVICE_FAMILY_7000 &&
|
||||
fwrt->fw->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_RADIO_REG))
|
||||
fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_RADIO_REG))
|
||||
radio_len = sizeof(*dump_data) + RADIO_REG_MAX_READ;
|
||||
}
|
||||
|
||||
file_len = sizeof(*dump_file) +
|
||||
fifo_data_len +
|
||||
prph_len +
|
||||
radio_len;
|
||||
file_len = sizeof(*dump_file) + fifo_len + prph_len + radio_len;
|
||||
|
||||
if (fwrt->fw->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_DEV_FW_INFO))
|
||||
if (fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_DEV_FW_INFO))
|
||||
file_len += sizeof(*dump_data) + sizeof(*dump_info);
|
||||
if (fwrt->fw->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_MEM_CFG))
|
||||
if (fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_MEM_CFG))
|
||||
file_len += sizeof(*dump_data) + sizeof(*dump_smem_cfg);
|
||||
|
||||
if (fwrt->fw->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_MEM)) {
|
||||
/* Make room for the SMEM, if it exists */
|
||||
if (smem_len)
|
||||
file_len += sizeof(*dump_data) + smem_len +
|
||||
sizeof(struct iwl_fw_error_dump_mem);
|
||||
if (fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_MEM)) {
|
||||
size_t hdr_len = sizeof(*dump_data) +
|
||||
sizeof(struct iwl_fw_error_dump_mem);
|
||||
|
||||
/* Make room for the secondary SRAM, if it exists */
|
||||
if (sram2_len)
|
||||
file_len += sizeof(*dump_data) + sram2_len +
|
||||
sizeof(struct iwl_fw_error_dump_mem);
|
||||
/* Dump SRAM only if no mem_tlvs */
|
||||
if (!fwrt->fw->dbg.n_mem_tlv)
|
||||
ADD_LEN(file_len, sram_len, hdr_len);
|
||||
|
||||
/* Make room for MEM segments */
|
||||
for (i = 0; i < fwrt->fw->n_dbg_mem_tlv; i++) {
|
||||
file_len += sizeof(*dump_data) +
|
||||
le32_to_cpu(fw_dbg_mem[i].len) +
|
||||
sizeof(struct iwl_fw_error_dump_mem);
|
||||
}
|
||||
/* Make room for all mem types that exist */
|
||||
ADD_LEN(file_len, smem_len, hdr_len);
|
||||
ADD_LEN(file_len, sram2_len, hdr_len);
|
||||
|
||||
for (i = 0; i < fwrt->fw->dbg.n_mem_tlv; i++)
|
||||
ADD_LEN(file_len, le32_to_cpu(fw_mem[i].len), hdr_len);
|
||||
}
|
||||
|
||||
/* Make room for fw's virtual image pages, if it exists */
|
||||
if (fwrt->fw->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_PAGING) &&
|
||||
if (fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_PAGING) &&
|
||||
!fwrt->trans->cfg->gen2 &&
|
||||
fwrt->fw->img[fwrt->cur_fw_img].paging_mem_size &&
|
||||
fwrt->fw_paging_db[0].fw_paging_block)
|
||||
@ -809,28 +732,21 @@ void iwl_fw_error_dump(struct iwl_fw_runtime *fwrt)
|
||||
sizeof(*dump_info) + sizeof(*dump_smem_cfg);
|
||||
}
|
||||
|
||||
if (fwrt->fw->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_ERROR_INFO) &&
|
||||
if (fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_ERROR_INFO) &&
|
||||
fwrt->dump.desc)
|
||||
file_len += sizeof(*dump_data) + sizeof(*dump_trig) +
|
||||
fwrt->dump.desc->len;
|
||||
|
||||
if (fwrt->fw->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_MEM) &&
|
||||
!fwrt->fw->n_dbg_mem_tlv)
|
||||
file_len += sizeof(*dump_data) + sram_len +
|
||||
sizeof(struct iwl_fw_error_dump_mem);
|
||||
|
||||
dump_file = vzalloc(file_len);
|
||||
if (!dump_file) {
|
||||
kfree(fw_error_dump);
|
||||
goto out;
|
||||
}
|
||||
if (!dump_file)
|
||||
return NULL;
|
||||
|
||||
fw_error_dump->fwrt_ptr = dump_file;
|
||||
|
||||
dump_file->barker = cpu_to_le32(IWL_FW_ERROR_DUMP_BARKER);
|
||||
dump_data = (void *)dump_file->data;
|
||||
|
||||
if (fwrt->fw->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_DEV_FW_INFO)) {
|
||||
if (fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_DEV_FW_INFO)) {
|
||||
dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_DEV_FW_INFO);
|
||||
dump_data->len = cpu_to_le32(sizeof(*dump_info));
|
||||
dump_info = (void *)dump_data->data;
|
||||
@ -851,7 +767,7 @@ void iwl_fw_error_dump(struct iwl_fw_runtime *fwrt)
|
||||
dump_data = iwl_fw_error_next_data(dump_data);
|
||||
}
|
||||
|
||||
if (fwrt->fw->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_MEM_CFG)) {
|
||||
if (fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_MEM_CFG)) {
|
||||
/* Dump shared memory configuration */
|
||||
dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM_CFG);
|
||||
dump_data->len = cpu_to_le32(sizeof(*dump_smem_cfg));
|
||||
@ -882,13 +798,13 @@ void iwl_fw_error_dump(struct iwl_fw_runtime *fwrt)
|
||||
}
|
||||
|
||||
/* We only dump the FIFOs if the FW is in error state */
|
||||
if (fifo_data_len) {
|
||||
if (fifo_len) {
|
||||
iwl_fw_dump_fifos(fwrt, &dump_data);
|
||||
if (radio_len)
|
||||
iwl_read_radio_regs(fwrt, &dump_data);
|
||||
}
|
||||
|
||||
if (fwrt->fw->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_ERROR_INFO) &&
|
||||
if (fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_ERROR_INFO) &&
|
||||
fwrt->dump.desc) {
|
||||
dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_ERROR_INFO);
|
||||
dump_data->len = cpu_to_le32(sizeof(*dump_trig) +
|
||||
@ -902,12 +818,32 @@ void iwl_fw_error_dump(struct iwl_fw_runtime *fwrt)
|
||||
|
||||
/* In case we only want monitor dump, skip to dump trasport data */
|
||||
if (monitor_dump_only)
|
||||
goto dump_trans_data;
|
||||
goto out;
|
||||
|
||||
if (fwrt->fw->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_MEM))
|
||||
iwl_fw_dump_mem(fwrt, &dump_data, sram_len, sram_ofs, smem_len,
|
||||
sram2_len);
|
||||
if (fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_MEM)) {
|
||||
const struct iwl_fw_dbg_mem_seg_tlv *fw_dbg_mem =
|
||||
fwrt->fw->dbg.mem_tlv;
|
||||
|
||||
if (!fwrt->fw->dbg.n_mem_tlv)
|
||||
iwl_fw_dump_mem(fwrt, &dump_data, sram_len, sram_ofs,
|
||||
IWL_FW_ERROR_DUMP_MEM_SRAM);
|
||||
|
||||
for (i = 0; i < fwrt->fw->dbg.n_mem_tlv; i++) {
|
||||
u32 len = le32_to_cpu(fw_dbg_mem[i].len);
|
||||
u32 ofs = le32_to_cpu(fw_dbg_mem[i].ofs);
|
||||
|
||||
iwl_fw_dump_mem(fwrt, &dump_data, len, ofs,
|
||||
le32_to_cpu(fw_dbg_mem[i].data_type));
|
||||
}
|
||||
|
||||
iwl_fw_dump_mem(fwrt, &dump_data, smem_len,
|
||||
fwrt->trans->cfg->smem_offset,
|
||||
IWL_FW_ERROR_DUMP_MEM_SMEM);
|
||||
|
||||
iwl_fw_dump_mem(fwrt, &dump_data, sram2_len,
|
||||
fwrt->trans->cfg->dccm2_offset,
|
||||
IWL_FW_ERROR_DUMP_MEM_SRAM);
|
||||
}
|
||||
|
||||
if (iwl_fw_dbg_is_d3_debug_enabled(fwrt) && fwrt->dump.d3_debug_data) {
|
||||
u32 addr = fwrt->trans->cfg->d3_debug_data_base_addr;
|
||||
@ -929,7 +865,7 @@ void iwl_fw_error_dump(struct iwl_fw_runtime *fwrt)
|
||||
}
|
||||
|
||||
/* Dump fw's virtual image */
|
||||
if (fwrt->fw->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_PAGING) &&
|
||||
if (fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_PAGING) &&
|
||||
!fwrt->trans->cfg->gen2 &&
|
||||
fwrt->fw->img[fwrt->cur_fw_img].paging_mem_size &&
|
||||
fwrt->fw_paging_db[0].fw_paging_block) {
|
||||
@ -965,13 +901,44 @@ void iwl_fw_error_dump(struct iwl_fw_runtime *fwrt)
|
||||
ARRAY_SIZE(iwl_prph_dump_addr_9000));
|
||||
}
|
||||
|
||||
dump_trans_data:
|
||||
out:
|
||||
dump_file->file_len = cpu_to_le32(file_len);
|
||||
return dump_file;
|
||||
}
|
||||
|
||||
void iwl_fw_error_dump(struct iwl_fw_runtime *fwrt)
|
||||
{
|
||||
struct iwl_fw_dump_ptrs *fw_error_dump;
|
||||
struct iwl_fw_error_dump_file *dump_file;
|
||||
struct scatterlist *sg_dump_data;
|
||||
u32 file_len;
|
||||
|
||||
IWL_DEBUG_INFO(fwrt, "WRT dump start\n");
|
||||
|
||||
/* there's no point in fw dump if the bus is dead */
|
||||
if (test_bit(STATUS_TRANS_DEAD, &fwrt->trans->status)) {
|
||||
IWL_ERR(fwrt, "Skip fw error dump since bus is dead\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
fw_error_dump = kzalloc(sizeof(*fw_error_dump), GFP_KERNEL);
|
||||
if (!fw_error_dump)
|
||||
goto out;
|
||||
|
||||
dump_file = _iwl_fw_error_dump(fwrt, fw_error_dump);
|
||||
if (!dump_file) {
|
||||
kfree(fw_error_dump);
|
||||
goto out;
|
||||
}
|
||||
|
||||
fw_error_dump->trans_ptr = iwl_trans_dump_data(fwrt->trans,
|
||||
fwrt->dump.trig);
|
||||
file_len = le32_to_cpu(dump_file->file_len);
|
||||
fw_error_dump->fwrt_len = file_len;
|
||||
if (fw_error_dump->trans_ptr)
|
||||
if (fw_error_dump->trans_ptr) {
|
||||
file_len += fw_error_dump->trans_ptr->len;
|
||||
dump_file->file_len = cpu_to_le32(file_len);
|
||||
dump_file->file_len = cpu_to_le32(file_len);
|
||||
}
|
||||
|
||||
sg_dump_data = alloc_sgtable(file_len);
|
||||
if (sg_dump_data) {
|
||||
@ -1006,15 +973,34 @@ const struct iwl_fw_dump_desc iwl_dump_desc_assert = {
|
||||
};
|
||||
IWL_EXPORT_SYMBOL(iwl_dump_desc_assert);
|
||||
|
||||
int iwl_fw_dbg_collect_desc(struct iwl_fw_runtime *fwrt,
|
||||
const struct iwl_fw_dump_desc *desc,
|
||||
const struct iwl_fw_dbg_trigger_tlv *trigger)
|
||||
void iwl_fw_alive_error_dump(struct iwl_fw_runtime *fwrt)
|
||||
{
|
||||
unsigned int delay = 0;
|
||||
struct iwl_fw_dump_desc *iwl_dump_desc_no_alive =
|
||||
kmalloc(sizeof(*iwl_dump_desc_no_alive), GFP_KERNEL);
|
||||
|
||||
if (trigger)
|
||||
delay = msecs_to_jiffies(le32_to_cpu(trigger->stop_delay));
|
||||
if (!iwl_dump_desc_no_alive)
|
||||
return;
|
||||
|
||||
iwl_dump_desc_no_alive->trig_desc.type =
|
||||
cpu_to_le32(FW_DBG_TRIGGER_NO_ALIVE);
|
||||
iwl_dump_desc_no_alive->len = 0;
|
||||
|
||||
if (WARN_ON(fwrt->dump.desc))
|
||||
iwl_fw_free_dump_desc(fwrt);
|
||||
|
||||
IWL_WARN(fwrt, "Collecting data: trigger %d fired.\n",
|
||||
FW_DBG_TRIGGER_NO_ALIVE);
|
||||
|
||||
fwrt->dump.desc = iwl_dump_desc_no_alive;
|
||||
iwl_fw_error_dump(fwrt);
|
||||
clear_bit(IWL_FWRT_STATUS_WAIT_ALIVE, &fwrt->status);
|
||||
}
|
||||
IWL_EXPORT_SYMBOL(iwl_fw_alive_error_dump);
|
||||
|
||||
int iwl_fw_dbg_collect_desc(struct iwl_fw_runtime *fwrt,
|
||||
const struct iwl_fw_dump_desc *desc, void *trigger,
|
||||
unsigned int delay)
|
||||
{
|
||||
/*
|
||||
* If the loading of the FW completed successfully, the next step is to
|
||||
* get the SMEM config data. Thus, if fwrt->smem_cfg.num_lmacs is non
|
||||
@ -1031,7 +1017,8 @@ int iwl_fw_dbg_collect_desc(struct iwl_fw_runtime *fwrt,
|
||||
fwrt->smem_cfg.num_lmacs)
|
||||
return -EIO;
|
||||
|
||||
if (test_and_set_bit(IWL_FWRT_STATUS_DUMPING, &fwrt->status))
|
||||
if (test_and_set_bit(IWL_FWRT_STATUS_DUMPING, &fwrt->status) ||
|
||||
test_bit(IWL_FWRT_STATUS_WAIT_ALIVE, &fwrt->status))
|
||||
return -EBUSY;
|
||||
|
||||
if (WARN_ON(fwrt->dump.desc))
|
||||
@ -1052,25 +1039,38 @@ IWL_EXPORT_SYMBOL(iwl_fw_dbg_collect_desc);
|
||||
int iwl_fw_dbg_collect(struct iwl_fw_runtime *fwrt,
|
||||
enum iwl_fw_dbg_trigger trig,
|
||||
const char *str, size_t len,
|
||||
const struct iwl_fw_dbg_trigger_tlv *trigger)
|
||||
struct iwl_fw_dbg_trigger_tlv *trigger)
|
||||
{
|
||||
struct iwl_fw_dump_desc *desc;
|
||||
unsigned int delay = 0;
|
||||
|
||||
if (trigger && trigger->flags & IWL_FW_DBG_FORCE_RESTART) {
|
||||
IWL_WARN(fwrt, "Force restart: trigger %d fired.\n", trig);
|
||||
iwl_force_nmi(fwrt->trans);
|
||||
return 0;
|
||||
if (trigger) {
|
||||
u16 occurrences = le16_to_cpu(trigger->occurrences) - 1;
|
||||
|
||||
if (!le16_to_cpu(trigger->occurrences))
|
||||
return 0;
|
||||
|
||||
if (trigger->flags & IWL_FW_DBG_FORCE_RESTART) {
|
||||
IWL_WARN(fwrt, "Force restart: trigger %d fired.\n",
|
||||
trig);
|
||||
iwl_force_nmi(fwrt->trans);
|
||||
return 0;
|
||||
}
|
||||
|
||||
trigger->occurrences = cpu_to_le16(occurrences);
|
||||
delay = le16_to_cpu(trigger->trig_dis_ms);
|
||||
}
|
||||
|
||||
desc = kzalloc(sizeof(*desc) + len, GFP_ATOMIC);
|
||||
if (!desc)
|
||||
return -ENOMEM;
|
||||
|
||||
|
||||
desc->len = len;
|
||||
desc->trig_desc.type = cpu_to_le32(trig);
|
||||
memcpy(desc->trig_desc.data, str, len);
|
||||
|
||||
return iwl_fw_dbg_collect_desc(fwrt, desc, trigger);
|
||||
return iwl_fw_dbg_collect_desc(fwrt, desc, trigger, delay);
|
||||
}
|
||||
IWL_EXPORT_SYMBOL(iwl_fw_dbg_collect);
|
||||
|
||||
@ -1078,13 +1078,9 @@ int iwl_fw_dbg_collect_trig(struct iwl_fw_runtime *fwrt,
|
||||
struct iwl_fw_dbg_trigger_tlv *trigger,
|
||||
const char *fmt, ...)
|
||||
{
|
||||
u16 occurrences = le16_to_cpu(trigger->occurrences);
|
||||
int ret, len = 0;
|
||||
char buf[64];
|
||||
|
||||
if (!occurrences)
|
||||
return 0;
|
||||
|
||||
if (fmt) {
|
||||
va_list ap;
|
||||
|
||||
@ -1107,7 +1103,6 @@ int iwl_fw_dbg_collect_trig(struct iwl_fw_runtime *fwrt,
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
trigger->occurrences = cpu_to_le16(occurrences - 1);
|
||||
return 0;
|
||||
}
|
||||
IWL_EXPORT_SYMBOL(iwl_fw_dbg_collect_trig);
|
||||
@ -1118,17 +1113,17 @@ int iwl_fw_start_dbg_conf(struct iwl_fw_runtime *fwrt, u8 conf_id)
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
if (WARN_ONCE(conf_id >= ARRAY_SIZE(fwrt->fw->dbg_conf_tlv),
|
||||
if (WARN_ONCE(conf_id >= ARRAY_SIZE(fwrt->fw->dbg.conf_tlv),
|
||||
"Invalid configuration %d\n", conf_id))
|
||||
return -EINVAL;
|
||||
|
||||
/* EARLY START - firmware's configuration is hard coded */
|
||||
if ((!fwrt->fw->dbg_conf_tlv[conf_id] ||
|
||||
!fwrt->fw->dbg_conf_tlv[conf_id]->num_of_hcmds) &&
|
||||
if ((!fwrt->fw->dbg.conf_tlv[conf_id] ||
|
||||
!fwrt->fw->dbg.conf_tlv[conf_id]->num_of_hcmds) &&
|
||||
conf_id == FW_DBG_START_FROM_ALIVE)
|
||||
return 0;
|
||||
|
||||
if (!fwrt->fw->dbg_conf_tlv[conf_id])
|
||||
if (!fwrt->fw->dbg.conf_tlv[conf_id])
|
||||
return -EINVAL;
|
||||
|
||||
if (fwrt->dump.conf != FW_DBG_INVALID)
|
||||
@ -1136,8 +1131,8 @@ int iwl_fw_start_dbg_conf(struct iwl_fw_runtime *fwrt, u8 conf_id)
|
||||
fwrt->dump.conf);
|
||||
|
||||
/* Send all HCMDs for configuring the FW debug */
|
||||
ptr = (void *)&fwrt->fw->dbg_conf_tlv[conf_id]->hcmd;
|
||||
for (i = 0; i < fwrt->fw->dbg_conf_tlv[conf_id]->num_of_hcmds; i++) {
|
||||
ptr = (void *)&fwrt->fw->dbg.conf_tlv[conf_id]->hcmd;
|
||||
for (i = 0; i < fwrt->fw->dbg.conf_tlv[conf_id]->num_of_hcmds; i++) {
|
||||
struct iwl_fw_dbg_conf_hcmd *cmd = (void *)ptr;
|
||||
struct iwl_host_cmd hcmd = {
|
||||
.id = cmd->id,
|
||||
@ -1183,7 +1178,7 @@ void iwl_fw_error_dump_wk(struct work_struct *work)
|
||||
|
||||
/* start recording again if the firmware is not crashed */
|
||||
if (!test_bit(STATUS_FW_ERROR, &fwrt->trans->status) &&
|
||||
fwrt->fw->dbg_dest_tlv) {
|
||||
fwrt->fw->dbg.dest_tlv) {
|
||||
/* wait before we collect the data till the DBGC stop */
|
||||
udelay(500);
|
||||
iwl_fw_dbg_restart_recording(fwrt, ¶ms);
|
||||
|
@ -107,25 +107,25 @@ static inline void iwl_fw_free_dump_desc(struct iwl_fw_runtime *fwrt)
|
||||
void iwl_fw_error_dump(struct iwl_fw_runtime *fwrt);
|
||||
int iwl_fw_dbg_collect_desc(struct iwl_fw_runtime *fwrt,
|
||||
const struct iwl_fw_dump_desc *desc,
|
||||
const struct iwl_fw_dbg_trigger_tlv *trigger);
|
||||
void *trigger, unsigned int delay);
|
||||
int iwl_fw_dbg_collect(struct iwl_fw_runtime *fwrt,
|
||||
enum iwl_fw_dbg_trigger trig,
|
||||
const char *str, size_t len,
|
||||
const struct iwl_fw_dbg_trigger_tlv *trigger);
|
||||
struct iwl_fw_dbg_trigger_tlv *trigger);
|
||||
int iwl_fw_dbg_collect_trig(struct iwl_fw_runtime *fwrt,
|
||||
struct iwl_fw_dbg_trigger_tlv *trigger,
|
||||
const char *fmt, ...) __printf(3, 4);
|
||||
int iwl_fw_start_dbg_conf(struct iwl_fw_runtime *fwrt, u8 id);
|
||||
|
||||
#define iwl_fw_dbg_trigger_enabled(fw, id) ({ \
|
||||
void *__dbg_trigger = (fw)->dbg_trigger_tlv[(id)]; \
|
||||
void *__dbg_trigger = (fw)->dbg.trigger_tlv[(id)]; \
|
||||
unlikely(__dbg_trigger); \
|
||||
})
|
||||
|
||||
static inline struct iwl_fw_dbg_trigger_tlv*
|
||||
_iwl_fw_dbg_get_trigger(const struct iwl_fw *fw, enum iwl_fw_dbg_trigger id)
|
||||
{
|
||||
return fw->dbg_trigger_tlv[id];
|
||||
return fw->dbg.trigger_tlv[id];
|
||||
}
|
||||
|
||||
#define iwl_fw_dbg_get_trigger(fw, id) ({ \
|
||||
@ -154,12 +154,9 @@ iwl_fw_dbg_trigger_stop_conf_match(struct iwl_fw_runtime *fwrt,
|
||||
}
|
||||
|
||||
static inline bool
|
||||
iwl_fw_dbg_no_trig_window(struct iwl_fw_runtime *fwrt,
|
||||
struct iwl_fw_dbg_trigger_tlv *trig)
|
||||
iwl_fw_dbg_no_trig_window(struct iwl_fw_runtime *fwrt, u32 id, u32 dis_ms)
|
||||
{
|
||||
unsigned long wind_jiff =
|
||||
msecs_to_jiffies(le16_to_cpu(trig->trig_dis_ms));
|
||||
u32 id = le32_to_cpu(trig->id);
|
||||
unsigned long wind_jiff = msecs_to_jiffies(dis_ms);
|
||||
|
||||
/* If this is the first event checked, jump to update start ts */
|
||||
if (fwrt->dump.non_collect_ts_start[id] &&
|
||||
@ -179,7 +176,8 @@ iwl_fw_dbg_trigger_check_stop(struct iwl_fw_runtime *fwrt,
|
||||
if (wdev && !iwl_fw_dbg_trigger_vif_match(trig, wdev))
|
||||
return false;
|
||||
|
||||
if (iwl_fw_dbg_no_trig_window(fwrt, trig)) {
|
||||
if (iwl_fw_dbg_no_trig_window(fwrt, le32_to_cpu(trig->id),
|
||||
le16_to_cpu(trig->trig_dis_ms))) {
|
||||
IWL_WARN(fwrt, "Trigger %d occurred while no-collect window.\n",
|
||||
trig->id);
|
||||
return false;
|
||||
@ -188,6 +186,30 @@ iwl_fw_dbg_trigger_check_stop(struct iwl_fw_runtime *fwrt,
|
||||
return iwl_fw_dbg_trigger_stop_conf_match(fwrt, trig);
|
||||
}
|
||||
|
||||
static inline struct iwl_fw_dbg_trigger_tlv*
|
||||
_iwl_fw_dbg_trigger_on(struct iwl_fw_runtime *fwrt,
|
||||
struct wireless_dev *wdev,
|
||||
const enum iwl_fw_dbg_trigger id)
|
||||
{
|
||||
struct iwl_fw_dbg_trigger_tlv *trig;
|
||||
|
||||
if (!iwl_fw_dbg_trigger_enabled(fwrt->fw, id))
|
||||
return NULL;
|
||||
|
||||
trig = _iwl_fw_dbg_get_trigger(fwrt->fw, id);
|
||||
|
||||
if (!iwl_fw_dbg_trigger_check_stop(fwrt, wdev, trig))
|
||||
return NULL;
|
||||
|
||||
return trig;
|
||||
}
|
||||
|
||||
#define iwl_fw_dbg_trigger_on(fwrt, wdev, id) ({ \
|
||||
BUILD_BUG_ON(!__builtin_constant_p(id)); \
|
||||
BUILD_BUG_ON((id) >= FW_DBG_TRIGGER_MAX); \
|
||||
_iwl_fw_dbg_trigger_on((fwrt), (wdev), (id)); \
|
||||
})
|
||||
|
||||
static inline void
|
||||
_iwl_fw_dbg_trigger_simple_stop(struct iwl_fw_runtime *fwrt,
|
||||
struct wireless_dev *wdev,
|
||||
@ -293,7 +315,7 @@ static inline bool iwl_fw_dbg_is_d3_debug_enabled(struct iwl_fw_runtime *fwrt)
|
||||
return fw_has_capa(&fwrt->fw->ucode_capa,
|
||||
IWL_UCODE_TLV_CAPA_D3_DEBUG) &&
|
||||
fwrt->trans->cfg->d3_debug_data_length &&
|
||||
fwrt->fw->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_D3_DEBUG_DATA);
|
||||
fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_D3_DEBUG_DATA);
|
||||
}
|
||||
|
||||
void iwl_fw_dbg_read_d3_debug_data(struct iwl_fw_runtime *fwrt);
|
||||
@ -344,4 +366,5 @@ static inline void iwl_fw_resume_timestamp(struct iwl_fw_runtime *fwrt) {}
|
||||
|
||||
#endif /* CONFIG_IWLWIFI_DEBUGFS */
|
||||
|
||||
void iwl_fw_alive_error_dump(struct iwl_fw_runtime *fwrt);
|
||||
#endif /* __iwl_fw_dbg_h__ */
|
||||
|
@ -258,11 +258,75 @@ static ssize_t iwl_dbgfs_timestamp_marker_read(struct iwl_fw_runtime *fwrt,
|
||||
|
||||
FWRT_DEBUGFS_READ_WRITE_FILE_OPS(timestamp_marker, 16);
|
||||
|
||||
struct hcmd_write_data {
|
||||
__be32 cmd_id;
|
||||
__be32 flags;
|
||||
__be16 length;
|
||||
u8 data[0];
|
||||
} __packed;
|
||||
|
||||
static ssize_t iwl_dbgfs_send_hcmd_write(struct iwl_fw_runtime *fwrt, char *buf,
|
||||
size_t count)
|
||||
{
|
||||
size_t header_size = (sizeof(u32) * 2 + sizeof(u16)) * 2;
|
||||
size_t data_size = (count - 1) / 2;
|
||||
int ret;
|
||||
struct hcmd_write_data *data;
|
||||
struct iwl_host_cmd hcmd = {
|
||||
.len = { 0, },
|
||||
.data = { NULL, },
|
||||
};
|
||||
|
||||
if (fwrt->ops && fwrt->ops->fw_running &&
|
||||
!fwrt->ops->fw_running(fwrt->ops_ctx))
|
||||
return -EIO;
|
||||
|
||||
if (count < header_size + 1 || count > 1024 * 4)
|
||||
return -EINVAL;
|
||||
|
||||
data = kmalloc(data_size, GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = hex2bin((u8 *)data, buf, data_size);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
hcmd.id = be32_to_cpu(data->cmd_id);
|
||||
hcmd.flags = be32_to_cpu(data->flags);
|
||||
hcmd.len[0] = be16_to_cpu(data->length);
|
||||
hcmd.data[0] = data->data;
|
||||
|
||||
if (count != header_size + hcmd.len[0] * 2 + 1) {
|
||||
IWL_ERR(fwrt,
|
||||
"host command data size does not match header length\n");
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (fwrt->ops && fwrt->ops->send_hcmd)
|
||||
ret = fwrt->ops->send_hcmd(fwrt->ops_ctx, &hcmd);
|
||||
else
|
||||
ret = -EPERM;
|
||||
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
if (hcmd.flags & CMD_WANT_SKB)
|
||||
iwl_free_resp(&hcmd);
|
||||
out:
|
||||
kfree(data);
|
||||
return ret ?: count;
|
||||
}
|
||||
|
||||
FWRT_DEBUGFS_WRITE_FILE_OPS(send_hcmd, 512);
|
||||
|
||||
int iwl_fwrt_dbgfs_register(struct iwl_fw_runtime *fwrt,
|
||||
struct dentry *dbgfs_dir)
|
||||
{
|
||||
INIT_DELAYED_WORK(&fwrt->timestamp.wk, iwl_fw_timestamp_marker_wk);
|
||||
FWRT_DEBUGFS_ADD_FILE(timestamp_marker, dbgfs_dir, 0200);
|
||||
FWRT_DEBUGFS_ADD_FILE(send_hcmd, dbgfs_dir, 0200);
|
||||
return 0;
|
||||
err:
|
||||
IWL_ERR(fwrt, "Can't create the fwrt debugfs directory\n");
|
||||
|
@ -328,6 +328,7 @@ iwl_fw_error_next_data(struct iwl_fw_error_dump_data *data)
|
||||
* @FW_DBG_TDLS: trigger log collection upon TDLS related events.
|
||||
* @FW_DBG_TRIGGER_TX_STATUS: trigger log collection upon tx status when
|
||||
* the firmware sends a tx reply.
|
||||
* @FW_DBG_TRIGGER_NO_ALIVE: trigger log collection if alive flow fails
|
||||
*/
|
||||
enum iwl_fw_dbg_trigger {
|
||||
FW_DBG_TRIGGER_INVALID = 0,
|
||||
@ -345,6 +346,7 @@ enum iwl_fw_dbg_trigger {
|
||||
FW_DBG_TRIGGER_TX_LATENCY,
|
||||
FW_DBG_TRIGGER_TDLS,
|
||||
FW_DBG_TRIGGER_TX_STATUS,
|
||||
FW_DBG_TRIGGER_NO_ALIVE,
|
||||
|
||||
/* must be last */
|
||||
FW_DBG_TRIGGER_MAX,
|
||||
|
@ -337,7 +337,7 @@ typedef unsigned int __bitwise iwl_ucode_tlv_capa_t;
|
||||
* antenna the beacon should be transmitted
|
||||
* @IWL_UCODE_TLV_CAPA_BEACON_STORING: firmware will store the latest beacon
|
||||
* from AP and will send it upon d0i3 exit.
|
||||
* @IWL_UCODE_TLV_CAPA_LAR_SUPPORT_V2: support LAR API V2
|
||||
* @IWL_UCODE_TLV_CAPA_LAR_SUPPORT_V3: support LAR API V3
|
||||
* @IWL_UCODE_TLV_CAPA_CT_KILL_BY_FW: firmware responsible for CT-kill
|
||||
* @IWL_UCODE_TLV_CAPA_TEMP_THS_REPORT_SUPPORT: supports temperature
|
||||
* thresholds reporting
|
||||
@ -352,6 +352,8 @@ typedef unsigned int __bitwise iwl_ucode_tlv_capa_t;
|
||||
* power reduction.
|
||||
* @IWL_UCODE_TLV_CAPA_MLME_OFFLOAD: supports MLME offload
|
||||
* @IWL_UCODE_TLV_CAPA_D3_DEBUG: supports debug recording during D3
|
||||
* @IWL_UCODE_TLV_CAPA_MCC_UPDATE_11AX_SUPPORT: MCC response support 11ax
|
||||
* capability.
|
||||
*
|
||||
* @NUM_IWL_UCODE_TLV_CAPA: number of bits used
|
||||
*/
|
||||
@ -392,7 +394,7 @@ enum iwl_ucode_tlv_capa {
|
||||
IWL_UCODE_TLV_CAPA_CSA_AND_TBTT_OFFLOAD = (__force iwl_ucode_tlv_capa_t)70,
|
||||
IWL_UCODE_TLV_CAPA_BEACON_ANT_SELECTION = (__force iwl_ucode_tlv_capa_t)71,
|
||||
IWL_UCODE_TLV_CAPA_BEACON_STORING = (__force iwl_ucode_tlv_capa_t)72,
|
||||
IWL_UCODE_TLV_CAPA_LAR_SUPPORT_V2 = (__force iwl_ucode_tlv_capa_t)73,
|
||||
IWL_UCODE_TLV_CAPA_LAR_SUPPORT_V3 = (__force iwl_ucode_tlv_capa_t)73,
|
||||
IWL_UCODE_TLV_CAPA_CT_KILL_BY_FW = (__force iwl_ucode_tlv_capa_t)74,
|
||||
IWL_UCODE_TLV_CAPA_TEMP_THS_REPORT_SUPPORT = (__force iwl_ucode_tlv_capa_t)75,
|
||||
IWL_UCODE_TLV_CAPA_CTDP_SUPPORT = (__force iwl_ucode_tlv_capa_t)76,
|
||||
@ -402,6 +404,7 @@ enum iwl_ucode_tlv_capa {
|
||||
IWL_UCODE_TLV_CAPA_TX_POWER_ACK = (__force iwl_ucode_tlv_capa_t)84,
|
||||
IWL_UCODE_TLV_CAPA_D3_DEBUG = (__force iwl_ucode_tlv_capa_t)87,
|
||||
IWL_UCODE_TLV_CAPA_LED_CMD_SUPPORT = (__force iwl_ucode_tlv_capa_t)88,
|
||||
IWL_UCODE_TLV_CAPA_MCC_UPDATE_11AX_SUPPORT = (__force iwl_ucode_tlv_capa_t)89,
|
||||
IWL_UCODE_TLV_CAPA_MLME_OFFLOAD = (__force iwl_ucode_tlv_capa_t)96,
|
||||
|
||||
NUM_IWL_UCODE_TLV_CAPA
|
||||
|
@ -197,6 +197,29 @@ enum iwl_fw_type {
|
||||
IWL_FW_MVM,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct iwl_fw_dbg - debug data
|
||||
*
|
||||
* @dest_tlv: points to debug destination TLV (typically SRAM or DRAM)
|
||||
* @n_dest_reg: num of reg_ops in dest_tlv
|
||||
* @conf_tlv: array of pointers to configuration HCMDs
|
||||
* @trigger_tlv: array of pointers to triggers TLVs
|
||||
* @trigger_tlv_len: lengths of the @dbg_trigger_tlv entries
|
||||
* @mem_tlv: Runtime addresses to dump
|
||||
* @n_mem_tlv: number of runtime addresses
|
||||
* @dump_mask: bitmask of dump regions
|
||||
*/
|
||||
struct iwl_fw_dbg {
|
||||
struct iwl_fw_dbg_dest_tlv_v1 *dest_tlv;
|
||||
u8 n_dest_reg;
|
||||
struct iwl_fw_dbg_conf_tlv *conf_tlv[FW_DBG_CONF_MAX];
|
||||
struct iwl_fw_dbg_trigger_tlv *trigger_tlv[FW_DBG_TRIGGER_MAX];
|
||||
size_t trigger_tlv_len[FW_DBG_TRIGGER_MAX];
|
||||
struct iwl_fw_dbg_mem_seg_tlv *mem_tlv;
|
||||
size_t n_mem_tlv;
|
||||
u32 dump_mask;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct iwl_fw - variables associated with the firmware
|
||||
*
|
||||
@ -217,12 +240,6 @@ enum iwl_fw_type {
|
||||
* @cipher_scheme: optional external cipher scheme.
|
||||
* @human_readable: human readable version
|
||||
* we get the ALIVE from the uCode
|
||||
* @dbg_dest_tlv: points to the destination TLV for debug
|
||||
* @dbg_conf_tlv: array of pointers to configuration TLVs for debug
|
||||
* @dbg_conf_tlv_len: lengths of the @dbg_conf_tlv entries
|
||||
* @dbg_trigger_tlv: array of pointers to triggers TLVs
|
||||
* @dbg_trigger_tlv_len: lengths of the @dbg_trigger_tlv entries
|
||||
* @dbg_dest_reg_num: num of reg_ops in %dbg_dest_tlv
|
||||
*/
|
||||
struct iwl_fw {
|
||||
u32 ucode_ver;
|
||||
@ -250,15 +267,7 @@ struct iwl_fw {
|
||||
struct iwl_fw_cipher_scheme cs[IWL_UCODE_MAX_CS];
|
||||
u8 human_readable[FW_VER_HUMAN_READABLE_SZ];
|
||||
|
||||
struct iwl_fw_dbg_dest_tlv_v1 *dbg_dest_tlv;
|
||||
struct iwl_fw_dbg_conf_tlv *dbg_conf_tlv[FW_DBG_CONF_MAX];
|
||||
size_t dbg_conf_tlv_len[FW_DBG_CONF_MAX];
|
||||
struct iwl_fw_dbg_trigger_tlv *dbg_trigger_tlv[FW_DBG_TRIGGER_MAX];
|
||||
struct iwl_fw_dbg_mem_seg_tlv *dbg_mem_tlv;
|
||||
size_t n_dbg_mem_tlv;
|
||||
size_t dbg_trigger_tlv_len[FW_DBG_TRIGGER_MAX];
|
||||
u8 dbg_dest_reg_num;
|
||||
u32 dbg_dump_mask;
|
||||
struct iwl_fw_dbg dbg;
|
||||
};
|
||||
|
||||
static inline const char *get_fw_dbg_mode_string(int mode)
|
||||
@ -280,7 +289,7 @@ static inline const char *get_fw_dbg_mode_string(int mode)
|
||||
static inline bool
|
||||
iwl_fw_dbg_conf_usniffer(const struct iwl_fw *fw, u8 id)
|
||||
{
|
||||
const struct iwl_fw_dbg_conf_tlv *conf_tlv = fw->dbg_conf_tlv[id];
|
||||
const struct iwl_fw_dbg_conf_tlv *conf_tlv = fw->dbg.conf_tlv[id];
|
||||
|
||||
if (!conf_tlv)
|
||||
return false;
|
||||
|
@ -71,6 +71,7 @@ struct iwl_fw_runtime_ops {
|
||||
int (*dump_start)(void *ctx);
|
||||
void (*dump_end)(void *ctx);
|
||||
bool (*fw_running)(void *ctx);
|
||||
int (*send_hcmd)(void *ctx, struct iwl_host_cmd *host_cmd);
|
||||
};
|
||||
|
||||
#define MAX_NUM_LMAC 2
|
||||
@ -88,6 +89,7 @@ struct iwl_fwrt_shared_mem_cfg {
|
||||
|
||||
enum iwl_fw_runtime_status {
|
||||
IWL_FWRT_STATUS_DUMPING = 0,
|
||||
IWL_FWRT_STATUS_WAIT_ALIVE,
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -168,12 +168,12 @@ static void iwl_dealloc_ucode(struct iwl_drv *drv)
|
||||
{
|
||||
int i;
|
||||
|
||||
kfree(drv->fw.dbg_dest_tlv);
|
||||
for (i = 0; i < ARRAY_SIZE(drv->fw.dbg_conf_tlv); i++)
|
||||
kfree(drv->fw.dbg_conf_tlv[i]);
|
||||
for (i = 0; i < ARRAY_SIZE(drv->fw.dbg_trigger_tlv); i++)
|
||||
kfree(drv->fw.dbg_trigger_tlv[i]);
|
||||
kfree(drv->fw.dbg_mem_tlv);
|
||||
kfree(drv->fw.dbg.dest_tlv);
|
||||
for (i = 0; i < ARRAY_SIZE(drv->fw.dbg.conf_tlv); i++)
|
||||
kfree(drv->fw.dbg.conf_tlv[i]);
|
||||
for (i = 0; i < ARRAY_SIZE(drv->fw.dbg.trigger_tlv); i++)
|
||||
kfree(drv->fw.dbg.trigger_tlv[i]);
|
||||
kfree(drv->fw.dbg.mem_tlv);
|
||||
kfree(drv->fw.iml);
|
||||
|
||||
for (i = 0; i < IWL_UCODE_TYPE_MAX; i++)
|
||||
@ -303,7 +303,7 @@ struct iwl_firmware_pieces {
|
||||
struct iwl_fw_dbg_trigger_tlv *dbg_trigger_tlv[FW_DBG_TRIGGER_MAX];
|
||||
size_t dbg_trigger_tlv_len[FW_DBG_TRIGGER_MAX];
|
||||
struct iwl_fw_dbg_mem_seg_tlv *dbg_mem_tlv;
|
||||
size_t n_dbg_mem_tlv;
|
||||
size_t n_mem_tlv;
|
||||
};
|
||||
|
||||
/*
|
||||
@ -936,7 +936,7 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
|
||||
IWL_INFO(drv, "Found debug destination: %s\n",
|
||||
get_fw_dbg_mode_string(mon_mode));
|
||||
|
||||
drv->fw.dbg_dest_reg_num = (dest_v1) ?
|
||||
drv->fw.dbg.n_dest_reg = (dest_v1) ?
|
||||
tlv_len -
|
||||
offsetof(struct iwl_fw_dbg_dest_tlv_v1,
|
||||
reg_ops) :
|
||||
@ -944,8 +944,8 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
|
||||
offsetof(struct iwl_fw_dbg_dest_tlv,
|
||||
reg_ops);
|
||||
|
||||
drv->fw.dbg_dest_reg_num /=
|
||||
sizeof(drv->fw.dbg_dest_tlv->reg_ops[0]);
|
||||
drv->fw.dbg.n_dest_reg /=
|
||||
sizeof(drv->fw.dbg.dest_tlv->reg_ops[0]);
|
||||
|
||||
break;
|
||||
}
|
||||
@ -959,7 +959,7 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
|
||||
break;
|
||||
}
|
||||
|
||||
if (conf->id >= ARRAY_SIZE(drv->fw.dbg_conf_tlv)) {
|
||||
if (conf->id >= ARRAY_SIZE(drv->fw.dbg.conf_tlv)) {
|
||||
IWL_ERR(drv,
|
||||
"Skip unknown configuration: %d\n",
|
||||
conf->id);
|
||||
@ -988,7 +988,7 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
|
||||
(void *)tlv_data;
|
||||
u32 trigger_id = le32_to_cpu(trigger->id);
|
||||
|
||||
if (trigger_id >= ARRAY_SIZE(drv->fw.dbg_trigger_tlv)) {
|
||||
if (trigger_id >= ARRAY_SIZE(drv->fw.dbg.trigger_tlv)) {
|
||||
IWL_ERR(drv,
|
||||
"Skip unknown trigger: %u\n",
|
||||
trigger->id);
|
||||
@ -1015,7 +1015,7 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
|
||||
break;
|
||||
}
|
||||
|
||||
drv->fw.dbg_dump_mask =
|
||||
drv->fw.dbg.dump_mask =
|
||||
le32_to_cpup((__le32 *)tlv_data);
|
||||
break;
|
||||
}
|
||||
@ -1070,13 +1070,13 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
|
||||
dbg_mem->data_type);
|
||||
|
||||
size = sizeof(*pieces->dbg_mem_tlv) *
|
||||
(pieces->n_dbg_mem_tlv + 1);
|
||||
(pieces->n_mem_tlv + 1);
|
||||
n = krealloc(pieces->dbg_mem_tlv, size, GFP_KERNEL);
|
||||
if (!n)
|
||||
return -ENOMEM;
|
||||
pieces->dbg_mem_tlv = n;
|
||||
pieces->dbg_mem_tlv[pieces->n_dbg_mem_tlv] = *dbg_mem;
|
||||
pieces->n_dbg_mem_tlv++;
|
||||
pieces->dbg_mem_tlv[pieces->n_mem_tlv] = *dbg_mem;
|
||||
pieces->n_mem_tlv++;
|
||||
break;
|
||||
}
|
||||
case IWL_UCODE_TLV_IML: {
|
||||
@ -1256,7 +1256,7 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context)
|
||||
IWL_DEFAULT_STANDARD_PHY_CALIBRATE_TBL_SIZE;
|
||||
fw->ucode_capa.n_scan_channels = IWL_DEFAULT_SCAN_CHANNELS;
|
||||
/* dump all fw memory areas by default except d3 debug data */
|
||||
fw->dbg_dump_mask = 0xfffdffff;
|
||||
fw->dbg.dump_mask = 0xfffdffff;
|
||||
|
||||
pieces = kzalloc(sizeof(*pieces), GFP_KERNEL);
|
||||
if (!pieces)
|
||||
@ -1323,21 +1323,21 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context)
|
||||
goto out_free_fw;
|
||||
|
||||
if (pieces->dbg_dest_tlv_init) {
|
||||
size_t dbg_dest_size = sizeof(*drv->fw.dbg_dest_tlv) +
|
||||
sizeof(drv->fw.dbg_dest_tlv->reg_ops[0]) *
|
||||
drv->fw.dbg_dest_reg_num;
|
||||
size_t dbg_dest_size = sizeof(*drv->fw.dbg.dest_tlv) +
|
||||
sizeof(drv->fw.dbg.dest_tlv->reg_ops[0]) *
|
||||
drv->fw.dbg.n_dest_reg;
|
||||
|
||||
drv->fw.dbg_dest_tlv = kmalloc(dbg_dest_size, GFP_KERNEL);
|
||||
drv->fw.dbg.dest_tlv = kmalloc(dbg_dest_size, GFP_KERNEL);
|
||||
|
||||
if (!drv->fw.dbg_dest_tlv)
|
||||
if (!drv->fw.dbg.dest_tlv)
|
||||
goto out_free_fw;
|
||||
|
||||
if (*pieces->dbg_dest_ver == 0) {
|
||||
memcpy(drv->fw.dbg_dest_tlv, pieces->dbg_dest_tlv_v1,
|
||||
memcpy(drv->fw.dbg.dest_tlv, pieces->dbg_dest_tlv_v1,
|
||||
dbg_dest_size);
|
||||
} else {
|
||||
struct iwl_fw_dbg_dest_tlv_v1 *dest_tlv =
|
||||
drv->fw.dbg_dest_tlv;
|
||||
drv->fw.dbg.dest_tlv;
|
||||
|
||||
dest_tlv->version = pieces->dbg_dest_tlv->version;
|
||||
dest_tlv->monitor_mode =
|
||||
@ -1352,8 +1352,8 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context)
|
||||
pieces->dbg_dest_tlv->base_shift;
|
||||
memcpy(dest_tlv->reg_ops,
|
||||
pieces->dbg_dest_tlv->reg_ops,
|
||||
sizeof(drv->fw.dbg_dest_tlv->reg_ops[0]) *
|
||||
drv->fw.dbg_dest_reg_num);
|
||||
sizeof(drv->fw.dbg.dest_tlv->reg_ops[0]) *
|
||||
drv->fw.dbg.n_dest_reg);
|
||||
|
||||
/* In version 1 of the destination tlv, which is
|
||||
* relevant for internal buffer exclusively,
|
||||
@ -1369,15 +1369,13 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context)
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(drv->fw.dbg_conf_tlv); i++) {
|
||||
for (i = 0; i < ARRAY_SIZE(drv->fw.dbg.conf_tlv); i++) {
|
||||
if (pieces->dbg_conf_tlv[i]) {
|
||||
drv->fw.dbg_conf_tlv_len[i] =
|
||||
pieces->dbg_conf_tlv_len[i];
|
||||
drv->fw.dbg_conf_tlv[i] =
|
||||
drv->fw.dbg.conf_tlv[i] =
|
||||
kmemdup(pieces->dbg_conf_tlv[i],
|
||||
drv->fw.dbg_conf_tlv_len[i],
|
||||
pieces->dbg_conf_tlv_len[i],
|
||||
GFP_KERNEL);
|
||||
if (!drv->fw.dbg_conf_tlv[i])
|
||||
if (!pieces->dbg_conf_tlv_len[i])
|
||||
goto out_free_fw;
|
||||
}
|
||||
}
|
||||
@ -1404,7 +1402,7 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context)
|
||||
trigger_tlv_sz[FW_DBG_TRIGGER_TDLS] =
|
||||
sizeof(struct iwl_fw_dbg_trigger_tdls);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(drv->fw.dbg_trigger_tlv); i++) {
|
||||
for (i = 0; i < ARRAY_SIZE(drv->fw.dbg.trigger_tlv); i++) {
|
||||
if (pieces->dbg_trigger_tlv[i]) {
|
||||
/*
|
||||
* If the trigger isn't long enough, WARN and exit.
|
||||
@ -1417,22 +1415,22 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context)
|
||||
(trigger_tlv_sz[i] +
|
||||
sizeof(struct iwl_fw_dbg_trigger_tlv))))
|
||||
goto out_free_fw;
|
||||
drv->fw.dbg_trigger_tlv_len[i] =
|
||||
drv->fw.dbg.trigger_tlv_len[i] =
|
||||
pieces->dbg_trigger_tlv_len[i];
|
||||
drv->fw.dbg_trigger_tlv[i] =
|
||||
drv->fw.dbg.trigger_tlv[i] =
|
||||
kmemdup(pieces->dbg_trigger_tlv[i],
|
||||
drv->fw.dbg_trigger_tlv_len[i],
|
||||
drv->fw.dbg.trigger_tlv_len[i],
|
||||
GFP_KERNEL);
|
||||
if (!drv->fw.dbg_trigger_tlv[i])
|
||||
if (!drv->fw.dbg.trigger_tlv[i])
|
||||
goto out_free_fw;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now that we can no longer fail, copy information */
|
||||
|
||||
drv->fw.dbg_mem_tlv = pieces->dbg_mem_tlv;
|
||||
drv->fw.dbg.mem_tlv = pieces->dbg_mem_tlv;
|
||||
pieces->dbg_mem_tlv = NULL;
|
||||
drv->fw.n_dbg_mem_tlv = pieces->n_dbg_mem_tlv;
|
||||
drv->fw.dbg.n_mem_tlv = pieces->n_mem_tlv;
|
||||
|
||||
/*
|
||||
* The (size - 16) / 12 formula is based on the information recorded
|
||||
@ -1473,6 +1471,7 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context)
|
||||
break;
|
||||
default:
|
||||
WARN(1, "Invalid fw type %d\n", fw->type);
|
||||
/* fall through */
|
||||
case IWL_FW_MVM:
|
||||
op = &iwlwifi_opmode_table[MVM_OP_MODE];
|
||||
break;
|
||||
|
@ -1335,6 +1335,7 @@ struct iwl_nvm_data *iwl_get_nvm(struct iwl_trans *trans,
|
||||
bool lar_fw_supported = !iwlwifi_mod_params.lar_disable &&
|
||||
fw_has_capa(&fw->ucode_capa,
|
||||
IWL_UCODE_TLV_CAPA_LAR_SUPPORT);
|
||||
bool empty_otp;
|
||||
u32 mac_flags;
|
||||
u32 sbands_flags = 0;
|
||||
|
||||
@ -1350,7 +1351,9 @@ struct iwl_nvm_data *iwl_get_nvm(struct iwl_trans *trans,
|
||||
}
|
||||
|
||||
rsp = (void *)hcmd.resp_pkt->data;
|
||||
if (le32_to_cpu(rsp->general.flags) & NVM_GENERAL_FLAGS_EMPTY_OTP)
|
||||
empty_otp = !!(le32_to_cpu(rsp->general.flags) &
|
||||
NVM_GENERAL_FLAGS_EMPTY_OTP);
|
||||
if (empty_otp)
|
||||
IWL_INFO(trans, "OTP is empty\n");
|
||||
|
||||
nvm = kzalloc(sizeof(*nvm) +
|
||||
@ -1374,6 +1377,11 @@ struct iwl_nvm_data *iwl_get_nvm(struct iwl_trans *trans,
|
||||
|
||||
/* Initialize general data */
|
||||
nvm->nvm_version = le16_to_cpu(rsp->general.nvm_version);
|
||||
nvm->n_hw_addrs = rsp->general.n_hw_addrs;
|
||||
if (nvm->n_hw_addrs == 0)
|
||||
IWL_WARN(trans,
|
||||
"Firmware declares no reserved mac addresses. OTP is empty: %d\n",
|
||||
empty_otp);
|
||||
|
||||
/* Initialize MAC sku data */
|
||||
mac_flags = le32_to_cpu(rsp->mac_sku.mac_sku_flags);
|
||||
|
@ -725,7 +725,7 @@ struct iwl_dram_data {
|
||||
* @dbg_dest_tlv: points to the destination TLV for debug
|
||||
* @dbg_conf_tlv: array of pointers to configuration TLVs for debug
|
||||
* @dbg_trigger_tlv: array of pointers to triggers TLVs for debug
|
||||
* @dbg_dest_reg_num: num of reg_ops in %dbg_dest_tlv
|
||||
* @dbg_n_dest_reg: num of reg_ops in %dbg_dest_tlv
|
||||
* @num_blocks: number of blocks in fw_mon
|
||||
* @fw_mon: address of the buffers for firmware monitor
|
||||
* @system_pm_mode: the system-wide power management mode in use.
|
||||
@ -778,7 +778,7 @@ struct iwl_trans {
|
||||
const struct iwl_fw_dbg_conf_tlv *dbg_conf_tlv[FW_DBG_CONF_MAX];
|
||||
struct iwl_fw_dbg_trigger_tlv * const *dbg_trigger_tlv;
|
||||
u32 dbg_dump_mask;
|
||||
u8 dbg_dest_reg_num;
|
||||
u8 dbg_n_dest_reg;
|
||||
int num_blocks;
|
||||
struct iwl_dram_data fw_mon[IWL_MAX_DEBUG_ALLOCATIONS];
|
||||
|
||||
|
@ -666,16 +666,11 @@ iwl_dbgfs_bt_force_ant_write(struct iwl_mvm *mvm, char *buf,
|
||||
};
|
||||
int ret, bt_force_ant_mode;
|
||||
|
||||
for (bt_force_ant_mode = 0;
|
||||
bt_force_ant_mode < ARRAY_SIZE(modes_str);
|
||||
bt_force_ant_mode++) {
|
||||
if (!strcmp(buf, modes_str[bt_force_ant_mode]))
|
||||
break;
|
||||
}
|
||||
|
||||
if (bt_force_ant_mode >= ARRAY_SIZE(modes_str))
|
||||
return -EINVAL;
|
||||
ret = match_string(modes_str, ARRAY_SIZE(modes_str), buf);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
bt_force_ant_mode = ret;
|
||||
ret = 0;
|
||||
mutex_lock(&mvm->mutex);
|
||||
if (mvm->bt_force_ant_mode == bt_force_ant_mode)
|
||||
|
@ -299,6 +299,7 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm,
|
||||
enum iwl_ucode_type old_type = mvm->fwrt.cur_fw_img;
|
||||
static const u16 alive_cmd[] = { MVM_ALIVE };
|
||||
|
||||
set_bit(IWL_FWRT_STATUS_WAIT_ALIVE, &mvm->fwrt.status);
|
||||
if (ucode_type == IWL_UCODE_REGULAR &&
|
||||
iwl_fw_dbg_conf_usniffer(mvm->fw, FW_DBG_START_FROM_ALIVE) &&
|
||||
!(fw_has_capa(&mvm->fw->ucode_capa,
|
||||
@ -369,6 +370,7 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm,
|
||||
atomic_set(&mvm->mac80211_queue_stop_count[i], 0);
|
||||
|
||||
set_bit(IWL_MVM_STATUS_FIRMWARE_RUNNING, &mvm->status);
|
||||
clear_bit(IWL_FWRT_STATUS_WAIT_ALIVE, &mvm->fwrt.status);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -699,8 +701,12 @@ static int iwl_mvm_sar_get_ewrd_table(struct iwl_mvm *mvm)
|
||||
enabled = !!(wifi_pkg->package.elements[1].integer.value);
|
||||
n_profiles = wifi_pkg->package.elements[2].integer.value;
|
||||
|
||||
/* in case of BIOS bug */
|
||||
if (n_profiles <= 0) {
|
||||
/*
|
||||
* Check the validity of n_profiles. The EWRD profiles start
|
||||
* from index 1, so the maximum value allowed here is
|
||||
* ACPI_SAR_PROFILES_NUM - 1.
|
||||
*/
|
||||
if (n_profiles <= 0 || n_profiles >= ACPI_SAR_PROFILE_NUM) {
|
||||
ret = -EINVAL;
|
||||
goto out_free;
|
||||
}
|
||||
@ -1022,7 +1028,7 @@ int iwl_mvm_up(struct iwl_mvm *mvm)
|
||||
|
||||
mvm->fwrt.dump.conf = FW_DBG_INVALID;
|
||||
/* if we have a destination, assume EARLY START */
|
||||
if (mvm->fw->dbg_dest_tlv)
|
||||
if (mvm->fw->dbg.dest_tlv)
|
||||
mvm->fwrt.dump.conf = FW_DBG_START_FROM_ALIVE;
|
||||
iwl_fw_start_dbg_conf(&mvm->fwrt, FW_DBG_START_FROM_ALIVE);
|
||||
|
||||
|
@ -1487,12 +1487,11 @@ static void iwl_mvm_beacon_loss_iterator(void *_data, u8 *mac,
|
||||
IWL_MVM_MISSED_BEACONS_THRESHOLD)
|
||||
ieee80211_beacon_loss(vif);
|
||||
|
||||
if (!iwl_fw_dbg_trigger_enabled(mvm->fw,
|
||||
FW_DBG_TRIGGER_MISSED_BEACONS))
|
||||
trigger = iwl_fw_dbg_trigger_on(&mvm->fwrt, ieee80211_vif_to_wdev(vif),
|
||||
FW_DBG_TRIGGER_MISSED_BEACONS);
|
||||
if (!trigger)
|
||||
return;
|
||||
|
||||
trigger = iwl_fw_dbg_get_trigger(mvm->fw,
|
||||
FW_DBG_TRIGGER_MISSED_BEACONS);
|
||||
bcon_trig = (void *)trigger->data;
|
||||
stop_trig_missed_bcon = le32_to_cpu(bcon_trig->stop_consec_missed_bcon);
|
||||
stop_trig_missed_bcon_since_rx =
|
||||
@ -1500,11 +1499,6 @@ static void iwl_mvm_beacon_loss_iterator(void *_data, u8 *mac,
|
||||
|
||||
/* TODO: implement start trigger */
|
||||
|
||||
if (!iwl_fw_dbg_trigger_check_stop(&mvm->fwrt,
|
||||
ieee80211_vif_to_wdev(vif),
|
||||
trigger))
|
||||
return;
|
||||
|
||||
if (rx_missed_bcon_since_rx >= stop_trig_missed_bcon_since_rx ||
|
||||
rx_missed_bcon >= stop_trig_missed_bcon)
|
||||
iwl_fw_dbg_collect_trig(&mvm->fwrt, trigger, NULL);
|
||||
|
@ -857,16 +857,13 @@ iwl_mvm_ampdu_check_trigger(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
|
||||
struct iwl_fw_dbg_trigger_tlv *trig;
|
||||
struct iwl_fw_dbg_trigger_ba *ba_trig;
|
||||
|
||||
if (!iwl_fw_dbg_trigger_enabled(mvm->fw, FW_DBG_TRIGGER_BA))
|
||||
trig = iwl_fw_dbg_trigger_on(&mvm->fwrt, ieee80211_vif_to_wdev(vif),
|
||||
FW_DBG_TRIGGER_BA);
|
||||
if (!trig)
|
||||
return;
|
||||
|
||||
trig = iwl_fw_dbg_get_trigger(mvm->fw, FW_DBG_TRIGGER_BA);
|
||||
ba_trig = (void *)trig->data;
|
||||
|
||||
if (!iwl_fw_dbg_trigger_check_stop(&mvm->fwrt,
|
||||
ieee80211_vif_to_wdev(vif), trig))
|
||||
return;
|
||||
|
||||
switch (action) {
|
||||
case IEEE80211_AMPDU_TX_OPERATIONAL: {
|
||||
struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
|
||||
@ -1231,12 +1228,15 @@ void __iwl_mvm_mac_stop(struct iwl_mvm *mvm)
|
||||
iwl_mvm_del_aux_sta(mvm);
|
||||
|
||||
/*
|
||||
* Clear IN_HW_RESTART flag when stopping the hw (as restart_complete()
|
||||
* won't be called in this case).
|
||||
* Clear IN_HW_RESTART and HW_RESTART_REQUESTED flag when stopping the
|
||||
* hw (as restart_complete() won't be called in this case) and mac80211
|
||||
* won't execute the restart.
|
||||
* But make sure to cleanup interfaces that have gone down before/during
|
||||
* HW restart was requested.
|
||||
*/
|
||||
if (test_and_clear_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status))
|
||||
if (test_and_clear_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status) ||
|
||||
test_and_clear_bit(IWL_MVM_STATUS_HW_RESTART_REQUESTED,
|
||||
&mvm->status))
|
||||
ieee80211_iterate_interfaces(mvm->hw, 0,
|
||||
iwl_mvm_cleanup_iterator, mvm);
|
||||
|
||||
@ -2802,14 +2802,12 @@ iwl_mvm_tdls_check_trigger(struct iwl_mvm *mvm,
|
||||
struct iwl_fw_dbg_trigger_tlv *trig;
|
||||
struct iwl_fw_dbg_trigger_tdls *tdls_trig;
|
||||
|
||||
if (!iwl_fw_dbg_trigger_enabled(mvm->fw, FW_DBG_TRIGGER_TDLS))
|
||||
trig = iwl_fw_dbg_trigger_on(&mvm->fwrt, ieee80211_vif_to_wdev(vif),
|
||||
FW_DBG_TRIGGER_TDLS);
|
||||
if (!trig)
|
||||
return;
|
||||
|
||||
trig = iwl_fw_dbg_get_trigger(mvm->fw, FW_DBG_TRIGGER_TDLS);
|
||||
tdls_trig = (void *)trig->data;
|
||||
if (!iwl_fw_dbg_trigger_check_stop(&mvm->fwrt,
|
||||
ieee80211_vif_to_wdev(vif), trig))
|
||||
return;
|
||||
|
||||
if (!(tdls_trig->action_bitmap & BIT(action)))
|
||||
return;
|
||||
@ -4491,14 +4489,12 @@ static void iwl_mvm_event_mlme_callback(struct iwl_mvm *mvm,
|
||||
struct iwl_fw_dbg_trigger_tlv *trig;
|
||||
struct iwl_fw_dbg_trigger_mlme *trig_mlme;
|
||||
|
||||
if (!iwl_fw_dbg_trigger_enabled(mvm->fw, FW_DBG_TRIGGER_MLME))
|
||||
trig = iwl_fw_dbg_trigger_on(&mvm->fwrt, ieee80211_vif_to_wdev(vif),
|
||||
FW_DBG_TRIGGER_MLME);
|
||||
if (!trig)
|
||||
return;
|
||||
|
||||
trig = iwl_fw_dbg_get_trigger(mvm->fw, FW_DBG_TRIGGER_MLME);
|
||||
trig_mlme = (void *)trig->data;
|
||||
if (!iwl_fw_dbg_trigger_check_stop(&mvm->fwrt,
|
||||
ieee80211_vif_to_wdev(vif), trig))
|
||||
return;
|
||||
|
||||
if (event->u.mlme.data == ASSOC_EVENT) {
|
||||
if (event->u.mlme.status == MLME_DENIED)
|
||||
@ -4533,14 +4529,12 @@ static void iwl_mvm_event_bar_rx_callback(struct iwl_mvm *mvm,
|
||||
struct iwl_fw_dbg_trigger_tlv *trig;
|
||||
struct iwl_fw_dbg_trigger_ba *ba_trig;
|
||||
|
||||
if (!iwl_fw_dbg_trigger_enabled(mvm->fw, FW_DBG_TRIGGER_BA))
|
||||
trig = iwl_fw_dbg_trigger_on(&mvm->fwrt, ieee80211_vif_to_wdev(vif),
|
||||
FW_DBG_TRIGGER_BA);
|
||||
if (!trig)
|
||||
return;
|
||||
|
||||
trig = iwl_fw_dbg_get_trigger(mvm->fw, FW_DBG_TRIGGER_BA);
|
||||
ba_trig = (void *)trig->data;
|
||||
if (!iwl_fw_dbg_trigger_check_stop(&mvm->fwrt,
|
||||
ieee80211_vif_to_wdev(vif), trig))
|
||||
return;
|
||||
|
||||
if (!(le16_to_cpu(ba_trig->rx_bar) & BIT(event->u.ba.tid)))
|
||||
return;
|
||||
|
@ -477,15 +477,11 @@ iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2,
|
||||
u32 status;
|
||||
int resp_len, n_channels;
|
||||
u16 mcc;
|
||||
bool resp_v2 = fw_has_capa(&mvm->fw->ucode_capa,
|
||||
IWL_UCODE_TLV_CAPA_LAR_SUPPORT_V2);
|
||||
|
||||
if (WARN_ON_ONCE(!iwl_mvm_is_lar_supported(mvm)))
|
||||
return ERR_PTR(-EOPNOTSUPP);
|
||||
|
||||
cmd.len[0] = sizeof(struct iwl_mcc_update_cmd);
|
||||
if (!resp_v2)
|
||||
cmd.len[0] = sizeof(struct iwl_mcc_update_cmd_v1);
|
||||
|
||||
IWL_DEBUG_LAR(mvm, "send MCC update to FW with '%c%c' src = %d\n",
|
||||
alpha2[0], alpha2[1], src_id);
|
||||
@ -497,7 +493,8 @@ iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2,
|
||||
pkt = cmd.resp_pkt;
|
||||
|
||||
/* Extract MCC response */
|
||||
if (resp_v2) {
|
||||
if (fw_has_capa(&mvm->fw->ucode_capa,
|
||||
IWL_UCODE_TLV_CAPA_MCC_UPDATE_11AX_SUPPORT)) {
|
||||
struct iwl_mcc_update_resp *mcc_resp = (void *)pkt->data;
|
||||
|
||||
n_channels = __le32_to_cpu(mcc_resp->n_channels);
|
||||
@ -509,9 +506,9 @@ iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2,
|
||||
goto exit;
|
||||
}
|
||||
} else {
|
||||
struct iwl_mcc_update_resp_v1 *mcc_resp_v1 = (void *)pkt->data;
|
||||
struct iwl_mcc_update_resp_v3 *mcc_resp_v3 = (void *)pkt->data;
|
||||
|
||||
n_channels = __le32_to_cpu(mcc_resp_v1->n_channels);
|
||||
n_channels = __le32_to_cpu(mcc_resp_v3->n_channels);
|
||||
resp_len = sizeof(struct iwl_mcc_update_resp) +
|
||||
n_channels * sizeof(__le32);
|
||||
resp_cp = kzalloc(resp_len, GFP_KERNEL);
|
||||
@ -520,12 +517,14 @@ iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2,
|
||||
goto exit;
|
||||
}
|
||||
|
||||
resp_cp->status = mcc_resp_v1->status;
|
||||
resp_cp->mcc = mcc_resp_v1->mcc;
|
||||
resp_cp->cap = mcc_resp_v1->cap;
|
||||
resp_cp->source_id = mcc_resp_v1->source_id;
|
||||
resp_cp->n_channels = mcc_resp_v1->n_channels;
|
||||
memcpy(resp_cp->channels, mcc_resp_v1->channels,
|
||||
resp_cp->status = mcc_resp_v3->status;
|
||||
resp_cp->mcc = mcc_resp_v3->mcc;
|
||||
resp_cp->cap = cpu_to_le16(mcc_resp_v3->cap);
|
||||
resp_cp->source_id = mcc_resp_v3->source_id;
|
||||
resp_cp->time = mcc_resp_v3->time;
|
||||
resp_cp->geo_info = mcc_resp_v3->geo_info;
|
||||
resp_cp->n_channels = mcc_resp_v3->n_channels;
|
||||
memcpy(resp_cp->channels, mcc_resp_v3->channels,
|
||||
n_channels * sizeof(__le32));
|
||||
}
|
||||
|
||||
|
@ -565,10 +565,23 @@ static bool iwl_mvm_fwrt_fw_running(void *ctx)
|
||||
return iwl_mvm_firmware_running(ctx);
|
||||
}
|
||||
|
||||
static int iwl_mvm_fwrt_send_hcmd(void *ctx, struct iwl_host_cmd *host_cmd)
|
||||
{
|
||||
struct iwl_mvm *mvm = (struct iwl_mvm *)ctx;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&mvm->mutex);
|
||||
ret = iwl_mvm_send_cmd(mvm, host_cmd);
|
||||
mutex_unlock(&mvm->mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct iwl_fw_runtime_ops iwl_mvm_fwrt_ops = {
|
||||
.dump_start = iwl_mvm_fwrt_dump_start,
|
||||
.dump_end = iwl_mvm_fwrt_dump_end,
|
||||
.fw_running = iwl_mvm_fwrt_fw_running,
|
||||
.send_hcmd = iwl_mvm_fwrt_send_hcmd,
|
||||
};
|
||||
|
||||
static struct iwl_op_mode *
|
||||
@ -604,9 +617,13 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
|
||||
|
||||
if (cfg->max_rx_agg_size)
|
||||
hw->max_rx_aggregation_subframes = cfg->max_rx_agg_size;
|
||||
else
|
||||
hw->max_rx_aggregation_subframes = IEEE80211_MAX_AMPDU_BUF;
|
||||
|
||||
if (cfg->max_tx_agg_size)
|
||||
hw->max_tx_aggregation_subframes = cfg->max_tx_agg_size;
|
||||
else
|
||||
hw->max_tx_aggregation_subframes = IEEE80211_MAX_AMPDU_BUF;
|
||||
|
||||
op_mode = hw->priv;
|
||||
|
||||
@ -748,12 +765,12 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
|
||||
iwl_trans_configure(mvm->trans, &trans_cfg);
|
||||
|
||||
trans->rx_mpdu_cmd = REPLY_RX_MPDU_CMD;
|
||||
trans->dbg_dest_tlv = mvm->fw->dbg_dest_tlv;
|
||||
trans->dbg_dest_reg_num = mvm->fw->dbg_dest_reg_num;
|
||||
memcpy(trans->dbg_conf_tlv, mvm->fw->dbg_conf_tlv,
|
||||
trans->dbg_dest_tlv = mvm->fw->dbg.dest_tlv;
|
||||
trans->dbg_n_dest_reg = mvm->fw->dbg.n_dest_reg;
|
||||
memcpy(trans->dbg_conf_tlv, mvm->fw->dbg.conf_tlv,
|
||||
sizeof(trans->dbg_conf_tlv));
|
||||
trans->dbg_trigger_tlv = mvm->fw->dbg_trigger_tlv;
|
||||
trans->dbg_dump_mask = mvm->fw->dbg_dump_mask;
|
||||
trans->dbg_trigger_tlv = mvm->fw->dbg.trigger_tlv;
|
||||
trans->dbg_dump_mask = mvm->fw->dbg.dump_mask;
|
||||
|
||||
trans->iml = mvm->fw->iml;
|
||||
trans->iml_len = mvm->fw->iml_len;
|
||||
@ -784,6 +801,8 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
|
||||
mutex_lock(&mvm->mutex);
|
||||
iwl_mvm_ref(mvm, IWL_MVM_REF_INIT_UCODE);
|
||||
err = iwl_run_init_mvm_ucode(mvm, true);
|
||||
if (test_bit(IWL_FWRT_STATUS_WAIT_ALIVE, &mvm->fwrt.status))
|
||||
iwl_fw_alive_error_dump(&mvm->fwrt);
|
||||
if (!iwlmvm_mod_params.init_dbg || !err)
|
||||
iwl_mvm_stop_device(mvm);
|
||||
iwl_mvm_unref(mvm, IWL_MVM_REF_INIT_UCODE);
|
||||
@ -953,15 +972,13 @@ static inline void iwl_mvm_rx_check_trigger(struct iwl_mvm *mvm,
|
||||
struct iwl_fw_dbg_trigger_cmd *cmds_trig;
|
||||
int i;
|
||||
|
||||
if (!iwl_fw_dbg_trigger_enabled(mvm->fw, FW_DBG_TRIGGER_FW_NOTIF))
|
||||
trig = iwl_fw_dbg_trigger_on(&mvm->fwrt, NULL,
|
||||
FW_DBG_TRIGGER_FW_NOTIF);
|
||||
if (!trig)
|
||||
return;
|
||||
|
||||
trig = iwl_fw_dbg_get_trigger(mvm->fw, FW_DBG_TRIGGER_FW_NOTIF);
|
||||
cmds_trig = (void *)trig->data;
|
||||
|
||||
if (!iwl_fw_dbg_trigger_check_stop(&mvm->fwrt, NULL, trig))
|
||||
return;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(cmds_trig->cmds); i++) {
|
||||
/* don't collect on CMD 0 */
|
||||
if (!cmds_trig->cmds[i].cmd_id)
|
||||
@ -1223,7 +1240,7 @@ void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error)
|
||||
*/
|
||||
if (!mvm->fw_restart && fw_error) {
|
||||
iwl_fw_dbg_collect_desc(&mvm->fwrt, &iwl_dump_desc_assert,
|
||||
NULL);
|
||||
NULL, 0);
|
||||
} else if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) {
|
||||
struct iwl_mvm_reprobe *reprobe;
|
||||
|
||||
|
@ -433,13 +433,14 @@ void iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct napi_struct *napi,
|
||||
struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
|
||||
struct ieee80211_vif *tx_blocked_vif =
|
||||
rcu_dereference(mvm->csa_tx_blocked_vif);
|
||||
struct iwl_fw_dbg_trigger_tlv *trig;
|
||||
struct ieee80211_vif *vif = mvmsta->vif;
|
||||
|
||||
/* We have tx blocked stations (with CS bit). If we heard
|
||||
* frames from a blocked station on a new channel we can
|
||||
* TX to it again.
|
||||
*/
|
||||
if (unlikely(tx_blocked_vif) &&
|
||||
mvmsta->vif == tx_blocked_vif) {
|
||||
if (unlikely(tx_blocked_vif) && vif == tx_blocked_vif) {
|
||||
struct iwl_mvm_vif *mvmvif =
|
||||
iwl_mvm_vif_from_mac80211(tx_blocked_vif);
|
||||
|
||||
@ -450,23 +451,18 @@ void iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct napi_struct *napi,
|
||||
|
||||
rs_update_last_rssi(mvm, mvmsta, rx_status);
|
||||
|
||||
if (iwl_fw_dbg_trigger_enabled(mvm->fw, FW_DBG_TRIGGER_RSSI) &&
|
||||
ieee80211_is_beacon(hdr->frame_control)) {
|
||||
struct iwl_fw_dbg_trigger_tlv *trig;
|
||||
trig = iwl_fw_dbg_trigger_on(&mvm->fwrt,
|
||||
ieee80211_vif_to_wdev(vif),
|
||||
FW_DBG_TRIGGER_RSSI);
|
||||
|
||||
if (trig && ieee80211_is_beacon(hdr->frame_control)) {
|
||||
struct iwl_fw_dbg_trigger_low_rssi *rssi_trig;
|
||||
bool trig_check;
|
||||
s32 rssi;
|
||||
|
||||
trig = iwl_fw_dbg_get_trigger(mvm->fw,
|
||||
FW_DBG_TRIGGER_RSSI);
|
||||
rssi_trig = (void *)trig->data;
|
||||
rssi = le32_to_cpu(rssi_trig->rssi);
|
||||
|
||||
trig_check =
|
||||
iwl_fw_dbg_trigger_check_stop(&mvm->fwrt,
|
||||
ieee80211_vif_to_wdev(mvmsta->vif),
|
||||
trig);
|
||||
if (trig_check && rx_status->signal < rssi)
|
||||
if (rx_status->signal < rssi)
|
||||
iwl_fw_dbg_collect_trig(&mvm->fwrt, trig,
|
||||
NULL);
|
||||
}
|
||||
@ -693,15 +689,12 @@ iwl_mvm_rx_stats_check_trigger(struct iwl_mvm *mvm, struct iwl_rx_packet *pkt)
|
||||
struct iwl_fw_dbg_trigger_stats *trig_stats;
|
||||
u32 trig_offset, trig_thold;
|
||||
|
||||
if (!iwl_fw_dbg_trigger_enabled(mvm->fw, FW_DBG_TRIGGER_STATS))
|
||||
trig = iwl_fw_dbg_trigger_on(&mvm->fwrt, NULL, FW_DBG_TRIGGER_STATS);
|
||||
if (!trig)
|
||||
return;
|
||||
|
||||
trig = iwl_fw_dbg_get_trigger(mvm->fw, FW_DBG_TRIGGER_STATS);
|
||||
trig_stats = (void *)trig->data;
|
||||
|
||||
if (!iwl_fw_dbg_trigger_check_stop(&mvm->fwrt, NULL, trig))
|
||||
return;
|
||||
|
||||
trig_offset = le32_to_cpu(trig_stats->stop_offset);
|
||||
trig_thold = le32_to_cpu(trig_stats->stop_threshold);
|
||||
|
||||
|
@ -923,6 +923,185 @@ static void iwl_mvm_decode_he_sigb(struct iwl_mvm *mvm,
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
iwl_mvm_decode_he_phy_ru_alloc(u64 he_phy_data, u32 rate_n_flags,
|
||||
struct ieee80211_radiotap_he *he,
|
||||
struct ieee80211_radiotap_he_mu *he_mu,
|
||||
struct ieee80211_rx_status *rx_status)
|
||||
{
|
||||
/*
|
||||
* Unfortunately, we have to leave the mac80211 data
|
||||
* incorrect for the case that we receive an HE-MU
|
||||
* transmission and *don't* have the HE phy data (due
|
||||
* to the bits being used for TSF). This shouldn't
|
||||
* happen though as management frames where we need
|
||||
* the TSF/timers are not be transmitted in HE-MU.
|
||||
*/
|
||||
u8 ru = FIELD_GET(IWL_RX_HE_PHY_RU_ALLOC_MASK, he_phy_data);
|
||||
u8 offs = 0;
|
||||
|
||||
rx_status->bw = RATE_INFO_BW_HE_RU;
|
||||
|
||||
he->data1 |= cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA1_BW_RU_ALLOC_KNOWN);
|
||||
|
||||
switch (ru) {
|
||||
case 0 ... 36:
|
||||
rx_status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_26;
|
||||
offs = ru;
|
||||
break;
|
||||
case 37 ... 52:
|
||||
rx_status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_52;
|
||||
offs = ru - 37;
|
||||
break;
|
||||
case 53 ... 60:
|
||||
rx_status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_106;
|
||||
offs = ru - 53;
|
||||
break;
|
||||
case 61 ... 64:
|
||||
rx_status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_242;
|
||||
offs = ru - 61;
|
||||
break;
|
||||
case 65 ... 66:
|
||||
rx_status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_484;
|
||||
offs = ru - 65;
|
||||
break;
|
||||
case 67:
|
||||
rx_status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_996;
|
||||
break;
|
||||
case 68:
|
||||
rx_status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_2x996;
|
||||
break;
|
||||
}
|
||||
he->data2 |= le16_encode_bits(offs,
|
||||
IEEE80211_RADIOTAP_HE_DATA2_RU_OFFSET);
|
||||
he->data2 |= cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA2_PRISEC_80_KNOWN |
|
||||
IEEE80211_RADIOTAP_HE_DATA2_RU_OFFSET_KNOWN);
|
||||
if (he_phy_data & IWL_RX_HE_PHY_RU_ALLOC_SEC80)
|
||||
he->data2 |=
|
||||
cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA2_PRISEC_80_SEC);
|
||||
|
||||
if (he_mu) {
|
||||
#define CHECK_BW(bw) \
|
||||
BUILD_BUG_ON(IEEE80211_RADIOTAP_HE_MU_FLAGS2_BW_FROM_SIG_A_BW_ ## bw ## MHZ != \
|
||||
RATE_MCS_CHAN_WIDTH_##bw >> RATE_MCS_CHAN_WIDTH_POS)
|
||||
CHECK_BW(20);
|
||||
CHECK_BW(40);
|
||||
CHECK_BW(80);
|
||||
CHECK_BW(160);
|
||||
he_mu->flags2 |=
|
||||
le16_encode_bits(FIELD_GET(RATE_MCS_CHAN_WIDTH_MSK,
|
||||
rate_n_flags),
|
||||
IEEE80211_RADIOTAP_HE_MU_FLAGS2_BW_FROM_SIG_A_BW);
|
||||
}
|
||||
}
|
||||
|
||||
static void iwl_mvm_decode_he_phy_data(struct iwl_mvm *mvm,
|
||||
struct iwl_rx_mpdu_desc *desc,
|
||||
struct ieee80211_radiotap_he *he,
|
||||
struct ieee80211_radiotap_he_mu *he_mu,
|
||||
struct ieee80211_rx_status *rx_status,
|
||||
u64 he_phy_data, u32 rate_n_flags,
|
||||
int queue)
|
||||
{
|
||||
u32 he_type = rate_n_flags & RATE_MCS_HE_TYPE_MSK;
|
||||
bool sigb_data;
|
||||
u16 d1known = IEEE80211_RADIOTAP_HE_DATA1_LDPC_XSYMSEG_KNOWN |
|
||||
IEEE80211_RADIOTAP_HE_DATA1_UL_DL_KNOWN |
|
||||
IEEE80211_RADIOTAP_HE_DATA1_SPTL_REUSE_KNOWN |
|
||||
IEEE80211_RADIOTAP_HE_DATA1_DOPPLER_KNOWN |
|
||||
IEEE80211_RADIOTAP_HE_DATA1_BSS_COLOR_KNOWN;
|
||||
u16 d2known = IEEE80211_RADIOTAP_HE_DATA2_PRE_FEC_PAD_KNOWN |
|
||||
IEEE80211_RADIOTAP_HE_DATA2_PE_DISAMBIG_KNOWN |
|
||||
IEEE80211_RADIOTAP_HE_DATA2_TXOP_KNOWN;
|
||||
|
||||
he->data1 |= cpu_to_le16(d1known);
|
||||
he->data2 |= cpu_to_le16(d2known);
|
||||
he->data3 |= le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_BSS_COLOR_MASK,
|
||||
he_phy_data),
|
||||
IEEE80211_RADIOTAP_HE_DATA3_BSS_COLOR);
|
||||
he->data3 |= le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_UPLINK,
|
||||
he_phy_data),
|
||||
IEEE80211_RADIOTAP_HE_DATA3_UL_DL);
|
||||
he->data3 |= le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_LDPC_EXT_SYM,
|
||||
he_phy_data),
|
||||
IEEE80211_RADIOTAP_HE_DATA3_LDPC_XSYMSEG);
|
||||
he->data4 |= le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_SPATIAL_REUSE_MASK,
|
||||
he_phy_data),
|
||||
IEEE80211_RADIOTAP_HE_DATA4_SU_MU_SPTL_REUSE);
|
||||
he->data5 |= le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_PRE_FEC_PAD_MASK,
|
||||
he_phy_data),
|
||||
IEEE80211_RADIOTAP_HE_DATA5_PRE_FEC_PAD);
|
||||
he->data5 |= le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_PE_DISAMBIG,
|
||||
he_phy_data),
|
||||
IEEE80211_RADIOTAP_HE_DATA5_PE_DISAMBIG);
|
||||
he->data6 |= le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_TXOP_DUR_MASK,
|
||||
he_phy_data),
|
||||
IEEE80211_RADIOTAP_HE_DATA6_TXOP);
|
||||
he->data6 |= le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_DOPPLER,
|
||||
he_phy_data),
|
||||
IEEE80211_RADIOTAP_HE_DATA6_DOPPLER);
|
||||
|
||||
switch (he_type) {
|
||||
case RATE_MCS_HE_TYPE_MU:
|
||||
he_mu->flags1 |=
|
||||
le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_MU_SIGB_DCM,
|
||||
he_phy_data),
|
||||
IEEE80211_RADIOTAP_HE_MU_FLAGS1_SIG_B_DCM);
|
||||
he_mu->flags1 |=
|
||||
le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_MU_SIGB_MCS_MASK,
|
||||
he_phy_data),
|
||||
IEEE80211_RADIOTAP_HE_MU_FLAGS1_SIG_B_MCS);
|
||||
he_mu->flags2 |=
|
||||
le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_MU_SIBG_SYM_OR_USER_NUM_MASK,
|
||||
he_phy_data),
|
||||
IEEE80211_RADIOTAP_HE_MU_FLAGS2_SIG_B_SYMS_USERS);
|
||||
he_mu->flags2 |=
|
||||
le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_MU_SIGB_COMPRESSION,
|
||||
he_phy_data),
|
||||
IEEE80211_RADIOTAP_HE_MU_FLAGS2_SIG_B_COMP);
|
||||
he_mu->flags2 |=
|
||||
le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_MU_PREAMBLE_PUNC_TYPE_MASK,
|
||||
he_phy_data),
|
||||
IEEE80211_RADIOTAP_HE_MU_FLAGS2_PUNC_FROM_SIG_A_BW);
|
||||
|
||||
sigb_data = FIELD_GET(IWL_RX_HE_PHY_INFO_TYPE_MASK,
|
||||
he_phy_data) ==
|
||||
IWL_RX_HE_PHY_INFO_TYPE_MU_EXT_INFO;
|
||||
if (sigb_data)
|
||||
iwl_mvm_decode_he_sigb(mvm, desc, rate_n_flags, he_mu);
|
||||
/* fall through */
|
||||
case RATE_MCS_HE_TYPE_TRIG:
|
||||
he->data2 |=
|
||||
cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA2_NUM_LTF_SYMS_KNOWN);
|
||||
he->data5 |=
|
||||
le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_HE_LTF_NUM_MASK,
|
||||
he_phy_data),
|
||||
IEEE80211_RADIOTAP_HE_DATA5_NUM_LTF_SYMS);
|
||||
break;
|
||||
case RATE_MCS_HE_TYPE_SU:
|
||||
case RATE_MCS_HE_TYPE_EXT_SU:
|
||||
he->data1 |=
|
||||
cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA1_BEAM_CHANGE_KNOWN);
|
||||
he->data3 |=
|
||||
le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_BEAM_CHNG,
|
||||
he_phy_data),
|
||||
IEEE80211_RADIOTAP_HE_DATA3_BEAM_CHANGE);
|
||||
break;
|
||||
}
|
||||
|
||||
switch (FIELD_GET(IWL_RX_HE_PHY_INFO_TYPE_MASK, he_phy_data)) {
|
||||
case IWL_RX_HE_PHY_INFO_TYPE_MU:
|
||||
case IWL_RX_HE_PHY_INFO_TYPE_MU_EXT_INFO:
|
||||
case IWL_RX_HE_PHY_INFO_TYPE_TB:
|
||||
iwl_mvm_decode_he_phy_ru_alloc(he_phy_data, rate_n_flags,
|
||||
he, he_mu, rx_status);
|
||||
break;
|
||||
default:
|
||||
/* nothing */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void iwl_mvm_rx_he(struct iwl_mvm *mvm, struct sk_buff *skb,
|
||||
struct iwl_rx_mpdu_desc *desc,
|
||||
u32 rate_n_flags, u16 phy_info, int queue)
|
||||
@ -933,9 +1112,8 @@ static void iwl_mvm_rx_he(struct iwl_mvm *mvm, struct sk_buff *skb,
|
||||
u64 he_phy_data = HE_PHY_DATA_INVAL;
|
||||
struct ieee80211_radiotap_he *he = NULL;
|
||||
struct ieee80211_radiotap_he_mu *he_mu = NULL;
|
||||
u32 he_type = 0xffffffff;
|
||||
u32 he_type = rate_n_flags & RATE_MCS_HE_TYPE_MSK;
|
||||
u8 stbc, 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 |
|
||||
@ -953,25 +1131,19 @@ static void iwl_mvm_rx_he(struct iwl_mvm *mvm, struct sk_buff *skb,
|
||||
IEEE80211_RADIOTAP_HE_MU_FLAGS2_BW_FROM_SIG_A_BW_KNOWN),
|
||||
};
|
||||
unsigned int radiotap_len = 0;
|
||||
bool overload = phy_info & IWL_RX_MPDU_PHY_TSF_OVERLOAD;
|
||||
bool sigb_data = false;
|
||||
|
||||
he = skb_put_data(skb, &known, sizeof(known));
|
||||
radiotap_len += sizeof(known);
|
||||
rx_status->flag |= RX_FLAG_RADIOTAP_HE;
|
||||
|
||||
he_type = rate_n_flags & RATE_MCS_HE_TYPE_MSK;
|
||||
|
||||
if (phy_info & IWL_RX_MPDU_PHY_TSF_OVERLOAD) {
|
||||
if (mvm->trans->cfg->device_family >=
|
||||
IWL_DEVICE_FAMILY_22560)
|
||||
if (mvm->trans->cfg->device_family >= IWL_DEVICE_FAMILY_22560)
|
||||
he_phy_data = le64_to_cpu(desc->v3.he_phy_data);
|
||||
else
|
||||
he_phy_data = le64_to_cpu(desc->v1.he_phy_data);
|
||||
|
||||
if (he_type == RATE_MCS_HE_TYPE_MU) {
|
||||
he_mu = skb_put_data(skb, &mu_known,
|
||||
sizeof(mu_known));
|
||||
he_mu = skb_put_data(skb, &mu_known, sizeof(mu_known));
|
||||
radiotap_len += sizeof(mu_known);
|
||||
rx_status->flag |= RX_FLAG_RADIOTAP_HE_MU;
|
||||
}
|
||||
@ -980,59 +1152,20 @@ static void iwl_mvm_rx_he(struct iwl_mvm *mvm, struct sk_buff *skb,
|
||||
/* temporarily hide the radiotap data */
|
||||
__skb_pull(skb, radiotap_len);
|
||||
|
||||
if (overload && he_type == RATE_MCS_HE_TYPE_SU) {
|
||||
he->data1 |=
|
||||
cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA1_UL_DL_KNOWN);
|
||||
if (FIELD_GET(IWL_RX_HE_PHY_UPLINK, he_phy_data))
|
||||
he->data3 |=
|
||||
cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA3_UL_DL);
|
||||
|
||||
if (he_phy_data != HE_PHY_DATA_INVAL &&
|
||||
he_type == RATE_MCS_HE_TYPE_SU) {
|
||||
/* report the AMPDU-EOF bit on single frames */
|
||||
if (!queue && !(phy_info & IWL_RX_MPDU_PHY_AMPDU)) {
|
||||
rx_status->flag |= RX_FLAG_AMPDU_DETAILS;
|
||||
rx_status->flag |= RX_FLAG_AMPDU_EOF_BIT_KNOWN;
|
||||
if (FIELD_GET(IWL_RX_HE_PHY_DELIM_EOF, he_phy_data))
|
||||
rx_status->flag |= RX_FLAG_AMPDU_EOF_BIT;
|
||||
}
|
||||
} else if (overload && he_mu && he_phy_data != HE_PHY_DATA_INVAL) {
|
||||
he_mu->flags1 |=
|
||||
le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_MU_SIBG_SYM_OR_USER_NUM_MASK,
|
||||
he_phy_data),
|
||||
IEEE80211_RADIOTAP_HE_MU_FLAGS2_SIG_B_SYMS_USERS);
|
||||
he_mu->flags1 |=
|
||||
le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_MU_SIGB_DCM,
|
||||
he_phy_data),
|
||||
IEEE80211_RADIOTAP_HE_MU_FLAGS1_SIG_B_DCM);
|
||||
he_mu->flags1 |=
|
||||
le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_MU_SIGB_MCS_MASK,
|
||||
he_phy_data),
|
||||
IEEE80211_RADIOTAP_HE_MU_FLAGS1_SIG_B_MCS);
|
||||
he_mu->flags2 |=
|
||||
le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_MU_SIGB_COMPRESSION,
|
||||
he_phy_data),
|
||||
IEEE80211_RADIOTAP_HE_MU_FLAGS2_SIG_B_COMP);
|
||||
he_mu->flags2 |=
|
||||
le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_MU_PREAMBLE_PUNC_TYPE_MASK,
|
||||
he_phy_data),
|
||||
IEEE80211_RADIOTAP_HE_MU_FLAGS2_PUNC_FROM_SIG_A_BW);
|
||||
|
||||
sigb_data = FIELD_GET(IWL_RX_HE_PHY_INFO_TYPE_MASK,
|
||||
he_phy_data) ==
|
||||
IWL_RX_HE_PHY_INFO_TYPE_MU_EXT_INFO;
|
||||
if (sigb_data)
|
||||
iwl_mvm_decode_he_sigb(mvm, desc, rate_n_flags, he_mu);
|
||||
}
|
||||
if (he_phy_data != HE_PHY_DATA_INVAL &&
|
||||
(he_type == RATE_MCS_HE_TYPE_SU ||
|
||||
he_type == RATE_MCS_HE_TYPE_MU)) {
|
||||
u8 bss_color = FIELD_GET(IWL_RX_HE_PHY_BSS_COLOR_MASK,
|
||||
he_phy_data);
|
||||
|
||||
if (bss_color) {
|
||||
he->data1 |=
|
||||
cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA1_BSS_COLOR_KNOWN);
|
||||
he->data3 |= cpu_to_le16(bss_color);
|
||||
}
|
||||
}
|
||||
if (he_phy_data != HE_PHY_DATA_INVAL)
|
||||
iwl_mvm_decode_he_phy_data(mvm, desc, he, he_mu, rx_status,
|
||||
he_phy_data, rate_n_flags, queue);
|
||||
|
||||
/* update aggregation data for monitor sake on default queue */
|
||||
if (!queue && (phy_info & IWL_RX_MPDU_PHY_AMPDU)) {
|
||||
@ -1056,84 +1189,12 @@ static void iwl_mvm_rx_he(struct iwl_mvm *mvm, struct sk_buff *skb,
|
||||
rx_status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_106;
|
||||
}
|
||||
|
||||
if (he_phy_data != HE_PHY_DATA_INVAL &&
|
||||
(FIELD_GET(IWL_RX_HE_PHY_INFO_TYPE_MASK, he_phy_data) ==
|
||||
IWL_RX_HE_PHY_INFO_TYPE_MU_EXT_INFO ||
|
||||
FIELD_GET(IWL_RX_HE_PHY_INFO_TYPE_MASK, he_phy_data) ==
|
||||
IWL_RX_HE_PHY_INFO_TYPE_TB_EXT_INFO)) {
|
||||
/*
|
||||
* Unfortunately, we have to leave the mac80211 data
|
||||
* incorrect for the case that we receive an HE-MU
|
||||
* transmission and *don't* have the HE phy data (due
|
||||
* to the bits being used for TSF). This shouldn't
|
||||
* happen though as management frames where we need
|
||||
* the TSF/timers are not be transmitted in HE-MU.
|
||||
*/
|
||||
u8 ru = FIELD_GET(IWL_RX_HE_PHY_RU_ALLOC_MASK, he_phy_data);
|
||||
u8 offs = 0;
|
||||
|
||||
rx_status->bw = RATE_INFO_BW_HE_RU;
|
||||
|
||||
/* actually data is filled in mac80211 */
|
||||
if (he_type == RATE_MCS_HE_TYPE_SU ||
|
||||
he_type == RATE_MCS_HE_TYPE_EXT_SU)
|
||||
he->data1 |=
|
||||
cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA1_BW_RU_ALLOC_KNOWN);
|
||||
|
||||
switch (ru) {
|
||||
case 0 ... 36:
|
||||
rx_status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_26;
|
||||
offs = ru;
|
||||
break;
|
||||
case 37 ... 52:
|
||||
rx_status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_52;
|
||||
offs = ru - 37;
|
||||
break;
|
||||
case 53 ... 60:
|
||||
rx_status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_106;
|
||||
offs = ru - 53;
|
||||
break;
|
||||
case 61 ... 64:
|
||||
rx_status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_242;
|
||||
offs = ru - 61;
|
||||
break;
|
||||
case 65 ... 66:
|
||||
rx_status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_484;
|
||||
offs = ru - 65;
|
||||
break;
|
||||
case 67:
|
||||
rx_status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_996;
|
||||
break;
|
||||
case 68:
|
||||
rx_status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_2x996;
|
||||
break;
|
||||
}
|
||||
he->data2 |=
|
||||
le16_encode_bits(offs,
|
||||
IEEE80211_RADIOTAP_HE_DATA2_RU_OFFSET);
|
||||
he->data2 |=
|
||||
cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA2_PRISEC_80_KNOWN |
|
||||
IEEE80211_RADIOTAP_HE_DATA2_RU_OFFSET_KNOWN);
|
||||
if (he_phy_data & IWL_RX_HE_PHY_RU_ALLOC_SEC80)
|
||||
he->data2 |=
|
||||
cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA2_PRISEC_80_SEC);
|
||||
|
||||
if (he_mu) {
|
||||
#define CHECK_BW(bw) \
|
||||
BUILD_BUG_ON(IEEE80211_RADIOTAP_HE_MU_FLAGS2_BW_FROM_SIG_A_BW_ ## bw ## MHZ != \
|
||||
RATE_MCS_CHAN_WIDTH_##bw >> RATE_MCS_CHAN_WIDTH_POS)
|
||||
CHECK_BW(20);
|
||||
CHECK_BW(40);
|
||||
CHECK_BW(80);
|
||||
CHECK_BW(160);
|
||||
he->data2 |=
|
||||
le16_encode_bits(FIELD_GET(RATE_MCS_CHAN_WIDTH_MSK,
|
||||
rate_n_flags),
|
||||
IEEE80211_RADIOTAP_HE_MU_FLAGS2_BW_FROM_SIG_A_BW);
|
||||
}
|
||||
} else if (he_type == RATE_MCS_HE_TYPE_SU ||
|
||||
he_type == RATE_MCS_HE_TYPE_EXT_SU) {
|
||||
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_VHT_MCS_NSS_MSK) >>
|
||||
@ -1202,9 +1263,8 @@ static void iwl_mvm_rx_he(struct iwl_mvm *mvm, struct sk_buff *skb,
|
||||
|
||||
he->data5 |= le16_encode_bits(ltf, IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE);
|
||||
|
||||
switch (he_type) {
|
||||
case RATE_MCS_HE_TYPE_SU:
|
||||
case RATE_MCS_HE_TYPE_EXT_SU: {
|
||||
if (he_type == RATE_MCS_HE_TYPE_SU ||
|
||||
he_type == RATE_MCS_HE_TYPE_EXT_SU) {
|
||||
u16 val;
|
||||
|
||||
/* LTF syms correspond to streams */
|
||||
@ -1234,31 +1294,10 @@ static void iwl_mvm_rx_he(struct iwl_mvm *mvm, struct sk_buff *skb,
|
||||
rx_status->nss);
|
||||
val = 0;
|
||||
}
|
||||
|
||||
he->data5 |=
|
||||
le16_encode_bits(val,
|
||||
IEEE80211_RADIOTAP_HE_DATA5_NUM_LTF_SYMS);
|
||||
}
|
||||
break;
|
||||
case RATE_MCS_HE_TYPE_MU: {
|
||||
u16 val;
|
||||
|
||||
if (he_phy_data == HE_PHY_DATA_INVAL)
|
||||
break;
|
||||
|
||||
val = FIELD_GET(IWL_RX_HE_PHY_HE_LTF_NUM_MASK,
|
||||
he_phy_data);
|
||||
|
||||
he->data2 |=
|
||||
cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA2_NUM_LTF_SYMS_KNOWN);
|
||||
he->data5 |=
|
||||
cpu_to_le16(FIELD_PREP(
|
||||
IEEE80211_RADIOTAP_HE_DATA5_NUM_LTF_SYMS,
|
||||
val));
|
||||
}
|
||||
break;
|
||||
case RATE_MCS_HE_TYPE_TRIG:
|
||||
/* not supported */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1424,6 +1463,8 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
|
||||
u8 baid = (u8)((le32_to_cpu(desc->reorder_data) &
|
||||
IWL_RX_MPDU_REORDER_BAID_MASK) >>
|
||||
IWL_RX_MPDU_REORDER_BAID_SHIFT);
|
||||
struct iwl_fw_dbg_trigger_tlv *trig;
|
||||
struct ieee80211_vif *vif = mvmsta->vif;
|
||||
|
||||
if (!mvm->tcm.paused && len >= sizeof(*hdr) &&
|
||||
!is_multicast_ether_addr(hdr->addr1) &&
|
||||
@ -1436,8 +1477,7 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
|
||||
* frames from a blocked station on a new channel we can
|
||||
* TX to it again.
|
||||
*/
|
||||
if (unlikely(tx_blocked_vif) &&
|
||||
tx_blocked_vif == mvmsta->vif) {
|
||||
if (unlikely(tx_blocked_vif) && tx_blocked_vif == vif) {
|
||||
struct iwl_mvm_vif *mvmvif =
|
||||
iwl_mvm_vif_from_mac80211(tx_blocked_vif);
|
||||
|
||||
@ -1448,23 +1488,18 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
|
||||
|
||||
rs_update_last_rssi(mvm, mvmsta, rx_status);
|
||||
|
||||
if (iwl_fw_dbg_trigger_enabled(mvm->fw, FW_DBG_TRIGGER_RSSI) &&
|
||||
ieee80211_is_beacon(hdr->frame_control)) {
|
||||
struct iwl_fw_dbg_trigger_tlv *trig;
|
||||
trig = iwl_fw_dbg_trigger_on(&mvm->fwrt,
|
||||
ieee80211_vif_to_wdev(vif),
|
||||
FW_DBG_TRIGGER_RSSI);
|
||||
|
||||
if (trig && ieee80211_is_beacon(hdr->frame_control)) {
|
||||
struct iwl_fw_dbg_trigger_low_rssi *rssi_trig;
|
||||
bool trig_check;
|
||||
s32 rssi;
|
||||
|
||||
trig = iwl_fw_dbg_get_trigger(mvm->fw,
|
||||
FW_DBG_TRIGGER_RSSI);
|
||||
rssi_trig = (void *)trig->data;
|
||||
rssi = le32_to_cpu(rssi_trig->rssi);
|
||||
|
||||
trig_check =
|
||||
iwl_fw_dbg_trigger_check_stop(&mvm->fwrt,
|
||||
ieee80211_vif_to_wdev(mvmsta->vif),
|
||||
trig);
|
||||
if (trig_check && rx_status->signal < rssi)
|
||||
if (rx_status->signal < rssi)
|
||||
iwl_fw_dbg_collect_trig(&mvm->fwrt, trig,
|
||||
NULL);
|
||||
}
|
||||
|
@ -1448,6 +1448,9 @@ static int iwl_mvm_scan_umac(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
|
||||
if (gen_flags & IWL_UMAC_SCAN_GEN_FLAGS_LMAC2_FRAGMENTED)
|
||||
cmd->v8.num_of_fragments[SCAN_HB_LMAC_IDX] =
|
||||
IWL_SCAN_NUM_OF_FRAGS;
|
||||
|
||||
cmd->v8.general_flags2 =
|
||||
IWL_UMAC_SCAN_GEN_FLAGS2_ALLOW_CHNL_REORDER;
|
||||
}
|
||||
|
||||
cmd->scan_start_mac_id = scan_vif->id;
|
||||
|
@ -254,17 +254,14 @@ static void iwl_mvm_te_check_trigger(struct iwl_mvm *mvm,
|
||||
struct iwl_fw_dbg_trigger_time_event *te_trig;
|
||||
int i;
|
||||
|
||||
if (!iwl_fw_dbg_trigger_enabled(mvm->fw, FW_DBG_TRIGGER_TIME_EVENT))
|
||||
trig = iwl_fw_dbg_trigger_on(&mvm->fwrt,
|
||||
ieee80211_vif_to_wdev(te_data->vif),
|
||||
FW_DBG_TRIGGER_TIME_EVENT);
|
||||
if (!trig)
|
||||
return;
|
||||
|
||||
trig = iwl_fw_dbg_get_trigger(mvm->fw, FW_DBG_TRIGGER_TIME_EVENT);
|
||||
te_trig = (void *)trig->data;
|
||||
|
||||
if (!iwl_fw_dbg_trigger_check_stop(&mvm->fwrt,
|
||||
ieee80211_vif_to_wdev(te_data->vif),
|
||||
trig))
|
||||
return;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(te_trig->time_events); i++) {
|
||||
u32 trig_te_id = le32_to_cpu(te_trig->time_events[i].id);
|
||||
u32 trig_action_bitmap =
|
||||
|
@ -79,15 +79,12 @@ iwl_mvm_bar_check_trigger(struct iwl_mvm *mvm, const u8 *addr,
|
||||
struct iwl_fw_dbg_trigger_tlv *trig;
|
||||
struct iwl_fw_dbg_trigger_ba *ba_trig;
|
||||
|
||||
if (!iwl_fw_dbg_trigger_enabled(mvm->fw, FW_DBG_TRIGGER_BA))
|
||||
trig = iwl_fw_dbg_trigger_on(&mvm->fwrt, NULL, FW_DBG_TRIGGER_BA);
|
||||
if (!trig)
|
||||
return;
|
||||
|
||||
trig = iwl_fw_dbg_get_trigger(mvm->fw, FW_DBG_TRIGGER_BA);
|
||||
ba_trig = (void *)trig->data;
|
||||
|
||||
if (!iwl_fw_dbg_trigger_check_stop(&mvm->fwrt, NULL, trig))
|
||||
return;
|
||||
|
||||
if (!(le16_to_cpu(ba_trig->tx_bar) & BIT(tid)))
|
||||
return;
|
||||
|
||||
@ -1414,15 +1411,13 @@ static void iwl_mvm_tx_status_check_trigger(struct iwl_mvm *mvm,
|
||||
struct iwl_fw_dbg_trigger_tx_status *status_trig;
|
||||
int i;
|
||||
|
||||
if (!iwl_fw_dbg_trigger_enabled(mvm->fw, FW_DBG_TRIGGER_TX_STATUS))
|
||||
trig = iwl_fw_dbg_trigger_on(&mvm->fwrt, NULL,
|
||||
FW_DBG_TRIGGER_TX_STATUS);
|
||||
if (!trig)
|
||||
return;
|
||||
|
||||
trig = iwl_fw_dbg_get_trigger(mvm->fw, FW_DBG_TRIGGER_TX_STATUS);
|
||||
status_trig = (void *)trig->data;
|
||||
|
||||
if (!iwl_fw_dbg_trigger_check_stop(&mvm->fwrt, NULL, trig))
|
||||
return;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(status_trig->statuses); i++) {
|
||||
/* don't collect on status 0 */
|
||||
if (!status_trig->statuses[i].status)
|
||||
|
@ -1238,14 +1238,12 @@ void iwl_mvm_connection_loss(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
|
||||
struct iwl_fw_dbg_trigger_tlv *trig;
|
||||
struct iwl_fw_dbg_trigger_mlme *trig_mlme;
|
||||
|
||||
if (!iwl_fw_dbg_trigger_enabled(mvm->fw, FW_DBG_TRIGGER_MLME))
|
||||
trig = iwl_fw_dbg_trigger_on(&mvm->fwrt, ieee80211_vif_to_wdev(vif),
|
||||
FW_DBG_TRIGGER_MLME);
|
||||
if (!trig)
|
||||
goto out;
|
||||
|
||||
trig = iwl_fw_dbg_get_trigger(mvm->fw, FW_DBG_TRIGGER_MLME);
|
||||
trig_mlme = (void *)trig->data;
|
||||
if (!iwl_fw_dbg_trigger_check_stop(&mvm->fwrt,
|
||||
ieee80211_vif_to_wdev(vif), trig))
|
||||
goto out;
|
||||
|
||||
if (trig_mlme->stop_connection_loss &&
|
||||
--trig_mlme->stop_connection_loss)
|
||||
@ -1430,14 +1428,12 @@ void iwl_mvm_event_frame_timeout_callback(struct iwl_mvm *mvm,
|
||||
struct iwl_fw_dbg_trigger_tlv *trig;
|
||||
struct iwl_fw_dbg_trigger_ba *ba_trig;
|
||||
|
||||
if (!iwl_fw_dbg_trigger_enabled(mvm->fw, FW_DBG_TRIGGER_BA))
|
||||
trig = iwl_fw_dbg_trigger_on(&mvm->fwrt, ieee80211_vif_to_wdev(vif),
|
||||
FW_DBG_TRIGGER_BA);
|
||||
if (!trig)
|
||||
return;
|
||||
|
||||
trig = iwl_fw_dbg_get_trigger(mvm->fw, FW_DBG_TRIGGER_BA);
|
||||
ba_trig = (void *)trig->data;
|
||||
if (!iwl_fw_dbg_trigger_check_stop(&mvm->fwrt,
|
||||
ieee80211_vif_to_wdev(vif), trig))
|
||||
return;
|
||||
|
||||
if (!(le16_to_cpu(ba_trig->frame_timeout) & BIT(tid)))
|
||||
return;
|
||||
|
@ -1144,6 +1144,14 @@ void iwl_pcie_rx_free(struct iwl_trans *trans)
|
||||
kfree(trans_pcie->rxq);
|
||||
}
|
||||
|
||||
static void iwl_pcie_rx_move_to_allocator(struct iwl_rxq *rxq,
|
||||
struct iwl_rb_allocator *rba)
|
||||
{
|
||||
spin_lock(&rba->lock);
|
||||
list_splice_tail_init(&rxq->rx_used, &rba->rbd_empty);
|
||||
spin_unlock(&rba->lock);
|
||||
}
|
||||
|
||||
/*
|
||||
* iwl_pcie_rx_reuse_rbd - Recycle used RBDs
|
||||
*
|
||||
@ -1175,9 +1183,7 @@ static void iwl_pcie_rx_reuse_rbd(struct iwl_trans *trans,
|
||||
if ((rxq->used_count % RX_CLAIM_REQ_ALLOC) == RX_POST_REQ_ALLOC) {
|
||||
/* Move the 2 RBDs to the allocator ownership.
|
||||
Allocator has another 6 from pool for the request completion*/
|
||||
spin_lock(&rba->lock);
|
||||
list_splice_tail_init(&rxq->rx_used, &rba->rbd_empty);
|
||||
spin_unlock(&rba->lock);
|
||||
iwl_pcie_rx_move_to_allocator(rxq, rba);
|
||||
|
||||
atomic_inc(&rba->req_pending);
|
||||
queue_work(rba->alloc_wq, &rba->rx_alloc);
|
||||
@ -1400,10 +1406,18 @@ restart:
|
||||
IWL_DEBUG_RX(trans, "Q %d: HW = SW = %d\n", rxq->id, r);
|
||||
|
||||
while (i != r) {
|
||||
struct iwl_rb_allocator *rba = &trans_pcie->rba;
|
||||
struct iwl_rx_mem_buffer *rxb;
|
||||
/* number of RBDs still waiting for page allocation */
|
||||
u32 rb_pending_alloc =
|
||||
atomic_read(&trans_pcie->rba.req_pending) *
|
||||
RX_CLAIM_REQ_ALLOC;
|
||||
|
||||
if (unlikely(rxq->used_count == rxq->queue_size / 2))
|
||||
if (unlikely(rb_pending_alloc >= rxq->queue_size / 2 &&
|
||||
!emergency)) {
|
||||
iwl_pcie_rx_move_to_allocator(rxq, rba);
|
||||
emergency = true;
|
||||
}
|
||||
|
||||
rxb = iwl_pcie_get_rxb(trans, rxq, i);
|
||||
if (!rxb)
|
||||
@ -1425,17 +1439,13 @@ restart:
|
||||
iwl_pcie_rx_allocator_get(trans, rxq);
|
||||
|
||||
if (rxq->used_count % RX_CLAIM_REQ_ALLOC == 0 && !emergency) {
|
||||
struct iwl_rb_allocator *rba = &trans_pcie->rba;
|
||||
|
||||
/* Add the remaining empty RBDs for allocator use */
|
||||
spin_lock(&rba->lock);
|
||||
list_splice_tail_init(&rxq->rx_used, &rba->rbd_empty);
|
||||
spin_unlock(&rba->lock);
|
||||
iwl_pcie_rx_move_to_allocator(rxq, rba);
|
||||
} else if (emergency) {
|
||||
count++;
|
||||
if (count == 8) {
|
||||
count = 0;
|
||||
if (rxq->used_count < rxq->queue_size / 3)
|
||||
if (rb_pending_alloc < rxq->queue_size / 3)
|
||||
emergency = false;
|
||||
|
||||
rxq->read = i;
|
||||
|
@ -931,7 +931,7 @@ void iwl_pcie_apply_destination(struct iwl_trans *trans)
|
||||
else
|
||||
IWL_WARN(trans, "PCI should have external buffer debug\n");
|
||||
|
||||
for (i = 0; i < trans->dbg_dest_reg_num; i++) {
|
||||
for (i = 0; i < trans->dbg_n_dest_reg; i++) {
|
||||
u32 addr = le32_to_cpu(dest->reg_ops[i].addr);
|
||||
u32 val = le32_to_cpu(dest->reg_ops[i].val);
|
||||
|
||||
|
@ -438,6 +438,8 @@ static int iwl_pcie_gen2_tx_add_frags(struct iwl_trans *trans,
|
||||
return -ENOMEM;
|
||||
tb_idx = iwl_pcie_gen2_set_tb(trans, tfd, tb_phys,
|
||||
skb_frag_size(frag));
|
||||
if (tb_idx < 0)
|
||||
return tb_idx;
|
||||
|
||||
out_meta->tbs |= BIT(tb_idx);
|
||||
}
|
||||
|
@ -2013,6 +2013,8 @@ static int iwl_fill_data_tbs(struct iwl_trans *trans, struct sk_buff *skb,
|
||||
return -EINVAL;
|
||||
tb_idx = iwl_pcie_txq_build_tfd(trans, txq, tb_phys,
|
||||
skb_frag_size(frag), false);
|
||||
if (tb_idx < 0)
|
||||
return tb_idx;
|
||||
|
||||
out_meta->tbs |= BIT(tb_idx);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user