From 78038d0e59304f1c81a30d48c9f97097b676e639 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Tue, 4 Nov 2014 00:06:12 +0000 Subject: [PATCH] iwlwifi: Backport firmware monitor from 3.17 (Closes: #767088) svn path=/dists/sid/linux/; revision=22029 --- debian/changelog | 1 + ...evice-firmware-to-fw-error-dump-file.patch | 175 ++++++++++ ...collect-logs-in-the-interrupt-thread.patch | 159 +++++++++ ...i-mvm-kill-iwl_mvm_fw_error_rxf_dump.patch | 315 ++++++++++++++++++ ...update-layout-of-firmware-error-dump.patch | 28 ++ ...ie-add-firmware-monitor-capabilities.patch | 315 ++++++++++++++++++ ...out-alignment-in-iwl-fw-error-dump.h.patch | 30 ++ ...fi-rename-iwl_mvm_fw_error_next_data.patch | 62 ++++ debian/patches/series | 7 + 9 files changed, 1092 insertions(+) create mode 100644 debian/patches/features/all/iwlwifi-debug/iwlwifi-add-device-firmware-to-fw-error-dump-file.patch create mode 100644 debian/patches/features/all/iwlwifi-debug/iwlwifi-mvm-don-t-collect-logs-in-the-interrupt-thread.patch create mode 100644 debian/patches/features/all/iwlwifi-debug/iwlwifi-mvm-kill-iwl_mvm_fw_error_rxf_dump.patch create mode 100644 debian/patches/features/all/iwlwifi-debug/iwlwifi-mvm-update-layout-of-firmware-error-dump.patch create mode 100644 debian/patches/features/all/iwlwifi-debug/iwlwifi-pcie-add-firmware-monitor-capabilities.patch create mode 100644 debian/patches/features/all/iwlwifi-debug/iwlwifi-remove-wrong-comment-about-alignment-in-iwl-fw-error-dump.h.patch create mode 100644 debian/patches/features/all/iwlwifi-debug/iwlwifi-rename-iwl_mvm_fw_error_next_data.patch diff --git a/debian/changelog b/debian/changelog index 8dd40e0a7..957aba8c2 100644 --- a/debian/changelog +++ b/debian/changelog @@ -158,6 +158,7 @@ linux (3.16.7-1) UNRELEASED; urgency=medium * [hppa] Reduce SIGRTMIN from 37 to 32 to behave like other Linux architectures (Closes: #766635) * [hppa] udeb: Add many more module packages (Closes: #766793) + * iwlwifi: Backport firmware monitor from 3.17 (Closes: #767088) [ Mauricio Faria de Oliveira ] * [ppc64el] Disable CONFIG_CMDLINE{,_BOOL} usage for setting consoles diff --git a/debian/patches/features/all/iwlwifi-debug/iwlwifi-add-device-firmware-to-fw-error-dump-file.patch b/debian/patches/features/all/iwlwifi-debug/iwlwifi-add-device-firmware-to-fw-error-dump-file.patch new file mode 100644 index 000000000..8fbf0b235 --- /dev/null +++ b/debian/patches/features/all/iwlwifi-debug/iwlwifi-add-device-firmware-to-fw-error-dump-file.patch @@ -0,0 +1,175 @@ +From: Emmanuel Grumbach +Date: Tue, 28 Oct 2014 08:11:20 +0200 +Subject: iwlwifi: add device / firmware to fw-error-dump file +Content-Transfer-Encoding: 8bit +Origin: https://git.kernel.org/linus/06ddbf5adac1fd2a031eade8a92239abfa6db93a +Bug-Debian: https://bugs.debian.org/767088 + +This can be useful later for parsing since the parsing may +differ based on the device's family / bus. +Also add the human readable version of the firmware. + +Signed-off-by: Emmanuel Grumbach +--- + drivers/net/wireless/iwlwifi/iwl-drv.c | 2 ++ + drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h | 24 ++++++++++++++++++++++++ + drivers/net/wireless/iwlwifi/iwl-fw-file.h | 5 +++-- + drivers/net/wireless/iwlwifi/iwl-fw.h | 3 +++ + drivers/net/wireless/iwlwifi/mvm/ops.c | 24 +++++++++++++++++++++--- + 5 files changed, 53 insertions(+), 5 deletions(-) + +diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.c b/drivers/net/wireless/iwlwifi/iwl-drv.c +index f2a5c12..2967fce 100644 +--- a/drivers/net/wireless/iwlwifi/iwl-drv.c ++++ b/drivers/net/wireless/iwlwifi/iwl-drv.c +@@ -565,6 +565,8 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv, + } + + drv->fw.ucode_ver = le32_to_cpu(ucode->ver); ++ memcpy(drv->fw.human_readable, ucode->human_readable, ++ sizeof(drv->fw.human_readable)); + build = le32_to_cpu(ucode->build); + + if (build) +diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h b/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h +index 2953ffc..aa0f85e 100644 +--- a/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h ++++ b/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h +@@ -74,12 +74,15 @@ + * @IWL_FW_ERROR_DUMP_RXF: + * @IWL_FW_ERROR_DUMP_TXCMD: last TX command data, structured as + * &struct iwl_fw_error_dump_txcmd packets ++ * @IWL_FW_ERROR_DUMP_DEV_FW_INFO: struct %iwl_fw_error_dump_info ++ * info on the device / firmware. + */ + enum iwl_fw_error_dump_type { + IWL_FW_ERROR_DUMP_SRAM = 0, + IWL_FW_ERROR_DUMP_REG = 1, + IWL_FW_ERROR_DUMP_RXF = 2, + IWL_FW_ERROR_DUMP_TXCMD = 3, ++ IWL_FW_ERROR_DUMP_DEV_FW_INFO = 4, + + IWL_FW_ERROR_DUMP_MAX, + }; +@@ -120,6 +123,27 @@ struct iwl_fw_error_dump_txcmd { + u8 data[]; + } __packed; + ++enum iwl_fw_error_dump_family { ++ IWL_FW_ERROR_DUMP_FAMILY_7 = 7, ++ IWL_FW_ERROR_DUMP_FAMILY_8 = 8, ++}; ++ ++/** ++ * struct iwl_fw_error_dump_info - info on the device / firmware ++ * @device_family: the family of the device (7 / 8) ++ * @hw_step: the step of the device ++ * @fw_human_readable: human readable FW version ++ * @dev_human_readable: name of the device ++ * @bus_human_readable: name of the bus used ++ */ ++struct iwl_fw_error_dump_info { ++ __le32 device_family; ++ __le32 hw_step; ++ u8 fw_human_readable[FW_VER_HUMAN_READABLE_SZ]; ++ u8 dev_human_readable[64]; ++ u8 bus_human_readable[8]; ++} __packed; ++ + /** + * iwl_mvm_fw_error_next_data - advance fw error dump data pointer + * @data: previous data block +diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-file.h b/drivers/net/wireless/iwlwifi/iwl-fw-file.h +index b45e576..dc1b913 100644 +--- a/drivers/net/wireless/iwlwifi/iwl-fw-file.h ++++ b/drivers/net/wireless/iwlwifi/iwl-fw-file.h +@@ -136,7 +136,8 @@ struct iwl_ucode_tlv { + u8 data[0]; + }; + +-#define IWL_TLV_UCODE_MAGIC 0x0a4c5749 ++#define IWL_TLV_UCODE_MAGIC 0x0a4c5749 ++#define FW_VER_HUMAN_READABLE_SZ 64 + + struct iwl_tlv_ucode_header { + /* +@@ -147,7 +148,7 @@ struct iwl_tlv_ucode_header { + */ + __le32 zero; + __le32 magic; +- u8 human_readable[64]; ++ u8 human_readable[FW_VER_HUMAN_READABLE_SZ]; + __le32 ver; /* major/minor/API/serial */ + __le32 build; + __le64 ignore; +diff --git a/drivers/net/wireless/iwlwifi/iwl-fw.h b/drivers/net/wireless/iwlwifi/iwl-fw.h +index b1a3332..663a91a 100644 +--- a/drivers/net/wireless/iwlwifi/iwl-fw.h ++++ b/drivers/net/wireless/iwlwifi/iwl-fw.h +@@ -65,6 +65,8 @@ + #include + #include + ++#include "iwl-fw-file.h" ++ + /** + * enum iwl_ucode_tlv_flag - ucode API flags + * @IWL_UCODE_TLV_FLAGS_PAN: This is PAN capable microcode; this previously +@@ -312,6 +314,7 @@ struct iwl_fw { + bool mvm_fw; + + struct ieee80211_cipher_scheme cs[IWL_UCODE_MAX_CS]; ++ u8 human_readable[FW_VER_HUMAN_READABLE_SZ]; + }; + + #endif /* __iwl_fw_h__ */ +diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c +index cc2f7de..d2fdd9f 100644 +--- a/drivers/net/wireless/iwlwifi/mvm/ops.c ++++ b/drivers/net/wireless/iwlwifi/mvm/ops.c +@@ -826,6 +826,7 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) + { + struct iwl_fw_error_dump_file *dump_file; + struct iwl_fw_error_dump_data *dump_data; ++ struct iwl_fw_error_dump_info *dump_info; + u32 file_len; + u32 trans_len; + +@@ -834,10 +835,11 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) + if (mvm->fw_error_dump) + return; + +- file_len = mvm->fw_error_sram_len + ++ file_len = sizeof(*dump_file) + ++ sizeof(*dump_data) * 3 + ++ mvm->fw_error_sram_len + + mvm->fw_error_rxf_len + +- sizeof(*dump_file) + +- sizeof(*dump_data) * 2; ++ sizeof(*dump_info); + + trans_len = iwl_trans_dump_data(mvm->trans, NULL, 0); + if (trans_len) +@@ -852,6 +854,22 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) + dump_file->barker = cpu_to_le32(IWL_FW_ERROR_DUMP_BARKER); + dump_file->file_len = cpu_to_le32(file_len); + dump_data = (void *)dump_file->data; ++ ++ dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_DEV_FW_INFO); ++ dump_data->len = cpu_to_le32(sizeof(*dump_info)); ++ dump_info = (void *) dump_data->data; ++ dump_info->device_family = ++ mvm->cfg->device_family == IWL_DEVICE_FAMILY_7000 ? ++ cpu_to_le32(IWL_FW_ERROR_DUMP_FAMILY_7) : ++ cpu_to_le32(IWL_FW_ERROR_DUMP_FAMILY_8); ++ memcpy(dump_info->fw_human_readable, mvm->fw->human_readable, ++ sizeof(dump_info->fw_human_readable)); ++ strncpy(dump_info->dev_human_readable, mvm->cfg->name, ++ sizeof(dump_info->dev_human_readable)); ++ strncpy(dump_info->bus_human_readable, mvm->dev->bus->name, ++ sizeof(dump_info->bus_human_readable)); ++ ++ dump_data = iwl_mvm_fw_error_next_data(dump_data); + dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_RXF); + dump_data->len = cpu_to_le32(mvm->fw_error_rxf_len); + memcpy(dump_data->data, mvm->fw_error_rxf, mvm->fw_error_rxf_len); diff --git a/debian/patches/features/all/iwlwifi-debug/iwlwifi-mvm-don-t-collect-logs-in-the-interrupt-thread.patch b/debian/patches/features/all/iwlwifi-debug/iwlwifi-mvm-don-t-collect-logs-in-the-interrupt-thread.patch new file mode 100644 index 000000000..e6b129490 --- /dev/null +++ b/debian/patches/features/all/iwlwifi-debug/iwlwifi-mvm-don-t-collect-logs-in-the-interrupt-thread.patch @@ -0,0 +1,159 @@ +From: Emmanuel Grumbach +Date: Tue, 28 Oct 2014 08:11:24 +0200 +Subject: iwlwifi: mvm: don't collect logs in the interrupt thread +Content-Transfer-Encoding: 8bit +Origin: https://git.kernel.org/linus/78dae98fab85f4cd2d38cfc3474dea6e87e7b53a +Bug-Debian: https://bugs.debian.org/767088 + +Instead of reading all the data in the context of the +interrupt thread, collect the data in the restart flow +before the actual restart takes place so that the device +still has all the information. +Remove iwl_mvm_fw_error_sram_dump and move its content to +iwl_mvm_fw_error_dump. + +Signed-off-by: Emmanuel Grumbach +--- + drivers/net/wireless/iwlwifi/mvm/mvm.h | 3 --- + drivers/net/wireless/iwlwifi/mvm/ops.c | 31 ++++++++++++------------------- + drivers/net/wireless/iwlwifi/mvm/utils.c | 22 ---------------------- + 3 files changed, 12 insertions(+), 44 deletions(-) + +diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h +index fcc6c29..e084fc6 100644 +--- a/drivers/net/wireless/iwlwifi/mvm/mvm.h ++++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h +@@ -586,8 +586,6 @@ struct iwl_mvm { + /* -1 for always, 0 for never, >0 for that many times */ + s8 restart_fw; + void *fw_error_dump; +- void *fw_error_sram; +- u32 fw_error_sram_len; + u32 *fw_error_rxf; + u32 fw_error_rxf_len; + +@@ -721,7 +719,6 @@ u8 iwl_mvm_mac80211_idx_to_hwrate(int rate_idx); + void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm); + #ifdef CONFIG_IWLWIFI_DEBUGFS + void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm); +-void iwl_mvm_fw_error_sram_dump(struct iwl_mvm *mvm); + void iwl_mvm_fw_error_rxf_dump(struct iwl_mvm *mvm); + #endif + u8 first_antenna(u8 mask); +diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c +index 2910f6d..94506ec 100644 +--- a/drivers/net/wireless/iwlwifi/mvm/ops.c ++++ b/drivers/net/wireless/iwlwifi/mvm/ops.c +@@ -549,7 +549,6 @@ static void iwl_op_mode_mvm_stop(struct iwl_op_mode *op_mode) + + kfree(mvm->scan_cmd); + vfree(mvm->fw_error_dump); +- kfree(mvm->fw_error_sram); + kfree(mvm->fw_error_rxf); + kfree(mvm->mcast_filter_cmd); + mvm->mcast_filter_cmd = NULL; +@@ -827,6 +826,8 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) + struct iwl_fw_error_dump_file *dump_file; + struct iwl_fw_error_dump_data *dump_data; + struct iwl_fw_error_dump_info *dump_info; ++ const struct fw_img *img; ++ u32 sram_len, sram_ofs; + u32 file_len; + u32 trans_len; + +@@ -835,9 +836,13 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) + if (mvm->fw_error_dump) + return; + ++ img = &mvm->fw->img[mvm->cur_ucode]; ++ sram_ofs = img->sec[IWL_UCODE_SECTION_DATA].offset; ++ sram_len = img->sec[IWL_UCODE_SECTION_DATA].len; ++ + file_len = sizeof(*dump_file) + + sizeof(*dump_data) * 3 + +- mvm->fw_error_sram_len + ++ sram_len + + mvm->fw_error_rxf_len + + sizeof(*dump_info); + +@@ -869,6 +874,8 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) + strncpy(dump_info->bus_human_readable, mvm->dev->bus->name, + sizeof(dump_info->bus_human_readable)); + ++ iwl_mvm_fw_error_rxf_dump(mvm); ++ + dump_data = iwl_fw_error_next_data(dump_data); + dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_RXF); + dump_data->len = cpu_to_le32(mvm->fw_error_rxf_len); +@@ -876,23 +883,14 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) + + dump_data = iwl_fw_error_next_data(dump_data); + dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_SRAM); +- dump_data->len = cpu_to_le32(mvm->fw_error_sram_len); +- +- /* +- * No need for lock since at the stage the FW isn't loaded. So it +- * can't assert - we are the only one who can possibly be accessing +- * mvm->fw_error_sram right now. +- */ +- memcpy(dump_data->data, mvm->fw_error_sram, mvm->fw_error_sram_len); ++ dump_data->len = cpu_to_le32(sram_len); ++ iwl_trans_read_mem_bytes(mvm->trans, sram_ofs, dump_data->data, ++ sram_len); + + kfree(mvm->fw_error_rxf); + mvm->fw_error_rxf = NULL; + mvm->fw_error_rxf_len = 0; + +- kfree(mvm->fw_error_sram); +- mvm->fw_error_sram = NULL; +- mvm->fw_error_sram_len = 0; +- + if (trans_len) { + void *buf = iwl_fw_error_next_data(dump_data); + u32 real_trans_len = iwl_trans_dump_data(mvm->trans, buf, +@@ -910,11 +908,6 @@ static void iwl_mvm_nic_error(struct iwl_op_mode *op_mode) + + iwl_mvm_dump_nic_error_log(mvm); + +-#ifdef CONFIG_IWLWIFI_DEBUGFS +- iwl_mvm_fw_error_sram_dump(mvm); +- iwl_mvm_fw_error_rxf_dump(mvm); +-#endif +- + iwl_mvm_nic_restart(mvm); + } + +diff --git a/drivers/net/wireless/iwlwifi/mvm/utils.c b/drivers/net/wireless/iwlwifi/mvm/utils.c +index aa9fc77..15db97c 100644 +--- a/drivers/net/wireless/iwlwifi/mvm/utils.c ++++ b/drivers/net/wireless/iwlwifi/mvm/utils.c +@@ -520,28 +520,6 @@ void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm) + } + + #ifdef CONFIG_IWLWIFI_DEBUGFS +-void iwl_mvm_fw_error_sram_dump(struct iwl_mvm *mvm) +-{ +- const struct fw_img *img; +- u32 ofs, sram_len; +- void *sram; +- +- if (!mvm->ucode_loaded || mvm->fw_error_sram || mvm->fw_error_dump) +- return; +- +- img = &mvm->fw->img[mvm->cur_ucode]; +- ofs = img->sec[IWL_UCODE_SECTION_DATA].offset; +- sram_len = img->sec[IWL_UCODE_SECTION_DATA].len; +- +- sram = kzalloc(sram_len, GFP_ATOMIC); +- if (!sram) +- return; +- +- iwl_trans_read_mem_bytes(mvm->trans, ofs, sram, sram_len); +- mvm->fw_error_sram = sram; +- mvm->fw_error_sram_len = sram_len; +-} +- + void iwl_mvm_fw_error_rxf_dump(struct iwl_mvm *mvm) + { + int i, reg_val; diff --git a/debian/patches/features/all/iwlwifi-debug/iwlwifi-mvm-kill-iwl_mvm_fw_error_rxf_dump.patch b/debian/patches/features/all/iwlwifi-debug/iwlwifi-mvm-kill-iwl_mvm_fw_error_rxf_dump.patch new file mode 100644 index 000000000..407bef833 --- /dev/null +++ b/debian/patches/features/all/iwlwifi-debug/iwlwifi-mvm-kill-iwl_mvm_fw_error_rxf_dump.patch @@ -0,0 +1,315 @@ +From: Emmanuel Grumbach +Date: Tue, 28 Oct 2014 08:11:25 +0200 +Subject: iwlwifi: mvm: kill iwl_mvm_fw_error_rxf_dump +Content-Transfer-Encoding: 8bit +Origin: https://git.kernel.org/linus/655e6d6db21b0c0d411aef9d816816fb68b0496c +Bug-Debian: https://bugs.debian.org/767088 + +Its content can move to the caller. +While at it, move iwl_mvm_fw_error_rxf_dump to caller. + +Signed-off-by: Emmanuel Grumbach +--- + drivers/net/wireless/iwlwifi/mvm/mac80211.c | 100 ++++++++++++++++++++++++++++ + drivers/net/wireless/iwlwifi/mvm/mvm.h | 6 -- + drivers/net/wireless/iwlwifi/mvm/ops.c | 83 ----------------------- + drivers/net/wireless/iwlwifi/mvm/utils.c | 43 ------------ + 4 files changed, 100 insertions(+), 132 deletions(-) + +diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c +index 98556d0..ed10e55 100644 +--- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c ++++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c +@@ -80,6 +80,8 @@ + #include "fw-api-scan.h" + #include "iwl-phy-db.h" + #include "testmode.h" ++#include "iwl-fw-error-dump.h" ++#include "iwl-prph.h" + + static const struct ieee80211_iface_limit iwl_mvm_limits[] = { + { +@@ -637,6 +639,104 @@ static void iwl_mvm_cleanup_iterator(void *data, u8 *mac, + mvmvif->phy_ctxt = NULL; + } + ++#ifdef CONFIG_IWLWIFI_DEBUGFS ++static void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) ++{ ++ struct iwl_fw_error_dump_file *dump_file; ++ struct iwl_fw_error_dump_data *dump_data; ++ struct iwl_fw_error_dump_info *dump_info; ++ const struct fw_img *img; ++ u32 sram_len, sram_ofs; ++ u32 file_len, rxf_len; ++ unsigned long flags; ++ u32 trans_len; ++ int reg_val; ++ ++ lockdep_assert_held(&mvm->mutex); ++ ++ if (mvm->fw_error_dump) ++ return; ++ ++ img = &mvm->fw->img[mvm->cur_ucode]; ++ sram_ofs = img->sec[IWL_UCODE_SECTION_DATA].offset; ++ sram_len = img->sec[IWL_UCODE_SECTION_DATA].len; ++ ++ /* reading buffer size */ ++ reg_val = iwl_trans_read_prph(mvm->trans, RXF_SIZE_ADDR); ++ rxf_len = (reg_val & RXF_SIZE_BYTE_CNT_MSK) >> RXF_SIZE_BYTE_CND_POS; ++ ++ /* the register holds the value divided by 128 */ ++ rxf_len = rxf_len << 7; ++ ++ file_len = sizeof(*dump_file) + ++ sizeof(*dump_data) * 3 + ++ sram_len + ++ rxf_len + ++ sizeof(*dump_info); ++ ++ trans_len = iwl_trans_dump_data(mvm->trans, NULL, 0); ++ if (trans_len) ++ file_len += trans_len; ++ ++ dump_file = vmalloc(file_len); ++ if (!dump_file) ++ return; ++ ++ mvm->fw_error_dump = dump_file; ++ ++ dump_file->barker = cpu_to_le32(IWL_FW_ERROR_DUMP_BARKER); ++ dump_file->file_len = cpu_to_le32(file_len); ++ dump_data = (void *)dump_file->data; ++ ++ dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_DEV_FW_INFO); ++ dump_data->len = cpu_to_le32(sizeof(*dump_info)); ++ dump_info = (void *) dump_data->data; ++ dump_info->device_family = ++ mvm->cfg->device_family == IWL_DEVICE_FAMILY_7000 ? ++ cpu_to_le32(IWL_FW_ERROR_DUMP_FAMILY_7) : ++ cpu_to_le32(IWL_FW_ERROR_DUMP_FAMILY_8); ++ memcpy(dump_info->fw_human_readable, mvm->fw->human_readable, ++ sizeof(dump_info->fw_human_readable)); ++ strncpy(dump_info->dev_human_readable, mvm->cfg->name, ++ sizeof(dump_info->dev_human_readable)); ++ strncpy(dump_info->bus_human_readable, mvm->dev->bus->name, ++ sizeof(dump_info->bus_human_readable)); ++ ++ dump_data = iwl_fw_error_next_data(dump_data); ++ dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_RXF); ++ dump_data->len = cpu_to_le32(rxf_len); ++ ++ if (iwl_trans_grab_nic_access(mvm->trans, false, &flags)) { ++ u32 *rxf = (void *)dump_data->data; ++ int i; ++ ++ for (i = 0; i < (rxf_len / sizeof(u32)); i++) { ++ iwl_trans_write_prph(mvm->trans, ++ RXF_LD_FENCE_OFFSET_ADDR, ++ i * sizeof(u32)); ++ rxf[i] = iwl_trans_read_prph(mvm->trans, ++ RXF_FIFO_RD_FENCE_ADDR); ++ } ++ iwl_trans_release_nic_access(mvm->trans, &flags); ++ } ++ ++ dump_data = iwl_fw_error_next_data(dump_data); ++ dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_SRAM); ++ dump_data->len = cpu_to_le32(sram_len); ++ iwl_trans_read_mem_bytes(mvm->trans, sram_ofs, dump_data->data, ++ sram_len); ++ ++ if (trans_len) { ++ void *buf = iwl_fw_error_next_data(dump_data); ++ u32 real_trans_len = iwl_trans_dump_data(mvm->trans, buf, ++ trans_len); ++ dump_data = (void *)((u8 *)buf + real_trans_len); ++ dump_file->file_len = ++ cpu_to_le32(file_len - trans_len + real_trans_len); ++ } ++} ++#endif ++ + static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm) + { + #ifdef CONFIG_IWLWIFI_DEBUGFS +diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h +index e084fc6..e99b7f1 100644 +--- a/drivers/net/wireless/iwlwifi/mvm/mvm.h ++++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h +@@ -586,8 +586,6 @@ struct iwl_mvm { + /* -1 for always, 0 for never, >0 for that many times */ + s8 restart_fw; + void *fw_error_dump; +- u32 *fw_error_rxf; +- u32 fw_error_rxf_len; + + #ifdef CONFIG_IWLWIFI_LEDS + struct led_classdev led; +@@ -717,10 +715,6 @@ void iwl_mvm_hwrate_to_tx_rate(u32 rate_n_flags, + struct ieee80211_tx_rate *r); + u8 iwl_mvm_mac80211_idx_to_hwrate(int rate_idx); + void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm); +-#ifdef CONFIG_IWLWIFI_DEBUGFS +-void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm); +-void iwl_mvm_fw_error_rxf_dump(struct iwl_mvm *mvm); +-#endif + u8 first_antenna(u8 mask); + u8 iwl_mvm_next_antenna(struct iwl_mvm *mvm, u8 valid, u8 last_idx); + +diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c +index 94506ec..172c1d4 100644 +--- a/drivers/net/wireless/iwlwifi/mvm/ops.c ++++ b/drivers/net/wireless/iwlwifi/mvm/ops.c +@@ -549,7 +549,6 @@ static void iwl_op_mode_mvm_stop(struct iwl_op_mode *op_mode) + + kfree(mvm->scan_cmd); + vfree(mvm->fw_error_dump); +- kfree(mvm->fw_error_rxf); + kfree(mvm->mcast_filter_cmd); + mvm->mcast_filter_cmd = NULL; + +@@ -820,88 +819,6 @@ static void iwl_mvm_nic_restart(struct iwl_mvm *mvm) + } + } + +-#ifdef CONFIG_IWLWIFI_DEBUGFS +-void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) +-{ +- struct iwl_fw_error_dump_file *dump_file; +- struct iwl_fw_error_dump_data *dump_data; +- struct iwl_fw_error_dump_info *dump_info; +- const struct fw_img *img; +- u32 sram_len, sram_ofs; +- u32 file_len; +- u32 trans_len; +- +- lockdep_assert_held(&mvm->mutex); +- +- if (mvm->fw_error_dump) +- return; +- +- img = &mvm->fw->img[mvm->cur_ucode]; +- sram_ofs = img->sec[IWL_UCODE_SECTION_DATA].offset; +- sram_len = img->sec[IWL_UCODE_SECTION_DATA].len; +- +- file_len = sizeof(*dump_file) + +- sizeof(*dump_data) * 3 + +- sram_len + +- mvm->fw_error_rxf_len + +- sizeof(*dump_info); +- +- trans_len = iwl_trans_dump_data(mvm->trans, NULL, 0); +- if (trans_len) +- file_len += trans_len; +- +- dump_file = vmalloc(file_len); +- if (!dump_file) +- return; +- +- mvm->fw_error_dump = dump_file; +- +- dump_file->barker = cpu_to_le32(IWL_FW_ERROR_DUMP_BARKER); +- dump_file->file_len = cpu_to_le32(file_len); +- dump_data = (void *)dump_file->data; +- +- dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_DEV_FW_INFO); +- dump_data->len = cpu_to_le32(sizeof(*dump_info)); +- dump_info = (void *) dump_data->data; +- dump_info->device_family = +- mvm->cfg->device_family == IWL_DEVICE_FAMILY_7000 ? +- cpu_to_le32(IWL_FW_ERROR_DUMP_FAMILY_7) : +- cpu_to_le32(IWL_FW_ERROR_DUMP_FAMILY_8); +- memcpy(dump_info->fw_human_readable, mvm->fw->human_readable, +- sizeof(dump_info->fw_human_readable)); +- strncpy(dump_info->dev_human_readable, mvm->cfg->name, +- sizeof(dump_info->dev_human_readable)); +- strncpy(dump_info->bus_human_readable, mvm->dev->bus->name, +- sizeof(dump_info->bus_human_readable)); +- +- iwl_mvm_fw_error_rxf_dump(mvm); +- +- dump_data = iwl_fw_error_next_data(dump_data); +- dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_RXF); +- dump_data->len = cpu_to_le32(mvm->fw_error_rxf_len); +- memcpy(dump_data->data, mvm->fw_error_rxf, mvm->fw_error_rxf_len); +- +- dump_data = iwl_fw_error_next_data(dump_data); +- dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_SRAM); +- dump_data->len = cpu_to_le32(sram_len); +- iwl_trans_read_mem_bytes(mvm->trans, sram_ofs, dump_data->data, +- sram_len); +- +- kfree(mvm->fw_error_rxf); +- mvm->fw_error_rxf = NULL; +- mvm->fw_error_rxf_len = 0; +- +- if (trans_len) { +- void *buf = iwl_fw_error_next_data(dump_data); +- u32 real_trans_len = iwl_trans_dump_data(mvm->trans, buf, +- trans_len); +- dump_data = (void *)((u8 *)buf + real_trans_len); +- dump_file->file_len = +- cpu_to_le32(file_len - trans_len + real_trans_len); +- } +-} +-#endif +- + static void iwl_mvm_nic_error(struct iwl_op_mode *op_mode) + { + struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); +diff --git a/drivers/net/wireless/iwlwifi/mvm/utils.c b/drivers/net/wireless/iwlwifi/mvm/utils.c +index 15db97c..ac249da 100644 +--- a/drivers/net/wireless/iwlwifi/mvm/utils.c ++++ b/drivers/net/wireless/iwlwifi/mvm/utils.c +@@ -519,49 +519,6 @@ void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm) + iwl_mvm_dump_umac_error_log(mvm); + } + +-#ifdef CONFIG_IWLWIFI_DEBUGFS +-void iwl_mvm_fw_error_rxf_dump(struct iwl_mvm *mvm) +-{ +- int i, reg_val; +- unsigned long flags; +- +- if (!mvm->ucode_loaded || mvm->fw_error_rxf || mvm->fw_error_dump) +- return; +- +- /* reading buffer size */ +- reg_val = iwl_trans_read_prph(mvm->trans, RXF_SIZE_ADDR); +- mvm->fw_error_rxf_len = +- (reg_val & RXF_SIZE_BYTE_CNT_MSK) >> RXF_SIZE_BYTE_CND_POS; +- +- /* the register holds the value divided by 128 */ +- mvm->fw_error_rxf_len = mvm->fw_error_rxf_len << 7; +- +- if (!mvm->fw_error_rxf_len) +- return; +- +- mvm->fw_error_rxf = kzalloc(mvm->fw_error_rxf_len, GFP_ATOMIC); +- if (!mvm->fw_error_rxf) { +- mvm->fw_error_rxf_len = 0; +- return; +- } +- +- if (!iwl_trans_grab_nic_access(mvm->trans, false, &flags)) { +- kfree(mvm->fw_error_rxf); +- mvm->fw_error_rxf = NULL; +- mvm->fw_error_rxf_len = 0; +- return; +- } +- +- for (i = 0; i < (mvm->fw_error_rxf_len / sizeof(u32)); i++) { +- iwl_trans_write_prph(mvm->trans, RXF_LD_FENCE_OFFSET_ADDR, +- i * sizeof(u32)); +- mvm->fw_error_rxf[i] = +- iwl_trans_read_prph(mvm->trans, RXF_FIFO_RD_FENCE_ADDR); +- } +- iwl_trans_release_nic_access(mvm->trans, &flags); +-} +-#endif +- + /** + * iwl_mvm_send_lq_cmd() - Send link quality command + * @init: This command is sent as part of station initialization right diff --git a/debian/patches/features/all/iwlwifi-debug/iwlwifi-mvm-update-layout-of-firmware-error-dump.patch b/debian/patches/features/all/iwlwifi-debug/iwlwifi-mvm-update-layout-of-firmware-error-dump.patch new file mode 100644 index 000000000..9bcd2e1a1 --- /dev/null +++ b/debian/patches/features/all/iwlwifi-debug/iwlwifi-mvm-update-layout-of-firmware-error-dump.patch @@ -0,0 +1,28 @@ +From: Emmanuel Grumbach +Date: Tue, 28 Oct 2014 08:11:26 +0200 +Subject: iwlwifi: mvm: update layout of firmware error dump +Content-Transfer-Encoding: 8bit +Origin: https://git.kernel.org/linus/5bfe6f53283de44855ee45a102210abbfac995f9 +Bug-Debian: https://bugs.debian.org/767088 + +The memory was not zeroed - fix that. Also update the +iwl_fw_error_dump_info structure. + +Signed-off-by: Emmanuel Grumbach +--- + drivers/net/wireless/iwlwifi/mvm/mac80211.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c +index ed10e55..83ab42a 100644 +--- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c ++++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c +@@ -678,7 +678,7 @@ static void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) + if (trans_len) + file_len += trans_len; + +- dump_file = vmalloc(file_len); ++ dump_file = vzalloc(file_len); + if (!dump_file) + return; + diff --git a/debian/patches/features/all/iwlwifi-debug/iwlwifi-pcie-add-firmware-monitor-capabilities.patch b/debian/patches/features/all/iwlwifi-debug/iwlwifi-pcie-add-firmware-monitor-capabilities.patch new file mode 100644 index 000000000..9e1416ea9 --- /dev/null +++ b/debian/patches/features/all/iwlwifi-debug/iwlwifi-pcie-add-firmware-monitor-capabilities.patch @@ -0,0 +1,315 @@ +From: Emmanuel Grumbach +Date: Tue, 28 Oct 2014 08:11:22 +0200 +Subject: iwlwifi: pcie: add firmware monitor capabilities +Content-Transfer-Encoding: 8bit +Origin: https://git.kernel.org/linus/c2d202017da18ebd6567862bd9a50392970f048f +Bug-Debian: https://bugs.debian.org/767088 + +This allows to use the firmware monitor. This capability +uses a lot of contiguous memory (up to 64MB), so make its +usage module parameter dependent. + +The driver will try to allocate as much contiguous memory +as possible downgrading its requirements until the +allocation succeeds. + +Dump this data into the fw-error dump file when an error +happens. + +Signed-off-by: Emmanuel Grumbach +--- + drivers/net/wireless/iwlwifi/iwl-drv.c | 4 + + drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h | 18 ++++ + drivers/net/wireless/iwlwifi/iwl-modparams.h | 2 + + drivers/net/wireless/iwlwifi/iwl-prph.h | 6 ++ + drivers/net/wireless/iwlwifi/pcie/internal.h | 7 ++ + drivers/net/wireless/iwlwifi/pcie/trans.c | 125 ++++++++++++++++++++++- + 6 files changed, 158 insertions(+), 4 deletions(-) + +diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.c b/drivers/net/wireless/iwlwifi/iwl-drv.c +index 2967fce..32e334a 100644 +--- a/drivers/net/wireless/iwlwifi/iwl-drv.c ++++ b/drivers/net/wireless/iwlwifi/iwl-drv.c +@@ -1396,3 +1396,7 @@ module_param_named(power_level, iwlwifi_mod_params.power_level, + int, S_IRUGO); + MODULE_PARM_DESC(power_level, + "default power save level (range from 1 - 5, default: 1)"); ++ ++module_param_named(fw_monitor, iwlwifi_mod_params.fw_monitor, bool, S_IRUGO); ++MODULE_PARM_DESC(fw_monitor, ++ "firmware monitor - to debug FW (default: false - needs lots of memory)"); +diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h b/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h +index 3584a75..ced5ba9 100644 +--- a/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h ++++ b/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h +@@ -76,6 +76,7 @@ + * &struct iwl_fw_error_dump_txcmd packets + * @IWL_FW_ERROR_DUMP_DEV_FW_INFO: struct %iwl_fw_error_dump_info + * info on the device / firmware. ++ * @IWL_FW_ERROR_DUMP_FW_MONITOR: firmware monitor + */ + enum iwl_fw_error_dump_type { + IWL_FW_ERROR_DUMP_SRAM = 0, +@@ -83,6 +84,7 @@ enum iwl_fw_error_dump_type { + IWL_FW_ERROR_DUMP_RXF = 2, + IWL_FW_ERROR_DUMP_TXCMD = 3, + IWL_FW_ERROR_DUMP_DEV_FW_INFO = 4, ++ IWL_FW_ERROR_DUMP_FW_MONITOR = 5, + + IWL_FW_ERROR_DUMP_MAX, + }; +@@ -145,6 +147,22 @@ struct iwl_fw_error_dump_info { + } __packed; + + /** ++ * struct iwl_fw_error_fw_mon - FW monitor data ++ * @fw_mon_wr_ptr: the position of the write pointer in the cyclic buffer ++ * @fw_mon_base_ptr: base pointer of the data ++ * @fw_mon_cycle_cnt: number of wrap arounds ++ * @reserved: for future use ++ * @data: captured data ++ */ ++struct iwl_fw_error_fw_mon { ++ __le32 fw_mon_wr_ptr; ++ __le32 fw_mon_base_ptr; ++ __le32 fw_mon_cycle_cnt; ++ __le32 reserved[3]; ++ u8 data[]; ++} __packed; ++ ++/** + * iwl_fw_error_next_data - advance fw error dump data pointer + * @data: previous data block + * Returns: next data block +diff --git a/drivers/net/wireless/iwlwifi/iwl-modparams.h b/drivers/net/wireless/iwlwifi/iwl-modparams.h +index d051857..f2d39cb 100644 +--- a/drivers/net/wireless/iwlwifi/iwl-modparams.h ++++ b/drivers/net/wireless/iwlwifi/iwl-modparams.h +@@ -103,6 +103,7 @@ enum iwl_disable_11n { + * @power_level: power level, default = 1 + * @debug_level: levels are IWL_DL_* + * @ant_coupling: antenna coupling in dB, default = 0 ++ * @fw_monitor: allow to use firmware monitor + */ + struct iwl_mod_params { + int sw_crypto; +@@ -120,6 +121,7 @@ struct iwl_mod_params { + int ant_coupling; + char *nvm_file; + bool uapsd_disable; ++ bool fw_monitor; + }; + + #endif /* #__iwl_modparams_h__ */ +diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h +index 4997e27..47033a3 100644 +--- a/drivers/net/wireless/iwlwifi/iwl-prph.h ++++ b/drivers/net/wireless/iwlwifi/iwl-prph.h +@@ -359,4 +359,10 @@ enum secure_load_status_reg { + #define RXF_LD_FENCE_OFFSET_ADDR (0xa00c10) + #define RXF_FIFO_RD_FENCE_ADDR (0xa00c0c) + ++/* FW monitor */ ++#define MON_BUFF_BASE_ADDR (0xa03c3c) ++#define MON_BUFF_END_ADDR (0xa03c40) ++#define MON_BUFF_WRPTR (0xa03c44) ++#define MON_BUFF_CYCLE_CNT (0xa03c48) ++ + #endif /* __iwl_prph_h__ */ +diff --git a/drivers/net/wireless/iwlwifi/pcie/internal.h b/drivers/net/wireless/iwlwifi/pcie/internal.h +index 6c22b23..78f72c3 100644 +--- a/drivers/net/wireless/iwlwifi/pcie/internal.h ++++ b/drivers/net/wireless/iwlwifi/pcie/internal.h +@@ -260,6 +260,9 @@ iwl_pcie_get_scratchbuf_dma(struct iwl_txq *txq, int idx) + * @wd_timeout: queue watchdog timeout (jiffies) + * @reg_lock: protect hw register access + * @cmd_in_flight: true when we have a host command in flight ++ * @fw_mon_phys: physical address of the buffer for the firmware monitor ++ * @fw_mon_page: points to the first page of the buffer for the firmware monitor ++ * @fw_mon_size: size of the buffer for the firmware monitor + */ + struct iwl_trans_pcie { + struct iwl_rxq rxq; +@@ -312,6 +315,10 @@ struct iwl_trans_pcie { + /*protect hw register */ + spinlock_t reg_lock; + bool cmd_in_flight; ++ ++ dma_addr_t fw_mon_phys; ++ struct page *fw_mon_page; ++ u32 fw_mon_size; + }; + + #define IWL_TRANS_GET_PCIE_TRANS(_iwl_trans) \ +diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c +index 788085b..3ffac48 100644 +--- a/drivers/net/wireless/iwlwifi/pcie/trans.c ++++ b/drivers/net/wireless/iwlwifi/pcie/trans.c +@@ -76,6 +76,68 @@ + #include "iwl-fw-error-dump.h" + #include "internal.h" + ++static void iwl_pcie_free_fw_monitor(struct iwl_trans *trans) ++{ ++ struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); ++ ++ if (!trans_pcie->fw_mon_page) ++ return; ++ ++ dma_unmap_page(trans->dev, trans_pcie->fw_mon_phys, ++ trans_pcie->fw_mon_size, DMA_FROM_DEVICE); ++ __free_pages(trans_pcie->fw_mon_page, ++ get_order(trans_pcie->fw_mon_size)); ++ trans_pcie->fw_mon_page = NULL; ++ trans_pcie->fw_mon_phys = 0; ++ trans_pcie->fw_mon_size = 0; ++} ++ ++static void iwl_pcie_alloc_fw_monitor(struct iwl_trans *trans) ++{ ++ struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); ++ struct page *page; ++ dma_addr_t phys; ++ u32 size; ++ u8 power; ++ ++ if (trans_pcie->fw_mon_page) { ++ dma_sync_single_for_device(trans->dev, trans_pcie->fw_mon_phys, ++ trans_pcie->fw_mon_size, ++ DMA_FROM_DEVICE); ++ return; ++ } ++ ++ phys = 0; ++ for (power = 26; power >= 11; power--) { ++ int order; ++ ++ size = BIT(power); ++ order = get_order(size); ++ page = alloc_pages(__GFP_COMP | __GFP_NOWARN | __GFP_ZERO, ++ order); ++ if (!page) ++ continue; ++ ++ phys = dma_map_page(trans->dev, page, 0, PAGE_SIZE << order, ++ DMA_FROM_DEVICE); ++ if (dma_mapping_error(trans->dev, phys)) { ++ __free_pages(page, order); ++ continue; ++ } ++ IWL_INFO(trans, ++ "Allocated 0x%08x bytes (order %d) for firmware monitor.\n", ++ size, order); ++ break; ++ } ++ ++ if (!page) ++ return; ++ ++ trans_pcie->fw_mon_page = page; ++ trans_pcie->fw_mon_phys = phys; ++ trans_pcie->fw_mon_size = size; ++} ++ + static u32 iwl_trans_pcie_read_shr(struct iwl_trans *trans, u32 reg) + { + iwl_write32(trans, HEEP_CTRL_WRD_PCIEX_CTRL_REG, +@@ -675,6 +737,7 @@ static int iwl_pcie_load_cpu_sections(struct iwl_trans *trans, + static int iwl_pcie_load_given_ucode(struct iwl_trans *trans, + const struct fw_img *image) + { ++ struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + int ret = 0; + int first_ucode_section; + +@@ -733,6 +796,20 @@ static int iwl_pcie_load_given_ucode(struct iwl_trans *trans, + return ret; + } + ++ /* supported for 7000 only for the moment */ ++ if (iwlwifi_mod_params.fw_monitor && ++ trans->cfg->device_family == IWL_DEVICE_FAMILY_7000) { ++ iwl_pcie_alloc_fw_monitor(trans); ++ ++ if (trans_pcie->fw_mon_size) { ++ iwl_write_prph(trans, MON_BUFF_BASE_ADDR, ++ trans_pcie->fw_mon_phys >> 4); ++ iwl_write_prph(trans, MON_BUFF_END_ADDR, ++ (trans_pcie->fw_mon_phys + ++ trans_pcie->fw_mon_size) >> 4); ++ } ++ } ++ + /* release CPU reset */ + if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) + iwl_write_prph(trans, RELEASE_CPU_RESET, RELEASE_CPU_RESET_BIT); +@@ -1126,6 +1203,8 @@ void iwl_trans_pcie_free(struct iwl_trans *trans) + if (trans_pcie->napi.poll) + netif_napi_del(&trans_pcie->napi); + ++ iwl_pcie_free_fw_monitor(trans); ++ + kfree(trans); + } + +@@ -1698,10 +1777,15 @@ static u32 iwl_trans_pcie_dump_data(struct iwl_trans *trans, + u32 len; + int i, ptr; + ++ len = sizeof(*data) + ++ cmdq->q.n_window * (sizeof(*txcmd) + TFD_MAX_PAYLOAD_SIZE); ++ ++ if (trans_pcie->fw_mon_page) ++ len += sizeof(*data) + sizeof(struct iwl_fw_error_fw_mon) + ++ trans_pcie->fw_mon_size; ++ + if (!buf) +- return sizeof(*data) + +- cmdq->q.n_window * (sizeof(*txcmd) + +- TFD_MAX_PAYLOAD_SIZE); ++ return len; + + len = 0; + data = buf; +@@ -1729,7 +1813,40 @@ static u32 iwl_trans_pcie_dump_data(struct iwl_trans *trans, + spin_unlock_bh(&cmdq->lock); + + data->len = cpu_to_le32(len); +- return sizeof(*data) + len; ++ len += sizeof(*data); ++ ++ if (trans_pcie->fw_mon_page) { ++ struct iwl_fw_error_fw_mon *fw_mon_data; ++ ++ data = iwl_fw_error_next_data(data); ++ data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_FW_MONITOR); ++ data->len = cpu_to_le32(trans_pcie->fw_mon_size + ++ sizeof(*fw_mon_data)); ++ fw_mon_data = (void *)data->data; ++ fw_mon_data->fw_mon_wr_ptr = ++ cpu_to_le32(iwl_read_prph(trans, MON_BUFF_WRPTR)); ++ fw_mon_data->fw_mon_cycle_cnt = ++ cpu_to_le32(iwl_read_prph(trans, MON_BUFF_CYCLE_CNT)); ++ fw_mon_data->fw_mon_base_ptr = ++ cpu_to_le32(iwl_read_prph(trans, MON_BUFF_BASE_ADDR)); ++ ++ /* ++ * The firmware is now asserted, it won't write anything to ++ * the buffer. CPU can take ownership to fetch the data. ++ * The buffer will be handed back to the device before the ++ * firmware will be restarted. ++ */ ++ dma_sync_single_for_cpu(trans->dev, trans_pcie->fw_mon_phys, ++ trans_pcie->fw_mon_size, ++ DMA_FROM_DEVICE); ++ memcpy(fw_mon_data->data, page_address(trans_pcie->fw_mon_page), ++ trans_pcie->fw_mon_size); ++ ++ len += sizeof(*data) + sizeof(*fw_mon_data) + ++ trans_pcie->fw_mon_size; ++ } ++ ++ return len; + } + #else + static int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans, diff --git a/debian/patches/features/all/iwlwifi-debug/iwlwifi-remove-wrong-comment-about-alignment-in-iwl-fw-error-dump.h.patch b/debian/patches/features/all/iwlwifi-debug/iwlwifi-remove-wrong-comment-about-alignment-in-iwl-fw-error-dump.h.patch new file mode 100644 index 000000000..4f3007ce0 --- /dev/null +++ b/debian/patches/features/all/iwlwifi-debug/iwlwifi-remove-wrong-comment-about-alignment-in-iwl-fw-error-dump.h.patch @@ -0,0 +1,30 @@ +From: Emmanuel Grumbach +Date: Tue, 28 Oct 2014 08:11:23 +0200 +Subject: iwlwifi: remove wrong comment about alignment in iwl-fw-error-dump.h +Content-Transfer-Encoding: 8bit +Origin: https://git.kernel.org/linus/d4849277f92a0bfa08a988545ea527fc8e0c9571 +Bug-Debian: https://bugs.debian.org/767088 + +The chunks of data do not need to be multipliers of 4 nor +4-bytes aligned. + +Signed-off-by: Emmanuel Grumbach +--- + drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h b/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h +index ced5ba9..9fd860f 100644 +--- a/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h ++++ b/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h +@@ -92,8 +92,8 @@ enum iwl_fw_error_dump_type { + /** + * struct iwl_fw_error_dump_data - data for one type + * @type: %enum iwl_fw_error_dump_type +- * @len: the length starting from %data - must be a multiplier of 4. +- * @data: the data itself padded to be a multiplier of 4. ++ * @len: the length starting from %data ++ * @data: the data itself + */ + struct iwl_fw_error_dump_data { + __le32 type; diff --git a/debian/patches/features/all/iwlwifi-debug/iwlwifi-rename-iwl_mvm_fw_error_next_data.patch b/debian/patches/features/all/iwlwifi-debug/iwlwifi-rename-iwl_mvm_fw_error_next_data.patch new file mode 100644 index 000000000..3c0ab83bb --- /dev/null +++ b/debian/patches/features/all/iwlwifi-debug/iwlwifi-rename-iwl_mvm_fw_error_next_data.patch @@ -0,0 +1,62 @@ +From: Emmanuel Grumbach +Date: Tue, 28 Oct 2014 08:11:21 +0200 +Subject: iwlwifi: rename iwl_mvm_fw_error_next_data +Content-Transfer-Encoding: 8bit +Origin: https://git.kernel.org/linus/1fa1605648d15d42f350807279b6c6e8d33b6382 +Bug-Debian: https://bugs.debian.org/767088 + +This is not related to mvm. Rename to iwl_fw_error_next_data. + +Signed-off-by: Emmanuel Grumbach +--- + drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h | 4 ++-- + drivers/net/wireless/iwlwifi/mvm/ops.c | 6 +++--- + 2 files changed, 5 insertions(+), 5 deletions(-) + +diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h b/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h +index aa0f85e..3584a75 100644 +--- a/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h ++++ b/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h +@@ -145,12 +145,12 @@ struct iwl_fw_error_dump_info { + } __packed; + + /** +- * iwl_mvm_fw_error_next_data - advance fw error dump data pointer ++ * iwl_fw_error_next_data - advance fw error dump data pointer + * @data: previous data block + * Returns: next data block + */ + static inline struct iwl_fw_error_dump_data * +-iwl_mvm_fw_error_next_data(struct iwl_fw_error_dump_data *data) ++iwl_fw_error_next_data(struct iwl_fw_error_dump_data *data) + { + return (void *)(data->data + le32_to_cpu(data->len)); + } +diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c +index d2fdd9f..2910f6d 100644 +--- a/drivers/net/wireless/iwlwifi/mvm/ops.c ++++ b/drivers/net/wireless/iwlwifi/mvm/ops.c +@@ -869,12 +869,12 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) + strncpy(dump_info->bus_human_readable, mvm->dev->bus->name, + sizeof(dump_info->bus_human_readable)); + +- dump_data = iwl_mvm_fw_error_next_data(dump_data); ++ dump_data = iwl_fw_error_next_data(dump_data); + dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_RXF); + dump_data->len = cpu_to_le32(mvm->fw_error_rxf_len); + memcpy(dump_data->data, mvm->fw_error_rxf, mvm->fw_error_rxf_len); + +- dump_data = iwl_mvm_fw_error_next_data(dump_data); ++ dump_data = iwl_fw_error_next_data(dump_data); + dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_SRAM); + dump_data->len = cpu_to_le32(mvm->fw_error_sram_len); + +@@ -894,7 +894,7 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) + mvm->fw_error_sram_len = 0; + + if (trans_len) { +- void *buf = iwl_mvm_fw_error_next_data(dump_data); ++ void *buf = iwl_fw_error_next_data(dump_data); + u32 real_trans_len = iwl_trans_dump_data(mvm->trans, buf, + trans_len); + dump_data = (void *)((u8 *)buf + real_trans_len); diff --git a/debian/patches/series b/debian/patches/series index 12b4510c0..a54a31e02 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -450,3 +450,10 @@ features/x86/apple-tb/0029-thunderbolt-Correct-the-size-argument-to-devm_kzallo. features/x86/apple-tb/0030-thunderbolt-Use-kcalloc.patch features/x86/apple-tb/0031-thunderbolt-Clear-hops-before-overwriting.patch bugfix/parisc/parisc-reduce-sigrtmin-from-37-to-32-to-behave-like-.patch +features/all/iwlwifi-debug/iwlwifi-add-device-firmware-to-fw-error-dump-file.patch +features/all/iwlwifi-debug/iwlwifi-rename-iwl_mvm_fw_error_next_data.patch +features/all/iwlwifi-debug/iwlwifi-pcie-add-firmware-monitor-capabilities.patch +features/all/iwlwifi-debug/iwlwifi-remove-wrong-comment-about-alignment-in-iwl-fw-error-dump.h.patch +features/all/iwlwifi-debug/iwlwifi-mvm-don-t-collect-logs-in-the-interrupt-thread.patch +features/all/iwlwifi-debug/iwlwifi-mvm-kill-iwl_mvm_fw_error_rxf_dump.patch +features/all/iwlwifi-debug/iwlwifi-mvm-update-layout-of-firmware-error-dump.patch