Merge branch 'android-msm-marlin-3.18-nyc-mr1' into android-msm-marlin-3.18-nyc-mr2

April 2017.1

Bug: 35315173
Change-Id: I8fd615cf13ee4766ad12de431dce4f545540a5e5
diff --git a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
index 3d29fce..8b456ce 100644
--- a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
@@ -425,6 +425,8 @@
 					in floating state(not LP00 or LP11) to turn on this property. Software
 					turns off PHY pmic power supply, phy ldo and DSI Lane ldo during
 					idle screen (footswitch control off) when this property is enabled.
+- htc,mdss-dsi-bl-dim-check:		Specifies the dim backlight level supported by the panel.
+					Must be over 0.
 [[Optional config sub-nodes]]		These subnodes provide different configurations for a given same panel.
 					Default configuration can be chosen by specifying phandle of the
 					selected subnode in the qcom,config-select.
diff --git a/arch/arm/boot/dts/qcom/msm8996.dtsi b/arch/arm/boot/dts/qcom/msm8996.dtsi
index 41cc939..ed411ed 100644
--- a/arch/arm/boot/dts/qcom/msm8996.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8996.dtsi
@@ -1875,7 +1875,6 @@
 		interrupts = <0 28 0>, <0 29 0>;
 		qcom,bark-time = <11000>;
 		qcom,pet-time = <10000>;
-		qcom,ipi-ping;
 		qcom,wakeup-enable;
 	};
 
diff --git a/arch/arm64/boot/dts/htc/dsi-panel-s1m1-ea8064tg.dtsi b/arch/arm64/boot/dts/htc/dsi-panel-s1m1-ea8064tg.dtsi
index abe53af..5eceda3 100644
--- a/arch/arm64/boot/dts/htc/dsi-panel-s1m1-ea8064tg.dtsi
+++ b/arch/arm64/boot/dts/htc/dsi-panel-s1m1-ea8064tg.dtsi
@@ -137,5 +137,6 @@
 		qcom,mdss-dsi-lp11-init;
 		qcom,esd-check-enabled;
 		qcom,mdss-dsi-panel-status-check-mode = "te_signal_check";
+		htc,mdss-dsi-bl-dim-check = <30>;
 	};
 };
diff --git a/arch/arm64/boot/dts/htc/dsi-panel-s1m1-s6e3ha3.dtsi b/arch/arm64/boot/dts/htc/dsi-panel-s1m1-s6e3ha3.dtsi
index 27ad914..8edc63b 100644
--- a/arch/arm64/boot/dts/htc/dsi-panel-s1m1-s6e3ha3.dtsi
+++ b/arch/arm64/boot/dts/htc/dsi-panel-s1m1-s6e3ha3.dtsi
@@ -145,5 +145,6 @@
 		qcom,esd-check-enabled;
 		qcom,mdss-dsi-panel-status-check-mode = "te_signal_check";
 		qcom,err-flag-check-enabled;
+		htc,mdss-dsi-bl-dim-check = <30>;
 	};
 };
diff --git a/arch/arm64/boot/dts/htc/msm8996-htc_marlin.dtsi b/arch/arm64/boot/dts/htc/msm8996-htc_marlin.dtsi
index 32a9ccd..c829eff 100644
--- a/arch/arm64/boot/dts/htc/msm8996-htc_marlin.dtsi
+++ b/arch/arm64/boot/dts/htc/msm8996-htc_marlin.dtsi
@@ -242,7 +242,7 @@
         qcom,cold-hot-jeita-hysteresis = <20 30>;
         qcom,fg-cutoff-voltage-mv = <3250>;
         qcom,irq-volt-empty-mv = <3050>;
-        /delete-property/ qcom,capacity-learning-feedback;
+        qcom,capacity-learning-feedback;
 };
 
 /{
diff --git a/arch/arm64/configs/marlin_defconfig b/arch/arm64/configs/marlin_defconfig
index 07612e9..7f08b81 100644
--- a/arch/arm64/configs/marlin_defconfig
+++ b/arch/arm64/configs/marlin_defconfig
@@ -5,6 +5,7 @@
 CONFIG_IRQ_TIME_ACCOUNTING=y
 CONFIG_SCHED_WALT=y
 CONFIG_RCU_FAST_NO_HZ=y
+CONFIG_RCU_BOOST=y
 CONFIG_IKCONFIG=y
 CONFIG_LOG_CPU_MAX_BUF_SHIFT=15
 CONFIG_CGROUPS=y
@@ -272,7 +273,6 @@
 CONFIG_CNSS_CRYPTO=y
 CONFIG_CNSS=y
 CONFIG_CLD_LL_CORE=y
-CONFIG_BUS_AUTO_SUSPEND=y
 CONFIG_HTC_WLAN_NV=y
 CONFIG_WLAN_FEATURE_RX_WAKELOCK=y
 CONFIG_INPUT_EVDEV=y
@@ -511,7 +511,6 @@
 CONFIG_MSM_WATCHDOG_V2=y
 CONFIG_MSM_FORCE_WDOG_BITE_ON_PANIC=y
 CONFIG_MSM_CACHE_M4M_ERP64=y
-# CONFIG_MSM_CACHE_M4M_ERP64_PANIC_ON_CE is not set
 CONFIG_MSM_CACHE_M4M_ERP64_PANIC_ON_UE=y
 CONFIG_MSM_RPM_SMD=y
 CONFIG_MSM_RPM_LOG=y
@@ -554,7 +553,6 @@
 CONFIG_MSM_MDSS_PLL=y
 CONFIG_REMOTE_SPINLOCK_MSM=y
 CONFIG_IOMMU_IO_PGTABLE_FAST=y
-CONFIG_IOMMU_IO_PGTABLE_FAST_SELFTEST=y
 CONFIG_ARM_SMMU=y
 CONFIG_IOMMU_DEBUG=y
 CONFIG_IOMMU_DEBUG_TRACKING=y
@@ -614,6 +612,7 @@
 CONFIG_LSM_MMAP_MIN_ADDR=4096
 CONFIG_SECURITY_SELINUX=y
 # CONFIG_INTEGRITY is not set
+# CONFIG_DEBUG_PREEMPT is not set
 CONFIG_CRYPTO_NULL=y
 CONFIG_CRYPTO_XCBC=y
 CONFIG_CRYPTO_MD4=y
@@ -638,3 +637,7 @@
 CONFIG_CRYPTO_AES_ARM64_CE_BLK=y
 CONFIG_CRYPTO_AES_ARM64_NEON_BLK=y
 CONFIG_QMI_ENCDEC=y
+CONFIG_LOCKUP_DETECTOR=y
+CONFIG_HARD_LOCKUP_DETECTOR_OTHER_CPU=y
+CONFIG_RCU_CPU_STALL_TIMEOUT=3
+CONFIG_SCHED_STACK_END_CHECK=y
diff --git a/arch/arm64/kernel/traps.c b/arch/arm64/kernel/traps.c
index ec0d4b2..7681c42 100644
--- a/arch/arm64/kernel/traps.c
+++ b/arch/arm64/kernel/traps.c
@@ -171,6 +171,14 @@
 	}
 }
 
+static void dump_context_switch_regs(struct task_struct *tsk)
+{
+	unsigned long start = (unsigned long)&tsk->thread.cpu_context;
+	unsigned long end = start + sizeof(tsk->thread.cpu_context);
+	dump_mem(KERN_EMERG, "Context switch saved registers",
+		start, end);
+}
+
 void show_stack(struct task_struct *tsk, unsigned long *sp)
 {
 	dump_backtrace(NULL, tsk);
@@ -209,6 +217,7 @@
 		 TASK_COMM_LEN, tsk->comm, task_pid_nr(tsk), thread + 1);
 
 	if (!user_mode(regs) || in_interrupt()) {
+		dump_context_switch_regs(tsk);
 		dump_backtrace(regs, tsk);
 		dump_instr(KERN_EMERG, regs);
 	}
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index 230ab8d..94c6772 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -1091,11 +1091,13 @@
 	}
 
 	error = dpm_run_callback(callback, dev, state, info);
-	if (!error)
+	if (!error) {
 		dev->power.is_noirq_suspended = true;
-	else
+	} else {
+		log_suspend_abort_reason("Callback failed on %s in %pF returned %d",
+					 dev_name(dev), callback, error);
 		async_error = error;
-
+	}
 Complete:
 	complete_all(&dev->power.completion);
 	return error;
@@ -1232,10 +1234,13 @@
 	}
 
 	error = dpm_run_callback(callback, dev, state, info);
-	if (!error)
+	if (!error) {
 		dev->power.is_late_suspended = true;
-	else
+	} else {
+		log_suspend_abort_reason("Callback failed on %s in %pF returned %d",
+					 dev_name(dev), callback, error);
 		async_error = error;
+	}
 
 Complete:
 	complete_all(&dev->power.completion);
@@ -1378,7 +1383,6 @@
 	int error = 0;
 	struct timer_list timer;
 	struct dpm_drv_wd_data data;
-	char suspend_abort[MAX_SUSPEND_ABORT_LEN];
 	DECLARE_DPM_WATCHDOG_ON_STACK(wd);
 
 	dpm_wait_for_children(dev, async);
@@ -1396,16 +1400,13 @@
 		pm_wakeup_event(dev, 0);
 
 	if (pm_wakeup_pending()) {
-		pm_get_active_wakeup_sources(suspend_abort,
-			MAX_SUSPEND_ABORT_LEN);
-		log_suspend_abort_reason(suspend_abort);
 		async_error = -EBUSY;
 		goto Complete;
 	}
 
 	if (dev->power.syscore)
 		goto Complete;
-	
+
 	data.dev = dev;
 	data.tsk = get_current();
 	init_timer_on_stack(&timer);
@@ -1488,6 +1489,9 @@
 
 			spin_unlock_irq(&parent->power.lock);
 		}
+	} else {
+		log_suspend_abort_reason("Callback failed on %s in %pF returned %d",
+					 dev_name(dev), callback, error);
 	}
 
 	device_unlock(dev);
@@ -1688,6 +1692,9 @@
 			printk(KERN_INFO "PM: Device %s not prepared "
 				"for power transition: code %d\n",
 				dev_name(dev), error);
+			log_suspend_abort_reason("Device %s not prepared "
+						 "for power transition: code %d",
+						 dev_name(dev), error);
 			put_device(dev);
 			break;
 		}
diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c
index 46a6191..aee70e3 100644
--- a/drivers/base/power/wakeup.c
+++ b/drivers/base/power/wakeup.c
@@ -15,6 +15,7 @@
 #include <linux/seq_file.h>
 #include <linux/debugfs.h>
 #include <linux/types.h>
+#include <linux/wakeup_reason.h>
 #include <trace/events/power.h>
 
 #include "power.h"
@@ -767,6 +768,7 @@
 {
 	unsigned long flags;
 	bool ret = false;
+	char suspend_abort[MAX_SUSPEND_ABORT_LEN];
 
 	spin_lock_irqsave(&events_lock, flags);
 	if (events_check_enabled) {
@@ -780,7 +782,11 @@
 
 	if (ret) {
 		pr_info("PM: Wakeup pending, aborting suspend\n");
-		pm_print_active_wakeup_sources();
+		pm_get_active_wakeup_sources(suspend_abort,
+					     MAX_SUSPEND_ABORT_LEN);
+		log_suspend_abort_reason(suspend_abort);
+		pr_info("PM: %s\n", suspend_abort);
+
 	}
 
 	return ret || pm_abort_suspend;
diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c
index f0dda1f..06c0eb7 100644
--- a/drivers/cpuidle/cpuidle.c
+++ b/drivers/cpuidle/cpuidle.c
@@ -542,28 +542,16 @@
 
 #ifdef CONFIG_SMP
 
-static void smp_callback(void *v)
-{
-	/* we already woke the CPU up, nothing more to do */
-}
-
 /*
  * This function gets called when a part of the kernel has a new latency
- * requirement.  This means we need to get only those processors out of their
- * C-state for which qos requirement is changed, and then recalculate a new
- * suitable C-state. Just do a cross-cpu IPI; that wakes them all right up.
+ * requirement.  This means we need to get all processors out of their C-state,
+ * and then recalculate a new suitable C-state. Just do a cross-cpu IPI; that
+ * wakes them all right up.
  */
 static int cpuidle_latency_notify(struct notifier_block *b,
 		unsigned long l, void *v)
 {
-	const struct cpumask *cpus;
-
-	cpus = v ?: cpu_online_mask;
-
-	preempt_disable();
-	smp_call_function_many(cpus, smp_callback, NULL, 1);
-	preempt_enable();
-
+	wake_up_all_idle_cpus();
 	return NOTIFY_OK;
 }
 
diff --git a/drivers/input/touchscreen/synaptics_dsx_htc_2.6/synaptics_dsx_rmi_dev.c b/drivers/input/touchscreen/synaptics_dsx_htc_2.6/synaptics_dsx_rmi_dev.c
index 6878b71..97025b7b 100644
--- a/drivers/input/touchscreen/synaptics_dsx_htc_2.6/synaptics_dsx_rmi_dev.c
+++ b/drivers/input/touchscreen/synaptics_dsx_htc_2.6/synaptics_dsx_rmi_dev.c
@@ -581,7 +581,9 @@
 	}
 	address = (unsigned short)(*f_pos);
 
-	rmidev_allocate_buffer(count);
+	retval = rmidev_allocate_buffer(count);
+	if (retval != 0)
+		goto clean_up;
 
 	retval = synaptics_rmi4_reg_read(rmidev->rmi4_data,
 			*f_pos,
@@ -655,7 +657,9 @@
 		goto unlock;
 	}
 
-	rmidev_allocate_buffer(count);
+	retval = rmidev_allocate_buffer(count);
+	if (retval != 0)
+		goto unlock;
 
 	if (copy_from_user(rmidev->tmpbuf, buf, count)) {
 		retval = -EFAULT;
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index 67f24bb..58b7220 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -131,6 +131,35 @@
 static DEFINE_MUTEX(app_access_lock);
 static DEFINE_MUTEX(clk_access_lock);
 
+struct sglist_info {
+	uint32_t indexAndFlags;
+	uint32_t sizeOrCount;
+};
+
+/*
+ * The 31th bit indicates only one or multiple physical address inside
+ * the request buffer. If it is set,  the index locates a single physical addr
+ * inside the request buffer, and `sizeOrCount` is the size of the memory being
+ * shared at that physical address.
+ * Otherwise, the index locates an array of {start, len} pairs (a
+ * "scatter/gather list"), and `sizeOrCount` gives the number of entries in
+ * that array.
+ *
+ * The 30th bit indicates 64 or 32bit address; when it is set, physical addr
+ * and scatter gather entry sizes are 64-bit values.  Otherwise, 32-bit values.
+ *
+ * The bits [0:29] of `indexAndFlags` hold an offset into the request buffer.
+ */
+#define SGLISTINFO_SET_INDEX_FLAG(c, s, i)	\
+	((uint32_t)(((c & 1) << 31) | ((s & 1) << 30) | (i & 0x3fffffff)))
+
+#define SGLISTINFO_TABLE_SIZE	(sizeof(struct sglist_info) * MAX_ION_FD)
+
+#define FEATURE_ID_WHITELIST	15	/*whitelist feature id*/
+
+#define MAKE_WHITELIST_VERSION(major, minor, patch) \
+	(((major & 0x3FF) << 22) | ((minor & 0x3FF) << 12) | (patch & 0xFFF))
+
 struct qseecom_registered_listener_list {
 	struct list_head                 list;
 	struct qseecom_register_listener_req svc;
@@ -145,6 +174,8 @@
 	bool                       listener_in_use;
 	/* wq for thread blocked on this listener*/
 	wait_queue_head_t          listener_block_app_wq;
+	struct sglist_info sglistinfo_ptr[MAX_ION_FD];
+	uint32_t sglist_cnt;
 };
 
 struct qseecom_registered_app_list {
@@ -205,6 +236,7 @@
 	uint32_t          qseos_version;
 	uint32_t          qsee_version;
 	struct device *pdev;
+	bool  whitelist_support;
 	bool  commonlib_loaded;
 	bool  commonlib64_loaded;
 	struct ion_handle *cmnlib_ion_handle;
@@ -280,6 +312,9 @@
 	bool  perf_enabled;
 	bool  fast_load_enabled;
 	enum qseecom_bandwidth_request_mode mode;
+	struct sglist_info sglistinfo_ptr[MAX_ION_FD];
+	uint32_t sglist_cnt;
+	bool use_legacy_cmd;
 };
 
 struct qseecom_key_id_usage_desc {
@@ -557,6 +592,34 @@
 			ret = scm_call2(smc_id, &desc);
 			break;
 		}
+		case QSEOS_LISTENER_DATA_RSP_COMMAND_WHITELIST: {
+			struct qseecom_client_listener_data_irsp *req;
+			struct qseecom_client_listener_data_64bit_irsp *req_64;
+
+			smc_id =
+			TZ_OS_LISTENER_RESPONSE_HANDLER_WITH_WHITELIST_ID;
+			desc.arginfo =
+			TZ_OS_LISTENER_RESPONSE_HANDLER_WITH_WHITELIST_PARAM_ID;
+			if (qseecom.qsee_version < QSEE_VERSION_40) {
+				req =
+				(struct qseecom_client_listener_data_irsp *)
+				req_buf;
+				desc.args[0] = req->listener_id;
+				desc.args[1] = req->status;
+				desc.args[2] = req->sglistinfo_ptr;
+				desc.args[3] = req->sglistinfo_len;
+			} else {
+				req_64 =
+			(struct qseecom_client_listener_data_64bit_irsp *)
+				req_buf;
+				desc.args[0] = req_64->listener_id;
+				desc.args[1] = req_64->status;
+				desc.args[2] = req_64->sglistinfo_ptr;
+				desc.args[3] = req_64->sglistinfo_len;
+			}
+			ret = scm_call2(smc_id, &desc);
+			break;
+		}
 		case QSEOS_LOAD_EXTERNAL_ELF_COMMAND: {
 			struct qseecom_load_app_ireq *req;
 			struct qseecom_load_app_64bit_ireq *req_64bit;
@@ -612,6 +675,38 @@
 			ret = scm_call2(smc_id, &desc);
 			break;
 		}
+		case QSEOS_CLIENT_SEND_DATA_COMMAND_WHITELIST: {
+			struct qseecom_client_send_data_ireq *req;
+			struct qseecom_client_send_data_64bit_ireq *req_64bit;
+
+			smc_id = TZ_APP_QSAPP_SEND_DATA_WITH_WHITELIST_ID;
+			desc.arginfo =
+			TZ_APP_QSAPP_SEND_DATA_WITH_WHITELIST_ID_PARAM_ID;
+			if (qseecom.qsee_version < QSEE_VERSION_40) {
+				req = (struct qseecom_client_send_data_ireq *)
+					req_buf;
+				desc.args[0] = req->app_id;
+				desc.args[1] = req->req_ptr;
+				desc.args[2] = req->req_len;
+				desc.args[3] = req->rsp_ptr;
+				desc.args[4] = req->rsp_len;
+				desc.args[5] = req->sglistinfo_ptr;
+				desc.args[6] = req->sglistinfo_len;
+			} else {
+				req_64bit =
+				(struct qseecom_client_send_data_64bit_ireq *)
+					req_buf;
+				desc.args[0] = req_64bit->app_id;
+				desc.args[1] = req_64bit->req_ptr;
+				desc.args[2] = req_64bit->req_len;
+				desc.args[3] = req_64bit->rsp_ptr;
+				desc.args[4] = req_64bit->rsp_len;
+				desc.args[5] = req_64bit->sglistinfo_ptr;
+				desc.args[6] = req_64bit->sglistinfo_len;
+			}
+			ret = scm_call2(smc_id, &desc);
+			break;
+		}
 		case QSEOS_RPMB_PROVISION_KEY_COMMAND: {
 			struct qseecom_client_send_service_ireq *req;
 			req = (struct qseecom_client_send_service_ireq *)
@@ -754,6 +849,36 @@
 			ret = scm_call2(smc_id, &desc);
 			break;
 		}
+		case QSEOS_TEE_OPEN_SESSION_WHITELIST: {
+			struct qseecom_qteec_ireq *req;
+			struct qseecom_qteec_64bit_ireq *req_64bit;
+
+			smc_id = TZ_APP_GPAPP_OPEN_SESSION_WITH_WHITELIST_ID;
+			desc.arginfo =
+			TZ_APP_GPAPP_OPEN_SESSION_WITH_WHITELIST_ID_PARAM_ID;
+			if (qseecom.qsee_version < QSEE_VERSION_40) {
+				req = (struct qseecom_qteec_ireq *)req_buf;
+				desc.args[0] = req->app_id;
+				desc.args[1] = req->req_ptr;
+				desc.args[2] = req->req_len;
+				desc.args[3] = req->resp_ptr;
+				desc.args[4] = req->resp_len;
+				desc.args[5] = req->sglistinfo_ptr;
+				desc.args[6] = req->sglistinfo_len;
+			} else {
+				req_64bit = (struct qseecom_qteec_64bit_ireq *)
+						req_buf;
+				desc.args[0] = req_64bit->app_id;
+				desc.args[1] = req_64bit->req_ptr;
+				desc.args[2] = req_64bit->req_len;
+				desc.args[3] = req_64bit->resp_ptr;
+				desc.args[4] = req_64bit->resp_len;
+				desc.args[5] = req_64bit->sglistinfo_ptr;
+				desc.args[6] = req_64bit->sglistinfo_len;
+			}
+			ret = scm_call2(smc_id, &desc);
+			break;
+		}
 		case QSEOS_TEE_INVOKE_COMMAND: {
 			struct qseecom_qteec_ireq *req;
 			struct qseecom_qteec_64bit_ireq *req_64bit;
@@ -778,6 +903,36 @@
 			ret = scm_call2(smc_id, &desc);
 			break;
 		}
+		case QSEOS_TEE_INVOKE_COMMAND_WHITELIST: {
+			struct qseecom_qteec_ireq *req;
+			struct qseecom_qteec_64bit_ireq *req_64bit;
+
+			smc_id = TZ_APP_GPAPP_INVOKE_COMMAND_WITH_WHITELIST_ID;
+			desc.arginfo =
+			TZ_APP_GPAPP_INVOKE_COMMAND_WITH_WHITELIST_ID_PARAM_ID;
+			if (qseecom.qsee_version < QSEE_VERSION_40) {
+				req = (struct qseecom_qteec_ireq *)req_buf;
+				desc.args[0] = req->app_id;
+				desc.args[1] = req->req_ptr;
+				desc.args[2] = req->req_len;
+				desc.args[3] = req->resp_ptr;
+				desc.args[4] = req->resp_len;
+				desc.args[5] = req->sglistinfo_ptr;
+				desc.args[6] = req->sglistinfo_len;
+			} else {
+				req_64bit = (struct qseecom_qteec_64bit_ireq *)
+						req_buf;
+				desc.args[0] = req_64bit->app_id;
+				desc.args[1] = req_64bit->req_ptr;
+				desc.args[2] = req_64bit->req_len;
+				desc.args[3] = req_64bit->resp_ptr;
+				desc.args[4] = req_64bit->resp_len;
+				desc.args[5] = req_64bit->sglistinfo_ptr;
+				desc.args[6] = req_64bit->sglistinfo_len;
+			}
+			ret = scm_call2(smc_id, &desc);
+			break;
+		}
 		case QSEOS_TEE_CLOSE_SESSION: {
 			struct qseecom_qteec_ireq *req;
 			struct qseecom_qteec_64bit_ireq *req_64bit;
@@ -1005,7 +1160,7 @@
 		return -EBUSY;
 	}
 
-	new_entry = kmalloc(sizeof(*new_entry), GFP_KERNEL);
+	new_entry = kzalloc(sizeof(*new_entry), GFP_KERNEL);
 	if (!new_entry) {
 		pr_err("kmalloc failed\n");
 		return -ENOMEM;
@@ -1466,6 +1621,16 @@
 	return ret;
 }
 
+static void __qseecom_clean_listener_sglistinfo(
+			struct qseecom_registered_listener_list *ptr_svc)
+{
+	if (ptr_svc->sglist_cnt) {
+		memset(ptr_svc->sglistinfo_ptr, 0,
+			SGLISTINFO_TABLE_SIZE);
+		ptr_svc->sglist_cnt = 0;
+	}
+}
+
 static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data,
 					struct qseecom_command_scm_resp *resp)
 {
@@ -1474,9 +1639,14 @@
 	uint32_t lstnr;
 	unsigned long flags;
 	struct qseecom_client_listener_data_irsp send_data_rsp;
+	struct qseecom_client_listener_data_64bit_irsp send_data_rsp_64bit;
 	struct qseecom_registered_listener_list *ptr_svc = NULL;
 	sigset_t new_sigset;
 	sigset_t old_sigset;
+	uint32_t status;
+	void *cmd_buf = NULL;
+	size_t cmd_len;
+	struct sglist_info *table = NULL;
 
 	while (resp->result == QSEOS_RESULT_INCOMPLETE) {
 		lstnr = resp->data;
@@ -1488,6 +1658,7 @@
 		list_for_each_entry(ptr_svc,
 				&qseecom.registered_listener_list_head, list) {
 			if (ptr_svc->svc.listener_id == lstnr) {
+				ptr_svc->listener_in_use = true;
 				ptr_svc->rcv_req_flag = 1;
 				wake_up_interruptible(&ptr_svc->rcv_req_wq);
 				break;
@@ -1549,15 +1720,42 @@
 			pr_err("Abort clnt %d waiting on lstnr svc %d, ret %d",
 				data->client.app_id, lstnr, ret);
 			rc = -ENODEV;
-			send_data_rsp.status  = QSEOS_RESULT_FAILURE;
+			status = QSEOS_RESULT_FAILURE;
 		} else {
-			send_data_rsp.status  = QSEOS_RESULT_SUCCESS;
+			status = QSEOS_RESULT_SUCCESS;
 		}
 
 		qseecom.send_resp_flag = 0;
 		ptr_svc->send_resp_flag = 0;
-		send_data_rsp.qsee_cmd_id = QSEOS_LISTENER_DATA_RSP_COMMAND;
-		send_data_rsp.listener_id  = lstnr;
+		table = ptr_svc->sglistinfo_ptr;
+		if (qseecom.qsee_version < QSEE_VERSION_40) {
+			send_data_rsp.listener_id  = lstnr;
+			send_data_rsp.status = status;
+			send_data_rsp.sglistinfo_ptr =
+				(uint32_t)virt_to_phys(table);
+			send_data_rsp.sglistinfo_len =
+				SGLISTINFO_TABLE_SIZE;
+			dmac_flush_range((void *)table,
+				(void *)table + SGLISTINFO_TABLE_SIZE);
+			cmd_buf = (void *)&send_data_rsp;
+			cmd_len = sizeof(send_data_rsp);
+		} else {
+			send_data_rsp_64bit.listener_id  = lstnr;
+			send_data_rsp_64bit.status = status;
+			send_data_rsp_64bit.sglistinfo_ptr =
+				virt_to_phys(table);
+			send_data_rsp_64bit.sglistinfo_len =
+				SGLISTINFO_TABLE_SIZE;
+			dmac_flush_range((void *)table,
+				(void *)table + SGLISTINFO_TABLE_SIZE);
+			cmd_buf = (void *)&send_data_rsp_64bit;
+			cmd_len = sizeof(send_data_rsp_64bit);
+		}
+		if (qseecom.whitelist_support == false)
+			*(uint32_t *)cmd_buf = QSEOS_LISTENER_DATA_RSP_COMMAND;
+		else
+			*(uint32_t *)cmd_buf =
+				QSEOS_LISTENER_DATA_RSP_COMMAND_WHITELIST;
 		if (ptr_svc)
 			msm_ion_do_cache_op(qseecom.ion_clnt, ptr_svc->ihandle,
 					ptr_svc->sb_virt, ptr_svc->sb_length,
@@ -1567,9 +1765,9 @@
 			__qseecom_enable_clk(CLK_QSEE);
 
 		ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1,
-					(const void *)&send_data_rsp,
-					sizeof(send_data_rsp), resp,
-					sizeof(*resp));
+					cmd_buf, cmd_len, resp, sizeof(*resp));
+		ptr_svc->listener_in_use = false;
+		__qseecom_clean_listener_sglistinfo(ptr_svc);
 		if (ret) {
 			pr_err("scm_call() failed with err: %d (app_id = %d)\n",
 				ret, data->client.app_id);
@@ -1696,9 +1894,14 @@
 	uint32_t lstnr;
 	unsigned long flags;
 	struct qseecom_client_listener_data_irsp send_data_rsp;
+	struct qseecom_client_listener_data_64bit_irsp send_data_rsp_64bit;
 	struct qseecom_registered_listener_list *ptr_svc = NULL;
 	sigset_t new_sigset;
 	sigset_t old_sigset;
+	uint32_t status;
+	void *cmd_buf = NULL;
+	size_t cmd_len;
+	struct sglist_info *table = NULL;
 
 	while (resp->result == QSEOS_RESULT_INCOMPLETE) {
 		lstnr = resp->data;
@@ -1761,13 +1964,38 @@
 			pr_err("Abort clnt %d waiting on lstnr svc %d, ret %d",
 				data->client.app_id, lstnr, ret);
 			rc = -ENODEV;
-			send_data_rsp.status  = QSEOS_RESULT_FAILURE;
+			status  = QSEOS_RESULT_FAILURE;
 		} else {
-			send_data_rsp.status  = QSEOS_RESULT_SUCCESS;
+			status  = QSEOS_RESULT_SUCCESS;
 		}
-
-		send_data_rsp.qsee_cmd_id = QSEOS_LISTENER_DATA_RSP_COMMAND;
-		send_data_rsp.listener_id  = lstnr;
+		table = ptr_svc->sglistinfo_ptr;
+		if (qseecom.qsee_version < QSEE_VERSION_40) {
+			send_data_rsp.listener_id  = lstnr;
+			send_data_rsp.status = status;
+			send_data_rsp.sglistinfo_ptr =
+				(uint32_t)virt_to_phys(table);
+			send_data_rsp.sglistinfo_len = SGLISTINFO_TABLE_SIZE;
+			dmac_flush_range((void *)table,
+				(void *)table + SGLISTINFO_TABLE_SIZE);
+			cmd_buf = (void *)&send_data_rsp;
+			cmd_len = sizeof(send_data_rsp);
+		} else {
+			send_data_rsp_64bit.listener_id  = lstnr;
+			send_data_rsp_64bit.status = status;
+			send_data_rsp_64bit.sglistinfo_ptr =
+				virt_to_phys(table);
+			send_data_rsp_64bit.sglistinfo_len =
+				SGLISTINFO_TABLE_SIZE;
+			dmac_flush_range((void *)table,
+				(void *)table + SGLISTINFO_TABLE_SIZE);
+			cmd_buf = (void *)&send_data_rsp_64bit;
+			cmd_len = sizeof(send_data_rsp_64bit);
+		}
+		if (qseecom.whitelist_support == false)
+			*(uint32_t *)cmd_buf = QSEOS_LISTENER_DATA_RSP_COMMAND;
+		else
+			*(uint32_t *)cmd_buf =
+				QSEOS_LISTENER_DATA_RSP_COMMAND_WHITELIST;
 		if (ptr_svc)
 			msm_ion_do_cache_op(qseecom.ion_clnt, ptr_svc->ihandle,
 					ptr_svc->sb_virt, ptr_svc->sb_length,
@@ -1777,11 +2005,9 @@
 			__qseecom_enable_clk(CLK_QSEE);
 
 		ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1,
-					(const void *)&send_data_rsp,
-					sizeof(send_data_rsp), resp,
-					sizeof(*resp));
-
+					cmd_buf, cmd_len, resp, sizeof(*resp));
 		ptr_svc->listener_in_use = false;
+		__qseecom_clean_listener_sglistinfo(ptr_svc);
 		wake_up_interruptible(&ptr_svc->listener_block_app_wq);
 
 		if (ret) {
@@ -2714,14 +2940,15 @@
 {
 	int ret = 0;
 	u32 reqd_len_sb_in = 0;
-	struct qseecom_client_send_data_ireq send_data_req;
-	struct qseecom_client_send_data_64bit_ireq send_data_req_64bit;
+	struct qseecom_client_send_data_ireq send_data_req = {0};
+	struct qseecom_client_send_data_64bit_ireq send_data_req_64bit = {0};
 	struct qseecom_command_scm_resp resp;
 	unsigned long flags;
 	struct qseecom_registered_app_list *ptr_app;
 	bool found_app = false;
 	void *cmd_buf = NULL;
 	size_t cmd_len;
+	struct sglist_info *table = data->sglistinfo_ptr;
 
 	reqd_len_sb_in = req->cmd_req_len + req->resp_len;
 	/* find app_id & img_name from list */
@@ -2743,7 +2970,6 @@
 	}
 
 	if (qseecom.qsee_version < QSEE_VERSION_40) {
-		send_data_req.qsee_cmd_id = QSEOS_CLIENT_SEND_DATA_COMMAND;
 		send_data_req.app_id = data->client.app_id;
 		send_data_req.req_ptr = (uint32_t)(__qseecom_uvirt_to_kphys(
 					data, (uintptr_t)req->cmd_req_buf));
@@ -2751,11 +2977,14 @@
 		send_data_req.rsp_ptr = (uint32_t)(__qseecom_uvirt_to_kphys(
 					data, (uintptr_t)req->resp_buf));
 		send_data_req.rsp_len = req->resp_len;
+		send_data_req.sglistinfo_ptr =
+				(uint32_t)virt_to_phys(table);
+		send_data_req.sglistinfo_len = SGLISTINFO_TABLE_SIZE;
+		dmac_flush_range((void *)table,
+				(void *)table + SGLISTINFO_TABLE_SIZE);
 		cmd_buf = (void *)&send_data_req;
 		cmd_len = sizeof(struct qseecom_client_send_data_ireq);
 	} else {
-		send_data_req_64bit.qsee_cmd_id =
-					QSEOS_CLIENT_SEND_DATA_COMMAND;
 		send_data_req_64bit.app_id = data->client.app_id;
 		send_data_req_64bit.req_ptr = __qseecom_uvirt_to_kphys(data,
 					(uintptr_t)req->cmd_req_buf);
@@ -2777,10 +3006,20 @@
 				send_data_req_64bit.rsp_len);
 			return -EFAULT;
 		}
+		send_data_req_64bit.sglistinfo_ptr =
+				(uint64_t)virt_to_phys(table);
+		send_data_req_64bit.sglistinfo_len = SGLISTINFO_TABLE_SIZE;
+		dmac_flush_range((void *)table,
+				(void *)table + SGLISTINFO_TABLE_SIZE);
 		cmd_buf = (void *)&send_data_req_64bit;
 		cmd_len = sizeof(struct qseecom_client_send_data_64bit_ireq);
 	}
 
+	if (qseecom.whitelist_support == false || data->use_legacy_cmd == true)
+		*(uint32_t *)cmd_buf = QSEOS_CLIENT_SEND_DATA_COMMAND;
+	else
+		*(uint32_t *)cmd_buf = QSEOS_CLIENT_SEND_DATA_COMMAND_WHITELIST;
+
 	msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle,
 					data->client.sb_virt,
 					reqd_len_sb_in,
@@ -2881,6 +3120,8 @@
 	struct qseecom_send_modfd_cmd_req *req = NULL;
 	struct qseecom_send_modfd_listener_resp *lstnr_resp = NULL;
 	struct qseecom_registered_listener_list *this_lstnr = NULL;
+	uint32_t offset;
+	struct sg_table *sg_ptr;
 
 	if ((data->type != QSEECOM_LISTENER_SERVICE) &&
 			(data->type != QSEECOM_CLIENT_APP))
@@ -2902,7 +3143,6 @@
 	}
 
 	for (i = 0; i < MAX_ION_FD; i++) {
-		struct sg_table *sg_ptr = NULL;
 		if ((data->type != QSEECOM_LISTENER_SERVICE) &&
 						(req->ifd_data[i].fd > 0)) {
 			ihandle = ion_import_dma_buf(qseecom.ion_clnt,
@@ -3034,14 +3274,37 @@
 					goto err;
 			}
 		}
-		if (cleanup)
+
+		if (cleanup) {
 			msm_ion_do_cache_op(qseecom.ion_clnt,
 					ihandle, NULL, len,
 					ION_IOC_INV_CACHES);
-		else
+		} else {
 			msm_ion_do_cache_op(qseecom.ion_clnt,
 					ihandle, NULL, len,
 					ION_IOC_CLEAN_INV_CACHES);
+			if (data->type == QSEECOM_CLIENT_APP) {
+				offset = req->ifd_data[i].cmd_buf_offset;
+				data->sglistinfo_ptr[i].indexAndFlags =
+					SGLISTINFO_SET_INDEX_FLAG(
+					(sg_ptr->nents == 1), 0, offset);
+				data->sglistinfo_ptr[i].sizeOrCount =
+					(sg_ptr->nents == 1) ?
+					sg->length : sg_ptr->nents;
+				data->sglist_cnt = i + 1;
+			} else {
+				offset = (lstnr_resp->ifd_data[i].cmd_buf_offset
+					+ (uintptr_t)lstnr_resp->resp_buf_ptr -
+					(uintptr_t)this_lstnr->sb_virt);
+				this_lstnr->sglistinfo_ptr[i].indexAndFlags =
+					SGLISTINFO_SET_INDEX_FLAG(
+					(sg_ptr->nents == 1), 0, offset);
+				this_lstnr->sglistinfo_ptr[i].sizeOrCount =
+					(sg_ptr->nents == 1) ?
+					sg->length : sg_ptr->nents;
+				this_lstnr->sglist_cnt = i + 1;
+			}
+		}
 		/* Deallocate the handle */
 		if (!IS_ERR_OR_NULL(ihandle))
 			ion_free(qseecom.ion_clnt, ihandle);
@@ -3112,6 +3375,8 @@
 	struct qseecom_send_modfd_cmd_req *req = NULL;
 	struct qseecom_send_modfd_listener_resp *lstnr_resp = NULL;
 	struct qseecom_registered_listener_list *this_lstnr = NULL;
+	uint32_t offset;
+	struct sg_table *sg_ptr;
 
 	if ((data->type != QSEECOM_LISTENER_SERVICE) &&
 			(data->type != QSEECOM_CLIENT_APP))
@@ -3133,7 +3398,6 @@
 	}
 
 	for (i = 0; i < MAX_ION_FD; i++) {
-		struct sg_table *sg_ptr = NULL;
 		if ((data->type != QSEECOM_LISTENER_SERVICE) &&
 						(req->ifd_data[i].fd > 0)) {
 			ihandle = ion_import_dma_buf(qseecom.ion_clnt,
@@ -3187,6 +3451,7 @@
 				}
 			}
 			len = QSEECOM_SG_LIST_BUF_HDR_SZ_64BIT;
+			sg = sg_ptr->sgl;
 			goto cleanup;
 		}
 		sg = sg_ptr->sgl;
@@ -3240,14 +3505,36 @@
 			}
 		}
 cleanup:
-		if (cleanup)
+		if (cleanup) {
 			msm_ion_do_cache_op(qseecom.ion_clnt,
 					ihandle, NULL, len,
 					ION_IOC_INV_CACHES);
-		else
+		} else {
 			msm_ion_do_cache_op(qseecom.ion_clnt,
 					ihandle, NULL, len,
 					ION_IOC_CLEAN_INV_CACHES);
+			if (data->type == QSEECOM_CLIENT_APP) {
+				offset = req->ifd_data[i].cmd_buf_offset;
+				data->sglistinfo_ptr[i].indexAndFlags =
+					SGLISTINFO_SET_INDEX_FLAG(
+					(sg_ptr->nents == 1), 1, offset);
+				data->sglistinfo_ptr[i].sizeOrCount =
+					(sg_ptr->nents == 1) ?
+					sg->length : sg_ptr->nents;
+				data->sglist_cnt = i + 1;
+			} else {
+				offset = (lstnr_resp->ifd_data[i].cmd_buf_offset
+					+ (uintptr_t)lstnr_resp->resp_buf_ptr -
+					(uintptr_t)this_lstnr->sb_virt);
+				this_lstnr->sglistinfo_ptr[i].indexAndFlags =
+					SGLISTINFO_SET_INDEX_FLAG(
+					(sg_ptr->nents == 1), 1, offset);
+				this_lstnr->sglistinfo_ptr[i].sizeOrCount =
+					(sg_ptr->nents == 1) ?
+					sg->length : sg_ptr->nents;
+				this_lstnr->sglist_cnt = i + 1;
+			}
+		}
 		/* Deallocate the handle */
 		if (!IS_ERR_OR_NULL(ihandle))
 			ion_free(qseecom.ion_clnt, ihandle);
@@ -4157,8 +4444,11 @@
 		}
 		perf_enabled = true;
 	}
+	if (!strcmp(data->client.app_name, "securemm"))
+		data->use_legacy_cmd = true;
 
 	ret = __qseecom_send_cmd(data, &req);
+	data->use_legacy_cmd = false;
 	if (qseecom.support_bus_scaling)
 		__qseecom_add_bw_scale_down_timer(
 			QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
@@ -5906,14 +6196,23 @@
 				*update = (uint32_t)sg_dma_address(sg_ptr->sgl);
 		}
 clean:
-		if (cleanup)
+		if (cleanup) {
 			msm_ion_do_cache_op(qseecom.ion_clnt,
 				ihandle, NULL, sg->length,
 				ION_IOC_INV_CACHES);
-		else
+		} else {
 			msm_ion_do_cache_op(qseecom.ion_clnt,
 				ihandle, NULL, sg->length,
 				ION_IOC_CLEAN_INV_CACHES);
+			data->sglistinfo_ptr[i].indexAndFlags =
+				SGLISTINFO_SET_INDEX_FLAG(
+				(sg_ptr->nents == 1), 0,
+				req->ifd_data[i].cmd_buf_offset);
+			data->sglistinfo_ptr[i].sizeOrCount =
+				(sg_ptr->nents == 1) ?
+				sg->length : sg_ptr->nents;
+			data->sglist_cnt = i + 1;
+		}
 		/* Deallocate the handle */
 		if (!IS_ERR_OR_NULL(ihandle))
 			ion_free(qseecom.ion_clnt, ihandle);
@@ -5938,6 +6237,7 @@
 	uint32_t reqd_len_sb_in = 0;
 	void *cmd_buf = NULL;
 	size_t cmd_len;
+	struct sglist_info *table = data->sglistinfo_ptr;
 
 	ret  = __qseecom_qteec_validate_msg(data, req);
 	if (ret)
@@ -5960,8 +6260,15 @@
 		return -ENOENT;
 	}
 
+	if ((cmd_id == QSEOS_TEE_OPEN_SESSION) ||
+			(cmd_id == QSEOS_TEE_REQUEST_CANCELLATION)) {
+		ret = __qseecom_update_qteec_req_buf(
+			(struct qseecom_qteec_modfd_req *)req, data, false);
+		if (ret)
+			return ret;
+	}
+
 	if (qseecom.qsee_version < QSEE_VERSION_40) {
-		ireq.qsee_cmd_id = cmd_id;
 		ireq.app_id = data->client.app_id;
 		ireq.req_ptr = (uint32_t)__qseecom_uvirt_to_kphys(data,
 						(uintptr_t)req->req_ptr);
@@ -5969,10 +6276,13 @@
 		ireq.resp_ptr = (uint32_t)__qseecom_uvirt_to_kphys(data,
 						(uintptr_t)req->resp_ptr);
 		ireq.resp_len = req->resp_len;
+		ireq.sglistinfo_ptr = (uint32_t)virt_to_phys(table);
+		ireq.sglistinfo_len = SGLISTINFO_TABLE_SIZE;
+		dmac_flush_range((void *)table,
+				(void *)table + SGLISTINFO_TABLE_SIZE);
 		cmd_buf = (void *)&ireq;
 		cmd_len = sizeof(struct qseecom_qteec_ireq);
 	} else {
-		ireq_64bit.qsee_cmd_id = cmd_id;
 		ireq_64bit.app_id = data->client.app_id;
 		ireq_64bit.req_ptr = (uint64_t)__qseecom_uvirt_to_kphys(data,
 						(uintptr_t)req->req_ptr);
@@ -5992,17 +6302,19 @@
 				ireq_64bit.resp_ptr, ireq_64bit.resp_len);
 			return -EFAULT;
 		}
+		ireq_64bit.sglistinfo_ptr = (uint64_t)virt_to_phys(table);
+		ireq_64bit.sglistinfo_len = SGLISTINFO_TABLE_SIZE;
+		dmac_flush_range((void *)table,
+				(void *)table + SGLISTINFO_TABLE_SIZE);
 		cmd_buf = (void *)&ireq_64bit;
 		cmd_len = sizeof(struct qseecom_qteec_64bit_ireq);
 	}
+	if (qseecom.whitelist_support == true
+		&& cmd_id == QSEOS_TEE_OPEN_SESSION)
+		*(uint32_t *)cmd_buf = QSEOS_TEE_OPEN_SESSION_WHITELIST;
+	else
+		*(uint32_t *)cmd_buf = cmd_id;
 
-	if ((cmd_id == QSEOS_TEE_OPEN_SESSION) ||
-			(cmd_id == QSEOS_TEE_REQUEST_CANCELLATION)) {
-		ret = __qseecom_update_qteec_req_buf(
-			(struct qseecom_qteec_modfd_req *)req, data, false);
-		if (ret)
-			return ret;
-	}
 	reqd_len_sb_in = req->req_len + req->resp_len;
 	msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle,
 					data->client.sb_virt,
@@ -6100,6 +6412,9 @@
 	uint32_t reqd_len_sb_in = 0;
 	void *cmd_buf = NULL;
 	size_t cmd_len;
+	struct sglist_info *table = data->sglistinfo_ptr;
+	void *req_ptr = NULL;
+	void *resp_ptr = NULL;
 
 	ret = copy_from_user(&req, argp,
 			sizeof(struct qseecom_qteec_modfd_req));
@@ -6111,6 +6426,8 @@
 					(struct qseecom_qteec_req *)(&req));
 	if (ret)
 		return ret;
+	req_ptr = req.req_ptr;
+	resp_ptr = req.resp_ptr;
 
 	/* find app_id & img_name from list */
 	spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
@@ -6129,31 +6446,6 @@
 		return -ENOENT;
 	}
 
-	if (qseecom.qsee_version < QSEE_VERSION_40) {
-		ireq.qsee_cmd_id = QSEOS_TEE_INVOKE_COMMAND;
-		ireq.app_id = data->client.app_id;
-		ireq.req_ptr = (uint32_t)__qseecom_uvirt_to_kphys(data,
-						(uintptr_t)req.req_ptr);
-		ireq.req_len = req.req_len;
-		ireq.resp_ptr = (uint32_t)__qseecom_uvirt_to_kphys(data,
-						(uintptr_t)req.resp_ptr);
-		ireq.resp_len = req.resp_len;
-		cmd_buf = (void *)&ireq;
-		cmd_len = sizeof(struct qseecom_qteec_ireq);
-	} else {
-		ireq_64bit.qsee_cmd_id = QSEOS_TEE_INVOKE_COMMAND;
-		ireq_64bit.app_id = data->client.app_id;
-		ireq_64bit.req_ptr = (uint64_t)__qseecom_uvirt_to_kphys(data,
-						(uintptr_t)req.req_ptr);
-		ireq_64bit.req_len = req.req_len;
-		ireq_64bit.resp_ptr = (uint64_t)__qseecom_uvirt_to_kphys(data,
-						(uintptr_t)req.resp_ptr);
-		ireq_64bit.resp_len = req.resp_len;
-		cmd_buf = (void *)&ireq_64bit;
-		cmd_len = sizeof(struct qseecom_qteec_64bit_ireq);
-	}
-	reqd_len_sb_in = req.req_len + req.resp_len;
-
 	/* validate offsets */
 	for (i = 0; i < MAX_ION_FD; i++) {
 		if (req.ifd_data[i].fd) {
@@ -6168,6 +6460,42 @@
 	ret = __qseecom_update_qteec_req_buf(&req, data, false);
 	if (ret)
 		return ret;
+
+	if (qseecom.qsee_version < QSEE_VERSION_40) {
+		ireq.app_id = data->client.app_id;
+		ireq.req_ptr = (uint32_t)__qseecom_uvirt_to_kphys(data,
+						(uintptr_t)req_ptr);
+		ireq.req_len = req.req_len;
+		ireq.resp_ptr = (uint32_t)__qseecom_uvirt_to_kphys(data,
+						(uintptr_t)resp_ptr);
+		ireq.resp_len = req.resp_len;
+		cmd_buf = (void *)&ireq;
+		cmd_len = sizeof(struct qseecom_qteec_ireq);
+		ireq.sglistinfo_ptr = (uint32_t)virt_to_phys(table);
+		ireq.sglistinfo_len = SGLISTINFO_TABLE_SIZE;
+		dmac_flush_range((void *)table,
+				(void *)table + SGLISTINFO_TABLE_SIZE);
+	} else {
+		ireq_64bit.app_id = data->client.app_id;
+		ireq_64bit.req_ptr = (uint64_t)__qseecom_uvirt_to_kphys(data,
+						(uintptr_t)req_ptr);
+		ireq_64bit.req_len = req.req_len;
+		ireq_64bit.resp_ptr = (uint64_t)__qseecom_uvirt_to_kphys(data,
+						(uintptr_t)resp_ptr);
+		ireq_64bit.resp_len = req.resp_len;
+		cmd_buf = (void *)&ireq_64bit;
+		cmd_len = sizeof(struct qseecom_qteec_64bit_ireq);
+		ireq_64bit.sglistinfo_ptr = (uint64_t)virt_to_phys(table);
+		ireq_64bit.sglistinfo_len = SGLISTINFO_TABLE_SIZE;
+		dmac_flush_range((void *)table,
+				(void *)table + SGLISTINFO_TABLE_SIZE);
+	}
+	reqd_len_sb_in = req.req_len + req.resp_len;
+	if (qseecom.whitelist_support == true)
+		*(uint32_t *)cmd_buf = QSEOS_TEE_INVOKE_COMMAND_WHITELIST;
+	else
+		*(uint32_t *)cmd_buf = QSEOS_TEE_INVOKE_COMMAND;
+
 	msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle,
 					data->client.sb_virt,
 					reqd_len_sb_in,
@@ -6230,6 +6558,15 @@
 	return ret;
 }
 
+static void __qseecom_clean_data_sglistinfo(struct qseecom_dev_handle *data)
+{
+	if (data->sglist_cnt) {
+		memset(data->sglistinfo_ptr, 0,
+			SGLISTINFO_TABLE_SIZE);
+		data->sglist_cnt = 0;
+	}
+}
+
 long qseecom_ioctl(struct file *file, unsigned cmd, unsigned long arg)
 {
 	int ret = 0;
@@ -6409,6 +6746,7 @@
 		mutex_unlock(&app_access_lock);
 		if (ret)
 			pr_err("failed qseecom_send_cmd: %d\n", ret);
+		__qseecom_clean_data_sglistinfo(data);
 		break;
 	}
 	case QSEECOM_IOCTL_RECEIVE_REQ: {
@@ -6782,6 +7120,7 @@
 		wake_up_all(&data->abort_wq);
 		if (ret)
 			pr_err("failed qseecom_send_mod_resp: %d\n", ret);
+		__qseecom_clean_data_sglistinfo(data);
 		break;
 	}
 	case QSEECOM_QTEEC_IOCTL_OPEN_SESSION_REQ: {
@@ -6806,6 +7145,7 @@
 		mutex_unlock(&app_access_lock);
 		if (ret)
 			pr_err("failed open_session_cmd: %d\n", ret);
+		__qseecom_clean_data_sglistinfo(data);
 		break;
 	}
 	case QSEECOM_QTEEC_IOCTL_CLOSE_SESSION_REQ: {
@@ -6854,6 +7194,7 @@
 		mutex_unlock(&app_access_lock);
 		if (ret)
 			pr_err("failed Invoke cmd: %d\n", ret);
+		__qseecom_clean_data_sglistinfo(data);
 		break;
 	}
 	case QSEECOM_QTEEC_IOCTL_REQUEST_CANCELLATION_REQ: {
@@ -6929,7 +7270,6 @@
 	data->mode = INACTIVE;
 	init_waitqueue_head(&data->abort_wq);
 	atomic_set(&data->ioctl_count, 0);
-
 	return ret;
 }
 
@@ -7731,6 +8071,17 @@
 	return ret;
 }
 
+/*
+ * Check whitelist feature, and if TZ feature version is < 1.0.0,
+ * then whitelist feature is not supported.
+ */
+static int qseecom_check_whitelist_feature(void)
+{
+	int version = scm_get_feat_version(FEATURE_ID_WHITELIST);
+
+	return version >= MAKE_WHITELIST_VERSION(1, 0, 0);
+}
+
 static int qseecom_probe(struct platform_device *pdev)
 {
 	int rc;
@@ -7763,6 +8114,7 @@
 
 	qseecom.app_block_ref_cnt = 0;
 	init_waitqueue_head(&qseecom.app_block_wq);
+	qseecom.whitelist_support = true;
 
 	rc = alloc_chrdev_region(&qseecom_device_no, 0, 1, QSEECOM_DEV);
 	if (rc < 0) {
@@ -7978,6 +8330,10 @@
 	qseecom.qsee_perf_client = msm_bus_scale_register_client(
 					qseecom_platform_support);
 
+	qseecom.whitelist_support = qseecom_check_whitelist_feature();
+	pr_warn("qseecom.whitelist_support = %d\n",
+				qseecom.whitelist_support);
+
 	if (!qseecom.qsee_perf_client)
 		pr_err("Unable to register bus client\n");
 
diff --git a/drivers/platform/msm/qpnp-power-on.c b/drivers/platform/msm/qpnp-power-on.c
index 954af54..7d01b04 100644
--- a/drivers/platform/msm/qpnp-power-on.c
+++ b/drivers/platform/msm/qpnp-power-on.c
@@ -787,6 +787,8 @@
 	switch (cfg->pon_type) {
 	case PON_KPDPWR:
 		pon_rt_bit = QPNP_PON_KPDPWR_N_SET;
+		pr_info("Report pwrkey %s event\n", pon_rt_bit & pon_rt_sts ?
+			"press" : "release");
 		break;
 	case PON_RESIN:
 		pon_rt_bit = QPNP_PON_RESIN_N_SET;
diff --git a/drivers/power/htc_battery.c b/drivers/power/htc_battery.c
index 4cbb9b85..bef4c21 100644
--- a/drivers/power/htc_battery.c
+++ b/drivers/power/htc_battery.c
@@ -24,6 +24,7 @@
 #include <linux/notifier.h>
 #include <linux/fb.h>
 #endif /* CONFIG_FB */
+#include <linux/leds.h>
 
 static struct htc_battery_info htc_batt_info;
 static struct htc_battery_timer htc_batt_timer;
@@ -1127,6 +1128,21 @@
         return 0;
 }
 
+void htc_battery_backlight_dim_mode_check(bool status)
+{
+	int rc = 0;
+
+	if (status) {
+		rc = pmi8996_charger_batfet_switch(true);
+		if (rc < 0)
+			BATT_ERR("Unable to set batfet switch true, rc = %d\n", rc);
+	} else {
+		rc = pmi8996_charger_batfet_switch(false);
+		if (rc < 0)
+			BATT_ERR("Unable to set batfet switch false, rc = %d\n", rc);
+	}
+}
+
 #if defined(CONFIG_FB)
 static int fb_notifier_callback(struct notifier_block *self,
                                 unsigned long event, void *data)
@@ -1439,14 +1455,12 @@
 	if ((int)htc_batt_info.rep.charging_source > POWER_SUPPLY_TYPE_BATTERY) {
 		/*  STEP 11.1.1 check and update chg_dis_reason */
 		if (g_ftm_charger_control_flag == FTM_FAST_CHARGE || g_flag_force_ac_chg) {
-			s_prev_user_set_chg_curr = get_property(htc_batt_info.usb_psy, POWER_SUPPLY_PROP_CURRENT_MAX);
 			if (htc_batt_info.rep.charging_source == POWER_SUPPLY_TYPE_USB){
 				user_set_chg_curr = FAST_CHARGE_CURR;
 			} else {
 				user_set_chg_curr = WALL_CHARGE_CURR;
 			}
 		} else if (g_ftm_charger_control_flag == FTM_SLOW_CHARGE) {
-			s_prev_user_set_chg_curr = get_property(htc_batt_info.usb_psy, POWER_SUPPLY_PROP_CURRENT_MAX);
 			user_set_chg_curr = SLOW_CHARGE_CURR;
 			pmi8994_set_iusb_max(user_set_chg_curr);
 #ifdef CONFIG_HTC_CHARGER
@@ -1456,7 +1470,7 @@
 		} else {
 			/* WA: QCT  recorgnize D+/D- open charger won't set 500mA. */
 			if ((htc_batt_info.rep.charging_source == POWER_SUPPLY_TYPE_USB)) {
-				s_prev_user_set_chg_curr = get_property(htc_batt_info.usb_psy, POWER_SUPPLY_PROP_CURRENT_MAX);
+				user_set_chg_curr = get_property(htc_batt_info.usb_psy, POWER_SUPPLY_PROP_CURRENT_MAX);
 				if (!get_connect2pc() && !g_rerun_apsd_done && !g_is_unknown_charger) {
 					user_set_chg_curr = SLOW_CHARGE_CURR;
 					if (delayed_work_pending(&htc_batt_info.chk_unknown_chg_work))
@@ -1464,15 +1478,14 @@
 					schedule_delayed_work(&htc_batt_info.chk_unknown_chg_work,
 							msecs_to_jiffies(CHG_UNKNOWN_CHG_PERIOD_MS));
 				} else {
-					if (s_prev_user_set_chg_curr < SLOW_CHARGE_CURR)
-						s_prev_user_set_chg_curr = SLOW_CHARGE_CURR;
-					user_set_chg_curr = s_prev_user_set_chg_curr;
+					if (user_set_chg_curr < SLOW_CHARGE_CURR)
+						user_set_chg_curr = SLOW_CHARGE_CURR;
 				}
 			} else if (htc_batt_info.rep.charging_source == POWER_SUPPLY_TYPE_USB_HVDCP){
-				s_prev_user_set_chg_curr = get_property(htc_batt_info.usb_psy, POWER_SUPPLY_PROP_CURRENT_MAX);
+				user_set_chg_curr = get_property(htc_batt_info.usb_psy, POWER_SUPPLY_PROP_CURRENT_MAX);
 				pmi8994_set_iusb_max(HVDCP_CHARGE_CURR);
 			} else if (htc_batt_info.rep.charging_source == POWER_SUPPLY_TYPE_USB_HVDCP_3){
-				s_prev_user_set_chg_curr = get_property(htc_batt_info.usb_psy, POWER_SUPPLY_PROP_CURRENT_MAX);
+				user_set_chg_curr = get_property(htc_batt_info.usb_psy, POWER_SUPPLY_PROP_CURRENT_MAX);
 				pmi8994_set_iusb_max(HVDCP_3_CHARGE_CURR);
 			}
 		}
@@ -2310,6 +2323,7 @@
 #define PD_LIMIT_VBUS_MV 5000
 #define PD_LIMIT_CURRENT_MA 3000
 #define MESG_MAX_LENGTH 300
+#define PD_MAX_POWER 18000000	/* 18W = 9V * 2A */
 int htc_battery_pd_charger_support(int size, struct htc_pd_data pd_data, int *max_mA)
 {
 	int i = 0;
@@ -2332,6 +2346,11 @@
 		pd_ma = pd_data.pd_list[i][1];
 		pd_power = pd_vbus_vol * pd_ma;
 
+		if (pd_power > PD_MAX_POWER) {
+			pd_power = PD_MAX_POWER;
+			pd_ma = pd_power / pd_vbus_vol;
+		}
+
 		if (pd_vbus_vol > PD_MAX_VBUS) {
 			pr_debug("[BATT][PD] Voltage %dV > %dV, skip to prevent OVP\n",
 					pd_vbus_vol/1000, PD_MAX_VBUS/1000);
diff --git a/drivers/power/qpnp-fg.c b/drivers/power/qpnp-fg.c
index a7842de..d254b1f 100644
--- a/drivers/power/qpnp-fg.c
+++ b/drivers/power/qpnp-fg.c
@@ -1549,7 +1549,8 @@
 
 		rc = fg_check_iacs_ready(chip);
 		if (rc) {
-			pr_debug("IACS_RDY failed rc=%d\n", rc);
+			pr_err("IACS_RDY failed post write to address %x offset %d rc=%d\n",
+				address, offset, rc);
 			return rc;
 		}
 
@@ -1595,7 +1596,8 @@
 
 		rc = fg_check_iacs_ready(chip);
 		if (rc) {
-			pr_debug("IACS_RDY failed rc=%d\n", rc);
+			pr_err("IACS_RDY failed post read for address %x offset %d rc=%d\n",
+				address, offset, rc);
 			return rc;
 		}
 
@@ -1678,7 +1680,8 @@
 
 	rc = fg_check_iacs_ready(chip);
 	if (rc) {
-		pr_debug("IACS_RDY failed rc=%d\n", rc);
+		pr_err("IACS_RDY failed before setting address: %x offset: %d rc=%d\n",
+			address, offset, rc);
 		return rc;
 	}
 
@@ -1691,7 +1694,8 @@
 
 	rc = fg_check_iacs_ready(chip);
 	if (rc)
-		pr_debug("IACS_RDY failed rc=%d\n", rc);
+		pr_err("IACS_RDY failed after setting address: %x offset: %d rc=%d\n",
+			address, offset, rc);
 
 	return rc;
 }
@@ -1702,7 +1706,7 @@
 static int fg_interleaved_mem_read(struct fg_chip *chip, u8 *val, u16 address,
 						int len, int offset)
 {
-	int rc = 0, orig_address = address;
+	int rc = 0, ret, orig_address = address;
 	u8 start_beat_count, end_beat_count, count = 0;
 	bool retry = false;
 
@@ -1783,9 +1787,14 @@
 	}
 out:
 	/* Release IMA access */
-	rc = fg_masked_write(chip, MEM_INTF_CFG(chip), IMA_REQ_ACCESS, 0, 1);
-	if (rc)
-		pr_err("failed to reset IMA access bit rc = %d\n", rc);
+	ret = fg_masked_write(chip, MEM_INTF_CFG(chip), IMA_REQ_ACCESS, 0, 1);
+	if (ret)
+		pr_err("failed to reset IMA access bit ret = %d\n", ret);
+
+	if (rc) {
+		mutex_unlock(&chip->rw_lock);
+		goto exit;
+	}
 
 	if (retry) {
 		retry = false;
@@ -1801,7 +1810,7 @@
 static int fg_interleaved_mem_write(struct fg_chip *chip, u8 *val, u16 address,
 							int len, int offset)
 {
-	int rc = 0, orig_address = address;
+	int rc = 0, ret, orig_address = address;
 	u8 count = 0;
 
 	if (chip->fg_shutdown)
@@ -1846,9 +1855,9 @@
 
 out:
 	/* Release IMA access */
-	rc = fg_masked_write(chip, MEM_INTF_CFG(chip), IMA_REQ_ACCESS, 0, 1);
-	if (rc)
-		pr_err("failed to reset IMA access bit rc = %d\n", rc);
+	ret = fg_masked_write(chip, MEM_INTF_CFG(chip), IMA_REQ_ACCESS, 0, 1);
+	if (ret)
+		pr_err("failed to reset IMA access bit ret = %d\n", ret);
 
 	mutex_unlock(&chip->rw_lock);
 	fg_relax(&chip->memif_wakeup_source);
@@ -2639,6 +2648,61 @@
 	return rc;
 }
 
+// Read the beat count and write it into the beat_count arg;
+// return non-zero on failure.
+static int read_beat(struct fg_chip *chip, u8 *beat_count)
+{
+	int rc = fg_read(chip, beat_count,
+			 chip->mem_base + MEM_INTF_FG_BEAT_COUNT, 1);
+	if (rc)
+		pr_err("failed to read beat count rc=%d\n", rc);
+	else if (fg_debug_mask & FG_STATUS)
+		pr_info("current: %d, prev: %d\n", *beat_count,
+			chip->last_beat_count);
+	return rc;
+}
+
+/*
+ * The FG_ALG_SYSCTL_1 word contains control bits for the
+ * fuel-gauge algorithm, most of whose effect are not
+ * publicly disclosed. The low nibble of 0x4B3 contains
+ * bits to control whether an IRQ is raised on low-battery
+ * conditions, as well as a debug bit (bit 3) that forces
+ * a delta-soc interrupt on every fuel-gauge cycle.
+ * The value in FG_ALG_SYSCTL_1_DFLT is the recommended
+ * default configuration with the IRQ's enabled.
+ */
+#define FG_ALG_SYSCTL_1		0x4B0
+#define FG_ALG_SYSCTL_1_DFLT	0x870C7999
+static int fg_check_system_config(struct fg_chip *chip)
+{
+	int rc;
+	u32 buf;
+
+	if (!chip->ima_supported)
+		return 0;
+
+	rc = fg_mem_read(chip, (u8 *)&buf, FG_ALG_SYSCTL_1, 4, 0, 0);
+	if (rc) {
+		pr_err("Failed to read 0x4B0-3 rc=%d\n", rc);
+		return rc;
+	}
+
+	if (fg_debug_mask & FG_STATUS)
+		pr_info("FG_ALG_SYSCTL_1: %x\n", buf);
+	if (buf != FG_ALG_SYSCTL_1_DFLT) {
+		pr_err("FG_ALG_SYSCTL_1 corrupted? buf: %x\n", buf);
+		buf = FG_ALG_SYSCTL_1_DFLT;
+		rc = fg_mem_write(chip, (u8 *)&buf, FG_ALG_SYSCTL_1, 4, 0, 0);
+		if (rc) {
+			pr_err("Failed to write 0x4B0-3 rc=%d\n", rc);
+			return rc;
+		}
+	}
+
+	return rc;
+}
+
 #define SANITY_CHECK_PERIOD_MS	5000
 static void check_sanity_work(struct work_struct *work)
 {
@@ -2649,19 +2713,28 @@
 	u8 beat_count;
 	bool tried_once = false;
 
+	rc = fg_check_system_config(chip);
+	if (rc)
+		pr_err("Failed to check system config rc=%d\n", rc);
+
+	// Try one beat check once up-front to avoid the common
+	// case where the beat has changed and we don't need to hold
+	// the chip awake.
+	rc = read_beat(chip, &beat_count);
+	if (rc == 0 && chip->last_beat_count != beat_count) {
+		chip->last_beat_count = beat_count;
+		schedule_delayed_work(
+			&chip->check_sanity_work,
+			msecs_to_jiffies(SANITY_CHECK_PERIOD_MS));
+		return;
+	}
+
 	fg_stay_awake(&chip->sanity_wakeup_source);
 
 try_again:
-	rc = fg_read(chip, &beat_count,
-			chip->mem_base + MEM_INTF_FG_BEAT_COUNT, 1);
-	if (rc) {
-		pr_err("failed to read beat count rc=%d\n", rc);
+	rc = read_beat(chip, &beat_count);
+	if (rc)
 		goto resched;
-	}
-
-	if (fg_debug_mask & FG_STATUS)
-		pr_info("current: %d, prev: %d\n", beat_count,
-			chip->last_beat_count);
 
 	if (chip->last_beat_count == beat_count) {
 		if (!tried_once) {
@@ -3291,7 +3364,7 @@
 	estimate_battery_age(chip, &chip->actual_cap_uah);
 }
 
-static int fg_get_coulomb_count(struct fg_chip *chip);
+static int fg_get_current_cc(struct fg_chip *chip);
 
 static enum power_supply_property fg_power_props[] = {
 	POWER_SUPPLY_PROP_CAPACITY,
@@ -3423,7 +3496,7 @@
 		val->intval = !!chip->profile_loaded;
 		break;
 	case POWER_SUPPLY_PROP_CHARGE_COUNTER:
-		val->intval = fg_get_coulomb_count(chip);
+		val->intval = fg_get_current_cc(chip);
 		break;
 	default:
 		return -EINVAL;
@@ -3622,13 +3695,11 @@
 
 #define CC_SOC_BASE_REG		0x5BC
 #define CC_SOC_OFFSET		3
-#define CC_SOC_MAGNITUDE_MASK	0x1FFFFFFF
-#define CC_SOC_NEGATIVE_BIT	BIT(28)
 static int fg_get_cc_soc(struct fg_chip *chip, int *cc_soc)
 {
 	int rc;
 	u8 reg[4];
-	unsigned int temp, magnitude;
+	int temp;
 
 	rc = fg_mem_read(chip, reg, CC_SOC_BASE_REG, 4, CC_SOC_OFFSET, 0);
 	if (rc) {
@@ -3637,15 +3708,30 @@
 	}
 
 	temp = reg[3] << 24 | reg[2] << 16 | reg[1] << 8 | reg[0];
-	magnitude = temp & CC_SOC_MAGNITUDE_MASK;
-	if (temp & CC_SOC_NEGATIVE_BIT)
-		*cc_soc = -1 * (~magnitude + 1);
-	else
-		*cc_soc = magnitude;
-
+	*cc_soc = sign_extend32(temp, 29);
 	return 0;
 }
 
+static int fg_get_current_cc(struct fg_chip *chip)
+{
+       int cc_soc, rc;
+
+       if (!(chip->wa_flag & USE_CC_SOC_REG))
+               return chip->learning_data.cc_uah;
+
+       if (!chip->learning_data.learned_cc_uah)
+               return -EINVAL;
+
+       rc = fg_get_cc_soc(chip, &cc_soc);
+       if (rc < 0) {
+               pr_err("Failed to get cc_soc, rc=%d\n", rc);
+               return rc;
+       }
+
+       return DIV_ROUND_CLOSEST(cc_soc * chip->learning_data.learned_cc_uah,
+               FULL_PERCENT_28BIT);
+}
+
 #define BATT_MISSING_STS BIT(6)
 static bool is_battery_missing(struct fg_chip *chip)
 {
@@ -4019,6 +4105,17 @@
 		}
 
 		fg_cap_learning_stop(chip);
+	} else if (chip->status == POWER_SUPPLY_STATUS_FULL) {
+		if (chip->wa_flag & USE_CC_SOC_REG) {
+			/* reset SW_CC_SOC register to 100% upon charge_full */
+			rc = fg_mem_write(chip, (u8 *)&cc_pc_100,
+				CC_SOC_BASE_REG, 4, CC_SOC_OFFSET, 0);
+			if (rc)
+				pr_err("Failed to reset CC_SOC_REG rc=%d\n",
+								rc);
+			else if (fg_debug_mask & FG_STATUS)
+				pr_info("Reset SW_CC_SOC to full value\n");
+		}
 	}
 
 fail:
@@ -4026,17 +4123,6 @@
 	return rc;
 }
 
-static int fg_get_coulomb_count(struct fg_chip *chip)
-{
-	int cc_pc_val;
-
-	if (fg_get_cc_soc(chip, &cc_pc_val))
-		return 0;
-
-	return div64_s64(chip->batt_capacity_mah * (int64_t) cc_pc_val,
-			 FULL_PERCENT_28BIT / 1000);
-}
-
 static bool is_usb_present(struct fg_chip *chip)
 {
 	union power_supply_propval prop = {0,};
@@ -4125,7 +4211,7 @@
 				struct fg_chip,
 				status_change_work);
 	unsigned long current_time = 0;
-	int cc_soc, rc, capacity = get_prop_capacity(chip);
+	int cc_soc, batt_soc, rc, capacity = get_prop_capacity(chip);
 	bool batt_missing = is_battery_missing(chip);
 
 	if (batt_missing) {
@@ -4180,6 +4266,26 @@
 
 	if (chip->prev_status != chip->status && chip->last_sram_update_time) {
 		/*
+		 * Reset SW_CC_SOC to a value based off battery SOC when
+		 * the device is discharging.
+		 */
+		if (chip->status == POWER_SUPPLY_STATUS_DISCHARGING) {
+			batt_soc = get_battery_soc_raw(chip);
+			if (!batt_soc)
+				return;
+
+			batt_soc = div64_s64((int64_t)batt_soc *
+					FULL_PERCENT_28BIT, FULL_PERCENT_3B);
+			rc = fg_mem_write(chip, (u8 *)&batt_soc,
+				CC_SOC_BASE_REG, 4, CC_SOC_OFFSET, 0);
+			if (rc)
+				pr_err("Failed to reset CC_SOC_REG rc=%d\n",
+									rc);
+			else if (fg_debug_mask & FG_STATUS)
+				pr_info("Reset SW_CC_SOC to %x\n", batt_soc);
+		}
+
+		/*
 		 * Schedule the update_temp_work whenever there is a status
 		 * change. This is essential for applying the slope limiter
 		 * coefficients when that feature is enabled.
@@ -4220,6 +4326,7 @@
 					chip->sw_cc_soc_data.init_cc_soc);
 		}
 	}
+
 	if ((chip->wa_flag & USE_CC_SOC_REG) && chip->bad_batt_detection_en
 			&& chip->safety_timer_expired) {
 		chip->sw_cc_soc_data.delta_soc =
@@ -4483,7 +4590,7 @@
 		chip->safety_timer_expired = val->intval;
 		schedule_work(&chip->status_change_work);
 		break;
-	case POWER_SUPPLY_PROP_HI_POWER:
+        case POWER_SUPPLY_PROP_HI_POWER:
 		if (chip->wa_flag & BCL_HI_POWER_FOR_CHGLED_WA) {
 			chip->bcl_lpm_disabled = !!val->intval;
 			schedule_work(&chip->bcl_hi_power_work);
@@ -5134,6 +5241,10 @@
 	if (fg_debug_mask & FG_IRQS)
 		pr_info("triggered 0x%x\n", soc_rt_sts);
 
+	rc = fg_check_system_config(chip);
+	if (rc)
+		pr_err("Failed to check system config rc=%d\n", rc);
+
 	if (chip->dischg_gain.enable) {
 		fg_stay_awake(&chip->dischg_gain_wakeup_source);
 		schedule_work(&chip->dischg_gain_work);
@@ -7237,9 +7348,10 @@
 				return rc;
 			}
 
-			rc = devm_request_irq(chip->dev,
-				chip->soc_irq[FULL_SOC].irq,
-				fg_soc_irq_handler, IRQF_TRIGGER_RISING,
+			rc = devm_request_threaded_irq(chip->dev,
+				chip->soc_irq[FULL_SOC].irq, NULL,
+				fg_soc_irq_handler,
+				IRQF_TRIGGER_RISING | IRQF_ONESHOT,
 				"full-soc", chip);
 			if (rc < 0) {
 				pr_err("Can't request %d full-soc: %d\n",
@@ -7262,9 +7374,10 @@
 				}
 			}
 
-			rc = devm_request_irq(chip->dev,
-				chip->soc_irq[DELTA_SOC].irq,
-				fg_soc_irq_handler, IRQF_TRIGGER_RISING,
+			rc = devm_request_threaded_irq(chip->dev,
+				chip->soc_irq[DELTA_SOC].irq, NULL,
+				fg_soc_irq_handler,
+				IRQF_TRIGGER_RISING | IRQF_ONESHOT,
 				"delta-soc", chip);
 			if (rc < 0) {
 				pr_err("Can't request %d delta-soc: %d\n",
@@ -7929,7 +8042,6 @@
 	return 0;
 }
 
-#define FG_ALG_SYSCTL_1			0x4B0
 #define KI_COEFF_PRED_FULL_ADDR		0x408
 #define TEMP_FRAC_SHIFT_REG		0x4A4
 #define FG_ADC_CONFIG_REG		0x4B8
@@ -8074,6 +8186,12 @@
 		pr_info("rslow_comp active is %sabled\n",
 			chip->rslow_comp.active ? "en" : "dis");
 
+	rc = fg_check_system_config(chip);
+	if (rc) {
+		pr_err("Failed to check system config rc=%d\n", rc);
+		return rc;
+	}
+
 	/*
 	 * Clear bits 0-2 in 0x4B3 and set them again to make empty_soc irq
 	 * trigger again.
@@ -8219,7 +8337,7 @@
 		/* Setup workaround flag based on PMIC type */
 		if (fg_sense_type == INTERNAL_CURRENT_SENSE)
 			chip->wa_flag |= IADC_GAIN_COMP_WA;
-		if (chip->pmic_revision[REVID_DIG_MAJOR] > 1)
+		if (chip->pmic_revision[REVID_DIG_MAJOR] >= 1)
 			chip->wa_flag |= USE_CC_SOC_REG;
 
 		break;
diff --git a/drivers/power/qpnp-smbcharger.c b/drivers/power/qpnp-smbcharger.c
index 702977b..14642fc 100644
--- a/drivers/power/qpnp-smbcharger.c
+++ b/drivers/power/qpnp-smbcharger.c
@@ -274,6 +274,7 @@
 	u32				vchg_adc_channel;
 	struct qpnp_vadc_chip		*vchg_vadc_dev;
 #ifdef CONFIG_HTC_BATT
+	struct work_struct		clean_tcc_WA;
 	struct work_struct		usb_aicl_limit_current;
 	struct delayed_work		usb_limit_max_current;
 	struct delayed_work		rerun_apsd_work;
@@ -282,6 +283,7 @@
 	struct delayed_work		force_hvdcp_work;
 	struct delayed_work             sink_current_change_work;
 	struct work_struct		hvdcp_redet_work;
+	struct work_struct		reset_batfet_work;
 	struct usb_typec_ctrl           utc;
 	u32				htc_wa_flags;
 #endif /* CONFIG_HTC_BATT */
@@ -309,6 +311,7 @@
 #define SKIP_HARD_LIMIT_CHECK_VBAT_MV	3900
 static struct smbchg_chip *the_chip;
 static bool g_is_batt_full_eoc_stop = false;
+static bool g_batfet_keep_close_wa = false;
 static void handle_usb_insertion(struct smbchg_chip *chip);
 
 
@@ -1366,6 +1369,152 @@
 	else
 		return false;
 }
+
+#define I_TERM_BIT			BIT(3)
+#define CHGR_CFG2			0xFC
+static int smbchg_charging_en(struct smbchg_chip *chip, bool en);
+static int pmi8996_charger_reset_batfet(struct smbchg_chip *chip)
+{
+	int rc = 0;
+
+	/* Force open/close batfet to keep charging battery */
+	rc = smbchg_charging_en(chip, false);
+	if (rc < 0) {
+		dev_err(chip->dev,
+			"Couldn't disable charging: rc = %d\n", rc);
+		return rc;
+	}
+
+	/* delay for charging-disable to take affect */
+	msleep(200);
+
+	rc = smbchg_charging_en(chip, true);
+	if (rc < 0) {
+		dev_err(chip->dev,
+			"Couldn't enable charging: rc = %d\n", rc);
+		return rc;
+	}
+
+	return rc;
+}
+
+static int pmi8996_charger_termination_control(bool enable)
+{
+	int rc = 0;
+	struct smbchg_chip *chip = the_chip;
+
+	if (!the_chip) {
+		pr_err("called before init\n");
+		return -ENODEV;
+	}
+
+	if (enable) {
+		/* Enable charger termination mechanism*/
+		rc = smbchg_sec_masked_write(chip, chip->chgr_base + CHGR_CFG2,
+			I_TERM_BIT, 0);
+		if (rc < 0) {
+			dev_err(chip->dev,
+				"Couldn't set I_TERM_BIT rc=%d\n", rc);
+			return rc;
+		}
+	} else {
+		/* Disable charger termination mechanism*/
+		rc = smbchg_sec_masked_write(chip, chip->chgr_base + CHGR_CFG2,
+			I_TERM_BIT, I_TERM_BIT);
+		if (rc < 0) {
+			dev_err(chip->dev,
+				"Couldn't set I_TERM_BIT rc=%d\n", rc);
+			return rc;
+		}
+	}
+
+	return rc;
+}
+
+void smbchg_reset_batfet_worker(struct work_struct *work)
+{
+	int rc = 0;
+	struct smbchg_chip *chip = container_of(work,
+						struct smbchg_chip,
+						reset_batfet_work);
+
+	rc = pmi8996_charger_reset_batfet(chip);
+	if (rc < 0) {
+		dev_err(chip->dev, "unable to reset batfet rc=%d\n", rc);
+	}
+}
+
+#define HOT_BAT_HARD_BIT	BIT(0)
+#define COLD_BAT_HARD_BIT	BIT(2)
+int pmi8996_charger_batfet_switch(bool enable)
+{
+	int rc = 0;
+	u8 chgr_rt_reg = 0, batif_rt_reg = 0;
+	struct smbchg_chip *chip = the_chip;
+
+	if (!the_chip) {
+		pr_err("called before init\n");
+		return -ENODEV;
+	}
+
+	if (g_batfet_keep_close_wa == enable) {
+		pr_smb(PR_STATUS, "Batfet WA %d->%d, do nothing\n",
+			g_batfet_keep_close_wa, enable);
+		return 0;
+	}
+
+	rc = smbchg_read(chip, &batif_rt_reg, chip->bat_if_base + RT_STS, 1);
+	if (rc < 0) {
+		dev_err(chip->dev, "Unable to read batif_RT_STS rc = %d\n", rc);
+		return rc;
+	}
+
+	if ((batif_rt_reg & HOT_BAT_HARD_BIT) ||
+	    (batif_rt_reg & COLD_BAT_HARD_BIT)) {
+		pr_smb(PR_STATUS,
+		       "Not enable WA due to batt is_hot=%d, is_cold=%d\n",
+		       chip->batt_hot, chip->batt_cold);
+		return 0;
+	}
+
+	rc = smbchg_read(chip, &chgr_rt_reg, chip->chgr_base + RT_STS, 1);
+	if (rc < 0) {
+		dev_err(chip->dev, "Unable to read chgr_RT_STS rc = %d\n", rc);
+		return rc;
+	}
+
+	pr_smb(PR_STATUS, "Batfet WA %d->%d, chgr_RT_STS=0x%X, batif_RT_STS=0x%X\n",
+	       g_batfet_keep_close_wa, enable, chgr_rt_reg, batif_rt_reg);
+
+	if (enable) {
+		/* Disable charger termination mechanism */
+		rc = pmi8996_charger_termination_control(false);
+		if (rc < 0) {
+			dev_err(chip->dev,
+				"unable to set charger termination control to false rc=%d\n",
+				rc);
+			return rc;
+		}
+		if (chgr_rt_reg & BAT_TCC_REACHED_BIT) {
+			schedule_work(&chip->reset_batfet_work);
+		}
+	} else {
+		/* Enable charger termination mechanism */
+		rc = pmi8996_charger_termination_control(true);
+		if (rc < 0) {
+			dev_err(chip->dev,
+				"unable to set charger terminaltion to true rc=%d\n",
+				rc);
+			return rc;
+		}
+		if (chgr_rt_reg & BAT_TCC_REACHED_BIT) {
+			schedule_work(&chip->reset_batfet_work);
+		}
+	}
+
+	g_batfet_keep_close_wa = enable;
+	return rc;
+}
 #endif /* CONFIG_HTC_BATT */
 
 static int get_prop_batt_health(struct smbchg_chip *chip)
@@ -7024,8 +7173,10 @@
 #ifdef CONFIG_HTC_BATT
 	if (chip->batt_warm)
 		set_property_on_fg(chip, POWER_SUPPLY_PROP_WARM_TEMP, TEMP_WARM_TO_NORMAL);
-	else
+	else {
 		set_property_on_fg(chip, POWER_SUPPLY_PROP_WARM_TEMP, TEMP_NORMAL_TO_WARM);
+		schedule_work(&chip->clean_tcc_WA);
+	}
 #endif /* CONFIG_HTC_BATT */
 	return IRQ_HANDLED;
 }
@@ -7111,6 +7262,51 @@
 }
 
 #ifdef CONFIG_HTC_BATT
+#define DISCHARGE_WINDOW_MS	200
+#define VFLOAT_COMP_WARM	0x10	// 0x10F4[5:0] - 0x10 = 4.1V
+#define VFLOAT_VOTLAGE_UV	4400000
+static void smbchg_clean_tcc_WA_work(struct work_struct *work)
+{
+	int level = 0;
+	int vbat_uv = 0;
+	u8 reg = 0;
+	int rc;
+
+	if(!the_chip) {
+		pr_err("called before init\n");
+		return;
+	}
+
+	level = htc_battery_level_adjust();
+	vbat_uv = get_prop_batt_voltage_now(the_chip);
+
+	/* Only execute WA while below conditions are all true */
+	/* Condition#1: Cable inserted */
+	if (the_chip->usb_supply_type == POWER_SUPPLY_TYPE_UNKNOWN) {
+		pr_smb(PR_STATUS, "Skip, no cable inserted.\n");
+		return;
+	}
+
+	/* Condition#2: VFLOAT COMP level not at WARM (4.1V) */
+	if (the_chip->float_voltage_comp == VFLOAT_COMP_WARM) {
+		pr_smb(PR_STATUS, "Skip, float_voltage_comp == %d.\n",
+				VFLOAT_COMP_WARM);
+		return;
+	}
+
+	/* Condition#3: TCC (0x1010 BIT7) is raised */
+	rc = smbchg_read(the_chip, &reg, the_chip->chgr_base + RT_STS, 1);
+	if (rc < 0) {
+		dev_err(the_chip->dev, "Unable to read RT_STS rc = %d\n", rc);
+		return;
+	}
+	if (reg & BAT_TCC_REACHED_BIT) {
+		pr_smb(PR_STATUS, "Reset batfet to clear incorrect TCC\n");
+		pmi8996_charger_reset_batfet(the_chip);
+	}
+	return;
+}
+
 static void smbchg_usb_limit_current_WA_work(struct work_struct *work)
 {
 	int rc = 0;
@@ -9540,6 +9736,8 @@
 
 	pr_smb(PR_STATUS, "set vfloat comp = %d\n",vfloat_comp);
 	rc = smbchg_float_voltage_comp_set(the_chip, vfloat_comp);
+	the_chip->float_voltage_comp = vfloat_comp;
+
 	if (rc) {
 		pr_err("Unable to set float_voltage_comp rc=%d\n", rc);
 		return -EINVAL;
@@ -9788,10 +9986,10 @@
 	printk(KERN_INFO "[BATT][SMBCHG] "
 		"0x1010=%02x,0x1210=%02x,0x1242=%02x,0x1310=%02x,0x1340=%02x,0x1608=%02x,0x1610=%02x,"
 		"cc=%duAh,warm_temp=%d,cool_temp=%d,pmic=rev%d.%d,sink_current=%d,pd_chgr=%d,"
-		"wake_reason=%d,smb_curr=%dmA\n",
+		"wake_reason=%d,smb_curr=%dmA,batfet_wa=%d\n",
 		chgr_rt_sts,bat_if_rt_sts,bat_if_cmd,chgpth_rt_sts,chgpth_cmd,pmic_chg_type,misc_rt_sts,
 		cc_uah,warm_temp,cool_temp,pmic_revid_rev4,pmic_revid_rev3,sink_current,(int)pd_charger,
-		wake_reason,smb_current);
+		wake_reason,smb_current,g_batfet_keep_close_wa);
 
 	smbchg_dump_reg();
 
@@ -10142,6 +10340,7 @@
 	INIT_DELAYED_WORK(&chip->vfloat_adjust_work, smbchg_vfloat_adjust_work);
 	INIT_DELAYED_WORK(&chip->hvdcp_det_work, smbchg_hvdcp_det_work);
 #ifdef CONFIG_HTC_BATT
+	INIT_WORK(&chip->clean_tcc_WA, smbchg_clean_tcc_WA_work);
 	INIT_WORK(&chip->usb_aicl_limit_current, smbchg_usb_limit_current_WA_work);
 	INIT_DELAYED_WORK(&chip->usb_limit_max_current, smbchg_usb_limit_max_current_work);
 	INIT_DELAYED_WORK(&chip->rerun_apsd_work, smbchg_rerun_apsd_worker);
@@ -10150,6 +10349,7 @@
 	INIT_DELAYED_WORK(&chip->force_hvdcp_work, smbchg_force_hvdcp_worker);
 	INIT_DELAYED_WORK(&chip->sink_current_change_work, smbchg_sink_current_change_worker);
 	INIT_WORK(&chip->hvdcp_redet_work, smbchg_hvdcp_redet_worker);
+	INIT_WORK(&chip->reset_batfet_work, smbchg_reset_batfet_worker);
 #endif /* CONFIG_HTC_BATT */
 	init_completion(&chip->src_det_lowered);
 	init_completion(&chip->src_det_raised);
diff --git a/drivers/soc/qcom/rpm-smd.c b/drivers/soc/qcom/rpm-smd.c
index 209e5c6..3504665 100644
--- a/drivers/soc/qcom/rpm-smd.c
+++ b/drivers/soc/qcom/rpm-smd.c
@@ -81,7 +81,7 @@
 #define DEFAULT_BUFFER_SIZE 256
 #define DEBUG_PRINT_BUFFER_SIZE 512
 #define MAX_SLEEP_BUFFER 128
-#define GFP_FLAG(noirq) (noirq ? GFP_ATOMIC : GFP_NOFS)
+#define GFP_FLAG(noirq) (noirq ? GFP_ATOMIC : GFP_NOIO)
 #define INV_RSC "resource does not exist"
 #define ERR "err\0"
 #define MAX_ERR_BUFFER_SIZE 128
diff --git a/drivers/soc/qcom/subsystem_restart.c b/drivers/soc/qcom/subsystem_restart.c
index 20b4175..97f9584 100644
--- a/drivers/soc/qcom/subsystem_restart.c
+++ b/drivers/soc/qcom/subsystem_restart.c
@@ -33,6 +33,7 @@
 #include <linux/of_gpio.h>
 #include <linux/cdev.h>
 #include <linux/platform_device.h>
+#include <linux/rtc.h>
 #include <soc/qcom/subsystem_restart.h>
 #include <soc/qcom/subsystem_notif.h>
 #include <soc/qcom/socinfo.h>
@@ -228,10 +229,13 @@
 static ssize_t crash_reason_show(struct device *dev,
 				struct device_attribute *attr, char *buf)
 {
-	if(is_ramdump_enabled(to_subsys(dev)))
-		return snprintf(buf, PAGE_SIZE, "%s\n", to_subsys(dev)->desc->last_crash_reason);
+	return snprintf(buf, PAGE_SIZE, "%s\n", to_subsys(dev)->desc->last_crash_reason);
+}
 
-	return snprintf(buf, PAGE_SIZE, "\n");
+static ssize_t crash_timestamp_show(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%s\n", to_subsys(dev)->desc->last_crash_timestamp);
 }
 
 static ssize_t
@@ -359,6 +363,7 @@
 	__ATTR_RO(state),
 	__ATTR_RO(crash_count),
 	__ATTR_RO(crash_reason),
+	__ATTR_RO(crash_timestamp),
 	__ATTR(restart_level, 0644, restart_level_show, restart_level_store),
 	__ATTR(firmware_name, 0644, firmware_name_show, firmware_name_store),
 	__ATTR(system_debug, 0644, system_debug_show, system_debug_store),
@@ -629,11 +634,21 @@
 static void subsystem_shutdown(struct subsys_device *dev, void *data)
 {
 	const char *name = dev->desc->name;
+	char *timestamp = dev->desc->last_crash_timestamp;
+	struct timespec ts_rtc;
+	struct rtc_time tm;
 
 	pr_info("[%p]: Shutting down %s\n", current, name);
 	if (dev->desc->shutdown(dev->desc, true) < 0)
 		panic("subsys-restart: [%p]: Failed to shutdown %s!",
 			current, name);
+
+	/* record crash time */
+	getnstimeofday(&ts_rtc);
+	rtc_time_to_tm(ts_rtc.tv_sec - (sys_tz.tz_minuteswest * 60), &tm);
+	snprintf(timestamp, MAX_CRASH_TIMESTAMP_LEN, "%d-%02d-%02d_%02d-%02d-%02d",
+		tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
+
 	dev->crash_count++;
 	subsys_set_state(dev, SUBSYS_OFFLINE);
 	disable_all_irqs(dev);
diff --git a/drivers/staging/nanohub/main.c b/drivers/staging/nanohub/main.c
index c733b1a..8078c44 100644
--- a/drivers/staging/nanohub/main.c
+++ b/drivers/staging/nanohub/main.c
@@ -49,9 +49,11 @@
 #define WAKEUP_INTERRUPT	1
 #define WAKEUP_TIMEOUT_MS	1000
 #define SUSPEND_TIMEOUT_MS	100
-#define ERR_RESET_TIME_SEC	60
-#define ERR_RESET_COUNT		70
-#define ERR_WARNING_COUNT	10
+#define KTHREAD_ERR_TIME_NS	(60LL * NSEC_PER_SEC)
+#define KTHREAD_ERR_CNT		70
+#define KTHREAD_WARN_CNT	10
+#define WAKEUP_ERR_TIME_NS	(60LL * NSEC_PER_SEC)
+#define WAKEUP_ERR_CNT		4
 
 /**
  * struct gpio_config - this is a binding between platform data and driver data
@@ -87,9 +89,9 @@
 static ssize_t nanohub_write(struct file *, const char *, size_t, loff_t *);
 static unsigned int nanohub_poll(struct file *, poll_table *);
 static int nanohub_release(struct inode *, struct file *);
+static int nanohub_hw_reset(struct nanohub_data *data);
 
 static struct class *sensor_class;
-static struct timespec first_err_ts;
 static int major;
 
 static const struct gpio_config gconf[] = {
@@ -299,6 +301,11 @@
 	return atomic_read(&data->thread_state);
 }
 
+static inline void nanohub_clear_err_cnt(struct nanohub_data *data)
+{
+	data->kthread_err_cnt = data->wakeup_err_cnt = 0;
+}
+
 /* the following fragment is based on wait_event_* code from wait.h */
 #define wait_event_interruptible_timeout_locked(q, cond, tmo)		\
 ({									\
@@ -344,6 +351,10 @@
 {
 	long timeout;
 	bool priority_lock = lock_mode > LOCK_MODE_NORMAL;
+	struct device *sensor_dev = data->io[ID_NANOHUB_SENSOR].dev;
+	int ret;
+	ktime_t ktime_delta;
+	ktime_t wakeup_ktime;
 
 	spin_lock(&data->wakeup_wait.lock);
 	mcu_wakeup_gpio_get_locked(data, priority_lock);
@@ -351,6 +362,8 @@
 		   msecs_to_jiffies(timeout_ms) :
 		   MAX_SCHEDULE_TIMEOUT;
 
+	if (!priority_lock && !data->wakeup_err_cnt)
+		wakeup_ktime = ktime_get_boottime();
 	timeout = wait_event_interruptible_timeout_locked(
 			data->wakeup_wait,
 			((priority_lock || nanohub_irq1_fired(data)) &&
@@ -359,11 +372,33 @@
 		  );
 
 	if (timeout <= 0) {
+		if (!timeout && !priority_lock) {
+			if (!data->wakeup_err_cnt)
+				data->wakeup_err_ktime = wakeup_ktime;
+			ktime_delta = ktime_sub(ktime_get_boottime(),
+						data->wakeup_err_ktime);
+			data->wakeup_err_cnt++;
+			if (ktime_to_ns(ktime_delta) > WAKEUP_ERR_TIME_NS
+				&& data->wakeup_err_cnt > WAKEUP_ERR_CNT) {
+				mcu_wakeup_gpio_put_locked(data, priority_lock);
+				spin_unlock(&data->wakeup_wait.lock);
+				dev_info(sensor_dev,
+					"wakeup: hard reset due to consistent error\n");
+				ret = nanohub_hw_reset(data);
+				if (ret) {
+					dev_info(sensor_dev,
+						"%s: failed to reset nanohub: ret=%d\n",
+						__func__, ret);
+				}
+				return -ETIME;
+			}
+		}
 		mcu_wakeup_gpio_put_locked(data, priority_lock);
 
 		if (timeout == 0)
 			timeout = -ETIME;
 	} else {
+		data->wakeup_err_cnt = 0;
 		timeout = 0;
 	}
 	spin_unlock(&data->wakeup_wait.lock);
@@ -471,7 +506,7 @@
 	struct nanohub_data *data = dev_get_nanohub_data(dev);
 	const struct nanohub_platform_data *pdata = data->pdata;
 
-	data->err_cnt = 0;
+	nanohub_clear_err_cnt(data);
 	if (nanohub_irq1_fired(data) || nanohub_irq2_fired(data))
 		wake_up_interruptible(&data->wakeup_wait);
 
@@ -612,6 +647,7 @@
 		usleep_range(70000, 75000);
 	else if (!boot0)
 		usleep_range(750000, 800000);
+	nanohub_clear_err_cnt(data);
 }
 
 static int nanohub_hw_reset(struct nanohub_data *data)
@@ -620,7 +656,6 @@
 	ret = nanohub_wakeup_lock(data, LOCK_MODE_RESET);
 
 	if (!ret) {
-		data->err_cnt = 0;
 		__nanohub_hw_reset(data, 0);
 		nanohub_wakeup_unlock(data);
 	}
@@ -652,7 +687,6 @@
 	if (ret < 0)
 		return ret;
 
-	data->err_cnt = 0;
 	__nanohub_hw_reset(data, 1);
 
 	status = nanohub_bl_erase_shared(data);
@@ -677,7 +711,6 @@
 	if (ret < 0)
 		return ret;
 
-	data->err_cnt = 0;
 	__nanohub_hw_reset(data, -1);
 
 	status = nanohub_bl_erase_shared_bl(data);
@@ -703,7 +736,6 @@
 	if (ret < 0)
 		return ret;
 
-	data->err_cnt = 0;
 	__nanohub_hw_reset(data, 1);
 
 	ret = request_firmware(&fw_entry, "nanohub.full.bin", dev);
@@ -763,7 +795,6 @@
 		if (ret < 0)
 			return ret;
 
-		data->err_cnt = 0;
 		__nanohub_hw_reset(data, -1);
 
 		status = nanohub_bl_erase_shared_bl(data);
@@ -891,7 +922,6 @@
 	if (ret < 0)
 		return ret;
 
-	data->err_cnt = 0;
 	__nanohub_hw_reset(data, 1);
 
 	gpio_set_value(data->pdata->boot0_gpio, 0);
@@ -917,7 +947,6 @@
 	if (ret < 0)
 		return ret;
 
-	data->err_cnt = 0;
 	__nanohub_hw_reset(data, 1);
 
 	gpio_set_value(data->pdata->boot0_gpio, 0);
@@ -1167,7 +1196,7 @@
 	bool wakeup = false;
 	struct nanohub_io *io = &data->io[ID_NANOHUB_SENSOR];
 
-	data->err_cnt = 0;
+	data->kthread_err_cnt = 0;
 	if (ret < 4 || nanohub_os_log((*buf)->buffer, ret)) {
 		release_wakeup(data);
 		return;
@@ -1204,14 +1233,14 @@
 	struct nanohub_data *data = (struct nanohub_data *)arg;
 	struct nanohub_buf *buf = NULL;
 	int ret;
-	struct timespec curr_ts;
+	ktime_t ktime_delta;
 	uint32_t clear_interrupts[8] = { 0x00000006 };
 	struct device *sensor_dev = data->io[ID_NANOHUB_SENSOR].dev;
 	static const struct sched_param param = {
 		.sched_priority = (MAX_USER_RT_PRIO/2)-1,
 	};
 
-	data->err_cnt = 0;
+	data->kthread_err_cnt = 0;
 	sched_setscheduler(current, SCHED_FIFO, &param);
 	nanohub_set_state(data, ST_IDLE);
 
@@ -1224,10 +1253,12 @@
 			nanohub_set_state(data, ST_RUNNING);
 			break;
 		case ST_ERROR:
-			get_monotonic_boottime(&curr_ts);
-			if (curr_ts.tv_sec - first_err_ts.tv_sec > ERR_RESET_TIME_SEC
-				&& data->err_cnt > ERR_RESET_COUNT) {
-				dev_info(sensor_dev, "hard reset due to consistent error\n");
+			ktime_delta = ktime_sub(ktime_get_boottime(),
+						data->kthread_err_ktime);
+			if (ktime_to_ns(ktime_delta) > KTHREAD_ERR_TIME_NS
+				&& data->kthread_err_cnt > KTHREAD_ERR_CNT) {
+				dev_info(sensor_dev,
+					"kthread: hard reset due to consistent error\n");
 				if (nanohub_hw_reset(data)) {
 					dev_info(sensor_dev,
 						"%s: failed to reset nanohub: ret=%d\n",
@@ -1266,21 +1297,23 @@
 				}
 			} else if (ret == 0) {
 				/* queue empty, go to sleep */
-				data->err_cnt = 0;
+				data->kthread_err_cnt = 0;
 				data->interrupts[0] &= ~0x00000006;
 				release_wakeup(data);
 				nanohub_set_state(data, ST_IDLE);
 				continue;
 			} else {
 				release_wakeup(data);
-				if (data->err_cnt == 0)
-					get_monotonic_boottime(&first_err_ts);
+				if (data->kthread_err_cnt == 0)
+					data->kthread_err_ktime =
+						ktime_get_boottime();
 
-				if (++data->err_cnt >= ERR_WARNING_COUNT) {
+				data->kthread_err_cnt++;
+				if (data->kthread_err_cnt >= KTHREAD_WARN_CNT) {
 					dev_err(sensor_dev,
-						"%s: err_cnt=%d\n",
+						"%s: kthread_err_cnt=%d\n",
 						__func__,
-						data->err_cnt);
+						data->kthread_err_cnt);
 					nanohub_set_state(data, ST_ERROR);
 					continue;
 				}
diff --git a/drivers/staging/nanohub/main.h b/drivers/staging/nanohub/main.h
index 71e6d5a..9fd28ab 100644
--- a/drivers/staging/nanohub/main.h
+++ b/drivers/staging/nanohub/main.h
@@ -82,7 +82,12 @@
 
 	uint32_t interrupts[8];
 
-	int err_cnt;
+	ktime_t wakeup_err_ktime;
+	int wakeup_err_cnt;
+
+	ktime_t kthread_err_ktime;
+	int kthread_err_cnt;
+
 	void *vbuf;
 	struct task_struct *thread;
 };
diff --git a/drivers/staging/qcacld-2.0/CORE/HDD/src/wlan_hdd_assoc.c b/drivers/staging/qcacld-2.0/CORE/HDD/src/wlan_hdd_assoc.c
index f353888..92c9a84 100644
--- a/drivers/staging/qcacld-2.0/CORE/HDD/src/wlan_hdd_assoc.c
+++ b/drivers/staging/qcacld-2.0/CORE/HDD/src/wlan_hdd_assoc.c
@@ -3989,8 +3989,8 @@
                 if((pHddCtx) &&
                    (VOS_TRUE == pHddStaCtx->hdd_ReassocScenario) &&
                    (TRUE == pHddCtx->hdd_wlan_suspended) &&
-                   (eCSR_ROAM_RESULT_NONE == roamResult))
-                {
+                   ((eCSR_ROAM_RESULT_NONE == roamResult)||
+                     (pRoamInfo && pRoamInfo->is11rAssoc))) {
                     /* Send DTIM period to the FW; only if the wlan is already
                        in suspend. This is the case with roaming (reassoc),
                        DELETE_BSS_REQ zeroes out Modulated/Dynamic DTIM sent in
@@ -4012,8 +4012,10 @@
                                          eSME_FULL_PWR_NEEDED_BY_HDD);
                     }
                 }
+
                 halStatus = hdd_RoamSetKeyCompleteHandler( pAdapter, pRoamInfo, roamId, roamStatus, roamResult );
-                if (eCSR_ROAM_RESULT_AUTHENTICATED == roamResult) {
+                if ((eCSR_ROAM_RESULT_NONE == roamResult) ||
+                    (pRoamInfo && pRoamInfo->is11rAssoc)) {
                     pHddStaCtx->hdd_ReassocScenario = VOS_FALSE;
                     hddLog(LOG1,
                            FL("hdd_ReassocScenario set to: %d, set key complete, session: %d"),
diff --git a/drivers/staging/qcacld-2.0/CORE/HDD/src/wlan_hdd_cfg80211.c b/drivers/staging/qcacld-2.0/CORE/HDD/src/wlan_hdd_cfg80211.c
index 9e4630a..b5a3ed0 100644
--- a/drivers/staging/qcacld-2.0/CORE/HDD/src/wlan_hdd_cfg80211.c
+++ b/drivers/staging/qcacld-2.0/CORE/HDD/src/wlan_hdd_cfg80211.c
@@ -19362,6 +19362,12 @@
     if (true == pHddStaCtx->hdd_ReassocScenario) {
         hddLog(LOG1,
                FL("Roaming is in progress, cannot continue with this request"));
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0))
+    sinfo->filled |= STATION_INFO_SIGNAL;
+#else
+    sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL);
+#endif
+        sinfo->signal = pAdapter->rssi;
         return 0;
     }
 
diff --git a/drivers/staging/qcacld-2.0/CORE/MAC/inc/qwlan_version.h b/drivers/staging/qcacld-2.0/CORE/MAC/inc/qwlan_version.h
index c6fab80..350ea13 100644
--- a/drivers/staging/qcacld-2.0/CORE/MAC/inc/qwlan_version.h
+++ b/drivers/staging/qcacld-2.0/CORE/MAC/inc/qwlan_version.h
@@ -42,9 +42,9 @@
 #define QWLAN_VERSION_MINOR            4
 #define QWLAN_VERSION_PATCH            25
 #define QWLAN_VERSION_EXTRA            ""
-#define QWLAN_VERSION_BUILD            27
+#define QWLAN_VERSION_BUILD            29
 
-#define QWLAN_VERSIONSTR               "4.4.25.027s_1"
+#define QWLAN_VERSIONSTR               "4.4.25.029"
 
 
 #define AR6320_REV1_VERSION             0x5000000
diff --git a/drivers/staging/qcacld-2.0/CORE/MAC/inc/sirApi.h b/drivers/staging/qcacld-2.0/CORE/MAC/inc/sirApi.h
index d6bdc9d..1042f82 100644
--- a/drivers/staging/qcacld-2.0/CORE/MAC/inc/sirApi.h
+++ b/drivers/staging/qcacld-2.0/CORE/MAC/inc/sirApi.h
@@ -3764,7 +3764,7 @@
  * SIR_MAC_ACTION_DLP              2      0
  * SIR_MAC_ACTION_BLKACK           3      0
  * SIR_MAC_ACTION_PUBLIC_USAGE     4      1
- * SIR_MAC_ACTION_RRM              5      1
+ * SIR_MAC_ACTION_RRM              5      0
  * SIR_MAC_ACTION_FAST_BSS_TRNST   6      0
  * SIR_MAC_ACTION_HT               7      0
  * SIR_MAC_ACTION_SA_QUERY         8      1
@@ -3784,7 +3784,6 @@
 		((1 << SIR_MAC_ACTION_SPECTRUM_MGMT) | \
 		 (1 << SIR_MAC_ACTION_QOS_MGMT) | \
 		 (1 << SIR_MAC_ACTION_PUBLIC_USAGE) | \
-		 (1 << SIR_MAC_ACTION_RRM) | \
 		 (1 << SIR_MAC_ACTION_SA_QUERY) | \
 		 (1 << SIR_MAC_ACTION_WNM) | \
 		 (1 << SIR_MAC_ACTION_WME) | \
diff --git a/drivers/staging/qcacld-2.0/CORE/MAC/src/pe/lim/limProcessActionFrame.c b/drivers/staging/qcacld-2.0/CORE/MAC/src/pe/lim/limProcessActionFrame.c
index d9edc9c..210e38b 100644
--- a/drivers/staging/qcacld-2.0/CORE/MAC/src/pe/lim/limProcessActionFrame.c
+++ b/drivers/staging/qcacld-2.0/CORE/MAC/src/pe/lim/limProcessActionFrame.c
@@ -618,7 +618,7 @@
             ch_bw = eHT_CHANNEL_WIDTH_20MHZ;
         }
         limCheckVHTOpModeChange(pMac, psessionEntry,
-                                 ch_bw,
+                                 ch_bw, MODE_MAX,
                                  pSta->staIndex, pHdr->sa);
     }
 
diff --git a/drivers/staging/qcacld-2.0/CORE/MAC/src/pe/lim/limProcessSmeReqMessages.c b/drivers/staging/qcacld-2.0/CORE/MAC/src/pe/lim/limProcessSmeReqMessages.c
index 2ae9df5..3f95ad5 100644
--- a/drivers/staging/qcacld-2.0/CORE/MAC/src/pe/lim/limProcessSmeReqMessages.c
+++ b/drivers/staging/qcacld-2.0/CORE/MAC/src/pe/lim/limProcessSmeReqMessages.c
@@ -60,7 +60,7 @@
 #include "regdomain_common.h"
 #include "rrmApi.h"
 #include "nan_datapath.h"
-
+#include "wma.h"
 #include "sapApi.h"
 
 #if defined(FEATURE_WLAN_ESE) && !defined(FEATURE_WLAN_ESE_UPLOAD)
@@ -5188,6 +5188,11 @@
             vos_mem_copy(pHtOpMode->peer_mac, &pStaDs->staAddr,
                  sizeof(tSirMacAddr));
             pHtOpMode->smesessionId = sessionId;
+            pHtOpMode->chanMode = wma_chan_to_mode(
+                                     psessionEntry->currentOperChannel,
+                                     psessionEntry->htSecondaryChannelOffset,
+                                     psessionEntry->vhtCapability,
+                                     psessionEntry->dot11mode);
 
             msg.type     = WDA_UPDATE_OP_MODE;
             msg.reserved = 0;
diff --git a/drivers/staging/qcacld-2.0/CORE/MAC/src/pe/lim/limUtils.c b/drivers/staging/qcacld-2.0/CORE/MAC/src/pe/lim/limUtils.c
index c907ef43..5296278 100644
--- a/drivers/staging/qcacld-2.0/CORE/MAC/src/pe/lim/limUtils.c
+++ b/drivers/staging/qcacld-2.0/CORE/MAC/src/pe/lim/limUtils.c
@@ -7378,11 +7378,13 @@
 
 #ifdef WLAN_FEATURE_11AC
 tANI_BOOLEAN limCheckVHTOpModeChange( tpAniSirGlobal pMac, tpPESession psessionEntry,
-                                      tANI_U8 chanWidth, tANI_U8 staId, tANI_U8 *peerMac)
+                                      tANI_U8 chanWidth, tANI_U8 chanMode,
+                                      tANI_U8 staId, tANI_U8 *peerMac)
 {
     tUpdateVHTOpMode tempParam;
 
     tempParam.opMode = chanWidth;
+    tempParam.chanMode = chanMode;
     tempParam.staId  = staId;
     tempParam.smesessionId = psessionEntry->smeSessionId;
     vos_mem_copy(tempParam.peer_mac, peerMac,
diff --git a/drivers/staging/qcacld-2.0/CORE/MAC/src/pe/lim/limUtils.h b/drivers/staging/qcacld-2.0/CORE/MAC/src/pe/lim/limUtils.h
index c91f2d7..d252ba4 100644
--- a/drivers/staging/qcacld-2.0/CORE/MAC/src/pe/lim/limUtils.h
+++ b/drivers/staging/qcacld-2.0/CORE/MAC/src/pe/lim/limUtils.h
@@ -454,7 +454,7 @@
 
 #ifdef WLAN_FEATURE_11AC
 tANI_BOOLEAN limCheckVHTOpModeChange( tpAniSirGlobal pMac, tpPESession psessionEntry,
-                                      tANI_U8 chanWidth, tANI_U8 staId, tANI_U8 *peerMac);
+                                      tANI_U8 chanWidth, tANI_U8 chanMode, tANI_U8 staId, tANI_U8 *peerMac);
 tANI_BOOLEAN limSetNssChange( tpAniSirGlobal pMac, tpPESession psessionEntry,
                               tANI_U8 rxNss, tANI_U8 staId, tANI_U8 *peerMac);
 tANI_BOOLEAN limCheckMembershipUserPosition( tpAniSirGlobal pMac, tpPESession psessionEntry,
diff --git a/drivers/staging/qcacld-2.0/CORE/MAC/src/pe/sch/schBeaconProcess.c b/drivers/staging/qcacld-2.0/CORE/MAC/src/pe/sch/schBeaconProcess.c
index cd18335..abdaab2 100644
--- a/drivers/staging/qcacld-2.0/CORE/MAC/src/pe/sch/schBeaconProcess.c
+++ b/drivers/staging/qcacld-2.0/CORE/MAC/src/pe/sch/schBeaconProcess.c
@@ -348,6 +348,8 @@
     tANI_U8  operMode;
     tANI_U8  chWidth = 0;
     tANI_U8  skip_opmode_update = false;
+    WLAN_PHY_MODE chanMode;
+    ePhyChanBondState chanOffset;
 #endif
 #if defined FEATURE_WLAN_ESE || defined WLAN_FEATURE_VOWIFI
      tPowerdBm regMax = 0,maxTxPower = 0;
@@ -500,6 +502,20 @@
        if (NULL != pStaDs && (HAL_STA_INVALID_IDX != pStaDs->staIndex ) &&
             (WNI_CFG_CHANNEL_BONDING_MODE_DISABLE != cbMode))
        {
+          if (pBeacon->HTInfo.present && pBeacon->VHTOperation.present) {
+              chanOffset = limGet11ACPhyCBState(pMac,
+                              pBeacon->channelNumber,
+                              pBeacon->HTInfo.secondaryChannelOffset,
+                              pBeacon->VHTOperation.chanCenterFreqSeg1,
+                              psessionEntry);
+              chanMode = wma_chan_to_mode(pBeacon->channelNumber,
+                              chanOffset,
+                              psessionEntry->vhtCapability,
+                              psessionEntry->dot11mode);
+          } else {
+              chanMode = MODE_MAX;
+          }
+
           if (psessionEntry->vhtCapability && pBeacon->OperatingMode.present )
           {
              operMode = pStaDs->vhtSupportedChannelWidthSet ?
@@ -564,7 +580,7 @@
                       chWidth = eHT_CHANNEL_WIDTH_20MHZ;
                    }
                 limCheckVHTOpModeChange(pMac, psessionEntry,
-                      chWidth,
+                      chWidth, chanMode,
                       pStaDs->staIndex, pMh->sa);
              }
              /* Update Nss setting */
@@ -639,7 +655,7 @@
                     }
                 }
                 limCheckVHTOpModeChange(pMac, psessionEntry,
-                        chWidth, pStaDs->staIndex, pMh->sa);
+                        chWidth, chanMode, pStaDs->staIndex, pMh->sa);
 
              }
           }
diff --git a/drivers/staging/qcacld-2.0/CORE/SERVICES/HIF/PCIe/copy_engine.c b/drivers/staging/qcacld-2.0/CORE/SERVICES/HIF/PCIe/copy_engine.c
index 7ade81b..3bfad87 100644
--- a/drivers/staging/qcacld-2.0/CORE/SERVICES/HIF/PCIe/copy_engine.c
+++ b/drivers/staging/qcacld-2.0/CORE/SERVICES/HIF/PCIe/copy_engine.c
@@ -103,7 +103,7 @@
  * trying to access the array, full locking of the recording process would
  * be needed to have sane logging.
  */
-static int get_next_record_index(adf_os_atomic_t *table_index, int array_size)
+int get_next_record_index(adf_os_atomic_t *table_index, int array_size)
 {
 	int record_index = adf_os_atomic_inc_return(table_index);
 	if (record_index == array_size)
@@ -513,10 +513,10 @@
     struct hif_pci_softc *sc = CE_state->sc;
     A_target_id_t targid = TARGID(sc);
 
-    adf_os_spin_lock(&sc->target_lock);
+    adf_os_spin_lock_bh(&sc->target_lock);
     CE_SRC_RING_LOWMARK_SET(targid, ctrl_addr, low_alert_nentries);
     CE_SRC_RING_HIGHMARK_SET(targid, ctrl_addr, high_alert_nentries);
-    adf_os_spin_unlock(&sc->target_lock);
+    adf_os_spin_unlock_bh(&sc->target_lock);
 }
 
 void
@@ -529,10 +529,10 @@
     struct hif_pci_softc *sc = CE_state->sc;
     A_target_id_t targid = TARGID(sc);
 
-    adf_os_spin_lock(&sc->target_lock);
+    adf_os_spin_lock_bh(&sc->target_lock);
     CE_DEST_RING_LOWMARK_SET(targid, ctrl_addr, low_alert_nentries);
     CE_DEST_RING_HIGHMARK_SET(targid, ctrl_addr, high_alert_nentries);
-    adf_os_spin_unlock(&sc->target_lock);
+    adf_os_spin_unlock_bh(&sc->target_lock);
 }
 
 unsigned int
@@ -545,10 +545,10 @@
     unsigned int sw_index;
     unsigned int write_index;
 
-    adf_os_spin_lock(&sc->target_lock);
+    adf_os_spin_lock_bh(&sc->target_lock);
     sw_index = src_ring->sw_index;
     write_index = src_ring->write_index;
-    adf_os_spin_unlock(&sc->target_lock);
+    adf_os_spin_unlock_bh(&sc->target_lock);
 
     return CE_RING_DELTA(nentries_mask, write_index, sw_index-1);
 }
@@ -563,10 +563,10 @@
     unsigned int sw_index;
     unsigned int write_index;
 
-    adf_os_spin_lock(&sc->target_lock);
+    adf_os_spin_lock_bh(&sc->target_lock);
     sw_index = dest_ring->sw_index;
     write_index = dest_ring->write_index;
-    adf_os_spin_unlock(&sc->target_lock);
+    adf_os_spin_unlock_bh(&sc->target_lock);
 
     return CE_RING_DELTA(nentries_mask, write_index, sw_index-1);
 }
@@ -598,9 +598,9 @@
     struct hif_pci_softc *sc = CE_state->sc;
     unsigned int nentries;
 
-    adf_os_spin_lock(&sc->target_lock);
+    adf_os_spin_lock_bh(&sc->target_lock);
     nentries = CE_send_entries_done_nolock(sc, CE_state);
-    adf_os_spin_unlock(&sc->target_lock);
+    adf_os_spin_unlock_bh(&sc->target_lock);
 
     return nentries;
 }
@@ -632,9 +632,9 @@
     struct hif_pci_softc *sc = CE_state->sc;
     unsigned int nentries;
 
-    adf_os_spin_lock(&sc->target_lock);
+    adf_os_spin_lock_bh(&sc->target_lock);
     nentries = CE_recv_entries_done_nolock(sc, CE_state);
-    adf_os_spin_unlock(&sc->target_lock);
+    adf_os_spin_unlock_bh(&sc->target_lock);
 
     return nentries;
 }
@@ -762,7 +762,7 @@
     }
 
     sc = CE_state->sc;
-    adf_os_spin_lock(&sc->target_lock);
+    adf_os_spin_lock_bh(&sc->target_lock);
     nentries_mask = dest_ring->nentries_mask;
     sw_index = dest_ring->sw_index;
     write_index = dest_ring->write_index;
@@ -790,7 +790,7 @@
     } else {
         status = A_ERROR;
     }
-    adf_os_spin_unlock(&sc->target_lock);
+    adf_os_spin_unlock_bh(&sc->target_lock);
 
     return status;
 }
@@ -896,7 +896,7 @@
     }
 
     sc = CE_state->sc;
-    adf_os_spin_lock(&sc->target_lock);
+    adf_os_spin_lock_bh(&sc->target_lock);
     nentries_mask = src_ring->nentries_mask;
     sw_index = src_ring->sw_index;
     write_index = src_ring->write_index;
@@ -927,7 +927,7 @@
     } else {
         status = A_ERROR;
     }
-    adf_os_spin_unlock(&sc->target_lock);
+    adf_os_spin_unlock_bh(&sc->target_lock);
 
     return status;
 }
@@ -1061,7 +1061,7 @@
 
     A_TARGET_ACCESS_BEGIN(targid);
 
-    adf_os_spin_lock(&sc->target_lock);
+    adf_os_spin_lock_bh(&sc->target_lock);
 
     /* Clear force_break flag and re-initialize receive_count to 0 */
     sc->receive_count = 0;
@@ -1073,7 +1073,7 @@
         while (CE_completed_recv_next_nolock(CE_state, &CE_context, &transfer_context,
                     &buf, &nbytes, &id, &flags) == A_OK)
         {
-                adf_os_spin_unlock(&sc->target_lock);
+                adf_os_spin_unlock_bh(&sc->target_lock);
                 CE_state->recv_cb((struct CE_handle *)CE_state, CE_context, transfer_context,
                                     buf, nbytes, id, flags);
 
@@ -1092,7 +1092,7 @@
                     A_TARGET_ACCESS_END(targid);
                     return;
                 }
-                adf_os_spin_lock(&sc->target_lock);
+                adf_os_spin_lock_bh(&sc->target_lock);
         }
     }
 
@@ -1110,10 +1110,10 @@
 
             if(CE_id != CE_HTT_H2T_MSG ||
                     WLAN_IS_EPPING_ENABLED(vos_get_conparam())){
-                adf_os_spin_unlock(&sc->target_lock);
+                adf_os_spin_unlock_bh(&sc->target_lock);
                 CE_state->send_cb((struct CE_handle *)CE_state, CE_context, transfer_context, buf, nbytes, id,
                                   sw_idx, hw_idx);
-                adf_os_spin_lock(&sc->target_lock);
+                adf_os_spin_lock_bh(&sc->target_lock);
             }else{
                 struct HIF_CE_pipe_info *pipe_info = (struct HIF_CE_pipe_info *)CE_context;
 
@@ -1125,10 +1125,10 @@
 #else  /*ATH_11AC_TXCOMPACT*/
         while (CE_completed_send_next_nolock(CE_state, &CE_context, &transfer_context,
                     &buf, &nbytes, &id, &sw_idx, &hw_idx) == A_OK){
-            adf_os_spin_unlock(&sc->target_lock);
+            adf_os_spin_unlock_bh(&sc->target_lock);
             CE_state->send_cb((struct CE_handle *)CE_state, CE_context, transfer_context, buf, nbytes, id,
                               sw_idx, hw_idx);
-            adf_os_spin_lock(&sc->target_lock);
+            adf_os_spin_lock_bh(&sc->target_lock);
         }
 #endif /*ATH_11AC_TXCOMPACT*/
     }
@@ -1139,12 +1139,12 @@
         if (CE_int_status & CE_WATERMARK_MASK) {
             if (CE_state->watermark_cb) {
 
-                adf_os_spin_unlock(&sc->target_lock);
+                adf_os_spin_unlock_bh(&sc->target_lock);
                 /* Convert HW IS bits to software flags */
                 flags = (CE_int_status & CE_WATERMARK_MASK) >> CE_WM_SHFT;
 
                 CE_state->watermark_cb((struct CE_handle *)CE_state, CE_state->wm_context, flags);
-                adf_os_spin_lock(&sc->target_lock);
+                adf_os_spin_lock_bh(&sc->target_lock);
             }
         }
     }
@@ -1201,7 +1201,7 @@
         }
     }
 
-    adf_os_spin_unlock(&sc->target_lock);
+    adf_os_spin_unlock_bh(&sc->target_lock);
     adf_os_atomic_set(&CE_state->rx_pending, 0);
     A_TARGET_ACCESS_END(targid);
 }
@@ -1346,18 +1346,18 @@
 void
 CE_disable_any_copy_compl_intr(struct hif_pci_softc *sc)
 {
-	adf_os_spin_lock(&sc->target_lock);
+	adf_os_spin_lock_bh(&sc->target_lock);
 	CE_disable_any_copy_compl_intr_nolock(sc);
-	adf_os_spin_unlock(&sc->target_lock);
+	adf_os_spin_unlock_bh(&sc->target_lock);
 }
 
 /*Re-enable the copy compl interrupt if it has not been disabled before.*/
 void
 CE_enable_any_copy_compl_intr(struct hif_pci_softc *sc)
 {
-	adf_os_spin_lock(&sc->target_lock);
+	adf_os_spin_lock_bh(&sc->target_lock);
 	CE_enable_any_copy_compl_intr_nolock(sc);
-	adf_os_spin_unlock(&sc->target_lock);
+	adf_os_spin_unlock_bh(&sc->target_lock);
 }
 
 void
@@ -1369,11 +1369,11 @@
     struct CE_state *CE_state = (struct CE_state *)copyeng;
     struct hif_pci_softc *sc = CE_state->sc;
 
-    adf_os_spin_lock(&sc->target_lock);
+    adf_os_spin_lock_bh(&sc->target_lock);
     CE_state->send_cb = fn_ptr;
     CE_state->send_context = CE_send_context;
     CE_per_engine_handler_adjust(CE_state, disable_interrupts);
-    adf_os_spin_unlock(&sc->target_lock);
+    adf_os_spin_unlock_bh(&sc->target_lock);
 }
 
 void
@@ -1385,11 +1385,11 @@
     struct CE_state *CE_state = (struct CE_state *)copyeng;
     struct hif_pci_softc *sc = CE_state->sc;
 
-    adf_os_spin_lock(&sc->target_lock);
+    adf_os_spin_lock_bh(&sc->target_lock);
     CE_state->recv_cb = fn_ptr;
     CE_state->recv_context = CE_recv_context;
     CE_per_engine_handler_adjust(CE_state, disable_interrupts);
-    adf_os_spin_unlock(&sc->target_lock);
+    adf_os_spin_unlock_bh(&sc->target_lock);
 }
 
 void
@@ -1400,14 +1400,14 @@
     struct CE_state *CE_state = (struct CE_state *)copyeng;
     struct hif_pci_softc *sc = CE_state->sc;
 
-    adf_os_spin_lock(&sc->target_lock);
+    adf_os_spin_lock_bh(&sc->target_lock);
     CE_state->watermark_cb = fn_ptr;
     CE_state->wm_context = CE_wm_context;
     CE_per_engine_handler_adjust(CE_state, 0);
     if (fn_ptr) {
         CE_state->misc_cbs = 1;
     }
-    adf_os_spin_unlock(&sc->target_lock);
+    adf_os_spin_unlock_bh(&sc->target_lock);
 }
 
 static unsigned int
@@ -1467,12 +1467,12 @@
 
     A_ASSERT(CE_id < sc->ce_count);
     ctrl_addr = CE_BASE_ADDRESS(CE_id);
-    adf_os_spin_lock(&sc->target_lock);
+    adf_os_spin_lock_bh(&sc->target_lock);
     CE_state = sc->CE_id_to_state[CE_id];
 
 
     if (!CE_state) {
-        adf_os_spin_unlock(&sc->target_lock);
+        adf_os_spin_unlock_bh(&sc->target_lock);
         CE_state = (struct CE_state *)A_MALLOC(sizeof(*CE_state));
         if (!CE_state) {
             dev_err(&sc->pdev->dev, "ath ERROR: CE_state has no mem\n");
@@ -1480,7 +1480,7 @@
         } else
             malloc_CE_state = true;
         A_MEMZERO(CE_state, sizeof(*CE_state));
-        adf_os_spin_lock(&sc->target_lock);
+        adf_os_spin_lock_bh(&sc->target_lock);
         if (!sc->CE_id_to_state[CE_id]) { /* re-check under lock */
             sc->CE_id_to_state[CE_id] = CE_state;
 
@@ -1500,7 +1500,7 @@
             CE_state = sc->CE_id_to_state[CE_id];
         }
     }
-    adf_os_spin_unlock(&sc->target_lock);
+    adf_os_spin_unlock_bh(&sc->target_lock);
 
     adf_os_atomic_init(&CE_state->rx_pending);
     if (attr == NULL) {
@@ -1539,9 +1539,9 @@
                 dev_err(&sc->pdev->dev, "ath ERROR: src ring has no mem\n");
                 if (malloc_CE_state) {
                     /* allocated CE_state locally */
-                    adf_os_spin_lock(&sc->target_lock);
+                    adf_os_spin_lock_bh(&sc->target_lock);
                     sc->CE_id_to_state[CE_id]= NULL;
-                    adf_os_spin_unlock(&sc->target_lock);
+                    adf_os_spin_unlock_bh(&sc->target_lock);
                     A_FREE(CE_state);
                     malloc_CE_state = false;
                 }
@@ -1642,9 +1642,9 @@
                 }
                 if (malloc_CE_state) {
                     /* allocated CE_state locally */
-                    adf_os_spin_lock(&sc->target_lock);
+                    adf_os_spin_lock_bh(&sc->target_lock);
                     sc->CE_id_to_state[CE_id]= NULL;
-                    adf_os_spin_unlock(&sc->target_lock);
+                    adf_os_spin_unlock_bh(&sc->target_lock);
                     A_FREE(CE_state);
                     malloc_CE_state = false;
                 }
diff --git a/drivers/staging/qcacld-2.0/CORE/SERVICES/HIF/PCIe/copy_engine_api.h b/drivers/staging/qcacld-2.0/CORE/SERVICES/HIF/PCIe/copy_engine_api.h
index 7e03a5f..d696415 100644
--- a/drivers/staging/qcacld-2.0/CORE/SERVICES/HIF/PCIe/copy_engine_api.h
+++ b/drivers/staging/qcacld-2.0/CORE/SERVICES/HIF/PCIe/copy_engine_api.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2014 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2014, 2016 The Linux Foundation. All rights reserved.
  *
  * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
  *
@@ -374,6 +374,9 @@
 /* API to check if any of the copy engine pipes has pending frames for prcoessing */
 bool CE_get_rx_pending(struct hif_pci_softc *sc);
 
+int get_next_record_index(atomic_t *table_index, int array_size);
+
+
 /* CE_attr.flags values */
 #define CE_ATTR_NO_SNOOP                0x01  /* Use NonSnooping PCIe accesses? */
 #define CE_ATTR_BYTE_SWAP_DATA          0x02  /* Byte swap data words */
diff --git a/drivers/staging/qcacld-2.0/CORE/SERVICES/HIF/PCIe/hif_pci.c b/drivers/staging/qcacld-2.0/CORE/SERVICES/HIF/PCIe/hif_pci.c
index 3a1de9d..ec1ce76 100644
--- a/drivers/staging/qcacld-2.0/CORE/SERVICES/HIF/PCIe/hif_pci.c
+++ b/drivers/staging/qcacld-2.0/CORE/SERVICES/HIF/PCIe/hif_pci.c
@@ -2354,6 +2354,7 @@
 	A_target_id_t pci_addr = TARGID_TO_PCI_ADDR(hif_state->targid);
 	struct hif_pci_softc *sc = hif_state->sc;
 	u_int32_t idle_ms;
+	unsigned long flags;
 
 	if (vos_is_unload_in_progress())
 		return;
@@ -2361,7 +2362,7 @@
 	if (sc->recovery)
 		return;
 
-	adf_os_spin_lock_irqsave(&hif_state->keep_awake_lock);
+	spin_lock_irqsave(&hif_state->keep_awake_lock, flags);
 	if (hif_state->verified_awake == FALSE) {
 		idle_ms = adf_os_ticks_to_msecs(adf_os_ticks()
 					- hif_state->sleep_ticks);
@@ -2381,7 +2382,7 @@
 		adf_os_timer_start(&hif_state->sleep_timer,
 			HIF_SLEEP_INACTIVITY_TIMER_PERIOD_MS);
 	}
-	adf_os_spin_unlock_irqrestore(&hif_state->keep_awake_lock);
+	spin_unlock_irqrestore(&hif_state->keep_awake_lock, flags);
 }
 
 void
@@ -2390,8 +2391,9 @@
 	struct HIF_CE_state *hif_state = (struct HIF_CE_state *)hif_device;
 	A_target_id_t pci_addr = TARGID_TO_PCI_ADDR(hif_state->targid);
 	struct hif_pci_softc *sc = hif_state->sc;
+	unsigned long flags;
 
-	adf_os_spin_lock_irqsave(&hif_state->keep_awake_lock);
+	spin_lock_irqsave(&hif_state->keep_awake_lock, flags);
 	/*
 	 * If the deferred sleep timer is running cancel it
 	 * and put the soc into sleep.
@@ -2404,7 +2406,7 @@
 		}
 		hif_state->fake_sleep = FALSE;
 	}
-	adf_os_spin_unlock_irqrestore(&hif_state->keep_awake_lock);
+	spin_unlock_irqrestore(&hif_state->keep_awake_lock, flags);
 }
 
 /*
@@ -2446,9 +2448,9 @@
     sc->hif_device = (HIF_DEVICE *)hif_state;
     hif_state->sc = sc;
 
-    adf_os_spinlock_init(&hif_state->keep_awake_lock);
+    spin_lock_init(&hif_state->keep_awake_lock);
 
-    adf_os_spinlock_init(&hif_state->suspend_lock);
+    spin_lock_init(&hif_state->suspend_lock);
 
     adf_os_atomic_init(&hif_state->hif_thread_idle);
     adf_os_atomic_inc(&hif_state->hif_thread_idle);
@@ -2760,6 +2762,7 @@
     static int max_delay;
     static int debug = 0;
     struct hif_pci_softc *sc = hif_state->sc;
+    unsigned long flags;
 
 
     if (sc->recovery)
@@ -2781,7 +2784,7 @@
     }
 
     if (sleep_ok) {
-        adf_os_spin_lock_irqsave(&hif_state->keep_awake_lock);
+        spin_lock_irqsave(&hif_state->keep_awake_lock, flags);
         hif_state->keep_awake_count--;
         if (hif_state->keep_awake_count == 0) {
             /* Allow sleep */
@@ -2797,9 +2800,9 @@
             adf_os_timer_start(&hif_state->sleep_timer,
                 HIF_SLEEP_INACTIVITY_TIMER_PERIOD_MS);
         }
-        adf_os_spin_unlock_irqrestore(&hif_state->keep_awake_lock);
+        spin_unlock_irqrestore(&hif_state->keep_awake_lock, flags);
     } else {
-        adf_os_spin_lock_irqsave(&hif_state->keep_awake_lock);
+        spin_lock_irqsave(&hif_state->keep_awake_lock, flags);
 
         if (hif_state->fake_sleep) {
             hif_state->verified_awake = TRUE;
@@ -2811,7 +2814,7 @@
             }
         }
         hif_state->keep_awake_count++;
-        adf_os_spin_unlock_irqrestore(&hif_state->keep_awake_lock);
+        spin_unlock_irqrestore(&hif_state->keep_awake_lock, flags);
 
         if (wait_for_it && !hif_state->verified_awake) {
 #define PCIE_WAKE_TIMEOUT 8000 /* 8Ms */
diff --git a/drivers/staging/qcacld-2.0/CORE/SERVICES/HIF/PCIe/hif_pci.h b/drivers/staging/qcacld-2.0/CORE/SERVICES/HIF/PCIe/hif_pci.h
index 1fe3759..1c57295 100644
--- a/drivers/staging/qcacld-2.0/CORE/SERVICES/HIF/PCIe/hif_pci.h
+++ b/drivers/staging/qcacld-2.0/CORE/SERVICES/HIF/PCIe/hif_pci.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2015 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2016 The Linux Foundation. All rights reserved.
  *
  * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
  *
@@ -100,8 +100,8 @@
     struct hif_pci_softc *sc;
     A_BOOL started;
 
-    adf_os_spinlock_t keep_awake_lock;
-    adf_os_spinlock_t suspend_lock;
+    spinlock_t keep_awake_lock;
+    spinlock_t suspend_lock;
     unsigned int keep_awake_count;
     A_BOOL verified_awake;
     A_BOOL fake_sleep;
diff --git a/drivers/staging/qcacld-2.0/CORE/SERVICES/HIF/PCIe/if_pci.c b/drivers/staging/qcacld-2.0/CORE/SERVICES/HIF/PCIe/if_pci.c
index 389e43c..399ef78 100644
--- a/drivers/staging/qcacld-2.0/CORE/SERVICES/HIF/PCIe/if_pci.c
+++ b/drivers/staging/qcacld-2.0/CORE/SERVICES/HIF/PCIe/if_pci.c
@@ -154,47 +154,59 @@
 } hif_irq_history;
 
 #define HIF_IRQ_HISTORY_MAX 1024
-A_UINT32 g_hif_irq_history_idx = 0;
+adf_os_atomic_t g_hif_irq_history_idx;
 hif_irq_history hif_irq_history_buffer[HIF_IRQ_HISTORY_MAX];
 
-void hif_irq_record(hif_irq_type type, struct hif_pci_softc *sc)
+static void hif_irq_record(hif_irq_type type, struct hif_pci_softc *sc)
 {
 	struct HIF_CE_state *hif_state = (struct HIF_CE_state *)sc->hif_device;
 	A_target_id_t targid = hif_state->targid;
 
-	if (HIF_IRQ_HISTORY_MAX <= g_hif_irq_history_idx)
-		g_hif_irq_history_idx = 0;
+	int record_index = get_next_record_index(
+			&g_hif_irq_history_idx, HIF_IRQ_HISTORY_MAX);
 
 	if (HIFTargetSleepStateAdjust(hif_state->targid, FALSE, TRUE) < 0) {
-		adf_os_mem_zero(&hif_irq_history_buffer[g_hif_irq_history_idx],
+		adf_os_mem_zero(&hif_irq_history_buffer[record_index],
 				sizeof(hif_irq_history));
 		goto out;
 	}
 
-	hif_irq_history_buffer[g_hif_irq_history_idx].irq_summary =
+	hif_irq_history_buffer[record_index].irq_summary =
 			CE_INTERRUPT_SUMMARY(targid);
-	hif_irq_history_buffer[g_hif_irq_history_idx].fw_indicator =
+	hif_irq_history_buffer[record_index].fw_indicator =
 			A_TARGET_READ(targid, hif_state->fw_indicator_address);
-	hif_irq_history_buffer[g_hif_irq_history_idx].irq_enable =
+	hif_irq_history_buffer[record_index].irq_enable =
 			A_PCI_READ32(sc->mem + SOC_CORE_BASE_ADDRESS +
 				PCIE_INTR_ENABLE_ADDRESS);
-	hif_irq_history_buffer[g_hif_irq_history_idx].irq_cause =
+	hif_irq_history_buffer[record_index].irq_cause =
 			A_PCI_READ32(sc->mem + SOC_CORE_BASE_ADDRESS +
 				PCIE_INTR_CAUSE_ADDRESS);
-	hif_irq_history_buffer[g_hif_irq_history_idx].irq_clear =
+	hif_irq_history_buffer[record_index].irq_clear =
 			A_PCI_READ32(sc->mem + SOC_CORE_BASE_ADDRESS +
 				PCIE_INTR_CLR_ADDRESS);
 
 	HIFTargetSleepStateAdjust(hif_state->targid, TRUE, FALSE);
 
 out:
-	hif_irq_history_buffer[g_hif_irq_history_idx].type = type;
-	hif_irq_history_buffer[g_hif_irq_history_idx].time = adf_get_boottime();
+	hif_irq_history_buffer[record_index].type = type;
+	hif_irq_history_buffer[record_index].time = adf_get_boottime();
 
-	g_hif_irq_history_idx++;
 }
+
+/**
+ * hif_irq_record_index_init() - initialize the hif irq index
+ *
+ * initialize the hif irq record index.
+ * Return: none
+ */
+static void hif_irq_record_index_init(void)
+{
+	adf_os_atomic_init(&g_hif_irq_history_idx);
+}
+
 #else
-void hif_irq_record(hif_irq_type type, struct hif_pci_softc *sc) {};
+static void hif_irq_record(hif_irq_type type, struct hif_pci_softc *sc) {};
+static void hif_irq_record_index_init(void) {};
 #endif
 
 #ifndef REMOVE_PKT_LOG
@@ -218,16 +230,17 @@
     struct hif_pci_softc *sc = (struct hif_pci_softc *) arg;
     struct HIF_CE_state *hif_state = (struct HIF_CE_state *)sc->hif_device;
     volatile int tmp;
+    unsigned long flags = 0;
 
     if (sc->hif_init_done == TRUE) {
-        adf_os_spin_lock_irqsave(&hif_state->suspend_lock);
+        spin_lock_irqsave(&hif_state->suspend_lock, flags);
     }
 
     if (LEGACY_INTERRUPTS(sc)) {
 
         if (sc->hif_init_done == TRUE) {
             if (Q_TARGET_ACCESS_BEGIN(hif_state->targid) < 0) {
-                adf_os_spin_unlock_irqrestore(&hif_state->suspend_lock);
+                spin_unlock_irqrestore(&hif_state->suspend_lock, flags);
                 return IRQ_HANDLED;
             }
 
@@ -250,7 +263,7 @@
 
         if (sc->hif_init_done == TRUE) {
             if (Q_TARGET_ACCESS_END(hif_state->targid) < 0) {
-                adf_os_spin_unlock_irqrestore(&hif_state->suspend_lock);
+                spin_unlock_irqrestore(&hif_state->suspend_lock, flags);
                 return IRQ_HANDLED;
             }
         }
@@ -263,7 +276,7 @@
 
     if (sc->hif_init_done == TRUE) {
         hif_irq_record(HIF_IRQ_END, sc);
-        adf_os_spin_unlock_irqrestore(&hif_state->suspend_lock);
+        spin_unlock_irqrestore(&hif_state->suspend_lock, flags);
     }
     return IRQ_HANDLED;
 }
@@ -770,6 +783,7 @@
     struct HIF_CE_state *hif_state = (struct HIF_CE_state *)sc->hif_device;
     volatile int tmp;
     bool hif_init_done = sc->hif_init_done;
+    unsigned long flags = 0;
 
     if (hif_init_done == FALSE) {
          goto irq_handled;
@@ -812,7 +826,7 @@
      * while this tasklet is running
      */
     if (hif_init_done == TRUE)
-        adf_os_spin_lock_irqsave(&hif_state->suspend_lock);
+        spin_lock_irqsave(&hif_state->suspend_lock, flags);
 
     if (LEGACY_INTERRUPTS(sc) && (sc->ol_sc->target_status !=
                                   OL_TRGET_STATUS_RESET) &&
@@ -820,7 +834,7 @@
 
         if (hif_init_done == TRUE) {
             if(HIFTargetSleepStateAdjust(hif_state->targid, FALSE, TRUE) < 0) {
-                adf_os_spin_unlock_irqrestore(&hif_state->suspend_lock);
+                spin_unlock_irqrestore(&hif_state->suspend_lock, flags);
                 return;
             }
         }
@@ -834,7 +848,7 @@
         if (hif_init_done == TRUE) {
              HIF_fw_interrupt_handler(sc->irq_event, sc);
              if(HIFTargetSleepStateAdjust(hif_state->targid, TRUE, FALSE) < 0) {
-                   adf_os_spin_unlock_irqrestore(&hif_state->suspend_lock);
+                   spin_unlock_irqrestore(&hif_state->suspend_lock, flags);
                    return;
                }
         }
@@ -842,7 +856,7 @@
 
     if (hif_init_done == TRUE) {
         hif_irq_record(HIF_TASKLET_END, sc);
-        adf_os_spin_unlock_irqrestore(&hif_state->suspend_lock);
+        spin_unlock_irqrestore(&hif_state->suspend_lock, flags);
     }
 
     adf_os_atomic_set(&sc->ce_suspend, 1);
@@ -1739,6 +1753,7 @@
 #endif
     adf_os_atomic_init(&sc->ce_suspend);
     adf_os_atomic_init(&sc->pci_link_suspended);
+    hif_irq_record_index_init();
     init_waitqueue_head(&ol_sc->sc_osdev->event_queue);
 
     ret = hif_init_adf_ctx(ol_sc);
@@ -2450,6 +2465,7 @@
     struct hif_pci_softc *sc;
     struct ol_softc *scn;
     struct HIF_CE_state *hif_state;
+    unsigned long flags;
 
     sc = pci_get_drvdata(pdev);
     /* Attach did not succeed, all resources have been
@@ -2474,10 +2490,10 @@
     scn = sc->ol_sc;
 
     hif_disable_isr(scn);
-    adf_os_spin_lock_irqsave(&hif_state->suspend_lock);
+    spin_lock_irqsave(&hif_state->suspend_lock, flags);
     if (!adf_os_atomic_read(&sc->pci_link_suspended))
         hif_pci_device_reset(sc);
-    adf_os_spin_unlock_irqrestore(&hif_state->suspend_lock);
+    spin_unlock_irqrestore(&hif_state->suspend_lock, flags);
 
 #ifndef REMOVE_PKT_LOG
     if (vos_get_conparam() != VOS_FTM_MODE &&
@@ -2563,11 +2579,12 @@
 	struct HIF_CE_state *hif_state = (struct HIF_CE_state *)sc->hif_device;
 	struct ol_softc *scn = sc->ol_sc;
 	int ret;
+	unsigned long flags;
 
 	if (!hif_state)
 		return;
 
-	adf_os_spin_lock_irqsave(&hif_state->suspend_lock);
+	spin_lock_irqsave(&hif_state->suspend_lock, flags);
 	hif_irq_record(HIF_CRASH, sc);
 	hif_dump_soc_and_ce_registers(sc);
 
@@ -2581,7 +2598,7 @@
 
 	pr_info("%s: RAM dump collecting completed!\n", __func__);
 out:
-	adf_os_spin_unlock_irqrestore(&hif_state->suspend_lock);
+	spin_unlock_irqrestore(&hif_state->suspend_lock, flags);
 }
 
 void hif_pci_crash_shutdown(struct pci_dev *pdev)
@@ -2642,6 +2659,7 @@
     v_VOID_t * temp_module;
     u32 tmp;
     int ret = -EBUSY;
+    unsigned long flags;
 
     hif_irq_record(HIF_SUSPEND_START, sc);
 
@@ -2727,7 +2745,7 @@
         goto out;
 
     /* Acquire lock to access shared register */
-    adf_os_spin_lock_irqsave(&hif_state->suspend_lock);
+    spin_lock_irqsave(&hif_state->suspend_lock, flags);
     A_PCI_WRITE32(sc->mem+(SOC_CORE_BASE_ADDRESS | PCIE_INTR_ENABLE_ADDRESS), 0);
     A_PCI_WRITE32(sc->mem+(SOC_CORE_BASE_ADDRESS | PCIE_INTR_CLR_ADDRESS),
                   PCIE_INTR_FIRMWARE_MASK | PCIE_INTR_CE_MASK_ALL);
@@ -2742,14 +2760,14 @@
 
     /* Put ROME to sleep */
     if (HIFTargetSleepStateAdjust(targid, TRUE, FALSE) < 0) {
-        adf_os_spin_unlock_irqrestore(&hif_state->suspend_lock);
+        spin_unlock_irqrestore(&hif_state->suspend_lock, flags);
         goto out;
     }
     /* Stop the HIF Sleep Timer */
     HIFCancelDeferredTargetSleep(sc->hif_device);
 
     adf_os_atomic_set(&sc->pci_link_suspended, 1);
-    adf_os_spin_unlock_irqrestore(&hif_state->suspend_lock);
+    spin_unlock_irqrestore(&hif_state->suspend_lock, flags);
 
     /* Keep PCIe bus driver's shadow memory intact */
     vos_pcie_shadow_control(pdev, FALSE);
diff --git a/drivers/staging/qcacld-2.0/CORE/SERVICES/WMA/wma.c b/drivers/staging/qcacld-2.0/CORE/SERVICES/WMA/wma.c
index a5c18cd..f28fa6e 100644
--- a/drivers/staging/qcacld-2.0/CORE/SERVICES/WMA/wma.c
+++ b/drivers/staging/qcacld-2.0/CORE/SERVICES/WMA/wma.c
@@ -23769,11 +23769,34 @@
 static void wma_process_update_opmode(tp_wma_handle wma_handle,
                                 tUpdateVHTOpMode *update_vht_opmode)
 {
-        WMA_LOGD("%s: opMode = %d", __func__, update_vht_opmode->opMode);
+	struct wma_txrx_node *iface;
+	WLAN_PHY_MODE  chanMode;
+	wmi_channel_width chanwidth;
 
-        wma_set_peer_param(wma_handle, update_vht_opmode->peer_mac,
-                           WMI_PEER_CHWIDTH, update_vht_opmode->opMode,
-                           update_vht_opmode->smesessionId);
+	iface = &wma_handle->interfaces[update_vht_opmode->smesessionId];
+	if (update_vht_opmode->chanMode == MODE_MAX)
+		chanMode = iface->chanmode;
+	else
+		chanMode = update_vht_opmode->chanMode;
+
+	WMA_LOGD("%s: opMode = %d, chanMode = %d",
+		__func__, update_vht_opmode->opMode, chanMode);
+
+	chanwidth = chanmode_to_chanwidth(chanMode);
+	if (chanwidth < update_vht_opmode->opMode) {
+		WMA_LOGE("%s: stop changing chanwidth from %d to %d,",
+			__func__,
+			chanwidth, update_vht_opmode->opMode);
+	} else {
+		iface->chanmode = chanMode;
+		wma_set_peer_param(wma_handle, update_vht_opmode->peer_mac,
+				WMI_PEER_PHYMODE, chanMode,
+				update_vht_opmode->smesessionId);
+
+		wma_set_peer_param(wma_handle, update_vht_opmode->peer_mac,
+				WMI_PEER_CHWIDTH, update_vht_opmode->opMode,
+				update_vht_opmode->smesessionId);
+	}
 }
 
 static void wma_process_update_rx_nss(tp_wma_handle wma_handle,
@@ -35990,20 +36013,12 @@
 		WMA_LOGE("%s:DFS- Invalid WMA handle", __func__);
 		return -ENOENT;
 	}
-	radar_event = (struct wma_dfs_radar_indication *)
-		vos_mem_malloc(sizeof(struct wma_dfs_radar_indication));
-	if (radar_event == NULL)
-	{
-		WMA_LOGE("%s:DFS- Invalid radar_event", __func__);
-		return -ENOENT;
-	}
 
 	/*
 	 * Do not post multiple Radar events on the same channel.
 	 * But, when DFS test mode is enabled, allow multiple dfs
 	 * radar events to be posted on the same channel.
 	 */
-
 	adf_os_spin_lock_bh(&ic->chan_lock);
 	if (!pmac->sap.SapDfsInfo.disable_dfs_ch_switch)
 		wma->dfs_ic->disable_phy_err_processing = true;
@@ -36011,6 +36026,13 @@
 	if ((ichan->ic_ieee  != (wma->dfs_ic->last_radar_found_chan)) ||
 	    ( pmac->sap.SapDfsInfo.disable_dfs_ch_switch == VOS_TRUE) )
 	{
+		radar_event = (struct wma_dfs_radar_indication *)
+			vos_mem_malloc(sizeof(*radar_event));
+		if (radar_event == NULL) {
+			WMA_LOGE(FL("Failed to allocate memory for radar_event"));
+			return -ENOMEM;
+		}
+
 		/* Indicate the radar event to HDD to stop the netif Tx queues*/
 		hdd_radar_event.ieee_chan_number = ichan->ic_ieee;
 		hdd_radar_event.chan_freq = ichan->ic_freq;
diff --git a/drivers/staging/qcacld-2.0/CORE/SME/src/csr/csrApiRoam.c b/drivers/staging/qcacld-2.0/CORE/SME/src/csr/csrApiRoam.c
index d7709d6..06aeebd 100644
--- a/drivers/staging/qcacld-2.0/CORE/SME/src/csr/csrApiRoam.c
+++ b/drivers/staging/qcacld-2.0/CORE/SME/src/csr/csrApiRoam.c
@@ -11043,6 +11043,8 @@
                                    "command failed(%d) PeerMac "MAC_ADDRESS_STR,
                                    pRsp->statusCode, MAC_ADDR_ARRAY(pRsp->peerMacAddr));
                         }
+                        roamInfo.is11rAssoc = csrRoamIs11rAssoc(pMac,
+                                                                  sessionId);
                         csrRoamCallCallback(pMac, sessionId, &roamInfo, pCommand->u.setKeyCmd.roamId,
                                             eCSR_ROAM_SET_KEY_COMPLETE, result);
                         // Indicate SME_QOS that the SET_KEY is completed, so that SME_QOS
diff --git a/drivers/staging/qcacld-2.0/CORE/SME/src/sme_common/sme_Api.c b/drivers/staging/qcacld-2.0/CORE/SME/src/sme_common/sme_Api.c
index 489531ef..9651045 100644
--- a/drivers/staging/qcacld-2.0/CORE/SME/src/sme_common/sme_Api.c
+++ b/drivers/staging/qcacld-2.0/CORE/SME/src/sme_common/sme_Api.c
@@ -14191,6 +14191,7 @@
    vos_mem_copy(pHtOpMode->peer_mac, macAddrSTA.bytes,
                  sizeof(tSirMacAddr));
    pHtOpMode->smesessionId = sessionId;
+   pHtOpMode->chanMode = MODE_MAX;
 
    msg.type     = WDA_UPDATE_OP_MODE;
    msg.reserved = 0;
diff --git a/drivers/staging/qcacld-2.0/CORE/WDA/inc/legacy/halMsgApi.h b/drivers/staging/qcacld-2.0/CORE/WDA/inc/legacy/halMsgApi.h
index 3ead091..e268f9c 100644
--- a/drivers/staging/qcacld-2.0/CORE/WDA/inc/legacy/halMsgApi.h
+++ b/drivers/staging/qcacld-2.0/CORE/WDA/inc/legacy/halMsgApi.h
@@ -931,7 +931,8 @@
 #ifdef WLAN_FEATURE_11AC
 typedef struct
 {
-   tANI_U16   opMode;
+   tANI_U16  opMode;
+   tANI_U16  chanMode;
    tANI_U16  staId;
    tANI_U16  smesessionId;
    tSirMacAddr peer_mac;
diff --git a/drivers/usb/fusb302/Makefile b/drivers/usb/fusb302/Makefile
index 5c95dc0..ee0fcf0 100644
--- a/drivers/usb/fusb302/Makefile
+++ b/drivers/usb/fusb302/Makefile
@@ -17,7 +17,6 @@
 ccflags-$(CONFIG_FUSB_30X) += -DFSC_HAVE_SRC
 ccflags-$(CONFIG_FUSB_30X) += -DFSC_HAVE_SNK
 ccflags-$(CONFIG_FUSB_30X) += -DFSC_HAVE_DRP
-ccflags-$(CONFIG_FUSB_30X) += -DFSC_HAVE_ACCMODE
 ccflags-$(CONFIG_FUSB_30X) += -DFSC_HAVE_VDM
 ccflags-$(CONFIG_FUSB_30X) += -DFSC_HAVE_DP
 
diff --git a/drivers/usb/fusb302/Platform_Linux/platform.c b/drivers/usb/fusb302/Platform_Linux/platform.c
index 484d788..3ea7fb0 100755
--- a/drivers/usb/fusb302/Platform_Linux/platform.c
+++ b/drivers/usb/fusb302/Platform_Linux/platform.c
@@ -311,7 +311,7 @@
 		if (chip && chip->uc && chip->uc->pd_vbus_ctrl) {
 			chip->uc->pd_vbus_ctrl(-1, FALSE);
 			if (!IsPRSwap)
-				platform_notify_attached_source(0);
+				platform_notify_attached_source(0, false);
 		}
 	}
 }
@@ -359,7 +359,7 @@
 }
 
 extern FSC_BOOL PolicyIsDFP;
-void platform_notify_attached_source(int value)
+void platform_notify_attached_source(int value, bool connected)
 {
 	struct fusb30x_chip* chip = fusb30x_GetChip();
 	int notify_retry_count = 0;
@@ -378,13 +378,20 @@
 	} while (notify_retry_count <= 3);
 
 	PolicyIsDFP = value ? TRUE : FALSE;
-	chip->pmode = value ? DUAL_ROLE_PROP_MODE_DFP : DUAL_ROLE_PROP_MODE_UFP;
-	chip->drole = value ? DUAL_ROLE_PROP_DR_HOST : DUAL_ROLE_PROP_DR_DEVICE;
+	if (connected) {
+		chip->pmode = value ? DUAL_ROLE_PROP_MODE_DFP : DUAL_ROLE_PROP_MODE_UFP;
+		chip->drole = value ? DUAL_ROLE_PROP_DR_HOST : DUAL_ROLE_PROP_DR_DEVICE;
+	} else {
+		chip->pmode = DUAL_ROLE_PROP_MODE_NONE;
+		chip->drole = DUAL_ROLE_PROP_DR_NONE;
+		chip->prole = DUAL_ROLE_PROP_PR_NONE;
+	}
+
 	if (chip->fusb_instance)
 		dual_role_instance_changed(chip->fusb_instance);
 }
 
-u8 platform_select_source_capability(u8 obj_cnt, doDataObject_t pd_data[7], int *device_max_ma)
+FSC_S32 platform_select_source_capability(u8 obj_cnt, doDataObject_t pd_data[7], int *device_max_ma)
 {
     return fusb_battery_select_source_capability(obj_cnt, pd_data, device_max_ma);
 }
diff --git a/drivers/usb/fusb302/Platform_Linux/platform_helpers.c b/drivers/usb/fusb302/Platform_Linux/platform_helpers.c
index aaf58d68..f34c29b 100755
--- a/drivers/usb/fusb302/Platform_Linux/platform_helpers.c
+++ b/drivers/usb/fusb302/Platform_Linux/platform_helpers.c
@@ -997,9 +997,10 @@
     }
 }
 
-u8 fusb_battery_select_source_capability(u8 obj_cnt, doDataObject_t pd_data[7], int *device_max_ma)
+FSC_S32 fusb_battery_select_source_capability(u8 obj_cnt, doDataObject_t pd_data[7], int *device_max_ma)
 {
-    u8 i, sel_voltage_pdo_index;
+    u8 i;
+    FSC_S32 sel_voltage_pdo_index;
     struct htc_pd_data htc_pdo_data;
 
     for (i = 0; i <= obj_cnt; i++) {
diff --git a/drivers/usb/fusb302/Platform_Linux/platform_helpers.h b/drivers/usb/fusb302/Platform_Linux/platform_helpers.h
index d6c3434..1309862 100755
--- a/drivers/usb/fusb302/Platform_Linux/platform_helpers.h
+++ b/drivers/usb/fusb302/Platform_Linux/platform_helpers.h
@@ -71,7 +71,7 @@
 ********************************************************************************/

 FSC_BOOL fusb_Power_Vconn(FSC_BOOL set);

 

-u8 fusb_battery_select_source_capability(u8 obj_cnt, doDataObject_t pd_data[7], int *device_max_ma);

+FSC_S32 fusb_battery_select_source_capability(u8 obj_cnt, doDataObject_t pd_data[7], int *device_max_ma);

 

 

 #ifdef FSC_DEBUG

diff --git a/drivers/usb/fusb302/core/PDPolicy.c b/drivers/usb/fusb302/core/PDPolicy.c
index 3846fab1..8c6286a 100755
--- a/drivers/usb/fusb302/core/PDPolicy.c
+++ b/drivers/usb/fusb302/core/PDPolicy.c
@@ -850,7 +850,7 @@
                 PolicyIsDFP = TRUE;;                                            // Set the current data role

                 Registers.Switches.DATAROLE = PolicyIsDFP;                      // Update the data role

                 DeviceWrite(regSwitches1, 1, &Registers.Switches.byte[1]);      // Commit the data role in the 302

-                platform_notify_attached_source(PolicyIsDFP);

+                platform_notify_attached_source(PolicyIsDFP, true);

             }

             if(IsVCONNSource)                                                   // Disable VCONN if VCONN Source

             {

@@ -1363,7 +1363,7 @@
                             DeviceWrite(regSwitches1, 1, &Registers.Switches.byte[1]); // Commit the data role in the 302 for the auto CRC

                             PolicyState = peSourceReady;                        // Source ready state

                             pr_info("FUSB %s: accept, PolicyIsDFP(%d)\n", __func__, PolicyIsDFP);

-                            platform_notify_attached_source(PolicyIsDFP);

+                            platform_notify_attached_source(PolicyIsDFP, true);

                             break;

                         case CMTSoftReset:

                             PolicyState = peSourceSoftReset;                    // Go to the soft reset state if we received a reset command

@@ -1410,7 +1410,7 @@
         Registers.Switches.DATAROLE = PolicyIsDFP;                          // Update the data role

         DeviceWrite(regSwitches1, 1, &Registers.Switches.byte[1]);          // Commit the data role in the 302 for the auto CRC

         pr_info("FUSB %s: accept, PolicyIsDFP(%d)\n", __func__, PolicyIsDFP);

-        platform_notify_attached_source(PolicyIsDFP);

+        platform_notify_attached_source(PolicyIsDFP, true);

     }

     else if (Status == STAT_ERROR)                                          // If we didn't receive the good CRC...

     {

@@ -1897,7 +1897,7 @@
                 PolicyIsDFP = FALSE;                                            // Set the current data role

                 Registers.Switches.DATAROLE = PolicyIsDFP;                      // Update the data role

                 DeviceWrite(regSwitches1, 1, &Registers.Switches.byte[1]);      // Commit the data role in the 302

-                platform_notify_attached_source(PolicyIsDFP);

+                platform_notify_attached_source(PolicyIsDFP, true);

             }

             if(IsVCONNSource)                                                   // Disable VCONN if VCONN Source

             {

@@ -2076,7 +2076,7 @@
     }

 }

 

-extern u8 platform_select_source_capability(u8 obj_cnt, doDataObject_t pd_data[7], int *device_max_ma);

+extern FSC_S32 platform_select_source_capability(u8 obj_cnt, doDataObject_t pd_data[7], int *device_max_ma);

 

 void PolicySinkEvaluateCaps(void)

 {

@@ -2160,11 +2160,9 @@
             SinkRequest.FVRDO.CapabilityMismatch = FALSE;                       // There can't be a capabilities mismatch

         else                                                                    // Otherwise...

         {

-            if (SelVoltage * ReqCurrent < SinkRequestMaxPower)                  // If the max power available is less than the max power requested...

+            if (SelVoltage * ReqCurrent != SinkRequestMaxPower)

             {

                 SinkRequest.FVRDO.CapabilityMismatch = TRUE;                    // flag the source that we need more power

-                SinkRequest.FVRDO.MinMaxCurrent = objCurrent;                     // Set operating power to max available

-                SinkRequest.FVRDO.OpCurrent =  objCurrent;   

             }

             else                                                                // Otherwise...

             {

@@ -2507,7 +2505,7 @@
                             DeviceWrite(regSwitches1, 1, &Registers.Switches.byte[1]); // Commit the data role in the 302 for the auto CRC

                             PolicyState = peSinkReady;                          // Sink ready state

                             pr_info("FUSB %s: accept, PolicyIsDFP(%d)\n", __func__, PolicyIsDFP);

-                            platform_notify_attached_source(PolicyIsDFP);

+                            platform_notify_attached_source(PolicyIsDFP, true);

                             break;

                         case CMTSoftReset:

                             PolicyState = peSinkSoftReset;                      // Go to the soft reset state if we received a reset command

@@ -2555,7 +2553,7 @@
         Registers.Switches.DATAROLE = PolicyIsDFP;                          // Update the data role

         DeviceWrite(regSwitches1, 1, &Registers.Switches.byte[1]);         // Commit the data role in the 302 for the auto CRC

         pr_info("FUSB %s: accept, PolicyIsDFP(%d)\n", __func__, PolicyIsDFP);

-        platform_notify_attached_source(PolicyIsDFP);

+        platform_notify_attached_source(PolicyIsDFP, true);

     }

     else if (Status == STAT_ERROR)                                          // If we didn't receive the good CRC...

     {

diff --git a/drivers/usb/fusb302/core/TypeC.c b/drivers/usb/fusb302/core/TypeC.c
index 96137ab..abd8e06 100755
--- a/drivers/usb/fusb302/core/TypeC.c
+++ b/drivers/usb/fusb302/core/TypeC.c
@@ -870,7 +870,7 @@
 {
     debounceCC();
     
-    if ((CC1TermCCDebounce == CCTypeOpen) || (CC2TermCCDebounce == CCTypeOpen)) // If we have detected an open for > tCCDebounce 
+    if ((CC1TermPrevious == CCTypeOpen) || (CC2TermPrevious == CCTypeOpen)) // If we have detected an open for > tCCDebounce
     {
 #ifdef FSC_HAVE_SRC
         if(PortType == USBTypeC_Source)
@@ -1453,7 +1453,7 @@
     
     platform_set_vbus_lvl_enable(VBUS_LVL_5V, TRUE, TRUE);                      // Enable only the 5V output
     if (!IsPRSwap)
-        platform_notify_attached_source(1);
+        platform_notify_attached_source(1, true);
     ConnState = AttachedSource;                                                 // Set the state machine variable to Attached.Src
     TypeCSubState = 0;
     sourceOrSink = SOURCE;
diff --git a/drivers/usb/fusb302/core/platform.h b/drivers/usb/fusb302/core/platform.h
index c4e4100..9e3bd81 100755
--- a/drivers/usb/fusb302/core/platform.h
+++ b/drivers/usb/fusb302/core/platform.h
@@ -218,7 +218,7 @@
 *******************************************************************************/
 void platform_notify_unsupported_accessory(void);
 
-void platform_notify_attached_source(int value);
+void platform_notify_attached_source(int value, bool connected);
 
 int platform_set_sink_current_previous(CCTermType Termination);
 
diff --git a/drivers/video/msm/mdss/mdss_dsi_panel.c b/drivers/video/msm/mdss/mdss_dsi_panel.c
index 00db79a..7b28b18 100644
--- a/drivers/video/msm/mdss/mdss_dsi_panel.c
+++ b/drivers/video/msm/mdss/mdss_dsi_panel.c
@@ -2553,6 +2553,9 @@
 	rc = of_property_read_u32(np, "qcom,mdss-dsi-bl-max-level", &tmp);
 	pinfo->bl_max = (!rc ? tmp : 255);
 	ctrl_pdata->bklt_max = pinfo->bl_max;
+	rc = of_property_read_u32(np, "htc,mdss-dsi-bl-dim-check", &tmp);
+	pinfo->bl_dim_check = (!rc ? tmp : 0);
+	pinfo->bl_dim_status = false;
 
 	rc = of_property_read_u32(np, "qcom,mdss-dsi-interleave-mode", &tmp);
 	pinfo->mipi.interleave_mode = (!rc ? tmp : 0);
diff --git a/drivers/video/msm/mdss/mdss_fb.c b/drivers/video/msm/mdss/mdss_fb.c
index c4a961a..9931469 100644
--- a/drivers/video/msm/mdss/mdss_fb.c
+++ b/drivers/video/msm/mdss/mdss_fb.c
@@ -48,6 +48,7 @@
 #include <linux/file.h>
 #include <linux/kthread.h>
 #include <linux/dma-buf.h>
+#include <linux/power/htc_battery.h>
 #include "mdss_fb.h"
 #include "mdss_mdp_splash_logo.h"
 #define CREATE_TRACE_POINTS
@@ -273,6 +274,26 @@
 	if (value > mfd->panel_info->brightness_max)
 		value = mfd->panel_info->brightness_max;
 
+	/* Check if the current bl is in dim level or not,
+	   except bl = zero */
+	if (mfd->panel_info->bl_dim_check) {
+		bool dim_status = false;
+
+		if ((value > 0) && (value <= mfd->panel_info->bl_dim_check)) {
+			dim_status = true;
+		} else {
+			dim_status = false;
+		}
+
+		if (mfd->panel_info->bl_dim_status != dim_status) {
+			mfd->panel_info->bl_dim_status = dim_status;
+			/* bl_dim_status = true :  dim level
+			   bl_dim_stauts = false : 0 or over dim */
+			htc_battery_backlight_dim_mode_check(mfd->panel_info->bl_dim_status);
+			pr_info("bl_dim_status =%d\n", mfd->panel_info->bl_dim_status);
+		}
+	}
+
 	/* This maps android backlight level 0 to 255 into
 	   driver backlight level 0 to bl_max with rounding */
 	MDSS_BRIGHT_TO_BL(bl_lvl, value, mfd->panel_info->bl_max,
diff --git a/drivers/video/msm/mdss/mdss_panel.h b/drivers/video/msm/mdss/mdss_panel.h
index e5c9ac6..ccfa797 100644
--- a/drivers/video/msm/mdss/mdss_panel.h
+++ b/drivers/video/msm/mdss/mdss_panel.h
@@ -607,6 +607,8 @@
 	u32 brightness_max;
 	u32 bl_max;
 	u32 bl_min;
+	u32 bl_dim_check;
+	bool bl_dim_status;
 	u32 fb_num;
 	u64 clk_rate;
 	u32 clk_min;
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index b2cfaee..ebd790b 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -3465,6 +3465,11 @@
 	unsigned blocksize;
 	struct inode *inode = mapping->host;
 
+	/* If we are processing an encrypted inode during orphan list
+	 * handling */
+	if (ext4_encrypted_inode(inode) && !ext4_has_encryption_key(inode))
+		return 0;
+
 	blocksize = inode->i_sb->s_blocksize;
 	length = blocksize - (offset & (blocksize - 1));
 
diff --git a/include/linux/power/htc_battery.h b/include/linux/power/htc_battery.h
index b5662e8..fb6d6cd 100644
--- a/include/linux/power/htc_battery.h
+++ b/include/linux/power/htc_battery.h
@@ -398,6 +398,7 @@
 bool htc_battery_is_pd_detected(void);
 int htc_battery_get_pd_current(void);
 int htc_battery_get_pd_vbus(int *vbus);
+void htc_battery_backlight_dim_mode_check(bool status);
 
 /* Implement on QCT driver */
 int request_charger_status(enum htc_charger_request mode, void *ret_buf);
@@ -425,4 +426,5 @@
 bool pmi8996_is_booting_stage(void);
 bool htc_battery_get_discharging_reason(void);
 bool get_ima_error_status(void);
+int pmi8996_charger_batfet_switch(bool enable);
 #endif /* __HTC_BATTERY_H__ */
diff --git a/include/soc/qcom/qseecomi.h b/include/soc/qcom/qseecomi.h
index 1349a34..e33fd9f 100644
--- a/include/soc/qcom/qseecomi.h
+++ b/include/soc/qcom/qseecomi.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -18,6 +18,7 @@
 
 #define QSEECOM_KEY_ID_SIZE   32
 
+#define QSEOS_RESULT_FAIL_SEND_CMD_NO_THREAD  -19   /*0xFFFFFFED*/
 #define QSEOS_RESULT_FAIL_UNSUPPORTED_CE_PIPE -63
 #define QSEOS_RESULT_FAIL_KS_OP               -64
 #define QSEOS_RESULT_FAIL_KEY_ID_EXISTS       -65
@@ -64,6 +65,10 @@
 	QSEOS_TEE_REQUEST_CANCELLATION,
 	QSEOS_CONTINUE_BLOCKED_REQ_COMMAND,
 	QSEOS_RPMB_CHECK_PROV_STATUS_COMMAND = 0x1B,
+	QSEOS_CLIENT_SEND_DATA_COMMAND_WHITELIST = 0x1C,
+	QSEOS_TEE_OPEN_SESSION_WHITELIST = 0x1D,
+	QSEOS_TEE_INVOKE_COMMAND_WHITELIST = 0x1E,
+	QSEOS_LISTENER_DATA_RSP_COMMAND_WHITELIST = 0x1F,
 	QSEOS_FSM_LTEOTA_REQ_CMD = 0x109,
 	QSEOS_FSM_LTEOTA_REQ_RSP_CMD = 0x110,
 	QSEOS_FSM_IKE_REQ_CMD = 0x203,
@@ -181,6 +186,8 @@
 	uint32_t req_len;
 	uint32_t rsp_ptr;/* First 4 bytes should be the return status */
 	uint32_t rsp_len;
+	uint32_t sglistinfo_ptr;
+	uint32_t sglistinfo_len;
 };
 
 __packed struct qseecom_client_send_data_64bit_ireq {
@@ -190,6 +197,8 @@
 	uint32_t req_len;
 	uint64_t rsp_ptr;
 	uint32_t rsp_len;
+	uint64_t sglistinfo_ptr;
+	uint32_t sglistinfo_len;
 };
 
 __packed struct qseecom_reg_log_buf_ireq {
@@ -209,6 +218,16 @@
 	uint32_t qsee_cmd_id;
 	uint32_t listener_id;
 	uint32_t status;
+	uint32_t sglistinfo_ptr;
+	uint32_t sglistinfo_len;
+};
+
+__packed struct qseecom_client_listener_data_64bit_irsp {
+	uint32_t qsee_cmd_id;
+	uint32_t listener_id;
+	uint32_t status;
+	uint64_t sglistinfo_ptr;
+	uint32_t sglistinfo_len;
 };
 
 /*
@@ -292,6 +311,8 @@
 	uint32_t    req_len;
 	uint32_t    resp_ptr;
 	uint32_t    resp_len;
+	uint32_t    sglistinfo_ptr;
+	uint32_t    sglistinfo_len;
 };
 
 __packed struct qseecom_qteec_64bit_ireq {
@@ -301,6 +322,8 @@
 	uint32_t    req_len;
 	uint64_t    resp_ptr;
 	uint32_t    resp_len;
+	uint64_t    sglistinfo_ptr;
+	uint32_t    sglistinfo_len;
 };
 
 __packed struct qseecom_client_send_fsm_key_req {
@@ -658,4 +681,45 @@
 #define TZ_OS_CONTINUE_BLOCKED_REQUEST_ID_PARAM_ID \
 	TZ_SYSCALL_CREATE_PARAM_ID_1(TZ_SYSCALL_PARAM_TYPE_VAL)
 
+#define TZ_APP_QSAPP_SEND_DATA_WITH_WHITELIST_ID \
+	TZ_SYSCALL_CREATE_SMC_ID(TZ_OWNER_TZ_APPS, \
+	TZ_SVC_APP_ID_PLACEHOLDER, 0x06)
+
+#define TZ_APP_QSAPP_SEND_DATA_WITH_WHITELIST_ID_PARAM_ID \
+	TZ_SYSCALL_CREATE_PARAM_ID_7( \
+	TZ_SYSCALL_PARAM_TYPE_VAL, TZ_SYSCALL_PARAM_TYPE_BUF_RW, \
+	TZ_SYSCALL_PARAM_TYPE_VAL, TZ_SYSCALL_PARAM_TYPE_BUF_RW, \
+	TZ_SYSCALL_PARAM_TYPE_VAL, TZ_SYSCALL_PARAM_TYPE_BUF_RW, \
+	TZ_SYSCALL_PARAM_TYPE_VAL)
+
+#define TZ_APP_GPAPP_OPEN_SESSION_WITH_WHITELIST_ID			\
+	TZ_SYSCALL_CREATE_SMC_ID(TZ_OWNER_TZ_APPS,			\
+	TZ_SVC_APP_ID_PLACEHOLDER, 0x07)
+
+#define TZ_APP_GPAPP_OPEN_SESSION_WITH_WHITELIST_ID_PARAM_ID		\
+	TZ_SYSCALL_CREATE_PARAM_ID_7(					\
+	TZ_SYSCALL_PARAM_TYPE_VAL, TZ_SYSCALL_PARAM_TYPE_BUF_RW,	\
+	TZ_SYSCALL_PARAM_TYPE_VAL, TZ_SYSCALL_PARAM_TYPE_BUF_RW,	\
+	TZ_SYSCALL_PARAM_TYPE_VAL, TZ_SYSCALL_PARAM_TYPE_BUF_RW,	\
+	TZ_SYSCALL_PARAM_TYPE_VAL)
+
+#define TZ_APP_GPAPP_INVOKE_COMMAND_WITH_WHITELIST_ID			\
+	TZ_SYSCALL_CREATE_SMC_ID(TZ_OWNER_TZ_APPS,			\
+	TZ_SVC_APP_ID_PLACEHOLDER, 0x09)
+
+#define TZ_APP_GPAPP_INVOKE_COMMAND_WITH_WHITELIST_ID_PARAM_ID		\
+	TZ_SYSCALL_CREATE_PARAM_ID_7(					\
+	TZ_SYSCALL_PARAM_TYPE_VAL, TZ_SYSCALL_PARAM_TYPE_BUF_RW,	\
+	TZ_SYSCALL_PARAM_TYPE_VAL, TZ_SYSCALL_PARAM_TYPE_BUF_RW,	\
+	TZ_SYSCALL_PARAM_TYPE_VAL, TZ_SYSCALL_PARAM_TYPE_BUF_RW,	\
+	TZ_SYSCALL_PARAM_TYPE_VAL)
+
+#define TZ_OS_LISTENER_RESPONSE_HANDLER_WITH_WHITELIST_ID \
+	TZ_SYSCALL_CREATE_SMC_ID(TZ_OWNER_QSEE_OS, TZ_SVC_LISTENER, 0x05)
+
+#define TZ_OS_LISTENER_RESPONSE_HANDLER_WITH_WHITELIST_PARAM_ID \
+	TZ_SYSCALL_CREATE_PARAM_ID_4( \
+	TZ_SYSCALL_PARAM_TYPE_VAL, TZ_SYSCALL_PARAM_TYPE_VAL, \
+	TZ_SYSCALL_PARAM_TYPE_BUF_RW, TZ_SYSCALL_PARAM_TYPE_VAL)
+
 #endif /* __QSEECOMI_H_ */
diff --git a/include/soc/qcom/subsystem_restart.h b/include/soc/qcom/subsystem_restart.h
index c13b864..c71ca17 100644
--- a/include/soc/qcom/subsystem_restart.h
+++ b/include/soc/qcom/subsystem_restart.h
@@ -18,6 +18,7 @@
 #include <linux/interrupt.h>
 
 #define MAX_SSR_REASON_LEN  81U
+#define MAX_CRASH_TIMESTAMP_LEN  30U
 
 struct subsys_device;
 
@@ -88,6 +89,7 @@
 	bool system_debug;
 	const char *edge;
 	char last_crash_reason[MAX_SSR_REASON_LEN];
+	char last_crash_timestamp[MAX_CRASH_TIMESTAMP_LEN];
 };
 
 /**
@@ -107,6 +109,8 @@
 	struct platform_device *pdev;
 };
 
+extern struct timezone sys_tz;
+
 #if defined(CONFIG_MSM_SUBSYSTEM_RESTART)
 
 extern int subsys_get_restart_level(struct subsys_device *dev);
diff --git a/kernel/irq/pm.c b/kernel/irq/pm.c
index 3ca5325..2abbaf8 100644
--- a/kernel/irq/pm.c
+++ b/kernel/irq/pm.c
@@ -11,7 +11,7 @@
 #include <linux/interrupt.h>
 #include <linux/suspend.h>
 #include <linux/syscore_ops.h>
-
+#include <linux/wakeup_reason.h>
 #include "internals.h"
 
 bool irq_pm_check_wakeup(struct irq_desc *desc)
@@ -21,6 +21,10 @@
 		desc->istate |= IRQS_SUSPENDED | IRQS_PENDING;
 		desc->depth++;
 		irq_disable(desc);
+		log_suspend_abort_reason("Wakeup IRQ %d %s pending",
+					 desc->irq_data.irq,
+					 (desc->action && desc->action->name) ?
+						 desc->action->name : "");
 		pm_system_wakeup();
 		return true;
 	}
diff --git a/kernel/power/process.c b/kernel/power/process.c
index 7456dcb..b09178f 100644
--- a/kernel/power/process.c
+++ b/kernel/power/process.c
@@ -36,9 +36,6 @@
 	unsigned int elapsed_msecs;
 	bool wakeup = false;
 	int sleep_usecs = USEC_PER_MSEC;
-#ifdef CONFIG_PM_SLEEP
-	char suspend_abort[MAX_SUSPEND_ABORT_LEN];
-#endif
 
 	do_gettimeofday(&start);
 
@@ -68,11 +65,6 @@
 			break;
 
 		if (pm_wakeup_pending()) {
-#ifdef CONFIG_PM_SLEEP
-			pm_get_active_wakeup_sources(suspend_abort,
-				MAX_SUSPEND_ABORT_LEN);
-			log_suspend_abort_reason(suspend_abort);
-#endif
 			wakeup = true;
 			break;
 		}
diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c
index 195d57a..db2d5e3 100644
--- a/kernel/power/suspend.c
+++ b/kernel/power/suspend.c
@@ -273,6 +273,7 @@
 	if (!error)
 		return 0;
 
+	log_suspend_abort_reason("One or more tasks refusing to freeze");
 	suspend_stats.failed_freeze++;
 	dpm_save_failed_step(SUSPEND_FREEZE);
  Finish:
@@ -302,7 +303,6 @@
  */
 static int suspend_enter(suspend_state_t state, bool *wakeup)
 {
-	char suspend_abort[MAX_SUSPEND_ABORT_LEN];
 	int error, last_dev;
 
 	error = platform_suspend_prepare(state);
@@ -371,9 +371,6 @@
 				state, false);
 			events_check_enabled = false;
 		} else if (*wakeup) {
-			pm_get_active_wakeup_sources(suspend_abort,
-				MAX_SUSPEND_ABORT_LEN);
-			log_suspend_abort_reason(suspend_abort);
 			error = -EBUSY;
 		}
 
diff --git a/kernel/power/wakeup_reason.c b/kernel/power/wakeup_reason.c
index dcf9dd5..e153923 100644
--- a/kernel/power/wakeup_reason.c
+++ b/kernel/power/wakeup_reason.c
@@ -436,12 +436,13 @@
 void log_suspend_abort_reason(const char *fmt, ...)
 {
 	va_list args;
+	unsigned long flags;
 
-	spin_lock(&resume_reason_lock);
+	spin_lock_irqsave(&resume_reason_lock, flags);
 
 	//Suspend abort reason has already been logged.
 	if (suspend_abort) {
-		spin_unlock(&resume_reason_lock);
+		spin_unlock_irqrestore(&resume_reason_lock, flags);
 		return;
 	}
 
@@ -450,7 +451,7 @@
 	vsnprintf(abort_reason, MAX_SUSPEND_ABORT_LEN, fmt, args);
 	va_end(args);
 
-	spin_unlock(&resume_reason_lock);
+	spin_unlock_irqrestore(&resume_reason_lock, flags);
 }
 
 static bool match_node(struct wakeup_irq_node *n, void *_p)
@@ -462,9 +463,10 @@
 int check_wakeup_reason(int irq)
 {
 	bool found;
-	spin_lock(&resume_reason_lock);
+	unsigned long flags;
+	spin_lock_irqsave(&resume_reason_lock, flags);
 	found = !walk_irq_node_tree(base_irq_nodes, match_node, &irq);
-	spin_unlock(&resume_reason_lock);
+	spin_unlock_irqrestore(&resume_reason_lock, flags);
 	return found;
 }
 
@@ -544,11 +546,12 @@
 static int wakeup_reason_pm_event(struct notifier_block *notifier,
 		unsigned long pm_event, void *unused)
 {
+	unsigned long flags;
 	switch (pm_event) {
 	case PM_SUSPEND_PREPARE:
-		spin_lock(&resume_reason_lock);
+		spin_lock_irqsave(&resume_reason_lock, flags);
 		suspend_abort = false;
-		spin_unlock(&resume_reason_lock);
+		spin_unlock_irqrestore(&resume_reason_lock, flags);
 		/* monotonic time since boot */
 		last_monotime = ktime_get();
 		/* monotonic time since boot including the time spent in suspend */
diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c
index 69690c7..aba6a55 100644
--- a/kernel/rcu/tree.c
+++ b/kernel/rcu/tree.c
@@ -1123,6 +1123,8 @@
 
 	/* Complain about tasks blocking the grace period. */
 
+	trigger_allbutself_cpu_backtrace();
+
 	rcu_print_detail_task_stall(rsp);
 
 	force_quiescent_state(rsp);  /* Kick them all. */
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index 50885d9..2e73693 100644
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -4015,7 +4015,7 @@
 #endif
 
 #ifdef CONFIG_CPU_FREQ_GOV_SCHED
-static void update_capacity_of(int cpu)
+static void update_capacity_of(int cpu, bool request)
 {
 	unsigned long req_cap;
 
@@ -4025,7 +4025,7 @@
 	/* Convert scale-invariant capacity to cpu. */
 	req_cap = boosted_cpu_util(cpu);
 	req_cap = req_cap * SCHED_CAPACITY_SCALE / capacity_orig_of(cpu);
-	set_cfs_cpu_capacity(cpu, true, req_cap);
+	set_cfs_cpu_capacity(cpu, request, req_cap);
 }
 #endif
 
@@ -4097,7 +4097,7 @@
 		 * request after load balancing is done.
 		 */
 		if (task_new || task_wakeup)
-			update_capacity_of(cpu_of(rq));
+			update_capacity_of(cpu_of(rq), true);
 	}
 
 	/* Get the top level CFS RQ for the task CPU */
@@ -4188,9 +4188,9 @@
 		 */
 		if (task_sleep) {
 			if (rq->cfs.nr_running)
-				update_capacity_of(cpu_of(rq));
+				update_capacity_of(cpu_of(rq), true);
 			else if (sched_freq())
-				set_cfs_cpu_capacity(cpu_of(rq), false, 0);
+				update_capacity_of(cpu_of(rq), false);
 		}
 	}
 
@@ -6677,7 +6677,7 @@
 	/*
 	 * We want to potentially raise target_cpu's OPP.
 	 */
-	update_capacity_of(cpu_of(rq));
+	update_capacity_of(cpu_of(rq), true);
 	raw_spin_unlock(&rq->lock);
 }
 
@@ -6702,7 +6702,7 @@
 	/*
 	 * We want to potentially raise env.dst_cpu's OPP.
 	 */
-	update_capacity_of(env->dst_cpu);
+	update_capacity_of(env->dst_cpu, true);
 
 	raw_spin_unlock(&env->dst_rq->lock);
 }
@@ -7988,7 +7988,7 @@
 		 * We want to potentially lower env.src_cpu's OPP.
 		 */
 		if (cur_ld_moved)
-			update_capacity_of(env.src_cpu);
+			update_capacity_of(env.src_cpu, true);
 
 		/*
 		 * We've detached some tasks from busiest_rq. Every
@@ -8320,7 +8320,7 @@
 		 * No task pulled and someone has been migrated away.
 		 * Good case to trigger an OPP update.
 		 */
-		update_capacity_of(this_cpu);
+		update_capacity_of(this_cpu, true);
 	}
 
 	return pulled_task;
@@ -8385,7 +8385,7 @@
 			/*
 			 * We want to potentially lower env.src_cpu's OPP.
 			 */
-			update_capacity_of(env.src_cpu);
+			update_capacity_of(env.src_cpu, true);
 		}
 		else
 			schedstat_inc(sd, alb_failed);
diff --git a/sound/soc/codecs/wcd-mbhc-v2.c b/sound/soc/codecs/wcd-mbhc-v2.c
index 252ad93..e314097 100755
--- a/sound/soc/codecs/wcd-mbhc-v2.c
+++ b/sound/soc/codecs/wcd-mbhc-v2.c
@@ -885,14 +885,14 @@
 		}
 
 		if (mbhc->micbias_enable) {
-			if (mbhc->mbhc_cb->mbhc_micbias_control)
-				mbhc->mbhc_cb->mbhc_micbias_control(
-						mbhc->codec, MIC_BIAS_2,
-						MICB_DISABLE);
 			if (mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic)
 				mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic(
 						mbhc->codec,
 						MIC_BIAS_2, false);
+			if (mbhc->mbhc_cb->mbhc_micbias_control)
+				mbhc->mbhc_cb->mbhc_micbias_control(
+						mbhc->codec, MIC_BIAS_2,
+						MICB_DISABLE);
 			if (mbhc->mbhc_cb->set_micbias_value) {
 				mbhc->mbhc_cb->set_micbias_value(mbhc->codec);
 				WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_MICB_CTRL, 0);
@@ -923,14 +923,14 @@
 		    (mbhc->hph_status && mbhc->hph_status != jack_type)) {
 
 			if (mbhc->micbias_enable && (mbhc->current_plug != MBHC_PLUG_TYPE_HIGH_HPH)) { //HTC_AUD
-				if (mbhc->mbhc_cb->mbhc_micbias_control)
-					mbhc->mbhc_cb->mbhc_micbias_control(
-						mbhc->codec, MIC_BIAS_2,
-						MICB_DISABLE);
 				if (mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic)
 					mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic(
 						mbhc->codec,
 						MIC_BIAS_2, false);
+				if (mbhc->mbhc_cb->mbhc_micbias_control)
+					mbhc->mbhc_cb->mbhc_micbias_control(
+						mbhc->codec, MIC_BIAS_2,
+						MICB_DISABLE);
 				if (mbhc->mbhc_cb->set_micbias_value) {
 					mbhc->mbhc_cb->set_micbias_value(
 							mbhc->codec);
@@ -1584,6 +1584,10 @@
 				hs_comp_res = 0;
 				spl_hs = true;
 				mbhc->micbias_enable = true;
+				/* Increase vote on micbias */
+				mbhc->mbhc_cb->mbhc_micbias_control(codec,
+								MIC_BIAS_2,
+								MICB_ENABLE);
 			}
 		}
 
@@ -1727,8 +1731,7 @@
 	else
 		wcd_enable_mbhc_supply(mbhc, plug_type);
 exit:
-	if (mbhc->mbhc_cb->mbhc_micbias_control &&
-	    !mbhc->micbias_enable)
+	if (mbhc->mbhc_cb->mbhc_micbias_control)
 		mbhc->mbhc_cb->mbhc_micbias_control(codec, MIC_BIAS_2,
 						    MICB_DISABLE);
 	if (mbhc->mbhc_cb->micbias_enable_status) {
diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c
index 1329adf..c480277 100755
--- a/sound/soc/codecs/wcd9335.c
+++ b/sound/soc/codecs/wcd9335.c
@@ -11565,8 +11565,9 @@
 		goto unlock_mutex;
 
 	if (tasha->power_active_ref < 0) {
-		dev_dbg(tasha->dev, "%s: power_active_ref is negative\n",
+		dev_info(tasha->dev, "%s: power_active_ref is negative\n",
 			__func__);
+		tasha->power_active_ref = 0;
 		goto unlock_mutex;
 	}