wlan: Handle fatal event triggered from framework and FW

Currently driver supports the fatal event triggered using ioctl.
Support is added for framework and FW triggered fatal events

Change-Id: I52acc8f85495b75807c72e0c5279701e38326c58
CRs-Fixed: 912066
diff --git a/CORE/HDD/inc/wlan_hdd_cfg80211.h b/CORE/HDD/inc/wlan_hdd_cfg80211.h
index 79c54f9..abbabe6 100644
--- a/CORE/HDD/inc/wlan_hdd_cfg80211.h
+++ b/CORE/HDD/inc/wlan_hdd_cfg80211.h
@@ -175,6 +175,8 @@
     QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_RESET_SSID_HOTLIST = 66,
     QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_HOTLIST_SSID_FOUND = 67,
     QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_HOTLIST_SSID_LOST = 68,
+    QCA_NL80211_VENDOR_SUBCMD_GET_RING_DATA = 77,
+
     QCA_NL80211_VENDOR_SUBCMD_SETBAND = 105,
 };
 
@@ -1082,6 +1084,21 @@
     QCA_WLAN_VENDOR_ATTR_SET_NO_DFS_FLAG_MAX =
         QCA_WLAN_VENDOR_ATTR_SET_NO_DFS_FLAG_AFTER_LAST - 1,
 };
+/*
+ * enum qca_wlan_vendor_attr_wifi_logger_get_ring_data - Get ring data
+ * @QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_GET_RING_DATA_INVALID: Invalid attribute
+ * @QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_GET_RING_DATA_ID: Ring ID
+ * @QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_GET_RING_DATA_AFTER_LAST: Last value
+ * @QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_GET_RING_DATA_MAX: Max value
+ */
+enum qca_wlan_vendor_attr_wifi_logger_get_ring_data {
+    QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_GET_RING_DATA_INVALID = 0,
+    QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_GET_RING_DATA_ID = 1,
+    /* keep last */
+    QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_GET_RING_DATA_AFTER_LAST,
+    QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_GET_RING_DATA_MAX =
+        QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_GET_RING_DATA_AFTER_LAST - 1,
+};
 
 
 /* Vendor id to be used in vendor specific command and events
diff --git a/CORE/HDD/src/wlan_hdd_cfg80211.c b/CORE/HDD/src/wlan_hdd_cfg80211.c
index 5e4b849..85a58cc 100644
--- a/CORE/HDD/src/wlan_hdd_cfg80211.c
+++ b/CORE/HDD/src/wlan_hdd_cfg80211.c
@@ -5594,6 +5594,88 @@
     return ret;
 }
 
+
+static const struct
+nla_policy
+qca_wlan_vendor_wifi_logger_get_ring_data_policy
+[QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_GET_RING_DATA_MAX + 1] = {
+    [QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_GET_RING_DATA_ID]
+        = {.type = NLA_U32 },
+};
+
+static int
+    __wlan_hdd_cfg80211_wifi_logger_get_ring_data(struct wiphy *wiphy,
+                                                      struct wireless_dev *wdev,
+                                                      const void *data,
+                                                      int data_len)
+{
+    int ret;
+    VOS_STATUS status;
+    uint32_t ring_id;
+    hdd_context_t *hdd_ctx = wiphy_priv(wiphy);
+    struct nlattr *tb
+        [QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_GET_RING_DATA_MAX + 1];
+
+    ENTER();
+
+    ret = wlan_hdd_validate_context(hdd_ctx);
+    if (0 != ret) {
+        return ret;
+    }
+
+    if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_GET_RING_DATA_MAX,
+            data, data_len,
+            qca_wlan_vendor_wifi_logger_get_ring_data_policy)) {
+        hddLog(LOGE, FL("Invalid attribute"));
+        return -EINVAL;
+    }
+
+    /* Parse and fetch ring id */
+    if (!tb[QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_GET_RING_DATA_ID]) {
+        hddLog(LOGE, FL("attr ATTR failed"));
+        return -EINVAL;
+    }
+
+    ring_id = nla_get_u32(
+            tb[QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_GET_RING_DATA_ID]);
+
+    hddLog(LOG1, FL("Bug report triggered by framework"));
+
+    status = vos_fatal_event_logs_req(WLAN_LOG_TYPE_NON_FATAL,
+                WLAN_LOG_INDICATOR_FRAMEWORK,
+                WLAN_LOG_REASON_CODE_FRAMEWORK,
+                TRUE
+                );
+    if (VOS_STATUS_SUCCESS != status) {
+        hddLog(LOGE, FL("Failed to trigger bug report"));
+
+        return -EINVAL;
+    }
+
+    return 0;
+
+
+}
+
+
+static int
+    wlan_hdd_cfg80211_wifi_logger_get_ring_data(struct wiphy *wiphy,
+                                                      struct wireless_dev *wdev,
+                                                      const void *data,
+                                                      int data_len)
+{
+    int ret = 0;
+
+    vos_ssr_protect(__func__);
+    ret = __wlan_hdd_cfg80211_wifi_logger_get_ring_data(wiphy,
+            wdev, data, data_len);
+    vos_ssr_unprotect(__func__);
+
+    return ret;
+
+}
+
+
 static int
 __wlan_hdd_cfg80211_get_concurrency_matrix(struct wiphy *wiphy,
                                          struct wireless_dev *wdev,
@@ -6396,6 +6478,14 @@
                  WIPHY_VENDOR_CMD_NEED_NETDEV|
                   WIPHY_VENDOR_CMD_NEED_RUNNING,
         .doit = wlan_hdd_cfg80211_get_wifi_info
+    },
+    {
+        .info.vendor_id = QCA_NL80211_VENDOR_ID,
+        .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_GET_RING_DATA,
+        .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
+                 WIPHY_VENDOR_CMD_NEED_NETDEV |
+                 WIPHY_VENDOR_CMD_NEED_RUNNING,
+        .doit = wlan_hdd_cfg80211_wifi_logger_get_ring_data
     }
 };
 
diff --git a/CORE/HDD/src/wlan_hdd_wext.c b/CORE/HDD/src/wlan_hdd_wext.c
index 2502c81..2304198 100644
--- a/CORE/HDD/src/wlan_hdd_wext.c
+++ b/CORE/HDD/src/wlan_hdd_wext.c
@@ -7089,7 +7089,7 @@
         {
             vos_fatal_event_logs_req(WLAN_LOG_TYPE_NON_FATAL,
                      WLAN_LOG_INDICATOR_IOCTL,
-                     WLAN_LOG_REASON_CODE_UNUSED,
+                     WLAN_LOG_REASON_IOCTL,
                      TRUE);
             break;
         }
diff --git a/CORE/SVC/inc/wlan_logging_sock_svc.h b/CORE/SVC/inc/wlan_logging_sock_svc.h
index 95f278d..9d8d071 100644
--- a/CORE/SVC/inc/wlan_logging_sock_svc.h
+++ b/CORE/SVC/inc/wlan_logging_sock_svc.h
@@ -84,5 +84,19 @@
 void wlan_disable_and_flush_pkt_stats(void);
  void wlan_fillTxStruct(void *pktStat);
  bool wlan_isPktStatsEnabled(void);
+#ifdef FEATURE_WLAN_DIAG_SUPPORT
+void wlan_report_log_completion(uint32 is_fatal,
+      uint32 indicator,
+      uint32 reason_code);
+#else
+static inline void wlan_report_log_completion(uint32 is_fatal,
+        uint32 indicator,
+        uint32 reason_code)
+{
+    return;
+}
+
+#endif
+
 
 #endif /* WLAN_LOGGING_SOCK_SVC_H */
diff --git a/CORE/SVC/src/logging/wlan_logging_sock_svc.c b/CORE/SVC/src/logging/wlan_logging_sock_svc.c
index a8bee4d..ed10cfd 100644
--- a/CORE/SVC/src/logging/wlan_logging_sock_svc.c
+++ b/CORE/SVC/src/logging/wlan_logging_sock_svc.c
@@ -1368,7 +1368,6 @@
 	gwlan_logging.log_complete.is_report_in_progress = true;
 	gwlan_logging.log_complete.reason_code = reason_code;
 	spin_unlock_irqrestore(&gwlan_logging.bug_report_lock, flags);
-
 	return 0;
 }
 void wlan_get_log_completion(uint32 *is_fatal,
@@ -1382,15 +1381,15 @@
 	*is_fatal = gwlan_logging.log_complete.is_fatal;
 	*reason_code = gwlan_logging.log_complete.reason_code;
 	gwlan_logging.log_complete.is_report_in_progress = false;
-
 	spin_unlock_irqrestore(&gwlan_logging.bug_report_lock, flags);
-
 }
+
 bool wlan_is_log_report_in_progress(void)
 {
 	return gwlan_logging.log_complete.is_report_in_progress;
 }
 
+
 void wlan_reset_log_report_in_progress(void)
 {
 	unsigned long flags;
@@ -1849,6 +1848,7 @@
 
 void wlan_process_done_indication(uint8 type, uint32 reason_code)
 {
+<<<<<<< HEAD
     if ((type == WLAN_FW_LOGS) && (wlan_is_log_report_in_progress() == TRUE))
     {
         pr_info("%s: Setting LOGGER_FATAL_EVENT\n", __func__);
@@ -1862,6 +1862,28 @@
 	    wake_up_interruptible(&gwlan_logging.wait_queue);
     }
 
+=======
+	if ((type == WLAN_FW_LOGS) && reason_code)
+	{
+		if(wlan_is_log_report_in_progress() == TRUE)
+		{
+			pr_info("%s : Setting LOGGER_FATAL_EVENT\n", __func__);
+			set_bit(LOGGER_FATAL_EVENT_POST_MASK, &gwlan_logging.event_flag);
+			wake_up_interruptible(&gwlan_logging.wait_queue);
+		}
+		else
+		{
+			/*Firmware Initiated*/
+			pr_info("%s : FW triggered Fatal Event, reason_code : %d\n", __func__,
+			reason_code);
+			wlan_set_log_completion(WLAN_LOG_TYPE_FATAL,
+					WLAN_LOG_INDICATOR_FIRMWARE,
+					reason_code);
+			set_bit(LOGGER_FATAL_EVENT_POST_MASK, &gwlan_logging.event_flag);
+			wake_up_interruptible(&gwlan_logging.wait_queue);
+		}
+	}
+>>>>>>> 6ea54f9... wlan: Handle fatal event triggered from framework and FW
 }
 
 /**
@@ -1907,6 +1929,7 @@
 	spin_unlock_irqrestore(&gwlan_logging.thread_stuck_lock, flags);
 }
 
+<<<<<<< HEAD
 int wlan_fwr_mem_dump_buffer_allocation(void)
 {
 	/*Allocate the dump memory as reported by fw.
@@ -2104,5 +2127,33 @@
 	kfree_skb(skb);
 	return;
 }
+=======
+#ifdef FEATURE_WLAN_DIAG_SUPPORT
+/**
+ * wlan_report_log_completion() - Report bug report completion to userspace
+ * @is_fatal: Type of event, fatal or not
+ * @indicator: Source of bug report, framework/host/firmware
+ * @reason_code: Reason for triggering bug report
+ *
+ * This function is used to report the bug report completion to userspace
+ *
+ * Return: None
+ */
+void wlan_report_log_completion(uint32_t is_fatal,
+				uint32_t indicator,
+				uint32_t reason_code)
+{
+	WLAN_VOS_DIAG_EVENT_DEF(wlan_diag_event,
+				struct vos_event_wlan_log_complete);
+
+	wlan_diag_event.is_fatal = is_fatal;
+	wlan_diag_event.indicator = indicator;
+	wlan_diag_event.reason_code = reason_code;
+	wlan_diag_event.reserved = 0;
+
+	WLAN_VOS_DIAG_EVENT_REPORT(&wlan_diag_event, EVENT_WLAN_LOG_COMPLETE);
+}
+#endif
+>>>>>>> 6ea54f9... wlan: Handle fatal event triggered from framework and FW
 
 #endif /* WLAN_LOGGING_SOCK_SVC_ENABLE */
diff --git a/CORE/VOSS/inc/event_defs.h b/CORE/VOSS/inc/event_defs.h
index 38a1694..c076cfe 100644
--- a/CORE/VOSS/inc/event_defs.h
+++ b/CORE/VOSS/inc/event_defs.h
@@ -1903,6 +1903,7 @@
   EVENT_SNS_DRV_OPMODE_CHANGE = 0x768,
   EVENT_WLAN_EAPOL = 0xA8D,/* 18 bytes payload */
   EVENT_WLAN_WAKE_LOCK = 0xAA2, /* 96 bytes payload */
+  EVENT_WLAN_LOG_COMPLETE = 0xAA7, /* 16 bytes payload */
   EVENT_NEXT_UNUSED_EVENT,
   EVENT_RSVD_START = 0x0800,
   EVENT_RSVD_END   = 0x083F,
diff --git a/CORE/VOSS/inc/vos_api.h b/CORE/VOSS/inc/vos_api.h
index 99746e5..1352502 100644
--- a/CORE/VOSS/inc/vos_api.h
+++ b/CORE/VOSS/inc/vos_api.h
@@ -196,6 +196,8 @@
 	WLAN_LOG_REASON_MALLOC_FAIL,
 	WLAN_LOG_REASON_VOS_MSG_UNDER_RUN,
 	WLAN_LOG_REASON_MSG_POST_FAIL,
+	WLAN_LOG_REASON_IOCTL,
+	WLAN_LOG_REASON_CODE_FRAMEWORK,
 };
 
 /*------------------------------------------------------------------------- 
diff --git a/CORE/VOSS/inc/vos_diag_core_event.h b/CORE/VOSS/inc/vos_diag_core_event.h
index 715fbd2..596711d 100644
--- a/CORE/VOSS/inc/vos_diag_core_event.h
+++ b/CORE/VOSS/inc/vos_diag_core_event.h
@@ -283,6 +283,24 @@
 };
 
 
+/*-------------------------------------------------------------------------
+  Event ID: EVENT_WLAN_LOG_COMPLETE
+  ------------------------------------------------------------------------*/
+/**
+ * struct vos_event_wlan_log_complete - Holds log completion details
+ * @is_fatal: Indicates if the event is fatal or not
+ * @indicator: Source of the bug report - Framework/Host/Firmware
+ * @reason_code: Reason for triggering bug report
+ * @reserved: Reserved field
+ *
+ * This structure holds the log completion related information
+ */
+struct vos_event_wlan_log_complete {
+    uint32_t is_fatal;
+    uint32_t indicator;
+    uint32_t reason_code;
+    uint32_t reserved;
+};
 
 
 /*------------------------------------------------------------------------- 
diff --git a/CORE/VOSS/src/vos_api.c b/CORE/VOSS/src/vos_api.c
index 9bb72ad..4a9a779 100644
--- a/CORE/VOSS/src/vos_api.c
+++ b/CORE/VOSS/src/vos_api.c
@@ -1722,8 +1722,10 @@
     /*The below API will reset is_report_in_progress flag*/
     vos_get_log_completion(&is_fatal, &indicator, &reason_code);
     VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_INFO,
-         "%s: is_fatal : %d, indicator: %d, reason_code=%d",
-         __func__, is_fatal, indicator, reason_code);
+         "is_fatal : %d, indicator: %d, reason_code=%d",
+         is_fatal, indicator, reason_code);
+    wlan_report_log_completion(is_fatal, indicator, reason_code);
+
 }
 
 
diff --git a/CORE/WDI/TRP/DTS/src/wlan_qct_wdi_dts.c b/CORE/WDI/TRP/DTS/src/wlan_qct_wdi_dts.c
index bfb3ed9..1832804 100644
--- a/CORE/WDI/TRP/DTS/src/wlan_qct_wdi_dts.c
+++ b/CORE/WDI/TRP/DTS/src/wlan_qct_wdi_dts.c
@@ -940,6 +940,10 @@
      vos_process_done_indication(pLoggingSession->logType,
                                  pLoggingSession->reasonCode);
 
+
+  if (pLoggingSession->logType == QXDM_LOGGING &&
+     pLoggingSession->reasonCode)
+      pLoggingSession->logType = FATAL_EVENT;
   ((WDI_DS_ClientDataType *)(pContext))->rxLogCB(pLoggingSession->logType);
 
   pLoggingSession->done = 0;
diff --git a/riva/inc/wlan_hal_msg.h b/riva/inc/wlan_hal_msg.h
index c3d332e..593fbee 100644
--- a/riva/inc/wlan_hal_msg.h
+++ b/riva/inc/wlan_hal_msg.h
@@ -140,7 +140,8 @@
 {
     MGMT_FRAME_LOGS    = 0,
     QXDM_LOGGING       = 1,
-    FW_MEMORY_DUMP     = 2
+    FW_MEMORY_DUMP     = 2,
+    FATAL_EVENT        = 3
 }tHalFrameLoggingType;
 
 /* Log size */