mirror of https://gitee.com/openkylin/linux.git
Patches intended for v5.3
* Work on the new debugging framework continues; * Update the FW API for CSI; * Special SAR implementation for South Korea; * Fixes in the module init error paths; * Debugging infra work continues; * A bunch of RF-kill fixes by Emmanuel; * A fix for AP mode, also related to RF-kill, by Johannes. * A few clean-ups; * Other small fixes and improvements; -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEF3LNfgb2BPWm68smoUecoho8xfoFAl0XEJEACgkQoUecoho8 xfopUQ/9FphsndYEQ0CLRXcb4yLgtmvfVJjho7m202zYOXr0LedCZEz89cgBHx9O add0UZB6hRyPXZiVpzGGs8H7524FViB2PN3MgQKA9CA0dBmiBecEKAFCGHmhcjde K+UYVYtYgUKQuzp/KOT8//sanjHfRgasUHltjLN12pZrATUFi0ET3kaxBf35u+cV KQUDv75S/cwGyT2HmVpMAHX0PM6Yj/YS+cxnjPQ5gC28coSpiOoA2KE700QZRGoA VSDsnZnSfWCWh6j73lXcZOXnwV4zis0Q578mu9i1rtEAkRkDVexNYfi2/tpA7gC9 dO/DzlHvfs3PuEakunR0iQEdKYc7DvPjPzTD0cDz0Hg1xTjpL+i+RnF3yikZWZAZ U9a1ztjkF9D4ZRNFap8HgaZL6jcsbRgKfQYfKeBAnrSZkZtTZ7sIV1FGFCst8Buh oH9PqlHWFGogBpA6xFzcEgpmgUiZ3PIAswxJigGcL9T3mmUsaE8RNsbZSxQk0A0O YbnKQk6opmFAvqw7GGOCkLWU5mE25Qo1X0Ayi3omtnfR6R3qMweoZM8owzAN17+m Gs9ebNN//XkR/SfudNyhBAWQgV6JLCeFqDVy4GI+uqg60lxEw4GfanQPZ4DuNFeb lZ/hrzwNbrW6DztDk4/x1y/L4VAYAaJzUvr46JtozGv1p93Kwnk= =g1qz -----END PGP SIGNATURE----- Merge tag 'iwlwifi-next-for-kalle-2019-06-29' of git://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi/iwlwifi-next Patches intended for v5.3 * Work on the new debugging framework continues; * Update the FW API for CSI; * Special SAR implementation for South Korea; * Fixes in the module init error paths; * Debugging infra work continues; * A bunch of RF-kill fixes by Emmanuel; * A fix for AP mode, also related to RF-kill, by Johannes. * A few clean-ups; * Other small fixes and improvements;
This commit is contained in:
commit
1375da4787
|
@ -1009,8 +1009,7 @@ int iwlagn_send_patterns(struct iwl_priv *priv,
|
|||
if (!wowlan->n_patterns)
|
||||
return 0;
|
||||
|
||||
cmd.len[0] = sizeof(*pattern_cmd) +
|
||||
wowlan->n_patterns * sizeof(struct iwlagn_wowlan_pattern);
|
||||
cmd.len[0] = struct_size(pattern_cmd, patterns, wowlan->n_patterns);
|
||||
|
||||
pattern_cmd = kmalloc(cmd.len[0], GFP_KERNEL);
|
||||
if (!pattern_cmd)
|
||||
|
|
|
@ -97,7 +97,7 @@ IWL_EXPORT_SYMBOL(iwl_acpi_get_object);
|
|||
|
||||
union acpi_object *iwl_acpi_get_wifi_pkg(struct device *dev,
|
||||
union acpi_object *data,
|
||||
int data_size)
|
||||
int data_size, int *tbl_rev)
|
||||
{
|
||||
int i;
|
||||
union acpi_object *wifi_pkg;
|
||||
|
@ -113,16 +113,19 @@ union acpi_object *iwl_acpi_get_wifi_pkg(struct device *dev,
|
|||
/*
|
||||
* We need at least two packages, one for the revision and one
|
||||
* for the data itself. Also check that the revision is valid
|
||||
* (i.e. it is an integer set to 0).
|
||||
* (i.e. it is an integer smaller than 2, as we currently support only
|
||||
* 2 revisions).
|
||||
*/
|
||||
if (data->type != ACPI_TYPE_PACKAGE ||
|
||||
data->package.count < 2 ||
|
||||
data->package.elements[0].type != ACPI_TYPE_INTEGER ||
|
||||
data->package.elements[0].integer.value != 0) {
|
||||
data->package.elements[0].integer.value > 1) {
|
||||
IWL_DEBUG_DEV_RADIO(dev, "Unsupported packages structure\n");
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
*tbl_rev = data->package.elements[0].integer.value;
|
||||
|
||||
/* loop through all the packages to find the one for WiFi */
|
||||
for (i = 1; i < data->package.count; i++) {
|
||||
union acpi_object *domain;
|
||||
|
@ -151,14 +154,15 @@ int iwl_acpi_get_mcc(struct device *dev, char *mcc)
|
|||
{
|
||||
union acpi_object *wifi_pkg, *data;
|
||||
u32 mcc_val;
|
||||
int ret;
|
||||
int ret, tbl_rev;
|
||||
|
||||
data = iwl_acpi_get_object(dev, ACPI_WRDD_METHOD);
|
||||
if (IS_ERR(data))
|
||||
return PTR_ERR(data);
|
||||
|
||||
wifi_pkg = iwl_acpi_get_wifi_pkg(dev, data, ACPI_WRDD_WIFI_DATA_SIZE);
|
||||
if (IS_ERR(wifi_pkg)) {
|
||||
wifi_pkg = iwl_acpi_get_wifi_pkg(dev, data, ACPI_WRDD_WIFI_DATA_SIZE,
|
||||
&tbl_rev);
|
||||
if (IS_ERR(wifi_pkg) || tbl_rev != 0) {
|
||||
ret = PTR_ERR(wifi_pkg);
|
||||
goto out_free;
|
||||
}
|
||||
|
@ -185,6 +189,7 @@ u64 iwl_acpi_get_pwr_limit(struct device *dev)
|
|||
{
|
||||
union acpi_object *data, *wifi_pkg;
|
||||
u64 dflt_pwr_limit;
|
||||
int tbl_rev;
|
||||
|
||||
data = iwl_acpi_get_object(dev, ACPI_SPLC_METHOD);
|
||||
if (IS_ERR(data)) {
|
||||
|
@ -193,8 +198,8 @@ u64 iwl_acpi_get_pwr_limit(struct device *dev)
|
|||
}
|
||||
|
||||
wifi_pkg = iwl_acpi_get_wifi_pkg(dev, data,
|
||||
ACPI_SPLC_WIFI_DATA_SIZE);
|
||||
if (IS_ERR(wifi_pkg) ||
|
||||
ACPI_SPLC_WIFI_DATA_SIZE, &tbl_rev);
|
||||
if (IS_ERR(wifi_pkg) || tbl_rev != 0 ||
|
||||
wifi_pkg->package.elements[1].integer.value != ACPI_TYPE_INTEGER) {
|
||||
dflt_pwr_limit = 0;
|
||||
goto out_free;
|
||||
|
@ -211,14 +216,15 @@ IWL_EXPORT_SYMBOL(iwl_acpi_get_pwr_limit);
|
|||
int iwl_acpi_get_eckv(struct device *dev, u32 *extl_clk)
|
||||
{
|
||||
union acpi_object *wifi_pkg, *data;
|
||||
int ret;
|
||||
int ret, tbl_rev;
|
||||
|
||||
data = iwl_acpi_get_object(dev, ACPI_ECKV_METHOD);
|
||||
if (IS_ERR(data))
|
||||
return PTR_ERR(data);
|
||||
|
||||
wifi_pkg = iwl_acpi_get_wifi_pkg(dev, data, ACPI_ECKV_WIFI_DATA_SIZE);
|
||||
if (IS_ERR(wifi_pkg)) {
|
||||
wifi_pkg = iwl_acpi_get_wifi_pkg(dev, data, ACPI_ECKV_WIFI_DATA_SIZE,
|
||||
&tbl_rev);
|
||||
if (IS_ERR(wifi_pkg) || tbl_rev != 0) {
|
||||
ret = PTR_ERR(wifi_pkg);
|
||||
goto out_free;
|
||||
}
|
||||
|
|
|
@ -97,7 +97,7 @@
|
|||
void *iwl_acpi_get_object(struct device *dev, acpi_string method);
|
||||
union acpi_object *iwl_acpi_get_wifi_pkg(struct device *dev,
|
||||
union acpi_object *data,
|
||||
int data_size);
|
||||
int data_size, int *tbl_rev);
|
||||
|
||||
/**
|
||||
* iwl_acpi_get_mcc - read MCC from ACPI, if available
|
||||
|
@ -131,7 +131,8 @@ static inline void *iwl_acpi_get_object(struct device *dev, acpi_string method)
|
|||
|
||||
static inline union acpi_object *iwl_acpi_get_wifi_pkg(struct device *dev,
|
||||
union acpi_object *data,
|
||||
int data_size)
|
||||
int data_size,
|
||||
int *tbl_rev)
|
||||
{
|
||||
return ERR_PTR(-ENOENT);
|
||||
}
|
||||
|
|
|
@ -291,6 +291,28 @@ struct iwl_fw_ini_trigger_tlv {
|
|||
struct iwl_fw_ini_trigger trigger_config[];
|
||||
} __packed; /* FW_TLV_DEBUG_TRIGGERS_API_S_VER_1 */
|
||||
|
||||
#define IWL_FW_INI_MAX_IMG_NAME_LEN 32
|
||||
#define IWL_FW_INI_MAX_DBG_CFG_NAME_LEN 64
|
||||
|
||||
/**
|
||||
* struct iwl_fw_ini_debug_info_tlv - (IWL_UCODE_TLV_TYPE_DEBUG_INFO)
|
||||
*
|
||||
* holds image name and debug configuration name
|
||||
*
|
||||
* @header: header
|
||||
* @img_name_len: length of the image name string
|
||||
* @img_name: image name string
|
||||
* @dbg_cfg_name_len : length of the debug configuration name string
|
||||
* @dbg_cfg_name: debug configuration name string
|
||||
*/
|
||||
struct iwl_fw_ini_debug_info_tlv {
|
||||
struct iwl_fw_ini_header header;
|
||||
__le32 img_name_len;
|
||||
u8 img_name[IWL_FW_INI_MAX_IMG_NAME_LEN];
|
||||
__le32 dbg_cfg_name_len;
|
||||
u8 dbg_cfg_name[IWL_FW_INI_MAX_DBG_CFG_NAME_LEN];
|
||||
} __packed; /* FW_DEBUG_TLV_INFO_API_S_VER_1 */
|
||||
|
||||
/**
|
||||
* enum iwl_fw_ini_trigger_id
|
||||
*
|
||||
|
|
|
@ -937,8 +937,13 @@ struct iwl_ftm_responder_stats {
|
|||
__le16 reserved;
|
||||
} __packed; /* TOF_RESPONDER_STATISTICS_NTFY_S_VER_2 */
|
||||
|
||||
#define IWL_CSI_CHUNK_CTL_NUM_MASK 0x3
|
||||
#define IWL_CSI_CHUNK_CTL_IDX_MASK 0xc
|
||||
#define IWL_CSI_MAX_EXPECTED_CHUNKS 16
|
||||
|
||||
#define IWL_CSI_CHUNK_CTL_NUM_MASK_VER_1 0x0003
|
||||
#define IWL_CSI_CHUNK_CTL_IDX_MASK_VER_1 0x000c
|
||||
|
||||
#define IWL_CSI_CHUNK_CTL_NUM_MASK_VER_2 0x00ff
|
||||
#define IWL_CSI_CHUNK_CTL_IDX_MASK_VER_2 0xff00
|
||||
|
||||
struct iwl_csi_chunk_notification {
|
||||
__le32 token;
|
||||
|
@ -946,6 +951,6 @@ struct iwl_csi_chunk_notification {
|
|||
__le16 ctl;
|
||||
__le32 size;
|
||||
u8 data[];
|
||||
} __packed; /* CSI_CHUNKS_HDR_NTFY_API_S_VER_1 */
|
||||
} __packed; /* CSI_CHUNKS_HDR_NTFY_API_S_VER_1/VER_2 */
|
||||
|
||||
#endif /* __iwl_fw_api_location_h__ */
|
||||
|
|
|
@ -419,14 +419,26 @@ struct iwl_per_chain_offset_group {
|
|||
struct iwl_per_chain_offset hb;
|
||||
} __packed; /* PER_CHAIN_LIMIT_OFFSET_GROUP_S_VER_1 */
|
||||
|
||||
/**
|
||||
* struct iwl_geo_tx_power_profile_cmd_v1 - struct for GEO_TX_POWER_LIMIT cmd.
|
||||
* @ops: operations, value from &enum iwl_geo_per_chain_offset_operation
|
||||
* @table: offset profile per band.
|
||||
*/
|
||||
struct iwl_geo_tx_power_profiles_cmd_v1 {
|
||||
__le32 ops;
|
||||
struct iwl_per_chain_offset_group table[IWL_NUM_GEO_PROFILES];
|
||||
} __packed; /* GEO_TX_POWER_LIMIT_VER_1 */
|
||||
|
||||
/**
|
||||
* struct iwl_geo_tx_power_profile_cmd - struct for GEO_TX_POWER_LIMIT cmd.
|
||||
* @ops: operations, value from &enum iwl_geo_per_chain_offset_operation
|
||||
* @table: offset profile per band.
|
||||
* @table_revision: BIOS table revision.
|
||||
*/
|
||||
struct iwl_geo_tx_power_profiles_cmd {
|
||||
__le32 ops;
|
||||
struct iwl_per_chain_offset_group table[IWL_NUM_GEO_PROFILES];
|
||||
__le32 table_revision;
|
||||
} __packed; /* GEO_TX_POWER_LIMIT */
|
||||
|
||||
/**
|
||||
|
|
|
@ -750,6 +750,21 @@ struct iwl_scan_req_umac {
|
|||
struct iwl_scan_umac_chan_param channel;
|
||||
u8 data[];
|
||||
} v8; /* SCAN_REQUEST_CMD_UMAC_API_S_VER_8 */
|
||||
struct {
|
||||
u8 active_dwell[SCAN_TWO_LMACS];
|
||||
u8 adwell_default_hb_n_aps;
|
||||
u8 adwell_default_lb_n_aps;
|
||||
u8 adwell_default_n_aps_social;
|
||||
u8 general_flags2;
|
||||
__le16 adwell_max_budget;
|
||||
__le32 max_out_time[SCAN_TWO_LMACS];
|
||||
__le32 suspend_time[SCAN_TWO_LMACS];
|
||||
__le32 scan_priority;
|
||||
u8 passive_dwell[SCAN_TWO_LMACS];
|
||||
u8 num_of_fragments[SCAN_TWO_LMACS];
|
||||
struct iwl_scan_umac_chan_param channel;
|
||||
u8 data[];
|
||||
} v9; /* SCAN_REQUEST_CMD_UMAC_API_S_VER_9 */
|
||||
};
|
||||
} __packed;
|
||||
|
||||
|
|
|
@ -1059,7 +1059,7 @@ static int iwl_dump_ini_prph_iter(struct iwl_fw_runtime *fwrt,
|
|||
u32 addr = le32_to_cpu(reg->start_addr[idx]) + le32_to_cpu(reg->offset);
|
||||
int i;
|
||||
|
||||
range->start_addr = cpu_to_le64(addr);
|
||||
range->internal_base_addr = cpu_to_le32(addr);
|
||||
range->range_data_size = reg->internal.range_data_size;
|
||||
for (i = 0; i < le32_to_cpu(reg->internal.range_data_size); i += 4) {
|
||||
prph_val = iwl_read_prph(fwrt->trans, addr + i);
|
||||
|
@ -1080,7 +1080,7 @@ static int iwl_dump_ini_csr_iter(struct iwl_fw_runtime *fwrt,
|
|||
u32 addr = le32_to_cpu(reg->start_addr[idx]) + le32_to_cpu(reg->offset);
|
||||
int i;
|
||||
|
||||
range->start_addr = cpu_to_le64(addr);
|
||||
range->internal_base_addr = cpu_to_le32(addr);
|
||||
range->range_data_size = reg->internal.range_data_size;
|
||||
for (i = 0; i < le32_to_cpu(reg->internal.range_data_size); i += 4)
|
||||
*val++ = cpu_to_le32(iwl_trans_read32(fwrt->trans, addr + i));
|
||||
|
@ -1095,7 +1095,7 @@ static int iwl_dump_ini_dev_mem_iter(struct iwl_fw_runtime *fwrt,
|
|||
struct iwl_fw_ini_error_dump_range *range = range_ptr;
|
||||
u32 addr = le32_to_cpu(reg->start_addr[idx]) + le32_to_cpu(reg->offset);
|
||||
|
||||
range->start_addr = cpu_to_le64(addr);
|
||||
range->internal_base_addr = cpu_to_le32(addr);
|
||||
range->range_data_size = reg->internal.range_data_size;
|
||||
iwl_trans_read_mem_bytes(fwrt->trans, addr, range->data,
|
||||
le32_to_cpu(reg->internal.range_data_size));
|
||||
|
@ -1111,7 +1111,7 @@ iwl_dump_ini_paging_gen2_iter(struct iwl_fw_runtime *fwrt,
|
|||
struct iwl_fw_ini_error_dump_range *range = range_ptr;
|
||||
u32 page_size = fwrt->trans->init_dram.paging[idx].size;
|
||||
|
||||
range->start_addr = cpu_to_le64(idx);
|
||||
range->page_num = cpu_to_le32(idx);
|
||||
range->range_data_size = cpu_to_le32(page_size);
|
||||
memcpy(range->data, fwrt->trans->init_dram.paging[idx].block,
|
||||
page_size);
|
||||
|
@ -1131,7 +1131,7 @@ static int iwl_dump_ini_paging_iter(struct iwl_fw_runtime *fwrt,
|
|||
dma_addr_t addr = fwrt->fw_paging_db[idx].fw_paging_phys;
|
||||
u32 page_size = fwrt->fw_paging_db[idx].fw_paging_size;
|
||||
|
||||
range->start_addr = cpu_to_le64(idx);
|
||||
range->page_num = cpu_to_le32(idx);
|
||||
range->range_data_size = cpu_to_le32(page_size);
|
||||
dma_sync_single_for_cpu(fwrt->trans->dev, addr, page_size,
|
||||
DMA_BIDIRECTIONAL);
|
||||
|
@ -1154,11 +1154,11 @@ iwl_dump_ini_mon_dram_iter(struct iwl_fw_runtime *fwrt,
|
|||
if (start_addr == 0x5a5a5a5a)
|
||||
return -EBUSY;
|
||||
|
||||
range->start_addr = cpu_to_le64(start_addr);
|
||||
range->range_data_size = cpu_to_le32(fwrt->trans->fw_mon[idx].size);
|
||||
range->dram_base_addr = cpu_to_le64(start_addr);
|
||||
range->range_data_size = cpu_to_le32(fwrt->trans->dbg.fw_mon[idx].size);
|
||||
|
||||
memcpy(range->data, fwrt->trans->fw_mon[idx].block,
|
||||
fwrt->trans->fw_mon[idx].size);
|
||||
memcpy(range->data, fwrt->trans->dbg.fw_mon[idx].block,
|
||||
fwrt->trans->dbg.fw_mon[idx].size);
|
||||
|
||||
return sizeof(*range) + le32_to_cpu(range->range_data_size);
|
||||
}
|
||||
|
@ -1228,7 +1228,7 @@ static int iwl_dump_ini_txf_iter(struct iwl_fw_runtime *fwrt,
|
|||
struct iwl_fw_ini_region_cfg *reg,
|
||||
void *range_ptr, int idx)
|
||||
{
|
||||
struct iwl_fw_ini_fifo_error_dump_range *range = range_ptr;
|
||||
struct iwl_fw_ini_error_dump_range *range = range_ptr;
|
||||
struct iwl_ini_txf_iter_data *iter;
|
||||
struct iwl_fw_ini_error_dump_register *reg_dump = (void *)range->data;
|
||||
u32 offs = le32_to_cpu(reg->offset), addr;
|
||||
|
@ -1246,8 +1246,8 @@ static int iwl_dump_ini_txf_iter(struct iwl_fw_runtime *fwrt,
|
|||
|
||||
iter = fwrt->dump.fifo_iter;
|
||||
|
||||
range->fifo_num = cpu_to_le32(iter->fifo);
|
||||
range->num_of_registers = reg->fifos.num_of_registers;
|
||||
range->fifo_hdr.fifo_num = cpu_to_le32(iter->fifo);
|
||||
range->fifo_hdr.num_of_registers = reg->fifos.num_of_registers;
|
||||
range->range_data_size = cpu_to_le32(iter->fifo_size + registers_size);
|
||||
|
||||
iwl_write_prph_no_grab(fwrt->trans, TXF_LARC_NUM + offs, iter->fifo);
|
||||
|
@ -1336,7 +1336,7 @@ static int iwl_dump_ini_rxf_iter(struct iwl_fw_runtime *fwrt,
|
|||
struct iwl_fw_ini_region_cfg *reg,
|
||||
void *range_ptr, int idx)
|
||||
{
|
||||
struct iwl_fw_ini_fifo_error_dump_range *range = range_ptr;
|
||||
struct iwl_fw_ini_error_dump_range *range = range_ptr;
|
||||
struct iwl_ini_rxf_data rxf_data;
|
||||
struct iwl_fw_ini_error_dump_register *reg_dump = (void *)range->data;
|
||||
u32 offs = le32_to_cpu(reg->offset), addr;
|
||||
|
@ -1353,8 +1353,8 @@ static int iwl_dump_ini_rxf_iter(struct iwl_fw_runtime *fwrt,
|
|||
if (!iwl_trans_grab_nic_access(fwrt->trans, &flags))
|
||||
return -EBUSY;
|
||||
|
||||
range->fifo_num = cpu_to_le32(rxf_data.fifo_num);
|
||||
range->num_of_registers = reg->fifos.num_of_registers;
|
||||
range->fifo_hdr.fifo_num = cpu_to_le32(rxf_data.fifo_num);
|
||||
range->fifo_hdr.num_of_registers = reg->fifos.num_of_registers;
|
||||
range->range_data_size = cpu_to_le32(rxf_data.size + registers_size);
|
||||
|
||||
/*
|
||||
|
@ -1408,7 +1408,7 @@ static void *iwl_dump_ini_mem_fill_header(struct iwl_fw_runtime *fwrt,
|
|||
{
|
||||
struct iwl_fw_ini_error_dump *dump = data;
|
||||
|
||||
dump->header.version = cpu_to_le32(IWL_INI_DUMP_MEM_VER);
|
||||
dump->header.version = cpu_to_le32(IWL_INI_DUMP_VER);
|
||||
|
||||
return dump->ranges;
|
||||
}
|
||||
|
@ -1433,7 +1433,7 @@ static void
|
|||
|
||||
iwl_trans_release_nic_access(fwrt->trans, &flags);
|
||||
|
||||
data->header.version = cpu_to_le32(IWL_INI_DUMP_MONITOR_VER);
|
||||
data->header.version = cpu_to_le32(IWL_INI_DUMP_VER);
|
||||
data->write_ptr = cpu_to_le32(write_ptr & write_ptr_msk);
|
||||
data->cycle_cnt = cpu_to_le32(cycle_cnt & cycle_cnt_msk);
|
||||
|
||||
|
@ -1490,17 +1490,6 @@ static void
|
|||
|
||||
}
|
||||
|
||||
static void *iwl_dump_ini_fifo_fill_header(struct iwl_fw_runtime *fwrt,
|
||||
struct iwl_fw_ini_region_cfg *reg,
|
||||
void *data)
|
||||
{
|
||||
struct iwl_fw_ini_fifo_error_dump *dump = data;
|
||||
|
||||
dump->header.version = cpu_to_le32(IWL_INI_DUMP_FIFO_VER);
|
||||
|
||||
return dump->ranges;
|
||||
}
|
||||
|
||||
static u32 iwl_dump_ini_mem_ranges(struct iwl_fw_runtime *fwrt,
|
||||
struct iwl_fw_ini_region_cfg *reg)
|
||||
{
|
||||
|
@ -1592,8 +1581,8 @@ static u32 iwl_dump_ini_mon_dram_get_size(struct iwl_fw_runtime *fwrt,
|
|||
u32 size = sizeof(struct iwl_fw_ini_monitor_dump) +
|
||||
sizeof(struct iwl_fw_ini_error_dump_range);
|
||||
|
||||
if (fwrt->trans->num_blocks)
|
||||
size += fwrt->trans->fw_mon[0].size;
|
||||
if (fwrt->trans->dbg.num_blocks)
|
||||
size += fwrt->trans->dbg.fw_mon[0].size;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
@ -1613,8 +1602,9 @@ static u32 iwl_dump_ini_txf_get_size(struct iwl_fw_runtime *fwrt,
|
|||
struct iwl_ini_txf_iter_data iter = { .init = true };
|
||||
void *fifo_iter = fwrt->dump.fifo_iter;
|
||||
u32 size = 0;
|
||||
u32 fifo_hdr = sizeof(struct iwl_fw_ini_fifo_error_dump_range) +
|
||||
le32_to_cpu(reg->fifos.num_of_registers) * sizeof(__le32) * 2;
|
||||
u32 fifo_hdr = sizeof(struct iwl_fw_ini_error_dump_range) +
|
||||
le32_to_cpu(reg->fifos.num_of_registers) *
|
||||
sizeof(struct iwl_fw_ini_error_dump_register);
|
||||
|
||||
fwrt->dump.fifo_iter = &iter;
|
||||
while (iwl_ini_txf_iter(fwrt, reg)) {
|
||||
|
@ -1624,7 +1614,7 @@ static u32 iwl_dump_ini_txf_get_size(struct iwl_fw_runtime *fwrt,
|
|||
}
|
||||
|
||||
if (size)
|
||||
size += sizeof(struct iwl_fw_ini_fifo_error_dump);
|
||||
size += sizeof(struct iwl_fw_ini_error_dump);
|
||||
|
||||
fwrt->dump.fifo_iter = fifo_iter;
|
||||
|
||||
|
@ -1635,9 +1625,10 @@ static u32 iwl_dump_ini_rxf_get_size(struct iwl_fw_runtime *fwrt,
|
|||
struct iwl_fw_ini_region_cfg *reg)
|
||||
{
|
||||
struct iwl_ini_rxf_data rx_data;
|
||||
u32 size = sizeof(struct iwl_fw_ini_fifo_error_dump) +
|
||||
sizeof(struct iwl_fw_ini_fifo_error_dump_range) +
|
||||
le32_to_cpu(reg->fifos.num_of_registers) * sizeof(__le32) * 2;
|
||||
u32 size = sizeof(struct iwl_fw_ini_error_dump) +
|
||||
sizeof(struct iwl_fw_ini_error_dump_range) +
|
||||
le32_to_cpu(reg->fifos.num_of_registers) *
|
||||
sizeof(struct iwl_fw_ini_error_dump_register);
|
||||
|
||||
if (reg->fifos.header_only)
|
||||
return size;
|
||||
|
@ -1683,20 +1674,24 @@ iwl_dump_ini_mem(struct iwl_fw_runtime *fwrt,
|
|||
struct iwl_dump_ini_mem_ops *ops)
|
||||
{
|
||||
struct iwl_fw_ini_error_dump_header *header = (void *)(*data)->data;
|
||||
u32 num_of_ranges, i, type = le32_to_cpu(reg->region_type);
|
||||
u32 num_of_ranges, i, type = le32_to_cpu(reg->region_type), size;
|
||||
void *range;
|
||||
|
||||
if (WARN_ON(!ops || !ops->get_num_of_ranges || !ops->get_size ||
|
||||
!ops->fill_mem_hdr || !ops->fill_range))
|
||||
return;
|
||||
|
||||
size = ops->get_size(fwrt, reg);
|
||||
if (!size)
|
||||
return;
|
||||
|
||||
IWL_DEBUG_FW(fwrt, "WRT: collecting region: id=%d, type=%d\n",
|
||||
le32_to_cpu(reg->region_id), type);
|
||||
|
||||
num_of_ranges = ops->get_num_of_ranges(fwrt, reg);
|
||||
|
||||
(*data)->type = cpu_to_le32(type | INI_DUMP_BIT);
|
||||
(*data)->len = cpu_to_le32(ops->get_size(fwrt, reg));
|
||||
(*data)->type = cpu_to_le32(type);
|
||||
(*data)->len = cpu_to_le32(size);
|
||||
|
||||
header->region_id = reg->region_id;
|
||||
header->num_of_ranges = cpu_to_le32(num_of_ranges);
|
||||
|
@ -1709,7 +1704,7 @@ iwl_dump_ini_mem(struct iwl_fw_runtime *fwrt,
|
|||
IWL_ERR(fwrt,
|
||||
"WRT: failed to fill region header: id=%d, type=%d\n",
|
||||
le32_to_cpu(reg->region_id), type);
|
||||
memset(*data, 0, le32_to_cpu((*data)->len));
|
||||
memset(*data, 0, size);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1720,7 +1715,7 @@ iwl_dump_ini_mem(struct iwl_fw_runtime *fwrt,
|
|||
IWL_ERR(fwrt,
|
||||
"WRT: failed to dump region: id=%d, type=%d\n",
|
||||
le32_to_cpu(reg->region_id), type);
|
||||
memset(*data, 0, le32_to_cpu((*data)->len));
|
||||
memset(*data, 0, size);
|
||||
return;
|
||||
}
|
||||
range = range + range_size;
|
||||
|
@ -1728,10 +1723,71 @@ iwl_dump_ini_mem(struct iwl_fw_runtime *fwrt,
|
|||
*data = iwl_fw_error_next_data(*data);
|
||||
}
|
||||
|
||||
static void iwl_dump_ini_info(struct iwl_fw_runtime *fwrt,
|
||||
struct iwl_fw_ini_trigger *trigger,
|
||||
struct iwl_fw_error_dump_data **data)
|
||||
{
|
||||
struct iwl_fw_ini_dump_info *dump = (void *)(*data)->data;
|
||||
u32 reg_ids_size = le32_to_cpu(trigger->num_regions) * sizeof(__le32);
|
||||
|
||||
(*data)->type = cpu_to_le32(IWL_INI_DUMP_INFO_TYPE);
|
||||
(*data)->len = cpu_to_le32(sizeof(*dump) + reg_ids_size);
|
||||
|
||||
dump->version = cpu_to_le32(IWL_INI_DUMP_VER);
|
||||
dump->trigger_id = trigger->trigger_id;
|
||||
dump->is_external_cfg =
|
||||
cpu_to_le32(fwrt->trans->dbg.external_ini_loaded);
|
||||
|
||||
dump->ver_type = cpu_to_le32(fwrt->dump.fw_ver.type);
|
||||
dump->ver_subtype = cpu_to_le32(fwrt->dump.fw_ver.subtype);
|
||||
|
||||
dump->hw_step = cpu_to_le32(CSR_HW_REV_STEP(fwrt->trans->hw_rev));
|
||||
dump->hw_type = cpu_to_le32(CSR_HW_REV_TYPE(fwrt->trans->hw_rev));
|
||||
|
||||
dump->rf_id_flavor =
|
||||
cpu_to_le32(CSR_HW_RFID_FLAVOR(fwrt->trans->hw_rf_id));
|
||||
dump->rf_id_dash = cpu_to_le32(CSR_HW_RFID_DASH(fwrt->trans->hw_rf_id));
|
||||
dump->rf_id_step = cpu_to_le32(CSR_HW_RFID_STEP(fwrt->trans->hw_rf_id));
|
||||
dump->rf_id_type = cpu_to_le32(CSR_HW_RFID_TYPE(fwrt->trans->hw_rf_id));
|
||||
|
||||
dump->lmac_major = cpu_to_le32(fwrt->dump.fw_ver.lmac_major);
|
||||
dump->lmac_minor = cpu_to_le32(fwrt->dump.fw_ver.lmac_minor);
|
||||
dump->umac_major = cpu_to_le32(fwrt->dump.fw_ver.umac_major);
|
||||
dump->umac_minor = cpu_to_le32(fwrt->dump.fw_ver.umac_minor);
|
||||
|
||||
dump->build_tag_len = cpu_to_le32(sizeof(dump->build_tag));
|
||||
memcpy(dump->build_tag, fwrt->fw->human_readable,
|
||||
sizeof(dump->build_tag));
|
||||
|
||||
dump->img_name_len = cpu_to_le32(sizeof(dump->img_name));
|
||||
memcpy(dump->img_name, fwrt->dump.img_name, sizeof(dump->img_name));
|
||||
|
||||
dump->internal_dbg_cfg_name_len =
|
||||
cpu_to_le32(sizeof(dump->internal_dbg_cfg_name));
|
||||
memcpy(dump->internal_dbg_cfg_name, fwrt->dump.internal_dbg_cfg_name,
|
||||
sizeof(dump->internal_dbg_cfg_name));
|
||||
|
||||
dump->external_dbg_cfg_name_len =
|
||||
cpu_to_le32(sizeof(dump->external_dbg_cfg_name));
|
||||
|
||||
/* dump info size is allocated in iwl_fw_ini_get_trigger_len.
|
||||
* The driver allocates (sizeof(*dump) + reg_ids_size) so it is safe to
|
||||
* use reg_ids_size
|
||||
*/
|
||||
memcpy(dump->external_dbg_cfg_name, fwrt->dump.external_dbg_cfg_name,
|
||||
sizeof(dump->external_dbg_cfg_name));
|
||||
|
||||
dump->regions_num = trigger->num_regions;
|
||||
memcpy(dump->region_ids, trigger->data, reg_ids_size);
|
||||
|
||||
*data = iwl_fw_error_next_data(*data);
|
||||
}
|
||||
|
||||
static int iwl_fw_ini_get_trigger_len(struct iwl_fw_runtime *fwrt,
|
||||
struct iwl_fw_ini_trigger *trigger)
|
||||
{
|
||||
int i, size = 0, hdr_len = sizeof(struct iwl_fw_error_dump_data);
|
||||
int i, ret_size = 0, hdr_len = sizeof(struct iwl_fw_error_dump_data);
|
||||
u32 size;
|
||||
|
||||
if (!trigger || !trigger->num_regions)
|
||||
return 0;
|
||||
|
@ -1763,32 +1819,40 @@ static int iwl_fw_ini_get_trigger_len(struct iwl_fw_runtime *fwrt,
|
|||
case IWL_FW_INI_REGION_CSR:
|
||||
case IWL_FW_INI_REGION_LMAC_ERROR_TABLE:
|
||||
case IWL_FW_INI_REGION_UMAC_ERROR_TABLE:
|
||||
size += hdr_len + iwl_dump_ini_mem_get_size(fwrt, reg);
|
||||
size = iwl_dump_ini_mem_get_size(fwrt, reg);
|
||||
if (size)
|
||||
ret_size += hdr_len + size;
|
||||
break;
|
||||
case IWL_FW_INI_REGION_TXF:
|
||||
size += hdr_len + iwl_dump_ini_txf_get_size(fwrt, reg);
|
||||
size = iwl_dump_ini_txf_get_size(fwrt, reg);
|
||||
if (size)
|
||||
ret_size += hdr_len + size;
|
||||
break;
|
||||
case IWL_FW_INI_REGION_RXF:
|
||||
size += hdr_len + iwl_dump_ini_rxf_get_size(fwrt, reg);
|
||||
size = iwl_dump_ini_rxf_get_size(fwrt, reg);
|
||||
if (size)
|
||||
ret_size += hdr_len + size;
|
||||
break;
|
||||
case IWL_FW_INI_REGION_PAGING:
|
||||
size += hdr_len;
|
||||
if (iwl_fw_dbg_is_paging_enabled(fwrt)) {
|
||||
size += iwl_dump_ini_paging_get_size(fwrt, reg);
|
||||
} else {
|
||||
size += iwl_dump_ini_paging_gen2_get_size(fwrt,
|
||||
reg);
|
||||
}
|
||||
if (iwl_fw_dbg_is_paging_enabled(fwrt))
|
||||
size = iwl_dump_ini_paging_get_size(fwrt, reg);
|
||||
else
|
||||
size = iwl_dump_ini_paging_gen2_get_size(fwrt,
|
||||
reg);
|
||||
if (size)
|
||||
ret_size += hdr_len + size;
|
||||
break;
|
||||
case IWL_FW_INI_REGION_DRAM_BUFFER:
|
||||
if (!fwrt->trans->num_blocks)
|
||||
if (!fwrt->trans->dbg.num_blocks)
|
||||
break;
|
||||
size += hdr_len +
|
||||
iwl_dump_ini_mon_dram_get_size(fwrt, reg);
|
||||
size = iwl_dump_ini_mon_dram_get_size(fwrt, reg);
|
||||
if (size)
|
||||
ret_size += hdr_len + size;
|
||||
break;
|
||||
case IWL_FW_INI_REGION_INTERNAL_BUFFER:
|
||||
size += hdr_len +
|
||||
iwl_dump_ini_mon_smem_get_size(fwrt, reg);
|
||||
size = iwl_dump_ini_mon_smem_get_size(fwrt, reg);
|
||||
if (size)
|
||||
ret_size += hdr_len + size;
|
||||
break;
|
||||
case IWL_FW_INI_REGION_DRAM_IMR:
|
||||
/* Undefined yet */
|
||||
|
@ -1796,7 +1860,13 @@ static int iwl_fw_ini_get_trigger_len(struct iwl_fw_runtime *fwrt,
|
|||
break;
|
||||
}
|
||||
}
|
||||
return size;
|
||||
|
||||
/* add dump info size */
|
||||
if (ret_size)
|
||||
ret_size += hdr_len + sizeof(struct iwl_fw_ini_dump_info) +
|
||||
(le32_to_cpu(trigger->num_regions) * sizeof(__le32));
|
||||
|
||||
return ret_size;
|
||||
}
|
||||
|
||||
static void iwl_fw_ini_dump_trigger(struct iwl_fw_runtime *fwrt,
|
||||
|
@ -1805,6 +1875,8 @@ static void iwl_fw_ini_dump_trigger(struct iwl_fw_runtime *fwrt,
|
|||
{
|
||||
int i, num = le32_to_cpu(trigger->num_regions);
|
||||
|
||||
iwl_dump_ini_info(fwrt, trigger, data);
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
u32 reg_id = le32_to_cpu(trigger->data[i]);
|
||||
struct iwl_fw_ini_region_cfg *reg;
|
||||
|
@ -1879,7 +1951,7 @@ static void iwl_fw_ini_dump_trigger(struct iwl_fw_runtime *fwrt,
|
|||
fwrt->dump.fifo_iter = &iter;
|
||||
ops.get_num_of_ranges = iwl_dump_ini_txf_ranges;
|
||||
ops.get_size = iwl_dump_ini_txf_get_size;
|
||||
ops.fill_mem_hdr = iwl_dump_ini_fifo_fill_header;
|
||||
ops.fill_mem_hdr = iwl_dump_ini_mem_fill_header;
|
||||
ops.fill_range = iwl_dump_ini_txf_iter;
|
||||
iwl_dump_ini_mem(fwrt, data, reg, &ops);
|
||||
fwrt->dump.fifo_iter = fifo_iter;
|
||||
|
@ -1888,7 +1960,7 @@ static void iwl_fw_ini_dump_trigger(struct iwl_fw_runtime *fwrt,
|
|||
case IWL_FW_INI_REGION_RXF:
|
||||
ops.get_num_of_ranges = iwl_dump_ini_rxf_ranges;
|
||||
ops.get_size = iwl_dump_ini_rxf_get_size;
|
||||
ops.fill_mem_hdr = iwl_dump_ini_fifo_fill_header;
|
||||
ops.fill_mem_hdr = iwl_dump_ini_mem_fill_header;
|
||||
ops.fill_range = iwl_dump_ini_rxf_iter;
|
||||
iwl_dump_ini_mem(fwrt, data, reg, &ops);
|
||||
break;
|
||||
|
@ -1908,18 +1980,18 @@ static void iwl_fw_ini_dump_trigger(struct iwl_fw_runtime *fwrt,
|
|||
}
|
||||
|
||||
static struct iwl_fw_error_dump_file *
|
||||
iwl_fw_error_ini_dump_file(struct iwl_fw_runtime *fwrt)
|
||||
iwl_fw_error_ini_dump_file(struct iwl_fw_runtime *fwrt,
|
||||
enum iwl_fw_ini_trigger_id trig_id)
|
||||
{
|
||||
int size;
|
||||
struct iwl_fw_error_dump_data *dump_data;
|
||||
struct iwl_fw_error_dump_file *dump_file;
|
||||
struct iwl_fw_ini_trigger *trigger;
|
||||
enum iwl_fw_ini_trigger_id id = fwrt->dump.ini_trig_id;
|
||||
|
||||
if (!iwl_fw_ini_trigger_on(fwrt, id))
|
||||
if (!iwl_fw_ini_trigger_on(fwrt, trig_id))
|
||||
return NULL;
|
||||
|
||||
trigger = fwrt->dump.active_trigs[id].trig;
|
||||
trigger = fwrt->dump.active_trigs[trig_id].trig;
|
||||
|
||||
size = iwl_fw_ini_get_trigger_len(fwrt, trigger);
|
||||
if (!size)
|
||||
|
@ -1931,7 +2003,7 @@ iwl_fw_error_ini_dump_file(struct iwl_fw_runtime *fwrt)
|
|||
if (!dump_file)
|
||||
return NULL;
|
||||
|
||||
dump_file->barker = cpu_to_le32(IWL_FW_ERROR_DUMP_BARKER);
|
||||
dump_file->barker = cpu_to_le32(IWL_FW_INI_ERROR_DUMP_BARKER);
|
||||
dump_data = (void *)dump_file->data;
|
||||
dump_file->file_len = cpu_to_le32(size);
|
||||
|
||||
|
@ -1952,7 +2024,7 @@ static void iwl_fw_error_dump(struct iwl_fw_runtime *fwrt)
|
|||
if (!dump_file)
|
||||
goto out;
|
||||
|
||||
if (!fwrt->trans->ini_valid && fwrt->dump.monitor_only)
|
||||
if (fwrt->dump.monitor_only)
|
||||
dump_mask &= IWL_FW_ERROR_DUMP_FW_MONITOR;
|
||||
|
||||
fw_error_dump.trans_ptr = iwl_trans_dump_data(fwrt->trans, dump_mask);
|
||||
|
@ -1984,16 +2056,16 @@ static void iwl_fw_error_dump(struct iwl_fw_runtime *fwrt)
|
|||
|
||||
out:
|
||||
iwl_fw_free_dump_desc(fwrt);
|
||||
clear_bit(IWL_FWRT_STATUS_DUMPING, &fwrt->status);
|
||||
}
|
||||
|
||||
static void iwl_fw_error_ini_dump(struct iwl_fw_runtime *fwrt)
|
||||
static void iwl_fw_error_ini_dump(struct iwl_fw_runtime *fwrt, u8 wk_idx)
|
||||
{
|
||||
enum iwl_fw_ini_trigger_id trig_id = fwrt->dump.wks[wk_idx].ini_trig_id;
|
||||
struct iwl_fw_error_dump_file *dump_file;
|
||||
struct scatterlist *sg_dump_data;
|
||||
u32 file_len;
|
||||
|
||||
dump_file = iwl_fw_error_ini_dump_file(fwrt);
|
||||
dump_file = iwl_fw_error_ini_dump_file(fwrt, trig_id);
|
||||
if (!dump_file)
|
||||
goto out;
|
||||
|
||||
|
@ -2008,8 +2080,7 @@ static void iwl_fw_error_ini_dump(struct iwl_fw_runtime *fwrt)
|
|||
}
|
||||
vfree(dump_file);
|
||||
out:
|
||||
fwrt->dump.ini_trig_id = IWL_FW_TRIGGER_ID_INVALID;
|
||||
clear_bit(IWL_FWRT_STATUS_DUMPING, &fwrt->status);
|
||||
fwrt->dump.wks[wk_idx].ini_trig_id = IWL_FW_TRIGGER_ID_INVALID;
|
||||
}
|
||||
|
||||
const struct iwl_fw_dump_desc iwl_dump_desc_assert = {
|
||||
|
@ -2027,7 +2098,7 @@ int iwl_fw_dbg_collect_desc(struct iwl_fw_runtime *fwrt,
|
|||
u32 trig_type = le32_to_cpu(desc->trig_desc.type);
|
||||
int ret;
|
||||
|
||||
if (fwrt->trans->ini_valid) {
|
||||
if (fwrt->trans->dbg.ini_valid) {
|
||||
ret = iwl_fw_dbg_ini_collect(fwrt, trig_type);
|
||||
if (!ret)
|
||||
iwl_fw_free_dump_desc(fwrt);
|
||||
|
@ -2035,7 +2106,10 @@ int iwl_fw_dbg_collect_desc(struct iwl_fw_runtime *fwrt,
|
|||
return ret;
|
||||
}
|
||||
|
||||
if (test_and_set_bit(IWL_FWRT_STATUS_DUMPING, &fwrt->status))
|
||||
/* use wks[0] since dump flow prior to ini does not need to support
|
||||
* consecutive triggers collection
|
||||
*/
|
||||
if (test_and_set_bit(fwrt->dump.wks[0].idx, &fwrt->dump.active_wks))
|
||||
return -EBUSY;
|
||||
|
||||
if (WARN_ON(fwrt->dump.desc))
|
||||
|
@ -2047,7 +2121,7 @@ int iwl_fw_dbg_collect_desc(struct iwl_fw_runtime *fwrt,
|
|||
fwrt->dump.desc = desc;
|
||||
fwrt->dump.monitor_only = monitor_only;
|
||||
|
||||
schedule_delayed_work(&fwrt->dump.wk, usecs_to_jiffies(delay));
|
||||
schedule_delayed_work(&fwrt->dump.wks[0].wk, usecs_to_jiffies(delay));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -2057,9 +2131,12 @@ int iwl_fw_dbg_error_collect(struct iwl_fw_runtime *fwrt,
|
|||
enum iwl_fw_dbg_trigger trig_type)
|
||||
{
|
||||
int ret;
|
||||
struct iwl_fw_dump_desc *iwl_dump_error_desc =
|
||||
kmalloc(sizeof(*iwl_dump_error_desc), GFP_KERNEL);
|
||||
struct iwl_fw_dump_desc *iwl_dump_error_desc;
|
||||
|
||||
if (!test_bit(STATUS_DEVICE_ENABLED, &fwrt->trans->status))
|
||||
return -EIO;
|
||||
|
||||
iwl_dump_error_desc = kmalloc(sizeof(*iwl_dump_error_desc), GFP_KERNEL);
|
||||
if (!iwl_dump_error_desc)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -2123,13 +2200,11 @@ int _iwl_fw_dbg_ini_collect(struct iwl_fw_runtime *fwrt,
|
|||
{
|
||||
struct iwl_fw_ini_active_triggers *active;
|
||||
u32 occur, delay;
|
||||
unsigned long idx;
|
||||
|
||||
if (WARN_ON(!iwl_fw_ini_trigger_on(fwrt, id)))
|
||||
return -EINVAL;
|
||||
|
||||
if (test_and_set_bit(IWL_FWRT_STATUS_DUMPING, &fwrt->status))
|
||||
return -EBUSY;
|
||||
|
||||
if (!iwl_fw_ini_trigger_on(fwrt, id)) {
|
||||
IWL_WARN(fwrt, "WRT: Trigger %d is not active, aborting dump\n",
|
||||
id);
|
||||
|
@ -2150,14 +2225,24 @@ int _iwl_fw_dbg_ini_collect(struct iwl_fw_runtime *fwrt,
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (test_and_set_bit(IWL_FWRT_STATUS_DUMPING, &fwrt->status))
|
||||
/* Check there is an available worker.
|
||||
* ffz return value is undefined if no zero exists,
|
||||
* so check against ~0UL first.
|
||||
*/
|
||||
if (fwrt->dump.active_wks == ~0UL)
|
||||
return -EBUSY;
|
||||
|
||||
fwrt->dump.ini_trig_id = id;
|
||||
idx = ffz(fwrt->dump.active_wks);
|
||||
|
||||
if (idx >= IWL_FW_RUNTIME_DUMP_WK_NUM ||
|
||||
test_and_set_bit(fwrt->dump.wks[idx].idx, &fwrt->dump.active_wks))
|
||||
return -EBUSY;
|
||||
|
||||
fwrt->dump.wks[idx].ini_trig_id = id;
|
||||
|
||||
IWL_WARN(fwrt, "WRT: collecting data: ini trigger %d fired.\n", id);
|
||||
|
||||
schedule_delayed_work(&fwrt->dump.wk, usecs_to_jiffies(delay));
|
||||
schedule_delayed_work(&fwrt->dump.wks[idx].wk, usecs_to_jiffies(delay));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -2191,9 +2276,6 @@ int iwl_fw_dbg_collect_trig(struct iwl_fw_runtime *fwrt,
|
|||
int ret, len = 0;
|
||||
char buf[64];
|
||||
|
||||
if (fwrt->trans->ini_valid)
|
||||
return 0;
|
||||
|
||||
if (fmt) {
|
||||
va_list ap;
|
||||
|
||||
|
@ -2270,56 +2352,57 @@ IWL_EXPORT_SYMBOL(iwl_fw_start_dbg_conf);
|
|||
/* this function assumes dump_start was called beforehand and dump_end will be
|
||||
* called afterwards
|
||||
*/
|
||||
void iwl_fw_dbg_collect_sync(struct iwl_fw_runtime *fwrt)
|
||||
static void iwl_fw_dbg_collect_sync(struct iwl_fw_runtime *fwrt, u8 wk_idx)
|
||||
{
|
||||
struct iwl_fw_dbg_params params = {0};
|
||||
|
||||
if (!test_bit(IWL_FWRT_STATUS_DUMPING, &fwrt->status))
|
||||
if (!test_bit(wk_idx, &fwrt->dump.active_wks))
|
||||
return;
|
||||
|
||||
if (fwrt->ops && fwrt->ops->fw_running &&
|
||||
!fwrt->ops->fw_running(fwrt->ops_ctx)) {
|
||||
IWL_ERR(fwrt, "Firmware not running - cannot dump error\n");
|
||||
iwl_fw_free_dump_desc(fwrt);
|
||||
clear_bit(IWL_FWRT_STATUS_DUMPING, &fwrt->status);
|
||||
return;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* 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");
|
||||
return;
|
||||
goto out;
|
||||
}
|
||||
|
||||
iwl_fw_dbg_stop_recording(fwrt, ¶ms);
|
||||
iwl_fw_dbg_stop_recording(fwrt->trans, ¶ms);
|
||||
|
||||
IWL_DEBUG_FW_INFO(fwrt, "WRT: data collection start\n");
|
||||
if (fwrt->trans->ini_valid)
|
||||
iwl_fw_error_ini_dump(fwrt);
|
||||
if (fwrt->trans->dbg.ini_valid)
|
||||
iwl_fw_error_ini_dump(fwrt, wk_idx);
|
||||
else
|
||||
iwl_fw_error_dump(fwrt);
|
||||
IWL_DEBUG_FW_INFO(fwrt, "WRT: data collection done\n");
|
||||
|
||||
/* start recording again if the firmware is not crashed */
|
||||
if (!test_bit(STATUS_FW_ERROR, &fwrt->trans->status) &&
|
||||
fwrt->fw->dbg.dest_tlv) {
|
||||
/* wait before we collect the data till the DBGC stop */
|
||||
udelay(500);
|
||||
iwl_fw_dbg_restart_recording(fwrt, ¶ms);
|
||||
}
|
||||
iwl_fw_dbg_restart_recording(fwrt, ¶ms);
|
||||
|
||||
out:
|
||||
clear_bit(wk_idx, &fwrt->dump.active_wks);
|
||||
}
|
||||
IWL_EXPORT_SYMBOL(iwl_fw_dbg_collect_sync);
|
||||
|
||||
void iwl_fw_error_dump_wk(struct work_struct *work)
|
||||
{
|
||||
struct iwl_fw_runtime *fwrt =
|
||||
container_of(work, struct iwl_fw_runtime, dump.wk.work);
|
||||
struct iwl_fw_runtime *fwrt;
|
||||
typeof(fwrt->dump.wks[0]) *wks;
|
||||
|
||||
wks = container_of(work, typeof(fwrt->dump.wks[0]), wk.work);
|
||||
fwrt = container_of(wks, struct iwl_fw_runtime, dump.wks[wks->idx]);
|
||||
|
||||
/* assumes the op mode mutex is locked in dump_start since
|
||||
* iwl_fw_dbg_collect_sync can't run in parallel
|
||||
*/
|
||||
if (fwrt->ops && fwrt->ops->dump_start &&
|
||||
fwrt->ops->dump_start(fwrt->ops_ctx))
|
||||
return;
|
||||
|
||||
iwl_fw_dbg_collect_sync(fwrt);
|
||||
iwl_fw_dbg_collect_sync(fwrt, wks->idx);
|
||||
|
||||
if (fwrt->ops && fwrt->ops->dump_end)
|
||||
fwrt->ops->dump_end(fwrt->ops_ctx);
|
||||
|
@ -2349,6 +2432,38 @@ void iwl_fw_dbg_read_d3_debug_data(struct iwl_fw_runtime *fwrt)
|
|||
}
|
||||
IWL_EXPORT_SYMBOL(iwl_fw_dbg_read_d3_debug_data);
|
||||
|
||||
static void iwl_fw_dbg_info_apply(struct iwl_fw_runtime *fwrt,
|
||||
struct iwl_fw_ini_debug_info_tlv *dbg_info,
|
||||
bool ext, enum iwl_fw_ini_apply_point pnt)
|
||||
{
|
||||
u32 img_name_len = le32_to_cpu(dbg_info->img_name_len);
|
||||
u32 dbg_cfg_name_len = le32_to_cpu(dbg_info->dbg_cfg_name_len);
|
||||
const char err_str[] =
|
||||
"WRT: ext=%d. Invalid %s name length %d, expected %d\n";
|
||||
|
||||
if (img_name_len != IWL_FW_INI_MAX_IMG_NAME_LEN) {
|
||||
IWL_WARN(fwrt, err_str, ext, "image", img_name_len,
|
||||
IWL_FW_INI_MAX_IMG_NAME_LEN);
|
||||
return;
|
||||
}
|
||||
|
||||
if (dbg_cfg_name_len != IWL_FW_INI_MAX_DBG_CFG_NAME_LEN) {
|
||||
IWL_WARN(fwrt, err_str, ext, "debug cfg", dbg_cfg_name_len,
|
||||
IWL_FW_INI_MAX_DBG_CFG_NAME_LEN);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ext) {
|
||||
memcpy(fwrt->dump.external_dbg_cfg_name, dbg_info->dbg_cfg_name,
|
||||
sizeof(fwrt->dump.external_dbg_cfg_name));
|
||||
} else {
|
||||
memcpy(fwrt->dump.img_name, dbg_info->img_name,
|
||||
sizeof(fwrt->dump.img_name));
|
||||
memcpy(fwrt->dump.internal_dbg_cfg_name, dbg_info->dbg_cfg_name,
|
||||
sizeof(fwrt->dump.internal_dbg_cfg_name));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
iwl_fw_dbg_buffer_allocation(struct iwl_fw_runtime *fwrt, u32 size)
|
||||
{
|
||||
|
@ -2356,7 +2471,8 @@ iwl_fw_dbg_buffer_allocation(struct iwl_fw_runtime *fwrt, u32 size)
|
|||
void *virtual_addr = NULL;
|
||||
dma_addr_t phys_addr;
|
||||
|
||||
if (WARN_ON_ONCE(trans->num_blocks == ARRAY_SIZE(trans->fw_mon)))
|
||||
if (WARN_ON_ONCE(trans->dbg.num_blocks ==
|
||||
ARRAY_SIZE(trans->dbg.fw_mon)))
|
||||
return;
|
||||
|
||||
virtual_addr =
|
||||
|
@ -2370,12 +2486,12 @@ iwl_fw_dbg_buffer_allocation(struct iwl_fw_runtime *fwrt, u32 size)
|
|||
|
||||
IWL_DEBUG_FW(trans,
|
||||
"Allocated DRAM buffer[%d], size=0x%x\n",
|
||||
trans->num_blocks, size);
|
||||
trans->dbg.num_blocks, size);
|
||||
|
||||
trans->fw_mon[trans->num_blocks].block = virtual_addr;
|
||||
trans->fw_mon[trans->num_blocks].physical = phys_addr;
|
||||
trans->fw_mon[trans->num_blocks].size = size;
|
||||
trans->num_blocks++;
|
||||
trans->dbg.fw_mon[trans->dbg.num_blocks].block = virtual_addr;
|
||||
trans->dbg.fw_mon[trans->dbg.num_blocks].physical = phys_addr;
|
||||
trans->dbg.fw_mon[trans->dbg.num_blocks].size = size;
|
||||
trans->dbg.num_blocks++;
|
||||
}
|
||||
|
||||
static void iwl_fw_dbg_buffer_apply(struct iwl_fw_runtime *fwrt,
|
||||
|
@ -2393,20 +2509,26 @@ static void iwl_fw_dbg_buffer_apply(struct iwl_fw_runtime *fwrt,
|
|||
.data[0] = &ldbg_cmd,
|
||||
.len[0] = sizeof(ldbg_cmd),
|
||||
};
|
||||
int block_idx = trans->num_blocks;
|
||||
int block_idx = trans->dbg.num_blocks;
|
||||
u32 buf_location = le32_to_cpu(alloc->tlv.buffer_location);
|
||||
|
||||
if (buf_location == IWL_FW_INI_LOCATION_SRAM_PATH) {
|
||||
if (!WARN(pnt != IWL_FW_INI_APPLY_EARLY,
|
||||
"WRT: Invalid apply point %d for SMEM buffer allocation, aborting\n",
|
||||
pnt)) {
|
||||
IWL_DEBUG_FW(trans,
|
||||
"WRT: applying SMEM buffer destination\n");
|
||||
if (fwrt->trans->dbg.ini_dest == IWL_FW_INI_LOCATION_INVALID)
|
||||
fwrt->trans->dbg.ini_dest = buf_location;
|
||||
|
||||
if (buf_location != fwrt->trans->dbg.ini_dest) {
|
||||
WARN(fwrt,
|
||||
"WRT: attempt to override buffer location on apply point %d\n",
|
||||
pnt);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (buf_location == IWL_FW_INI_LOCATION_SRAM_PATH) {
|
||||
IWL_DEBUG_FW(trans, "WRT: applying SMEM buffer destination\n");
|
||||
/* set sram monitor by enabling bit 7 */
|
||||
iwl_set_bit(fwrt->trans, CSR_HW_IF_CONFIG_REG,
|
||||
CSR_HW_IF_CONFIG_REG_BIT_MONITOR_SRAM);
|
||||
|
||||
/* set sram monitor by enabling bit 7 */
|
||||
iwl_set_bit(fwrt->trans, CSR_HW_IF_CONFIG_REG,
|
||||
CSR_HW_IF_CONFIG_REG_BIT_MONITOR_SRAM);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -2416,13 +2538,13 @@ static void iwl_fw_dbg_buffer_apply(struct iwl_fw_runtime *fwrt,
|
|||
if (!alloc->is_alloc) {
|
||||
iwl_fw_dbg_buffer_allocation(fwrt,
|
||||
le32_to_cpu(alloc->tlv.size));
|
||||
if (block_idx == trans->num_blocks)
|
||||
if (block_idx == trans->dbg.num_blocks)
|
||||
return;
|
||||
alloc->is_alloc = 1;
|
||||
}
|
||||
|
||||
/* First block is assigned via registers / context info */
|
||||
if (trans->num_blocks == 1)
|
||||
if (trans->dbg.num_blocks == 1)
|
||||
return;
|
||||
|
||||
IWL_DEBUG_FW(trans,
|
||||
|
@ -2430,7 +2552,7 @@ static void iwl_fw_dbg_buffer_apply(struct iwl_fw_runtime *fwrt,
|
|||
|
||||
cmd->num_frags = cpu_to_le32(1);
|
||||
cmd->fragments[0].address =
|
||||
cpu_to_le64(trans->fw_mon[block_idx].physical);
|
||||
cpu_to_le64(trans->dbg.fw_mon[block_idx].physical);
|
||||
cmd->fragments[0].size = alloc->tlv.size;
|
||||
cmd->allocation_id = alloc->tlv.allocation_id;
|
||||
cmd->buffer_location = alloc->tlv.buffer_location;
|
||||
|
@ -2653,20 +2775,30 @@ static void _iwl_fw_dbg_apply_point(struct iwl_fw_runtime *fwrt,
|
|||
struct iwl_ucode_tlv *tlv = iter;
|
||||
void *ini_tlv = (void *)tlv->data;
|
||||
u32 type = le32_to_cpu(tlv->type);
|
||||
const char invalid_ap_str[] =
|
||||
"WRT: ext=%d. Invalid apply point %d for %s\n";
|
||||
|
||||
switch (type) {
|
||||
case IWL_UCODE_TLV_TYPE_DEBUG_INFO:
|
||||
iwl_fw_dbg_info_apply(fwrt, ini_tlv, ext, pnt);
|
||||
break;
|
||||
case IWL_UCODE_TLV_TYPE_BUFFER_ALLOCATION: {
|
||||
struct iwl_fw_ini_allocation_data *buf_alloc = ini_tlv;
|
||||
|
||||
if (pnt != IWL_FW_INI_APPLY_EARLY) {
|
||||
IWL_ERR(fwrt, invalid_ap_str, ext, pnt,
|
||||
"buffer allocation");
|
||||
goto next;
|
||||
}
|
||||
|
||||
iwl_fw_dbg_buffer_apply(fwrt, ini_tlv, pnt);
|
||||
iter += sizeof(buf_alloc->is_alloc);
|
||||
break;
|
||||
}
|
||||
case IWL_UCODE_TLV_TYPE_HCMD:
|
||||
if (pnt < IWL_FW_INI_APPLY_AFTER_ALIVE) {
|
||||
IWL_ERR(fwrt,
|
||||
"WRT: ext=%d. Invalid apply point %d for host command\n",
|
||||
ext, pnt);
|
||||
IWL_ERR(fwrt, invalid_ap_str, ext, pnt,
|
||||
"host command");
|
||||
goto next;
|
||||
}
|
||||
iwl_fw_dbg_send_hcmd(fwrt, tlv, ext);
|
||||
|
@ -2690,34 +2822,51 @@ static void _iwl_fw_dbg_apply_point(struct iwl_fw_runtime *fwrt,
|
|||
}
|
||||
}
|
||||
|
||||
static void iwl_fw_dbg_ini_reset_cfg(struct iwl_fw_runtime *fwrt)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < IWL_FW_INI_MAX_REGION_ID; i++)
|
||||
fwrt->dump.active_regs[i] = NULL;
|
||||
|
||||
/* disable the triggers, used in recovery flow */
|
||||
for (i = 0; i < IWL_FW_TRIGGER_ID_NUM; i++)
|
||||
fwrt->dump.active_trigs[i].active = false;
|
||||
|
||||
memset(fwrt->dump.img_name, 0,
|
||||
sizeof(fwrt->dump.img_name));
|
||||
memset(fwrt->dump.internal_dbg_cfg_name, 0,
|
||||
sizeof(fwrt->dump.internal_dbg_cfg_name));
|
||||
memset(fwrt->dump.external_dbg_cfg_name, 0,
|
||||
sizeof(fwrt->dump.external_dbg_cfg_name));
|
||||
|
||||
fwrt->trans->dbg.ini_dest = IWL_FW_INI_LOCATION_INVALID;
|
||||
}
|
||||
|
||||
void iwl_fw_dbg_apply_point(struct iwl_fw_runtime *fwrt,
|
||||
enum iwl_fw_ini_apply_point apply_point)
|
||||
{
|
||||
void *data = &fwrt->trans->apply_points[apply_point];
|
||||
int i;
|
||||
void *data = &fwrt->trans->dbg.apply_points[apply_point];
|
||||
|
||||
IWL_DEBUG_FW(fwrt, "WRT: enabling apply point %d\n", apply_point);
|
||||
|
||||
if (apply_point == IWL_FW_INI_APPLY_EARLY) {
|
||||
for (i = 0; i < IWL_FW_INI_MAX_REGION_ID; i++)
|
||||
fwrt->dump.active_regs[i] = NULL;
|
||||
|
||||
/* disable the triggers, used in recovery flow */
|
||||
for (i = 0; i < IWL_FW_TRIGGER_ID_NUM; i++)
|
||||
fwrt->dump.active_trigs[i].active = false;
|
||||
}
|
||||
if (apply_point == IWL_FW_INI_APPLY_EARLY)
|
||||
iwl_fw_dbg_ini_reset_cfg(fwrt);
|
||||
|
||||
_iwl_fw_dbg_apply_point(fwrt, data, apply_point, false);
|
||||
|
||||
data = &fwrt->trans->apply_points_ext[apply_point];
|
||||
data = &fwrt->trans->dbg.apply_points_ext[apply_point];
|
||||
_iwl_fw_dbg_apply_point(fwrt, data, apply_point, true);
|
||||
}
|
||||
IWL_EXPORT_SYMBOL(iwl_fw_dbg_apply_point);
|
||||
|
||||
void iwl_fwrt_stop_device(struct iwl_fw_runtime *fwrt)
|
||||
{
|
||||
int i;
|
||||
|
||||
del_timer(&fwrt->dump.periodic_trig);
|
||||
iwl_fw_dbg_collect_sync(fwrt);
|
||||
for (i = 0; i < IWL_FW_RUNTIME_DUMP_WK_NUM; i++)
|
||||
iwl_fw_dbg_collect_sync(fwrt, i);
|
||||
|
||||
iwl_trans_stop_device(fwrt->trans);
|
||||
}
|
||||
|
|
|
@ -73,6 +73,7 @@
|
|||
#include "error-dump.h"
|
||||
#include "api/commands.h"
|
||||
#include "api/dbg-tlv.h"
|
||||
#include "api/alive.h"
|
||||
|
||||
/**
|
||||
* struct iwl_fw_dump_desc - describes the dump
|
||||
|
@ -201,7 +202,7 @@ _iwl_fw_dbg_trigger_on(struct iwl_fw_runtime *fwrt,
|
|||
{
|
||||
struct iwl_fw_dbg_trigger_tlv *trig;
|
||||
|
||||
if (fwrt->trans->ini_valid)
|
||||
if (fwrt->trans->dbg.ini_valid)
|
||||
return NULL;
|
||||
|
||||
if (!iwl_fw_dbg_trigger_enabled(fwrt->fw, id))
|
||||
|
@ -228,7 +229,7 @@ iwl_fw_ini_trigger_on(struct iwl_fw_runtime *fwrt,
|
|||
struct iwl_fw_ini_trigger *trig;
|
||||
u32 usec;
|
||||
|
||||
if (!fwrt->trans->ini_valid || id == IWL_FW_TRIGGER_ID_INVALID ||
|
||||
if (!fwrt->trans->dbg.ini_valid || id == IWL_FW_TRIGGER_ID_INVALID ||
|
||||
id >= IWL_FW_TRIGGER_ID_NUM || !fwrt->dump.active_trigs[id].active)
|
||||
return false;
|
||||
|
||||
|
@ -262,23 +263,6 @@ _iwl_fw_dbg_trigger_simple_stop(struct iwl_fw_runtime *fwrt,
|
|||
iwl_fw_dbg_get_trigger((fwrt)->fw,\
|
||||
(trig)))
|
||||
|
||||
static inline int
|
||||
iwl_fw_dbg_start_stop_hcmd(struct iwl_fw_runtime *fwrt, bool start)
|
||||
{
|
||||
struct iwl_ldbg_config_cmd cmd = {
|
||||
.type = start ? cpu_to_le32(START_DEBUG_RECORDING) :
|
||||
cpu_to_le32(STOP_DEBUG_RECORDING),
|
||||
};
|
||||
struct iwl_host_cmd hcmd = {
|
||||
.id = LDBG_CONFIG_CMD,
|
||||
.flags = CMD_ASYNC,
|
||||
.data[0] = &cmd,
|
||||
.len[0] = sizeof(cmd),
|
||||
};
|
||||
|
||||
return iwl_trans_send_cmd(fwrt->trans, &hcmd);
|
||||
}
|
||||
|
||||
static inline void
|
||||
_iwl_fw_dbg_stop_recording(struct iwl_trans *trans,
|
||||
struct iwl_fw_dbg_params *params)
|
||||
|
@ -294,21 +278,35 @@ _iwl_fw_dbg_stop_recording(struct iwl_trans *trans,
|
|||
}
|
||||
|
||||
iwl_write_umac_prph(trans, DBGC_IN_SAMPLE, 0);
|
||||
udelay(100);
|
||||
/* wait for the DBGC to finish writing the internal buffer to DRAM to
|
||||
* avoid halting the HW while writing
|
||||
*/
|
||||
usleep_range(700, 1000);
|
||||
iwl_write_umac_prph(trans, DBGC_OUT_CTRL, 0);
|
||||
#ifdef CONFIG_IWLWIFI_DEBUGFS
|
||||
trans->dbg_rec_on = false;
|
||||
trans->dbg.rec_on = false;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void
|
||||
iwl_fw_dbg_stop_recording(struct iwl_fw_runtime *fwrt,
|
||||
iwl_fw_dbg_stop_recording(struct iwl_trans *trans,
|
||||
struct iwl_fw_dbg_params *params)
|
||||
{
|
||||
if (fwrt->trans->cfg->device_family < IWL_DEVICE_FAMILY_22560)
|
||||
_iwl_fw_dbg_stop_recording(fwrt->trans, params);
|
||||
else
|
||||
iwl_fw_dbg_start_stop_hcmd(fwrt, false);
|
||||
/* if the FW crashed or not debug monitor cfg was given, there is
|
||||
* no point in stopping
|
||||
*/
|
||||
if (test_bit(STATUS_FW_ERROR, &trans->status) ||
|
||||
(!trans->dbg.dest_tlv &&
|
||||
trans->dbg.ini_dest == IWL_FW_INI_LOCATION_INVALID))
|
||||
return;
|
||||
|
||||
if (trans->cfg->device_family >= IWL_DEVICE_FAMILY_22560) {
|
||||
IWL_ERR(trans,
|
||||
"WRT: unsupported device family %d for debug stop recording\n",
|
||||
trans->cfg->device_family);
|
||||
return;
|
||||
}
|
||||
_iwl_fw_dbg_stop_recording(trans, params);
|
||||
}
|
||||
|
||||
static inline void
|
||||
|
@ -324,7 +322,6 @@ _iwl_fw_dbg_restart_recording(struct iwl_trans *trans,
|
|||
iwl_set_bits_prph(trans, MON_BUFF_SAMPLE_CTL, 0x1);
|
||||
} else {
|
||||
iwl_write_umac_prph(trans, DBGC_IN_SAMPLE, params->in_sample);
|
||||
udelay(100);
|
||||
iwl_write_umac_prph(trans, DBGC_OUT_CTRL, params->out_ctrl);
|
||||
}
|
||||
}
|
||||
|
@ -332,8 +329,10 @@ _iwl_fw_dbg_restart_recording(struct iwl_trans *trans,
|
|||
#ifdef CONFIG_IWLWIFI_DEBUGFS
|
||||
static inline void iwl_fw_set_dbg_rec_on(struct iwl_fw_runtime *fwrt)
|
||||
{
|
||||
if (fwrt->fw->dbg.dest_tlv && fwrt->cur_fw_img == IWL_UCODE_REGULAR)
|
||||
fwrt->trans->dbg_rec_on = true;
|
||||
if (fwrt->cur_fw_img == IWL_UCODE_REGULAR &&
|
||||
(fwrt->fw->dbg.dest_tlv ||
|
||||
fwrt->trans->dbg.ini_dest != IWL_FW_INI_LOCATION_INVALID))
|
||||
fwrt->trans->dbg.rec_on = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -341,10 +340,21 @@ static inline void
|
|||
iwl_fw_dbg_restart_recording(struct iwl_fw_runtime *fwrt,
|
||||
struct iwl_fw_dbg_params *params)
|
||||
{
|
||||
if (fwrt->trans->cfg->device_family < IWL_DEVICE_FAMILY_22560)
|
||||
_iwl_fw_dbg_restart_recording(fwrt->trans, params);
|
||||
else
|
||||
iwl_fw_dbg_start_stop_hcmd(fwrt, true);
|
||||
/* if the FW crashed or not debug monitor cfg was given, there is
|
||||
* no point in restarting
|
||||
*/
|
||||
if (test_bit(STATUS_FW_ERROR, &fwrt->trans->status) ||
|
||||
(!fwrt->trans->dbg.dest_tlv &&
|
||||
fwrt->trans->dbg.ini_dest == IWL_FW_INI_LOCATION_INVALID))
|
||||
return;
|
||||
|
||||
if (fwrt->trans->cfg->device_family >= IWL_DEVICE_FAMILY_22560) {
|
||||
IWL_ERR(fwrt,
|
||||
"WRT: unsupported device family %d for debug restart recording\n",
|
||||
fwrt->trans->cfg->device_family);
|
||||
return;
|
||||
}
|
||||
_iwl_fw_dbg_restart_recording(fwrt->trans, params);
|
||||
#ifdef CONFIG_IWLWIFI_DEBUGFS
|
||||
iwl_fw_set_dbg_rec_on(fwrt);
|
||||
#endif
|
||||
|
@ -359,7 +369,7 @@ void iwl_fw_error_dump_wk(struct work_struct *work);
|
|||
|
||||
static inline bool iwl_fw_dbg_type_on(struct iwl_fw_runtime *fwrt, u32 type)
|
||||
{
|
||||
return (fwrt->fw->dbg.dump_mask & BIT(type) || fwrt->trans->ini_valid);
|
||||
return (fwrt->fw->dbg.dump_mask & BIT(type));
|
||||
}
|
||||
|
||||
static inline bool iwl_fw_dbg_is_d3_debug_enabled(struct iwl_fw_runtime *fwrt)
|
||||
|
@ -383,16 +393,26 @@ static inline bool iwl_fw_dbg_is_paging_enabled(struct iwl_fw_runtime *fwrt)
|
|||
|
||||
void iwl_fw_dbg_read_d3_debug_data(struct iwl_fw_runtime *fwrt);
|
||||
|
||||
static inline void iwl_fw_flush_dump(struct iwl_fw_runtime *fwrt)
|
||||
static inline void iwl_fw_flush_dumps(struct iwl_fw_runtime *fwrt)
|
||||
{
|
||||
int i;
|
||||
|
||||
del_timer(&fwrt->dump.periodic_trig);
|
||||
flush_delayed_work(&fwrt->dump.wk);
|
||||
for (i = 0; i < IWL_FW_RUNTIME_DUMP_WK_NUM; i++) {
|
||||
flush_delayed_work(&fwrt->dump.wks[i].wk);
|
||||
fwrt->dump.wks[i].ini_trig_id = IWL_FW_TRIGGER_ID_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void iwl_fw_cancel_dump(struct iwl_fw_runtime *fwrt)
|
||||
static inline void iwl_fw_cancel_dumps(struct iwl_fw_runtime *fwrt)
|
||||
{
|
||||
int i;
|
||||
|
||||
del_timer(&fwrt->dump.periodic_trig);
|
||||
cancel_delayed_work_sync(&fwrt->dump.wk);
|
||||
for (i = 0; i < IWL_FW_RUNTIME_DUMP_WK_NUM; i++) {
|
||||
cancel_delayed_work_sync(&fwrt->dump.wks[i].wk);
|
||||
fwrt->dump.wks[i].ini_trig_id = IWL_FW_TRIGGER_ID_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IWLWIFI_DEBUGFS
|
||||
|
@ -431,7 +451,6 @@ static inline void iwl_fw_resume_timestamp(struct iwl_fw_runtime *fwrt) {}
|
|||
|
||||
#endif /* CONFIG_IWLWIFI_DEBUGFS */
|
||||
|
||||
void iwl_fw_dbg_collect_sync(struct iwl_fw_runtime *fwrt);
|
||||
void iwl_fw_dbg_apply_point(struct iwl_fw_runtime *fwrt,
|
||||
enum iwl_fw_ini_apply_point apply_point);
|
||||
|
||||
|
@ -440,31 +459,28 @@ void iwl_fwrt_stop_device(struct iwl_fw_runtime *fwrt);
|
|||
static inline void iwl_fw_lmac1_set_alive_err_table(struct iwl_trans *trans,
|
||||
u32 lmac_error_event_table)
|
||||
{
|
||||
if (!(trans->error_event_table_tlv_status &
|
||||
if (!(trans->dbg.error_event_table_tlv_status &
|
||||
IWL_ERROR_EVENT_TABLE_LMAC1) ||
|
||||
WARN_ON(trans->lmac_error_event_table[0] !=
|
||||
WARN_ON(trans->dbg.lmac_error_event_table[0] !=
|
||||
lmac_error_event_table))
|
||||
trans->lmac_error_event_table[0] = lmac_error_event_table;
|
||||
trans->dbg.lmac_error_event_table[0] = lmac_error_event_table;
|
||||
}
|
||||
|
||||
static inline void iwl_fw_umac_set_alive_err_table(struct iwl_trans *trans,
|
||||
u32 umac_error_event_table)
|
||||
{
|
||||
if (!(trans->error_event_table_tlv_status &
|
||||
if (!(trans->dbg.error_event_table_tlv_status &
|
||||
IWL_ERROR_EVENT_TABLE_UMAC) ||
|
||||
WARN_ON(trans->umac_error_event_table !=
|
||||
WARN_ON(trans->dbg.umac_error_event_table !=
|
||||
umac_error_event_table))
|
||||
trans->umac_error_event_table = umac_error_event_table;
|
||||
trans->dbg.umac_error_event_table = umac_error_event_table;
|
||||
}
|
||||
|
||||
/* This bit is used to differentiate the legacy dump from the ini dump */
|
||||
#define INI_DUMP_BIT BIT(31)
|
||||
|
||||
static inline void iwl_fw_error_collect(struct iwl_fw_runtime *fwrt)
|
||||
{
|
||||
if (fwrt->trans->ini_valid && fwrt->trans->hw_error) {
|
||||
if (fwrt->trans->dbg.ini_valid && fwrt->trans->dbg.hw_error) {
|
||||
_iwl_fw_dbg_ini_collect(fwrt, IWL_FW_TRIGGER_ID_FW_HW_ERROR);
|
||||
fwrt->trans->hw_error = false;
|
||||
fwrt->trans->dbg.hw_error = false;
|
||||
} else {
|
||||
iwl_fw_dbg_collect_desc(fwrt, &iwl_dump_desc_assert, false, 0);
|
||||
}
|
||||
|
@ -473,4 +489,21 @@ static inline void iwl_fw_error_collect(struct iwl_fw_runtime *fwrt)
|
|||
void iwl_fw_dbg_periodic_trig_handler(struct timer_list *t);
|
||||
|
||||
void iwl_fw_error_print_fseq_regs(struct iwl_fw_runtime *fwrt);
|
||||
|
||||
static inline void iwl_fwrt_update_fw_versions(struct iwl_fw_runtime *fwrt,
|
||||
struct iwl_lmac_alive *lmac,
|
||||
struct iwl_umac_alive *umac)
|
||||
{
|
||||
if (lmac) {
|
||||
fwrt->dump.fw_ver.type = lmac->ver_type;
|
||||
fwrt->dump.fw_ver.subtype = lmac->ver_subtype;
|
||||
fwrt->dump.fw_ver.lmac_major = le32_to_cpu(lmac->ucode_major);
|
||||
fwrt->dump.fw_ver.lmac_minor = le32_to_cpu(lmac->ucode_minor);
|
||||
}
|
||||
|
||||
if (umac) {
|
||||
fwrt->dump.fw_ver.umac_major = le32_to_cpu(umac->umac_major);
|
||||
fwrt->dump.fw_ver.umac_minor = le32_to_cpu(umac->umac_minor);
|
||||
}
|
||||
}
|
||||
#endif /* __iwl_fw_dbg_h__ */
|
||||
|
|
|
@ -67,6 +67,7 @@
|
|||
#include <linux/types.h>
|
||||
|
||||
#define IWL_FW_ERROR_DUMP_BARKER 0x14789632
|
||||
#define IWL_FW_INI_ERROR_DUMP_BARKER 0x14789633
|
||||
|
||||
/**
|
||||
* enum iwl_fw_error_dump_type - types of data in the dump file
|
||||
|
@ -278,19 +279,42 @@ struct iwl_fw_error_dump_mem {
|
|||
u8 data[];
|
||||
};
|
||||
|
||||
#define IWL_INI_DUMP_MEM_VER 1
|
||||
#define IWL_INI_DUMP_MONITOR_VER 1
|
||||
#define IWL_INI_DUMP_FIFO_VER 1
|
||||
/* Dump version, used by the dump parser to differentiate between
|
||||
* different dump formats
|
||||
*/
|
||||
#define IWL_INI_DUMP_VER 1
|
||||
|
||||
/* Use bit 31 as dump info type to avoid colliding with region types */
|
||||
#define IWL_INI_DUMP_INFO_TYPE BIT(31)
|
||||
|
||||
/**
|
||||
* struct iwl_fw_ini_fifo_hdr - fifo range header
|
||||
* @fifo_num: the fifo number. In case of umac rx fifo, set BIT(31) to
|
||||
* distinguish between lmac and umac rx fifos
|
||||
* @num_of_registers: num of registers to dump, dword size each
|
||||
*/
|
||||
struct iwl_fw_ini_fifo_hdr {
|
||||
__le32 fifo_num;
|
||||
__le32 num_of_registers;
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
* struct iwl_fw_ini_error_dump_range - range of memory
|
||||
* @range_data_size: the size of this range, in bytes
|
||||
* @start_addr: the start address of this range
|
||||
* @internal_base_addr - base address of internal memory range
|
||||
* @dram_base_addr - base address of dram monitor range
|
||||
* @page_num - page number of memory range
|
||||
* @fifo_hdr - fifo header of memory range
|
||||
* @data: the actual memory
|
||||
*/
|
||||
struct iwl_fw_ini_error_dump_range {
|
||||
__le32 range_data_size;
|
||||
__le64 start_addr;
|
||||
union {
|
||||
__le32 internal_base_addr;
|
||||
__le64 dram_base_addr;
|
||||
__le32 page_num;
|
||||
struct iwl_fw_ini_fifo_hdr fifo_hdr;
|
||||
};
|
||||
__le32 data[];
|
||||
} __packed;
|
||||
|
||||
|
@ -333,30 +357,63 @@ struct iwl_fw_ini_error_dump_register {
|
|||
__le32 data;
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
* struct iwl_fw_ini_fifo_error_dump_range - ini fifo range dump
|
||||
* @fifo_num: the fifo num. In case of rxf and umac rxf, set BIT(31) to
|
||||
* distinguish between lmac and umac
|
||||
* @num_of_registers: num of registers to dump, dword size each
|
||||
* @range_data_size: the size of the data
|
||||
* @data: consist of
|
||||
* num_of_registers * (register address + register value) + fifo data
|
||||
/* struct iwl_fw_ini_dump_info - ini dump information
|
||||
* @version: dump version
|
||||
* @trigger_id: trigger id that caused the dump collection
|
||||
* @trigger_reason: not supported yet
|
||||
* @is_external_cfg: 1 if an external debug configuration was loaded
|
||||
* and 0 otherwise
|
||||
* @ver_type: FW version type
|
||||
* @ver_subtype: FW version subype
|
||||
* @hw_step: HW step
|
||||
* @hw_type: HW type
|
||||
* @rf_id_flavor: HW RF id flavor
|
||||
* @rf_id_dash: HW RF id dash
|
||||
* @rf_id_step: HW RF id step
|
||||
* @rf_id_type: HW RF id type
|
||||
* @lmac_major: lmac major version
|
||||
* @lmac_minor: lmac minor version
|
||||
* @umac_major: umac major version
|
||||
* @umac_minor: umac minor version
|
||||
* @build_tag_len: length of the build tag
|
||||
* @build_tag: build tag string
|
||||
* @img_name_len: length of the FW image name
|
||||
* @img_name: FW image name
|
||||
* @internal_dbg_cfg_name_len: length of the internal debug configuration name
|
||||
* @internal_dbg_cfg_name: internal debug configuration name
|
||||
* @external_dbg_cfg_name_len: length of the external debug configuration name
|
||||
* @external_dbg_cfg_name: external debug configuration name
|
||||
* @regions_num: number of region ids
|
||||
* @region_ids: region ids the trigger configured to collect
|
||||
*/
|
||||
struct iwl_fw_ini_fifo_error_dump_range {
|
||||
__le32 fifo_num;
|
||||
__le32 num_of_registers;
|
||||
__le32 range_data_size;
|
||||
__le32 data[];
|
||||
} __packed;
|
||||
struct iwl_fw_ini_dump_info {
|
||||
__le32 version;
|
||||
__le32 trigger_id;
|
||||
__le32 trigger_reason;
|
||||
__le32 is_external_cfg;
|
||||
__le32 ver_type;
|
||||
__le32 ver_subtype;
|
||||
__le32 hw_step;
|
||||
__le32 hw_type;
|
||||
__le32 rf_id_flavor;
|
||||
__le32 rf_id_dash;
|
||||
__le32 rf_id_step;
|
||||
__le32 rf_id_type;
|
||||
__le32 lmac_major;
|
||||
__le32 lmac_minor;
|
||||
__le32 umac_major;
|
||||
__le32 umac_minor;
|
||||
__le32 build_tag_len;
|
||||
u8 build_tag[FW_VER_HUMAN_READABLE_SZ];
|
||||
__le32 img_name_len;
|
||||
u8 img_name[IWL_FW_INI_MAX_IMG_NAME_LEN];
|
||||
__le32 internal_dbg_cfg_name_len;
|
||||
u8 internal_dbg_cfg_name[IWL_FW_INI_MAX_DBG_CFG_NAME_LEN];
|
||||
__le32 external_dbg_cfg_name_len;
|
||||
u8 external_dbg_cfg_name[IWL_FW_INI_MAX_DBG_CFG_NAME_LEN];
|
||||
__le32 regions_num;
|
||||
__le32 region_ids[];
|
||||
|
||||
/**
|
||||
* struct iwl_fw_ini_fifo_error_dump - ini fifo region dump
|
||||
* @header: the header of this region
|
||||
* @ranges: the memory ranges of this region
|
||||
*/
|
||||
struct iwl_fw_ini_fifo_error_dump {
|
||||
struct iwl_fw_ini_error_dump_header header;
|
||||
struct iwl_fw_ini_fifo_error_dump_range ranges[];
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
|
|
|
@ -151,12 +151,13 @@ enum iwl_ucode_tlv_type {
|
|||
IWL_UCODE_TLV_FW_RECOVERY_INFO = 57,
|
||||
IWL_UCODE_TLV_FW_FSEQ_VERSION = 60,
|
||||
|
||||
IWL_UCODE_TLV_TYPE_BUFFER_ALLOCATION = IWL_UCODE_INI_TLV_GROUP + 0x1,
|
||||
IWL_UCODE_TLV_DEBUG_BASE = IWL_UCODE_TLV_TYPE_BUFFER_ALLOCATION,
|
||||
IWL_UCODE_TLV_TYPE_HCMD = IWL_UCODE_INI_TLV_GROUP + 0x2,
|
||||
IWL_UCODE_TLV_TYPE_REGIONS = IWL_UCODE_INI_TLV_GROUP + 0x3,
|
||||
IWL_UCODE_TLV_TYPE_TRIGGERS = IWL_UCODE_INI_TLV_GROUP + 0x4,
|
||||
IWL_UCODE_TLV_TYPE_DEBUG_FLOW = IWL_UCODE_INI_TLV_GROUP + 0x5,
|
||||
IWL_UCODE_TLV_DEBUG_BASE = IWL_UCODE_INI_TLV_GROUP,
|
||||
IWL_UCODE_TLV_TYPE_DEBUG_INFO = IWL_UCODE_TLV_DEBUG_BASE + 0,
|
||||
IWL_UCODE_TLV_TYPE_BUFFER_ALLOCATION = IWL_UCODE_TLV_DEBUG_BASE + 1,
|
||||
IWL_UCODE_TLV_TYPE_HCMD = IWL_UCODE_TLV_DEBUG_BASE + 2,
|
||||
IWL_UCODE_TLV_TYPE_REGIONS = IWL_UCODE_TLV_DEBUG_BASE + 3,
|
||||
IWL_UCODE_TLV_TYPE_TRIGGERS = IWL_UCODE_TLV_DEBUG_BASE + 4,
|
||||
IWL_UCODE_TLV_TYPE_DEBUG_FLOW = IWL_UCODE_TLV_DEBUG_BASE + 5,
|
||||
IWL_UCODE_TLV_DEBUG_MAX = IWL_UCODE_TLV_TYPE_DEBUG_FLOW,
|
||||
|
||||
/* TLVs 0x1000-0x2000 are for internal driver usage */
|
||||
|
@ -286,6 +287,8 @@ typedef unsigned int __bitwise iwl_ucode_tlv_api_t;
|
|||
* SCAN_OFFLOAD_PROFILES_QUERY_RSP_S.
|
||||
* @IWL_UCODE_TLV_API_MBSSID_HE: This ucode supports v2 of
|
||||
* STA_CONTEXT_DOT11AX_API_S
|
||||
* @IWL_UCODE_TLV_CAPA_SAR_TABLE_VER: This ucode supports different sar
|
||||
* version tables.
|
||||
*
|
||||
* @NUM_IWL_UCODE_TLV_API: number of bits used
|
||||
*/
|
||||
|
@ -318,6 +321,8 @@ enum iwl_ucode_tlv_api {
|
|||
IWL_UCODE_TLV_API_MBSSID_HE = (__force iwl_ucode_tlv_api_t)52,
|
||||
IWL_UCODE_TLV_API_WOWLAN_TCP_SYN_WAKE = (__force iwl_ucode_tlv_api_t)53,
|
||||
IWL_UCODE_TLV_API_FTM_RTT_ACCURACY = (__force iwl_ucode_tlv_api_t)54,
|
||||
IWL_UCODE_TLV_API_SAR_TABLE_VER = (__force iwl_ucode_tlv_api_t)55,
|
||||
IWL_UCODE_TLV_API_ADWELL_HB_DEF_N_AP = (__force iwl_ucode_tlv_api_t)57,
|
||||
|
||||
NUM_IWL_UCODE_TLV_API
|
||||
#ifdef __CHECKER__
|
||||
|
|
|
@ -67,6 +67,8 @@ void iwl_fw_runtime_init(struct iwl_fw_runtime *fwrt, struct iwl_trans *trans,
|
|||
const struct iwl_fw_runtime_ops *ops, void *ops_ctx,
|
||||
struct dentry *dbgfs_dir)
|
||||
{
|
||||
int i;
|
||||
|
||||
memset(fwrt, 0, sizeof(*fwrt));
|
||||
fwrt->trans = trans;
|
||||
fwrt->fw = fw;
|
||||
|
@ -74,7 +76,10 @@ void iwl_fw_runtime_init(struct iwl_fw_runtime *fwrt, struct iwl_trans *trans,
|
|||
fwrt->dump.conf = FW_DBG_INVALID;
|
||||
fwrt->ops = ops;
|
||||
fwrt->ops_ctx = ops_ctx;
|
||||
INIT_DELAYED_WORK(&fwrt->dump.wk, iwl_fw_error_dump_wk);
|
||||
for (i = 0; i < IWL_FW_RUNTIME_DUMP_WK_NUM; i++) {
|
||||
fwrt->dump.wks[i].idx = i;
|
||||
INIT_DELAYED_WORK(&fwrt->dump.wks[i].wk, iwl_fw_error_dump_wk);
|
||||
}
|
||||
iwl_fwrt_dbgfs_register(fwrt, dbgfs_dir);
|
||||
timer_setup(&fwrt->dump.periodic_trig,
|
||||
iwl_fw_dbg_periodic_trig_handler, 0);
|
||||
|
|
|
@ -89,9 +89,7 @@ struct iwl_fwrt_shared_mem_cfg {
|
|||
u32 internal_txfifo_size[TX_FIFO_INTERNAL_MAX_NUM];
|
||||
};
|
||||
|
||||
enum iwl_fw_runtime_status {
|
||||
IWL_FWRT_STATUS_DUMPING = 0,
|
||||
};
|
||||
#define IWL_FW_RUNTIME_DUMP_WK_NUM 5
|
||||
|
||||
/**
|
||||
* struct iwl_fw_runtime - runtime data for firmware
|
||||
|
@ -100,7 +98,6 @@ enum iwl_fw_runtime_status {
|
|||
* @dev: device pointer
|
||||
* @ops: user ops
|
||||
* @ops_ctx: user ops context
|
||||
* @status: status flags
|
||||
* @fw_paging_db: paging database
|
||||
* @num_of_paging_blk: number of paging blocks
|
||||
* @num_of_pages_in_last_blk: number of pages in the last block
|
||||
|
@ -117,8 +114,6 @@ struct iwl_fw_runtime {
|
|||
const struct iwl_fw_runtime_ops *ops;
|
||||
void *ops_ctx;
|
||||
|
||||
unsigned long status;
|
||||
|
||||
/* Paging */
|
||||
struct iwl_fw_paging fw_paging_db[NUM_OF_FW_PAGING_BLOCKS];
|
||||
u16 num_of_paging_blk;
|
||||
|
@ -133,7 +128,12 @@ struct iwl_fw_runtime {
|
|||
struct {
|
||||
const struct iwl_fw_dump_desc *desc;
|
||||
bool monitor_only;
|
||||
struct delayed_work wk;
|
||||
struct {
|
||||
u8 idx;
|
||||
enum iwl_fw_ini_trigger_id ini_trig_id;
|
||||
struct delayed_work wk;
|
||||
} wks[IWL_FW_RUNTIME_DUMP_WK_NUM];
|
||||
unsigned long active_wks;
|
||||
|
||||
u8 conf;
|
||||
|
||||
|
@ -145,8 +145,20 @@ struct iwl_fw_runtime {
|
|||
u32 lmac_err_id[MAX_NUM_LMAC];
|
||||
u32 umac_err_id;
|
||||
void *fifo_iter;
|
||||
enum iwl_fw_ini_trigger_id ini_trig_id;
|
||||
struct timer_list periodic_trig;
|
||||
|
||||
u8 img_name[IWL_FW_INI_MAX_IMG_NAME_LEN];
|
||||
u8 internal_dbg_cfg_name[IWL_FW_INI_MAX_DBG_CFG_NAME_LEN];
|
||||
u8 external_dbg_cfg_name[IWL_FW_INI_MAX_DBG_CFG_NAME_LEN];
|
||||
|
||||
struct {
|
||||
u8 type;
|
||||
u8 subtype;
|
||||
u32 lmac_major;
|
||||
u32 lmac_minor;
|
||||
u32 umac_major;
|
||||
u32 umac_minor;
|
||||
} fw_ver;
|
||||
} dump;
|
||||
#ifdef CONFIG_IWLWIFI_DEBUGFS
|
||||
struct {
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
|
||||
* Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
|
||||
* Copyright(c) 2016 - 2017 Intel Deutschland GmbH
|
||||
* Copyright(c) 2018 Intel Corporation
|
||||
* Copyright(c) 2018 - 2019 Intel Corporation
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
|
@ -31,7 +31,7 @@
|
|||
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
|
||||
* Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
|
||||
* Copyright(c) 2016 - 2017 Intel Deutschland GmbH
|
||||
* Copyright(c) 2018 Intel Corporation
|
||||
* Copyright(c) 2018 - 2019 Intel Corporation
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
@ -134,6 +134,7 @@ void iwl_get_shared_mem_conf(struct iwl_fw_runtime *fwrt)
|
|||
.len = { 0, },
|
||||
};
|
||||
struct iwl_rx_packet *pkt;
|
||||
int ret;
|
||||
|
||||
if (fw_has_capa(&fwrt->fw->ucode_capa,
|
||||
IWL_UCODE_TLV_CAPA_EXTEND_SHARED_MEM_CFG))
|
||||
|
@ -141,8 +142,13 @@ void iwl_get_shared_mem_conf(struct iwl_fw_runtime *fwrt)
|
|||
else
|
||||
cmd.id = SHARED_MEM_CFG;
|
||||
|
||||
if (WARN_ON(iwl_trans_send_cmd(fwrt->trans, &cmd)))
|
||||
ret = iwl_trans_send_cmd(fwrt->trans, &cmd);
|
||||
|
||||
if (ret) {
|
||||
WARN(ret != -ERFKILL,
|
||||
"Could not send the SMEM command: %d\n", ret);
|
||||
return;
|
||||
}
|
||||
|
||||
pkt = cmd.resp_pkt;
|
||||
if (fwrt->trans->cfg->device_family >= IWL_DEVICE_FAMILY_22000)
|
||||
|
|
|
@ -81,9 +81,9 @@ void iwl_fw_dbg_copy_tlv(struct iwl_trans *trans, struct iwl_ucode_tlv *tlv,
|
|||
return;
|
||||
|
||||
if (ext)
|
||||
data = &trans->apply_points_ext[apply_point];
|
||||
data = &trans->dbg.apply_points_ext[apply_point];
|
||||
else
|
||||
data = &trans->apply_points[apply_point];
|
||||
data = &trans->dbg.apply_points[apply_point];
|
||||
|
||||
/* add room for is_alloc field in &iwl_fw_ini_allocation_data struct */
|
||||
if (le32_to_cpu(tlv->type) == IWL_UCODE_TLV_TYPE_BUFFER_ALLOCATION) {
|
||||
|
@ -172,14 +172,14 @@ void iwl_alloc_dbg_tlv(struct iwl_trans *trans, size_t len, const u8 *data,
|
|||
}
|
||||
|
||||
if (ext) {
|
||||
trans->apply_points_ext[i].data = mem;
|
||||
trans->apply_points_ext[i].size = size[i];
|
||||
trans->dbg.apply_points_ext[i].data = mem;
|
||||
trans->dbg.apply_points_ext[i].size = size[i];
|
||||
} else {
|
||||
trans->apply_points[i].data = mem;
|
||||
trans->apply_points[i].size = size[i];
|
||||
trans->dbg.apply_points[i].data = mem;
|
||||
trans->dbg.apply_points[i].size = size[i];
|
||||
}
|
||||
|
||||
trans->ini_valid = true;
|
||||
trans->dbg.ini_valid = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -187,14 +187,14 @@ void iwl_fw_dbg_free(struct iwl_trans *trans)
|
|||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(trans->apply_points); i++) {
|
||||
kfree(trans->apply_points[i].data);
|
||||
trans->apply_points[i].size = 0;
|
||||
trans->apply_points[i].offset = 0;
|
||||
for (i = 0; i < ARRAY_SIZE(trans->dbg.apply_points); i++) {
|
||||
kfree(trans->dbg.apply_points[i].data);
|
||||
trans->dbg.apply_points[i].size = 0;
|
||||
trans->dbg.apply_points[i].offset = 0;
|
||||
|
||||
kfree(trans->apply_points_ext[i].data);
|
||||
trans->apply_points_ext[i].size = 0;
|
||||
trans->apply_points_ext[i].offset = 0;
|
||||
kfree(trans->dbg.apply_points_ext[i].data);
|
||||
trans->dbg.apply_points_ext[i].size = 0;
|
||||
trans->dbg.apply_points_ext[i].offset = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -221,6 +221,7 @@ static int iwl_parse_fw_dbg_tlv(struct iwl_trans *trans, const u8 *data,
|
|||
data += sizeof(*tlv) + ALIGN(tlv_len, 4);
|
||||
|
||||
switch (tlv_type) {
|
||||
case IWL_UCODE_TLV_TYPE_DEBUG_INFO:
|
||||
case IWL_UCODE_TLV_TYPE_BUFFER_ALLOCATION:
|
||||
case IWL_UCODE_TLV_TYPE_HCMD:
|
||||
case IWL_UCODE_TLV_TYPE_REGIONS:
|
||||
|
@ -242,7 +243,7 @@ void iwl_load_fw_dbg_tlv(struct device *dev, struct iwl_trans *trans)
|
|||
const struct firmware *fw;
|
||||
int res;
|
||||
|
||||
if (trans->external_ini_loaded || !iwlwifi_mod_params.enable_ini)
|
||||
if (trans->dbg.external_ini_loaded || !iwlwifi_mod_params.enable_ini)
|
||||
return;
|
||||
|
||||
res = request_firmware(&fw, "iwl-dbg-tlv.ini", dev);
|
||||
|
@ -252,6 +253,6 @@ void iwl_load_fw_dbg_tlv(struct device *dev, struct iwl_trans *trans)
|
|||
iwl_alloc_dbg_tlv(trans, fw->size, fw->data, true);
|
||||
iwl_parse_fw_dbg_tlv(trans, fw->data, fw->size);
|
||||
|
||||
trans->external_ini_loaded = true;
|
||||
trans->dbg.external_ini_loaded = true;
|
||||
release_firmware(fw);
|
||||
}
|
||||
|
|
|
@ -1105,6 +1105,18 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
|
|||
le32_to_cpu(recov_info->buf_size);
|
||||
}
|
||||
break;
|
||||
case IWL_UCODE_TLV_FW_FSEQ_VERSION: {
|
||||
struct {
|
||||
u8 version[32];
|
||||
u8 sha1[20];
|
||||
} *fseq_ver = (void *)tlv_data;
|
||||
|
||||
if (tlv_len != sizeof(*fseq_ver))
|
||||
goto invalid_tlv_len;
|
||||
IWL_INFO(drv, "TLV_FW_FSEQ_VERSION: %s\n",
|
||||
fseq_ver->version);
|
||||
}
|
||||
break;
|
||||
case IWL_UCODE_TLV_UMAC_DEBUG_ADDRS: {
|
||||
struct iwl_umac_debug_addrs *dbg_ptrs =
|
||||
(void *)tlv_data;
|
||||
|
@ -1114,10 +1126,10 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
|
|||
if (drv->trans->cfg->device_family <
|
||||
IWL_DEVICE_FAMILY_22000)
|
||||
break;
|
||||
drv->trans->umac_error_event_table =
|
||||
drv->trans->dbg.umac_error_event_table =
|
||||
le32_to_cpu(dbg_ptrs->error_info_addr) &
|
||||
~FW_ADDR_CACHE_CONTROL;
|
||||
drv->trans->error_event_table_tlv_status |=
|
||||
drv->trans->dbg.error_event_table_tlv_status |=
|
||||
IWL_ERROR_EVENT_TABLE_UMAC;
|
||||
break;
|
||||
}
|
||||
|
@ -1130,13 +1142,14 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
|
|||
if (drv->trans->cfg->device_family <
|
||||
IWL_DEVICE_FAMILY_22000)
|
||||
break;
|
||||
drv->trans->lmac_error_event_table[0] =
|
||||
drv->trans->dbg.lmac_error_event_table[0] =
|
||||
le32_to_cpu(dbg_ptrs->error_event_table_ptr) &
|
||||
~FW_ADDR_CACHE_CONTROL;
|
||||
drv->trans->error_event_table_tlv_status |=
|
||||
drv->trans->dbg.error_event_table_tlv_status |=
|
||||
IWL_ERROR_EVENT_TABLE_LMAC1;
|
||||
break;
|
||||
}
|
||||
case IWL_UCODE_TLV_TYPE_DEBUG_INFO:
|
||||
case IWL_UCODE_TLV_TYPE_BUFFER_ALLOCATION:
|
||||
case IWL_UCODE_TLV_TYPE_HCMD:
|
||||
case IWL_UCODE_TLV_TYPE_REGIONS:
|
||||
|
@ -1744,7 +1757,7 @@ IWL_EXPORT_SYMBOL(iwl_opmode_deregister);
|
|||
|
||||
static int __init iwl_drv_init(void)
|
||||
{
|
||||
int i;
|
||||
int i, err;
|
||||
|
||||
mutex_init(&iwlwifi_opmode_table_mtx);
|
||||
|
||||
|
@ -1759,7 +1772,17 @@ static int __init iwl_drv_init(void)
|
|||
iwl_dbgfs_root = debugfs_create_dir(DRV_NAME, NULL);
|
||||
#endif
|
||||
|
||||
return iwl_pci_register_driver();
|
||||
err = iwl_pci_register_driver();
|
||||
if (err)
|
||||
goto cleanup_debugfs;
|
||||
|
||||
return 0;
|
||||
|
||||
cleanup_debugfs:
|
||||
#ifdef CONFIG_IWLWIFI_DEBUGFS
|
||||
debugfs_remove_recursive(iwl_dbgfs_root);
|
||||
#endif
|
||||
return err;
|
||||
}
|
||||
module_init(iwl_drv_init);
|
||||
|
||||
|
|
|
@ -721,6 +721,50 @@ struct iwl_self_init_dram {
|
|||
int paging_cnt;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct iwl_trans_debug - transport debug related data
|
||||
*
|
||||
* @n_dest_reg: num of reg_ops in %dbg_dest_tlv
|
||||
* @rec_on: true iff there is a fw debug recording currently active
|
||||
* @dest_tlv: points to the destination TLV for debug
|
||||
* @conf_tlv: array of pointers to configuration TLVs for debug
|
||||
* @trigger_tlv: array of pointers to triggers TLVs for debug
|
||||
* @lmac_error_event_table: addrs of lmacs error tables
|
||||
* @umac_error_event_table: addr of umac error table
|
||||
* @error_event_table_tlv_status: bitmap that indicates what error table
|
||||
* pointers was recevied via TLV. uses enum &iwl_error_event_table_status
|
||||
* @external_ini_loaded: indicates if an external ini cfg was given
|
||||
* @ini_valid: indicates if debug ini mode is on
|
||||
* @num_blocks: number of blocks in fw_mon
|
||||
* @fw_mon: address of the buffers for firmware monitor
|
||||
* @hw_error: equals true if hw error interrupt was received from the FW
|
||||
* @ini_dest: debug monitor destination uses &enum iwl_fw_ini_buffer_location
|
||||
*/
|
||||
struct iwl_trans_debug {
|
||||
u8 n_dest_reg;
|
||||
bool rec_on;
|
||||
|
||||
const struct iwl_fw_dbg_dest_tlv_v1 *dest_tlv;
|
||||
const struct iwl_fw_dbg_conf_tlv *conf_tlv[FW_DBG_CONF_MAX];
|
||||
struct iwl_fw_dbg_trigger_tlv * const *trigger_tlv;
|
||||
|
||||
u32 lmac_error_event_table[2];
|
||||
u32 umac_error_event_table;
|
||||
unsigned int error_event_table_tlv_status;
|
||||
|
||||
bool external_ini_loaded;
|
||||
bool ini_valid;
|
||||
|
||||
struct iwl_apply_point_data apply_points[IWL_FW_INI_APPLY_NUM];
|
||||
struct iwl_apply_point_data apply_points_ext[IWL_FW_INI_APPLY_NUM];
|
||||
|
||||
int num_blocks;
|
||||
struct iwl_dram_data fw_mon[IWL_FW_INI_APPLY_NUM];
|
||||
|
||||
bool hw_error;
|
||||
enum iwl_fw_ini_buffer_location ini_dest;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct iwl_trans - transport common data
|
||||
*
|
||||
|
@ -750,24 +794,12 @@ struct iwl_self_init_dram {
|
|||
* @rx_mpdu_cmd_hdr_size: used for tracing, amount of data before the
|
||||
* start of the 802.11 header in the @rx_mpdu_cmd
|
||||
* @dflt_pwr_limit: default power limit fetched from the platform (ACPI)
|
||||
* @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_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.
|
||||
* This mode is set dynamically, depending on the WoWLAN values
|
||||
* configured from the userspace at runtime.
|
||||
* @runtime_pm_mode: the runtime power management mode in use. This
|
||||
* mode is set during the initialization phase and is not
|
||||
* supposed to change during runtime.
|
||||
* @dbg_rec_on: true iff there is a fw debug recording currently active
|
||||
* @lmac_error_event_table: addrs of lmacs error tables
|
||||
* @umac_error_event_table: addr of umac error table
|
||||
* @error_event_table_tlv_status: bitmap that indicates what error table
|
||||
* pointers was recevied via TLV. use enum &iwl_error_event_table_status
|
||||
* @hw_error: equals true if hw error interrupt was received from the FW
|
||||
*/
|
||||
struct iwl_trans {
|
||||
const struct iwl_trans_ops *ops;
|
||||
|
@ -808,29 +840,12 @@ struct iwl_trans {
|
|||
struct lockdep_map sync_cmd_lockdep_map;
|
||||
#endif
|
||||
|
||||
struct iwl_apply_point_data apply_points[IWL_FW_INI_APPLY_NUM];
|
||||
struct iwl_apply_point_data apply_points_ext[IWL_FW_INI_APPLY_NUM];
|
||||
|
||||
bool external_ini_loaded;
|
||||
bool ini_valid;
|
||||
|
||||
const struct iwl_fw_dbg_dest_tlv_v1 *dbg_dest_tlv;
|
||||
const struct iwl_fw_dbg_conf_tlv *dbg_conf_tlv[FW_DBG_CONF_MAX];
|
||||
struct iwl_fw_dbg_trigger_tlv * const *dbg_trigger_tlv;
|
||||
u8 dbg_n_dest_reg;
|
||||
int num_blocks;
|
||||
struct iwl_dram_data fw_mon[IWL_FW_INI_APPLY_NUM];
|
||||
struct iwl_trans_debug dbg;
|
||||
struct iwl_self_init_dram init_dram;
|
||||
|
||||
enum iwl_plat_pm_mode system_pm_mode;
|
||||
enum iwl_plat_pm_mode runtime_pm_mode;
|
||||
bool suspending;
|
||||
bool dbg_rec_on;
|
||||
|
||||
u32 lmac_error_event_table[2];
|
||||
u32 umac_error_event_table;
|
||||
unsigned int error_event_table_tlv_status;
|
||||
bool hw_error;
|
||||
|
||||
/* pointer to trans specific struct */
|
||||
/*Ensure that this pointer will always be aligned to sizeof pointer */
|
||||
|
|
|
@ -152,5 +152,6 @@
|
|||
#define IWL_MVM_FTM_INITIATOR_ALGO IWL_TOF_ALGO_TYPE_MAX_LIKE
|
||||
#define IWL_MVM_FTM_INITIATOR_DYNACK true
|
||||
#define IWL_MVM_D3_DEBUG false
|
||||
#define IWL_MVM_USE_TWT false
|
||||
|
||||
#endif /* __MVM_CONSTANTS_H */
|
||||
|
|
|
@ -398,8 +398,7 @@ static int iwl_mvm_send_patterns_v1(struct iwl_mvm *mvm,
|
|||
if (!wowlan->n_patterns)
|
||||
return 0;
|
||||
|
||||
cmd.len[0] = sizeof(*pattern_cmd) +
|
||||
wowlan->n_patterns * sizeof(struct iwl_wowlan_pattern_v1);
|
||||
cmd.len[0] = struct_size(pattern_cmd, patterns, wowlan->n_patterns);
|
||||
|
||||
pattern_cmd = kmalloc(cmd.len[0], GFP_KERNEL);
|
||||
if (!pattern_cmd)
|
||||
|
@ -1079,11 +1078,12 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
|
|||
#endif
|
||||
|
||||
/*
|
||||
* TODO: this is needed because the firmware is not stopping
|
||||
* the recording automatically before entering D3. This can
|
||||
* be removed once the FW starts doing that.
|
||||
* Prior to 9000 device family the driver needs to stop the dbg
|
||||
* recording before entering D3. In later devices the FW stops the
|
||||
* recording automatically.
|
||||
*/
|
||||
_iwl_fw_dbg_stop_recording(mvm->fwrt.trans, NULL);
|
||||
if (mvm->trans->cfg->device_family < IWL_DEVICE_FAMILY_9000)
|
||||
iwl_fw_dbg_stop_recording(mvm->trans, NULL);
|
||||
|
||||
/* must be last -- this switches firmware state */
|
||||
ret = iwl_mvm_send_cmd(mvm, &d3_cfg_cmd);
|
||||
|
@ -1986,7 +1986,7 @@ static void iwl_mvm_d3_disconnect_iter(void *data, u8 *mac,
|
|||
static int iwl_mvm_check_rt_status(struct iwl_mvm *mvm,
|
||||
struct ieee80211_vif *vif)
|
||||
{
|
||||
u32 base = mvm->trans->lmac_error_event_table[0];
|
||||
u32 base = mvm->trans->dbg.lmac_error_event_table[0];
|
||||
struct error_table_start {
|
||||
/* cf. struct iwl_error_event_table */
|
||||
u32 valid;
|
||||
|
|
|
@ -467,6 +467,46 @@ static ssize_t iwl_dbgfs_rs_data_read(struct file *file, char __user *user_buf,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t iwl_dbgfs_amsdu_len_write(struct ieee80211_sta *sta,
|
||||
char *buf, size_t count,
|
||||
loff_t *ppos)
|
||||
{
|
||||
struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
|
||||
int i;
|
||||
u16 amsdu_len;
|
||||
|
||||
if (kstrtou16(buf, 0, &amsdu_len))
|
||||
return -EINVAL;
|
||||
|
||||
if (amsdu_len) {
|
||||
mvmsta->orig_amsdu_len = sta->max_amsdu_len;
|
||||
sta->max_amsdu_len = amsdu_len;
|
||||
for (i = 0; i < ARRAY_SIZE(sta->max_tid_amsdu_len); i++)
|
||||
sta->max_tid_amsdu_len[i] = amsdu_len;
|
||||
} else {
|
||||
sta->max_amsdu_len = mvmsta->orig_amsdu_len;
|
||||
mvmsta->orig_amsdu_len = 0;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t iwl_dbgfs_amsdu_len_read(struct file *file,
|
||||
char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct ieee80211_sta *sta = file->private_data;
|
||||
struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
|
||||
|
||||
char buf[32];
|
||||
int pos;
|
||||
|
||||
pos = scnprintf(buf, sizeof(buf), "current %d ", sta->max_amsdu_len);
|
||||
pos += scnprintf(buf + pos, sizeof(buf) - pos, "stored %d\n",
|
||||
mvmsta->orig_amsdu_len);
|
||||
|
||||
return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
|
||||
}
|
||||
|
||||
static ssize_t iwl_dbgfs_disable_power_off_read(struct file *file,
|
||||
char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
|
@ -1356,24 +1396,6 @@ static ssize_t iwl_dbgfs_fw_dbg_collect_write(struct iwl_mvm *mvm,
|
|||
return count;
|
||||
}
|
||||
|
||||
static ssize_t iwl_dbgfs_max_amsdu_len_write(struct iwl_mvm *mvm,
|
||||
char *buf, size_t count,
|
||||
loff_t *ppos)
|
||||
{
|
||||
unsigned int max_amsdu_len;
|
||||
int ret;
|
||||
|
||||
ret = kstrtouint(buf, 0, &max_amsdu_len);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (max_amsdu_len > IEEE80211_MAX_MPDU_LEN_VHT_11454)
|
||||
return -EINVAL;
|
||||
mvm->max_amsdu_len = max_amsdu_len;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
#define ADD_TEXT(...) pos += scnprintf(buf + pos, bufsz - pos, __VA_ARGS__)
|
||||
#ifdef CONFIG_IWLWIFI_BCAST_FILTERING
|
||||
static ssize_t iwl_dbgfs_bcast_filters_read(struct file *file,
|
||||
|
@ -1873,7 +1895,6 @@ MVM_DEBUGFS_READ_WRITE_FILE_OPS(scan_ant_rxchain, 8);
|
|||
MVM_DEBUGFS_READ_WRITE_FILE_OPS(d0i3_refs, 8);
|
||||
MVM_DEBUGFS_READ_WRITE_FILE_OPS(fw_dbg_conf, 8);
|
||||
MVM_DEBUGFS_WRITE_FILE_OPS(fw_dbg_collect, 64);
|
||||
MVM_DEBUGFS_WRITE_FILE_OPS(max_amsdu_len, 8);
|
||||
MVM_DEBUGFS_WRITE_FILE_OPS(indirection_tbl,
|
||||
(IWL_RSS_INDIRECTION_TABLE_SIZE * 2));
|
||||
MVM_DEBUGFS_WRITE_FILE_OPS(inject_packet, 512);
|
||||
|
@ -1891,6 +1912,8 @@ MVM_DEBUGFS_READ_WRITE_FILE_OPS(bcast_filters_macs, 256);
|
|||
MVM_DEBUGFS_READ_FILE_OPS(sar_geo_profile);
|
||||
#endif
|
||||
|
||||
MVM_DEBUGFS_READ_WRITE_STA_FILE_OPS(amsdu_len, 16);
|
||||
|
||||
MVM_DEBUGFS_READ_WRITE_FILE_OPS(he_sniffer_params, 32);
|
||||
|
||||
static ssize_t iwl_dbgfs_mem_read(struct file *file, char __user *user_buf,
|
||||
|
@ -2032,8 +2055,10 @@ void iwl_mvm_sta_add_debugfs(struct ieee80211_hw *hw,
|
|||
{
|
||||
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
|
||||
|
||||
if (iwl_mvm_has_tlc_offload(mvm))
|
||||
if (iwl_mvm_has_tlc_offload(mvm)) {
|
||||
MVM_DEBUGFS_ADD_STA_FILE(rs_data, dir, 0400);
|
||||
}
|
||||
MVM_DEBUGFS_ADD_STA_FILE(amsdu_len, dir, 0600);
|
||||
}
|
||||
|
||||
void iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir)
|
||||
|
@ -2069,7 +2094,6 @@ void iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir)
|
|||
MVM_DEBUGFS_ADD_FILE(d0i3_refs, mvm->debugfs_dir, 0600);
|
||||
MVM_DEBUGFS_ADD_FILE(fw_dbg_conf, mvm->debugfs_dir, 0600);
|
||||
MVM_DEBUGFS_ADD_FILE(fw_dbg_collect, mvm->debugfs_dir, 0200);
|
||||
MVM_DEBUGFS_ADD_FILE(max_amsdu_len, mvm->debugfs_dir, 0200);
|
||||
MVM_DEBUGFS_ADD_FILE(send_echo_cmd, mvm->debugfs_dir, 0200);
|
||||
MVM_DEBUGFS_ADD_FILE(indirection_tbl, mvm->debugfs_dir, 0200);
|
||||
MVM_DEBUGFS_ADD_FILE(inject_packet, mvm->debugfs_dir, 0200);
|
||||
|
|
|
@ -238,7 +238,7 @@ static bool iwl_alive_fn(struct iwl_notif_wait_data *notif_wait,
|
|||
iwl_fw_lmac1_set_alive_err_table(mvm->trans, lmac_error_event_table);
|
||||
|
||||
if (lmac2)
|
||||
mvm->trans->lmac_error_event_table[1] =
|
||||
mvm->trans->dbg.lmac_error_event_table[1] =
|
||||
le32_to_cpu(lmac2->dbg_ptrs.error_event_table_ptr);
|
||||
|
||||
umac_error_event_table = le32_to_cpu(umac->dbg_ptrs.error_info_addr);
|
||||
|
@ -276,6 +276,8 @@ static bool iwl_alive_fn(struct iwl_notif_wait_data *notif_wait,
|
|||
le32_to_cpu(umac->umac_major),
|
||||
le32_to_cpu(umac->umac_minor));
|
||||
|
||||
iwl_fwrt_update_fw_versions(&mvm->fwrt, lmac1, umac);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -419,6 +421,8 @@ static int iwl_run_unified_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm)
|
|||
|
||||
lockdep_assert_held(&mvm->mutex);
|
||||
|
||||
mvm->rfkill_safe_init_done = false;
|
||||
|
||||
iwl_init_notification_wait(&mvm->notif_wait,
|
||||
&init_wait,
|
||||
init_complete,
|
||||
|
@ -537,8 +541,7 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm)
|
|||
|
||||
lockdep_assert_held(&mvm->mutex);
|
||||
|
||||
if (WARN_ON_ONCE(mvm->rfkill_safe_init_done))
|
||||
return 0;
|
||||
mvm->rfkill_safe_init_done = false;
|
||||
|
||||
iwl_init_notification_wait(&mvm->notif_wait,
|
||||
&calib_wait,
|
||||
|
@ -681,15 +684,15 @@ static int iwl_mvm_sar_get_wrds_table(struct iwl_mvm *mvm)
|
|||
{
|
||||
union acpi_object *wifi_pkg, *table, *data;
|
||||
bool enabled;
|
||||
int ret;
|
||||
int ret, tbl_rev;
|
||||
|
||||
data = iwl_acpi_get_object(mvm->dev, ACPI_WRDS_METHOD);
|
||||
if (IS_ERR(data))
|
||||
return PTR_ERR(data);
|
||||
|
||||
wifi_pkg = iwl_acpi_get_wifi_pkg(mvm->dev, data,
|
||||
ACPI_WRDS_WIFI_DATA_SIZE);
|
||||
if (IS_ERR(wifi_pkg)) {
|
||||
ACPI_WRDS_WIFI_DATA_SIZE, &tbl_rev);
|
||||
if (IS_ERR(wifi_pkg) || tbl_rev != 0) {
|
||||
ret = PTR_ERR(wifi_pkg);
|
||||
goto out_free;
|
||||
}
|
||||
|
@ -718,15 +721,15 @@ static int iwl_mvm_sar_get_ewrd_table(struct iwl_mvm *mvm)
|
|||
{
|
||||
union acpi_object *wifi_pkg, *data;
|
||||
bool enabled;
|
||||
int i, n_profiles, ret;
|
||||
int i, n_profiles, ret, tbl_rev;
|
||||
|
||||
data = iwl_acpi_get_object(mvm->dev, ACPI_EWRD_METHOD);
|
||||
if (IS_ERR(data))
|
||||
return PTR_ERR(data);
|
||||
|
||||
wifi_pkg = iwl_acpi_get_wifi_pkg(mvm->dev, data,
|
||||
ACPI_EWRD_WIFI_DATA_SIZE);
|
||||
if (IS_ERR(wifi_pkg)) {
|
||||
ACPI_EWRD_WIFI_DATA_SIZE, &tbl_rev);
|
||||
if (IS_ERR(wifi_pkg) || tbl_rev != 0) {
|
||||
ret = PTR_ERR(wifi_pkg);
|
||||
goto out_free;
|
||||
}
|
||||
|
@ -777,7 +780,7 @@ static int iwl_mvm_sar_get_ewrd_table(struct iwl_mvm *mvm)
|
|||
static int iwl_mvm_sar_get_wgds_table(struct iwl_mvm *mvm)
|
||||
{
|
||||
union acpi_object *wifi_pkg, *data;
|
||||
int i, j, ret;
|
||||
int i, j, ret, tbl_rev;
|
||||
int idx = 1;
|
||||
|
||||
data = iwl_acpi_get_object(mvm->dev, ACPI_WGDS_METHOD);
|
||||
|
@ -785,12 +788,13 @@ static int iwl_mvm_sar_get_wgds_table(struct iwl_mvm *mvm)
|
|||
return PTR_ERR(data);
|
||||
|
||||
wifi_pkg = iwl_acpi_get_wifi_pkg(mvm->dev, data,
|
||||
ACPI_WGDS_WIFI_DATA_SIZE);
|
||||
if (IS_ERR(wifi_pkg)) {
|
||||
ACPI_WGDS_WIFI_DATA_SIZE, &tbl_rev);
|
||||
if (IS_ERR(wifi_pkg) || tbl_rev > 1) {
|
||||
ret = PTR_ERR(wifi_pkg);
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
mvm->geo_rev = tbl_rev;
|
||||
for (i = 0; i < ACPI_NUM_GEO_PROFILES; i++) {
|
||||
for (j = 0; j < ACPI_GEO_TABLE_SIZE; j++) {
|
||||
union acpi_object *entry;
|
||||
|
@ -858,6 +862,9 @@ int iwl_mvm_sar_select_profile(struct iwl_mvm *mvm, int prof_a, int prof_b)
|
|||
return -ENOENT;
|
||||
}
|
||||
|
||||
IWL_DEBUG_INFO(mvm,
|
||||
"SAR EWRD: chain %d profile index %d\n",
|
||||
i, profs[i]);
|
||||
IWL_DEBUG_RADIO(mvm, " Chain[%d]:\n", i);
|
||||
for (j = 0; j < ACPI_SAR_NUM_SUB_BANDS; j++) {
|
||||
idx = (i * ACPI_SAR_NUM_SUB_BANDS) + j;
|
||||
|
@ -877,15 +884,29 @@ int iwl_mvm_get_sar_geo_profile(struct iwl_mvm *mvm)
|
|||
{
|
||||
struct iwl_geo_tx_power_profiles_resp *resp;
|
||||
int ret;
|
||||
u16 len;
|
||||
void *data;
|
||||
struct iwl_geo_tx_power_profiles_cmd geo_cmd;
|
||||
struct iwl_geo_tx_power_profiles_cmd_v1 geo_cmd_v1;
|
||||
struct iwl_host_cmd cmd;
|
||||
|
||||
struct iwl_geo_tx_power_profiles_cmd geo_cmd = {
|
||||
.ops = cpu_to_le32(IWL_PER_CHAIN_OFFSET_GET_CURRENT_TABLE),
|
||||
};
|
||||
struct iwl_host_cmd cmd = {
|
||||
if (fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_SAR_TABLE_VER)) {
|
||||
geo_cmd.ops =
|
||||
cpu_to_le32(IWL_PER_CHAIN_OFFSET_GET_CURRENT_TABLE);
|
||||
len = sizeof(geo_cmd);
|
||||
data = &geo_cmd;
|
||||
} else {
|
||||
geo_cmd_v1.ops =
|
||||
cpu_to_le32(IWL_PER_CHAIN_OFFSET_GET_CURRENT_TABLE);
|
||||
len = sizeof(geo_cmd_v1);
|
||||
data = &geo_cmd_v1;
|
||||
}
|
||||
|
||||
cmd = (struct iwl_host_cmd){
|
||||
.id = WIDE_ID(PHY_OPS_GROUP, GEO_TX_POWER_LIMIT),
|
||||
.len = { sizeof(geo_cmd), },
|
||||
.len = { len, },
|
||||
.flags = CMD_WANT_SKB,
|
||||
.data = { &geo_cmd },
|
||||
.data = { data },
|
||||
};
|
||||
|
||||
ret = iwl_mvm_send_cmd(mvm, &cmd);
|
||||
|
@ -955,6 +976,16 @@ static int iwl_mvm_sar_geo_init(struct iwl_mvm *mvm)
|
|||
i, j, value[1], value[2], value[0]);
|
||||
}
|
||||
}
|
||||
|
||||
cmd.table_revision = cpu_to_le32(mvm->geo_rev);
|
||||
|
||||
if (!fw_has_api(&mvm->fw->ucode_capa,
|
||||
IWL_UCODE_TLV_API_SAR_TABLE_VER)) {
|
||||
return iwl_mvm_send_cmd_pdu(mvm, cmd_wide_id, 0,
|
||||
sizeof(struct iwl_geo_tx_power_profiles_cmd_v1),
|
||||
&cmd);
|
||||
}
|
||||
|
||||
return iwl_mvm_send_cmd_pdu(mvm, cmd_wide_id, 0, sizeof(cmd), &cmd);
|
||||
}
|
||||
|
||||
|
@ -1108,10 +1139,13 @@ static int iwl_mvm_load_rt_fw(struct iwl_mvm *mvm)
|
|||
|
||||
iwl_fw_dbg_apply_point(&mvm->fwrt, IWL_FW_INI_APPLY_EARLY);
|
||||
|
||||
mvm->rfkill_safe_init_done = false;
|
||||
ret = iwl_mvm_load_ucode_wait_alive(mvm, IWL_UCODE_REGULAR);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
mvm->rfkill_safe_init_done = true;
|
||||
|
||||
iwl_fw_dbg_apply_point(&mvm->fwrt, IWL_FW_INI_APPLY_AFTER_ALIVE);
|
||||
|
||||
return iwl_init_paging(&mvm->fwrt, mvm->fwrt.cur_fw_img);
|
||||
|
@ -1144,7 +1178,7 @@ int iwl_mvm_up(struct iwl_mvm *mvm)
|
|||
if (ret)
|
||||
IWL_ERR(mvm, "Failed to initialize Smart Fifo\n");
|
||||
|
||||
if (!mvm->trans->ini_valid) {
|
||||
if (!mvm->trans->dbg.ini_valid) {
|
||||
mvm->fwrt.dump.conf = FW_DBG_INVALID;
|
||||
/* if we have a destination, assume EARLY START */
|
||||
if (mvm->fw->dbg.dest_tlv)
|
||||
|
|
|
@ -558,15 +558,16 @@ static void iwl_mvm_mac_ctxt_cmd_common(struct iwl_mvm *mvm,
|
|||
|
||||
for (i = 0; i < IEEE80211_NUM_ACS; i++) {
|
||||
u8 txf = iwl_mvm_mac_ac_to_tx_fifo(mvm, i);
|
||||
u8 ucode_ac = iwl_mvm_mac80211_ac_to_ucode_ac(i);
|
||||
|
||||
cmd->ac[txf].cw_min =
|
||||
cmd->ac[ucode_ac].cw_min =
|
||||
cpu_to_le16(mvmvif->queue_params[i].cw_min);
|
||||
cmd->ac[txf].cw_max =
|
||||
cmd->ac[ucode_ac].cw_max =
|
||||
cpu_to_le16(mvmvif->queue_params[i].cw_max);
|
||||
cmd->ac[txf].edca_txop =
|
||||
cmd->ac[ucode_ac].edca_txop =
|
||||
cpu_to_le16(mvmvif->queue_params[i].txop * 32);
|
||||
cmd->ac[txf].aifsn = mvmvif->queue_params[i].aifs;
|
||||
cmd->ac[txf].fifos_mask = BIT(txf);
|
||||
cmd->ac[ucode_ac].aifsn = mvmvif->queue_params[i].aifs;
|
||||
cmd->ac[ucode_ac].fifos_mask = BIT(txf);
|
||||
}
|
||||
|
||||
if (vif->bss_conf.qos)
|
||||
|
@ -678,7 +679,7 @@ static int iwl_mvm_mac_ctxt_cmd_sta(struct iwl_mvm *mvm,
|
|||
|
||||
if (vif->bss_conf.he_support && !iwlwifi_mod_params.disable_11ax) {
|
||||
cmd.filter_flags |= cpu_to_le32(MAC_FILTER_IN_11AX);
|
||||
if (vif->bss_conf.twt_requester)
|
||||
if (vif->bss_conf.twt_requester && IWL_MVM_USE_TWT)
|
||||
ctxt_sta->data_policy |= cpu_to_le32(TWT_SUPPORTED);
|
||||
}
|
||||
|
||||
|
@ -1081,9 +1082,6 @@ static void iwl_mvm_mac_ctxt_cmd_fill_ap(struct iwl_mvm *mvm,
|
|||
IWL_DEBUG_HC(mvm, "No need to receive beacons\n");
|
||||
}
|
||||
|
||||
if (vif->bss_conf.he_support && !iwlwifi_mod_params.disable_11ax)
|
||||
cmd->filter_flags |= cpu_to_le32(MAC_FILTER_IN_11AX);
|
||||
|
||||
ctxt_ap->bi = cpu_to_le32(vif->bss_conf.beacon_int);
|
||||
ctxt_ap->dtim_interval = cpu_to_le32(vif->bss_conf.beacon_int *
|
||||
vif->bss_conf.dtim_period);
|
||||
|
|
|
@ -207,6 +207,12 @@ static const struct cfg80211_pmsr_capabilities iwl_mvm_pmsr_capa = {
|
|||
},
|
||||
};
|
||||
|
||||
static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw,
|
||||
enum set_key_cmd cmd,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_sta *sta,
|
||||
struct ieee80211_key_conf *key);
|
||||
|
||||
void iwl_mvm_ref(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type)
|
||||
{
|
||||
if (!iwl_mvm_is_d0i3_supported(mvm))
|
||||
|
@ -1439,7 +1445,7 @@ static void iwl_mvm_mac_stop(struct ieee80211_hw *hw)
|
|||
*/
|
||||
clear_bit(IWL_MVM_STATUS_FIRMWARE_RUNNING, &mvm->status);
|
||||
|
||||
iwl_fw_cancel_dump(&mvm->fwrt);
|
||||
iwl_fw_cancel_dumps(&mvm->fwrt);
|
||||
cancel_delayed_work_sync(&mvm->cs_tx_unblock_dwork);
|
||||
cancel_delayed_work_sync(&mvm->scan_timeout_dwork);
|
||||
iwl_fw_free_dump_desc(&mvm->fwrt);
|
||||
|
@ -2365,22 +2371,23 @@ static void iwl_mvm_cfg_he_sta(struct iwl_mvm *mvm,
|
|||
|
||||
/* Mark MU EDCA as enabled, unless none detected on some AC */
|
||||
flags |= STA_CTXT_HE_MU_EDCA_CW;
|
||||
for (i = 0; i < AC_NUM; i++) {
|
||||
for (i = 0; i < IEEE80211_NUM_ACS; i++) {
|
||||
struct ieee80211_he_mu_edca_param_ac_rec *mu_edca =
|
||||
&mvmvif->queue_params[i].mu_edca_param_rec;
|
||||
u8 ac = iwl_mvm_mac80211_ac_to_ucode_ac(i);
|
||||
|
||||
if (!mvmvif->queue_params[i].mu_edca) {
|
||||
flags &= ~STA_CTXT_HE_MU_EDCA_CW;
|
||||
break;
|
||||
}
|
||||
|
||||
sta_ctxt_cmd.trig_based_txf[i].cwmin =
|
||||
sta_ctxt_cmd.trig_based_txf[ac].cwmin =
|
||||
cpu_to_le16(mu_edca->ecw_min_max & 0xf);
|
||||
sta_ctxt_cmd.trig_based_txf[i].cwmax =
|
||||
sta_ctxt_cmd.trig_based_txf[ac].cwmax =
|
||||
cpu_to_le16((mu_edca->ecw_min_max & 0xf0) >> 4);
|
||||
sta_ctxt_cmd.trig_based_txf[i].aifsn =
|
||||
sta_ctxt_cmd.trig_based_txf[ac].aifsn =
|
||||
cpu_to_le16(mu_edca->aifsn);
|
||||
sta_ctxt_cmd.trig_based_txf[i].mu_time =
|
||||
sta_ctxt_cmd.trig_based_txf[ac].mu_time =
|
||||
cpu_to_le16(mu_edca->mu_edca_timer);
|
||||
}
|
||||
|
||||
|
@ -2636,7 +2643,7 @@ static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw,
|
|||
{
|
||||
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
|
||||
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
|
||||
int ret;
|
||||
int ret, i;
|
||||
|
||||
/*
|
||||
* iwl_mvm_mac_ctxt_add() might read directly from the device
|
||||
|
@ -2710,6 +2717,20 @@ static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw,
|
|||
/* must be set before quota calculations */
|
||||
mvmvif->ap_ibss_active = true;
|
||||
|
||||
/* send all the early keys to the device now */
|
||||
for (i = 0; i < ARRAY_SIZE(mvmvif->ap_early_keys); i++) {
|
||||
struct ieee80211_key_conf *key = mvmvif->ap_early_keys[i];
|
||||
|
||||
if (!key)
|
||||
continue;
|
||||
|
||||
mvmvif->ap_early_keys[i] = NULL;
|
||||
|
||||
ret = iwl_mvm_mac_set_key(hw, SET_KEY, vif, NULL, key);
|
||||
if (ret)
|
||||
goto out_quota_failed;
|
||||
}
|
||||
|
||||
if (vif->type == NL80211_IFTYPE_AP && !vif->p2p) {
|
||||
iwl_mvm_vif_set_low_latency(mvmvif, true,
|
||||
LOW_LATENCY_VIF_TYPE);
|
||||
|
@ -3479,11 +3500,12 @@ static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw,
|
|||
struct ieee80211_sta *sta,
|
||||
struct ieee80211_key_conf *key)
|
||||
{
|
||||
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
|
||||
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
|
||||
struct iwl_mvm_sta *mvmsta;
|
||||
struct iwl_mvm_key_pn *ptk_pn;
|
||||
int keyidx = key->keyidx;
|
||||
int ret;
|
||||
int ret, i;
|
||||
u8 key_offset;
|
||||
|
||||
if (iwlwifi_mod_params.swcrypto) {
|
||||
|
@ -3556,6 +3578,22 @@ static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw,
|
|||
key->hw_key_idx = STA_KEY_IDX_INVALID;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!mvmvif->ap_ibss_active) {
|
||||
for (i = 0;
|
||||
i < ARRAY_SIZE(mvmvif->ap_early_keys);
|
||||
i++) {
|
||||
if (!mvmvif->ap_early_keys[i]) {
|
||||
mvmvif->ap_early_keys[i] = key;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i >= ARRAY_SIZE(mvmvif->ap_early_keys))
|
||||
ret = -ENOSPC;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* During FW restart, in order to restore the state as it was,
|
||||
|
@ -3624,6 +3662,18 @@ static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw,
|
|||
|
||||
break;
|
||||
case DISABLE_KEY:
|
||||
ret = -ENOENT;
|
||||
for (i = 0; i < ARRAY_SIZE(mvmvif->ap_early_keys); i++) {
|
||||
if (mvmvif->ap_early_keys[i] == key) {
|
||||
mvmvif->ap_early_keys[i] = NULL;
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* found in pending list - don't do anything else */
|
||||
if (ret == 0)
|
||||
break;
|
||||
|
||||
if (key->hw_key_idx == STA_KEY_IDX_INVALID) {
|
||||
ret = 0;
|
||||
break;
|
||||
|
|
|
@ -501,6 +501,9 @@ struct iwl_mvm_vif {
|
|||
netdev_features_t features;
|
||||
|
||||
struct iwl_probe_resp_data __rcu *probe_resp_data;
|
||||
|
||||
/* we can only have 2 GTK + 2 IGTK active at a time */
|
||||
struct ieee80211_key_conf *ap_early_keys[4];
|
||||
};
|
||||
|
||||
static inline struct iwl_mvm_vif *
|
||||
|
@ -1107,7 +1110,6 @@ struct iwl_mvm {
|
|||
u8 ps_disabled; /* u8 instead of bool to ease debugfs_create_* usage */
|
||||
/* Indicate if 32Khz external clock is valid */
|
||||
u32 ext_clock_valid;
|
||||
unsigned int max_amsdu_len; /* used for debugfs only */
|
||||
|
||||
struct ieee80211_vif __rcu *csa_vif;
|
||||
struct ieee80211_vif __rcu *csa_tx_blocked_vif;
|
||||
|
@ -1181,6 +1183,7 @@ struct iwl_mvm {
|
|||
#ifdef CONFIG_ACPI
|
||||
struct iwl_mvm_sar_profile sar_profiles[ACPI_SAR_PROFILE_NUM];
|
||||
struct iwl_mvm_geo_profile geo_profiles[ACPI_NUM_GEO_PROFILES];
|
||||
u32 geo_rev;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
@ -1307,6 +1310,12 @@ static inline bool iwl_mvm_is_adaptive_dwell_v2_supported(struct iwl_mvm *mvm)
|
|||
IWL_UCODE_TLV_API_ADAPTIVE_DWELL_V2);
|
||||
}
|
||||
|
||||
static inline bool iwl_mvm_is_adwell_hb_ap_num_supported(struct iwl_mvm *mvm)
|
||||
{
|
||||
return fw_has_api(&mvm->fw->ucode_capa,
|
||||
IWL_UCODE_TLV_API_ADWELL_HB_DEF_N_AP);
|
||||
}
|
||||
|
||||
static inline bool iwl_mvm_is_oce_supported(struct iwl_mvm *mvm)
|
||||
{
|
||||
/* OCE should never be enabled for LMAC scan FWs */
|
||||
|
@ -1532,6 +1541,7 @@ void iwl_mvm_hwrate_to_tx_rate(u32 rate_n_flags,
|
|||
enum nl80211_band band,
|
||||
struct ieee80211_tx_rate *r);
|
||||
u8 iwl_mvm_mac80211_idx_to_hwrate(int rate_idx);
|
||||
u8 iwl_mvm_mac80211_ac_to_ucode_ac(enum ieee80211_ac_numbers ac);
|
||||
void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm);
|
||||
u8 first_antenna(u8 mask);
|
||||
u8 iwl_mvm_next_antenna(struct iwl_mvm *mvm, u8 valid, u8 last_idx);
|
||||
|
|
|
@ -620,6 +620,7 @@ void iwl_mvm_rx_chub_update_mcc(struct iwl_mvm *mvm,
|
|||
enum iwl_mcc_source src;
|
||||
char mcc[3];
|
||||
struct ieee80211_regdomain *regd;
|
||||
u32 wgds_tbl_idx;
|
||||
|
||||
lockdep_assert_held(&mvm->mutex);
|
||||
|
||||
|
@ -643,6 +644,14 @@ void iwl_mvm_rx_chub_update_mcc(struct iwl_mvm *mvm,
|
|||
if (IS_ERR_OR_NULL(regd))
|
||||
return;
|
||||
|
||||
wgds_tbl_idx = iwl_mvm_get_sar_geo_profile(mvm);
|
||||
if (wgds_tbl_idx < 0)
|
||||
IWL_DEBUG_INFO(mvm, "SAR WGDS is disabled (%d)\n",
|
||||
wgds_tbl_idx);
|
||||
else
|
||||
IWL_DEBUG_INFO(mvm, "SAR WGDS: geo profile %d is configured\n",
|
||||
wgds_tbl_idx);
|
||||
|
||||
regulatory_set_wiphy_regd(mvm->hw->wiphy, regd);
|
||||
kfree(regd);
|
||||
}
|
||||
|
|
|
@ -564,24 +564,24 @@ static void iwl_mvm_tx_unblock_dwork(struct work_struct *work)
|
|||
static int iwl_mvm_fwrt_dump_start(void *ctx)
|
||||
{
|
||||
struct iwl_mvm *mvm = ctx;
|
||||
int ret;
|
||||
|
||||
ret = iwl_mvm_ref_sync(mvm, IWL_MVM_REF_FW_DBG_COLLECT);
|
||||
if (ret)
|
||||
return ret;
|
||||
int ret = 0;
|
||||
|
||||
mutex_lock(&mvm->mutex);
|
||||
|
||||
return 0;
|
||||
ret = iwl_mvm_ref_sync(mvm, IWL_MVM_REF_FW_DBG_COLLECT);
|
||||
if (ret)
|
||||
mutex_unlock(&mvm->mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void iwl_mvm_fwrt_dump_end(void *ctx)
|
||||
{
|
||||
struct iwl_mvm *mvm = ctx;
|
||||
|
||||
mutex_unlock(&mvm->mutex);
|
||||
|
||||
iwl_mvm_unref(mvm, IWL_MVM_REF_FW_DBG_COLLECT);
|
||||
|
||||
mutex_unlock(&mvm->mutex);
|
||||
}
|
||||
|
||||
static bool iwl_mvm_fwrt_fw_running(void *ctx)
|
||||
|
@ -799,11 +799,11 @@ 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_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.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->iml = mvm->fw->iml;
|
||||
trans->iml_len = mvm->fw->iml_len;
|
||||
|
@ -880,7 +880,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
|
|||
return op_mode;
|
||||
|
||||
out_free:
|
||||
iwl_fw_flush_dump(&mvm->fwrt);
|
||||
iwl_fw_flush_dumps(&mvm->fwrt);
|
||||
iwl_fw_runtime_free(&mvm->fwrt);
|
||||
|
||||
if (iwlmvm_mod_params.init_dbg)
|
||||
|
|
|
@ -101,7 +101,7 @@ static u8 rs_fw_sgi_cw_support(struct ieee80211_sta *sta)
|
|||
struct ieee80211_sta_he_cap *he_cap = &sta->he_cap;
|
||||
u8 supp = 0;
|
||||
|
||||
if (he_cap && he_cap->has_he)
|
||||
if (he_cap->has_he)
|
||||
return 0;
|
||||
|
||||
if (ht_cap->cap & IEEE80211_HT_CAP_SGI_20)
|
||||
|
@ -123,12 +123,12 @@ static u16 rs_fw_get_config_flags(struct iwl_mvm *mvm,
|
|||
struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
|
||||
struct ieee80211_sta_vht_cap *vht_cap = &sta->vht_cap;
|
||||
struct ieee80211_sta_he_cap *he_cap = &sta->he_cap;
|
||||
bool vht_ena = vht_cap && vht_cap->vht_supported;
|
||||
bool vht_ena = vht_cap->vht_supported;
|
||||
u16 flags = 0;
|
||||
|
||||
if (mvm->cfg->ht_params->stbc &&
|
||||
(num_of_ant(iwl_mvm_get_valid_tx_ant(mvm)) > 1)) {
|
||||
if (he_cap && he_cap->has_he) {
|
||||
if (he_cap->has_he) {
|
||||
if (he_cap->he_cap_elem.phy_cap_info[2] &
|
||||
IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ)
|
||||
flags |= IWL_TLC_MNG_CFG_FLAGS_STBC_MSK;
|
||||
|
@ -136,15 +136,14 @@ static u16 rs_fw_get_config_flags(struct iwl_mvm *mvm,
|
|||
if (he_cap->he_cap_elem.phy_cap_info[7] &
|
||||
IEEE80211_HE_PHY_CAP7_STBC_RX_ABOVE_80MHZ)
|
||||
flags |= IWL_TLC_MNG_CFG_FLAGS_HE_STBC_160MHZ_MSK;
|
||||
} else if ((ht_cap &&
|
||||
(ht_cap->cap & IEEE80211_HT_CAP_RX_STBC)) ||
|
||||
} else if ((ht_cap->cap & IEEE80211_HT_CAP_RX_STBC) ||
|
||||
(vht_ena &&
|
||||
(vht_cap->cap & IEEE80211_VHT_CAP_RXSTBC_MASK)))
|
||||
flags |= IWL_TLC_MNG_CFG_FLAGS_STBC_MSK;
|
||||
}
|
||||
|
||||
if (mvm->cfg->ht_params->ldpc &&
|
||||
((ht_cap && (ht_cap->cap & IEEE80211_HT_CAP_LDPC_CODING)) ||
|
||||
((ht_cap->cap & IEEE80211_HT_CAP_LDPC_CODING) ||
|
||||
(vht_ena && (vht_cap->cap & IEEE80211_VHT_CAP_RXLDPC))))
|
||||
flags |= IWL_TLC_MNG_CFG_FLAGS_LDPC_MSK;
|
||||
|
||||
|
@ -154,7 +153,7 @@ static u16 rs_fw_get_config_flags(struct iwl_mvm *mvm,
|
|||
IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD))
|
||||
flags &= ~IWL_TLC_MNG_CFG_FLAGS_LDPC_MSK;
|
||||
|
||||
if (he_cap && he_cap->has_he &&
|
||||
if (he_cap->has_he &&
|
||||
(he_cap->he_cap_elem.phy_cap_info[3] &
|
||||
IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_MASK))
|
||||
flags |= IWL_TLC_MNG_CFG_FLAGS_HE_DCM_NSS_1_MSK;
|
||||
|
@ -293,13 +292,13 @@ static void rs_fw_set_supp_rates(struct ieee80211_sta *sta,
|
|||
cmd->mode = IWL_TLC_MNG_MODE_NON_HT;
|
||||
|
||||
/* HT/VHT rates */
|
||||
if (he_cap && he_cap->has_he) {
|
||||
if (he_cap->has_he) {
|
||||
cmd->mode = IWL_TLC_MNG_MODE_HE;
|
||||
rs_fw_he_set_enabled_rates(sta, sband, cmd);
|
||||
} else if (vht_cap && vht_cap->vht_supported) {
|
||||
} else if (vht_cap->vht_supported) {
|
||||
cmd->mode = IWL_TLC_MNG_MODE_VHT;
|
||||
rs_fw_vht_set_enabled_rates(sta, vht_cap, cmd);
|
||||
} else if (ht_cap && ht_cap->ht_supported) {
|
||||
} else if (ht_cap->ht_supported) {
|
||||
cmd->mode = IWL_TLC_MNG_MODE_HT;
|
||||
cmd->ht_rates[0][0] = cpu_to_le16(ht_cap->mcs.rx_mask[0]);
|
||||
cmd->ht_rates[1][0] = cpu_to_le16(ht_cap->mcs.rx_mask[1]);
|
||||
|
@ -344,7 +343,7 @@ void iwl_mvm_tlc_update_notif(struct iwl_mvm *mvm,
|
|||
lq_sta->last_rate_n_flags);
|
||||
}
|
||||
|
||||
if (flags & IWL_TLC_NOTIF_FLAG_AMSDU) {
|
||||
if (flags & IWL_TLC_NOTIF_FLAG_AMSDU && !mvmsta->orig_amsdu_len) {
|
||||
u16 size = le32_to_cpu(notif->amsdu_size);
|
||||
int i;
|
||||
|
||||
|
@ -381,7 +380,7 @@ static u16 rs_fw_get_max_amsdu_len(struct ieee80211_sta *sta)
|
|||
const struct ieee80211_sta_vht_cap *vht_cap = &sta->vht_cap;
|
||||
const struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
|
||||
|
||||
if (vht_cap && vht_cap->vht_supported) {
|
||||
if (vht_cap->vht_supported) {
|
||||
switch (vht_cap->cap & IEEE80211_VHT_CAP_MAX_MPDU_MASK) {
|
||||
case IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454:
|
||||
return IEEE80211_MAX_MPDU_LEN_VHT_11454;
|
||||
|
@ -391,7 +390,7 @@ static u16 rs_fw_get_max_amsdu_len(struct ieee80211_sta *sta)
|
|||
return IEEE80211_MAX_MPDU_LEN_VHT_3895;
|
||||
}
|
||||
|
||||
} else if (ht_cap && ht_cap->ht_supported) {
|
||||
} else if (ht_cap->ht_supported) {
|
||||
if (ht_cap->cap & IEEE80211_HT_CAP_MAX_AMSDU)
|
||||
/*
|
||||
* agg is offloaded so we need to assume that agg
|
||||
|
|
|
@ -83,8 +83,10 @@
|
|||
#define IWL_SCAN_ADWELL_MAX_BUDGET_FULL_SCAN 300
|
||||
/* adaptive dwell max budget time [TU] for directed scan */
|
||||
#define IWL_SCAN_ADWELL_MAX_BUDGET_DIRECTED_SCAN 100
|
||||
/* adaptive dwell default APs number */
|
||||
#define IWL_SCAN_ADWELL_DEFAULT_N_APS 2
|
||||
/* adaptive dwell default high band APs number */
|
||||
#define IWL_SCAN_ADWELL_DEFAULT_HB_N_APS 8
|
||||
/* adaptive dwell default low band APs number */
|
||||
#define IWL_SCAN_ADWELL_DEFAULT_LB_N_APS 2
|
||||
/* adaptive dwell default APs number in social channels (1, 6, 11) */
|
||||
#define IWL_SCAN_ADWELL_DEFAULT_N_APS_SOCIAL 10
|
||||
|
||||
|
@ -1288,7 +1290,11 @@ static void iwl_mvm_scan_umac_dwell(struct iwl_mvm *mvm,
|
|||
cmd->v7.adwell_default_n_aps_social =
|
||||
IWL_SCAN_ADWELL_DEFAULT_N_APS_SOCIAL;
|
||||
cmd->v7.adwell_default_n_aps =
|
||||
IWL_SCAN_ADWELL_DEFAULT_N_APS;
|
||||
IWL_SCAN_ADWELL_DEFAULT_LB_N_APS;
|
||||
|
||||
if (iwl_mvm_is_adwell_hb_ap_num_supported(mvm))
|
||||
cmd->v9.adwell_default_hb_n_aps =
|
||||
IWL_SCAN_ADWELL_DEFAULT_HB_N_APS;
|
||||
|
||||
/* if custom max budget was configured with debugfs */
|
||||
if (IWL_MVM_ADWELL_MAX_BUDGET)
|
||||
|
|
|
@ -386,6 +386,9 @@ struct iwl_mvm_rxq_dup_data {
|
|||
* @amsdu_enabled: bitmap of TX AMSDU allowed TIDs.
|
||||
* In case TLC offload is not active it is either 0xFFFF or 0.
|
||||
* @max_amsdu_len: max AMSDU length
|
||||
* @orig_amsdu_len: used to save the original amsdu_len when it is changed via
|
||||
* debugfs. If it's set to 0, it means that it is it's not set via
|
||||
* debugfs.
|
||||
* @agg_tids: bitmap of tids whose status is operational aggregated (IWL_AGG_ON)
|
||||
* @sleep_tx_count: the number of frames that we told the firmware to let out
|
||||
* even when that station is asleep. This is useful in case the queue
|
||||
|
@ -434,6 +437,7 @@ struct iwl_mvm_sta {
|
|||
bool disable_tx;
|
||||
u16 amsdu_enabled;
|
||||
u16 max_amsdu_len;
|
||||
u16 orig_amsdu_len;
|
||||
bool sleeping;
|
||||
u8 agg_tids;
|
||||
u8 sleep_tx_count;
|
||||
|
|
|
@ -726,6 +726,9 @@ int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb)
|
|||
|
||||
memcpy(&info, skb->cb, sizeof(info));
|
||||
|
||||
if (WARN_ON_ONCE(skb->len > IEEE80211_MAX_DATA_LEN + hdrlen))
|
||||
return -1;
|
||||
|
||||
if (WARN_ON_ONCE(info.flags & IEEE80211_TX_CTL_AMPDU))
|
||||
return -1;
|
||||
|
||||
|
@ -893,18 +896,15 @@ static int iwl_mvm_tx_tso(struct iwl_mvm *mvm, struct sk_buff *skb,
|
|||
unsigned int mss = skb_shinfo(skb)->gso_size;
|
||||
unsigned int num_subframes, tcp_payload_len, subf_len, max_amsdu_len;
|
||||
u16 snap_ip_tcp, pad;
|
||||
unsigned int dbg_max_amsdu_len;
|
||||
netdev_features_t netdev_flags = NETIF_F_CSUM_MASK | NETIF_F_SG;
|
||||
u8 tid;
|
||||
|
||||
snap_ip_tcp = 8 + skb_transport_header(skb) - skb_network_header(skb) +
|
||||
tcp_hdrlen(skb);
|
||||
|
||||
dbg_max_amsdu_len = READ_ONCE(mvm->max_amsdu_len);
|
||||
|
||||
if (!mvmsta->max_amsdu_len ||
|
||||
!ieee80211_is_data_qos(hdr->frame_control) ||
|
||||
(!mvmsta->amsdu_enabled && !dbg_max_amsdu_len))
|
||||
!mvmsta->amsdu_enabled)
|
||||
return iwl_mvm_tx_tso_segment(skb, 1, netdev_flags, mpdus_skb);
|
||||
|
||||
/*
|
||||
|
@ -936,10 +936,6 @@ static int iwl_mvm_tx_tso(struct iwl_mvm *mvm, struct sk_buff *skb,
|
|||
|
||||
max_amsdu_len = iwl_mvm_max_amsdu_size(mvm, sta, tid);
|
||||
|
||||
if (unlikely(dbg_max_amsdu_len))
|
||||
max_amsdu_len = min_t(unsigned int, max_amsdu_len,
|
||||
dbg_max_amsdu_len);
|
||||
|
||||
/*
|
||||
* Limit A-MSDU in A-MPDU to 4095 bytes when VHT is not
|
||||
* supported. This is a spec requirement (IEEE 802.11-2015
|
||||
|
@ -1063,7 +1059,9 @@ static int iwl_mvm_tx_pkt_queued(struct iwl_mvm *mvm,
|
|||
}
|
||||
|
||||
/*
|
||||
* Sets the fields in the Tx cmd that are crypto related
|
||||
* Sets the fields in the Tx cmd that are crypto related.
|
||||
*
|
||||
* This function must be called with BHs disabled.
|
||||
*/
|
||||
static int iwl_mvm_tx_mpdu(struct iwl_mvm *mvm, struct sk_buff *skb,
|
||||
struct ieee80211_tx_info *info,
|
||||
|
|
|
@ -238,6 +238,18 @@ u8 iwl_mvm_mac80211_idx_to_hwrate(int rate_idx)
|
|||
return fw_rate_idx_to_plcp[rate_idx];
|
||||
}
|
||||
|
||||
u8 iwl_mvm_mac80211_ac_to_ucode_ac(enum ieee80211_ac_numbers ac)
|
||||
{
|
||||
static const u8 mac80211_ac_to_ucode_ac[] = {
|
||||
AC_VO,
|
||||
AC_VI,
|
||||
AC_BE,
|
||||
AC_BK
|
||||
};
|
||||
|
||||
return mac80211_ac_to_ucode_ac[ac];
|
||||
}
|
||||
|
||||
void iwl_mvm_rx_fw_error(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb)
|
||||
{
|
||||
struct iwl_rx_packet *pkt = rxb_addr(rxb);
|
||||
|
@ -457,10 +469,10 @@ static void iwl_mvm_dump_umac_error_log(struct iwl_mvm *mvm)
|
|||
{
|
||||
struct iwl_trans *trans = mvm->trans;
|
||||
struct iwl_umac_error_event_table table;
|
||||
u32 base = mvm->trans->umac_error_event_table;
|
||||
u32 base = mvm->trans->dbg.umac_error_event_table;
|
||||
|
||||
if (!mvm->support_umac_log &&
|
||||
!(mvm->trans->error_event_table_tlv_status &
|
||||
!(mvm->trans->dbg.error_event_table_tlv_status &
|
||||
IWL_ERROR_EVENT_TABLE_UMAC))
|
||||
return;
|
||||
|
||||
|
@ -496,7 +508,7 @@ static void iwl_mvm_dump_lmac_error_log(struct iwl_mvm *mvm, u8 lmac_num)
|
|||
{
|
||||
struct iwl_trans *trans = mvm->trans;
|
||||
struct iwl_error_event_table table;
|
||||
u32 val, base = mvm->trans->lmac_error_event_table[lmac_num];
|
||||
u32 val, base = mvm->trans->dbg.lmac_error_event_table[lmac_num];
|
||||
|
||||
if (mvm->fwrt.cur_fw_img == IWL_UCODE_INIT) {
|
||||
if (!base)
|
||||
|
@ -592,7 +604,7 @@ void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm)
|
|||
|
||||
iwl_mvm_dump_lmac_error_log(mvm, 0);
|
||||
|
||||
if (mvm->trans->lmac_error_event_table[1])
|
||||
if (mvm->trans->dbg.lmac_error_event_table[1])
|
||||
iwl_mvm_dump_lmac_error_log(mvm, 1);
|
||||
|
||||
iwl_mvm_dump_umac_error_log(mvm);
|
||||
|
|
|
@ -96,13 +96,13 @@ int iwl_pcie_ctxt_info_gen3_init(struct iwl_trans *trans,
|
|||
cpu_to_le64(trans_pcie->rxq->bd_dma);
|
||||
|
||||
/* Configure debug, for integration */
|
||||
if (!trans->ini_valid)
|
||||
if (!trans->dbg.ini_valid)
|
||||
iwl_pcie_alloc_fw_monitor(trans, 0);
|
||||
if (trans->num_blocks) {
|
||||
if (trans->dbg.num_blocks) {
|
||||
prph_sc_ctrl->hwm_cfg.hwm_base_addr =
|
||||
cpu_to_le64(trans->fw_mon[0].physical);
|
||||
cpu_to_le64(trans->dbg.fw_mon[0].physical);
|
||||
prph_sc_ctrl->hwm_cfg.hwm_size =
|
||||
cpu_to_le32(trans->fw_mon[0].size);
|
||||
cpu_to_le32(trans->dbg.fw_mon[0].size);
|
||||
}
|
||||
|
||||
/* allocate ucode sections in dram and set addresses */
|
||||
|
@ -169,7 +169,7 @@ int iwl_pcie_ctxt_info_gen3_init(struct iwl_trans *trans,
|
|||
|
||||
memcpy(iml_img, trans->iml, trans->iml_len);
|
||||
|
||||
iwl_enable_interrupts(trans);
|
||||
iwl_enable_fw_load_int_ctx_info(trans);
|
||||
|
||||
/* kick FW self load */
|
||||
iwl_write64(trans, CSR_CTXT_INFO_ADDR,
|
||||
|
|
|
@ -222,7 +222,7 @@ int iwl_pcie_ctxt_info_init(struct iwl_trans *trans,
|
|||
|
||||
trans_pcie->ctxt_info = ctxt_info;
|
||||
|
||||
iwl_enable_interrupts(trans);
|
||||
iwl_enable_fw_load_int_ctx_info(trans);
|
||||
|
||||
/* Configure debug, if exists */
|
||||
if (iwl_pcie_dbg_on(trans))
|
||||
|
|
|
@ -874,6 +874,33 @@ static inline void iwl_enable_fw_load_int(struct iwl_trans *trans)
|
|||
}
|
||||
}
|
||||
|
||||
static inline void iwl_enable_fw_load_int_ctx_info(struct iwl_trans *trans)
|
||||
{
|
||||
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
|
||||
|
||||
IWL_DEBUG_ISR(trans, "Enabling ALIVE interrupt only\n");
|
||||
|
||||
if (!trans_pcie->msix_enabled) {
|
||||
/*
|
||||
* When we'll receive the ALIVE interrupt, the ISR will call
|
||||
* iwl_enable_fw_load_int_ctx_info again to set the ALIVE
|
||||
* interrupt (which is not really needed anymore) but also the
|
||||
* RX interrupt which will allow us to receive the ALIVE
|
||||
* notification (which is Rx) and continue the flow.
|
||||
*/
|
||||
trans_pcie->inta_mask = CSR_INT_BIT_ALIVE | CSR_INT_BIT_FH_RX;
|
||||
iwl_write32(trans, CSR_INT_MASK, trans_pcie->inta_mask);
|
||||
} else {
|
||||
iwl_enable_hw_int_msk_msix(trans,
|
||||
MSIX_HW_INT_CAUSES_REG_ALIVE);
|
||||
/*
|
||||
* Leave all the FH causes enabled to get the ALIVE
|
||||
* notification.
|
||||
*/
|
||||
iwl_enable_fh_int_msk_msix(trans, trans_pcie->fh_init_mask);
|
||||
}
|
||||
}
|
||||
|
||||
static inline u16 iwl_pcie_get_cmd_index(const struct iwl_txq *q, u32 index)
|
||||
{
|
||||
return index & (q->n_window - 1);
|
||||
|
@ -1018,7 +1045,7 @@ static inline void __iwl_trans_pcie_set_bit(struct iwl_trans *trans,
|
|||
|
||||
static inline bool iwl_pcie_dbg_on(struct iwl_trans *trans)
|
||||
{
|
||||
return (trans->dbg_dest_tlv || trans->ini_valid);
|
||||
return (trans->dbg.dest_tlv || trans->dbg.ini_valid);
|
||||
}
|
||||
|
||||
void iwl_trans_pcie_rf_kill(struct iwl_trans *trans, bool state);
|
||||
|
|
|
@ -1827,26 +1827,26 @@ irqreturn_t iwl_pcie_irq_handler(int irq, void *dev_id)
|
|||
goto out;
|
||||
}
|
||||
|
||||
if (iwl_have_debug_level(IWL_DL_ISR)) {
|
||||
/* NIC fires this, but we don't use it, redundant with WAKEUP */
|
||||
if (inta & CSR_INT_BIT_SCD) {
|
||||
IWL_DEBUG_ISR(trans,
|
||||
"Scheduler finished to transmit the frame/frames.\n");
|
||||
isr_stats->sch++;
|
||||
/* NIC fires this, but we don't use it, redundant with WAKEUP */
|
||||
if (inta & CSR_INT_BIT_SCD) {
|
||||
IWL_DEBUG_ISR(trans,
|
||||
"Scheduler finished to transmit the frame/frames.\n");
|
||||
isr_stats->sch++;
|
||||
}
|
||||
|
||||
/* Alive notification via Rx interrupt will do the real work */
|
||||
if (inta & CSR_INT_BIT_ALIVE) {
|
||||
IWL_DEBUG_ISR(trans, "Alive interrupt\n");
|
||||
isr_stats->alive++;
|
||||
if (trans->cfg->gen2) {
|
||||
/*
|
||||
* We can restock, since firmware configured
|
||||
* the RFH
|
||||
*/
|
||||
iwl_pcie_rxmq_restock(trans, trans_pcie->rxq);
|
||||
}
|
||||
|
||||
/* Alive notification via Rx interrupt will do the real work */
|
||||
if (inta & CSR_INT_BIT_ALIVE) {
|
||||
IWL_DEBUG_ISR(trans, "Alive interrupt\n");
|
||||
isr_stats->alive++;
|
||||
if (trans->cfg->gen2) {
|
||||
/*
|
||||
* We can restock, since firmware configured
|
||||
* the RFH
|
||||
*/
|
||||
iwl_pcie_rxmq_restock(trans, trans_pcie->rxq);
|
||||
}
|
||||
}
|
||||
handled |= CSR_INT_BIT_ALIVE;
|
||||
}
|
||||
|
||||
/* Safely ignore these bits for debug checks below */
|
||||
|
@ -1965,6 +1965,9 @@ irqreturn_t iwl_pcie_irq_handler(int irq, void *dev_id)
|
|||
/* Re-enable RF_KILL if it occurred */
|
||||
else if (handled & CSR_INT_BIT_RF_KILL)
|
||||
iwl_enable_rfkill_int(trans);
|
||||
/* Re-enable the ALIVE / Rx interrupt if it occurred */
|
||||
else if (handled & (CSR_INT_BIT_ALIVE | CSR_INT_BIT_FH_RX))
|
||||
iwl_enable_fw_load_int_ctx_info(trans);
|
||||
spin_unlock(&trans_pcie->irq_lock);
|
||||
|
||||
out:
|
||||
|
@ -2108,10 +2111,18 @@ irqreturn_t iwl_pcie_irq_msix_handler(int irq, void *dev_id)
|
|||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
if (iwl_have_debug_level(IWL_DL_ISR))
|
||||
IWL_DEBUG_ISR(trans, "ISR inta_fh 0x%08x, enabled 0x%08x\n",
|
||||
inta_fh,
|
||||
if (iwl_have_debug_level(IWL_DL_ISR)) {
|
||||
IWL_DEBUG_ISR(trans,
|
||||
"ISR inta_fh 0x%08x, enabled (sw) 0x%08x (hw) 0x%08x\n",
|
||||
inta_fh, trans_pcie->fh_mask,
|
||||
iwl_read32(trans, CSR_MSIX_FH_INT_MASK_AD));
|
||||
if (inta_fh & ~trans_pcie->fh_mask)
|
||||
IWL_DEBUG_ISR(trans,
|
||||
"We got a masked interrupt (0x%08x)\n",
|
||||
inta_fh & ~trans_pcie->fh_mask);
|
||||
}
|
||||
|
||||
inta_fh &= trans_pcie->fh_mask;
|
||||
|
||||
if ((trans_pcie->shared_vec_mask & IWL_SHARED_IRQ_NON_RX) &&
|
||||
inta_fh & MSIX_FH_INT_CAUSES_Q0) {
|
||||
|
@ -2151,11 +2162,18 @@ irqreturn_t iwl_pcie_irq_msix_handler(int irq, void *dev_id)
|
|||
}
|
||||
|
||||
/* After checking FH register check HW register */
|
||||
if (iwl_have_debug_level(IWL_DL_ISR))
|
||||
if (iwl_have_debug_level(IWL_DL_ISR)) {
|
||||
IWL_DEBUG_ISR(trans,
|
||||
"ISR inta_hw 0x%08x, enabled 0x%08x\n",
|
||||
inta_hw,
|
||||
"ISR inta_hw 0x%08x, enabled (sw) 0x%08x (hw) 0x%08x\n",
|
||||
inta_hw, trans_pcie->hw_mask,
|
||||
iwl_read32(trans, CSR_MSIX_HW_INT_MASK_AD));
|
||||
if (inta_hw & ~trans_pcie->hw_mask)
|
||||
IWL_DEBUG_ISR(trans,
|
||||
"We got a masked interrupt 0x%08x\n",
|
||||
inta_hw & ~trans_pcie->hw_mask);
|
||||
}
|
||||
|
||||
inta_hw &= trans_pcie->hw_mask;
|
||||
|
||||
/* Alive notification via Rx interrupt will do the real work */
|
||||
if (inta_hw & MSIX_HW_INT_CAUSES_REG_ALIVE) {
|
||||
|
@ -2212,7 +2230,7 @@ irqreturn_t iwl_pcie_irq_msix_handler(int irq, void *dev_id)
|
|||
"Hardware error detected. Restarting.\n");
|
||||
|
||||
isr_stats->hw++;
|
||||
trans->hw_error = true;
|
||||
trans->dbg.hw_error = true;
|
||||
iwl_pcie_irq_handle_error(trans);
|
||||
}
|
||||
|
||||
|
|
|
@ -148,7 +148,7 @@ void _iwl_trans_pcie_gen2_stop_device(struct iwl_trans *trans, bool low_power)
|
|||
trans_pcie->is_down = true;
|
||||
|
||||
/* Stop dbgc before stopping device */
|
||||
_iwl_fw_dbg_stop_recording(trans, NULL);
|
||||
iwl_fw_dbg_stop_recording(trans, NULL);
|
||||
|
||||
/* tell the device to stop sending interrupts */
|
||||
iwl_disable_interrupts(trans);
|
||||
|
@ -273,6 +273,15 @@ void iwl_trans_pcie_gen2_fw_alive(struct iwl_trans *trans, u32 scd_addr)
|
|||
* paging memory cannot be freed included since FW will still use it
|
||||
*/
|
||||
iwl_pcie_ctxt_info_free(trans);
|
||||
|
||||
/*
|
||||
* Re-enable all the interrupts, including the RF-Kill one, now that
|
||||
* the firmware is alive.
|
||||
*/
|
||||
iwl_enable_interrupts(trans);
|
||||
mutex_lock(&trans_pcie->mutex);
|
||||
iwl_pcie_check_hw_rf_kill(trans);
|
||||
mutex_unlock(&trans_pcie->mutex);
|
||||
}
|
||||
|
||||
int iwl_trans_pcie_gen2_start_fw(struct iwl_trans *trans,
|
||||
|
|
|
@ -90,8 +90,10 @@
|
|||
|
||||
void iwl_trans_pcie_dump_regs(struct iwl_trans *trans)
|
||||
{
|
||||
#define PCI_DUMP_SIZE 64
|
||||
#define PREFIX_LEN 32
|
||||
#define PCI_DUMP_SIZE 352
|
||||
#define PCI_MEM_DUMP_SIZE 64
|
||||
#define PCI_PARENT_DUMP_SIZE 524
|
||||
#define PREFIX_LEN 32
|
||||
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
|
||||
struct pci_dev *pdev = trans_pcie->pci_dev;
|
||||
u32 i, pos, alloc_size, *ptr, *buf;
|
||||
|
@ -102,11 +104,15 @@ void iwl_trans_pcie_dump_regs(struct iwl_trans *trans)
|
|||
|
||||
/* Should be a multiple of 4 */
|
||||
BUILD_BUG_ON(PCI_DUMP_SIZE > 4096 || PCI_DUMP_SIZE & 0x3);
|
||||
BUILD_BUG_ON(PCI_MEM_DUMP_SIZE > 4096 || PCI_MEM_DUMP_SIZE & 0x3);
|
||||
BUILD_BUG_ON(PCI_PARENT_DUMP_SIZE > 4096 || PCI_PARENT_DUMP_SIZE & 0x3);
|
||||
|
||||
/* Alloc a max size buffer */
|
||||
if (PCI_ERR_ROOT_ERR_SRC + 4 > PCI_DUMP_SIZE)
|
||||
alloc_size = PCI_ERR_ROOT_ERR_SRC + 4 + PREFIX_LEN;
|
||||
else
|
||||
alloc_size = PCI_DUMP_SIZE + PREFIX_LEN;
|
||||
alloc_size = PCI_ERR_ROOT_ERR_SRC + 4 + PREFIX_LEN;
|
||||
alloc_size = max_t(u32, alloc_size, PCI_DUMP_SIZE + PREFIX_LEN);
|
||||
alloc_size = max_t(u32, alloc_size, PCI_MEM_DUMP_SIZE + PREFIX_LEN);
|
||||
alloc_size = max_t(u32, alloc_size, PCI_PARENT_DUMP_SIZE + PREFIX_LEN);
|
||||
|
||||
buf = kmalloc(alloc_size, GFP_ATOMIC);
|
||||
if (!buf)
|
||||
return;
|
||||
|
@ -123,7 +129,7 @@ void iwl_trans_pcie_dump_regs(struct iwl_trans *trans)
|
|||
print_hex_dump(KERN_ERR, prefix, DUMP_PREFIX_OFFSET, 32, 4, buf, i, 0);
|
||||
|
||||
IWL_ERR(trans, "iwlwifi device memory mapped registers:\n");
|
||||
for (i = 0, ptr = buf; i < PCI_DUMP_SIZE; i += 4, ptr++)
|
||||
for (i = 0, ptr = buf; i < PCI_MEM_DUMP_SIZE; i += 4, ptr++)
|
||||
*ptr = iwl_read32(trans, i);
|
||||
print_hex_dump(KERN_ERR, prefix, DUMP_PREFIX_OFFSET, 32, 4, buf, i, 0);
|
||||
|
||||
|
@ -146,7 +152,7 @@ void iwl_trans_pcie_dump_regs(struct iwl_trans *trans)
|
|||
|
||||
IWL_ERR(trans, "iwlwifi parent port (%s) config registers:\n",
|
||||
pci_name(pdev));
|
||||
for (i = 0, ptr = buf; i < PCI_DUMP_SIZE; i += 4, ptr++)
|
||||
for (i = 0, ptr = buf; i < PCI_PARENT_DUMP_SIZE; i += 4, ptr++)
|
||||
if (pci_read_config_dword(pdev, i, ptr))
|
||||
goto err_read;
|
||||
print_hex_dump(KERN_ERR, prefix, DUMP_PREFIX_OFFSET, 32, 4, buf, i, 0);
|
||||
|
@ -188,14 +194,14 @@ static void iwl_pcie_free_fw_monitor(struct iwl_trans *trans)
|
|||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < trans->num_blocks; i++) {
|
||||
dma_free_coherent(trans->dev, trans->fw_mon[i].size,
|
||||
trans->fw_mon[i].block,
|
||||
trans->fw_mon[i].physical);
|
||||
trans->fw_mon[i].block = NULL;
|
||||
trans->fw_mon[i].physical = 0;
|
||||
trans->fw_mon[i].size = 0;
|
||||
trans->num_blocks--;
|
||||
for (i = 0; i < trans->dbg.num_blocks; i++) {
|
||||
dma_free_coherent(trans->dev, trans->dbg.fw_mon[i].size,
|
||||
trans->dbg.fw_mon[i].block,
|
||||
trans->dbg.fw_mon[i].physical);
|
||||
trans->dbg.fw_mon[i].block = NULL;
|
||||
trans->dbg.fw_mon[i].physical = 0;
|
||||
trans->dbg.fw_mon[i].size = 0;
|
||||
trans->dbg.num_blocks--;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -230,10 +236,10 @@ static void iwl_pcie_alloc_fw_monitor_block(struct iwl_trans *trans,
|
|||
(unsigned long)BIT(power - 10),
|
||||
(unsigned long)BIT(max_power - 10));
|
||||
|
||||
trans->fw_mon[trans->num_blocks].block = cpu_addr;
|
||||
trans->fw_mon[trans->num_blocks].physical = phys;
|
||||
trans->fw_mon[trans->num_blocks].size = size;
|
||||
trans->num_blocks++;
|
||||
trans->dbg.fw_mon[trans->dbg.num_blocks].block = cpu_addr;
|
||||
trans->dbg.fw_mon[trans->dbg.num_blocks].physical = phys;
|
||||
trans->dbg.fw_mon[trans->dbg.num_blocks].size = size;
|
||||
trans->dbg.num_blocks++;
|
||||
}
|
||||
|
||||
void iwl_pcie_alloc_fw_monitor(struct iwl_trans *trans, u8 max_power)
|
||||
|
@ -254,7 +260,7 @@ void iwl_pcie_alloc_fw_monitor(struct iwl_trans *trans, u8 max_power)
|
|||
* This function allocats the default fw monitor.
|
||||
* The optional additional ones will be allocated in runtime
|
||||
*/
|
||||
if (trans->num_blocks)
|
||||
if (trans->dbg.num_blocks)
|
||||
return;
|
||||
|
||||
iwl_pcie_alloc_fw_monitor_block(trans, max_power, 11);
|
||||
|
@ -889,21 +895,21 @@ static int iwl_pcie_load_cpu_sections(struct iwl_trans *trans,
|
|||
|
||||
void iwl_pcie_apply_destination(struct iwl_trans *trans)
|
||||
{
|
||||
const struct iwl_fw_dbg_dest_tlv_v1 *dest = trans->dbg_dest_tlv;
|
||||
const struct iwl_fw_dbg_dest_tlv_v1 *dest = trans->dbg.dest_tlv;
|
||||
int i;
|
||||
|
||||
if (trans->ini_valid) {
|
||||
if (!trans->num_blocks)
|
||||
if (trans->dbg.ini_valid) {
|
||||
if (!trans->dbg.num_blocks)
|
||||
return;
|
||||
|
||||
IWL_DEBUG_FW(trans,
|
||||
"WRT: applying DRAM buffer[0] destination\n");
|
||||
iwl_write_umac_prph(trans, MON_BUFF_BASE_ADDR_VER2,
|
||||
trans->fw_mon[0].physical >>
|
||||
trans->dbg.fw_mon[0].physical >>
|
||||
MON_BUFF_SHIFT_VER2);
|
||||
iwl_write_umac_prph(trans, MON_BUFF_END_ADDR_VER2,
|
||||
(trans->fw_mon[0].physical +
|
||||
trans->fw_mon[0].size - 256) >>
|
||||
(trans->dbg.fw_mon[0].physical +
|
||||
trans->dbg.fw_mon[0].size - 256) >>
|
||||
MON_BUFF_SHIFT_VER2);
|
||||
return;
|
||||
}
|
||||
|
@ -916,7 +922,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_n_dest_reg; 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);
|
||||
|
||||
|
@ -955,18 +961,19 @@ void iwl_pcie_apply_destination(struct iwl_trans *trans)
|
|||
}
|
||||
|
||||
monitor:
|
||||
if (dest->monitor_mode == EXTERNAL_MODE && trans->fw_mon[0].size) {
|
||||
if (dest->monitor_mode == EXTERNAL_MODE && trans->dbg.fw_mon[0].size) {
|
||||
iwl_write_prph(trans, le32_to_cpu(dest->base_reg),
|
||||
trans->fw_mon[0].physical >> dest->base_shift);
|
||||
trans->dbg.fw_mon[0].physical >>
|
||||
dest->base_shift);
|
||||
if (trans->cfg->device_family >= IWL_DEVICE_FAMILY_8000)
|
||||
iwl_write_prph(trans, le32_to_cpu(dest->end_reg),
|
||||
(trans->fw_mon[0].physical +
|
||||
trans->fw_mon[0].size - 256) >>
|
||||
(trans->dbg.fw_mon[0].physical +
|
||||
trans->dbg.fw_mon[0].size - 256) >>
|
||||
dest->end_shift);
|
||||
else
|
||||
iwl_write_prph(trans, le32_to_cpu(dest->end_reg),
|
||||
(trans->fw_mon[0].physical +
|
||||
trans->fw_mon[0].size) >>
|
||||
(trans->dbg.fw_mon[0].physical +
|
||||
trans->dbg.fw_mon[0].size) >>
|
||||
dest->end_shift);
|
||||
}
|
||||
}
|
||||
|
@ -1003,12 +1010,12 @@ static int iwl_pcie_load_given_ucode(struct iwl_trans *trans,
|
|||
trans->cfg->device_family == IWL_DEVICE_FAMILY_7000) {
|
||||
iwl_pcie_alloc_fw_monitor(trans, 0);
|
||||
|
||||
if (trans->fw_mon[0].size) {
|
||||
if (trans->dbg.fw_mon[0].size) {
|
||||
iwl_write_prph(trans, MON_BUFF_BASE_ADDR,
|
||||
trans->fw_mon[0].physical >> 4);
|
||||
trans->dbg.fw_mon[0].physical >> 4);
|
||||
iwl_write_prph(trans, MON_BUFF_END_ADDR,
|
||||
(trans->fw_mon[0].physical +
|
||||
trans->fw_mon[0].size) >> 4);
|
||||
(trans->dbg.fw_mon[0].physical +
|
||||
trans->dbg.fw_mon[0].size) >> 4);
|
||||
}
|
||||
} else if (iwl_pcie_dbg_on(trans)) {
|
||||
iwl_pcie_apply_destination(trans);
|
||||
|
@ -1236,7 +1243,7 @@ static void _iwl_trans_pcie_stop_device(struct iwl_trans *trans, bool low_power)
|
|||
trans_pcie->is_down = true;
|
||||
|
||||
/* Stop dbgc before stopping device */
|
||||
_iwl_fw_dbg_stop_recording(trans, NULL);
|
||||
iwl_fw_dbg_stop_recording(trans, NULL);
|
||||
|
||||
/* tell the device to stop sending interrupts */
|
||||
iwl_disable_interrupts(trans);
|
||||
|
@ -2729,8 +2736,8 @@ static int iwl_dbgfs_monitor_data_open(struct inode *inode,
|
|||
struct iwl_trans *trans = inode->i_private;
|
||||
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
|
||||
|
||||
if (!trans->dbg_dest_tlv ||
|
||||
trans->dbg_dest_tlv->monitor_mode != EXTERNAL_MODE) {
|
||||
if (!trans->dbg.dest_tlv ||
|
||||
trans->dbg.dest_tlv->monitor_mode != EXTERNAL_MODE) {
|
||||
IWL_ERR(trans, "Debug destination is not set to DRAM\n");
|
||||
return -ENOENT;
|
||||
}
|
||||
|
@ -2777,22 +2784,22 @@ static ssize_t iwl_dbgfs_monitor_data_read(struct file *file,
|
|||
{
|
||||
struct iwl_trans *trans = file->private_data;
|
||||
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
|
||||
void *cpu_addr = (void *)trans->fw_mon[0].block, *curr_buf;
|
||||
void *cpu_addr = (void *)trans->dbg.fw_mon[0].block, *curr_buf;
|
||||
struct cont_rec *data = &trans_pcie->fw_mon_data;
|
||||
u32 write_ptr_addr, wrap_cnt_addr, write_ptr, wrap_cnt;
|
||||
ssize_t size, bytes_copied = 0;
|
||||
bool b_full;
|
||||
|
||||
if (trans->dbg_dest_tlv) {
|
||||
if (trans->dbg.dest_tlv) {
|
||||
write_ptr_addr =
|
||||
le32_to_cpu(trans->dbg_dest_tlv->write_ptr_reg);
|
||||
wrap_cnt_addr = le32_to_cpu(trans->dbg_dest_tlv->wrap_count);
|
||||
le32_to_cpu(trans->dbg.dest_tlv->write_ptr_reg);
|
||||
wrap_cnt_addr = le32_to_cpu(trans->dbg.dest_tlv->wrap_count);
|
||||
} else {
|
||||
write_ptr_addr = MON_BUFF_WRPTR;
|
||||
wrap_cnt_addr = MON_BUFF_CYCLE_CNT;
|
||||
}
|
||||
|
||||
if (unlikely(!trans->dbg_rec_on))
|
||||
if (unlikely(!trans->dbg.rec_on))
|
||||
return 0;
|
||||
|
||||
mutex_lock(&data->mutex);
|
||||
|
@ -2816,7 +2823,7 @@ static ssize_t iwl_dbgfs_monitor_data_read(struct file *file,
|
|||
|
||||
} else if (data->prev_wrap_cnt == wrap_cnt - 1 &&
|
||||
write_ptr < data->prev_wr_ptr) {
|
||||
size = trans->fw_mon[0].size - data->prev_wr_ptr;
|
||||
size = trans->dbg.fw_mon[0].size - data->prev_wr_ptr;
|
||||
curr_buf = cpu_addr + data->prev_wr_ptr;
|
||||
b_full = iwl_write_to_user_buf(user_buf, count,
|
||||
curr_buf, &size,
|
||||
|
@ -3035,14 +3042,10 @@ iwl_trans_pcie_dump_pointers(struct iwl_trans *trans,
|
|||
base_high = DBGC_CUR_DBGBUF_BASE_ADDR_MSB;
|
||||
write_ptr = DBGC_CUR_DBGBUF_STATUS;
|
||||
wrap_cnt = DBGC_DBGBUF_WRAP_AROUND;
|
||||
} else if (trans->ini_valid) {
|
||||
base = iwl_umac_prph(trans, MON_BUFF_BASE_ADDR_VER2);
|
||||
write_ptr = iwl_umac_prph(trans, MON_BUFF_WRPTR_VER2);
|
||||
wrap_cnt = iwl_umac_prph(trans, MON_BUFF_CYCLE_CNT_VER2);
|
||||
} else if (trans->dbg_dest_tlv) {
|
||||
write_ptr = le32_to_cpu(trans->dbg_dest_tlv->write_ptr_reg);
|
||||
wrap_cnt = le32_to_cpu(trans->dbg_dest_tlv->wrap_count);
|
||||
base = le32_to_cpu(trans->dbg_dest_tlv->base_reg);
|
||||
} else if (trans->dbg.dest_tlv) {
|
||||
write_ptr = le32_to_cpu(trans->dbg.dest_tlv->write_ptr_reg);
|
||||
wrap_cnt = le32_to_cpu(trans->dbg.dest_tlv->wrap_count);
|
||||
base = le32_to_cpu(trans->dbg.dest_tlv->base_reg);
|
||||
} else {
|
||||
base = MON_BUFF_BASE_ADDR;
|
||||
write_ptr = MON_BUFF_WRPTR;
|
||||
|
@ -3069,11 +3072,10 @@ iwl_trans_pcie_dump_monitor(struct iwl_trans *trans,
|
|||
{
|
||||
u32 len = 0;
|
||||
|
||||
if ((trans->num_blocks &&
|
||||
if (trans->dbg.dest_tlv ||
|
||||
(trans->dbg.num_blocks &&
|
||||
(trans->cfg->device_family == IWL_DEVICE_FAMILY_7000 ||
|
||||
trans->cfg->device_family >= IWL_DEVICE_FAMILY_AX210 ||
|
||||
trans->ini_valid)) ||
|
||||
(trans->dbg_dest_tlv && !trans->ini_valid)) {
|
||||
trans->cfg->device_family >= IWL_DEVICE_FAMILY_AX210))) {
|
||||
struct iwl_fw_error_dump_fw_mon *fw_mon_data;
|
||||
|
||||
(*data)->type = cpu_to_le32(IWL_FW_ERROR_DUMP_FW_MONITOR);
|
||||
|
@ -3082,32 +3084,32 @@ iwl_trans_pcie_dump_monitor(struct iwl_trans *trans,
|
|||
iwl_trans_pcie_dump_pointers(trans, fw_mon_data);
|
||||
|
||||
len += sizeof(**data) + sizeof(*fw_mon_data);
|
||||
if (trans->num_blocks) {
|
||||
if (trans->dbg.num_blocks) {
|
||||
memcpy(fw_mon_data->data,
|
||||
trans->fw_mon[0].block,
|
||||
trans->fw_mon[0].size);
|
||||
trans->dbg.fw_mon[0].block,
|
||||
trans->dbg.fw_mon[0].size);
|
||||
|
||||
monitor_len = trans->fw_mon[0].size;
|
||||
} else if (trans->dbg_dest_tlv->monitor_mode == SMEM_MODE) {
|
||||
monitor_len = trans->dbg.fw_mon[0].size;
|
||||
} else if (trans->dbg.dest_tlv->monitor_mode == SMEM_MODE) {
|
||||
u32 base = le32_to_cpu(fw_mon_data->fw_mon_base_ptr);
|
||||
/*
|
||||
* Update pointers to reflect actual values after
|
||||
* shifting
|
||||
*/
|
||||
if (trans->dbg_dest_tlv->version) {
|
||||
if (trans->dbg.dest_tlv->version) {
|
||||
base = (iwl_read_prph(trans, base) &
|
||||
IWL_LDBG_M2S_BUF_BA_MSK) <<
|
||||
trans->dbg_dest_tlv->base_shift;
|
||||
trans->dbg.dest_tlv->base_shift;
|
||||
base *= IWL_M2S_UNIT_SIZE;
|
||||
base += trans->cfg->smem_offset;
|
||||
} else {
|
||||
base = iwl_read_prph(trans, base) <<
|
||||
trans->dbg_dest_tlv->base_shift;
|
||||
trans->dbg.dest_tlv->base_shift;
|
||||
}
|
||||
|
||||
iwl_trans_read_mem(trans, base, fw_mon_data->data,
|
||||
monitor_len / sizeof(u32));
|
||||
} else if (trans->dbg_dest_tlv->monitor_mode == MARBH_MODE) {
|
||||
} else if (trans->dbg.dest_tlv->monitor_mode == MARBH_MODE) {
|
||||
monitor_len =
|
||||
iwl_trans_pci_dump_marbh_monitor(trans,
|
||||
fw_mon_data,
|
||||
|
@ -3126,40 +3128,40 @@ iwl_trans_pcie_dump_monitor(struct iwl_trans *trans,
|
|||
|
||||
static int iwl_trans_get_fw_monitor_len(struct iwl_trans *trans, u32 *len)
|
||||
{
|
||||
if (trans->num_blocks) {
|
||||
if (trans->dbg.num_blocks) {
|
||||
*len += sizeof(struct iwl_fw_error_dump_data) +
|
||||
sizeof(struct iwl_fw_error_dump_fw_mon) +
|
||||
trans->fw_mon[0].size;
|
||||
return trans->fw_mon[0].size;
|
||||
} else if (trans->dbg_dest_tlv) {
|
||||
trans->dbg.fw_mon[0].size;
|
||||
return trans->dbg.fw_mon[0].size;
|
||||
} else if (trans->dbg.dest_tlv) {
|
||||
u32 base, end, cfg_reg, monitor_len;
|
||||
|
||||
if (trans->dbg_dest_tlv->version == 1) {
|
||||
cfg_reg = le32_to_cpu(trans->dbg_dest_tlv->base_reg);
|
||||
if (trans->dbg.dest_tlv->version == 1) {
|
||||
cfg_reg = le32_to_cpu(trans->dbg.dest_tlv->base_reg);
|
||||
cfg_reg = iwl_read_prph(trans, cfg_reg);
|
||||
base = (cfg_reg & IWL_LDBG_M2S_BUF_BA_MSK) <<
|
||||
trans->dbg_dest_tlv->base_shift;
|
||||
trans->dbg.dest_tlv->base_shift;
|
||||
base *= IWL_M2S_UNIT_SIZE;
|
||||
base += trans->cfg->smem_offset;
|
||||
|
||||
monitor_len =
|
||||
(cfg_reg & IWL_LDBG_M2S_BUF_SIZE_MSK) >>
|
||||
trans->dbg_dest_tlv->end_shift;
|
||||
trans->dbg.dest_tlv->end_shift;
|
||||
monitor_len *= IWL_M2S_UNIT_SIZE;
|
||||
} else {
|
||||
base = le32_to_cpu(trans->dbg_dest_tlv->base_reg);
|
||||
end = le32_to_cpu(trans->dbg_dest_tlv->end_reg);
|
||||
base = le32_to_cpu(trans->dbg.dest_tlv->base_reg);
|
||||
end = le32_to_cpu(trans->dbg.dest_tlv->end_reg);
|
||||
|
||||
base = iwl_read_prph(trans, base) <<
|
||||
trans->dbg_dest_tlv->base_shift;
|
||||
trans->dbg.dest_tlv->base_shift;
|
||||
end = iwl_read_prph(trans, end) <<
|
||||
trans->dbg_dest_tlv->end_shift;
|
||||
trans->dbg.dest_tlv->end_shift;
|
||||
|
||||
/* Make "end" point to the actual end */
|
||||
if (trans->cfg->device_family >=
|
||||
IWL_DEVICE_FAMILY_8000 ||
|
||||
trans->dbg_dest_tlv->monitor_mode == MARBH_MODE)
|
||||
end += (1 << trans->dbg_dest_tlv->end_shift);
|
||||
trans->dbg.dest_tlv->monitor_mode == MARBH_MODE)
|
||||
end += (1 << trans->dbg.dest_tlv->end_shift);
|
||||
monitor_len = end - base;
|
||||
}
|
||||
*len += sizeof(struct iwl_fw_error_dump_data) +
|
||||
|
@ -3192,7 +3194,7 @@ static struct iwl_trans_dump_data
|
|||
len = sizeof(*dump_data);
|
||||
|
||||
/* host commands */
|
||||
if (dump_mask & BIT(IWL_FW_ERROR_DUMP_TXCMD))
|
||||
if (dump_mask & BIT(IWL_FW_ERROR_DUMP_TXCMD) && cmdq)
|
||||
len += sizeof(*data) +
|
||||
cmdq->n_window * (sizeof(*txcmd) +
|
||||
TFD_MAX_PAYLOAD_SIZE);
|
||||
|
@ -3244,7 +3246,7 @@ static struct iwl_trans_dump_data
|
|||
len = 0;
|
||||
data = (void *)dump_data->data;
|
||||
|
||||
if (dump_mask & BIT(IWL_FW_ERROR_DUMP_TXCMD)) {
|
||||
if (dump_mask & BIT(IWL_FW_ERROR_DUMP_TXCMD) && cmdq) {
|
||||
u16 tfd_size = trans_pcie->tfd_size;
|
||||
|
||||
data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_TXCMD);
|
||||
|
@ -3681,6 +3683,7 @@ void iwl_trans_pcie_sync_nmi(struct iwl_trans *trans)
|
|||
{
|
||||
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
|
||||
unsigned long timeout = jiffies + IWL_TRANS_NMI_TIMEOUT;
|
||||
bool interrupts_enabled = test_bit(STATUS_INT_ENABLED, &trans->status);
|
||||
u32 inta_addr, sw_err_bit;
|
||||
|
||||
if (trans_pcie->msix_enabled) {
|
||||
|
@ -3691,7 +3694,12 @@ void iwl_trans_pcie_sync_nmi(struct iwl_trans *trans)
|
|||
sw_err_bit = CSR_INT_BIT_SW_ERR;
|
||||
}
|
||||
|
||||
iwl_disable_interrupts(trans);
|
||||
/* if the interrupts were already disabled, there is no point in
|
||||
* calling iwl_disable_interrupts
|
||||
*/
|
||||
if (interrupts_enabled)
|
||||
iwl_disable_interrupts(trans);
|
||||
|
||||
iwl_force_nmi(trans);
|
||||
while (time_after(timeout, jiffies)) {
|
||||
u32 inta_hw = iwl_read32(trans, inta_addr);
|
||||
|
@ -3705,6 +3713,13 @@ void iwl_trans_pcie_sync_nmi(struct iwl_trans *trans)
|
|||
|
||||
mdelay(1);
|
||||
}
|
||||
iwl_enable_interrupts(trans);
|
||||
|
||||
/* enable interrupts only if there were already enabled before this
|
||||
* function to avoid a case were the driver enable interrupts before
|
||||
* proper configurations were made
|
||||
*/
|
||||
if (interrupts_enabled)
|
||||
iwl_enable_interrupts(trans);
|
||||
|
||||
iwl_trans_fw_error(trans);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue