1 // SPDX-License-Identifier: ISC
3 * Copyright (c) 2011-2017 Qualcomm Atheros, Inc.
4 * Copyright (c) 2018, The Linux Foundation. All rights reserved.
9 #include <linux/devcoredump.h>
10 #include <linux/kernel.h>
11 #include <linux/types.h>
12 #include <linux/utsname.h>
17 static const struct ath10k_mem_section qca6174_hw21_register_sections[] = {
273 static const struct ath10k_mem_section qca6174_hw30_register_sections[] = {
529 static const struct ath10k_mem_region qca6174_hw10_mem_regions[] = {
531 .type = ATH10K_MEM_REGION_TYPE_DRAM,
541 .type = ATH10K_MEM_REGION_TYPE_REG,
543 /* RTC_SOC_BASE_ADDRESS */
546 /* WLAN_MBOX_BASE_ADDRESS - RTC_SOC_BASE_ADDRESS */
556 .type = ATH10K_MEM_REGION_TYPE_REG,
558 /* STEREO_BASE_ADDRESS */
561 /* USB_BASE_ADDRESS - STEREO_BASE_ADDRESS */
562 .len = 0x60000 - 0x27000,
572 static const struct ath10k_mem_region qca6174_hw21_mem_regions[] = {
574 .type = ATH10K_MEM_REGION_TYPE_DRAM,
584 .type = ATH10K_MEM_REGION_TYPE_AXI,
594 .type = ATH10K_MEM_REGION_TYPE_REG,
596 .len = 0x80020 - 0x800,
599 .sections = qca6174_hw21_register_sections,
600 .size = ARRAY_SIZE(qca6174_hw21_register_sections),
605 static const struct ath10k_mem_region qca6174_hw30_mem_regions[] = {
607 .type = ATH10K_MEM_REGION_TYPE_DRAM,
617 .type = ATH10K_MEM_REGION_TYPE_AXI,
627 .type = ATH10K_MEM_REGION_TYPE_REG,
629 .len = 0x80020 - 0x800,
632 .sections = qca6174_hw30_register_sections,
633 .size = ARRAY_SIZE(qca6174_hw30_register_sections),
637 /* IRAM dump must be put last */
639 .type = ATH10K_MEM_REGION_TYPE_IRAM1,
649 .type = ATH10K_MEM_REGION_TYPE_IRAM2,
660 static const struct ath10k_mem_region qca988x_hw20_mem_regions[] = {
662 .type = ATH10K_MEM_REGION_TYPE_DRAM,
672 .type = ATH10K_MEM_REGION_TYPE_REG,
682 .type = ATH10K_MEM_REGION_TYPE_REG,
693 static const struct ath10k_mem_region qca99x0_hw20_mem_regions[] = {
695 .type = ATH10K_MEM_REGION_TYPE_DRAM,
705 .type = ATH10K_MEM_REGION_TYPE_REG,
715 .type = ATH10K_MEM_REGION_TYPE_IOSRAM,
725 .type = ATH10K_MEM_REGION_TYPE_IOREG,
735 .type = ATH10K_MEM_REGION_TYPE_IOREG,
745 .type = ATH10K_MEM_REGION_TYPE_IOREG,
755 .type = ATH10K_MEM_REGION_TYPE_IOREG,
765 .type = ATH10K_MEM_REGION_TYPE_IOREG,
776 static const struct ath10k_mem_region qca9984_hw10_mem_regions[] = {
778 .type = ATH10K_MEM_REGION_TYPE_DRAM,
788 .type = ATH10K_MEM_REGION_TYPE_REG,
798 .type = ATH10K_MEM_REGION_TYPE_IOSRAM,
808 .type = ATH10K_MEM_REGION_TYPE_IOREG,
818 .type = ATH10K_MEM_REGION_TYPE_IOREG,
828 .type = ATH10K_MEM_REGION_TYPE_IOREG,
838 .type = ATH10K_MEM_REGION_TYPE_IOREG,
848 .type = ATH10K_MEM_REGION_TYPE_IOREG,
859 static const struct ath10k_mem_section ipq4019_soc_reg_range[] = {
860 {0x080000, 0x080004},
861 {0x080020, 0x080024},
862 {0x080028, 0x080050},
863 {0x0800d4, 0x0800ec},
864 {0x08010c, 0x080118},
865 {0x080284, 0x080290},
866 {0x0802a8, 0x0802b8},
867 {0x0802dc, 0x08030c},
871 static const struct ath10k_mem_region qca4019_hw10_mem_regions[] = {
873 .type = ATH10K_MEM_REGION_TYPE_DRAM,
883 .type = ATH10K_MEM_REGION_TYPE_REG,
893 .type = ATH10K_MEM_REGION_TYPE_REG,
903 .type = ATH10K_MEM_REGION_TYPE_IOREG,
913 .type = ATH10K_MEM_REGION_TYPE_IOREG,
923 .type = ATH10K_MEM_REGION_TYPE_IOREG,
933 .type = ATH10K_MEM_REGION_TYPE_IOREG,
943 .type = ATH10K_MEM_REGION_TYPE_REG,
945 .len = 0x083fff - 0x080000,
948 .sections = ipq4019_soc_reg_range,
949 .size = ARRAY_SIZE(ipq4019_soc_reg_range),
954 static const struct ath10k_hw_mem_layout hw_mem_layouts[] = {
956 .hw_id = QCA6174_HW_1_0_VERSION,
957 .hw_rev = ATH10K_HW_QCA6174,
959 .regions = qca6174_hw10_mem_regions,
960 .size = ARRAY_SIZE(qca6174_hw10_mem_regions),
964 .hw_id = QCA6174_HW_1_1_VERSION,
965 .hw_rev = ATH10K_HW_QCA6174,
967 .regions = qca6174_hw10_mem_regions,
968 .size = ARRAY_SIZE(qca6174_hw10_mem_regions),
972 .hw_id = QCA6174_HW_1_3_VERSION,
973 .hw_rev = ATH10K_HW_QCA6174,
975 .regions = qca6174_hw10_mem_regions,
976 .size = ARRAY_SIZE(qca6174_hw10_mem_regions),
980 .hw_id = QCA6174_HW_2_1_VERSION,
981 .hw_rev = ATH10K_HW_QCA6174,
983 .regions = qca6174_hw21_mem_regions,
984 .size = ARRAY_SIZE(qca6174_hw21_mem_regions),
988 .hw_id = QCA6174_HW_3_0_VERSION,
989 .hw_rev = ATH10K_HW_QCA6174,
991 .regions = qca6174_hw30_mem_regions,
992 .size = ARRAY_SIZE(qca6174_hw30_mem_regions),
996 .hw_id = QCA6174_HW_3_2_VERSION,
997 .hw_rev = ATH10K_HW_QCA6174,
999 .regions = qca6174_hw30_mem_regions,
1000 .size = ARRAY_SIZE(qca6174_hw30_mem_regions),
1004 .hw_id = QCA9377_HW_1_1_DEV_VERSION,
1005 .hw_rev = ATH10K_HW_QCA9377,
1007 .regions = qca6174_hw30_mem_regions,
1008 .size = ARRAY_SIZE(qca6174_hw30_mem_regions),
1012 .hw_id = QCA988X_HW_2_0_VERSION,
1013 .hw_rev = ATH10K_HW_QCA988X,
1015 .regions = qca988x_hw20_mem_regions,
1016 .size = ARRAY_SIZE(qca988x_hw20_mem_regions),
1020 .hw_id = QCA9984_HW_1_0_DEV_VERSION,
1021 .hw_rev = ATH10K_HW_QCA9984,
1023 .regions = qca9984_hw10_mem_regions,
1024 .size = ARRAY_SIZE(qca9984_hw10_mem_regions),
1028 .hw_id = QCA9888_HW_2_0_DEV_VERSION,
1029 .hw_rev = ATH10K_HW_QCA9888,
1031 .regions = qca9984_hw10_mem_regions,
1032 .size = ARRAY_SIZE(qca9984_hw10_mem_regions),
1036 .hw_id = QCA99X0_HW_2_0_DEV_VERSION,
1037 .hw_rev = ATH10K_HW_QCA99X0,
1039 .regions = qca99x0_hw20_mem_regions,
1040 .size = ARRAY_SIZE(qca99x0_hw20_mem_regions),
1044 .hw_id = QCA4019_HW_1_0_DEV_VERSION,
1045 .hw_rev = ATH10K_HW_QCA4019,
1047 .regions = qca4019_hw10_mem_regions,
1048 .size = ARRAY_SIZE(qca4019_hw10_mem_regions),
1053 static u32 ath10k_coredump_get_ramdump_size(struct ath10k *ar)
1055 const struct ath10k_hw_mem_layout *hw;
1056 const struct ath10k_mem_region *mem_region;
1060 hw = ath10k_coredump_get_mem_layout(ar);
1065 mem_region = &hw->region_table.regions[0];
1067 for (i = 0; i < hw->region_table.size; i++) {
1068 size += mem_region->len;
1072 /* reserve space for the headers */
1073 size += hw->region_table.size * sizeof(struct ath10k_dump_ram_data_hdr);
1075 /* make sure it is aligned 16 bytes for debug message print out */
1076 size = ALIGN(size, 16);
1081 const struct ath10k_hw_mem_layout *ath10k_coredump_get_mem_layout(struct ath10k *ar)
1085 if (!test_bit(ATH10K_FW_CRASH_DUMP_RAM_DATA, &ath10k_coredump_mask))
1088 if (WARN_ON(ar->target_version == 0))
1091 for (i = 0; i < ARRAY_SIZE(hw_mem_layouts); i++) {
1092 if (ar->target_version == hw_mem_layouts[i].hw_id &&
1093 ar->hw_rev == hw_mem_layouts[i].hw_rev)
1094 return &hw_mem_layouts[i];
1099 EXPORT_SYMBOL(ath10k_coredump_get_mem_layout);
1101 struct ath10k_fw_crash_data *ath10k_coredump_new(struct ath10k *ar)
1103 struct ath10k_fw_crash_data *crash_data = ar->coredump.fw_crash_data;
1105 lockdep_assert_held(&ar->data_lock);
1107 if (ath10k_coredump_mask == 0)
1108 /* coredump disabled */
1111 guid_gen(&crash_data->guid);
1112 ktime_get_real_ts64(&crash_data->timestamp);
1116 EXPORT_SYMBOL(ath10k_coredump_new);
1118 static struct ath10k_dump_file_data *ath10k_coredump_build(struct ath10k *ar)
1120 struct ath10k_fw_crash_data *crash_data = ar->coredump.fw_crash_data;
1121 struct ath10k_ce_crash_hdr *ce_hdr;
1122 struct ath10k_dump_file_data *dump_data;
1123 struct ath10k_tlv_dump_data *dump_tlv;
1124 size_t hdr_len = sizeof(*dump_data);
1125 size_t len, sofar = 0;
1130 if (test_bit(ATH10K_FW_CRASH_DUMP_REGISTERS, &ath10k_coredump_mask))
1131 len += sizeof(*dump_tlv) + sizeof(crash_data->registers);
1133 if (test_bit(ATH10K_FW_CRASH_DUMP_CE_DATA, &ath10k_coredump_mask))
1134 len += sizeof(*dump_tlv) + sizeof(*ce_hdr) +
1135 CE_COUNT * sizeof(ce_hdr->entries[0]);
1137 if (test_bit(ATH10K_FW_CRASH_DUMP_RAM_DATA, &ath10k_coredump_mask))
1138 len += sizeof(*dump_tlv) + crash_data->ramdump_buf_len;
1142 /* This is going to get big when we start dumping FW RAM and such,
1143 * so go ahead and use vmalloc.
1149 spin_lock_bh(&ar->data_lock);
1151 dump_data = (struct ath10k_dump_file_data *)(buf);
1152 strlcpy(dump_data->df_magic, "ATH10K-FW-DUMP",
1153 sizeof(dump_data->df_magic));
1154 dump_data->len = cpu_to_le32(len);
1156 dump_data->version = cpu_to_le32(ATH10K_FW_CRASH_DUMP_VERSION);
1158 guid_copy(&dump_data->guid, &crash_data->guid);
1159 dump_data->chip_id = cpu_to_le32(ar->bus_param.chip_id);
1160 dump_data->bus_type = cpu_to_le32(0);
1161 dump_data->target_version = cpu_to_le32(ar->target_version);
1162 dump_data->fw_version_major = cpu_to_le32(ar->fw_version_major);
1163 dump_data->fw_version_minor = cpu_to_le32(ar->fw_version_minor);
1164 dump_data->fw_version_release = cpu_to_le32(ar->fw_version_release);
1165 dump_data->fw_version_build = cpu_to_le32(ar->fw_version_build);
1166 dump_data->phy_capability = cpu_to_le32(ar->phy_capability);
1167 dump_data->hw_min_tx_power = cpu_to_le32(ar->hw_min_tx_power);
1168 dump_data->hw_max_tx_power = cpu_to_le32(ar->hw_max_tx_power);
1169 dump_data->ht_cap_info = cpu_to_le32(ar->ht_cap_info);
1170 dump_data->vht_cap_info = cpu_to_le32(ar->vht_cap_info);
1171 dump_data->num_rf_chains = cpu_to_le32(ar->num_rf_chains);
1173 strlcpy(dump_data->fw_ver, ar->hw->wiphy->fw_version,
1174 sizeof(dump_data->fw_ver));
1176 dump_data->kernel_ver_code = 0;
1177 strlcpy(dump_data->kernel_ver, init_utsname()->release,
1178 sizeof(dump_data->kernel_ver));
1180 dump_data->tv_sec = cpu_to_le64(crash_data->timestamp.tv_sec);
1181 dump_data->tv_nsec = cpu_to_le64(crash_data->timestamp.tv_nsec);
1183 if (test_bit(ATH10K_FW_CRASH_DUMP_REGISTERS, &ath10k_coredump_mask)) {
1184 dump_tlv = (struct ath10k_tlv_dump_data *)(buf + sofar);
1185 dump_tlv->type = cpu_to_le32(ATH10K_FW_CRASH_DUMP_REGISTERS);
1186 dump_tlv->tlv_len = cpu_to_le32(sizeof(crash_data->registers));
1187 memcpy(dump_tlv->tlv_data, &crash_data->registers,
1188 sizeof(crash_data->registers));
1189 sofar += sizeof(*dump_tlv) + sizeof(crash_data->registers);
1192 if (test_bit(ATH10K_FW_CRASH_DUMP_CE_DATA, &ath10k_coredump_mask)) {
1193 dump_tlv = (struct ath10k_tlv_dump_data *)(buf + sofar);
1194 dump_tlv->type = cpu_to_le32(ATH10K_FW_CRASH_DUMP_CE_DATA);
1195 dump_tlv->tlv_len = cpu_to_le32(sizeof(*ce_hdr) +
1196 CE_COUNT * sizeof(ce_hdr->entries[0]));
1197 ce_hdr = (struct ath10k_ce_crash_hdr *)(dump_tlv->tlv_data);
1198 ce_hdr->ce_count = cpu_to_le32(CE_COUNT);
1199 memset(ce_hdr->reserved, 0, sizeof(ce_hdr->reserved));
1200 memcpy(ce_hdr->entries, crash_data->ce_crash_data,
1201 CE_COUNT * sizeof(ce_hdr->entries[0]));
1202 sofar += sizeof(*dump_tlv) + sizeof(*ce_hdr) +
1203 CE_COUNT * sizeof(ce_hdr->entries[0]);
1206 /* Gather ram dump */
1207 if (test_bit(ATH10K_FW_CRASH_DUMP_RAM_DATA, &ath10k_coredump_mask)) {
1208 dump_tlv = (struct ath10k_tlv_dump_data *)(buf + sofar);
1209 dump_tlv->type = cpu_to_le32(ATH10K_FW_CRASH_DUMP_RAM_DATA);
1210 dump_tlv->tlv_len = cpu_to_le32(crash_data->ramdump_buf_len);
1211 memcpy(dump_tlv->tlv_data, crash_data->ramdump_buf,
1212 crash_data->ramdump_buf_len);
1213 sofar += sizeof(*dump_tlv) + crash_data->ramdump_buf_len;
1216 spin_unlock_bh(&ar->data_lock);
1221 int ath10k_coredump_submit(struct ath10k *ar)
1223 struct ath10k_dump_file_data *dump;
1225 if (ath10k_coredump_mask == 0)
1226 /* coredump disabled */
1229 dump = ath10k_coredump_build(ar);
1231 ath10k_warn(ar, "no crash dump data found for devcoredump");
1235 dev_coredumpv(ar->dev, dump, le32_to_cpu(dump->len), GFP_KERNEL);
1240 int ath10k_coredump_create(struct ath10k *ar)
1242 if (ath10k_coredump_mask == 0)
1243 /* coredump disabled */
1246 ar->coredump.fw_crash_data = vzalloc(sizeof(*ar->coredump.fw_crash_data));
1247 if (!ar->coredump.fw_crash_data)
1253 int ath10k_coredump_register(struct ath10k *ar)
1255 struct ath10k_fw_crash_data *crash_data = ar->coredump.fw_crash_data;
1257 if (test_bit(ATH10K_FW_CRASH_DUMP_RAM_DATA, &ath10k_coredump_mask)) {
1258 crash_data->ramdump_buf_len = ath10k_coredump_get_ramdump_size(ar);
1260 crash_data->ramdump_buf = vzalloc(crash_data->ramdump_buf_len);
1261 if (!crash_data->ramdump_buf)
1268 void ath10k_coredump_unregister(struct ath10k *ar)
1270 struct ath10k_fw_crash_data *crash_data = ar->coredump.fw_crash_data;
1272 vfree(crash_data->ramdump_buf);
1275 void ath10k_coredump_destroy(struct ath10k *ar)
1277 if (ar->coredump.fw_crash_data->ramdump_buf) {
1278 vfree(ar->coredump.fw_crash_data->ramdump_buf);
1279 ar->coredump.fw_crash_data->ramdump_buf = NULL;
1280 ar->coredump.fw_crash_data->ramdump_buf_len = 0;
1283 vfree(ar->coredump.fw_crash_data);
1284 ar->coredump.fw_crash_data = NULL;