Browse Source

Version 1.9.0_20180717-1550 released

Jenkins 7 years ago
parent
commit
43a08f7fec
48 changed files with 1477 additions and 205 deletions
  1. 5 1
      crypto/hmac.c
  2. 3 2
      crypto/shash.c
  3. 2 2
      drivers/input/touchscreen/mediatek/GT1151/gt1x_generic.c
  4. 3 0
      drivers/input/touchscreen/mediatek/GT1151/gt1x_tools.c
  5. 24 2
      drivers/misc/mediatek/base/power/mt6735/mt_ptp.c
  6. 14 1
      drivers/misc/mediatek/cameraisp/src/mt6735/camera_sysram_D1.c
  7. 10 3
      drivers/misc/mediatek/connectivity/common/conn_soc/linux/pri/wmt_dev.c
  8. 21 1
      drivers/misc/mediatek/connectivity/wlan/gen2/Makefile
  9. 270 0
      drivers/misc/mediatek/connectivity/wlan/gen2/common/fwcfg.c
  10. 61 0
      drivers/misc/mediatek/connectivity/wlan/gen2/common/wlan_oid.c
  11. 126 0
      drivers/misc/mediatek/connectivity/wlan/gen2/include/fwcfg.h
  12. 5 0
      drivers/misc/mediatek/connectivity/wlan/gen2/include/wlan_oid.h
  13. 53 1
      drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/tdls.c
  14. 26 0
      drivers/misc/mediatek/connectivity/wlan/gen2/nic/nic_cmd_event.c
  15. 29 0
      drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_init.c
  16. 56 0
      drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_p2p.c
  17. 166 56
      drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_proc.c
  18. 18 1
      drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_vendor.c
  19. 4 0
      drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_os.h
  20. 1 0
      drivers/misc/mediatek/eccci/ccci_bm.h
  21. 8 0
      drivers/misc/mediatek/eccci/ccci_core.h
  22. 6 0
      drivers/misc/mediatek/eccci/modem_ccif_c2k.c
  23. 107 38
      drivers/misc/mediatek/eccci/modem_cldma.c
  24. 2 1
      drivers/misc/mediatek/eccci/modem_cldma.h
  25. 10 1
      drivers/misc/mediatek/eccci/mt6735/cldma_platform.c
  26. 46 6
      drivers/misc/mediatek/eccci/port_kernel.c
  27. 32 5
      drivers/misc/mediatek/fmradio/core/fm_main.c
  28. 2 0
      drivers/misc/mediatek/include/mt-plat/mt6735/include/mach/mt_thermal.h
  29. 65 2
      drivers/misc/mediatek/thermal/common/thermal_zones/mtk_ts_cpu.c
  30. 2 0
      drivers/misc/mediatek/thermal/mt6735/inc/D1/tscpu_settings.h
  31. 2 0
      drivers/misc/mediatek/thermal/mt6735/inc/D2/tscpu_settings.h
  32. 2 0
      drivers/misc/mediatek/thermal/mt6735/inc/D3/tscpu_settings.h
  33. 6 6
      drivers/misc/mediatek/thermal/mt6735/src/mtk_tc_D1.c
  34. 6 6
      drivers/misc/mediatek/thermal/mt6735/src/mtk_tc_D2.c
  35. 6 6
      drivers/misc/mediatek/thermal/mt6735/src/mtk_tc_D3.c
  36. 37 9
      drivers/mmc/host/mediatek/emmc_rpmb.c
  37. 30 5
      drivers/power/mediatek/battery_common.c
  38. 6 3
      drivers/usb/core/config.c
  39. 20 4
      drivers/usb/gadget/f_hid.c
  40. 8 0
      include/crypto/internal/hash.h
  41. 94 7
      kernel/futex.c
  42. 27 19
      lib/asn1_decoder.c
  43. 5 2
      net/ipv4/ip_output.c
  44. 3 0
      net/ipv4/raw.c
  45. 1 1
      net/ipv4/udp.c
  46. 8 5
      net/ipv6/ip6_output.c
  47. 2 0
      net/ipv6/raw.c
  48. 37 9
      security/keys/request_key.c

+ 5 - 1
crypto/hmac.c

@@ -194,11 +194,15 @@ static int hmac_create(struct crypto_template *tmpl, struct rtattr **tb)
 	salg = shash_attr_alg(tb[1], 0, 0);
 	if (IS_ERR(salg))
 		return PTR_ERR(salg);
+	alg = &salg->base;
 
+	/* The underlying hash algorithm must be unkeyed */
 	err = -EINVAL;
+	if (crypto_shash_alg_has_setkey(salg))
+		goto out_put_alg;
+
 	ds = salg->digestsize;
 	ss = salg->statesize;
-	alg = &salg->base;
 	if (ds > alg->cra_blocksize ||
 	    ss < alg->cra_blocksize)
 		goto out_put_alg;

+ 3 - 2
crypto/shash.c

@@ -24,11 +24,12 @@
 
 static const struct crypto_type crypto_shash_type;
 
-static int shash_no_setkey(struct crypto_shash *tfm, const u8 *key,
-			   unsigned int keylen)
+int shash_no_setkey(struct crypto_shash *tfm, const u8 *key,
+		    unsigned int keylen)
 {
 	return -ENOSYS;
 }
+EXPORT_SYMBOL_GPL(shash_no_setkey);
 
 static int shash_setkey_unaligned(struct crypto_shash *tfm, const u8 *key,
 				  unsigned int keylen)

+ 2 - 2
drivers/input/touchscreen/mediatek/GT1151/gt1x_generic.c

@@ -181,7 +181,7 @@ static ssize_t gt1x_debug_write_proc(struct file *file, const char __user *buffe
 		return count;
 	}
 
-	ret = sscanf(buf, "%s %d", (char *)&mode_str, &mode);
+	ret = sscanf(buf, "%49s %d", (char *)&mode_str, &mode);
 	if (ret < 0) {
 		GTP_ERROR("Sscanf buf ERROR1");
 		return ret;
@@ -238,7 +238,7 @@ static ssize_t gt1x_debug_write_proc(struct file *file, const char __user *buffe
 		return count;
 	}
 #endif
-	ret = sscanf(buf, "%s %s", (char *)&mode_str, (char *)&arg1);
+	ret = sscanf(buf, "%49s %49s", (char *)&mode_str, (char *)&arg1);
 	if (ret < 0) {
 		GTP_ERROR("Sscanf buf ERROR2");
 		return ret;

+ 3 - 0
drivers/input/touchscreen/mediatek/GT1151/gt1x_tools.c

@@ -279,6 +279,9 @@ static ssize_t gt1x_tool_write(struct file *filp, const char __user *buff, size_
 		return cmd_head.data_len + CMD_HEAD_LENGTH;
 	} else if (3 == cmd_head.wr) {	/*gt1x unused*/
 
+		cmd_head.data_len =
+			cmd_head.data_len > sizeof(IC_TYPE) ?
+				sizeof(IC_TYPE) : cmd_head.data_len;
 		memcpy(IC_TYPE, cmd_head.data, cmd_head.data_len);
 		return cmd_head.data_len + CMD_HEAD_LENGTH;
 	} else if (5 == cmd_head.wr) {

+ 24 - 2
drivers/misc/mediatek/base/power/mt6735/mt_ptp.c

@@ -137,6 +137,7 @@ unsigned int reg_dump_addr_off[] = {
 #include "mach/mt_thermal.h"
 #include "mach/mt_clkmgr.h"
 #include "mach/mt_freqhopping.h"
+#include "mt-plat/upmu_common.h"
 
 #ifdef CONFIG_OF
 #include <linux/of.h>
@@ -1244,16 +1245,25 @@ static void ptp_init_det(struct ptp_det *det, struct ptp_devinfo *devinfo)
 	FUNC_EXIT(FUNC_LV_HELP);
 }
 
+int __attribute__((weak)) tscpu_is_temp_valid(void)
+{
+	return 1;
+}
+
+void __attribute__((weak)) pmic_force_vproc_pwm(unsigned int en)
+{
+}
 
 static void ptp_set_ptp_volt(struct ptp_det *det)
 {
 #if SET_PMIC_VOLT
 	int i, cur_temp, low_temp_offset;
 	struct ptp_ctrl *ctrl = id_to_ptp_ctrl(det->ctrl_id);
+	int tscpu_bank0_temp_is_valid = tscpu_is_temp_valid();
 
 	 cur_temp = det->ops->get_temp(det);
-	/* ptp_debug("ptp_set_ptp_volt cur_temp = %d\n", cur_temp); */
-	if (cur_temp <= 33000) {
+	ptp_debug("ptp_set_ptp_volt(): cur_temp = %d, valid = %d\n", cur_temp, tscpu_bank0_temp_is_valid);
+	if (!tscpu_bank0_temp_is_valid || cur_temp <= 33000) {
 		low_temp_offset = 10;
 		ctrl->volt_update |= PTP_VOLT_UPDATE;
 	} else {
@@ -1774,9 +1784,12 @@ static int ptp_probe(struct platform_device *pdev)
 	int ret;
 	struct ptp_det *det;
 	struct ptp_ctrl *ctrl;
+	enum mt_cpu_dvfs_id cpu;
 
 	FUNC_ENTER(FUNC_LV_MODULE);
 
+	cpu = MT_CPU_DVFS_LITTLE;
+
 	/* set PTP IRQ */
 	ret = request_irq(ptpod_irq_number, ptp_isr, IRQF_TRIGGER_LOW, "ptp", NULL);
 
@@ -1797,6 +1810,10 @@ static int ptp_probe(struct platform_device *pdev)
 	/* disable DVFS and set vproc = 1.15v (1 GHz) */
 	mt_cpufreq_disable_by_ptpod(MT_CPU_DVFS_LITTLE);
 
+	/* Enable PWM mode here */
+	if (mt_cpufreq_get_freq_by_idx(cpu, 0) <= 1300000)
+		pmic_force_vproc_pwm(1);
+
 	/*for slow idle */
 	ptp_data[0] = 0xffffffff;
 
@@ -1804,6 +1821,11 @@ static int ptp_probe(struct platform_device *pdev)
 		ptp_init_det(det, &ptp_devinfo);
 	}
 	ptp_init01();
+
+	/* Disable PWM mode here */
+	if (mt_cpufreq_get_freq_by_idx(cpu, 0) <= 1300000)
+		pmic_force_vproc_pwm(0);
+
 	ptp_data[0] = 0;
 	/* enable DVFS */
 	mt_cpufreq_enable_by_ptpod(MT_CPU_DVFS_LITTLE);

+ 14 - 1
drivers/misc/mediatek/cameraisp/src/mt6735/camera_sysram_D1.c

@@ -1,3 +1,16 @@
+/*
+ * Copyright (C) 2015 MediaTek Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
 #include <linux/uaccess.h>
 #include <linux/module.h>
 #include <linux/types.h>
@@ -809,7 +822,7 @@ static int SYSRAM_mmap(
 	struct file *pFile,
 	struct vm_area_struct *pVma)
 {
-	long length = 0;
+	unsigned long length = 0;
 	MUINT32 pfn = 0x0;
 	/* LOG_MSG(""); */
 	pVma->vm_page_prot = pgprot_noncached(pVma->vm_page_prot);

+ 10 - 3
drivers/misc/mediatek/connectivity/common/conn_soc/linux/pri/wmt_dev.c

@@ -2109,12 +2109,12 @@ long WMT_unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 		break;
 
 	case WMT_IOCTL_SET_PATCH_NUM:{
-			pAtchNum = arg;
-			if (pAtchNum == 0 || pAtchNum > MAX_PATCH_NUM) {
-				WMT_ERR_FUNC("patch num(%d) == 0 or > %d!\n", pAtchNum, MAX_PATCH_NUM);
+			if (arg == 0 || arg > MAX_PATCH_NUM) {
+				WMT_ERR_FUNC("patch num(%d) == 0 or > %d!\n", arg, MAX_PATCH_NUM);
 				iRet = -1;
 				break;
 			}
+			pAtchNum = arg;
 
 			pPatchInfo = kcalloc(pAtchNum, sizeof(WMT_PATCH_INFO), GFP_ATOMIC);
 			if (!pPatchInfo) {
@@ -2145,6 +2145,13 @@ long WMT_unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 				break;
 			}
 
+			if (wMtPatchInfo.dowloadSeq > pAtchNum || wMtPatchInfo.dowloadSeq == 0) {
+				WMT_ERR_FUNC("dowloadSeq num(%u) > %u or == 0!\n", wMtPatchInfo.dowloadSeq, pAtchNum);
+				iRet = -EFAULT;
+				counter = 0;
+				break;
+			}
+
 			dWloadSeq = wMtPatchInfo.dowloadSeq;
 			WMT_DBG_FUNC(
 				"patch dl seq %d,name %s,address info 0x%02x,0x%02x,0x%02x,0x%02x\n",

+ 21 - 1
drivers/misc/mediatek/connectivity/wlan/gen2/Makefile

@@ -112,6 +112,7 @@ OS_DIR      := os/linux/
 HIF_DIR	    := os/linux/hif/ahb/
 NIC_DIR     := nic/
 MGMT_DIR    := mgmt/
+FWCFG_DIR   := $(srctree)/drivers/misc/mediatek/connectivity/wlan/gen2/$(MTK_PROJECT)/
 DMA_DIR     := ../../../../platform/$(call lc,$(MTK_PLATFORM))/kernel/drivers/wifi/
 PLAT_DIR    := os/linux/plat/$(MTK_PLATFORM)/
 #$(call lc,$(MTK_PLATFORM))
@@ -223,7 +224,26 @@ ifeq ($(CONFIG_ARCH_MT6735), y)
 PLAT_OBJS := $(PLAT_DIR)plat_priv.o
 $(MODULE_NAME)-objs  += $(PLAT_OBJS)
 endif
-
+# ---------------------------------------------------
+# FW customization
+# ---------------------------------------------------
+FW_CUSTOMIZATION = y
+ifeq ($(FW_CUSTOMIZATION), y)
+$(warning fw_config, $(FWCFG_DIR)fw_config.c)
+ifneq ($(wildcard $(FWCFG_DIR)fw_config.c),)
+$(warning fw_config exist, $(FWCFG_DIR))
+	COMMON_OBJS += $(MTK_PROJECT)/fw_config.o
+endif
+	COMMON_OBJS += $(COMMON_DIR)fwcfg.o
+	ccflags-y += -DFW_CFG_SUPPORT
+ifeq ($(TARGET_BUILD_VARIANT), eng)
+    ccflags-y += -DENABLED_IN_ENGUSERDEBUG
+endif
+ifeq ($(TARGET_BUILD_VARIANT), userdebug)
+    ccflags-y += -DENABLED_IN_ENGUSERDEBUG
+endif
+endif
+# ---------------------------------------------------
 $(MODULE_NAME)-objs  += $(COMMON_OBJS)
 $(MODULE_NAME)-objs  += $(NIC_OBJS)
 $(MODULE_NAME)-objs  += $(OS_OBJS)

+ 270 - 0
drivers/misc/mediatek/connectivity/wlan/gen2/common/fwcfg.c

@@ -0,0 +1,270 @@
+/*
+* Copyright (C) 2016 MediaTek Inc.
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License version 2 as
+* published by the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+* See http://www.gnu.org/licenses/gpl-2.0.html for more details.
+*/
+
+
+#include "fwcfg.h"
+
+/*******************************************************************************
+*                   F U N C T I O N   D E C L A R A T I O N S
+********************************************************************************
+*/
+static char *strtok_r(char *s, const char *delim, char **last);
+/*******************************************************************************
+*                            P U B L I C   D A T A
+********************************************************************************
+*/
+struct _FW_CFG __weak fwCfgArray[] = {
+};
+/* ******************************************************************************
+*                              F U N C T I O N S
+*********************************************************************************
+*/
+INT_32 __weak getFwCfgItemNum()
+{
+	return ARRAY_SIZE(fwCfgArray);
+}
+
+PUINT_8 __weak getFwCfgItemKey(UINT_8 i)
+{
+	if (i < ARRAY_SIZE(fwCfgArray))
+		return fwCfgArray[i].key;
+	else
+		return NULL;
+}
+
+PUINT_8 __weak getFwCfgItemValue(UINT_8 i)
+{
+	if (i < ARRAY_SIZE(fwCfgArray))
+		return fwCfgArray[i].value;
+	else
+		return NULL;
+}
+
+void wlanCfgFwSetParam(PUINT_8 fwBuffer, PCHAR cmdStr, PCHAR value, int num, int type)
+{
+	struct _CMD_FORMAT_V1_T *cmd = (struct _CMD_FORMAT_V1_T *)fwBuffer + num;
+
+	kalMemSet(cmd, 0, sizeof(struct _CMD_FORMAT_V1_T));
+	cmd->itemType = type;
+
+	cmd->itemStringLength = strlen(cmdStr);
+	if (cmd->itemStringLength > MAX_CMD_NAME_MAX_LENGTH)
+		cmd->itemStringLength = MAX_CMD_NAME_MAX_LENGTH;
+
+	/* here will not ensure the end will be '\0' */
+	kalMemCopy(cmd->itemString, cmdStr, cmd->itemStringLength);
+
+	cmd->itemValueLength = strlen(value);
+	if (cmd->itemValueLength > MAX_CMD_VALUE_MAX_LENGTH)
+		cmd->itemValueLength = MAX_CMD_VALUE_MAX_LENGTH;
+
+	/* here will not ensure the end will be '\0' */
+	kalMemCopy(cmd->itemValue, value, cmd->itemValueLength);
+}
+
+WLAN_STATUS wlanCfgSetGetFw(IN P_ADAPTER_T prAdapter, const PCHAR fwBuffer, int cmdNum, enum _CMD_TYPE_T cmdType)
+{
+	struct _CMD_HEADER_T *pcmdV1Header = NULL;
+
+	pcmdV1Header = (struct _CMD_HEADER_T *) kalMemAlloc(sizeof(struct _CMD_HEADER_T), VIR_MEM_TYPE);
+
+	if (pcmdV1Header == NULL)
+		return WLAN_STATUS_FAILURE;
+
+	kalMemSet(pcmdV1Header->buffer, 0, MAX_CMD_BUFFER_LENGTH);
+	pcmdV1Header->cmdType = cmdType;
+	pcmdV1Header->cmdVersion = CMD_VER_1_EXT;
+	pcmdV1Header->itemNum = cmdNum;
+	pcmdV1Header->cmdBufferLen = cmdNum * sizeof(struct _CMD_FORMAT_V1_T);
+	kalMemCopy(pcmdV1Header->buffer, fwBuffer, pcmdV1Header->cmdBufferLen);
+
+	wlanSendSetQueryCmd(prAdapter, CMD_ID_GET_SET_CUSTOMER_CFG,
+				TRUE, FALSE, FALSE,
+				NULL, NULL,
+				sizeof(struct _CMD_HEADER_T),
+				(PUINT_8) pcmdV1Header,
+				NULL, 0);
+	kalMemFree(pcmdV1Header, VIR_MEM_TYPE, sizeof(struct _CMD_HEADER_T));
+	return WLAN_STATUS_SUCCESS;
+}
+
+WLAN_STATUS wlanFwArrayCfg(IN P_ADAPTER_T prAdapter)
+{
+	int kk = 0;
+	PUINT_8 cmdBuffer = NULL;
+	int fwCfgItemNum = getFwCfgItemNum();
+
+	if (!fwCfgItemNum)
+		return WLAN_STATUS_FAILURE;
+
+	cmdBuffer = kalMemAlloc(MAX_CMD_BUFFER_LENGTH, VIR_MEM_TYPE);
+
+	if (cmdBuffer == 0)
+		return WLAN_STATUS_FAILURE;
+
+	kalMemSet(cmdBuffer, 0, MAX_CMD_BUFFER_LENGTH);
+
+	for (; kk < fwCfgItemNum;) {
+		wlanCfgFwSetParam(cmdBuffer, getFwCfgItemKey(kk),
+			getFwCfgItemValue(kk), (kk % MAX_CMD_ITEM_MAX), 1);
+		kk++;
+		if (kk % MAX_CMD_ITEM_MAX == 0) {
+			wlanCfgSetGetFw(prAdapter, cmdBuffer, MAX_CMD_ITEM_MAX, CMD_TYPE_SET);
+			kalMemSet(cmdBuffer, 0, MAX_CMD_BUFFER_LENGTH);
+		}
+	}
+	if (kk % MAX_CMD_ITEM_MAX)
+		wlanCfgSetGetFw(prAdapter, cmdBuffer, (kk % MAX_CMD_ITEM_MAX), CMD_TYPE_SET);
+
+	kalMemFree(cmdBuffer, VIR_MEM_TYPE, MAX_CMD_BUFFER_LENGTH);
+	return WLAN_STATUS_SUCCESS;
+}
+
+WLAN_STATUS wlanFwFileCfg(IN P_ADAPTER_T prAdapter)
+{
+	UINT_32 u4FwCfgReadLen = 0;
+	PUINT_8 pucFwCfgBuf = (PUINT_8) kalMemAlloc(WLAN_CFG_FILE_BUF_SIZE, VIR_MEM_TYPE);
+
+	if (!pucFwCfgBuf) {
+		DBGLOG(INIT, INFO, "omega, pucFwCfgBuf alloc fail!");
+		return WLAN_STATUS_FAILURE;
+	}
+	kalMemZero(pucFwCfgBuf, WLAN_CFG_FILE_BUF_SIZE);
+
+	if (kalReadToFile(FW_CFG_FILE, pucFwCfgBuf,
+		WLAN_CFG_FILE_BUF_SIZE, &u4FwCfgReadLen)) {
+		DBGLOG(INIT, INFO, "omega, kalreadtofile fail!");
+		kalMemFree(pucFwCfgBuf, VIR_MEM_TYPE, WLAN_CFG_FILE_BUF_SIZE);
+		return WLAN_STATUS_FAILURE;
+	}
+
+	if (pucFwCfgBuf[0] != '\0' && u4FwCfgReadLen > 0) {
+		/* Here limited the file length < 2048, bcz only for dbg purpose
+		 * Meanwhile, if the file length == 2048, it MAY cause the last
+		 * several <= 4 cmd failed
+		 */
+		if (u4FwCfgReadLen == WLAN_CFG_FILE_BUF_SIZE)
+			pucFwCfgBuf[WLAN_CFG_FILE_BUF_SIZE - 1] = '\0';
+
+		wlanFwCfgParse(prAdapter, pucFwCfgBuf);
+	}
+	kalMemFree(pucFwCfgBuf, VIR_MEM_TYPE, WLAN_CFG_FILE_BUF_SIZE);
+	return WLAN_STATUS_SUCCESS;
+}
+
+WLAN_STATUS wlanFwCfgParse(IN P_ADAPTER_T prAdapter, PUINT_8 pucConfigBuf)
+{
+	/* here return a list should be better */
+	char *saveptr1, *saveptr2;
+	char *cfgItems = pucConfigBuf;
+	UINT_8 cmdNum = 0;
+
+	PUINT_8 cmdBuffer = kalMemAlloc(MAX_CMD_BUFFER_LENGTH, VIR_MEM_TYPE);
+
+	if (cmdBuffer == 0) {
+		DBGLOG(INIT, INFO, "omega, cmd buffer return fail!");
+		return WLAN_STATUS_FAILURE;
+	}
+	kalMemSet(cmdBuffer, 0, MAX_CMD_BUFFER_LENGTH);
+
+	while (1) {
+		char *keyStr = NULL;
+		char *valueStr = NULL;
+		char *cfgEntry = strtok_r(cfgItems, "\n\r", &saveptr1);
+
+		if (!cfgEntry) {
+			if (cmdNum)
+				wlanCfgSetGetFw(prAdapter, cmdBuffer, cmdNum, CMD_TYPE_SET);
+
+			if (cmdBuffer)
+				kalMemFree(cmdBuffer, VIR_MEM_TYPE, MAX_CMD_BUFFER_LENGTH);
+			return WLAN_STATUS_SUCCESS;
+		}
+		cfgItems = NULL;
+
+		keyStr = strtok_r(cfgEntry, " \t", &saveptr2);
+		valueStr = strtok_r(NULL, "\0", &saveptr2);
+
+		/* maybe a blank line, but with some tab or whitespace */
+		if (!keyStr)
+			continue;
+
+		/* here take '#' at the beginning of line as comment */
+		if (keyStr[0] == '#')
+			continue;
+
+		/* remove the \t " " at the beginning of the valueStr */
+		while (valueStr && (*valueStr == '\t' || *valueStr == ' '))
+			valueStr++;
+
+		if (keyStr && valueStr) {
+			wlanCfgFwSetParam(cmdBuffer, keyStr, valueStr, cmdNum, 1);
+			cmdNum++;
+			if (cmdNum == MAX_CMD_ITEM_MAX) {
+				wlanCfgSetGetFw(prAdapter, cmdBuffer, MAX_CMD_ITEM_MAX, CMD_TYPE_SET);
+				kalMemSet(cmdBuffer, 0, MAX_CMD_BUFFER_LENGTH);
+				cmdNum = 0;
+			}
+		} else {
+			/* here will not to try send the cmd has been parsed, but not sent yet */
+			if (cmdBuffer)
+				kalMemFree(cmdBuffer, VIR_MEM_TYPE, MAX_CMD_BUFFER_LENGTH);
+			return WLAN_STATUS_FAILURE;
+		}
+	}
+}
+
+/*
+ * This func is mainly from bionic's strtok.c
+ */
+static char *strtok_r(char *s, const char *delim, char **last)
+{
+	char *spanp;
+	int c, sc;
+	char *tok;
+
+
+	if (s == NULL) {
+		s = *last;
+		if (s == 0)
+			return 0;
+	}
+cont:
+	c = *s++;
+	for (spanp = (char *)delim; (sc = *spanp++) != 0;) {
+		if (c == sc)
+			goto cont;
+	}
+
+	if (c == 0) {		/* no non-delimiter characters */
+		*last = NULL;
+		return NULL;
+	}
+	tok = s - 1;
+
+	for (;;) {
+		c = *s++;
+		spanp = (char *)delim;
+		do {
+			sc = *spanp++;
+			if (sc == c) {
+				if (c == 0)
+					s = NULL;
+				else
+					s[-1] = 0;
+				*last = s;
+				return tok;
+			}
+		} while (sc != 0);
+	}
+}

+ 61 - 0
drivers/misc/mediatek/connectivity/wlan/gen2/common/wlan_oid.c

@@ -1061,6 +1061,9 @@
 #include "precomp.h"
 #include "mgmt/rsn.h"
 
+#ifdef FW_CFG_SUPPORT
+#include "fwcfg.h"
+#endif
 #include <stddef.h>
 
 /******************************************************************************
@@ -5547,6 +5550,12 @@ wlanoidSetSwCtrlWrite(IN P_ADAPTER_T prAdapter,
 
 			authSendDeauthFrame(prAdapter, prBssInfo->prStaRecOfAP, NULL, 7, NULL);
 		}
+		if (u2SubId == 0x4) {
+			P_BSS_INFO_T prBssInfo = &(prAdapter->rWifiVar.arBssInfo[(NETWORK_TYPE_AIS_INDEX)]);
+
+			DBGLOG(RSN, INFO, "Send deauth\n");
+			authSendDeauthFrame(prAdapter, prBssInfo->prStaRecOfAP, NULL, 1, NULL);
+		}
 		/* wext_set_mode */
 		/*
 		   if (u2SubId == 0x3) {
@@ -11057,3 +11066,55 @@ wlanoidNotifyFwSuspend(IN P_ADAPTER_T prAdapter,
 							0);
 }
 
+#ifdef FW_CFG_SUPPORT
+/*----------------------------------------------------------------------------*/
+/*!
+* \brief This routine is called to query fw cfg info
+*
+* \param[in]  pvAdapter        Pointer to the Adapter structure.
+* \param[out] pvQueryBuffer    A pointer to the buffer that holds the result of
+*                              the query.
+* \param[in]  u4QueryBufferLen The length of the query buffer.
+* \param[out] pu4QueryInfoLen  If the call is successful, returns the number of
+*                              bytes written into the query buffer. If the call
+*                              failed due to invalid length of the query buffer,
+*                              returns the amount of storage needed.
+*
+* \retval WLAN_STATUS_PENDING
+* \retval WLAN_STATUS_FAILURE
+*/
+/*----------------------------------------------------------------------------*/
+WLAN_STATUS wlanoidQueryCfgRead(IN P_ADAPTER_T prAdapter,
+			   IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen)
+{
+	struct _CMD_HEADER_T *prCmdV1Header = (struct _CMD_HEADER_T *)pvQueryBuffer;
+	struct _CMD_HEADER_T cmdV1Header;
+	WLAN_STATUS rStatus = WLAN_STATUS_FAILURE;
+
+	ASSERT(prAdapter);
+	ASSERT(pu4QueryInfoLen);
+
+	if (u4QueryBufferLen)
+		ASSERT(pvQueryBuffer);
+
+	*pu4QueryInfoLen = sizeof(struct _CMD_HEADER_T);
+
+	if (u4QueryBufferLen < sizeof(struct _CMD_HEADER_T))
+		return WLAN_STATUS_INVALID_LENGTH;
+
+	kalMemCopy(&cmdV1Header, prCmdV1Header, sizeof(struct _CMD_HEADER_T));
+	rStatus = wlanSendSetQueryCmd(
+			prAdapter,
+			CMD_ID_GET_SET_CUSTOMER_CFG,
+			FALSE,
+			TRUE,
+			TRUE,
+			nicCmdEventQueryCfgRead,
+			nicCmdTimeoutCommon,
+			sizeof(struct _CMD_HEADER_T),
+			(PUINT_8) &cmdV1Header,
+			pvQueryBuffer,
+			u4QueryBufferLen);
+	return rStatus;
+}
+#endif

+ 126 - 0
drivers/misc/mediatek/connectivity/wlan/gen2/include/fwcfg.h

@@ -0,0 +1,126 @@
+/*
+* Copyright (C) 2016 MediaTek Inc.
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License version 2 as
+* published by the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+* See http://www.gnu.org/licenses/gpl-2.0.html for more details.
+*/
+
+#ifndef _FWCFG_H
+#define _FWCFG_H
+#include "precomp.h"
+/*******************************************************************************
+*                         C O M P I L E R   F L A G S
+********************************************************************************
+*/
+
+/*******************************************************************************
+*                    E X T E R N A L   R E F E R E N C E S
+********************************************************************************
+*/
+
+/*******************************************************************************
+*                              C O N S T A N T S
+********************************************************************************
+*/
+#ifdef FW_CFG_SUPPORT
+#define MAX_CMD_ITEM_MAX		4
+#define MAX_CMD_NAME_MAX_LENGTH		32
+#define MAX_CMD_VALUE_MAX_LENGTH	32
+
+#define MAX_CMD_TYPE_LENGTH		1
+#define MAX_CMD_RESERVE_LENGTH		1
+#define MAX_CMD_STRING_LENGTH		1
+#define MAX_CMD_VALUE_LENGTH		1
+
+#define CMD_FORMAT_V1_LENGTH		(MAX_CMD_NAME_MAX_LENGTH + \
+					MAX_CMD_VALUE_MAX_LENGTH + MAX_CMD_TYPE_LENGTH + \
+					MAX_CMD_STRING_LENGTH + MAX_CMD_VALUE_LENGTH + MAX_CMD_RESERVE_LENGTH)
+
+#define MAX_CMD_BUFFER_LENGTH		(CMD_FORMAT_V1_LENGTH * MAX_CMD_ITEM_MAX)
+
+#define FW_CFG_FILE "/etc/firmware/wifi_fw.cfg"
+/*******************************************************************************
+*                             D A T A   T Y P E S
+********************************************************************************
+*/
+
+enum _CMD_VER_T {
+	CMD_VER_1,
+	CMD_VER_1_EXT
+};
+
+enum _CMD_TYPE_T {
+	CMD_TYPE_QUERY,
+	CMD_TYPE_SET
+};
+
+struct _CMD_FORMAT_V1_T {
+	UINT_8 itemType;
+	UINT_8 itemStringLength;
+	UINT_8 itemValueLength;
+	UINT_8 Reserved;
+	UINT_8 itemString[MAX_CMD_NAME_MAX_LENGTH];
+	UINT_8 itemValue[MAX_CMD_VALUE_MAX_LENGTH];
+};
+
+struct _CMD_HEADER_T {
+	enum _CMD_VER_T cmdVersion;
+	enum _CMD_TYPE_T cmdType;
+	UINT_8 itemNum;
+	UINT_16 cmdBufferLen;
+	UINT_8 buffer[MAX_CMD_BUFFER_LENGTH];
+};
+
+struct WLAN_CFG_PARSE_STATE_S {
+	CHAR *ptr;
+	CHAR *text;
+	INT_32 nexttoken;
+	UINT_32 maxSize;
+};
+
+struct _FW_CFG {
+	PUINT_8 key;
+	PUINT_8 value;
+};
+/*******************************************************************************
+*                            P U B L I C   D A T A
+********************************************************************************
+*/
+/*******************************************************************************
+*                           P R I V A T E   D A T A
+********************************************************************************
+*/
+
+/*******************************************************************************
+*                                 M A C R O S
+********************************************************************************
+*/
+
+/*******************************************************************************
+*                   F U N C T I O N   D E C L A R A T I O N S
+********************************************************************************
+*/
+
+INT_32 getFwCfgItemNum(void);
+
+PUINT_8 getFwCfgItemKey(UINT_8 i);
+
+PUINT_8 getFwCfgItemValue(UINT_8 i);
+
+void wlanCfgFwSetParam(PUINT_8 fwBuffer, PCHAR cmdStr, PCHAR value, int num, int type);
+
+WLAN_STATUS wlanCfgSetGetFw(IN P_ADAPTER_T prAdapter, const PCHAR fwBuffer, int cmdNum, enum _CMD_TYPE_T cmdType);
+
+WLAN_STATUS wlanFwCfgParse(IN P_ADAPTER_T prAdapter, PUINT_8 pucConfigBuf);
+
+WLAN_STATUS wlanFwArrayCfg(IN P_ADAPTER_T prAdpter);
+
+WLAN_STATUS wlanFwFileCfg(IN P_ADAPTER_T prAdpter);
+#endif
+#endif

+ 5 - 0
drivers/misc/mediatek/connectivity/wlan/gen2/include/wlan_oid.h

@@ -1713,6 +1713,11 @@ wlanoidNotifyFwSuspend(IN P_ADAPTER_T prAdapter,
 								IN UINT_32 u4SetBufferLen,
 								OUT PUINT_32 pu4SetInfoLen);
 
+#ifdef FW_CFG_SUPPORT
+WLAN_STATUS wlanoidQueryCfgRead(IN P_ADAPTER_T prAdapter,
+				IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen);
+#endif
+
 #endif /* _WLAN_OID_H */
 WLAN_STATUS wlanoidSetPacketFilter(P_ADAPTER_T prAdapter, UINT_32 u4PacketFilter,
 				BOOLEAN fgIsOid, PVOID pvSetBuffer, UINT_32 u4SetBufferLen);

+ 53 - 1
drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/tdls.c

@@ -1,3 +1,54 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual license.  When you use or
+ * distribute this software, you may choose to be licensed under
+ * version 2 of the GNU General Public License ("GPLv2 License")
+ * or BSD License.
+ *
+ * GPLv2 License
+ *
+ * Copyright(C) 2016 MediaTek Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See http://www.gnu.org/licenses/gpl-2.0.html for more details.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(C) 2016 MediaTek Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name of the copyright holder nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *****************************************************************************/
 /*
 ** Id: tdls.c#1
 */
@@ -4984,7 +5035,8 @@ VOID TdlsexRxFrameHandle(GLUE_INFO_T *prGlueInfo, UINT8 *pPkt, UINT16 u2PktLen)
 		switch (ucElmId) {
 		case ELEM_ID_HT_CAP:	/* 0x2d */
 			/* backup the HT IE of 1st unhandled setup request frame */
-			if (prGlueInfo->rTdlsHtCap.ucId == 0x00) {
+			if (prGlueInfo->rTdlsHtCap.ucId == 0x00 &&
+					ucElmLen <= sizeof(IE_HT_CAP_T) - 2) {
 				kalMemCopy(prGlueInfo->aucTdlsHtPeerMac, pucPeerMac, 6);
 				kalMemCopy(&prGlueInfo->rTdlsHtCap, pPkt - 2, ucElmLen + 2);
 

+ 26 - 0
drivers/misc/mediatek/connectivity/wlan/gen2/nic/nic_cmd_event.c

@@ -320,6 +320,9 @@
 ********************************************************************************
 */
 #include "precomp.h"
+#ifdef FW_CFG_SUPPORT
+#include "fwcfg.h"
+#endif
 
 /*******************************************************************************
 *                              C O N S T A N T S
@@ -1636,3 +1639,26 @@ VOID nicCmdEventGetBSSInfo(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo,
 	}
 
 }
+#ifdef FW_CFG_SUPPORT
+VOID nicCmdEventQueryCfgRead(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf)
+{
+	UINT_32 u4QueryInfoLen;
+	struct _CMD_HEADER_T *prInCfgHeader;
+	P_GLUE_INFO_T prGlueInfo;
+	struct _CMD_HEADER_T *prOutCfgHeader;
+
+	ASSERT(prAdapter);
+	ASSERT(prCmdInfo);
+	ASSERT(pucEventBuf);
+
+	if (prCmdInfo->fgIsOid) {
+		prGlueInfo = prAdapter->prGlueInfo;
+		prInCfgHeader = (struct _CMD_HEADER_T *) pucEventBuf;
+		u4QueryInfoLen = sizeof(struct _CMD_HEADER_T);
+		prOutCfgHeader = (struct _CMD_HEADER_T *) prCmdInfo->pvInformationBuffer;
+		kalMemCopy(prOutCfgHeader, prInCfgHeader, sizeof(struct _CMD_HEADER_T));
+
+		kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, WLAN_STATUS_SUCCESS);
+	}
+}
+#endif

+ 29 - 0
drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_init.c

@@ -681,6 +681,9 @@
 #endif
 #include "gl_vendor.h"
 
+#ifdef FW_CFG_SUPPORT
+#include "fwcfg.h"
+#endif
 /*******************************************************************************
 *                              C O N S T A N T S
 ********************************************************************************
@@ -2884,6 +2887,7 @@ static INT_32 wlanProbe(PVOID pvData)
 		prAdapter->u4CSUMFlags = (CSUM_OFFLOAD_EN_TX_TCP | CSUM_OFFLOAD_EN_TX_UDP | CSUM_OFFLOAD_EN_TX_IP);
 #endif
 #if CFG_SUPPORT_CFG_FILE
+#ifdef ENABLED_IN_ENGUSERDEBUG
 		{
 			PUINT_8 pucConfigBuf;
 			UINT_32 u4ConfigReadLen;
@@ -2911,6 +2915,7 @@ static INT_32 wlanProbe(PVOID pvData)
 				kalMemFree(pucConfigBuf, VIR_MEM_TYPE, WLAN_CFG_FILE_BUF_SIZE);
 			}	/* pucConfigBuf */
 		}
+#endif
 #endif
 		/* 4 <5> Start Device */
 		/*  */
@@ -2931,7 +2936,9 @@ static INT_32 wlanProbe(PVOID pvData)
 			/* Load NVRAM content to REG_INFO_T */
 			glLoadNvram(prGlueInfo, prRegInfo);
 #if CFG_SUPPORT_CFG_FILE
+#ifdef ENABLED_IN_ENGUSERDEBUG
 			wlanCfgApply(prAdapter);
+#endif
 #endif
 
 			/* kalMemCopy(&prGlueInfo->rRegInfo, prRegInfo, sizeof(REG_INFO_T)); */
@@ -3057,6 +3064,18 @@ bailout:
 #endif
 			}
 		}
+#ifdef FW_CFG_SUPPORT
+		{
+			if (wlanFwArrayCfg(prAdapter) != WLAN_STATUS_FAILURE)
+				DBGLOG(INIT, INFO, "FW Array Cfg done!");
+		}
+#ifdef ENABLED_IN_ENGUSERDEBUG
+		{
+			if (wlanFwFileCfg(prAdapter) != WLAN_STATUS_FAILURE)
+				DBGLOG(INIT, INFO, "FW File Cfg done!");
+		}
+#endif
+#endif
 
 #if CFG_TCP_IP_CHKSUM_OFFLOAD
 		/* set HW checksum offload */
@@ -3097,6 +3116,13 @@ bailout:
 		}
 #endif /* WLAN_INCLUDE_PROC */
 
+#ifdef FW_CFG_SUPPORT
+		i4Status = cfgCreateProcEntry(prGlueInfo);
+		if (i4Status < 0) {
+			DBGLOG(INIT, ERROR, "fw cfg proc failed\n");
+			break;
+		}
+#endif
 #if CFG_ENABLE_BT_OVER_WIFI
 		prGlueInfo->rBowInfo.fgIsNetRegistered = FALSE;
 		prGlueInfo->rBowInfo.fgIsRegistered = FALSE;
@@ -3253,6 +3279,9 @@ static VOID wlanRemove(VOID)
 
 	kalPerMonDestroy(prGlueInfo);
 	/* 4 <3> Remove /proc filesystem. */
+#ifdef FW_CFG_SUPPORT
+	cfgRemoveProcEntry();
+#endif
 #ifdef WLAN_INCLUDE_PROC
 	procRemoveProcfs();
 #endif /* WLAN_INCLUDE_PROC */

+ 56 - 0
drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_p2p.c

@@ -1,3 +1,55 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual license.  When you use or
+ * distribute this software, you may choose to be licensed under
+ * version 2 of the GNU General Public License ("GPLv2 License")
+ * or BSD License.
+ *
+ * GPLv2 License
+ *
+ * Copyright(C) 2016 MediaTek Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See http://www.gnu.org/licenses/gpl-2.0.html for more details.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(C) 2016 MediaTek Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name of the copyright holder nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *****************************************************************************/
+
 /*
 ** Id: @(#) gl_p2p.c@@
 */
@@ -2908,6 +2960,10 @@ mtk_p2p_wext_set_key(IN struct net_device *prDev,
 
 					/* BSSID */
 					memcpy(prKey->arBSSID, prIWEncExt->addr.sa_data, 6);
+					if (prIWEncExt->key_len >= 32) {
+						ret = -EINVAL;
+						break;
+					}
 					memcpy(prKey->aucKeyMaterial, prIWEncExt->key, prIWEncExt->key_len);
 
 					prKey->u4KeyLength = prIWEncExt->key_len;

+ 166 - 56
drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_proc.c

@@ -1,3 +1,16 @@
+/*
+ * Copyright (C) 2016 MediaTek Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See http://www.gnu.org/licenses/gpl-2.0.html for more details.
+ */
+
 /*
 ** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/os/linux/gl_proc.c#1
 */
@@ -64,6 +77,9 @@
 
 #include "precomp.h"
 
+#ifdef FW_CFG_SUPPORT
+#include "fwcfg.h"
+#endif
 /* #include "wlan_lib.h" */
 /* #include "debug.h" */
 
@@ -80,6 +96,7 @@
 #define PROC_NEED_TX_DONE						"TxDoneCfg"
 #define PROC_ROOT_NAME			"wlan"
 #define PROC_CMD_DEBUG_NAME		"cmdDebug"
+#define PROC_CFG_NAME			"cfg"
 
 #define PROC_MCR_ACCESS_MAX_USER_INPUT_LEN      20
 #define PROC_RX_STATISTICS_MAX_USER_INPUT_LEN   10
@@ -108,6 +125,9 @@
 #if CFG_SUPPORT_THERMO_THROTTLING
 static P_GLUE_INFO_T g_prGlueInfo_proc;
 #endif
+#if FW_CFG_SUPPORT
+static P_GLUE_INFO_T gprGlueInfo;
+#endif
 /*******************************************************************************
 *                                 M A C R O S
 ********************************************************************************
@@ -502,8 +522,7 @@ static ssize_t procDbgLevelWrite(struct file *file, const char *buffer, size_t c
 	UINT_8 *temp = &aucProcBuf[0];
 
 	kalMemSet(aucProcBuf, 0, u4CopySize);
-	if (u4CopySize >= count + 1)
-		u4CopySize = count;
+	u4CopySize = (count < u4CopySize) ? count : (u4CopySize - 1);
 
 	if (copy_from_user(aucProcBuf, buffer, u4CopySize)) {
 		kalPrint("error of copy from user\n");
@@ -583,8 +602,7 @@ static ssize_t procTxDoneCfgWrite(struct file *file, const char *buffer, size_t
 	UINT_8 aucModuleArray[][MODULE_NAME_LENGTH] = {"ARP", "DNS", "TCP", "UDP", "EAPOL", "DHCP", "ICMP"};
 
 	kalMemSet(aucProcBuf, 0, u4CopySize);
-	if (u4CopySize >= count + 1)
-		u4CopySize = count;
+	u4CopySize = (count < u4CopySize) ? count : (u4CopySize - 1);
 
 	if (copy_from_user(aucProcBuf, buffer, u4CopySize)) {
 		kalPrint("error of copy from user\n");
@@ -594,7 +612,7 @@ static ssize_t procTxDoneCfgWrite(struct file *file, const char *buffer, size_t
 	temp = &aucProcBuf[0];
 	while (temp) {
 		/* pick up a string and teminated after meet : */
-		if (sscanf(temp, "%s %d", aucModule, &u4Enabled) != 2)  {
+		if (sscanf(temp, "%5s %d", aucModule, &u4Enabled) != 2)  {
 			kalPrint("read param fail, aucModule=%s\n", aucModule);
 			break;
 		}
@@ -799,85 +817,54 @@ INT32 wlan_get_link_mode(void)
 	return 0;
 }
 
-static ssize_t procfile_write(struct file *filp, const char __user *buffer, size_t count, loff_t *f_pos)
+static ssize_t procfile_write(struct file *filp, const char __user *buffer,
+			      size_t count, loff_t *f_pos)
 {
 	char buf[256];
 	char *pBuf;
 	ULONG len = count;
-	INT32 x = 0, y = 0, z = 0;
+	unsigned int x = 0;
 	char *pToken = NULL;
 	char *pDelimiter = " \t";
-	INT32 i4Ret = 0;
-
-	if (copy_from_user(gCoexBuf1.buffer, buffer, count))
-		return -EFAULT;
-	/* gCoexBuf1.availSize = count; */
+	INT32 i4Ret = -1;
 
-	/* return gCoexBuf1.availSize; */
-#if 1
 	DBGLOG(INIT, TRACE, "write parameter len = %d\n\r", (INT32) len);
 	if (len >= sizeof(buf)) {
 		DBGLOG(INIT, ERROR, "input handling fail!\n");
-		len = sizeof(buf) - 1;
 		return -1;
 	}
 
 	if (copy_from_user(buf, buffer, len))
 		return -EFAULT;
+
 	buf[len] = '\0';
 	DBGLOG(INIT, TRACE, "write parameter data = %s\n\r", buf);
-
 	pBuf = buf;
 	pToken = strsep(&pBuf, pDelimiter);
-
-	if (pToken) /* x = NULL != pToken ? simple_strtol(pToken, NULL, 16) : 0; */
-		i4Ret = kalkStrtos32(pToken, 16, &x);
-	if (!i4Ret)
-		DBGLOG(INIT, TRACE, "x = 0x%x\n", x);
-
-#if 1
-	pToken = strsep(&pBuf, "\t\n ");
-	if (pToken != NULL) {
-		i4Ret = kalkStrtos32(pToken, 16, &y); /* y = simple_strtol(pToken, NULL, 16); */
+	if (pToken) {
+		i4Ret = kalkStrtou32(pToken, 16, &x);
 		if (!i4Ret)
-			DBGLOG(INIT, TRACE, "y = 0x%08x\n\r", y);
-	} else {
-		y = 3000;
-		/*efuse, register read write default value */
-		if (0x11 == x || 0x12 == x || 0x13 == x)
-			y = 0x80000000;
-	}
-
-	pToken = strsep(&pBuf, "\t\n ");
-	if (pToken != NULL) {
-		i4Ret = kalkStrtos32(pToken, 16, &z); /* z = simple_strtol(pToken, NULL, 16); */
-		if (!i4Ret)
-			DBGLOG(INIT, TRACE, "z = 0x%08x\n\r", z);
-	} else {
-		z = 10;
-		/*efuse, register read write default value */
-		if (0x11 == x || 0x12 == x || 0x13 == x)
-			z = 0xffffffff;
+			DBGLOG(INIT, TRACE, " x(0x%08x)\n\r", x);
 	}
 
-	DBGLOG(INIT, TRACE, " x(0x%08x), y(0x%08x), z(0x%08x)\n\r", x, y, z);
-#endif
-
-	if (((sizeof(wlan_dev_dbg_func) / sizeof(wlan_dev_dbg_func[0])) > x) && NULL != wlan_dev_dbg_func[x])
+	if ((!i4Ret) &&
+	    ((sizeof(wlan_dev_dbg_func) / sizeof(wlan_dev_dbg_func[0])) > x) &&
+	    (wlan_dev_dbg_func[x] != NULL))
 		(*wlan_dev_dbg_func[x]) ();
 	else
-		DBGLOG(INIT, ERROR, "no handler defined for command id(0x%08x)\n\r", x);
-#endif
+		DBGLOG(INIT, ERROR,
+		       "no handler defined for command id(0x%08x), pToken=%p, i4Ret=%d\n\r",
+		       x, pToken, i4Ret);
 
-	/* len = gCoexBuf1.availSize; */
 	return len;
 }
 #endif
-	static const struct file_operations proc_fops = {
-		.owner = THIS_MODULE,
-		.read = procfile_read,
-		.write = procfile_write,
-	};
+
+static const struct file_operations proc_fops = {
+	.owner = THIS_MODULE,
+	.read = procfile_read,
+	.write = procfile_write,
+};
 #endif
 
 INT_32 procInitFs(VOID)
@@ -972,3 +959,126 @@ INT_32 procCreateFsEntry(P_GLUE_INFO_T prGlueInfo)
 	return 0;
 }
 
+#ifdef FW_CFG_SUPPORT
+#define MAX_CFG_OUTPUT_BUF_LENGTH 1024
+static UINT_8 aucCfgBuf[CMD_FORMAT_V1_LENGTH];
+static UINT_8 aucCfgQueryKey[MAX_CMD_NAME_MAX_LENGTH];
+static UINT_8 aucCfgOutputBuf[MAX_CFG_OUTPUT_BUF_LENGTH];
+
+static ssize_t cfgRead(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
+{
+	WLAN_STATUS rStatus = WLAN_STATUS_FAILURE;
+	UINT_8 *temp = &aucCfgOutputBuf[0];
+	UINT_32 u4CopySize = 0;
+	struct _CMD_HEADER_T cmdV1Header;
+	struct _CMD_FORMAT_V1_T *pr_cmd_v1 = (struct _CMD_FORMAT_V1_T *) cmdV1Header.buffer;
+
+	/* if *f_pos >  0, we should return 0 to make cat command exit */
+	if (*f_pos > 0 || gprGlueInfo == NULL)
+		return 0;
+
+	kalMemSet(aucCfgOutputBuf, 0, MAX_CFG_OUTPUT_BUF_LENGTH);
+
+	SPRINTF(temp, ("\nprocCfgRead() %s:\n", aucCfgQueryKey));
+
+	/* send to FW */
+	cmdV1Header.cmdVersion = CMD_VER_1;
+	cmdV1Header.cmdType = CMD_TYPE_QUERY;
+	cmdV1Header.itemNum = 1;
+	cmdV1Header.cmdBufferLen = sizeof(struct _CMD_FORMAT_V1_T);
+	kalMemSet(cmdV1Header.buffer, 0, MAX_CMD_BUFFER_LENGTH);
+
+	pr_cmd_v1->itemStringLength = kalStrLen(aucCfgQueryKey);
+	kalMemCopy(pr_cmd_v1->itemString, aucCfgQueryKey, kalStrLen(aucCfgQueryKey));
+
+	rStatus = kalIoctl(gprGlueInfo,
+			wlanoidQueryCfgRead,
+			(PVOID)&cmdV1Header,
+			sizeof(cmdV1Header),
+			TRUE,
+			TRUE,
+			TRUE,
+			FALSE,
+			&u4CopySize);
+	if (rStatus == WLAN_STATUS_FAILURE)
+		DBGLOG(INIT, ERROR, "prCmdV1Header kalIoctl wlanoidQueryCfgRead fail 0x%x\n", rStatus);
+
+	SPRINTF(temp, ("%s\n", cmdV1Header.buffer));
+
+	u4CopySize = kalStrLen(aucCfgOutputBuf);
+	if (u4CopySize > count)
+		u4CopySize = count;
+
+	if (copy_to_user(buf, aucCfgOutputBuf, u4CopySize))
+		DBGLOG(INIT, ERROR, "copy to user failed\n");
+
+	*f_pos += u4CopySize;
+	return (ssize_t)u4CopySize;
+}
+
+static ssize_t cfgWrite(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos)
+{
+	/* echo xxx xxx > /proc/net/wlan/cfg */
+	UINT_8 i = 0;
+	UINT_32 u4CopySize = sizeof(aucCfgBuf);
+	UINT_8 token_num = 1;
+
+	kalMemSet(aucCfgBuf, 0, u4CopySize);
+	u4CopySize = (count < u4CopySize) ? count : (u4CopySize - 1);
+
+	if (copy_from_user(aucCfgBuf, buf, u4CopySize)) {
+		DBGLOG(INIT, ERROR, "copy from user failed\n");
+		return -EFAULT;
+	}
+
+	for (; i < u4CopySize; i++) {
+		if (aucCfgBuf[i] == ' ') {
+			token_num++;
+			break;
+		}
+	}
+
+	DBGLOG(INIT, INFO, "procCfgWrite %s\n", aucCfgBuf);
+
+	if (token_num == 1) {
+		kalMemSet(aucCfgQueryKey, 0, sizeof(aucCfgQueryKey));
+		memcpy(aucCfgQueryKey, aucCfgBuf, u4CopySize);
+		if (aucCfgQueryKey[u4CopySize - 1] == 0x0a)
+			aucCfgQueryKey[u4CopySize - 1] = '\0';
+	} else {
+		if (u4CopySize)
+			wlanFwCfgParse(gprGlueInfo->prAdapter, aucCfgBuf);
+	}
+
+	return count;
+}
+
+static const struct file_operations cfg_ops = {
+	.owner = THIS_MODULE,
+	.read = cfgRead,
+	.write = cfgWrite,
+};
+
+INT_32 cfgRemoveProcEntry(void)
+{
+	remove_proc_entry(PROC_CFG_NAME, gprProcRoot);
+	return 0;
+}
+
+INT_32 cfgCreateProcEntry(P_GLUE_INFO_T prGlueInfo)
+{
+	struct proc_dir_entry *prEntry;
+
+	prGlueInfo->pProcRoot = gprProcRoot;
+	gprGlueInfo = prGlueInfo;
+
+	prEntry = proc_create(PROC_CFG_NAME, 0664, gprProcRoot, &cfg_ops);
+	if (prEntry == NULL) {
+		DBGLOG(INIT, ERROR, "Unable to create /proc entry cfg\n\r");
+		return -1;
+	}
+	proc_set_user(prEntry, KUIDT_INIT(PROC_UID_SHELL), KGIDT_INIT(PROC_GID_WIFI));
+
+	return 0;
+}
+#endif

+ 18 - 1
drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_vendor.c

@@ -1,3 +1,16 @@
+/*
+ * Copyright (C) 2016 MediaTek Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See http://www.gnu.org/licenses/gpl-2.0.html for more details.
+ */
+
 /*
 ** Id: @(#) gl_cfg80211.c@@
 */
@@ -242,6 +255,7 @@ int mtk_cfg80211_vendor_set_config(struct wiphy *wiphy, struct wireless_dev *wde
 	struct nlattr *pbucket, *pchannel;
 	UINT_32 len_basic, len_bucket, len_channel;
 	int i, j, k;
+	UINT_32 u4ArySize;
 
 	ASSERT(wiphy);
 	ASSERT(wdev);
@@ -268,7 +282,10 @@ int mtk_cfg80211_vendor_set_config(struct wiphy *wiphy, struct wireless_dev *wde
 				len_basic += NLA_ALIGN(attr[k]->nla_len);
 				break;
 			case GSCAN_ATTRIBUTE_NUM_BUCKETS:
-				prWifiScanCmd->num_buckets = nla_get_u32(attr[k]);
+				u4ArySize = nla_get_u32(attr[k]);
+				prWifiScanCmd->num_buckets =
+					(u4ArySize <= GSCAN_MAX_BUCKETS)
+					? u4ArySize : GSCAN_MAX_BUCKETS;
 				len_basic += NLA_ALIGN(attr[k]->nla_len);
 				DBGLOG(REQ, TRACE, "attr=0x%x, num_buckets=%d nla_len=%d, \r\n",
 				       *(UINT_32 *) attr[k], prWifiScanCmd->num_buckets, attr[k]->nla_len);

+ 4 - 0
drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_os.h

@@ -1253,6 +1253,10 @@ void p2pSetMulticastListWorkQueueWrapper(P_GLUE_INFO_T prGlueInfo);
 
 #endif
 
+#ifdef FW_CFG_SUPPORT
+INT_32 cfgCreateProcEntry(P_GLUE_INFO_T prGlueInfo);
+INT_32 cfgRemoveProcEntry(void);
+#endif
 /*******************************************************************************
 *                              F U N C T I O N S
 ********************************************************************************

+ 1 - 0
drivers/misc/mediatek/eccci/ccci_bm.h

@@ -15,6 +15,7 @@
 #define SKB_4K (CCCI_MTU+128)	/* user MTU+CCCI_H+extra(ex. ccci_fsd's OP_ID), for genral packet */
 #define SKB_1_5K (CCCI_NET_MTU+16)	/* net MTU+CCCI_H, for network packet */
 #define SKB_16 16		/* for struct ccci_header */
+#define NET_RX_BUF SKB_4K
 
 #ifdef NET_SKBUFF_DATA_USES_OFFSET
 #define skb_size(x) ((x)->end)

+ 8 - 0
drivers/misc/mediatek/eccci/ccci_core.h

@@ -685,6 +685,14 @@ typedef enum{
 	MISC_INFO_CCCI,
 	MISC_INFO_CLIB_TIME,
 	MISC_INFO_C2K,
+	MD_IMAGE_START_MEMORY,
+	CCISM_SHARE_MEMORY,
+	CCB_SHARE_MEMORY, /* total size of all CCB regions */
+	DHL_RAW_SHARE_MEMORY,
+	DT_NETD_SHARE_MEMORY,
+	DT_USB_SHARE_MEMORY,
+	EE_AFTER_EPOF,
+	CCMNI_MTU, /* max Rx packet buffer size on AP side */
 	RUNTIME_FEATURE_ID_MAX,
 } MD_CCCI_RUNTIME_FEATURE_ID;
 

+ 6 - 0
drivers/misc/mediatek/eccci/modem_ccif_c2k.c

@@ -939,6 +939,7 @@ static int md_ccif_op_start(struct ccci_modem *md)
 	md->ops->broadcast_state(md, BOOTING);
 	md_ccif_let_md_go(md);
 	enable_irq(md_ctrl->md_wdt_irq_id);
+	md->is_forced_assert = 0;
  out:
 	CCCI_INF_MSG(md->index, TAG, "ccif modem started %d\n", ret);
 	/*used for throttling feature - start */
@@ -1289,6 +1290,10 @@ static int md_ccif_op_force_assert(struct ccci_modem *md, MD_COMM_TYPE type)
 	struct ccci_request *req = NULL;
 	struct ccci_header *ccci_h;
 
+	if (md->is_forced_assert == 1) {
+		CCCI_ERR_MSG(md->index, TAG, "MD has been forced assert, no need again using %d\n", type);
+		return 0;
+	}
 	CCCI_INF_MSG(md->index, TAG, "force assert MD using %d\n", type);
 	switch (type) {
 	case CCCI_MESSAGE:
@@ -1314,6 +1319,7 @@ static int md_ccif_op_force_assert(struct ccci_modem *md, MD_COMM_TYPE type)
 		md_ccif_send(md, AP_MD_SEQ_ERROR);
 		break;
 	};
+	md->is_forced_assert = 1;
 	return 0;
 
 }

+ 107 - 38
drivers/misc/mediatek/eccci/modem_cldma.c

@@ -62,7 +62,7 @@ static int md_cd_ccif_send(struct ccci_modem *md, int channel_id);
  * we use this as rgpd->data_allow_len, so skb length must be >= this size, check ccci_bm.c's skb pool design.
  * channel 3 is for network in normal mode, but for mdlogger_ctrl in exception mode, so choose the max packet size.
  */
-static int net_rx_queue_buffer_size[CLDMA_RXQ_NUM] = { 0, 0, 0, SKB_1_5K, SKB_1_5K, SKB_1_5K, 0, 0 };
+static int net_rx_queue_buffer_size[CLDMA_RXQ_NUM] = { 0, 0, 0, NET_RX_BUF, NET_RX_BUF, NET_RX_BUF, 0, 0 };
 static int normal_rx_queue_buffer_size[CLDMA_RXQ_NUM] = { SKB_4K, SKB_4K, SKB_4K, SKB_4K, 0, 0, SKB_4K, SKB_16 };
 
 #if 0				/* for debug log dump convenience */
@@ -1146,6 +1146,31 @@ static void cldma_tx_queue_init(struct md_cd_queue *queue)
 #endif
 }
 
+void cldma_enable_irq(struct md_cd_ctrl *md_ctrl)
+{
+	if (atomic_read(&md_ctrl->cldma_irq_enabled) == 0) {
+		enable_irq(md_ctrl->cldma_irq_id);
+		atomic_inc(&md_ctrl->cldma_irq_enabled);
+	}
+}
+
+void cldma_disable_irq(struct md_cd_ctrl *md_ctrl)
+{
+	if (atomic_read(&md_ctrl->cldma_irq_enabled) == 1) {
+		disable_irq(md_ctrl->cldma_irq_id);
+		atomic_dec(&md_ctrl->cldma_irq_enabled);
+	}
+}
+
+void cldma_disable_irq_nosync(struct md_cd_ctrl *md_ctrl)
+{
+	if (atomic_read(&md_ctrl->cldma_irq_enabled) == 1) {
+		/*may be called in isr, so use disable_irq_nosync.
+		   if use disable_irq in isr, system will hang */
+		disable_irq_nosync(md_ctrl->cldma_irq_id);
+		atomic_dec(&md_ctrl->cldma_irq_enabled);
+	}
+}
 static void cldma_irq_work_cb(struct ccci_modem *md)
 {
 	int i, ret;
@@ -1219,8 +1244,12 @@ static void cldma_irq_work_cb(struct ccci_modem *md)
 				/* disable TX_DONE interrupt */
 				cldma_write32(md_ctrl->cldma_ap_pdn_base, CLDMA_AP_L2TIMSR0,
 					      CLDMA_BM_ALL_QUEUE & (1 << i));
-				ret = queue_delayed_work(md_ctrl->txq[i].worker, &md_ctrl->txq[i].cldma_tx_work,
+				if (IS_NET_QUE(md, i))
+					ret = queue_delayed_work(md_ctrl->txq[i].worker, &md_ctrl->txq[i].cldma_tx_work,
 							 msecs_to_jiffies(10));
+				else
+					ret = queue_delayed_work(md_ctrl->txq[i].worker, &md_ctrl->txq[i].cldma_tx_work,
+							 msecs_to_jiffies(0));
 				CCCI_DBG_MSG(md->index, TAG, "qno%d queue_delayed_work=%d\n", i, ret);
 			}
 		}
@@ -1260,7 +1289,7 @@ static void cldma_irq_work_cb(struct ccci_modem *md)
 	}
 	md_cd_lock_cldma_clock_src(0);
 #ifndef ENABLE_CLDMA_AP_SIDE
-	enable_irq(md_ctrl->cldma_irq_id);
+	cldma_enable_irq(md_ctrl);
 #endif
 }
 
@@ -1275,7 +1304,7 @@ static irqreturn_t cldma_isr(int irq, void *data)
 #ifdef ENABLE_CLDMA_AP_SIDE
 	cldma_irq_work_cb(md);
 #else
-	disable_irq_nosync(md_ctrl->cldma_irq_id);
+	cldma_disable_irq_nosync(md_ctrl)
 	queue_work(md_ctrl->cldma_irq_worker, &md_ctrl->cldma_irq_work);
 #endif
 	return IRQ_HANDLED;
@@ -1374,7 +1403,7 @@ static inline void cldma_stop(struct ccci_modem *md)
 #endif
 	spin_unlock_irqrestore(&md_ctrl->cldma_timeout_lock, flags);
 	/* flush work */
-	disable_irq(md_ctrl->cldma_irq_id);
+	cldma_disable_irq(md_ctrl);
 	flush_work(&md_ctrl->cldma_irq_work);
 	for (i = 0; i < QUEUE_LEN(md_ctrl->txq); i++)
 		flush_delayed_work(&md_ctrl->txq[i].cldma_tx_work);
@@ -1511,7 +1540,7 @@ static inline void cldma_start(struct ccci_modem *md)
 	unsigned long flags;
 
 	CCCI_INF_MSG(md->index, TAG, "%s from %ps\n", __func__, __builtin_return_address(0));
-	enable_irq(md_ctrl->cldma_irq_id);
+	cldma_enable_irq(md_ctrl);
 	spin_lock_irqsave(&md_ctrl->cldma_timeout_lock, flags);
 	/* set start address */
 	for (i = 0; i < QUEUE_LEN(md_ctrl->txq); i++) {
@@ -1807,6 +1836,13 @@ static void md_cd_wdt_work(struct work_struct *work)
 			CCCI_INF_MSG(md->index, TAG, "mdlogger closed,reset MD after WDT %d\n", ret);
 			/* 4. send message, only reset MD on non-eng load */
 			ccci_send_virtual_md_msg(md, CCCI_MONITOR_CH, CCCI_MD_MSG_RESET, 0);
+#ifdef CONFIG_MTK_ECCCI_C2K
+			exec_ccci_kern_func_by_md_id(MD_SYS3, ID_RESET_MD, NULL, 0);
+#else
+#ifdef CONFIG_MTK_SVLTE_SUPPORT
+			c2k_reset_modem();
+#endif
+#endif
 		} else {
 			md_cd_dump_debug_register(md);
 			ccci_md_exception_notify(md, MD_WDT);
@@ -1820,6 +1856,11 @@ static irqreturn_t md_cd_wdt_isr(int irq, void *data)
 	struct ccci_modem *md = (struct ccci_modem *)data;
 	struct md_cd_ctrl *md_ctrl = (struct md_cd_ctrl *)md->private_data;
 
+	if (md->boot_stage == MD_BOOT_STAGE_0 && md->md_state != EXCEPTION && md->md_state != BOOT_FAIL) {
+		CCCI_ERR_MSG(md->index, TAG, "Ignore MD WDT IRQ which cann't be handled.\n");
+		return IRQ_HANDLED;
+	}
+
 	CCCI_ERR_MSG(md->index, TAG, "MD WDT IRQ\n");
 	ccif_disable_irq(md);
 #ifndef DISABLE_MD_WDT_PROCESS
@@ -1884,11 +1925,10 @@ static void md_cd_ccif_delayed_work(struct ccci_modem *md)
 	struct md_cd_ctrl *md_ctrl = (struct md_cd_ctrl *)md->private_data;
 	int i;
 
-#if defined (CONFIG_MTK_AEE_FEATURE)
+#if defined(CONFIG_MTK_AEE_FEATURE)
 	aee_kernel_dal_show("Modem exception dump start, please wait up to 5 minutes.\n");
 #endif
-
- 	/* stop CLDMA, we don't want to get CLDMA IRQ when MD is reseting CLDMA after it got cleaq_ack */
+	/* stop CLDMA, we don't want to get CLDMA IRQ when MD is resetting CLDMA after it got cleaq_ack */
 	cldma_stop(md);
 	for (i = 0; i < QUEUE_LEN(md_ctrl->txq); i++)
 		flush_delayed_work(&md_ctrl->txq[i].cldma_tx_work);
@@ -1906,6 +1946,7 @@ static void md_cd_exception(struct ccci_modem *md, HIF_EX_STAGE stage)
 	volatile unsigned int SO_CFG;
 
 	CCCI_ERR_MSG(md->index, TAG, "MD exception HIF %d\n", stage);
+	wake_lock_timeout(&md_ctrl->trm_wake_lock, 50 * HZ);
 	/* in exception mode, MD won't sleep, so we do not need to request MD resource first */
 	switch (stage) {
 	case HIF_EX_INIT:
@@ -1916,7 +1957,6 @@ static void md_cd_exception(struct ccci_modem *md, HIF_EX_STAGE stage)
 			CCCI_ERR_MSG(md->index, KERN, "MD found wrong sequence number\n");
 			md->ops->dump_info(md, DUMP_FLAG_CLDMA, NULL, -1);
 		}
-		wake_lock_timeout(&md_ctrl->trm_wake_lock, 10 * HZ);
 		ccci_md_exception_notify(md, EX_INIT);
 		/* disable CLDMA except un-stop queues */
 		cldma_stop_for_ee(md);
@@ -1954,15 +1994,22 @@ static void md_cd_exception(struct ccci_modem *md, HIF_EX_STAGE stage)
 	};
 }
 
-static void polling_ready(struct md_cd_ctrl *md_ctrl, int step)
+static void polling_ready(struct ccci_modem *md, int step)
 {
-	int cnt = 100;
-	while (cnt--)
-	{
-		if (md_ctrl->channel_id & (1 << step))
-			break;
-		msleep(20);
+	int cnt = 500; /*MD timeout is 10s*/
+	int time_once = 20;
+	struct md_cd_ctrl *md_ctrl = (struct md_cd_ctrl *)md->private_data;
+
+	while (cnt > 0)	{
+		md_ctrl->channel_id = cldma_read32(md_ctrl->ap_ccif_base, APCCIF_RCHNUM);
+		if (md_ctrl->channel_id & (1 << step)) {
+			cldma_write32(md_ctrl->ap_ccif_base, APCCIF_ACK, (1 << step));
+			return;
+		}
+		msleep(time_once);
+		cnt--;
 	}
+	CCCI_ERR_MSG(md->index, TAG, "poll EE HS timeout, RCHNUM %d\n", md_ctrl->channel_id);
 }
 static void md_cd_ccif_work(struct work_struct *work)
 {
@@ -1970,25 +2017,29 @@ static void md_cd_ccif_work(struct work_struct *work)
 	struct ccci_modem *md = md_ctrl->modem;
 
 	mutex_lock(&md_ctrl->ccif_wdt_mutex);
-	if (!wdt_executed)
-	{
-		polling_ready(md_ctrl, D2H_EXCEPTION_INIT);
+	if (!wdt_executed) {
+		wake_lock_timeout(&md_ctrl->trm_wake_lock, 20 * HZ);/* Avoid sleep at polling */
+		/* polling_ready(md, D2H_EXCEPTION_INIT); */
 		md_cd_exception(md, HIF_EX_INIT);
-		polling_ready(md_ctrl, D2H_EXCEPTION_INIT_DONE);
+
+		wake_lock_timeout(&md_ctrl->trm_wake_lock, 20 * HZ);/* Avoid sleep at polling */
+		polling_ready(md, D2H_EXCEPTION_INIT_DONE);
 		md_cd_exception(md, HIF_EX_INIT_DONE);
 
-		polling_ready(md_ctrl, D2H_EXCEPTION_CLEARQ_DONE);
+		wake_lock_timeout(&md_ctrl->trm_wake_lock, 20 * HZ);/* Avoid sleep at polling */
+		polling_ready(md, D2H_EXCEPTION_CLEARQ_DONE);
 		md_cd_exception(md, HIF_EX_CLEARQ_DONE);
 
-		polling_ready(md_ctrl, D2H_EXCEPTION_ALLQ_RESET);
+		wake_lock_timeout(&md_ctrl->trm_wake_lock, 20 * HZ);/* Avoid sleep at polling */
+		polling_ready(md, D2H_EXCEPTION_ALLQ_RESET);
 		md_cd_exception(md, HIF_EX_ALLQ_RESET);
 
-	    if(md_ctrl->channel_id & (1<<AP_MD_PEER_WAKEUP))
-	        wake_lock_timeout(&md_ctrl->peer_wake_lock, HZ);
-	    if(md_ctrl->channel_id & (1<<AP_MD_SEQ_ERROR)) {
-	        CCCI_ERR_MSG(md->index, TAG, "MD check seq fail\n");
-	        md->ops->dump_info(md, DUMP_FLAG_CCIF, NULL, 0);
-	    }
+		if (md_ctrl->channel_id & (1<<AP_MD_PEER_WAKEUP))
+			wake_lock_timeout(&md_ctrl->peer_wake_lock, HZ);
+		if (md_ctrl->channel_id & (1<<AP_MD_SEQ_ERROR)) {
+			CCCI_ERR_MSG(md->index, TAG, "MD check seq fail\n");
+			md->ops->dump_info(md, DUMP_FLAG_CCIF, NULL, 0);
+		}
 	}
 	mutex_unlock(&md_ctrl->ccif_wdt_mutex);
 }
@@ -2033,7 +2084,7 @@ static inline int cldma_sw_init(struct ccci_modem *md)
 			     ret);
 		return ret;
 	}
-	disable_irq(md_ctrl->hw_info->cldma_irq_id);
+	cldma_disable_irq(md_ctrl);
 #ifndef FEATURE_FPGA_PORTING
 	ret =
 	    request_irq(md_ctrl->hw_info->md_wdt_irq_id, md_cd_wdt_isr, md_ctrl->hw_info->md_wdt_irq_flags, "MD_WDT",
@@ -2042,8 +2093,7 @@ static inline int cldma_sw_init(struct ccci_modem *md)
 		CCCI_ERR_MSG(md->index, TAG, "request MD_WDT IRQ(%d) error %d\n", md_ctrl->hw_info->md_wdt_irq_id, ret);
 		return ret;
 	}
-	atomic_inc(&md_ctrl->wdt_enabled);
-		/* IRQ is enabled after requested, so call enable_irq after request_irq will get a unbalance warning */
+	/* IRQ is enabled after requested, so call enable_irq after request_irq will get a unbalance warning */
 	ret =
 	    request_irq(md_ctrl->hw_info->ap_ccif_irq_id, md_cd_ccif_isr, md_ctrl->hw_info->ap_ccif_irq_flags,
 			"CCIF0_AP", md);
@@ -2052,7 +2102,6 @@ static inline int cldma_sw_init(struct ccci_modem *md)
 			     ret);
 		return ret;
 	}
-	atomic_inc(&md_ctrl->ccif_irq_enabled);
 #endif
 	return 0;
 }
@@ -2282,6 +2331,7 @@ static int md_cd_start(struct ccci_modem *md)
 	md->ops->broadcast_state(md, BOOTING);
 	md->boot_stage = MD_BOOT_STAGE_0;
 	md->ex_stage = EX_NONE;
+	md->is_forced_assert = 0;
 	cldma_start(md);
 
  out:
@@ -2410,6 +2460,8 @@ static int md_cd_stop(struct ccci_modem *md, unsigned int timeout)
 	struct md_cd_ctrl *md_ctrl = (struct md_cd_ctrl *)md->private_data;
 	u32 pending;
 	int en_power_check;
+	int i;
+	unsigned int rx_ch_bitmap;
 
 	CCCI_INF_MSG(md->index, TAG, "CLDMA modem is power off, timeout=%d\n", timeout);
 	md->sim_type = 0xEEEEEEEE;	/* reset sim_type(MCC/MNC) to 0xEEEEEEEE */
@@ -2483,7 +2535,17 @@ static int md_cd_stop(struct ccci_modem *md, unsigned int timeout)
 #endif
 
 	/* ACK CCIF for MD. while entering flight mode, we may send something after MD slept */
-	cldma_write32(md_ctrl->md_ccif_base, APCCIF_ACK, cldma_read32(md_ctrl->md_ccif_base, APCCIF_RCHNUM));
+	rx_ch_bitmap = cldma_read32(md_ctrl->md_ccif_base, APCCIF_RCHNUM);
+	if (rx_ch_bitmap) {
+		CCCI_INF_MSG(md->index, TAG, "CCIF rx bitmap: 0x%x\n", rx_ch_bitmap);
+		for (i = 0; i < 16; i++) {
+			/* Ack one by one */
+			if (rx_ch_bitmap & (1<<i))
+				cldma_write32(md_ctrl->md_ccif_base, APCCIF_ACK, (1<<i));
+		}
+		rx_ch_bitmap = cldma_read32(md_ctrl->md_ccif_base, APCCIF_RCHNUM);
+		CCCI_INF_MSG(md->index, TAG, "CCIF rx bitmap: 0x%x(after ack)\n", rx_ch_bitmap);
+	}
 
 	md_cd_check_emi_state(md, 0);	/* Check EMI after */
 	return 0;
@@ -3214,6 +3276,10 @@ static int md_cd_force_assert(struct ccci_modem *md, MD_COMM_TYPE type)
 	struct ccci_request *req = NULL;
 	struct ccci_header *ccci_h;
 
+	if (md->is_forced_assert == 1) {
+		CCCI_ERR_MSG(md->index, TAG, "MD has been forced assert, no need again using %d\n", type);
+		return 0;
+	}
 	CCCI_INF_MSG(md->index, TAG, "force assert MD using %d\n", type);
 	switch (type) {
 	case CCCI_MESSAGE:
@@ -3236,6 +3302,7 @@ static int md_cd_force_assert(struct ccci_modem *md, MD_COMM_TYPE type)
 		md_cd_ccif_send(md, AP_MD_SEQ_ERROR);
 		break;
 	};
+	md->is_forced_assert = 1;
 	return 0;
 }
 
@@ -3452,8 +3519,8 @@ static ssize_t md_cd_control_store(struct ccci_modem *md, const char *buf, size_
 	}
 	if (strncmp(buf, "ccci_trm", count - 1) == 0) {
 		CCCI_INF_MSG(md->index, TAG, "TRM triggered\n");
-		md->ops->reset(md);
-		ccci_send_virtual_md_msg(md, CCCI_MONITOR_CH, CCCI_MD_MSG_RESET, 0);
+		if (md->ops->reset(md) == 0)
+			ccci_send_virtual_md_msg(md, CCCI_MONITOR_CH, CCCI_MD_MSG_RESET, 0);
 	}
 	size = strlen("md_type=");
 	if (strncmp(buf, "md_type=", size) == 0) {
@@ -3716,8 +3783,10 @@ static int ccci_modem_probe(struct platform_device *plat_dev)
 	INIT_WORK(&md_ctrl->cldma_irq_work, cldma_irq_work);
 	md_ctrl->channel_id = 0;
 	atomic_set(&md_ctrl->reset_on_going, 0);
-	atomic_set(&md_ctrl->wdt_enabled, 0);
-	atomic_set(&md_ctrl->ccif_irq_enabled, 0);
+	/* IRQ is default enabled after request_irq, so set init 1 */
+	atomic_set(&md_ctrl->wdt_enabled, 1);
+	atomic_set(&md_ctrl->cldma_irq_enabled, 1);
+	atomic_set(&md_ctrl->ccif_irq_enabled, 1);
 	INIT_WORK(&md_ctrl->wdt_work, md_cd_wdt_work);
 #if TRAFFIC_MONITOR_INTERVAL
 	init_timer(&md_ctrl->traffic_monitor);

+ 2 - 1
drivers/misc/mediatek/eccci/modem_cldma.h

@@ -166,6 +166,7 @@ struct md_cd_ctrl {
 	struct mutex ccif_wdt_mutex;
 	atomic_t reset_on_going;
 	atomic_t wdt_enabled;
+	atomic_t cldma_irq_enabled;
 	atomic_t ccif_irq_enabled;
 	char trm_wakelock_name[32];
 	struct wake_lock trm_wake_lock;
@@ -331,7 +332,7 @@ extern unsigned long ccci_modem_boot_count[];
 extern int gf_port_list_reg[GF_PORT_LIST_MAX];
 extern int gf_port_list_unreg[GF_PORT_LIST_MAX];
 extern int ccci_ipc_set_garbage_filter(struct ccci_modem *md, int reg);
-
+extern bool spm_is_md1_sleep(void);
 #ifdef TEST_MESSAGE_FOR_BRINGUP
 extern int ccci_sysmsg_echo_test(int, int);
 extern int ccci_sysmsg_echo_test_l1core(int, int);

+ 10 - 1
drivers/misc/mediatek/eccci/mt6735/cldma_platform.c

@@ -330,6 +330,7 @@ int md_cd_let_md_go(struct ccci_modem *md)
 int md_cd_power_off(struct ccci_modem *md, unsigned int timeout)
 {
 	int ret = 0;
+	int count = 50;
 	unsigned int reg_value;
 #if defined(FEATURE_RF_CLK_BUF)
 	struct pinctrl_state *RFIC0_04_mode;
@@ -342,7 +343,15 @@ int md_cd_power_off(struct ccci_modem *md, unsigned int timeout)
 	/* notify NFC */
 	inform_nfc_vsim_change(md->index, 0, 0);
 #endif
-
+	while (spm_is_md1_sleep() == 0) {
+		msleep(20);
+		count--;
+		if (count == 0) {
+			CCCI_INF_MSG(md->index, TAG, "%s:poll md sleep timeout: %d",
+				__func__, spm_is_md1_sleep());
+			break;
+		}
+	}
 #ifdef FEATURE_RF_CLK_BUF
 	mutex_lock(&clk_buf_ctrl_lock);
 #endif

+ 46 - 6
drivers/misc/mediatek/eccci/port_kernel.c

@@ -1,3 +1,16 @@
+/*
+*Copyright(C)2017 MediaTek Inc.
+*
+*This program is free software;you can redistribute it and/or modify it under
+*the terms of the GNU General Public License version 2 as published by the
+*Free Software Foundation.
+*
+*This program is distributed in the hope that it will be useful,but WITHOUT
+*ANY WARRANTY;without even the implied warranty of MERCHANTABILITY or FITNESS
+*FOR A PARTICULAR PURPOSE.
+*See http://www.gnu.org/licenses/gpl-2.0.html for more details.
+*/
+
 #include <linux/device.h>
 #include <linux/wait.h>
 #include <linux/module.h>
@@ -132,10 +145,10 @@ static inline void append_runtime_feature(char **p_rt_data, struct ccci_runtime_
 {
 	CCCI_DBG_MSG(-1, KERN, "append rt_data %p, feature %u len %u\n",
 		     *p_rt_data, rt_feature->feature_id, rt_feature->data_len);
-	memcpy(*p_rt_data, rt_feature, sizeof(struct ccci_runtime_feature));
+	memcpy_toio(*p_rt_data, rt_feature, sizeof(struct ccci_runtime_feature));
 	*p_rt_data += sizeof(struct ccci_runtime_feature);
 	if (data != NULL) {
-		memcpy(*p_rt_data, data, rt_feature->data_len);
+		memcpy_toio(*p_rt_data, data, rt_feature->data_len);
 		*p_rt_data += rt_feature->data_len;
 	}
 }
@@ -226,6 +239,7 @@ static void config_ap_side_feature(struct ccci_modem *md, struct md_query_ap_fea
 #else
 	ap_side_md_feature->feature_set[MISC_INFO_C2K].support_mask = CCCI_FEATURE_NOT_SUPPORT;
 #endif
+	ap_side_md_feature->feature_set[CCMNI_MTU].support_mask = CCCI_FEATURE_MUST_SUPPORT;
 }
 
 static int prepare_runtime_data(struct ccci_modem *md, struct ccci_request *req)
@@ -1189,13 +1203,22 @@ static void ccci_rpc_work_helper(struct ccci_modem *md, struct rpc_pkt *pkt,
 				CCCI_ERR_MSG(md->index, RPC, "invalid ContentAdddr[0x%p] for RPC_SECURE_ALGO_OP!\n",
 					     (void *)ContentAddr);
 				tmp_data[0] = FS_PARAM_ERROR;
+				pkt_num = 0;
 				pkt[pkt_num].len = sizeof(unsigned int);
 				pkt[pkt_num++].buf = (void *)&tmp_data[0];
 				break;
 			}
 			ContentLen = *(unsigned int *)pkt[2].buf;
 			/* CustomSeed = *(sed_t*)pkt[3].buf; */
-			WARN_ON(sizeof(CustomSeed.sed) < pkt[3].len);
+			if (sizeof(CustomSeed.sed) < pkt[3].len) {
+				CCCI_ERR_MSG(md->index, RPC, "invalid pkt_len %d for RPC_SECURE_ALGO_OP!\n",
+					    pkt[3].len);
+				tmp_data[0] = FS_PARAM_ERROR;
+				pkt_num = 0;
+				pkt[pkt_num].len = sizeof(unsigned int);
+				pkt[pkt_num++].buf = (void *)&tmp_data[0];
+				break;
+			}
 			memcpy(CustomSeed.sed, pkt[3].buf, pkt[3].len);
 
 #ifdef ENCRYPT_DEBUG
@@ -1232,6 +1255,7 @@ static void ccci_rpc_work_helper(struct ccci_modem *md, struct rpc_pkt *pkt,
 			if (ResText == NULL) {
 				CCCI_ERR_MSG(md->index, RPC, "Fail alloc Mem for RPC_SECURE_ALGO_OP!\n");
 				tmp_data[0] = FS_PARAM_ERROR;
+				pkt_num = 0;
 				pkt[pkt_num].len = sizeof(unsigned int);
 				pkt[pkt_num++].buf = (void *)&tmp_data[0];
 				break;
@@ -1839,7 +1863,7 @@ static void rpc_msg_handler(struct ccci_port *port, struct ccci_request *req)
 {
 	struct ccci_modem *md = port->modem;
 	struct rpc_buffer *rpc_buf = (struct rpc_buffer *)req->skb->data;
-	int i, data_len = 0, AlignLength, ret;
+	int i, data_len, AlignLength, ret;
 	struct rpc_pkt pkt[RPC_MAX_ARG_NUM];
 	char *ptr, *ptr_base;
 	/* unsigned int tmp_data[128]; */	/* size of tmp_data should be >= any RPC output result */
@@ -1850,6 +1874,10 @@ static void rpc_msg_handler(struct ccci_port *port, struct ccci_request *req)
 		goto err_out;
 	}
 	/* sanity check */
+	if (req->skb->len > RPC_MAX_BUF_SIZE) {
+		CCCI_ERR_MSG(md->index, RPC, "invalid RPC buffer size 0x%x/0x%x\n", req->skb->len, RPC_MAX_BUF_SIZE);
+		goto err_out;
+	}
 	if (rpc_buf->header.reserved < 0 || rpc_buf->header.reserved > RPC_REQ_BUFFER_NUM ||
 	    rpc_buf->para_num < 0 || rpc_buf->para_num > RPC_MAX_ARG_NUM) {
 		CCCI_ERR_MSG(md->index, RPC, "invalid RPC index %d/%d\n", rpc_buf->header.reserved, rpc_buf->para_num);
@@ -1857,11 +1885,23 @@ static void rpc_msg_handler(struct ccci_port *port, struct ccci_request *req)
 	}
 	/* parse buffer */
 	ptr_base = ptr = rpc_buf->buffer;
+	data_len = sizeof(rpc_buf->op_id) + sizeof(rpc_buf->para_num);
 	for (i = 0; i < rpc_buf->para_num; i++) {
 		pkt[i].len = *((unsigned int *)ptr);
+		if (pkt[i].len >= req->skb->len) {
+			CCCI_ERR_MSG(md->index, RPC, "invalid packet length in parse %u\n", pkt[i].len);
+			goto err_out;
+		}
+		if ((data_len + sizeof(pkt[i].len) + pkt[i].len) > RPC_MAX_BUF_SIZE) {
+			CCCI_ERR_MSG(md->index, RPC, "RPC buffer overflow in parse %zu\n",
+					data_len + sizeof(pkt[i].len) + pkt[i].len);
+			goto err_out;
+		}
 		ptr += sizeof(pkt[i].len);
 		pkt[i].buf = ptr;
-		ptr += ((pkt[i].len + 3) >> 2) << 2;	/* 4byte align */
+		AlignLength = ((pkt[i].len + 3) >> 2) << 2;
+		ptr += AlignLength;	/* 4byte align */
+		data_len += (sizeof(pkt[i].len) + AlignLength);
 	}
 	if ((ptr - ptr_base) > RPC_MAX_BUF_SIZE) {
 		CCCI_ERR_MSG(md->index, RPC, "RPC overflow in parse 0x%p\n", (void *)(ptr - ptr_base));
@@ -1872,7 +1912,7 @@ static void rpc_msg_handler(struct ccci_port *port, struct ccci_request *req)
 	/* write back to modem */
 	/* update message */
 	rpc_buf->op_id |= RPC_API_RESP_ID;
-	data_len += (sizeof(rpc_buf->op_id) + sizeof(rpc_buf->para_num));
+	data_len = (sizeof(rpc_buf->op_id) + sizeof(rpc_buf->para_num));
 	ptr = rpc_buf->buffer;
 	for (i = 0; i < rpc_buf->para_num; i++) {
 		if ((data_len + sizeof(pkt[i].len) + pkt[i].len) > RPC_MAX_BUF_SIZE) {

+ 32 - 5
drivers/misc/mediatek/fmradio/core/fm_main.c

@@ -1,3 +1,16 @@
+/*
+ * Copyright (C) 2015 MediaTek Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
 #include <linux/kernel.h>
 #include <asm/uaccess.h>
 #include <linux/slab.h>
@@ -146,7 +159,7 @@ fm_s32 fm_set_stat(struct fm *fmp, int which, bool stat)
 	if (FM_LOCK(fm_ops_lock))
 		return -FM_ELOCK;
 
-	if (which < (sizeof(g_fm_stat) / sizeof(g_fm_stat[0]))) {
+	if (which >= 0 && which < (sizeof(g_fm_stat) / sizeof(g_fm_stat[0]))) {
 		g_fm_stat[which] = stat;
 		WCN_DBG(FM_DBG | MAIN, "fm set stat object=%d, stat=%d\n", which, stat);
 	} else {
@@ -173,7 +186,7 @@ fm_s32 fm_get_stat(struct fm *fmp, int which, bool *stat)
 	if (FM_LOCK(fm_ops_lock))
 		return -FM_ELOCK;
 
-	if (which < (sizeof(g_fm_stat) / sizeof(g_fm_stat[0]))) {
+	if (which >= 0 && which < (sizeof(g_fm_stat) / sizeof(g_fm_stat[0]))) {
 		*stat = g_fm_stat[which];
 		WCN_DBG(FM_DBG | MAIN, "fm get stat object=%d, stat=%d\n", which, *stat);
 	} else {
@@ -1982,6 +1995,8 @@ fm_s32 fm_tune_tx(struct fm *fm, struct fm_tune_parm *parm)
 fm_s32 fm_tune(struct fm *fm, struct fm_tune_parm *parm)
 {
 	fm_s32 ret = 0;
+	fm_s32 len;
+	struct rds_raw_t rds_log;
 
 	if (fm_low_ops.bi.mute == NULL) {
 		pr_err("%s,invalid pointer\n", __func__);
@@ -2001,6 +2016,20 @@ fm_s32 fm_tune(struct fm *fm, struct fm_tune_parm *parm)
 
 	WCN_DBG(FM_DBG | MAIN, "%s\n", __func__);
 
+	/* clean RDS first in case RDS event report before tune success */
+	/* clean RDS data */
+	fm_memset(fm->pstRDSData, 0, sizeof(rds_t));
+
+	/* clean RDS log buffer */
+	do {
+		ret = fm_rds_log_get(fm, (struct rds_rx_t *)&(rds_log.data), &len);
+		rds_log.dirty = TRUE;
+		rds_log.len = (len < sizeof(rds_log.data)) ? len : sizeof(rds_log.data);
+		WCN_DBG(FM_ALT | MAIN, "clean rds log, rds_log.len =%d\n", rds_log.len);
+		if (ret < 0)
+			break;
+	} while (rds_log.len > 0);
+
 	if (fm_pwr_state_get(fm) != FM_PWR_RX_ON) {
 		parm->err = FM_BADSTATUS;
 		ret = -EPERM;
@@ -2013,8 +2042,6 @@ fm_s32 fm_tune(struct fm *fm, struct fm_tune_parm *parm)
 		goto out;
 	}
 
-	if (fm_cur_freq_get() != parm->freq)
-		fm_memset(fm->pstRDSData, 0, sizeof(rds_t));
 
 #if 0				/* (!defined(MT6620_FM)&&!defined(MT6628_FM)) */
 	/* HILO side adjust if need */
@@ -2659,7 +2686,7 @@ static fm_s32 fm_rds_parser(struct rds_rx_t *rds_raw, fm_s32 rds_size)
 	FM_UNLOCK(fm_read_lock);
 
 	if ((pstRDSData->event_status != 0x0000) && (pstRDSData->event_status != RDS_EVENT_AF_LIST)) {
-		WCN_DBG(FM_NTC | MAIN, "Notify user to read, [event:%04x]\n", pstRDSData->event_status);
+		WCN_DBG(FM_NTC | MAIN, "Notify user to read, [event:0x%04x]\n", pstRDSData->event_status);
 		FM_EVENT_SEND(fm->rds_event, FM_RDS_DATA_READY);
 	}
 

+ 2 - 0
drivers/misc/mediatek/include/mt-plat/mt6735/include/mach/mt_thermal.h

@@ -299,6 +299,8 @@ struct TS_PTPOD {
 
 extern int mtktscpu_limited_dmips;
 
+extern int tscpu_is_temp_valid(void); /* Valid if it returns 1, invalid if it returns 0*/
+
 extern void get_thermal_slope_intercept(struct TS_PTPOD *ts_info, thermal_bank_name ts_bank);
 extern void set_taklking_flag(bool flag);
 extern int tscpu_get_cpu_temp(void);

+ 65 - 2
drivers/misc/mediatek/thermal/common/thermal_zones/mtk_ts_cpu.c

@@ -1,3 +1,16 @@
+/*
+ * Copyright (C) 2015 MediaTek Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
 #define DEBUG 1
 #include <linux/version.h>
 #include <linux/kernel.h>
@@ -192,6 +205,9 @@ void tscpu_met_unlock(unsigned long *flags)
 EXPORT_SYMBOL(tscpu_met_unlock);
 
 #endif
+static int g_is_temp_valid;
+static void temp_valid_lock(unsigned long *flags);
+static void temp_valid_unlock(unsigned long *flags);
 /*=============================================================
  *Weak functions
  *=============================================================*/
@@ -287,6 +303,9 @@ static void tscpu_fast_initial_sw_workaround(void)
 
 	mt_ptp_unlock(&flags);
 
+	temp_valid_lock(&flags);
+	g_is_temp_valid = 0;
+	temp_valid_unlock(&flags);
 }
 
 void tscpu_thermal_tempADCPNP(int adc, int order)
@@ -787,7 +806,7 @@ static ssize_t tscpu_write_GPIO_out(struct file *file, const char __user *buffer
 
 	desc[len] = '\0';
 
-	if (sscanf(desc, "%s %d %s %d ", TEMP, &valTEMP, ENABLE, &valENABLE) == 4) {
+	if (sscanf(desc, "%9s %d %9s %d ", TEMP, &valTEMP, ENABLE, &valENABLE) == 4) {
 		/* tscpu_printk("XXXXXXXXX\n"); */
 
 		if (!strcmp(TEMP, "TEMP")) {
@@ -1075,7 +1094,7 @@ static ssize_t tscpu_write(struct file *file, const char __user *buffer, size_t
 
 	if (sscanf
 	    (ptr_mtktscpu_data->desc,
-	     "%d %d %d %s %d %d %s %d %d %s %d %d %s %d %d %s %d %d %s %d %d %s %d %d %s %d %d %s %d %d %s %d",
+	     "%d %d %d %19s %d %d %19s %d %d %19s %d %d %19s %d %d %19s %d %d %19s %d %d %19s %d %d %19s %d %d %19s %d %d %19s %d",
 	     &num_trip,
 	     &ptr_mtktscpu_data->trip[0], &ptr_mtktscpu_data->t_type[0], ptr_mtktscpu_data->bind0,
 	     &ptr_mtktscpu_data->trip[1], &ptr_mtktscpu_data->t_type[1], ptr_mtktscpu_data->bind1,
@@ -1955,6 +1974,49 @@ static void tscpu_thermal_release(void)
 }
 #endif
 #endif
+
+static DEFINE_SPINLOCK(temp_valid_spinlock);
+static void temp_valid_lock(unsigned long *flags)
+{
+	spin_lock_irqsave(&temp_valid_spinlock, *flags);
+}
+
+static void temp_valid_unlock(unsigned long *flags)
+{
+	spin_unlock_irqrestore(&temp_valid_spinlock, *flags);
+}
+
+static void check_all_temp_valid(void)
+{
+	int i, j, raw;
+
+	for (i = 0; i < ARRAY_SIZE(tscpu_g_bank); i++) {
+		for (j = 0; j < tscpu_g_bank[i].ts_number; j++) {
+			raw = tscpu_bank_ts_r[i][tscpu_g_bank[i].ts[j].type];
+
+			if (raw == THERMAL_INIT_VALUE)
+				return;	/* The temperature is not valid. */
+		}
+	}
+
+	g_is_temp_valid = 1;
+}
+
+int tscpu_is_temp_valid(void)
+{
+	int is_valid = 0;
+	unsigned long flags;
+
+	temp_valid_lock(&flags);
+	if (g_is_temp_valid == 0)
+		check_all_temp_valid();
+
+	is_valid = g_is_temp_valid;
+	temp_valid_unlock(&flags);
+
+	return is_valid;
+}
+
 static void read_all_bank_temperature(void)
 {
 	int i = 0;
@@ -1971,6 +2033,7 @@ static void read_all_bank_temperature(void)
 
 
 	mt_ptp_unlock(&flags);
+	tscpu_is_temp_valid();
 }
 
 void tscpu_update_tempinfo(void)

+ 2 - 0
drivers/misc/mediatek/thermal/mt6735/inc/D1/tscpu_settings.h

@@ -48,6 +48,7 @@ they means one reading is a avg of X samples */
 
 /* 1: thermal driver update temp to MET directly, use hrtimer; 0: turn off */
 #define THERMAL_DRV_UPDATE_TEMP_DIRECT_TO_MET  (1)
+#define THERMAL_INIT_VALUE (0xDA1)
 /*=============================================================
  * Chip related
  *=============================================================*/
@@ -191,6 +192,7 @@ struct mtk_cpu_power_info {
 extern int tscpu_debug_log;
 extern const struct of_device_id mt_thermal_of_match[2];
 extern int tscpu_bank_ts[THERMAL_BANK_NUM][ENUM_MAX];
+extern int tscpu_bank_ts_r[THERMAL_BANK_NUM][ENUM_MAX]; /* raw data */
 extern bank_t tscpu_g_bank[THERMAL_BANK_NUM];
 extern int tscpu_polling_trip_temp1;
 extern int tscpu_polling_trip_temp2;

+ 2 - 0
drivers/misc/mediatek/thermal/mt6735/inc/D2/tscpu_settings.h

@@ -48,6 +48,7 @@ they means one reading is a avg of X samples */
 
 /* 1: thermal driver update temp to MET directly, use hrtimer; 0: turn off */
 #define THERMAL_DRV_UPDATE_TEMP_DIRECT_TO_MET  (1)
+#define THERMAL_INIT_VALUE (0xDA1)
 /*=============================================================
  * Chip related
  *=============================================================*/
@@ -192,6 +193,7 @@ struct mtk_cpu_power_info {
 extern int tscpu_debug_log;
 extern const struct of_device_id mt_thermal_of_match[2];
 extern int tscpu_bank_ts[THERMAL_BANK_NUM][ENUM_MAX];
+extern int tscpu_bank_ts_r[THERMAL_BANK_NUM][ENUM_MAX]; /* raw data */
 extern bank_t tscpu_g_bank[THERMAL_BANK_NUM];
 extern int tscpu_polling_trip_temp1;
 extern int tscpu_polling_trip_temp2;

+ 2 - 0
drivers/misc/mediatek/thermal/mt6735/inc/D3/tscpu_settings.h

@@ -48,6 +48,7 @@ they means one reading is a avg of X samples */
 
 /* 1: thermal driver update temp to MET directly, use hrtimer; 0: turn off */
 #define THERMAL_DRV_UPDATE_TEMP_DIRECT_TO_MET  (1)
+#define THERMAL_INIT_VALUE (0xDA1)
 /*=============================================================
  * Chip related
  *=============================================================*/
@@ -201,6 +202,7 @@ struct mtk_cpu_power_info {
 extern int tscpu_debug_log;
 extern const struct of_device_id mt_thermal_of_match[2];
 extern int tscpu_bank_ts[THERMAL_BANK_NUM][ENUM_MAX];
+extern int tscpu_bank_ts_r[THERMAL_BANK_NUM][ENUM_MAX]; /* raw data */
 extern bank_t tscpu_g_bank[THERMAL_BANK_NUM];
 extern int tscpu_polling_trip_temp1;
 extern int tscpu_polling_trip_temp2;

+ 6 - 6
drivers/misc/mediatek/thermal/mt6735/src/mtk_tc_D1.c

@@ -58,7 +58,7 @@ Bank2 : LTE     (TS_MCU3)
 */
 
 int tscpu_bank_ts[THERMAL_BANK_NUM][ENUM_MAX];
-static int tscpu_bank_ts_r[THERMAL_BANK_NUM][ENUM_MAX];
+int tscpu_bank_ts_r[THERMAL_BANK_NUM][ENUM_MAX];
 
 /* chip dependent */
 bank_t tscpu_g_bank[THERMAL_BANK_NUM] = {
@@ -897,7 +897,7 @@ int tscpu_thermal_fast_init(void)
 	/* tscpu_printk( "tscpu_thermal_fast_init\n"); */
 
 
-	temp = 0xDA1;
+	temp = THERMAL_INIT_VALUE;
 	DRV_WriteReg32(PTPSPARE2, (0x00001000 + temp));	/* write temp to spare register */
 
 	DRV_WriteReg32(TEMPMONCTL1, 1);	/* counting unit is 320 * 31.25us = 10ms */
@@ -944,7 +944,7 @@ int tscpu_thermal_fast_init(void)
 
 	cunt = 0;
 	temp = DRV_Reg32(TEMPMSR0) & 0x0fff;
-	while (temp != 0xDA1 && cunt < 20) {
+	while (temp != THERMAL_INIT_VALUE && cunt < 20) {
 		cunt++;
 		/* pr_debug("[Power/CPU_Thermal]0 temp=%d,cunt=%d\n",temp,cunt); */
 		temp = DRV_Reg32(TEMPMSR0) & 0x0fff;
@@ -952,7 +952,7 @@ int tscpu_thermal_fast_init(void)
 
 	cunt = 0;
 	temp = DRV_Reg32(TEMPMSR1) & 0x0fff;
-	while (temp != 0xDA1 && cunt < 20) {
+	while (temp != THERMAL_INIT_VALUE && cunt < 20) {
 		cunt++;
 		/* pr_debug("[Power/CPU_Thermal]1 temp=%d,cunt=%d\n",temp,cunt); */
 		temp = DRV_Reg32(TEMPMSR1) & 0x0fff;
@@ -960,7 +960,7 @@ int tscpu_thermal_fast_init(void)
 
 	cunt = 0;
 	temp = DRV_Reg32(TEMPMSR2) & 0x0fff;
-	while (temp != 0xDA1 && cunt < 20) {
+	while (temp != THERMAL_INIT_VALUE && cunt < 20) {
 		cunt++;
 		/* pr_debug("[Power/CPU_Thermal]2 temp=%d,cunt=%d\n",temp,cunt); */
 		temp = DRV_Reg32(TEMPMSR2) & 0x0fff;
@@ -968,7 +968,7 @@ int tscpu_thermal_fast_init(void)
 
 	cunt = 0;
 	temp = DRV_Reg32(TEMPMSR3) & 0x0fff;
-	while (temp != 0xDA1 && cunt < 20) {
+	while (temp != THERMAL_INIT_VALUE && cunt < 20) {
 		cunt++;
 		/* pr_debug("[Power/CPU_Thermal]3 temp=%d,cunt=%d\n",temp,cunt); */
 		temp = DRV_Reg32(TEMPMSR3) & 0x0fff;

+ 6 - 6
drivers/misc/mediatek/thermal/mt6735/src/mtk_tc_D2.c

@@ -58,7 +58,7 @@ Bank2 : LTE     (TS_MCU2)
 */
 
 int tscpu_bank_ts[THERMAL_BANK_NUM][ENUM_MAX];
-static int tscpu_bank_ts_r[THERMAL_BANK_NUM][ENUM_MAX];
+int tscpu_bank_ts_r[THERMAL_BANK_NUM][ENUM_MAX];
 
 /* chip dependent */
 bank_t tscpu_g_bank[THERMAL_BANK_NUM] = {
@@ -894,7 +894,7 @@ int tscpu_thermal_fast_init(void)
 	/* tscpu_printk( "tscpu_thermal_fast_init\n"); */
 
 
-	temp = 0xDA1;
+	temp = THERMAL_INIT_VALUE;
 	DRV_WriteReg32(PTPSPARE2, (0x00001000 + temp));	/* write temp to spare register */
 
 	DRV_WriteReg32(TEMPMONCTL1, 1);	/* counting unit is 320 * 31.25us = 10ms */
@@ -939,7 +939,7 @@ int tscpu_thermal_fast_init(void)
 
 	cunt = 0;
 	temp = DRV_Reg32(TEMPMSR0) & 0x0fff;
-	while (temp != 0xDA1 && cunt < 20) {
+	while (temp != THERMAL_INIT_VALUE && cunt < 20) {
 		cunt++;
 		/* pr_debug("[Power/CPU_Thermal]0 temp=%d,cunt=%d\n",temp,cunt); */
 		temp = DRV_Reg32(TEMPMSR0) & 0x0fff;
@@ -947,7 +947,7 @@ int tscpu_thermal_fast_init(void)
 
 	cunt = 0;
 	temp = DRV_Reg32(TEMPMSR1) & 0x0fff;
-	while (temp != 0xDA1 && cunt < 20) {
+	while (temp != THERMAL_INIT_VALUE && cunt < 20) {
 		cunt++;
 		/* pr_debug("[Power/CPU_Thermal]1 temp=%d,cunt=%d\n",temp,cunt); */
 		temp = DRV_Reg32(TEMPMSR1) & 0x0fff;
@@ -955,7 +955,7 @@ int tscpu_thermal_fast_init(void)
 
 	cunt = 0;
 	temp = DRV_Reg32(TEMPMSR2) & 0x0fff;
-	while (temp != 0xDA1 && cunt < 20) {
+	while (temp != THERMAL_INIT_VALUE && cunt < 20) {
 		cunt++;
 		/* pr_debug("[Power/CPU_Thermal]2 temp=%d,cunt=%d\n",temp,cunt); */
 		temp = DRV_Reg32(TEMPMSR2) & 0x0fff;
@@ -963,7 +963,7 @@ int tscpu_thermal_fast_init(void)
 
 	cunt = 0;
 	temp = DRV_Reg32(TEMPMSR3) & 0x0fff;
-	while (temp != 0xDA1 && cunt < 20) {
+	while (temp != THERMAL_INIT_VALUE && cunt < 20) {
 		cunt++;
 		/* pr_debug("[Power/CPU_Thermal]3 temp=%d,cunt=%d\n",temp,cunt); */
 		temp = DRV_Reg32(TEMPMSR3) & 0x0fff;

+ 6 - 6
drivers/misc/mediatek/thermal/mt6735/src/mtk_tc_D3.c

@@ -59,7 +59,7 @@ TS_ABB => TS_MCU3
 */
 
 int tscpu_bank_ts[THERMAL_BANK_NUM][ENUM_MAX];
-static int tscpu_bank_ts_r[THERMAL_BANK_NUM][ENUM_MAX];
+int tscpu_bank_ts_r[THERMAL_BANK_NUM][ENUM_MAX];
 
 /* chip dependent */
 bank_t tscpu_g_bank[THERMAL_BANK_NUM] = {
@@ -897,7 +897,7 @@ int tscpu_thermal_fast_init(void)
 	/* tscpu_printk( "tscpu_thermal_fast_init\n"); */
 
 
-	temp = 0xDA1;
+	temp = THERMAL_INIT_VALUE;
 	DRV_WriteReg32(PTPSPARE2, (0x00001000 + temp));	/* write temp to spare register */
 
 	DRV_WriteReg32(TEMPMONCTL1, 1);	/* counting unit is 320 * 31.25us = 10ms */
@@ -944,7 +944,7 @@ int tscpu_thermal_fast_init(void)
 
 	cunt = 0;
 	temp = DRV_Reg32(TEMPMSR0) & 0x0fff;
-	while (temp != 0xDA1 && cunt < 20) {
+	while (temp != THERMAL_INIT_VALUE && cunt < 20) {
 		cunt++;
 		/* pr_debug("[Power/CPU_Thermal]0 temp=%d,cunt=%d\n",temp,cunt); */
 		temp = DRV_Reg32(TEMPMSR0) & 0x0fff;
@@ -952,7 +952,7 @@ int tscpu_thermal_fast_init(void)
 
 	cunt = 0;
 	temp = DRV_Reg32(TEMPMSR1) & 0x0fff;
-	while (temp != 0xDA1 && cunt < 20) {
+	while (temp != THERMAL_INIT_VALUE && cunt < 20) {
 		cunt++;
 		/* pr_debug("[Power/CPU_Thermal]1 temp=%d,cunt=%d\n",temp,cunt); */
 		temp = DRV_Reg32(TEMPMSR1) & 0x0fff;
@@ -960,7 +960,7 @@ int tscpu_thermal_fast_init(void)
 
 	cunt = 0;
 	temp = DRV_Reg32(TEMPMSR2) & 0x0fff;
-	while (temp != 0xDA1 && cunt < 20) {
+	while (temp != THERMAL_INIT_VALUE && cunt < 20) {
 		cunt++;
 		/* pr_debug("[Power/CPU_Thermal]2 temp=%d,cunt=%d\n",temp,cunt); */
 		temp = DRV_Reg32(TEMPMSR2) & 0x0fff;
@@ -968,7 +968,7 @@ int tscpu_thermal_fast_init(void)
 
 	cunt = 0;
 	temp = DRV_Reg32(TEMPMSR3) & 0x0fff;
-	while (temp != 0xDA1 && cunt < 20) {
+	while (temp != THERMAL_INIT_VALUE && cunt < 20) {
 		cunt++;
 		/* pr_debug("[Power/CPU_Thermal]3 temp=%d,cunt=%d\n",temp,cunt); */
 		temp = DRV_Reg32(TEMPMSR3) & 0x0fff;

+ 37 - 9
drivers/mmc/host/mediatek/emmc_rpmb.c

@@ -1,3 +1,15 @@
+/*
+ * Copyright (C) 2015 MediaTek Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
 
 #include <linux/kernel.h>
 #include <linux/module.h>
@@ -79,7 +91,8 @@ do {\
 } while (0)
 
 #if (defined(CONFIG_MICROTRUST_TZ_DRIVER))
-#define RPMB_DATA_BUFF_SIZE (1024 * 33)
+#define RPMB_DATA_BUFF_SIZE (1024 * 24)
+#define RPMB_ONE_FRAME_SIZE (512)
 static unsigned char *rpmb_buffer;
 #endif
 
@@ -1451,6 +1464,7 @@ static long emmc_rpmb_ioctl(struct file *file, unsigned int cmd, unsigned long a
 	struct rpmb_ioc_param param;
 	int ret;
 #if (defined(CONFIG_MICROTRUST_TZ_DRIVER))
+	u32 rpmb_size = 0;
 	struct rpmb_infor rpmbinfor;
 
 	memset(&rpmbinfor, 0, sizeof(struct rpmb_infor));
@@ -1466,27 +1480,41 @@ static long emmc_rpmb_ioctl(struct file *file, unsigned int cmd, unsigned long a
 
 #if (defined(CONFIG_MICROTRUST_TZ_DRIVER))
 	if ((cmd == RPMB_IOCTL_SOTER_WRITE_DATA) || (cmd == RPMB_IOCTL_SOTER_READ_DATA)) {
-		err = copy_from_user(rpmb_buffer, (void *)arg, 4);
+		if (rpmb_buffer == NULL) {
+			MSG(ERR, "%s, rpmb_buffer is NULL!\n", __func__);
+			return -1;
+		}
+		err = copy_from_user(&rpmb_size, (void *)arg, 4);
 		if (err < 0) {
 			MSG(ERR, "%s, err=%x\n", __func__, err);
 			return -1;
 		}
-		rpmbinfor.size =  *(unsigned char *)rpmb_buffer | (*((unsigned char *)rpmb_buffer + 1) << 8);
-		rpmbinfor.size |= (*((unsigned char *)rpmb_buffer+2) << 16) | (*((unsigned char *)rpmb_buffer+3) << 24);
-		MSG(INFO, "%s, rpmbinfor.size is %d!\n", __func__, rpmbinfor.size);
-		err = copy_from_user(rpmb_buffer, (void *)arg, 4 + rpmbinfor.size);
-		rpmbinfor.data_frame = (rpmb_buffer + 4);
+		rpmbinfor.size =  *(unsigned char *)&rpmb_size | (*((unsigned char *)&rpmb_size + 1) << 8);
+		rpmbinfor.size |= (*((unsigned char *)&rpmb_size+2) << 16) | (*((unsigned char *)&rpmb_size+3) << 24);
+		if (rpmbinfor.size <= (RPMB_DATA_BUFF_SIZE-4)) {
+			MSG(INFO, "%s, rpmbinfor.size is %d!\n", __func__, rpmbinfor.size);
+			err = copy_from_user(rpmb_buffer, (void *)arg, 4 + rpmbinfor.size);
+			if (err < 0) {
+				MSG(ERR, "%s, err=%x\n", __func__, err);
+				return -1;
+			}
+			rpmbinfor.data_frame = (rpmb_buffer + 4);
+		} else {
+			MSG(ERR, "%s, rpmbinfor.size(%d+4) is overflow (%d)!\n",
+					__func__, rpmbinfor.size, RPMB_DATA_BUFF_SIZE);
+			return -1;
+		}
 
 		if (cmd == RPMB_IOCTL_SOTER_WRITE_DATA) {
 			ret = neu_rpmb_req_write_data(card,
-				(struct s_rpmb *)(rpmbinfor.data_frame), rpmbinfor.size/1024);
+				(struct s_rpmb *)(rpmbinfor.data_frame), rpmbinfor.size/RPMB_ONE_FRAME_SIZE);
 			if (ret)
 				MSG(ERR, "%s, emmc_rpmb_req_handle IO error!!!(%x)\n", __func__, ret);
 			err = copy_to_user((void *)arg, rpmb_buffer, 4 + rpmbinfor.size);
 
 		} else if (cmd == RPMB_IOCTL_SOTER_READ_DATA) {
 			ret = neu_rpmb_req_read_data(card,
-				(struct s_rpmb *)(rpmbinfor.data_frame), rpmbinfor.size/1024);
+				(struct s_rpmb *)(rpmbinfor.data_frame), rpmbinfor.size/RPMB_ONE_FRAME_SIZE);
 			if (ret)
 				MSG(ERR, "%s, emmc_rpmb_req_handle IO error!!!(%x)\n", __func__, ret);
 			err = copy_to_user((void *)arg, rpmb_buffer, 4 + rpmbinfor.size);

+ 30 - 5
drivers/power/mediatek/battery_common.c

@@ -4401,6 +4401,7 @@ static void battery_timer_resume(void)
 	kal_bool is_pcm_timer_trigger = KAL_FALSE;
 	struct timespec bat_time_after_sleep;
 	ktime_t ktime, hvtime;
+	kal_bool ext_gauge_IC_update_SOC = KAL_FALSE;
 
 #ifdef CONFIG_MTK_POWER_EXT_DETECT
 	if (KAL_TRUE == bat_is_ext_power())
@@ -4421,11 +4422,35 @@ static void battery_timer_resume(void)
 		battery_log(BAT_LOG_CRTI, "battery resume NOT by pcm timer!!\n");
 	}
 
-	if (g_call_state == CALL_ACTIVE &&
-		(bat_time_after_sleep.tv_sec - g_bat_time_before_sleep.tv_sec >= batt_cust_data.talking_sync_time)) {
-		/* phone call last than x min */
-		BMT_status.UI_SOC = battery_meter_get_battery_percentage();
-		battery_log(BAT_LOG_CRTI, "Sync UI SOC to SOC immediately\n");
+//modified by xmwwy, update UI_SOC when system has gauge IC
+#if defined(SOC_BY_EXT_HW_FG)
+#if defined(CONFIG_MALATA_HARDWARE_VERSION)
+	if (MATCH_BQ27520_HARDWARE_VERSION == hardware_version)
+	{
+		ext_gauge_IC_update_SOC = KAL_TRUE;
+	}else{
+		ext_gauge_IC_update_SOC = KAL_FALSE;
+		battery_log(BAT_LOG_CRTI, "---flag ext_gauge_IC_update_SOC is false!---\n");
+	}
+#else
+	ext_gauge_IC_update_SOC = KAL_FALSE;
+#endif
+#else
+	ext_gauge_IC_update_SOC = KAL_FALSE;
+#endif
+	battery_log(BAT_LOG_CRTI, "flag ext_gauge_IC_update_SOC=%d\n",(int)ext_gauge_IC_update_SOC);
+	if(ext_gauge_IC_update_SOC){
+		if(bat_time_after_sleep.tv_sec - g_bat_time_before_sleep.tv_sec >= 20) {
+			BMT_status.UI_SOC = battery_meter_get_battery_percentage();
+			battery_log(BAT_LOG_CRTI, "ext_gauge_IC_update_SOC, Sync UI SOC to SOC immediately\n");
+		}
+	}else{
+		if (g_call_state == CALL_ACTIVE &&
+			(bat_time_after_sleep.tv_sec - g_bat_time_before_sleep.tv_sec >= batt_cust_data.talking_sync_time)) {
+			/* phone call last than x min */
+			BMT_status.UI_SOC = battery_meter_get_battery_percentage();
+			battery_log(BAT_LOG_CRTI, "Sync UI SOC to SOC immediately\n");
+		}
 	}
 
 	mutex_lock(&bat_mutex);

+ 6 - 3
drivers/usb/core/config.c

@@ -641,18 +641,21 @@ void usb_destroy_configuration(struct usb_device *dev)
 		return;
 
 	if (dev->rawdescriptors) {
-		for (i = 0; i < dev->descriptor.bNumConfigurations; i++)
+		for (i = 0; i < dev->descriptor.bNumConfigurations &&
+				i < USB_MAXCONFIG; i++)
 			kfree(dev->rawdescriptors[i]);
 
 		kfree(dev->rawdescriptors);
 		dev->rawdescriptors = NULL;
 	}
 
-	for (c = 0; c < dev->descriptor.bNumConfigurations; c++) {
+	for (c = 0; c < dev->descriptor.bNumConfigurations &&
+			c < USB_MAXCONFIG; c++) {
 		struct usb_host_config *cf = &dev->config[c];
 
 		kfree(cf->string);
-		for (i = 0; i < cf->desc.bNumInterfaces; i++) {
+		for (i = 0; i < cf->desc.bNumInterfaces &&
+				i < USB_MAXINTERFACES; i++) {
 			if (cf->intf_cache[i])
 				kref_put(&cf->intf_cache[i]->ref,
 					  usb_release_interface_cache);

+ 20 - 4
drivers/usb/gadget/f_hid.c

@@ -195,6 +195,13 @@ static ssize_t f_hidg_read(struct file *file, char __user *buffer,
 	/* pick the first one */
 	list = list_first_entry(&hidg->completed_out_req,
 				struct f_hidg_req_list, list);
+
+	/*
+	 * Remove this from list to protect it from beign free()
+	 * while host disables our function
+	 */
+	list_del(&list->list);
+
 	req = list->req;
 	count = min_t(unsigned int, count, req->actual - list->pos);
 	spin_unlock_irqrestore(&hidg->spinlock, flags);
@@ -210,16 +217,21 @@ static ssize_t f_hidg_read(struct file *file, char __user *buffer,
 	 * call, taking into account its current read position.
 	 */
 	if (list->pos == req->actual) {
-		spin_lock_irqsave(&hidg->spinlock, flags);
-		list_del(&list->list);
 		kfree(list);
-		spin_unlock_irqrestore(&hidg->spinlock, flags);
 
 		req->length = hidg->report_length;
 		ret = usb_ep_queue(hidg->out_ep, req, GFP_KERNEL);
-		if (ret < 0)
+		if (ret < 0) {
+			free_ep_req(hidg->out_ep, req);
 			return ret;
 	}
+	} else {
+		spin_lock_irqsave(&hidg->spinlock, flags);
+		list_add(&list->list, &hidg->completed_out_req);
+		spin_unlock_irqrestore(&hidg->spinlock, flags);
+
+		wake_up(&hidg->read_queue);
+	}
 
 	return count;
 }
@@ -463,6 +475,7 @@ static void hidg_disable(struct usb_function *f)
 {
 	struct f_hidg *hidg = func_to_hidg(f);
 	struct f_hidg_req_list *list, *next;
+	unsigned long flags;
 
 	usb_ep_disable(hidg->in_ep);
 	hidg->in_ep->driver_data = NULL;
@@ -470,10 +483,13 @@ static void hidg_disable(struct usb_function *f)
 	usb_ep_disable(hidg->out_ep);
 	hidg->out_ep->driver_data = NULL;
 
+	spin_lock_irqsave(&hidg->spinlock, flags);
 	list_for_each_entry_safe(list, next, &hidg->completed_out_req, list) {
+		free_ep_req(hidg->out_ep, list->req);
 		list_del(&list->list);
 		kfree(list);
 	}
+	spin_unlock_irqrestore(&hidg->spinlock, flags);
 }
 
 static int hidg_set_alt(struct usb_function *f, unsigned intf, unsigned alt)

+ 8 - 0
include/crypto/internal/hash.h

@@ -83,6 +83,14 @@ int ahash_register_instance(struct crypto_template *tmpl,
 			    struct ahash_instance *inst);
 void ahash_free_instance(struct crypto_instance *inst);
 
+int shash_no_setkey(struct crypto_shash *tfm, const u8 *key,
+		    unsigned int keylen);
+
+static inline bool crypto_shash_alg_has_setkey(struct shash_alg *alg)
+{
+	return alg->setkey != shash_no_setkey;
+}
+
 int crypto_init_ahash_spawn(struct crypto_ahash_spawn *spawn,
 			    struct hash_alg_common *alg,
 			    struct crypto_instance *inst);

+ 94 - 7
kernel/futex.c

@@ -400,6 +400,7 @@ get_futex_key(u32 __user *uaddr, int fshared, union futex_key *key, int rw)
 	unsigned long address = (unsigned long)uaddr;
 	struct mm_struct *mm = current->mm;
 	struct page *page, *page_head;
+	struct address_space *mapping;
 	int err, ro = 0;
 
 	/*
@@ -478,7 +479,19 @@ again:
 	}
 #endif
 
-	lock_page(page_head);
+	/*
+	 * The treatment of mapping from this point on is critical. The page
+	 * lock protects many things but in this context the page lock
+	 * stabilizes mapping, prevents inode freeing in the shared
+	 * file-backed region case and guards against movement to swap cache.
+	 *
+	 * Strictly speaking the page lock is not needed in all cases being
+	 * considered here and page lock forces unnecessarily serialization
+	 * From this point on, mapping will be re-verified if necessary and
+	 * page lock will be acquired only if it is unavoidable
+	 */
+
+	mapping = READ_ONCE(page_head->mapping);
 
 	/*
 	 * If page_head->mapping is NULL, then it cannot be a PageAnon
@@ -495,18 +508,31 @@ again:
 	 * shmem_writepage move it from filecache to swapcache beneath us:
 	 * an unlikely race, but we do need to retry for page_head->mapping.
 	 */
-	if (!page_head->mapping) {
-		int shmem_swizzled = PageSwapCache(page_head);
+	if (unlikely(!mapping)) {
+		int shmem_swizzled;
+
+		/*
+		 * Page lock is required to identify which special case above
+		 * applies. If this is really a shmem page then the page lock
+		 * will prevent unexpected transitions.
+		 */
+		lock_page(page);
+		shmem_swizzled = PageSwapCache(page) || page->mapping;
 		unlock_page(page_head);
 		put_page(page_head);
+
 		if (shmem_swizzled)
 			goto again;
+
 		return -EFAULT;
 	}
 
 	/*
 	 * Private mappings are handled in a simple way.
 	 *
+	 * If the futex key is stored on an anonymous page, then the associated
+	 * object is the mm which is implicitly pinned by the calling process.
+	 *
 	 * NOTE: When userspace waits on a MAP_SHARED mapping, even if
 	 * it's a read-only handle, it's expected that futexes attach to
 	 * the object not the particular process.
@@ -524,16 +550,74 @@ again:
 		key->both.offset |= FUT_OFF_MMSHARED; /* ref taken on mm */
 		key->private.mm = mm;
 		key->private.address = address;
+
+		get_futex_key_refs(key); /* implies smp_mb(); (B) */
+
 	} else {
+		struct inode *inode;
+
+		/*
+		 * The associated futex object in this case is the inode and
+		 * the page->mapping must be traversed. Ordinarily this should
+		 * be stabilised under page lock but it's not strictly
+		 * necessary in this case as we just want to pin the inode, not
+		 * update the radix tree or anything like that.
+		 *
+		 * The RCU read lock is taken as the inode is finally freed
+		 * under RCU. If the mapping still matches expectations then the
+		 * mapping->host can be safely accessed as being a valid inode.
+		 */
+		rcu_read_lock();
+
+		if (READ_ONCE(page_head->mapping) != mapping) {
+			rcu_read_unlock();
+			put_page(page_head);
+
+			goto again;
+		}
+
+		inode = READ_ONCE(mapping->host);
+		if (!inode) {
+			rcu_read_unlock();
+			put_page(page_head);
+
+			goto again;
+		}
+
+		/*
+		 * Take a reference unless it is about to be freed. Previously
+		 * this reference was taken by ihold under the page lock
+		 * pinning the inode in place so i_lock was unnecessary. The
+		 * only way for this check to fail is if the inode was
+		 * truncated in parallel so warn for now if this happens.
+		 *
+		 * We are not calling into get_futex_key_refs() in file-backed
+		 * cases, therefore a successful atomic_inc return below will
+		 * guarantee that get_futex_key() will still imply smp_mb(); (B).
+		 */
+		if (WARN_ON_ONCE(!atomic_inc_not_zero(&inode->i_count))) {
+			rcu_read_unlock();
+			put_page(page_head);
+
+			goto again;
+		}
+
+		/* Should be impossible but lets be paranoid for now */
+		if (WARN_ON_ONCE(inode->i_mapping != mapping)) {
+			err = -EFAULT;
+			rcu_read_unlock();
+			iput(inode);
+
+			goto out;
+		}
+
 		key->both.offset |= FUT_OFF_INODE; /* inode-based key */
-		key->shared.inode = page_head->mapping->host;
+		key->shared.inode = inode;
 		key->shared.pgoff = basepage_index(page);
+		rcu_read_unlock();
 	}
 
-	get_futex_key_refs(key); /* implies MB (B) */
-
 out:
-	unlock_page(page_head);
 	put_page(page_head);
 	return err;
 }
@@ -1504,6 +1588,9 @@ static int futex_requeue(u32 __user *uaddr1, unsigned int flags,
 	struct futex_hash_bucket *hb1, *hb2;
 	struct futex_q *this, *next;
 
+	if (nr_wake < 0 || nr_requeue < 0)
+		return -EINVAL;
+
 	if (requeue_pi) {
 		/*
 		 * Requeue PI only works on two distinct uaddrs. This

+ 27 - 19
lib/asn1_decoder.c

@@ -276,6 +276,9 @@ next_op:
 				if (unlikely(len > datalen - dp))
 					goto data_overrun_error;
 			}
+		} else {
+			if (unlikely(len > datalen - dp))
+				goto data_overrun_error;
 		}
 
 		if (flags & FLAG_CONS) {
@@ -302,38 +305,43 @@ next_op:
 
 	/* Decide how to handle the operation */
 	switch (op) {
-	case ASN1_OP_MATCH_ANY_ACT:
-	case ASN1_OP_COND_MATCH_ANY_ACT:
-		ret = actions[machine[pc + 1]](context, hdr, tag, data + dp, len);
-		if (ret < 0)
-			return ret;
-		goto skip_data;
-
-	case ASN1_OP_MATCH_ACT:
-	case ASN1_OP_MATCH_ACT_OR_SKIP:
-	case ASN1_OP_COND_MATCH_ACT_OR_SKIP:
-		ret = actions[machine[pc + 2]](context, hdr, tag, data + dp, len);
-		if (ret < 0)
-			return ret;
-		goto skip_data;
-
 	case ASN1_OP_MATCH:
 	case ASN1_OP_MATCH_OR_SKIP:
+	case ASN1_OP_MATCH_ACT:
+	case ASN1_OP_MATCH_ACT_OR_SKIP:
 	case ASN1_OP_MATCH_ANY:
+	case ASN1_OP_MATCH_ANY_ACT:
 	case ASN1_OP_COND_MATCH_OR_SKIP:
+	case ASN1_OP_COND_MATCH_ACT_OR_SKIP:
 	case ASN1_OP_COND_MATCH_ANY:
-	skip_data:
+	case ASN1_OP_COND_MATCH_ANY_ACT:
+
 		if (!(flags & FLAG_CONS)) {
 			if (flags & FLAG_INDEFINITE_LENGTH) {
+				size_t tmp = dp;
+
 				ret = asn1_find_indefinite_length(
-					data, datalen, &dp, &len, &errmsg);
+					data, datalen, &tmp, &len, &errmsg);
 				if (ret < 0)
 					goto error;
-			} else {
-				dp += len;
 			}
 			pr_debug("- LEAF: %zu\n", len);
 		}
+
+		if (op & ASN1_OP_MATCH__ACT) {
+			unsigned char act;
+
+			if (op & ASN1_OP_MATCH__ANY)
+				act = machine[pc + 1];
+			else
+				act = machine[pc + 2];
+			ret = actions[act](context, hdr, tag, data + dp, len);
+			if (ret < 0)
+				return ret;
+		}
+
+		if (!(flags & FLAG_CONS))
+			dp += len;
 		pc += asn1_op_lengths[op];
 		goto next_op;
 

+ 5 - 2
net/ipv4/ip_output.c

@@ -888,10 +888,12 @@ static int __ip_append_data(struct sock *sk,
 		csummode = CHECKSUM_PARTIAL;
 
 	cork->length += length;
-	if (((length > mtu) || (skb && skb_is_gso(skb))) &&
+	if ((skb && skb_is_gso(skb)) ||
+	    ((length > mtu) &&
+	    (skb_queue_len(queue) <= 1) &&
 	    (sk->sk_protocol == IPPROTO_UDP) &&
 	    (rt->dst.dev->features & NETIF_F_UFO) && !rt->dst.header_len &&
-	    (sk->sk_type == SOCK_DGRAM)) {
+	    (sk->sk_type == SOCK_DGRAM))) {
 		err = ip_ufo_append_data(sk, queue, getfrag, from, length,
 					 hh_len, fragheaderlen, transhdrlen,
 					 maxfraglen, flags);
@@ -1207,6 +1209,7 @@ ssize_t	ip_append_page(struct sock *sk, struct flowi4 *fl4, struct page *page,
 
 	cork->length += size;
 	if ((size + skb->len > mtu) &&
+	    (skb_queue_len(&sk->sk_write_queue) == 1) &&
 	    (sk->sk_protocol == IPPROTO_UDP) &&
 	    (rt->dst.dev->features & NETIF_F_UFO)) {
 		skb_shinfo(skb)->gso_size = mtu - fragheaderlen;

+ 3 - 0
net/ipv4/raw.c

@@ -345,6 +345,9 @@ static int raw_send_hdrinc(struct sock *sk, struct flowi4 *fl4,
 			       rt->dst.dev->mtu);
 		return -EMSGSIZE;
 	}
+	if (length < sizeof(struct iphdr))
+		return -EINVAL;
+
 	if (flags&MSG_PROBE)
 		goto out;
 

+ 1 - 1
net/ipv4/udp.c

@@ -826,7 +826,7 @@ static int udp_send_skb(struct sk_buff *skb, struct flowi4 *fl4)
 	if (is_udplite)  				 /*     UDP-Lite      */
 		csum = udplite_csum(skb);
 
-	else if (sk->sk_no_check_tx) {   /* UDP csum disabled */
+	else if (sk->sk_no_check_tx && !skb_is_gso(skb)) {   /* UDP csum off */
 
 		skb->ip_summed = CHECKSUM_NONE;
 		goto send;

+ 8 - 5
net/ipv6/ip6_output.c

@@ -1203,14 +1203,16 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to,
 		np->cork.tclass = tclass;
 		if (rt->dst.flags & DST_XFRM_TUNNEL)
 			mtu = np->pmtudisc >= IPV6_PMTUDISC_PROBE ?
-			      rt->dst.dev->mtu : dst_mtu(&rt->dst);
+			      READ_ONCE(rt->dst.dev->mtu) : dst_mtu(&rt->dst);
 		else
 			mtu = np->pmtudisc >= IPV6_PMTUDISC_PROBE ?
-			      rt->dst.dev->mtu : dst_mtu(rt->dst.path);
+			      READ_ONCE(rt->dst.dev->mtu) : dst_mtu(rt->dst.path);
 		if (np->frag_size < mtu) {
 			if (np->frag_size)
 				mtu = np->frag_size;
 		}
+		if (mtu < IPV6_MIN_MTU)
+			return -EINVAL;
 		cork->fragsize = mtu;
 		if (dst_allfrag(rt->dst.path))
 			cork->flags |= IPCORK_ALLFRAG;
@@ -1294,11 +1296,12 @@ emsgsize:
 
 	skb = skb_peek_tail(&sk->sk_write_queue);
 	cork->length += length;
-	if (((length > mtu) ||
-	     (skb && skb_is_gso(skb))) &&
+	if ((skb && skb_is_gso(skb)) ||
+	    (((length + fragheaderlen) > mtu) &&
+	    (skb_queue_len(&sk->sk_write_queue) <= 1) &&
 	    (sk->sk_protocol == IPPROTO_UDP) &&
 	    (rt->dst.dev->features & NETIF_F_UFO) &&
-	    (sk->sk_type == SOCK_DGRAM)) {
+	    (sk->sk_type == SOCK_DGRAM))) {
 		err = ip6_ufo_append_data(sk, getfrag, from, length,
 					  hh_len, fragheaderlen,
 					  transhdrlen, mtu, flags, rt);

+ 2 - 0
net/ipv6/raw.c

@@ -624,6 +624,8 @@ static int rawv6_send_hdrinc(struct sock *sk, void *from, int length,
 		ipv6_local_error(sk, EMSGSIZE, fl6, rt->dst.dev->mtu);
 		return -EMSGSIZE;
 	}
+	if (length < sizeof(struct ipv6hdr))
+		return -EINVAL;
 	if (flags&MSG_PROBE)
 		goto out;
 

+ 37 - 9
security/keys/request_key.c

@@ -250,11 +250,12 @@ static int construct_key(struct key *key, const void *callout_info,
  * The keyring selected is returned with an extra reference upon it which the
  * caller must release.
  */
-static void construct_get_dest_keyring(struct key **_dest_keyring)
+static int construct_get_dest_keyring(struct key **_dest_keyring)
 {
 	struct request_key_auth *rka;
 	const struct cred *cred = current_cred();
 	struct key *dest_keyring = *_dest_keyring, *authkey;
+	int ret;
 
 	kenter("%p", dest_keyring);
 
@@ -263,6 +264,8 @@ static void construct_get_dest_keyring(struct key **_dest_keyring)
 		/* the caller supplied one */
 		key_get(dest_keyring);
 	} else {
+		bool do_perm_check = true;
+
 		/* use a default keyring; falling through the cases until we
 		 * find one that we actually have */
 		switch (cred->jit_keyring) {
@@ -277,8 +280,10 @@ static void construct_get_dest_keyring(struct key **_dest_keyring)
 					dest_keyring =
 						key_get(rka->dest_keyring);
 				up_read(&authkey->sem);
-				if (dest_keyring)
+				if (dest_keyring) {
+					do_perm_check = false;
 					break;
+				}
 			}
 
 		case KEY_REQKEY_DEFL_THREAD_KEYRING:
@@ -313,11 +318,29 @@ static void construct_get_dest_keyring(struct key **_dest_keyring)
 		default:
 			BUG();
 		}
+
+		/*
+		 * Require Write permission on the keyring.  This is essential
+		 * because the default keyring may be the session keyring, and
+		 * joining a keyring only requires Search permission.
+		 *
+		 * However, this check is skipped for the "requestor keyring" so
+		 * that /sbin/request-key can itself use request_key() to add
+		 * keys to the original requestor's destination keyring.
+		 */
+		if (dest_keyring && do_perm_check) {
+			ret = key_permission(make_key_ref(dest_keyring, 1),
+					     KEY_NEED_WRITE);
+			if (ret) {
+				key_put(dest_keyring);
+				return ret;
+			}
+		}
 	}
 
 	*_dest_keyring = dest_keyring;
 	kleave(" [dk %d]", key_serial(dest_keyring));
-	return;
+	return 0;
 }
 
 /*
@@ -439,11 +462,15 @@ static struct key *construct_key_and_link(struct keyring_search_context *ctx,
 
 	kenter("");
 
-	user = key_user_lookup(current_fsuid());
-	if (!user)
-		return ERR_PTR(-ENOMEM);
+	ret = construct_get_dest_keyring(&dest_keyring);
+	if (ret)
+		goto error;
 
-	construct_get_dest_keyring(&dest_keyring);
+	user = key_user_lookup(current_fsuid());
+	if (!user) {
+		ret = -ENOMEM;
+		goto error_put_dest_keyring;
+	}
 
 	ret = construct_alloc_key(ctx, dest_keyring, flags, user, &key);
 	key_user_put(user);
@@ -458,7 +485,7 @@ static struct key *construct_key_and_link(struct keyring_search_context *ctx,
 	} else if (ret == -EINPROGRESS) {
 		ret = 0;
 	} else {
-		goto couldnt_alloc_key;
+		goto error_put_dest_keyring;
 	}
 
 	key_put(dest_keyring);
@@ -468,8 +495,9 @@ static struct key *construct_key_and_link(struct keyring_search_context *ctx,
 construction_failed:
 	key_negate_and_link(key, key_negative_timeout, NULL, NULL);
 	key_put(key);
-couldnt_alloc_key:
+error_put_dest_keyring:
 	key_put(dest_keyring);
+error:
 	kleave(" = %d", ret);
 	return ERR_PTR(ret);
 }