diff options
Diffstat (limited to 'drivers/net/wireless/ath/ath10k/snoc.c')
-rw-r--r-- | drivers/net/wireless/ath/ath10k/snoc.c | 66 |
1 files changed, 66 insertions, 0 deletions
diff --git a/drivers/net/wireless/ath/ath10k/snoc.c b/drivers/net/wireless/ath/ath10k/snoc.c index c8c92906a178..cd22c8654aa9 100644 --- a/drivers/net/wireless/ath/ath10k/snoc.c +++ b/drivers/net/wireless/ath/ath10k/snoc.c @@ -13,6 +13,7 @@ #include <linux/regulator/consumer.h> #include "ce.h" +#include "coredump.h" #include "debug.h" #include "hif.h" #include "htc.h" @@ -1389,6 +1390,71 @@ static int ath10k_hw_power_off(struct ath10k *ar) return regulator_bulk_disable(ar_snoc->num_vregs, ar_snoc->vregs); } +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((unsigned long)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, |