MSA memory region caries the hw descriptors information.
Dump MSA region in core dump as this is very helpful in debugging
hw issues.

Testing: Tested on WCN3990 HW
Tested FW: WLAN.HL.3.1-00959-QCAHLSWMTPLZ-1

Signed-off-by: Govind Singh <govi...@codeaurora.org>

---
Changes from v2:
- Rebased on top of 38faed150438 ath10k: perform crash dump collection in 
workqueue.
- Removed redundant msa permission call.
---
 drivers/net/wireless/ath/ath10k/coredump.c | 21 +++++++
 drivers/net/wireless/ath/ath10k/coredump.h |  1 +
 drivers/net/wireless/ath/ath10k/qmi.c      |  4 ++
 drivers/net/wireless/ath/ath10k/snoc.c     | 66 ++++++++++++++++++++++
 drivers/net/wireless/ath/ath10k/snoc.h     |  1 +
 5 files changed, 93 insertions(+)

diff --git a/drivers/net/wireless/ath/ath10k/coredump.c 
b/drivers/net/wireless/ath/ath10k/coredump.c
index aa04fbf146e0..0ec690b49fb1 100644
--- a/drivers/net/wireless/ath/ath10k/coredump.c
+++ b/drivers/net/wireless/ath/ath10k/coredump.c
@@ -962,6 +962,19 @@ static const struct ath10k_mem_region 
qca4019_hw10_mem_regions[] = {
        },
 };
 
+static const struct ath10k_mem_region wcn399x_hw10_mem_regions[] = {
+       {
+               /* MSA region start is not fixed, hence it is assigned at 
runtime */
+               .type = ATH10K_MEM_REGION_TYPE_MSA,
+               .len = 0x100000,
+               .name = "DRAM",
+               .section_table = {
+                       .sections = NULL,
+                       .size = 0,
+               },
+       },
+};
+
 static const struct ath10k_hw_mem_layout hw_mem_layouts[] = {
        {
                .hw_id = QCA6174_HW_1_0_VERSION,
@@ -1059,6 +1072,14 @@ static const struct ath10k_hw_mem_layout 
hw_mem_layouts[] = {
                        .size = ARRAY_SIZE(qca4019_hw10_mem_regions),
                },
        },
+       {
+               .hw_id = WCN3990_HW_1_0_DEV_VERSION,
+               .hw_rev = ATH10K_HW_WCN3990,
+               .region_table = {
+                       .regions = wcn399x_hw10_mem_regions,
+                       .size = ARRAY_SIZE(wcn399x_hw10_mem_regions),
+               },
+       },
 };
 
 static u32 ath10k_coredump_get_ramdump_size(struct ath10k *ar)
diff --git a/drivers/net/wireless/ath/ath10k/coredump.h 
b/drivers/net/wireless/ath/ath10k/coredump.h
index 5dac653e1649..9802e90483f4 100644
--- a/drivers/net/wireless/ath/ath10k/coredump.h
+++ b/drivers/net/wireless/ath/ath10k/coredump.h
@@ -126,6 +126,7 @@ enum ath10k_mem_region_type {
        ATH10K_MEM_REGION_TYPE_IRAM2    = 5,
        ATH10K_MEM_REGION_TYPE_IOSRAM   = 6,
        ATH10K_MEM_REGION_TYPE_IOREG    = 7,
+       ATH10K_MEM_REGION_TYPE_MSA      = 8,
 };
 
 /* Define a section of the region which should be copied. As not all parts
diff --git a/drivers/net/wireless/ath/ath10k/qmi.c 
b/drivers/net/wireless/ath/ath10k/qmi.c
index ba8f5a8f83d1..8eb0f0f0d3a7 100644
--- a/drivers/net/wireless/ath/ath10k/qmi.c
+++ b/drivers/net/wireless/ath/ath10k/qmi.c
@@ -817,9 +817,13 @@ ath10k_qmi_driver_event_post(struct ath10k_qmi *qmi,
 static void ath10k_qmi_event_server_exit(struct ath10k_qmi *qmi)
 {
        struct ath10k *ar = qmi->ar;
+       struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
 
        ath10k_qmi_remove_msa_permission(qmi);
        ath10k_core_free_board_files(ar);
+       if (!test_bit(ATH10K_SNOC_FLAG_UNREGISTERING, &ar_snoc->flags))
+               ath10k_snoc_fw_crashed_dump(ar);
+
        ath10k_snoc_fw_indication(ar, ATH10K_QMI_EVENT_FW_DOWN_IND);
        ath10k_dbg(ar, ATH10K_DBG_QMI, "wifi fw qmi service disconnected\n");
 }
diff --git a/drivers/net/wireless/ath/ath10k/snoc.c 
b/drivers/net/wireless/ath/ath10k/snoc.c
index 0be12996beba..ecc0f884b123 100644
--- a/drivers/net/wireless/ath/ath10k/snoc.c
+++ b/drivers/net/wireless/ath/ath10k/snoc.c
@@ -24,6 +24,7 @@
 #include <linux/regulator/consumer.h>
 
 #include "ce.h"
+#include "coredump.h"
 #include "debug.h"
 #include "hif.h"
 #include "htc.h"
@@ -1586,6 +1587,71 @@ static int ath10k_hw_power_off(struct ath10k *ar)
        return ret;
 }
 
+static void ath10k_msa_dump_memory(struct ath10k *ar,
+                                  struct ath10k_fw_crash_data *crash_data)
+{
+       struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
+       const struct ath10k_hw_mem_layout *mem_layout;
+       const struct ath10k_mem_region *current_region;
+       struct ath10k_dump_ram_data_hdr *hdr;
+       size_t buf_len;
+       u8 *buf;
+
+       if (!crash_data && !crash_data->ramdump_buf)
+               return;
+
+       mem_layout = ath10k_coredump_get_mem_layout(ar);
+       if (!mem_layout)
+               return;
+
+       current_region = &mem_layout->region_table.regions[0];
+
+       buf = crash_data->ramdump_buf;
+       buf_len = crash_data->ramdump_buf_len;
+       memset(buf, 0, buf_len);
+
+       /* Reserve space for the header. */
+       hdr = (void *)buf;
+       buf += sizeof(*hdr);
+       buf_len -= sizeof(*hdr);
+
+       hdr->region_type = cpu_to_le32(current_region->type);
+       hdr->start = cpu_to_le32(ar_snoc->qmi->msa_va);
+       hdr->length = cpu_to_le32(ar_snoc->qmi->msa_mem_size);
+
+       if (current_region->len < ar_snoc->qmi->msa_mem_size) {
+               memcpy(buf, ar_snoc->qmi->msa_va, current_region->len);
+               ath10k_warn(ar, "msa dump length is less than msa size %x, 
%x\n",
+                           current_region->len, ar_snoc->qmi->msa_mem_size);
+       } else {
+               memcpy(buf, ar_snoc->qmi->msa_va, ar_snoc->qmi->msa_mem_size);
+       }
+}
+
+void ath10k_snoc_fw_crashed_dump(struct ath10k *ar)
+{
+       struct ath10k_fw_crash_data *crash_data;
+       char guid[UUID_STRING_LEN + 1];
+
+       mutex_lock(&ar->dump_mutex);
+
+       spin_lock_bh(&ar->data_lock);
+       ar->stats.fw_crash_counter++;
+       spin_unlock_bh(&ar->data_lock);
+
+       crash_data = ath10k_coredump_new(ar);
+
+       if (crash_data)
+               scnprintf(guid, sizeof(guid), "%pUl", &crash_data->guid);
+       else
+               scnprintf(guid, sizeof(guid), "n/a");
+
+       ath10k_err(ar, "firmware crashed! (guid %s)\n", guid);
+       ath10k_print_driver_info(ar);
+       ath10k_msa_dump_memory(ar, crash_data);
+       mutex_unlock(&ar->dump_mutex);
+}
+
 static const struct of_device_id ath10k_snoc_dt_match[] = {
        { .compatible = "qcom,wcn3990-wifi",
         .data = &drv_priv,
diff --git a/drivers/net/wireless/ath/ath10k/snoc.h 
b/drivers/net/wireless/ath/ath10k/snoc.h
index 25383de8f17d..6d28a6290a94 100644
--- a/drivers/net/wireless/ath/ath10k/snoc.h
+++ b/drivers/net/wireless/ath/ath10k/snoc.h
@@ -101,5 +101,6 @@ static inline struct ath10k_snoc *ath10k_snoc_priv(struct 
ath10k *ar)
 }
 
 int ath10k_snoc_fw_indication(struct ath10k *ar, u64 type);
+void ath10k_snoc_fw_crashed_dump(struct ath10k *ar);
 
 #endif /* _SNOC_H_ */
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project


_______________________________________________
ath10k mailing list
ath10k@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/ath10k

Reply via email to