From: Johannes Berg Currently, the dump code attempts to dump any number of memories and register banks, as defined by the firmware. Especially when the device is failing, this can lead to excessive time spent attempting to acquire NIC access over and over again. Improve the code to only attempt to acquire NIC access once or twice, but using the new memory dump functions that may drop the spinlock etc. Mark all dump regions that require NIC access, and skip them if we couldn't obtain that. In order to avoid CPU latency due to the increased time holding the spinlock (and possibly disabling softirqs), drop locks and call cond_resched() after each section (if holding NIC access) but don't release HW NIC access. Signed-off-by: Johannes Berg Signed-off-by: Miri Korenblit --- drivers/net/wireless/intel/iwlwifi/fw/dbg.c | 90 +++++++++---------- .../net/wireless/intel/iwlwifi/iwl-trans.c | 5 ++ .../net/wireless/intel/iwlwifi/iwl-trans.h | 11 +++ .../intel/iwlwifi/pcie/gen1_2/internal.h | 1 + .../intel/iwlwifi/pcie/gen1_2/trans.c | 2 +- 5 files changed, 63 insertions(+), 46 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c index 069c3bad6f29..337e312c2f43 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c @@ -103,7 +103,7 @@ static int iwl_dump_ini_prph_mac_iter_common(struct iwl_fw_runtime *fwrt, range->internal_base_addr = cpu_to_le32(addr); range->range_data_size = size; for (i = 0; i < le32_to_cpu(size); i += 4) - *val++ = cpu_to_le32(iwl_read_prph(fwrt->trans, addr + i)); + *val++ = cpu_to_le32(iwl_trans_read_prph(fwrt->trans, addr + i)); return sizeof(*range) + le32_to_cpu(range->range_data_size); } @@ -158,9 +158,6 @@ static int iwl_dump_ini_prph_phy_iter_common(struct iwl_fw_runtime *fwrt, indirect_wr_addr += le32_to_cpu(offset); indirect_rd_addr += le32_to_cpu(offset); - if (!iwl_trans_grab_nic_access(fwrt->trans)) - return -EBUSY; - dphy_addr = (offset) ? WFPM_LMAC2_PS_CTL_RW : WFPM_LMAC1_PS_CTL_RW; dphy_state = iwl_read_umac_prph_no_grab(fwrt->trans, dphy_addr); @@ -194,7 +191,6 @@ static int iwl_dump_ini_prph_phy_iter_common(struct iwl_fw_runtime *fwrt, *val++ = cpu_to_le32(prph_val); } - iwl_trans_release_nic_access(fwrt->trans); return sizeof(*range) + le32_to_cpu(range->range_data_size); } @@ -283,8 +279,8 @@ static int iwl_dump_ini_dev_mem_iter(struct iwl_fw_runtime *fwrt, range->internal_base_addr = cpu_to_le32(addr); range->range_data_size = reg->dev_addr.size; - iwl_trans_read_mem_bytes(fwrt->trans, addr, range->data, - le32_to_cpu(reg->dev_addr.size)); + iwl_trans_read_mem_bytes_no_grab(fwrt->trans, addr, range->data, + le32_to_cpu(reg->dev_addr.size)); if (reg->sub_type == IWL_FW_INI_REGION_DEVICE_MEMORY_SUBTYPE_HW_SMEM && fwrt->sanitize_ops && fwrt->sanitize_ops->frob_txf) @@ -368,8 +364,8 @@ static int iwl_dump_ini_mon_smem_iter(struct iwl_fw_runtime *fwrt, range->internal_base_addr = cpu_to_le32(addr); range->range_data_size = reg->internal_buffer.size; - iwl_trans_read_mem_bytes(fwrt->trans, addr, range->data, - le32_to_cpu(reg->internal_buffer.size)); + iwl_trans_read_mem_bytes_no_grab(fwrt->trans, addr, range->data, + le32_to_cpu(reg->internal_buffer.size)); return sizeof(*range) + le32_to_cpu(range->range_data_size); } @@ -443,9 +439,6 @@ static int iwl_dump_ini_txf_iter(struct iwl_fw_runtime *fwrt, if (!iwl_ini_txf_iter(fwrt, reg_data, idx)) return -EIO; - if (!iwl_trans_grab_nic_access(fwrt->trans)) - return -EBUSY; - range->fifo_hdr.fifo_num = cpu_to_le32(iter->fifo); range->fifo_hdr.num_of_registers = cpu_to_le32(registers_num); range->range_data_size = cpu_to_le32(iter->fifo_size + registers_size); @@ -489,8 +482,6 @@ static int iwl_dump_ini_txf_iter(struct iwl_fw_runtime *fwrt, reg_dump, iter->fifo_size); out: - iwl_trans_release_nic_access(fwrt->trans); - return sizeof(*range) + le32_to_cpu(range->range_data_size); } @@ -511,9 +502,6 @@ iwl_dump_ini_prph_snps_dphyip_iter(struct iwl_fw_runtime *fwrt, range->internal_base_addr = cpu_to_le32(addr); range->range_data_size = reg->dev_addr.size; - if (!iwl_trans_grab_nic_access(fwrt->trans)) - return -EBUSY; - indirect_rd_wr_addr += le32_to_cpu(offset); dphy_addr = offset ? WFPM_LMAC2_PS_CTL_RW : WFPM_LMAC1_PS_CTL_RW; @@ -537,7 +525,6 @@ iwl_dump_ini_prph_snps_dphyip_iter(struct iwl_fw_runtime *fwrt, DPHYIP_INDIRECT_RD_SHIFT); } - iwl_trans_release_nic_access(fwrt->trans); return sizeof(*range) + le32_to_cpu(range->range_data_size); } @@ -626,9 +613,6 @@ static int iwl_dump_ini_rxf_iter(struct iwl_fw_runtime *fwrt, if (!rxf_data.size) return -EIO; - if (!iwl_trans_grab_nic_access(fwrt->trans)) - return -EBUSY; - range->fifo_hdr.fifo_num = cpu_to_le32(rxf_data.fifo_num); range->fifo_hdr.num_of_registers = cpu_to_le32(registers_num); range->range_data_size = cpu_to_le32(rxf_data.size + registers_size); @@ -668,8 +652,6 @@ static int iwl_dump_ini_rxf_iter(struct iwl_fw_runtime *fwrt, *data++ = cpu_to_le32(iwl_trans_read_prph(fwrt->trans, addr)); out: - iwl_trans_release_nic_access(fwrt->trans); - return sizeof(*range) + le32_to_cpu(range->range_data_size); } @@ -686,8 +668,8 @@ iwl_dump_ini_err_table_iter(struct iwl_fw_runtime *fwrt, range->internal_base_addr = cpu_to_le32(addr); range->range_data_size = err_table->size; - iwl_trans_read_mem_bytes(fwrt->trans, addr, range->data, - le32_to_cpu(err_table->size)); + iwl_trans_read_mem_bytes_no_grab(fwrt->trans, addr, range->data, + le32_to_cpu(err_table->size)); return sizeof(*range) + le32_to_cpu(range->range_data_size); } @@ -707,8 +689,8 @@ iwl_dump_ini_special_mem_iter(struct iwl_fw_runtime *fwrt, range->internal_base_addr = cpu_to_le32(addr); range->range_data_size = special_mem->size; - iwl_trans_read_mem_bytes(fwrt->trans, addr, range->data, - le32_to_cpu(special_mem->size)); + iwl_trans_read_mem_bytes_no_grab(fwrt->trans, addr, range->data, + le32_to_cpu(special_mem->size)); return sizeof(*range) + le32_to_cpu(range->range_data_size); } @@ -724,9 +706,6 @@ iwl_dump_ini_dbgi_sram_iter(struct iwl_fw_runtime *fwrt, u32 prph_data; int i; - if (!iwl_trans_grab_nic_access(fwrt->trans)) - return -EBUSY; - range->range_data_size = reg->dev_addr.size; for (i = 0; i < (le32_to_cpu(reg->dev_addr.size) / 4); i++) { prph_data = @@ -734,13 +713,11 @@ iwl_dump_ini_dbgi_sram_iter(struct iwl_fw_runtime *fwrt, (i % 2) ? DBGI_SRAM_TARGET_ACCESS_RDATA_MSB : DBGI_SRAM_TARGET_ACCESS_RDATA_LSB); - if (iwl_trans_is_hw_error_value(prph_data)) { - iwl_trans_release_nic_access(fwrt->trans); + if (iwl_trans_is_hw_error_value(prph_data)) return -EBUSY; - } *val++ = cpu_to_le32(prph_data); } - iwl_trans_release_nic_access(fwrt->trans); + return sizeof(*range) + le32_to_cpu(range->range_data_size); } @@ -787,8 +764,8 @@ static int iwl_dump_ini_imr_iter(struct iwl_fw_runtime *fwrt, fwrt->trans->dbg.imr_data.imr_curr_addr = imr_curr_addr + size_to_dump; fwrt->trans->dbg.imr_data.imr2sram_remainbyte -= size_to_dump; - iwl_trans_read_mem_bytes(fwrt->trans, sram_addr, range->data, - size_to_dump); + iwl_trans_read_mem_bytes_no_grab(fwrt->trans, sram_addr, range->data, + size_to_dump); return sizeof(*range) + le32_to_cpu(range->range_data_size); } @@ -842,11 +819,6 @@ iwl_dump_ini_mon_fill_header(struct iwl_fw_runtime *fwrt, u32 alloc_id, struct iwl_fw_ini_monitor_dump *data, const struct iwl_fw_mon_regs *addrs) { - if (!iwl_trans_grab_nic_access(fwrt->trans)) { - IWL_ERR(fwrt, "Failed to get monitor header\n"); - return NULL; - } - data->write_ptr = iwl_get_mon_reg(fwrt, alloc_id, &addrs->write_ptr); if (fwrt->trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_AX210) { @@ -859,8 +831,6 @@ iwl_dump_ini_mon_fill_header(struct iwl_fw_runtime *fwrt, u32 alloc_id, data->cur_frag = iwl_get_mon_reg(fwrt, alloc_id, &addrs->cur_frag); - iwl_trans_release_nic_access(fwrt->trans); - data->header.version = cpu_to_le32(IWL_INI_DUMP_VER); return data->data; @@ -1266,6 +1236,7 @@ iwl_dump_ini_imr_get_size(struct iwl_fw_runtime *fwrt, * the first range or NULL if failed to fill headers. * @fill_range: copies a given memory range into the dump. * Returns the size of the range or negative error value otherwise. + * @requires_nic_access: indicates to dump only if NIC access was acquired */ struct iwl_dump_ini_mem_ops { u32 (*get_num_of_ranges)(struct iwl_fw_runtime *fwrt, @@ -1278,6 +1249,7 @@ struct iwl_dump_ini_mem_ops { int (*fill_range)(struct iwl_fw_runtime *fwrt, struct iwl_dump_ini_region_data *reg_data, void *range, int idx); + bool requires_nic_access; }; struct iwl_fw_ini_dump_entry { @@ -1374,7 +1346,8 @@ static void iwl_dump_ini_mem_prep(struct iwl_fw_runtime *fwrt, } static u32 iwl_dump_ini_mem(struct iwl_fw_runtime *fwrt, - struct iwl_fw_ini_dump_entry *entry) + struct iwl_fw_ini_dump_entry *entry, + bool have_nic_access) { struct iwl_dump_ini_region_data *reg_data = &entry->reg_data; struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data; @@ -1388,6 +1361,9 @@ static u32 iwl_dump_ini_mem(struct iwl_fw_runtime *fwrt, u32 free_size; u64 header_size; + if (!have_nic_access && ops->requires_nic_access) + goto out_err; + tlv = (void *)entry->data; header = (void *)tlv->data; @@ -1541,36 +1517,42 @@ static const struct iwl_dump_ini_mem_ops iwl_dump_ini_region_ops[] = { .get_size = iwl_dump_ini_mon_smem_get_size, .fill_mem_hdr = iwl_dump_ini_mon_smem_fill_header, .fill_range = iwl_dump_ini_mon_smem_iter, + .requires_nic_access = true, }, [IWL_FW_INI_REGION_DRAM_BUFFER] = { .get_num_of_ranges = iwl_dump_ini_mon_dram_ranges, .get_size = iwl_dump_ini_mon_dram_get_size, .fill_mem_hdr = iwl_dump_ini_mon_dram_fill_header, .fill_range = iwl_dump_ini_mon_dram_iter, + .requires_nic_access = true, }, [IWL_FW_INI_REGION_TXF] = { .get_num_of_ranges = iwl_dump_ini_txf_ranges, .get_size = iwl_dump_ini_txf_get_size, .fill_mem_hdr = iwl_dump_ini_mem_fill_header, .fill_range = iwl_dump_ini_txf_iter, + .requires_nic_access = true, }, [IWL_FW_INI_REGION_RXF] = { .get_num_of_ranges = iwl_dump_ini_single_range, .get_size = iwl_dump_ini_rxf_get_size, .fill_mem_hdr = iwl_dump_ini_mem_fill_header, .fill_range = iwl_dump_ini_rxf_iter, + .requires_nic_access = true, }, [IWL_FW_INI_REGION_LMAC_ERROR_TABLE] = { .get_num_of_ranges = iwl_dump_ini_single_range, .get_size = iwl_dump_ini_err_table_get_size, .fill_mem_hdr = iwl_dump_ini_err_table_fill_header, .fill_range = iwl_dump_ini_err_table_iter, + .requires_nic_access = true, }, [IWL_FW_INI_REGION_UMAC_ERROR_TABLE] = { .get_num_of_ranges = iwl_dump_ini_single_range, .get_size = iwl_dump_ini_err_table_get_size, .fill_mem_hdr = iwl_dump_ini_err_table_fill_header, .fill_range = iwl_dump_ini_err_table_iter, + .requires_nic_access = true, }, [IWL_FW_INI_REGION_RSP_OR_NOTIF] = { .get_num_of_ranges = iwl_dump_ini_single_range, @@ -1583,30 +1565,35 @@ static const struct iwl_dump_ini_mem_ops iwl_dump_ini_region_ops[] = { .get_size = iwl_dump_ini_mem_get_size, .fill_mem_hdr = iwl_dump_ini_mem_fill_header, .fill_range = iwl_dump_ini_dev_mem_iter, + .requires_nic_access = true, }, [IWL_FW_INI_REGION_PERIPHERY_MAC] = { .get_num_of_ranges = iwl_dump_ini_mem_ranges, .get_size = iwl_dump_ini_mem_get_size, .fill_mem_hdr = iwl_dump_ini_mem_fill_header, .fill_range = iwl_dump_ini_prph_mac_iter, + .requires_nic_access = true, }, [IWL_FW_INI_REGION_PERIPHERY_PHY] = { .get_num_of_ranges = iwl_dump_ini_mem_ranges, .get_size = iwl_dump_ini_mem_get_size, .fill_mem_hdr = iwl_dump_ini_mem_fill_header, .fill_range = iwl_dump_ini_prph_phy_iter, + .requires_nic_access = true, }, [IWL_FW_INI_REGION_PERIPHERY_MAC_RANGE] = { .get_num_of_ranges = iwl_dump_ini_mem_block_ranges, .get_size = iwl_dump_ini_mem_block_get_size, .fill_mem_hdr = iwl_dump_ini_mem_fill_header, .fill_range = iwl_dump_ini_prph_mac_block_iter, + .requires_nic_access = true, }, [IWL_FW_INI_REGION_PERIPHERY_PHY_RANGE] = { .get_num_of_ranges = iwl_dump_ini_mem_block_ranges, .get_size = iwl_dump_ini_mem_block_get_size, .fill_mem_hdr = iwl_dump_ini_mem_fill_header, .fill_range = iwl_dump_ini_prph_phy_block_iter, + .requires_nic_access = true, }, [IWL_FW_INI_REGION_PERIPHERY_AUX] = {}, [IWL_FW_INI_REGION_PAGING] = { @@ -1626,6 +1613,7 @@ static const struct iwl_dump_ini_mem_ops iwl_dump_ini_region_ops[] = { .get_size = iwl_dump_ini_imr_get_size, .fill_mem_hdr = iwl_dump_ini_imr_fill_header, .fill_range = iwl_dump_ini_imr_iter, + .requires_nic_access = true, }, [IWL_FW_INI_REGION_PCI_IOSF_CONFIG] = { .get_num_of_ranges = iwl_dump_ini_mem_ranges, @@ -1638,18 +1626,21 @@ static const struct iwl_dump_ini_mem_ops iwl_dump_ini_region_ops[] = { .get_size = iwl_dump_ini_special_mem_get_size, .fill_mem_hdr = iwl_dump_ini_special_mem_fill_header, .fill_range = iwl_dump_ini_special_mem_iter, + .requires_nic_access = true, }, [IWL_FW_INI_REGION_DBGI_SRAM] = { .get_num_of_ranges = iwl_dump_ini_mem_ranges, .get_size = iwl_dump_ini_mon_dbgi_get_size, .fill_mem_hdr = iwl_dump_ini_mon_dbgi_fill_header, .fill_range = iwl_dump_ini_dbgi_sram_iter, + .requires_nic_access = true, }, [IWL_FW_INI_REGION_PERIPHERY_SNPS_DPHYIP] = { .get_num_of_ranges = iwl_dump_ini_mem_ranges, .get_size = iwl_dump_ini_mem_get_size, .fill_mem_hdr = iwl_dump_ini_mem_fill_header, .fill_range = iwl_dump_ini_prph_snps_dphyip_iter, + .requires_nic_access = true, }, }; @@ -1733,8 +1724,11 @@ iwl_dump_ini_dump_entries(struct iwl_fw_runtime *fwrt, enum iwl_dump_ini_region_selector which) { struct iwl_fw_ini_dump_entry *entry, *tmp; + bool have_nic_access; u32 size = 0; + have_nic_access = iwl_trans_grab_nic_access(fwrt->trans); + list_for_each_entry_safe(entry, tmp, list, list) { u32 dp = entry->region_dump_policy; @@ -1751,9 +1745,15 @@ iwl_dump_ini_dump_entries(struct iwl_fw_runtime *fwrt, break; } - size += iwl_dump_ini_mem(fwrt, entry); + size += iwl_dump_ini_mem(fwrt, entry, have_nic_access); + + if (have_nic_access) + iwl_trans_resched_with_nic_access(fwrt->trans); } + if (have_nic_access) + iwl_trans_release_nic_access(fwrt->trans); + return size; } diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.c b/drivers/net/wireless/intel/iwlwifi/iwl-trans.c index 0009488ca51b..73aae1125042 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.c @@ -558,6 +558,11 @@ bool iwl_trans_grab_nic_access(struct iwl_trans *trans) } IWL_EXPORT_SYMBOL(iwl_trans_grab_nic_access); +void iwl_trans_resched_with_nic_access(struct iwl_trans *trans) +{ + iwl_trans_pcie_resched_with_nic_access(trans); +} + void __releases(nic_access) iwl_trans_release_nic_access(struct iwl_trans *trans) { diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h index 3ae840e546e8..914864005704 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h @@ -981,6 +981,17 @@ void iwl_trans_set_bits_mask(struct iwl_trans *trans, u32 reg, bool iwl_trans_grab_nic_access(struct iwl_trans *trans); +/** + * iwl_trans_resched_with_nic_access - reschedule while holding NIC access + * @trans: the transport pointer + * + * This can be called while holding NIC access, during periods where + * the lock itself isn't interesting, the NIC should remain active, + * but a lot of processing is happening and the CPU may need to be + * released. In practice, this is only during FW dump. + */ +void iwl_trans_resched_with_nic_access(struct iwl_trans *trans); + void __releases(nic_access) iwl_trans_release_nic_access(struct iwl_trans *trans); diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/internal.h b/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/internal.h index abc0c831d1ca..d84c7c1efee1 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/internal.h +++ b/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/internal.h @@ -1203,6 +1203,7 @@ void iwl_trans_pcie_set_bits_mask(struct iwl_trans *trans, u32 reg, int iwl_trans_pcie_read_config32(struct iwl_trans *trans, u32 ofs, u32 *val); bool iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans); +void iwl_trans_pcie_resched_with_nic_access(struct iwl_trans *trans); void __releases(nic_access_nobh) iwl_trans_pcie_release_nic_access(struct iwl_trans *trans); void iwl_pcie_alloc_fw_monitor(struct iwl_trans *trans, u8 max_power); diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans.c index 1c4ee76d8387..40fd5f3fdeb7 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans.c @@ -2424,7 +2424,7 @@ bool iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans) return false; } -static void iwl_trans_pcie_resched_with_nic_access(struct iwl_trans *trans) +void iwl_trans_pcie_resched_with_nic_access(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); -- 2.34.1