qcacmn: Add support to log ce hang event info

Add hif APIs to support logging of ce hang event
data.

Change-Id: I9b930d5f983d57a7359ba9f97ea65050c4f54a8a
CRs-Fixed: 2649148
diff --git a/hif/inc/hif.h b/hif/inc/hif.h
index 7442874..4671ce7 100644
--- a/hif/inc/hif.h
+++ b/hif/inc/hif.h
@@ -1367,4 +1367,23 @@
 {
 }
 #endif
+
+#ifdef HIF_CE_LOG_INFO
+/**
+ * hif_log_ce_info() - API to log ce info
+ * @hif_ctx: hif opaque handle
+ * @data: hang event data buffer
+ * @offset: offset at which data needs to be written
+ *
+ * Return:  None
+ */
+void hif_log_ce_info(struct hif_opaque_softc *hif_ctx, uint8_t *data,
+		     unsigned int *offset);
+#else
+static inline
+void hif_log_ce_info(struct hif_opaque_softc *hif_ctx, uint8_t *data,
+		     unsigned int *offset)
+{
+}
+#endif
 #endif /* _HIF_H_ */
diff --git a/hif/src/ce/ce_api.h b/hif/src/ce/ce_api.h
index 5ff48e0..7b6b97b 100644
--- a/hif/src/ce/ce_api.h
+++ b/hif/src/ce/ce_api.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2020 The Linux Foundation. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for
  * any purpose with or without fee is hereby granted, provided that the
@@ -546,6 +546,8 @@
 	void (*ce_prepare_shadow_register_v2_cfg)(struct hif_softc *scn,
 			    struct pld_shadow_reg_v2_cfg **shadow_config,
 			    int *num_shadow_registers_configured);
+	int (*ce_get_index_info)(struct hif_softc *scn, void *ce_state,
+				 struct ce_index *info);
 };
 
 int hif_ce_bus_early_suspend(struct hif_softc *scn);
diff --git a/hif/src/ce/ce_main.c b/hif/src/ce/ce_main.c
index 2c95be3..2f43da4 100644
--- a/hif/src/ce/ce_main.c
+++ b/hif/src/ce/ce_main.c
@@ -49,6 +49,9 @@
 #define PCIE_ACCESS_DUMP 4
 #endif
 #include "mp_dev.h"
+#ifdef HIF_CE_LOG_INFO
+#include "qdf_hang_event_notifier.h"
+#endif
 
 #if (defined(QCA_WIFI_QCA8074) || defined(QCA_WIFI_QCA6290) || \
 	defined(QCA_WIFI_QCA6018)) && !defined(QCA_WIFI_SUPPORT_SRNG)
@@ -4158,3 +4161,59 @@
 
 	return 0;
 }
+
+#ifdef HIF_CE_LOG_INFO
+/**
+ * ce_get_index_info(): Get CE index info
+ * @scn: HIF Context
+ * @ce_state: CE opaque handle
+ * @info: CE info
+ *
+ * Return: 0 for success and non zero for failure
+ */
+static
+int ce_get_index_info(struct hif_softc *scn, void *ce_state,
+		      struct ce_index *info)
+{
+	struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(scn);
+
+	return hif_state->ce_services->ce_get_index_info(scn, ce_state, info);
+}
+
+void hif_log_ce_info(struct hif_opaque_softc *hif_ctx, uint8_t *data,
+		     unsigned int *offset)
+{
+	struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
+	struct hang_event_info info = {0};
+	static uint32_t tracked_ce = BIT(CE_ID_1) | BIT(CE_ID_2) |
+		BIT(CE_ID_3) | BIT(CE_ID_4) | BIT(CE_ID_9) | BIT(CE_ID_10);
+	uint8_t curr_index = 0;
+	uint8_t i;
+	uint16_t size;
+
+	info.active_tasklet_count = qdf_atomic_read(&scn->active_tasklet_cnt);
+	info.active_grp_tasklet_cnt =
+				qdf_atomic_read(&scn->active_grp_tasklet_cnt);
+
+	for (i = 0; i < scn->ce_count; i++) {
+		if (!(tracked_ce & BIT(i)) || !scn->ce_id_to_state[i])
+			continue;
+
+		if (ce_get_index_info(scn, scn->ce_id_to_state[i],
+				      &info.ce_info[curr_index]))
+			continue;
+
+		curr_index++;
+	}
+
+	info.ce_count = curr_index;
+	size = sizeof(info) -
+		(CE_COUNT_MAX - info.ce_count) * sizeof(struct ce_index);
+
+	QDF_HANG_EVT_SET_HDR(&info.tlv_header, HANG_EVT_TAG_CE_INFO,
+			     size - QDF_HANG_EVENT_TLV_HDR_SIZE);
+
+	qdf_mem_copy(data + *offset, &info, size);
+	*offset = *offset + size;
+}
+#endif
diff --git a/hif/src/ce/ce_main.h b/hif/src/ce/ce_main.h
index f3feb76..00ca3ec 100644
--- a/hif/src/ce/ce_main.h
+++ b/hif/src/ce/ce_main.h
@@ -265,6 +265,49 @@
 #endif
 #endif
 
+/**
+ * struct ce_index
+ *
+ * @id: CE id
+ * @sw_index: sw index
+ * @write_index: write index
+ * @hp: ring head pointer
+ * @tp: ring tail pointer
+ * @status_hp: status ring head pointer
+ * @status_tp: status ring tail pointer
+ */
+struct ce_index {
+	uint8_t id;
+	union {
+		struct {
+			uint16_t sw_index;
+			uint16_t write_index;
+		} legacy_info;
+		struct {
+			uint16_t hp;
+			uint16_t tp;
+			uint16_t status_hp;
+			uint16_t status_tp;
+		} srng_info;
+	} u;
+} qdf_packed;
+
+/**
+ * struct hang_event_info
+ *
+ * @tlv_header: tlv header
+ * @active_tasklet_count: active tasklet count
+ * @active_grp_tasklet_cnt: active grp tasklet count
+ * @ce_info: CE info
+ */
+struct hang_event_info {
+	uint32_t tlv_header;
+	uint8_t active_tasklet_count;
+	uint8_t active_grp_tasklet_cnt;
+	uint8_t ce_count;
+	struct ce_index ce_info[CE_COUNT_MAX];
+} qdf_packed;
+
 void hif_ce_stop(struct hif_softc *scn);
 int hif_dump_ce_registers(struct hif_softc *scn);
 void
diff --git a/hif/src/ce/ce_service_legacy.c b/hif/src/ce/ce_service_legacy.c
index 2a473b6..5596d0d 100644
--- a/hif/src/ce/ce_service_legacy.c
+++ b/hif/src/ce/ce_service_legacy.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2020 The Linux Foundation. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for
  * any purpose with or without fee is hereby granted, provided that the
@@ -1266,6 +1266,34 @@
 	return false;
 }
 
+#ifdef HIF_CE_LOG_INFO
+/**
+ * ce_get_index_info_legacy(): Get CE index info
+ * @scn: HIF Context
+ * @ce_state: CE opaque handle
+ * @info: CE info
+ *
+ * Return: 0 for success and non zero for failure
+ */
+static
+int ce_get_index_info_legacy(struct hif_softc *scn, void *ce_state,
+			     struct ce_index *info)
+{
+	struct CE_state *state = (struct CE_state *)ce_state;
+
+	info->id = state->id;
+	if (state->src_ring) {
+		info->u.legacy_info.sw_index = state->src_ring->sw_index;
+		info->u.legacy_info.write_index = state->src_ring->write_index;
+	} else if (state->dest_ring) {
+		info->u.legacy_info.sw_index = state->dest_ring->sw_index;
+		info->u.legacy_info.write_index = state->dest_ring->write_index;
+	}
+
+	return 0;
+}
+#endif
+
 struct ce_ops ce_service_legacy = {
 	.ce_get_desc_size = ce_get_desc_size_legacy,
 	.ce_ring_setup = ce_ring_setup_legacy,
@@ -1282,6 +1310,10 @@
 	.ce_send_entries_done_nolock = ce_send_entries_done_nolock_legacy,
 	.ce_prepare_shadow_register_v2_cfg =
 		ce_prepare_shadow_register_v2_cfg_legacy,
+#ifdef HIF_CE_LOG_INFO
+	.ce_get_index_info =
+		ce_get_index_info_legacy,
+#endif
 };
 
 struct ce_ops *ce_services_legacy()
diff --git a/hif/src/ce/ce_service_srng.c b/hif/src/ce/ce_service_srng.c
index 2082048..8168026 100644
--- a/hif/src/ce/ce_service_srng.c
+++ b/hif/src/ce/ce_service_srng.c
@@ -979,6 +979,43 @@
 			      num_shadow_registers_configured);
 }
 
+#ifdef HIF_CE_LOG_INFO
+/**
+ * ce_get_index_info_srng(): Get CE index info
+ * @scn: HIF Context
+ * @ce_state: CE opaque handle
+ * @info: CE info
+ *
+ * Return: 0 for success and non zero for failure
+ */
+static
+int ce_get_index_info_srng(struct hif_softc *scn, void *ce_state,
+			   struct ce_index *info)
+{
+	struct CE_state *CE_state = (struct CE_state *)ce_state;
+	uint32_t tp, hp;
+
+	info->id = CE_state->id;
+	if (CE_state->src_ring) {
+		hal_get_sw_hptp(scn->hal_soc, CE_state->src_ring->srng_ctx,
+				&tp, &hp);
+		info->u.srng_info.tp = tp;
+		info->u.srng_info.hp = hp;
+	} else if (CE_state->dest_ring && CE_state->status_ring) {
+		hal_get_sw_hptp(scn->hal_soc, CE_state->status_ring->srng_ctx,
+				&tp, &hp);
+		info->u.srng_info.status_tp = tp;
+		info->u.srng_info.status_hp = hp;
+		hal_get_sw_hptp(scn->hal_soc, CE_state->dest_ring->srng_ctx,
+				&tp, &hp);
+		info->u.srng_info.tp = tp;
+		info->u.srng_info.hp = hp;
+	}
+
+	return 0;
+}
+#endif
+
 static struct ce_ops ce_service_srng = {
 	.ce_get_desc_size = ce_get_desc_size_srng,
 	.ce_ring_setup = ce_ring_setup_srng,
@@ -995,6 +1032,10 @@
 	.ce_send_entries_done_nolock = ce_send_entries_done_nolock_srng,
 	.ce_prepare_shadow_register_v2_cfg =
 		ce_prepare_shadow_register_v2_cfg_srng,
+#ifdef HIF_CE_LOG_INFO
+	.ce_get_index_info =
+		ce_get_index_info_srng,
+#endif
 };
 
 struct ce_ops *ce_services_srng()