Browse Source

cnss2: Collect and load elfdump data

Call collect_driver_dump() driver ops to add the data from the buffer
for the four log types.

Change-Id: Ic06d4520de6f87202d1c3ce24362d61002b85f61
CRs-Fixed: 3352310
Alan Chen 2 years ago
parent
commit
ae2498e987
7 changed files with 194 additions and 4 deletions
  1. 4 0
      Kbuild
  2. 1 0
      Makefile
  3. 100 0
      cnss2/main.c
  4. 12 1
      cnss2/main.h
  5. 45 2
      cnss2/pci.c
  6. 9 1
      cnss2/pci.h
  7. 23 0
      inc/cnss2.h

+ 4 - 0
Kbuild

@@ -40,6 +40,10 @@ ifeq ($(CONFIG_AUTO_PROJECT),y)
 KBUILD_CPPFLAGS += -DCONFIG_PULLDOWN_WLANEN
 endif
 
+ifeq ($(CONFIG_CNSS2_SSR_DRIVER_DUMP),y)
+KBUILD_CPPFLAGS += -DCONFIG_CNSS2_SSR_DRIVER_DUMP
+endif
+
 obj-$(CONFIG_CNSS2) += cnss2/
 obj-$(CONFIG_ICNSS2) += icnss2/
 obj-$(CONFIG_CNSS_GENL) += cnss_genl/

+ 1 - 0
Makefile

@@ -22,6 +22,7 @@ KBUILD_OPTIONS += CONFIG_CNSS_PLAT_IPC_QMI_SVC=m
 KBUILD_OPTIONS += CONFIG_CNSS_GENL=m
 KBUILD_OPTIONS += CONFIG_WCNSS_MEM_PRE_ALLOC=m
 KBUILD_OPTIONS += CONFIG_CNSS_UTILS=m
+KBUILD_OPTIONS += CONFIG_CNSS2_SSR_DRIVER_DUMP=y
 endif
 endif
 

+ 100 - 0
cnss2/main.c

@@ -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)

+ 12 - 1
cnss2/main.h

@@ -1,7 +1,7 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved.
- * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #ifndef _CNSS_MAIN_H
@@ -276,6 +276,14 @@ struct cnss_dump_meta_info {
 	struct cnss_dump_entry entry[CNSS_FW_DUMP_TYPE_MAX];
 };
 
+struct cnss_host_dump_meta_info {
+	u32 magic;
+	u32 version;
+	u32 chipset;
+	u32 total_entries;
+	struct cnss_dump_entry entry[CNSS_HOST_DUMP_TYPE_MAX];
+};
+
 enum cnss_driver_event_type {
 	CNSS_DRIVER_EVENT_SERVER_ARRIVE,
 	CNSS_DRIVER_EVENT_SERVER_EXIT,
@@ -630,6 +638,9 @@ int cnss_register_ramdump(struct cnss_plat_data *plat_priv);
 void cnss_unregister_ramdump(struct cnss_plat_data *plat_priv);
 int cnss_do_ramdump(struct cnss_plat_data *plat_priv);
 int cnss_do_elf_ramdump(struct cnss_plat_data *plat_priv);
+int cnss_do_host_ramdump(struct cnss_plat_data *plat_priv,
+			 struct cnss_ssr_driver_dump_entry *ssr_entry,
+			 size_t num_entries_loaded);
 void cnss_set_pin_connect_status(struct cnss_plat_data *plat_priv);
 int cnss_get_cpr_info(struct cnss_plat_data *plat_priv);
 int cnss_update_cpr_info(struct cnss_plat_data *plat_priv);

+ 45 - 2
cnss2/pci.c

@@ -1,7 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
  * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved.
- * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #include <linux/completion.h>
@@ -5188,6 +5188,37 @@ exit:
 		    plat_priv->hang_event_data_len);
 }
 
+#ifdef CONFIG_CNSS2_SSR_DRIVER_DUMP
+void cnss_pci_collect_host_dump_info(struct cnss_pci_data *pci_priv)
+{
+	struct cnss_ssr_driver_dump_entry ssr_entry[CNSS_HOST_DUMP_TYPE_MAX] = {0};
+	struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
+	size_t num_entries_loaded = 0;
+	int x;
+	int ret = -1;
+
+	if (pci_priv->driver_ops &&
+	    pci_priv->driver_ops->collect_driver_dump) {
+		ret = pci_priv->driver_ops->collect_driver_dump(pci_priv->pci_dev,
+								ssr_entry,
+								&num_entries_loaded);
+	}
+
+	if (!ret) {
+		for (x = 0; x < num_entries_loaded; x++) {
+			cnss_pr_info("Idx:%d, ptr: %p, name: %s, size: %d\n",
+				     x, ssr_entry[x].buffer_pointer,
+				     ssr_entry[x].region_name,
+				     ssr_entry[x].buffer_size);
+		}
+
+		cnss_do_host_ramdump(plat_priv, ssr_entry, num_entries_loaded);
+	} else {
+		cnss_pr_info("Host SSR elf dump collection feature disabled\n");
+	}
+}
+#endif
+
 void cnss_pci_collect_dump_info(struct cnss_pci_data *pci_priv, bool in_panic)
 {
 	struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
@@ -5367,9 +5398,21 @@ void cnss_pci_clear_dump_info(struct cnss_pci_data *pci_priv)
 
 void cnss_pci_device_crashed(struct cnss_pci_data *pci_priv)
 {
-	if (!pci_priv)
+	struct cnss_plat_data *plat_priv;
+
+	if (!pci_priv) {
+		cnss_pr_err("pci_priv is NULL\n");
+		return;
+	}
+
+	plat_priv = pci_priv->plat_priv;
+	if (!plat_priv) {
+		cnss_pr_err("plat_priv is NULL\n");
 		return;
+	}
 
+	if (plat_priv->recovery_enabled)
+		cnss_pci_collect_host_dump_info(pci_priv);
 	cnss_device_crashed(&pci_priv->pci_dev->dev);
 }
 

+ 9 - 1
cnss2/pci.h

@@ -1,7 +1,7 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved.
- * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #ifndef _CNSS_PCI_H
@@ -236,6 +236,14 @@ void cnss_pci_free_blob_mem(struct cnss_pci_data *pci_priv);
 int cnss_pci_handle_dev_sol_irq(struct cnss_pci_data *pci_priv);
 int cnss_pci_start_mhi(struct cnss_pci_data *pci_priv);
 void cnss_pci_collect_dump_info(struct cnss_pci_data *pci_priv, bool in_panic);
+#ifdef CONFIG_CNSS2_SSR_DRIVER_DUMP
+void cnss_pci_collect_host_dump_info(struct cnss_pci_data *pci_priv);
+#else
+static inline
+void cnss_pci_collect_host_dump_info(struct cnss_pci_data *pci_priv)
+{
+}
+#endif
 void cnss_pci_device_crashed(struct cnss_pci_data *pci_priv);
 void cnss_pci_clear_dump_info(struct cnss_pci_data *pci_priv);
 u32 cnss_pci_get_wake_msi(struct cnss_pci_data *pci_priv);

+ 23 - 0
inc/cnss2.h

@@ -94,6 +94,29 @@ enum cnss_driver_status {
 	CNSS_BUS_EVENT,
 };
 
+enum cnss_host_dump_type {
+	CNSS_HOST_WLAN_LOGS,
+	CNSS_HOST_HTC_CREDIT,
+	CNSS_HOST_WMI_TX_CMP,
+	CNSS_HOST_WMI_COMMAND_LOG,
+	CNSS_HOST_WMI_EVENT_LOG,
+	CNSS_HOST_WMI_RX_EVENT,
+	CNSS_HOST_HAL_SOC,
+	CNSS_HOST_WMI_HANG_DATA,
+	CNSS_HOST_CE_HANG_EVT,
+	CNSS_HOST_PEER_MAC_ADDR_HANG_DATA,
+	CNSS_HOST_CP_VDEV_INFO,
+	CNSS_HOST_GWLAN_LOGGING,
+	CNSS_HOST_WMI_DEBUG_LOG_INFO,
+	CNSS_HOST_HTC_CREDIT_IDX,
+	CNSS_HOST_HTC_CREDIT_LEN,
+	CNSS_HOST_WMI_TX_CMP_IDX,
+	CNSS_HOST_WMI_COMMAND_LOG_IDX,
+	CNSS_HOST_WMI_EVENT_LOG_IDX,
+	CNSS_HOST_WMI_RX_EVENT_IDX,
+	CNSS_HOST_DUMP_TYPE_MAX,
+};
+
 enum cnss_bus_event_type {
 	BUS_EVENT_PCI_LINK_DOWN = 0,