|
@@ -2923,6 +2923,106 @@ do_elf_dump:
|
|
|
|
|
|
return ret;
|
|
|
}
|
|
|
+
|
|
|
+#ifdef CONFIG_CNSS2_SSR_DRIVER_DUMP
|
|
|
+int cnss_do_host_ramdump(struct cnss_plat_data *plat_priv,
|
|
|
+ struct cnss_ssr_driver_dump_entry *ssr_entry,
|
|
|
+ size_t num_entries_loaded)
|
|
|
+{
|
|
|
+ struct qcom_dump_segment *seg;
|
|
|
+ struct cnss_host_dump_meta_info meta_info = {0};
|
|
|
+ struct list_head head;
|
|
|
+ int dev_ret = 0;
|
|
|
+ struct device *new_device;
|
|
|
+ static const char * const wlan_str[] = {
|
|
|
+ [CNSS_HOST_WLAN_LOGS] = "wlan_logs",
|
|
|
+ [CNSS_HOST_HTC_CREDIT] = "htc_credit",
|
|
|
+ [CNSS_HOST_WMI_TX_CMP] = "wmi_tx_cmp",
|
|
|
+ [CNSS_HOST_WMI_COMMAND_LOG] = "wmi_command_log",
|
|
|
+ [CNSS_HOST_WMI_EVENT_LOG] = "wmi_event_log",
|
|
|
+ [CNSS_HOST_WMI_RX_EVENT] = "wmi_rx_event",
|
|
|
+ [CNSS_HOST_HAL_SOC] = "hal_soc",
|
|
|
+ [CNSS_HOST_WMI_HANG_DATA] = "wmi_hang_data",
|
|
|
+ [CNSS_HOST_CE_HANG_EVT] = "ce_hang_evt",
|
|
|
+ [CNSS_HOST_PEER_MAC_ADDR_HANG_DATA] = "peer_mac_addr_hang_data",
|
|
|
+ [CNSS_HOST_CP_VDEV_INFO] = "cp_vdev_info",
|
|
|
+ [CNSS_HOST_GWLAN_LOGGING] = "gwlan_logging",
|
|
|
+ [CNSS_HOST_WMI_DEBUG_LOG_INFO] = "wmi_debug_log_info",
|
|
|
+ [CNSS_HOST_HTC_CREDIT_IDX] = "htc_credit_history_idx",
|
|
|
+ [CNSS_HOST_HTC_CREDIT_LEN] = "htc_credit_history_length",
|
|
|
+ [CNSS_HOST_WMI_TX_CMP_IDX] = "wmi_tx_cmp_idx",
|
|
|
+ [CNSS_HOST_WMI_COMMAND_LOG_IDX] = "wmi_command_log_idx",
|
|
|
+ [CNSS_HOST_WMI_EVENT_LOG_IDX] = "wmi_event_log_idx",
|
|
|
+ [CNSS_HOST_WMI_RX_EVENT_IDX] = "wmi_rx_event_idx"
|
|
|
+ };
|
|
|
+ int i, j;
|
|
|
+ int ret = 0;
|
|
|
+
|
|
|
+ if (!dump_enabled()) {
|
|
|
+ cnss_pr_info("Dump collection is not enabled\n");
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+
|
|
|
+ new_device = kcalloc(1, sizeof(*new_device), GFP_KERNEL);
|
|
|
+ if (!new_device) {
|
|
|
+ cnss_pr_err("Failed to alloc device mem\n");
|
|
|
+ return -ENOMEM;
|
|
|
+ }
|
|
|
+
|
|
|
+ device_initialize(new_device);
|
|
|
+ dev_set_name(new_device, "wlan_driver");
|
|
|
+ dev_ret = device_add(new_device);
|
|
|
+ if (dev_ret) {
|
|
|
+ cnss_pr_err("Failed to add new device\n");
|
|
|
+ goto put_device;
|
|
|
+ }
|
|
|
+
|
|
|
+ INIT_LIST_HEAD(&head);
|
|
|
+ for (i = 0; i < num_entries_loaded; i++) {
|
|
|
+ seg = kcalloc(1, sizeof(*seg), GFP_KERNEL);
|
|
|
+ if (!seg) {
|
|
|
+ cnss_pr_err("Failed to alloc seg entry %d\n", i);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ seg->va = ssr_entry[i].buffer_pointer;
|
|
|
+ seg->da = (dma_addr_t)ssr_entry[i].buffer_pointer;
|
|
|
+ seg->size = ssr_entry[i].buffer_size;
|
|
|
+
|
|
|
+ for (j = 0; j < ARRAY_SIZE(wlan_str); j++) {
|
|
|
+ if (strncmp(ssr_entry[i].region_name, wlan_str[j],
|
|
|
+ strlen(wlan_str[j])) == 0) {
|
|
|
+ meta_info.entry[i].type = j;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ meta_info.entry[i].entry_start = i + 1;
|
|
|
+ meta_info.entry[i].entry_num++;
|
|
|
+
|
|
|
+ list_add_tail(&seg->node, &head);
|
|
|
+ }
|
|
|
+
|
|
|
+ seg = kcalloc(1, sizeof(*seg), GFP_KERNEL);
|
|
|
+ meta_info.magic = CNSS_RAMDUMP_MAGIC;
|
|
|
+ meta_info.version = CNSS_RAMDUMP_VERSION;
|
|
|
+ meta_info.chipset = plat_priv->device_id;
|
|
|
+ meta_info.total_entries = num_entries_loaded;
|
|
|
+ seg->va = &meta_info;
|
|
|
+ seg->da = (dma_addr_t)&meta_info;
|
|
|
+ seg->size = sizeof(meta_info);
|
|
|
+ list_add(&seg->node, &head);
|
|
|
+ ret = qcom_elf_dump(&head, new_device, ELF_CLASS);
|
|
|
+ while (!list_empty(&head)) {
|
|
|
+ seg = list_first_entry(&head, struct qcom_dump_segment, node);
|
|
|
+ list_del(&seg->node);
|
|
|
+ kfree(seg);
|
|
|
+ }
|
|
|
+ device_del(new_device);
|
|
|
+put_device:
|
|
|
+ put_device(new_device);
|
|
|
+ kfree(new_device);
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+#endif
|
|
|
#endif /* CONFIG_MSM_SUBSYSTEM_RESTART */
|
|
|
|
|
|
#if IS_ENABLED(CONFIG_QCOM_MEMORY_DUMP_V2)
|