[DTV00890206] wowlan: support the way to get wakeup reason between magic packet and Cast

[Description]
Add FW event handler to receive the wakeup reason
Add iwpriv command to provide framework to get the wakeup reason

Change-Id: I4e766dad16a0245b44445eb11b811e8c03021ece
Signed-off-by: Evelyn Tasi <evelyn.tsai@mediatek.com>
CR-Id: DTV00890206
Feature: wowlan
Signed-off-by: Evelyn <evelyn.tsai@mediatek.com>
diff --git a/include/nic_cmd_event.h b/include/nic_cmd_event.h
index 9c6cd73..fbacc11 100644
--- a/include/nic_cmd_event.h
+++ b/include/nic_cmd_event.h
@@ -628,6 +628,10 @@
 	EVENT_ID_CSA_DONE = 0x61,
 #endif
 
+#if (CFG_WOW_SUPPORT == 1)
+	EVENT_ID_WOW_WAKEUP_REASON = 0x62,
+#endif
+
 	EVENT_ID_TDLS = 0x80,	/* TDLS event_id */
 
 	EVENT_ID_UPDATE_COEX_PHYRATE = 0x90,	/* 0x90 (Unsolicited) */
@@ -2325,6 +2329,14 @@
 } EVENT_RDD_REPORT_T, *P_EVENT_RDD_REPORT_T;
 #endif
 
+#if (CFG_WOW_SUPPORT == 1)
+/* event of wake up reason */
+struct _EVENT_WAKEUP_REASON_INFO {
+	UINT_8 reason;
+	UINT_8 aucReserved[3];
+};
+#endif
+
 typedef struct _EVENT_BSS_BEACON_TIMEOUT_T {
 	UINT_8 ucBssIndex;
 	UINT_8 ucReasonCode;
@@ -3165,7 +3177,9 @@
 VOID nicEventHifCtrl(IN P_ADAPTER_T prAdapter, IN P_WIFI_EVENT_T prEvent);
 VOID nicEventRddSendPulse(IN P_ADAPTER_T prAdapter, IN P_WIFI_EVENT_T prEvent);
 VOID nicEventUpdateCoexPhyrate(IN P_ADAPTER_T prAdapter, IN P_WIFI_EVENT_T prEvent);
-
+#if (CFG_WOW_SUPPORT == 1)
+VOID nicEventWakeUpReason(IN P_ADAPTER_T prAdapter, IN P_WIFI_EVENT_T prEvent);
+#endif
 /*******************************************************************************
 *                              F U N C T I O N S
 ********************************************************************************
diff --git a/include/wlan_lib.h b/include/wlan_lib.h
index a5741d4..96d6516 100644
--- a/include/wlan_lib.h
+++ b/include/wlan_lib.h
@@ -199,6 +199,10 @@
 #define ACS_DIRTINESS_LEVEL_LOW 32
 #endif
 
+#if CFG_WOW_SUPPORT
+#define INVALID_WOW_WAKE_UP_REASON 255
+#endif
+
 
 typedef enum _CMD_VER_T {
 	CMD_VER_1, /* Type[2]+String[32]+Value[32] */
@@ -483,6 +487,7 @@
 	UINT_8 aucReserved1[1];
 	WOW_WAKE_HIF_T astWakeHif[2];
 	WOW_PORT_T stWowPort;
+	UINT_8 ucReason;
 } WOW_CTRL_T, *P_WOW_CTRL_T;
 
 #endif
diff --git a/nic/nic_cmd_event.c b/nic/nic_cmd_event.c
index 178f8c1..7ec02f2 100644
--- a/nic/nic_cmd_event.c
+++ b/nic/nic_cmd_event.c
@@ -3289,3 +3289,34 @@
 	}
 }
 
+#if (CFG_WOW_SUPPORT == 1)
+VOID nicEventWakeUpReason(IN P_ADAPTER_T prAdapter, IN P_WIFI_EVENT_T prEvent)
+{
+	struct _EVENT_WAKEUP_REASON_INFO *prWakeUpReason;
+	P_GLUE_INFO_T prGlueInfo;
+
+	DBGLOG(NIC, INFO, "nicEventWakeUpReason\n");
+	prGlueInfo = prAdapter->prGlueInfo;
+
+	/* Driver receives EVENT_ID_WOW_WAKEUP_REASON after firmware wake up host
+	 * The possible Wakeup Reason define in FW as following
+	 * 0:  MAGIC PACKET
+	 * 1:  BITMAP
+	 * 2:  ARPNS
+	 * 3:  GTK_REKEY
+	 * 4:  COALESCING_FILTER
+	 * 5:  HW_GLOBAL_ENABLE
+	 * 6:  TCP_SYN PACKET
+	 * 7:  TDLS
+	 * 8:  DISCONNECT
+	 * 9:  IPV4_UDP PACKET
+	 * 10: IPV4_TCP PACKET
+	 * 11: IPV6_UDP PACKET
+	 * 12: IPV6_TCP PACKET
+	 */
+	prWakeUpReason = (struct _EVENT_WAKEUP_REASON_INFO *) (prEvent->aucBuffer);
+	prGlueInfo->prAdapter->rWowCtrl.ucReason = prWakeUpReason->reason;
+	DBGLOG(NIC, INFO, "nicEventWakeUpReason:%d\n", prGlueInfo->prAdapter->rWowCtrl.ucReason);
+}
+#endif
+
diff --git a/nic/nic_rx.c b/nic/nic_rx.c
index f48c29a..a2fab39 100644
--- a/nic/nic_rx.c
+++ b/nic/nic_rx.c
@@ -181,6 +181,10 @@
 #else
 	{EVENT_ID_UPDATE_COEX_PHYRATE,		nicEventUpdateCoexPhyrate},
 #endif
+#if (CFG_WOW_SUPPORT == 1)
+	{EVENT_ID_WOW_WAKEUP_REASON,		nicEventWakeUpReason},
+#endif
+
 };
 
 /*******************************************************************************
diff --git a/os/linux/gl_kal.c b/os/linux/gl_kal.c
index 95b2a82..05a2cb5 100644
--- a/os/linux/gl_kal.c
+++ b/os/linux/gl_kal.c
@@ -4983,6 +4983,7 @@
 VOID kalWowInit(IN P_GLUE_INFO_T prGlueInfo)
 {
 	kalMemZero(&prGlueInfo->prAdapter->rWowCtrl.stWowPort, sizeof(WOW_PORT_T));
+	prGlueInfo->prAdapter->rWowCtrl.ucReason = INVALID_WOW_WAKE_UP_REASON;
 }
 
 VOID kalWowCmdEventSetCb(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf)
@@ -5055,6 +5056,7 @@
 	wlanSetSuspendMode(prGlueInfo, enable);
 	/* p2pSetSuspendMode(prGlueInfo, TRUE); */
 
+	pWOW_CTRL->ucReason = INVALID_WOW_WAKE_UP_REASON;
 	/* Let WOW enable/disable as last command, so we can back/restore DMA classify filter in FW */
 	rCmdWowlanParam.ucScenarioID = pWOW_CTRL->ucScenarioId;
 	rCmdWowlanParam.ucBlockCount = pWOW_CTRL->ucBlockCount;
diff --git a/os/linux/gl_wext_priv.c b/os/linux/gl_wext_priv.c
index ab6fecf..6aeb404 100644
--- a/os/linux/gl_wext_priv.c
+++ b/os/linux/gl_wext_priv.c
@@ -2330,6 +2330,7 @@
 #define CMD_SET_WOW_UDP			"SET_WOW_UDP"
 #define CMD_SET_WOW_TCP			"SET_WOW_TCP"
 #define CMD_GET_WOW_PORT		"GET_WOW_PORT"
+#define CMD_GET_WOW_REASON		"GET_WOW_REASON"
 #endif
 #define CMD_SET_ADV_PWS			"SET_ADV_PWS"
 #define CMD_SET_MDTIM			"SET_MDTIM"
@@ -7826,6 +7827,28 @@
 		return -1;
 
 }
+
+static int priv_driver_get_wow_reason(IN struct net_device *prNetDev, IN char *pcCommand, IN int i4TotalLen)
+{
+	P_GLUE_INFO_T prGlueInfo = NULL;
+	INT_32 i4Argc = 0;
+	INT_32 i4BytesWritten = 0;
+	PCHAR apcArgv[WLAN_CFG_ARGV_MAX] = { 0 };
+	P_WOW_CTRL_T pWOW_CTRL = NULL;
+
+	ASSERT(prNetDev);
+	prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev));
+	pWOW_CTRL = &prGlueInfo->prAdapter->rWowCtrl;
+
+	DBGLOG(REQ, LOUD, "command is %s\n", pcCommand);
+	wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv);
+	DBGLOG(REQ, LOUD, "argc is %i\n", i4Argc);
+
+	if (pWOW_CTRL->ucReason != INVALID_WOW_WAKE_UP_REASON)
+		LOGBUF(pcCommand, i4TotalLen, i4BytesWritten, "\nwakeup_reason:%d", pWOW_CTRL->ucReason);
+
+	return	i4BytesWritten;
+}
 #endif
 
 static int priv_driver_set_adv_pws(IN struct net_device *prNetDev, IN char *pcCommand, IN int i4TotalLen)
@@ -9627,6 +9650,8 @@
 			i4BytesWritten = priv_driver_set_wow_tcpport(prNetDev, pcCommand, i4TotalLen);
 		else if (strnicmp(pcCommand, CMD_GET_WOW_PORT, strlen(CMD_GET_WOW_PORT)) == 0)
 			i4BytesWritten = priv_driver_get_wow_port(prNetDev, pcCommand, i4TotalLen);
+		else if (strnicmp(pcCommand, CMD_GET_WOW_REASON, strlen(CMD_GET_WOW_REASON)) == 0)
+			i4BytesWritten = priv_driver_get_wow_reason(prNetDev, pcCommand, i4TotalLen);
 #endif
 		else if (strnicmp(pcCommand, CMD_SET_ADV_PWS, strlen(CMD_SET_ADV_PWS)) == 0)
 			i4BytesWritten = priv_driver_set_adv_pws(prNetDev, pcCommand, i4TotalLen);