[WCNCR00158507] misc: add noise histogram feature

[Description]
Add noise histogram feature, needs the corresponding firmware

Usage:
1. Start collection (Disable power saving)
iwpriv wlan0 driver "SET_CHIP KeepFullPwr 1"
iwpriv wlan0 driver "noise_histogram enable"
iwpriv wlan0 driver "noise_histogram get"

2. Reset noise histogram to 0 (Optional)
iwpriv wlan0 driver "noise_histogram reset"

3. Stop collection  (Enable saving mode)
iwpriv wlan0 driver "noise_histogram disable"
iwpriv wlan0 driver "SET_CHIP KeepFullPwr 0"

4. Noise histogram format
keira: # iwpriv wlan0 driver "noise_histogram get"
wlan0     driver:
       Power > -55:          0
-55 >= Power > -60:          1
-60 >= Power > -65:         79
-65 >= Power > -70:       8874
-70 >= Power > -75:      11736
-75 >= Power > -80:       1863
-80 >= Power > -83:       1613
-83 >= Power > -86:      12429
-86 >= Power > -89:       8874
-89 >= Power > -92:       3987
-92 >= Power      :     249502

5. Works when AP is not connected

Test:
1. Sanity check: WiFi scan/connection OK
2. If not use the corresponding firmware,
   "noise_histogram get" will show 1 time command timeout log.
   This is expected due to no corresponding event in old firmware.

Change-Id: I1783f066768b34ffb8130d93dd53d66d0743a039
CR-Id: WCNCR00158507
Feature: misc
Signed-off-by: ZD Hu <zd.hu@mediatek.com>
(cherry picked from commit fa350821cf7f567f26be41d7aed7adf927f00df4)
diff --git a/common/wlan_oid.c b/common/wlan_oid.c
index 88a3513..905aa08 100644
--- a/common/wlan_oid.c
+++ b/common/wlan_oid.c
@@ -11830,6 +11830,10 @@
 		*pu4QueryInfoLen = sizeof(struct CMD_GET_TRAFFIC_REPORT);
 		len = sizeof(struct CMD_GET_TRAFFIC_REPORT);
 		break;
+	case CMD_NOISE_HISTOGRAM_TYPE:
+		*pu4QueryInfoLen = sizeof(struct CMD_NOISE_HISTOGRAM_REPORT);
+		len = sizeof(struct CMD_NOISE_HISTOGRAM_REPORT);
+		break;
 	default:
 		return WLAN_STATUS_INVALID_LENGTH;
 	}
diff --git a/include/nic_cmd_event.h b/include/nic_cmd_event.h
index 31d9c24..509a359 100644
--- a/include/nic_cmd_event.h
+++ b/include/nic_cmd_event.h
@@ -2475,6 +2475,7 @@
 #define CMD_AFH_CONFIG_TYPE (0x2)
 #define CMD_BA_CONFIG_TYPE (0x3)
 #define CMD_GET_REPORT_TYPE (0x4)
+#define CMD_NOISE_HISTOGRAM_TYPE (0x5)
 
 /* for PtaConfig field */
 #define CMD_PTA_CONFIG_PTA_EN (1<<0)
@@ -2625,6 +2626,33 @@
 	UINT_16 u2Type;
 	UINT_16 u2Len;
 } CMD_ADV_CONFIG_HEADER_T, *P_CMD_ADV_CONFIG_HEADER_T;
+
+/* noise histogram related */
+enum _ENUM_NOISE_HISTOGRAM_ACTION_T {
+	CMD_NOISE_HISTOGRAM_ENABLE = 1,
+	CMD_NOISE_HISTOGRAM_DISABLE,
+	CMD_NOISE_HISTOGRAM_RESET,
+	CMD_NOISE_HISTOGRAM_GET
+};
+struct CMD_NOISE_HISTOGRAM_REPORT {
+	UINT_16 u2Type;
+	UINT_16 u2Len;
+	/* parameter */
+	UINT_8 ucAction;
+	UINT_8 reserved[3];
+	/* IPI_report */
+	UINT_32 u4IPI0;  /* Power <= -92 */
+	UINT_32 u4IPI1;  /* -92 < Power <= -89 */
+	UINT_32 u4IPI2;  /* -89 < Power <= -86 */
+	UINT_32 u4IPI3;  /* -86 < Power <= -83 */
+	UINT_32 u4IPI4;  /* -83 < Power <= -80 */
+	UINT_32 u4IPI5;  /* -80 < Power <= -75 */
+	UINT_32 u4IPI6;  /* -75 < Power <= -70 */
+	UINT_32 u4IPI7;  /* -70 < Power <= -65 */
+	UINT_32 u4IPI8;  /* -65 < Power <= -60 */
+	UINT_32 u4IPI9;  /* -60 < Power <= -55 */
+	UINT_32 u4IPI10; /* -55 < Power  */
+};
 #endif
 typedef struct _CMD_SET_DEVICE_MODE_T {
 	UINT_16 u2ChipID;
diff --git a/os/linux/gl_wext_priv.c b/os/linux/gl_wext_priv.c
index 81168ba..5d99d2e 100644
--- a/os/linux/gl_wext_priv.c
+++ b/os/linux/gl_wext_priv.c
@@ -2369,6 +2369,7 @@
 #define CMD_GET_PD            "GET_PD"
 #define CMD_SET_MAX_RFGAIN        "SET_MAX_RFGAIN"
 #define CMD_GET_MAX_RFGAIN        "GET_MAX_RFGAIN"
+#define CMD_NOISE_HISTOGRAM   "NOISE_HISTOGRAM"
 
 enum {
 	CMD_ADVCTL_NOISE_ID = 1,
@@ -9850,6 +9851,108 @@
 	return i4BytesWritten;
 
 }
+
+static int priv_driver_noise_histogram(IN struct net_device *prNetDev, IN char *pcCommand, IN int i4TotalLen)
+{
+	WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS;
+	P_GLUE_INFO_T prGlueInfo;
+	INT_32 i4BytesWritten = 0;
+	UINT_32 u4BufLen = 0;
+	INT_32 i4Argc = 0;
+	PCHAR apcArgv[WLAN_CFG_ARGV_MAX];
+	struct CMD_NOISE_HISTOGRAM_REPORT *cmd = NULL;
+
+	wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv);
+
+	prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev));
+	if (!prGlueInfo)
+		goto noise_histogram_invalid;
+
+	cmd = (struct CMD_NOISE_HISTOGRAM_REPORT *)kalMemAlloc(sizeof(*cmd), VIR_MEM_TYPE);
+	if (!cmd)
+		goto noise_histogram_invalid;
+
+	if ((i4Argc > 4) || (i4Argc < 2))
+		goto noise_histogram_invalid;
+
+	memset(cmd, 0, sizeof(*cmd));
+
+	cmd->u2Type = CMD_NOISE_HISTOGRAM_TYPE;
+	cmd->u2Len = sizeof(*cmd);
+
+	if (strnicmp(apcArgv[1], "ENABLE", strlen("ENABLE")) == 0) {
+		cmd->ucAction = CMD_NOISE_HISTOGRAM_ENABLE;
+		cmd->u2Type |= CMD_ADV_CONTROL_SET;
+	} else if (strnicmp(apcArgv[1], "DISABLE", strlen("DISABLE")) == 0) {
+		cmd->ucAction = CMD_NOISE_HISTOGRAM_DISABLE;
+		cmd->u2Type |= CMD_ADV_CONTROL_SET;
+	} else if (strnicmp(apcArgv[1], "RESET", strlen("RESET")) == 0) {
+		cmd->ucAction = CMD_NOISE_HISTOGRAM_RESET;
+		cmd->u2Type |= CMD_ADV_CONTROL_SET;
+	} else if (strnicmp(apcArgv[1], "GET", strlen("GET")) == 0) {
+		cmd->ucAction = CMD_NOISE_HISTOGRAM_GET;
+	} else
+		goto noise_histogram_invalid;
+
+	DBGLOG(REQ, LOUD, "%s(%s) action %x\n"
+		, __func__, pcCommand, cmd->ucAction);
+
+	rStatus = kalIoctl(prGlueInfo, wlanoidAdvCtrl, cmd, sizeof(*cmd), TRUE, TRUE, TRUE, &u4BufLen);
+
+	if ((rStatus != WLAN_STATUS_SUCCESS) && (rStatus != WLAN_STATUS_PENDING))
+		i4BytesWritten += snprintf(pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten,
+				"\ncommand failed %x", rStatus);
+	else if (cmd->ucAction == CMD_NOISE_HISTOGRAM_GET) {
+
+		i4BytesWritten += snprintf(pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten,
+				"\n       Power > -55: %10d"
+				, cmd->u4IPI10);
+		i4BytesWritten += snprintf(pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten,
+				"\n-55 >= Power > -60: %10d"
+				, cmd->u4IPI9);
+		i4BytesWritten += snprintf(pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten,
+				"\n-60 >= Power > -65: %10d"
+				, cmd->u4IPI8);
+		i4BytesWritten += snprintf(pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten,
+				"\n-65 >= Power > -70: %10d"
+				, cmd->u4IPI7);
+		i4BytesWritten += snprintf(pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten,
+				"\n-70 >= Power > -75: %10d"
+				, cmd->u4IPI6);
+		i4BytesWritten += snprintf(pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten,
+				"\n-75 >= Power > -80: %10d"
+				, cmd->u4IPI5);
+		i4BytesWritten += snprintf(pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten,
+				"\n-80 >= Power > -83: %10d"
+				, cmd->u4IPI4);
+		i4BytesWritten += snprintf(pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten,
+				"\n-83 >= Power > -86: %10d"
+				, cmd->u4IPI3);
+		i4BytesWritten += snprintf(pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten,
+				"\n-86 >= Power > -89: %10d"
+				, cmd->u4IPI2);
+		i4BytesWritten += snprintf(pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten,
+				"\n-89 >= Power > -92: %10d"
+				, cmd->u4IPI1);
+		i4BytesWritten += snprintf(pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten,
+				"\n-92 >= Power      : %10d"
+				, cmd->u4IPI0);
+
+	} else
+		i4BytesWritten += snprintf(pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten,
+				"\ncommand sent %x", rStatus);
+
+	if (cmd)
+		kalMemFree(cmd, VIR_MEM_TYPE, sizeof(*cmd));
+
+	return i4BytesWritten;
+noise_histogram_invalid:
+	if (cmd)
+		kalMemFree(cmd, VIR_MEM_TYPE, sizeof(*cmd));
+	i4BytesWritten += snprintf(pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten,
+				"\nformat:get_report [enable|disable|get|reset]");
+	return i4BytesWritten;
+}
 #endif
 
 static int priv_driver_set_csi(IN struct net_device *prNetDev, IN char *pcCommand, IN int i4TotalLen)
@@ -10316,6 +10419,8 @@
 			i4BytesWritten = priv_driver_set_maxrfgain(prNetDev, pcCommand, i4TotalLen);
 		else if (strnicmp(pcCommand, CMD_GET_MAX_RFGAIN, strlen(CMD_GET_MAX_RFGAIN)) == 0)
 			i4BytesWritten = priv_driver_get_maxrfgain(prNetDev, pcCommand, i4TotalLen);
+		else if (strnicmp(pcCommand, CMD_NOISE_HISTOGRAM, strlen(CMD_NOISE_HISTOGRAM)) == 0)
+			i4BytesWritten = priv_driver_noise_histogram(prNetDev, pcCommand, i4TotalLen);
 #endif
 		else
 			i4CmdFound = 0;