]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
wifi: iwlwifi: fw: cut down NIC wakeups during dump
authorJohannes Berg <johannes.berg@intel.com>
Wed, 27 May 2026 20:04:58 +0000 (23:04 +0300)
committerMiri Korenblit <miriam.rachel.korenblit@intel.com>
Wed, 3 Jun 2026 14:02:54 +0000 (17:02 +0300)
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 <johannes.berg@intel.com>
Link: https://patch.msgid.link/20260527230313.bec886142cc8.I41f2eaf2403b38147504d5dab0a7414de2699adc@changeid
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
drivers/net/wireless/intel/iwlwifi/fw/dbg.c
drivers/net/wireless/intel/iwlwifi/iwl-trans.c
drivers/net/wireless/intel/iwlwifi/iwl-trans.h
drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/internal.h
drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans.c

index 069c3bad6f29f96d708750b6ffa87c2d3e99f080..337e312c2f43dc8deffe502229e7f0365e347bf7 100644 (file)
@@ -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;
 }
 
index 0009488ca51b132f4fc759c74141cb6b7521e80d..73aae11250421f4738a535538a6be2389a1e1f8a 100644 (file)
@@ -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)
 {
index 3ae840e546e8211212382f38b7eb7c687ba0753a..914864005704a76a9ae996375660aa077f85bc7d 100644 (file)
@@ -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);
 
index abc0c831d1ca73e910eb7aab0d9f963f384c7268..d84c7c1efee1c07b4257d0cc635236c1e8e18e00 100644 (file)
@@ -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);
index 1c4ee76d8387731c14047fef973501b4c30cc764..40fd5f3fdeb74e4c31649a33255d00075cc70dde 100644 (file)
@@ -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);