Merge "msm: kgsl: Add a timer to detect possible syncpoint deadlocks"
diff --git a/Documentation/devicetree/bindings/arm/msm/msm_thermal.txt b/Documentation/devicetree/bindings/arm/msm/msm_thermal.txt
index 15b94ca..bbc9f08 100644
--- a/Documentation/devicetree/bindings/arm/msm/msm_thermal.txt
+++ b/Documentation/devicetree/bindings/arm/msm/msm_thermal.txt
@@ -88,6 +88,18 @@
 - <consumer_supply_name>-supply = <&phandle_of_regulator>: consumer_supply_name
 			is the name that's defined in thermal driver.
 			phandle_of_regulator is defined by reuglator device tree.
+- qcom,default-temp:    Default cpu temperature limit for SoC. It is an optional
+			property. Not defining this property requires a full truth
+			table for qcom,efuse temperature map and valid efuse info for
+			qcom,efuse-data otherwise feature will be disabled.
+- qcom,efuse-data:      Efuse data for getting device parts info for cpu temperature
+			limit recommendation for SoC. It expects below data in order to
+			read target parts, efuse address, efuse size, row number to be
+			read, starting bit number of the row for identifying device parts
+			and number of bits to read from start bit as bit mask.
+- qcom,efuse-temperature-map: Truth table of efuse value temperature value pair for
+			different parts. if qcom,default temp is defined, then it can
+			specify only pairs which deviate from default temperature.
 
 Optional child nodes
 - qti,pmic-opt-curr-temp: Threshold temperature for requesting optimum current (request
@@ -147,6 +159,9 @@
 		qti,pmic-opt-curr-temp-hysteresis = <10>;
 		qti,pmic-opt-curr-regs = "vdd-dig";
 		vdd-dig-supply=<&pm8841_s2_floor_corner>
+		qcom,default-temp = <80>;
+		qcom,efuse-data = <0xfc4b8000 0x1000 23 30 0x3>;
+		qcom,efuse-temperature-map = <0x0 80>, <0x1 70>, <0x2 80>, <0x3 80>;
 
 		qcom,vdd-dig-rstr{
 			qcom,vdd-rstr-reg = "vdd-dig";
diff --git a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
index f6b4923..3144045 100644
--- a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
@@ -172,6 +172,8 @@
 					horizontal back porch (HBP) blanking period.
 - qcom,mdss-dsi-hsa-power-mode:		Boolean to determine DSI lane state during
 					horizontal sync active (HSA) mode.
+- qcom,mdss-dsi-last-line-interleave	Boolean to determine if last line
+					interleave flag needs to be enabled.
 - qcom,mdss-dsi-bllp-eof-power-mode:	Boolean to determine DSI lane state during
 					blanking low power period (BLLP) EOF mode.
 - qcom,mdss-dsi-bllp-power-mode:	Boolean to determine DSI lane state during
@@ -347,6 +349,7 @@
 		qcom,mdss-dsi-hsa-power-mode;
 		qcom,mdss-dsi-bllp-eof-power-mode;
 		qcom,mdss-dsi-bllp-power-mode;
+		qcom,mdss-dsi-last-line-interleave;
 		qcom,mdss-dsi-traffic-mode = <0>;
 		qcom,mdss-dsi-virtual-channel-id = <0>;
 		qcom,mdss-dsi-color-order = <0>;
diff --git a/Documentation/devicetree/bindings/media/video/msm-cci.txt b/Documentation/devicetree/bindings/media/video/msm-cci.txt
index f256d78..da54138 100644
--- a/Documentation/devicetree/bindings/media/video/msm-cci.txt
+++ b/Documentation/devicetree/bindings/media/video/msm-cci.txt
@@ -171,6 +171,22 @@
     - 0 -> MASTER 0
     - 1 -> MASTER 1
 
+Optional properties:
+- qcom,cam-vreg-name : should contain names of all regulators needed by this
+    actuator
+    - "cam_vaf"
+- qcom,cam-vreg-type : should contain regulator type for regulators mentioned in
+    qcom,cam-vreg-name property (in the same order)
+    - 0 for LDO and 1 for LVS
+- qcom,cam-vreg-min-voltage : should contain minimum voltage level in mcrovolts
+   for regulators mentioned in qcom,cam-vreg-name property (in the same order)
+- qcom,cam-vreg-max-voltage : should contain maximum voltage level in mcrovolts
+   for regulators mentioned in qcom,cam-vreg-name property (in the same order)
+- qcom,cam-vreg-op-mode : should contain the maximum current in microamps
+   required from the regulators mentioned in the qcom,cam-vreg-name property
+   (in the same order).
+- cam_vaf-supply : should contain regulator from which AF voltage is supplied
+
 Example:
 
    qcom,cci@0xfda0c000 {
@@ -200,8 +216,14 @@
         actuator0: qcom,actuator@18 {
                 cell-index = <0>;
                 reg = <0x18>;
-                compatible = "qcom,actuator";
-                qcom,cci-master = <0>;
+		compatible = "qcom,actuator";
+		qcom,cci-master = <0>;
+		cam_vaf-supply = <&pm8941_l23>;
+		qcom,cam-vreg-name = "cam_vaf";
+		qcom,cam-vreg-type = <0>;
+		qcom,cam-vreg-min-voltage = <3000000>;
+		qcom,cam-vreg-max-voltage = <3000000>;
+		qcom,cam-vreg-op-mode = <100000>;
         };
 
        qcom,s5k3l1yx@6e {
diff --git a/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt b/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt
index 5201827..8eb9b64 100644
--- a/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt
+++ b/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt
@@ -27,6 +27,15 @@
 should be performed during boot up.
 - qcom,wlan-rx-buff-count: WLAN RX buffer count is a configurable value,
 using a smaller count for this buffer will reduce the memory usage.
+- qcom,wcnss-pm : <Core rail LDO#, PA rail LDO#, XO settling time,
+                   RPM power collapse enabled, standalone power collapse enabled>
+        Power manager related parameter for LDO configuration.
+        11     -  WCN CORE rail LDO number
+        21     -  WCN PA rail LDO number
+        1200   -  WCN XO settling time (usec)
+        1      -  WCN RPM power collapse enabled
+        1      -  WCN standalone power collapse enabled
+
 
 Example:
 
@@ -51,4 +60,5 @@
         qcom,has-48mhz-xo;
         qcom,has-pronto-hw;
         qcom,wcnss-adc_tm = <&pm8226_adc_tm>;
+	qcom,wcnss-pm = <11 21 1200 1 1>;
     };
diff --git a/arch/arm/boot/dts/msm8610.dtsi b/arch/arm/boot/dts/msm8610.dtsi
index 90dae06..d243b78 100644
--- a/arch/arm/boot/dts/msm8610.dtsi
+++ b/arch/arm/boot/dts/msm8610.dtsi
@@ -895,6 +895,9 @@
 		qcom,hotplug-temp-hysteresis = <20>;
 		qcom,cpu-sensors = "tsens_tz_sensor5", "tsens_tz_sensor5",
 				"tsens_tz_sensor5", "tsens_tz_sensor5";
+		qcom,default-temp = <80>;
+		qcom,efuse-data = <0xfc4b8000 0x1000 23 30 0x3>;
+		qcom,efuse-temperature-map = <0x1 70>;
 		qcom,vdd-restriction-temp = <5>;
 		qcom,vdd-restriction-temp-hysteresis = <10>;
 		vdd-dig-supply = <&pm8110_s1_floor_corner>;
diff --git a/arch/arm/boot/dts/msm8974pro-ab-pm8941.dtsi b/arch/arm/boot/dts/msm8974pro-ab-pm8941.dtsi
index a44bc56..d0bf90a 100644
--- a/arch/arm/boot/dts/msm8974pro-ab-pm8941.dtsi
+++ b/arch/arm/boot/dts/msm8974pro-ab-pm8941.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2014, 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
@@ -22,3 +22,29 @@
 		      <217 0x10000>,
 		      <218 0x10000>;
 };
+
+&soc {
+	i2c@f9928000 { /* BLSP1 QUP6 */
+		nfc-nci@e {
+			compatible = "qcom,nfc-nci";
+			reg = <0x0e>;
+			qcom,irq-gpio = <&msmgpio 57 0x00>;
+			qcom,dis-gpio = <&msmgpio 13 0x00>;
+			qcom,clk-src = "BBCLK2";
+			interrupt-parent = <&msmgpio>;
+			interrupts = <57 0>;
+			qcom,clk-gpio = <&pm8941_gpios 32 0>;
+		};
+	};
+};
+
+&pm8941_gpios {
+	gpio@df00 {
+		/* NFC clk request */
+		qcom,mode = <0>;                /* QPNP_PIN_MODE_DIG_IN */
+		qcom,pull = <5>;                /* QPNP_PIN_PULL_NO */
+		qcom,vin-sel = <2>;             /* QPNP_PIN_VIN2 */
+		qcom,src-sel = <2>;             /* QPNP_PIN_SEL_FUNC_1 */
+		qcom,master-en = <1>;
+	};
+};
diff --git a/arch/arm/boot/dts/msm8974pro.dtsi b/arch/arm/boot/dts/msm8974pro.dtsi
index d398f72..bb4c619 100644
--- a/arch/arm/boot/dts/msm8974pro.dtsi
+++ b/arch/arm/boot/dts/msm8974pro.dtsi
@@ -1593,12 +1593,12 @@
 		<26 512 0 3680000>, <89 604 0 6224000>,
 		/* Nominal / Nominal */
 		<26 512 0 4912000>, <89 604 0 6224000>,
-		/* low Turbo / Nominal */
-		<26 512 0 6400000>, <89 604 0 6224000>,
+		/* Turbo / Nominal */
+		<26 512 0 7464000>, <89 604 0 6224000>,
+		/* low Nominal / low Turbo */
+		<26 512 0 3680000>, <89 604 0 7398000>,
 		/* Nominal / low Turbo */
 		<26 512 0 4912000>, <89 604 0 7398000>,
-		/* low Turbo / low Turbo */
-		<26 512 0 6400000>, <89 604 0 7398000>,
 		/* Turbo / low Turbo */
 		<26 512 0 7464000>, <89 604 0 7398000>,
 		/* Nominal / Turbo */
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index 6b551cd..3721809 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -1837,22 +1837,6 @@
 	  Support for receiving handset events like headset detect,
 	  headset switch and clamshell state.
 
-config MSM_RMT_STORAGE_CLIENT
-	depends on (ARCH_MSM && MSM_ONCRPCROUTER)
-	default n
-	bool "Remote Storage RPC client"
-	help
-	  Provide RPC mechanism for remote processors to access storage
-	  device on apps processor.
-
-config MSM_RMT_STORAGE_CLIENT_STATS
-	depends on (MSM_RMT_STORAGE_CLIENT && DEBUG_FS)
-	default n
-	bool "Remote storage RPC client performance statistics"
-	help
-	  Collects performance statistics and shows this information
-	  through a debugfs file rmt_storage_stats.
-
 config MSM_DALRPC
 	bool "DAL RPC support"
 	default n
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index 5f7f0d9..c945b10 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -314,7 +314,6 @@
 
 obj-$(CONFIG_HTC_PWRSINK) += htc_pwrsink.o
 obj-$(CONFIG_HTC_HEADSET) += htc_headset.o
-obj-$(CONFIG_MSM_RMT_STORAGE_CLIENT) += rmt_storage_client.o
 obj-$(CONFIG_MSM_RPM) += rpm.o rpm_resources.o
 obj-$(CONFIG_MSM_LPM_TEST) += test-lpm.o
 obj-$(CONFIG_MSM_RPM_SMD) += rpm-smd.o lpm_levels.o
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_aac.c b/arch/arm/mach-msm/qdsp6v2/audio_aac.c
index caeb79d..d95c356 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_aac.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_aac.c
@@ -2,7 +2,7 @@
  *
  * Copyright (C) 2008 Google, Inc.
  * Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2010-2014, The Linux Foundation. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -232,7 +232,12 @@
 		kfree(audio);
 		return -ENOMEM;
 	}
-
+	rc = audio_aio_open(audio, file);
+	if (rc < 0) {
+		pr_err("%s: audio_aio_open rc=%d\n",
+			__func__, rc);
+		goto fail;
+	}
 	/* open in T/NT mode */
 	if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) {
 		rc = q6asm_open_read_write(audio->ac, FORMAT_LINEAR_PCM,
@@ -261,11 +266,6 @@
 		rc = -EACCES;
 		goto fail;
 	}
-	rc = audio_aio_open(audio, file);
-	if (rc < 0) {
-		pr_err("audio_aio_open rc=%d\n", rc);
-		goto fail;
-	}
 
 #ifdef CONFIG_DEBUG_FS
 	snprintf(name, sizeof name, "msm_aac_%04x", audio->ac->session);
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_amrnb.c b/arch/arm/mach-msm/qdsp6v2/audio_amrnb.c
index fc023c1..5d57293 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_amrnb.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_amrnb.c
@@ -2,7 +2,7 @@
  *
  * Copyright (C) 2008 Google, Inc.
  * Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2014, The Linux Foundation. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -91,7 +91,12 @@
 		kfree(audio);
 		return -ENOMEM;
 	}
-
+	rc = audio_aio_open(audio, file);
+	if (rc < 0) {
+		pr_err("%s: audio_aio_open rc=%d\n",
+			__func__, rc);
+		goto fail;
+	}
 	/* open in T/NT mode */
 	if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) {
 		rc = q6asm_open_read_write(audio->ac, FORMAT_LINEAR_PCM,
@@ -119,11 +124,6 @@
 		rc = -EACCES;
 		goto fail;
 	}
-	rc = audio_aio_open(audio, file);
-	if (rc < 0) {
-		pr_err("audio_aio_open rc=%d\n", rc);
-		goto fail;
-	}
 
 #ifdef CONFIG_DEBUG_FS
 	snprintf(name, sizeof name, "msm_amrnb_%04x", audio->ac->session);
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_amrwb.c b/arch/arm/mach-msm/qdsp6v2/audio_amrwb.c
index 256da4d..d2728b7 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_amrwb.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_amrwb.c
@@ -2,7 +2,7 @@
  *
  * Copyright (C) 2008 Google, Inc.
  * Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2014, The Linux Foundation. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -93,6 +93,12 @@
 		kfree(audio);
 		return -ENOMEM;
 	}
+	rc = audio_aio_open(audio, file);
+	if (rc < 0) {
+		pr_err("%s: audio_aio_open rc=%d\n",
+			__func__, rc);
+		goto fail;
+	}
 
 	/* open in T/NT mode */
 	if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) {
@@ -121,11 +127,6 @@
 		rc = -EACCES;
 		goto fail;
 	}
-	rc = audio_aio_open(audio, file);
-	if (rc < 0) {
-		pr_err("audio_aio_open rc=%d\n", rc);
-		goto fail;
-	}
 
 #ifdef CONFIG_DEBUG_FS
 	snprintf(name, sizeof name, "msm_amrwb_%04x", audio->ac->session);
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_amrwbplus.c b/arch/arm/mach-msm/qdsp6v2/audio_amrwbplus.c
index 544bf9c..8169914 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_amrwbplus.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_amrwbplus.c
@@ -2,7 +2,7 @@
  *
  * Copyright (C) 2008 Google, Inc.
  * Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2010-2014, The Linux Foundation. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -170,6 +170,12 @@
 		kfree(audio);
 		return -ENOMEM;
 	}
+	rc = audio_aio_open(audio, file);
+	if (rc < 0) {
+		pr_err("%s: audio_aio_open rc=%d\n",
+			__func__, rc);
+		goto fail;
+	}
 
 	/* open in T/NT mode */
 	if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) {
@@ -198,11 +204,6 @@
 		rc = -EACCES;
 		goto fail;
 	}
-	rc = audio_aio_open(audio, file);
-	if (rc < 0) {
-		pr_err("audio_aio_open rc=%d\n", rc);
-		goto fail;
-	}
 
 	config_debug_fs(audio);
 	pr_debug("%s: AMRWBPLUS dec success mode[%d]session[%d]\n", __func__,
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_evrc.c b/arch/arm/mach-msm/qdsp6v2/audio_evrc.c
index 3498e69..2de2178 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_evrc.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_evrc.c
@@ -2,7 +2,7 @@
  *
  * Copyright (C) 2008 Google, Inc.
  * Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2014, The Linux Foundation. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -99,6 +99,12 @@
 		kfree(audio);
 		return -ENOMEM;
 	}
+	rc = audio_aio_open(audio, file);
+	if (rc < 0) {
+		pr_err("%s: audio_aio_open rc=%d\n",
+			__func__, rc);
+		goto fail;
+	}
 
 	/* open in T/NT mode */
 	if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) {
@@ -127,11 +133,6 @@
 		rc = -EACCES;
 		goto fail;
 	}
-	rc = audio_aio_open(audio, file);
-	if (rc < 0) {
-		pr_err("audio_aio_open rc=%d\n", rc);
-		goto fail;
-	}
 
 #ifdef CONFIG_DEBUG_FS
 	snprintf(name, sizeof name, "msm_evrc_%04x", audio->ac->session);
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_mp3.c b/arch/arm/mach-msm/qdsp6v2/audio_mp3.c
index d2f0270..9132486 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_mp3.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_mp3.c
@@ -2,7 +2,7 @@
  *
  * Copyright (C) 2008 Google, Inc.
  * Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2014, The Linux Foundation. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -98,6 +98,12 @@
 		kfree(audio);
 		return -ENOMEM;
 	}
+	rc = audio_aio_open(audio, file);
+	if (rc < 0) {
+		pr_err("%s: audio_aio_open rc=%d\n",
+			__func__, rc);
+		goto fail;
+	}
 
 	/* open in T/NT mode */
 	if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) {
@@ -127,11 +133,6 @@
 		rc = -EACCES;
 		goto fail;
 	}
-	rc = audio_aio_open(audio, file);
-	if (rc < 0) {
-		pr_err("audio_aio_open rc=%d\n", rc);
-		goto fail;
-	}
 
 #ifdef CONFIG_DEBUG_FS
 	snprintf(name, sizeof name, "msm_mp3_%04x", audio->ac->session);
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_multi_aac.c b/arch/arm/mach-msm/qdsp6v2/audio_multi_aac.c
index 0a8ce8e..ecea6d0 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_multi_aac.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_multi_aac.c
@@ -2,7 +2,7 @@
  *
  * Copyright (C) 2008 Google, Inc.
  * Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2014, The Linux Foundation. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -252,6 +252,12 @@
 		kfree(audio);
 		return -ENOMEM;
 	}
+	rc = audio_aio_open(audio, file);
+	if (rc < 0) {
+		pr_err("%s: audio_aio_open rc=%d\n",
+			__func__, rc);
+		goto fail;
+	}
 
 	/* open in T/NT mode */
 	if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) {
@@ -281,11 +287,6 @@
 		rc = -EACCES;
 		goto fail;
 	}
-	rc = audio_aio_open(audio, file);
-	if (rc < 0) {
-		pr_err("audio_aio_open rc=%d\n", rc);
-		goto fail;
-	}
 
 #ifdef CONFIG_DEBUG_FS
 	snprintf(name, sizeof name, "msm_multi_aac_%04x", audio->ac->session);
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_qcelp.c b/arch/arm/mach-msm/qdsp6v2/audio_qcelp.c
index 4993226..acfcb65 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_qcelp.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_qcelp.c
@@ -2,7 +2,7 @@
  *
  * Copyright (C) 2008 Google, Inc.
  * Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2014, The Linux Foundation. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -104,6 +104,12 @@
 		kfree(audio);
 		return -ENOMEM;
 	}
+	rc = audio_aio_open(audio, file);
+	if (rc < 0) {
+		pr_err("%s: audio_aio_open rc=%d\n",
+			__func__, rc);
+		goto fail;
+	}
 
 	/* open in T/NT mode */
 	if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) {
@@ -132,11 +138,6 @@
 		rc = -EACCES;
 		goto fail;
 	}
-	rc = audio_aio_open(audio, file);
-	if (rc < 0) {
-		pr_err("audio_aio_open rc=%d\n", rc);
-		goto fail;
-	}
 
 #ifdef CONFIG_DEBUG_FS
 	snprintf(name, sizeof name, "msm_qcelp_%04x", audio->ac->session);
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_wma.c b/arch/arm/mach-msm/qdsp6v2/audio_wma.c
index 5e3de86..5a64a69 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_wma.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_wma.c
@@ -2,7 +2,7 @@
  *
  * Copyright (C) 2008 Google, Inc.
  * Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2009-2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2009-2014, The Linux Foundation. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -138,6 +138,12 @@
 		kfree(audio);
 		return -ENOMEM;
 	}
+	rc = audio_aio_open(audio, file);
+	if (rc < 0) {
+		pr_err("%s: audio_aio_open rc=%d\n",
+			__func__, rc);
+		goto fail;
+	}
 	/* open in T/NT mode */
 	if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) {
 		rc = q6asm_open_read_write(audio->ac, FORMAT_LINEAR_PCM,
@@ -166,11 +172,6 @@
 		rc = -EACCES;
 		goto fail;
 	}
-	rc = audio_aio_open(audio, file);
-	if (rc < 0) {
-		pr_err("audio_aio_open rc=%d\n", rc);
-		goto fail;
-	}
 
 #ifdef CONFIG_DEBUG_FS
 	snprintf(name, sizeof name, "msm_wma_%04x", audio->ac->session);
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_wmapro.c b/arch/arm/mach-msm/qdsp6v2/audio_wmapro.c
index ce49cac..7d0edf0 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_wmapro.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_wmapro.c
@@ -2,7 +2,7 @@
  *
  * Copyright (C) 2008 Google, Inc.
  * Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2009-2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2009-2014, The Linux Foundation. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -198,6 +198,12 @@
 		return -ENOMEM;
 	}
 
+	rc = audio_aio_open(audio, file);
+	if (rc < 0) {
+		pr_err("%s: audio_aio_open rc=%d\n",
+			__func__, rc);
+		goto fail;
+	}
 	/* open in T/NT mode */
 	if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) {
 		rc = q6asm_open_read_write(audio->ac, FORMAT_LINEAR_PCM,
@@ -226,11 +232,6 @@
 		rc = -EACCES;
 		goto fail;
 	}
-	rc = audio_aio_open(audio, file);
-	if (rc < 0) {
-		pr_err("audio_aio_open rc=%d\n", rc);
-		goto fail;
-	}
 
 #ifdef CONFIG_DEBUG_FS
 	snprintf(name, sizeof name, "msm_wmapro_%04x", audio->ac->session);
diff --git a/arch/arm/mach-msm/rmt_storage_client.c b/arch/arm/mach-msm/rmt_storage_client.c
deleted file mode 100644
index 550624c..0000000
--- a/arch/arm/mach-msm/rmt_storage_client.c
+++ /dev/null
@@ -1,1839 +0,0 @@
-/* Copyright (c) 2009-2013, 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
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- */
-
-#include <linux/miscdevice.h>
-#include <linux/wait.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/mm.h>
-#include <linux/fs.h>
-#include <linux/err.h>
-#include <linux/sched.h>
-#include <linux/wakelock.h>
-#include <linux/rmt_storage_client.h>
-#include <linux/debugfs.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/reboot.h>
-#include <asm/uaccess.h>
-#include <asm/pgtable.h>
-#include <mach/msm_rpcrouter.h>
-#ifdef CONFIG_MSM_SDIO_SMEM
-#include <mach/sdio_smem.h>
-#endif
-#include <mach/msm_smem.h>
-
-enum {
-	RMT_STORAGE_EVNT_OPEN = 0,
-	RMT_STORAGE_EVNT_CLOSE,
-	RMT_STORAGE_EVNT_WRITE_BLOCK,
-	RMT_STORAGE_EVNT_GET_DEV_ERROR,
-	RMT_STORAGE_EVNT_WRITE_IOVEC,
-	RMT_STORAGE_EVNT_SEND_USER_DATA,
-	RMT_STORAGE_EVNT_READ_IOVEC,
-	RMT_STORAGE_EVNT_ALLOC_RMT_BUF,
-} rmt_storage_event;
-
-struct shared_ramfs_entry {
-	uint32_t client_id;	/* Client id to uniquely identify a client */
-	uint32_t base_addr;	/* Base address of shared RAMFS memory */
-	uint32_t size;		/* Size of the shared RAMFS memory */
-	uint32_t client_sts;	/* This will be initialized to 1 when
-				   remote storage RPC client is ready
-				   to process requests */
-};
-struct shared_ramfs_table {
-	uint32_t magic_id;	/* Identify RAMFS details in SMEM */
-	uint32_t version;	/* Version of shared_ramfs_table */
-	uint32_t entries;	/* Total number of valid entries   */
-	/* List all entries */
-	struct shared_ramfs_entry ramfs_entry[MAX_RAMFS_TBL_ENTRIES];
-};
-
-struct rmt_storage_client_info {
-	unsigned long cids;
-	struct list_head shrd_mem_list; /* List of shared memory entries */
-	int open_excl;
-	atomic_t total_events;
-	wait_queue_head_t event_q;
-	struct list_head event_list;
-	struct list_head client_list;	/* List of remote storage clients */
-	/* Lock to protect lists */
-	spinlock_t lock;
-	/* Wakelock to be acquired when processing requests from modem */
-	struct wake_lock wlock;
-	atomic_t wcount;
-	struct workqueue_struct *workq;
-};
-
-struct rmt_storage_kevent {
-	struct list_head list;
-	struct rmt_storage_event event;
-};
-
-/* Remote storage server on modem */
-struct rmt_storage_srv {
-	uint32_t prog;
-	int sync_token;
-	struct platform_driver plat_drv;
-	struct msm_rpc_client *rpc_client;
-	struct delayed_work restart_work;
-};
-
-/* Remote storage client on modem */
-struct rmt_storage_client {
-	uint32_t handle;
-	uint32_t sid;			/* Storage ID */
-	char path[MAX_PATH_NAME];
-	struct rmt_storage_srv *srv;
-	struct list_head list;
-};
-
-struct rmt_shrd_mem {
-	struct list_head list;
-	struct rmt_shrd_mem_param param;
-	struct shared_ramfs_entry *smem_info;
-	struct rmt_storage_srv *srv;
-};
-
-static struct rmt_storage_srv *rmt_storage_get_srv(uint32_t prog);
-static uint32_t rmt_storage_get_sid(const char *path);
-#ifdef CONFIG_MSM_SDIO_SMEM
-static void rmt_storage_sdio_smem_work(struct work_struct *work);
-#endif
-
-static struct rmt_storage_client_info *rmc;
-struct rmt_storage_srv *rmt_srv;
-
-#ifdef CONFIG_MSM_SDIO_SMEM
-DECLARE_DELAYED_WORK(sdio_smem_work, rmt_storage_sdio_smem_work);
-#endif
-
-#ifdef CONFIG_MSM_SDIO_SMEM
-#define MDM_LOCAL_BUF_SZ	0xC0000
-static struct sdio_smem_client *sdio_smem;
-#endif
-
-#ifdef CONFIG_MSM_RMT_STORAGE_CLIENT_STATS
-struct rmt_storage_op_stats {
-	unsigned long count;
-	ktime_t start;
-	ktime_t min;
-	ktime_t max;
-	ktime_t total;
-};
-struct rmt_storage_stats {
-       char path[MAX_PATH_NAME];
-       struct rmt_storage_op_stats rd_stats;
-       struct rmt_storage_op_stats wr_stats;
-};
-static struct rmt_storage_stats client_stats[MAX_NUM_CLIENTS];
-static struct dentry *stats_dentry;
-#endif
-
-#define MSM_RMT_STORAGE_APIPROG	0x300000A7
-#define MDM_RMT_STORAGE_APIPROG	0x300100A7
-
-#define RMT_STORAGE_OP_FINISH_PROC              2
-#define RMT_STORAGE_REGISTER_OPEN_PROC          3
-#define RMT_STORAGE_REGISTER_WRITE_IOVEC_PROC   4
-#define RMT_STORAGE_REGISTER_CB_PROC            5
-#define RMT_STORAGE_UN_REGISTER_CB_PROC         6
-#define RMT_STORAGE_FORCE_SYNC_PROC             7
-#define RMT_STORAGE_GET_SYNC_STATUS_PROC        8
-#define RMT_STORAGE_REGISTER_READ_IOVEC_PROC    9
-#define RMT_STORAGE_REGISTER_ALLOC_RMT_BUF_PROC 10
-
-#define RMT_STORAGE_OPEN_CB_TYPE_PROC           1
-#define RMT_STORAGE_WRITE_IOVEC_CB_TYPE_PROC    2
-#define RMT_STORAGE_EVENT_CB_TYPE_PROC          3
-#define RMT_STORAGE_READ_IOVEC_CB_TYPE_PROC     4
-#define RMT_STORAGE_ALLOC_RMT_BUF_CB_TYPE_PROC  5
-
-#define RAMFS_INFO_MAGICNUMBER		0x654D4D43
-#define RAMFS_INFO_VERSION		0x00000001
-#define RAMFS_DEFAULT			0xFFFFFFFF
-
-/* MSM EFS*/
-#define RAMFS_MODEMSTORAGE_ID		0x4D454653
-#define RAMFS_SHARED_EFS_RAM_BASE	0x46100000
-#define RAMFS_SHARED_EFS_RAM_SIZE	(3 * 1024 * 1024)
-
-/* MDM EFS*/
-#define RAMFS_MDM_STORAGE_ID		0x4D4583A1
-/* SSD */
-#define RAMFS_SSD_STORAGE_ID		0x00535344
-#define RAMFS_SHARED_SSD_RAM_BASE	0x42E00000
-#define RAMFS_SHARED_SSD_RAM_SIZE	0x2000
-
-static struct rmt_storage_client *rmt_storage_get_client(uint32_t handle)
-{
-	struct rmt_storage_client *rs_client;
-	list_for_each_entry(rs_client, &rmc->client_list, list)
-		if (rs_client->handle == handle)
-			return rs_client;
-	return NULL;
-}
-
-static struct rmt_storage_client *
-rmt_storage_get_client_by_path(const char *path)
-{
-	struct rmt_storage_client *rs_client;
-	list_for_each_entry(rs_client, &rmc->client_list, list)
-		if (!strncmp(path, rs_client->path, MAX_PATH_NAME))
-			return rs_client;
-	return NULL;
-}
-
-static struct rmt_shrd_mem_param *rmt_storage_get_shrd_mem(uint32_t sid)
-{
-	struct rmt_shrd_mem *shrd_mem;
-	struct rmt_shrd_mem_param *shrd_mem_param = NULL;
-
-	spin_lock(&rmc->lock);
-	list_for_each_entry(shrd_mem, &rmc->shrd_mem_list, list)
-		if (shrd_mem->param.sid == sid)
-			shrd_mem_param = &shrd_mem->param;
-	spin_unlock(&rmc->lock);
-
-	return shrd_mem_param;
-}
-
-static int rmt_storage_add_shrd_mem(uint32_t sid, uint32_t start,
-				    uint32_t size, void *base,
-				    struct shared_ramfs_entry *smem_info,
-				    struct rmt_storage_srv *srv)
-{
-	struct rmt_shrd_mem *shrd_mem;
-
-	shrd_mem = kzalloc(sizeof(struct rmt_shrd_mem), GFP_KERNEL);
-	if (!shrd_mem)
-		return -ENOMEM;
-	shrd_mem->param.sid = sid;
-	shrd_mem->param.start = start;
-	shrd_mem->param.size = size;
-	shrd_mem->param.base = base;
-	shrd_mem->smem_info = smem_info;
-	shrd_mem->srv = srv;
-
-	spin_lock(&rmc->lock);
-	list_add(&shrd_mem->list, &rmc->shrd_mem_list);
-	spin_unlock(&rmc->lock);
-	return 0;
-}
-
-static struct msm_rpc_client *rmt_storage_get_rpc_client(uint32_t handle)
-{
-	struct rmt_storage_client *rs_client;
-
-	rs_client = rmt_storage_get_client(handle);
-	if (!rs_client)
-		return NULL;
-	return rs_client->srv->rpc_client;
-}
-
-static int rmt_storage_validate_iovec(uint32_t handle,
-				      struct rmt_storage_iovec_desc *xfer)
-{
-	struct rmt_storage_client *rs_client;
-	struct rmt_shrd_mem_param *shrd_mem;
-
-	rs_client = rmt_storage_get_client(handle);
-	if (!rs_client)
-		return -EINVAL;
-	shrd_mem = rmt_storage_get_shrd_mem(rs_client->sid);
-	if (!shrd_mem)
-		return -EINVAL;
-
-	if ((xfer->data_phy_addr < shrd_mem->start) ||
-	    ((xfer->data_phy_addr + RAMFS_BLOCK_SIZE * xfer->num_sector) >
-	     (shrd_mem->start + shrd_mem->size)))
-		return -EINVAL;
-	return 0;
-}
-
-static int rmt_storage_send_sts_arg(struct msm_rpc_client *client,
-				struct msm_rpc_xdr *xdr, void *data)
-{
-	struct rmt_storage_send_sts *args = data;
-
-	xdr_send_uint32(xdr, &args->handle);
-	xdr_send_uint32(xdr, &args->err_code);
-	xdr_send_uint32(xdr, &args->data);
-	return 0;
-}
-
-static void put_event(struct rmt_storage_client_info *rmc,
-			struct rmt_storage_kevent *kevent)
-{
-	spin_lock(&rmc->lock);
-	list_add_tail(&kevent->list, &rmc->event_list);
-	spin_unlock(&rmc->lock);
-}
-
-static struct rmt_storage_kevent *get_event(struct rmt_storage_client_info *rmc)
-{
-	struct rmt_storage_kevent *kevent = NULL;
-
-	spin_lock(&rmc->lock);
-	if (!list_empty(&rmc->event_list)) {
-		kevent = list_first_entry(&rmc->event_list,
-			struct rmt_storage_kevent, list);
-		list_del(&kevent->list);
-	}
-	spin_unlock(&rmc->lock);
-	return kevent;
-}
-
-static int rmt_storage_event_open_cb(struct rmt_storage_event *event_args,
-		struct msm_rpc_xdr *xdr)
-{
-	uint32_t cid, len, event_type;
-	char *path;
-	int ret;
-	struct rmt_storage_srv *srv;
-	struct rmt_storage_client *rs_client = NULL;
-#ifdef CONFIG_MSM_RMT_STORAGE_CLIENT_STATS
-	struct rmt_storage_stats *stats;
-#endif
-
-	srv = rmt_storage_get_srv(event_args->usr_data);
-	if (!srv)
-		return -EINVAL;
-
-	xdr_recv_uint32(xdr, &event_type);
-	if (event_type != RMT_STORAGE_EVNT_OPEN)
-		return -1;
-
-	pr_info("%s: open callback received\n", __func__);
-
-	ret = xdr_recv_bytes(xdr, (void **)&path, &len);
-	if (ret || !path) {
-		pr_err("%s: Invalid path\n", __func__);
-		if (!ret)
-			ret = -1;
-		goto free_rs_client;
-	}
-
-	rs_client = rmt_storage_get_client_by_path(path);
-	if (rs_client) {
-		pr_debug("%s: Handle %d found for %s\n",
-			__func__, rs_client->handle, path);
-		event_args->id = RMT_STORAGE_NOOP;
-		cid = rs_client->handle;
-		goto end_open_cb;
-	}
-
-	rs_client = kzalloc(sizeof(struct rmt_storage_client), GFP_KERNEL);
-	if (!rs_client) {
-		pr_err("%s: Error allocating rmt storage client\n", __func__);
-		ret = -ENOMEM;
-		goto free_path;
-	}
-
-	memcpy(event_args->path, path, len);
-	rs_client->sid = rmt_storage_get_sid(event_args->path);
-	if (!rs_client->sid) {
-		pr_err("%s: No storage id found for %s\n", __func__,
-		       event_args->path);
-		ret = -EINVAL;
-		goto free_path;
-	}
-	strncpy(rs_client->path, event_args->path, MAX_PATH_NAME);
-
-	cid = find_first_zero_bit(&rmc->cids, sizeof(rmc->cids) * 8);
-	if (cid > MAX_NUM_CLIENTS) {
-		pr_err("%s: Max clients are reached\n", __func__);
-		cid = 0;
-		return cid;
-	}
-	__set_bit(cid, &rmc->cids);
-	pr_info("open partition %s handle=%d\n", event_args->path, cid);
-
-#ifdef CONFIG_MSM_RMT_STORAGE_CLIENT_STATS
-	stats = &client_stats[cid - 1];
-	memcpy(stats->path, event_args->path, len);
-	memset(stats->rd_stats, 0, sizeof(struct rmt_storage_op_stats));
-	memset(stats->wr_stats, 0, sizeof(struct rmt_storage_op_stats));
-	stats->rd_stats.min.tv64 = KTIME_MAX;
-	stats->wr_stats.min.tv64 = KTIME_MAX;
-#endif
-	event_args->id = RMT_STORAGE_OPEN;
-	event_args->sid = rs_client->sid;
-	event_args->handle = cid;
-
-	rs_client->handle = event_args->handle;
-	rs_client->srv = srv;
-	INIT_LIST_HEAD(&rs_client->list);
-	spin_lock(&rmc->lock);
-	list_add_tail(&rs_client->list, &rmc->client_list);
-	spin_unlock(&rmc->lock);
-
-end_open_cb:
-	kfree(path);
-	return cid;
-
-free_path:
-	kfree(path);
-free_rs_client:
-	kfree(rs_client);
-	return ret;
-}
-
-struct rmt_storage_close_args {
-	uint32_t handle;
-};
-
-struct rmt_storage_rw_block_args {
-	uint32_t handle;
-	uint32_t data_phy_addr;
-	uint32_t sector_addr;
-	uint32_t num_sector;
-};
-
-struct rmt_storage_get_err_args {
-	uint32_t handle;
-};
-
-struct rmt_storage_user_data_args {
-	uint32_t handle;
-	uint32_t data;
-};
-
-struct rmt_storage_event_params {
-	uint32_t type;
-	union {
-		struct rmt_storage_close_args close;
-		struct rmt_storage_rw_block_args block;
-		struct rmt_storage_get_err_args get_err;
-		struct rmt_storage_user_data_args user_data;
-	} params;
-};
-
-static int rmt_storage_parse_params(struct msm_rpc_xdr *xdr,
-		struct rmt_storage_event_params *event)
-{
-	xdr_recv_uint32(xdr, &event->type);
-
-	switch (event->type) {
-	case RMT_STORAGE_EVNT_CLOSE: {
-		struct rmt_storage_close_args *args;
-		args = &event->params.close;
-
-		xdr_recv_uint32(xdr, &args->handle);
-		break;
-	}
-
-	case RMT_STORAGE_EVNT_WRITE_BLOCK: {
-		struct rmt_storage_rw_block_args *args;
-		args = &event->params.block;
-
-		xdr_recv_uint32(xdr, &args->handle);
-		xdr_recv_uint32(xdr, &args->data_phy_addr);
-		xdr_recv_uint32(xdr, &args->sector_addr);
-		xdr_recv_uint32(xdr, &args->num_sector);
-		break;
-	}
-
-	case RMT_STORAGE_EVNT_GET_DEV_ERROR: {
-		struct rmt_storage_get_err_args *args;
-		args = &event->params.get_err;
-
-		xdr_recv_uint32(xdr, &args->handle);
-		break;
-	}
-
-	case RMT_STORAGE_EVNT_SEND_USER_DATA: {
-		struct rmt_storage_user_data_args *args;
-		args = &event->params.user_data;
-
-		xdr_recv_uint32(xdr, &args->handle);
-		xdr_recv_uint32(xdr, &args->data);
-		break;
-	}
-
-	default:
-		pr_err("%s: unknown event %d\n", __func__, event->type);
-		return -1;
-	}
-	return 0;
-}
-
-static int rmt_storage_event_close_cb(struct rmt_storage_event *event_args,
-		struct msm_rpc_xdr *xdr)
-{
-	struct rmt_storage_event_params *event;
-	struct rmt_storage_close_args *close;
-	struct rmt_storage_client *rs_client;
-	uint32_t event_type;
-	int ret;
-
-	xdr_recv_uint32(xdr, &event_type);
-	if (event_type != RMT_STORAGE_EVNT_CLOSE)
-		return -1;
-
-	pr_debug("%s: close callback received\n", __func__);
-	ret = xdr_recv_pointer(xdr, (void **)&event,
-			sizeof(struct rmt_storage_event_params),
-			rmt_storage_parse_params);
-
-	if (ret || !event)
-		return -1;
-
-	close = &event->params.close;
-	event_args->handle = close->handle;
-	event_args->id = RMT_STORAGE_CLOSE;
-	__clear_bit(event_args->handle, &rmc->cids);
-	rs_client = rmt_storage_get_client(event_args->handle);
-	if (rs_client) {
-		list_del(&rs_client->list);
-		kfree(rs_client);
-	}
-	kfree(event);
-	return RMT_STORAGE_NO_ERROR;
-}
-
-static int rmt_storage_event_write_block_cb(
-		struct rmt_storage_event *event_args,
-		struct msm_rpc_xdr *xdr)
-{
-	struct rmt_storage_event_params *event;
-	struct rmt_storage_rw_block_args *write_block;
-	struct rmt_storage_iovec_desc *xfer;
-	uint32_t event_type;
-	int ret;
-
-	xdr_recv_uint32(xdr, &event_type);
-	if (event_type != RMT_STORAGE_EVNT_WRITE_BLOCK)
-		return -1;
-
-	pr_debug("%s: write block callback received\n", __func__);
-	ret = xdr_recv_pointer(xdr, (void **)&event,
-			sizeof(struct rmt_storage_event_params),
-			rmt_storage_parse_params);
-
-	if (ret || !event)
-		return -1;
-
-	write_block = &event->params.block;
-	event_args->handle = write_block->handle;
-	xfer = &event_args->xfer_desc[0];
-	xfer->sector_addr = write_block->sector_addr;
-	xfer->data_phy_addr = write_block->data_phy_addr;
-	xfer->num_sector = write_block->num_sector;
-
-	ret = rmt_storage_validate_iovec(event_args->handle, xfer);
-	if (ret)
-		return -1;
-	event_args->xfer_cnt = 1;
-	event_args->id = RMT_STORAGE_WRITE;
-
-	if (atomic_inc_return(&rmc->wcount) == 1)
-		wake_lock(&rmc->wlock);
-
-	pr_debug("sec_addr = %u, data_addr = %x, num_sec = %d\n\n",
-		xfer->sector_addr, xfer->data_phy_addr,
-		xfer->num_sector);
-
-	kfree(event);
-	return RMT_STORAGE_NO_ERROR;
-}
-
-static int rmt_storage_event_get_err_cb(struct rmt_storage_event *event_args,
-		struct msm_rpc_xdr *xdr)
-{
-	struct rmt_storage_event_params *event;
-	struct rmt_storage_get_err_args *get_err;
-	uint32_t event_type;
-	int ret;
-
-	xdr_recv_uint32(xdr, &event_type);
-	if (event_type != RMT_STORAGE_EVNT_GET_DEV_ERROR)
-		return -1;
-
-	pr_debug("%s: get err callback received\n", __func__);
-	ret = xdr_recv_pointer(xdr, (void **)&event,
-			sizeof(struct rmt_storage_event_params),
-			rmt_storage_parse_params);
-
-	if (ret || !event)
-		return -1;
-
-	get_err = &event->params.get_err;
-	event_args->handle = get_err->handle;
-	kfree(event);
-	/* Not implemented */
-	return -1;
-
-}
-
-static int rmt_storage_event_user_data_cb(struct rmt_storage_event *event_args,
-		struct msm_rpc_xdr *xdr)
-{
-	struct rmt_storage_event_params *event;
-	struct rmt_storage_user_data_args *user_data;
-	uint32_t event_type;
-	int ret;
-
-	xdr_recv_uint32(xdr, &event_type);
-	if (event_type != RMT_STORAGE_EVNT_SEND_USER_DATA)
-		return -1;
-
-	pr_info("%s: send user data callback received\n", __func__);
-	ret = xdr_recv_pointer(xdr, (void **)&event,
-			sizeof(struct rmt_storage_event_params),
-			rmt_storage_parse_params);
-
-	if (ret || !event)
-		return -1;
-
-	user_data = &event->params.user_data;
-	event_args->handle = user_data->handle;
-	event_args->usr_data = user_data->data;
-	event_args->id = RMT_STORAGE_SEND_USER_DATA;
-
-	kfree(event);
-	return RMT_STORAGE_NO_ERROR;
-}
-
-static int rmt_storage_event_write_iovec_cb(
-		struct rmt_storage_event *event_args,
-		struct msm_rpc_xdr *xdr)
-{
-	struct rmt_storage_iovec_desc *xfer;
-	uint32_t i, ent, event_type;
-#ifdef CONFIG_MSM_RMT_STORAGE_CLIENT_STATS
-	struct rmt_storage_stats *stats;
-#endif
-
-	xdr_recv_uint32(xdr, &event_type);
-	if (event_type != RMT_STORAGE_EVNT_WRITE_IOVEC)
-		return -EINVAL;
-
-	pr_info("%s: write iovec callback received\n", __func__);
-	xdr_recv_uint32(xdr, &event_args->handle);
-	xdr_recv_uint32(xdr, &ent);
-	pr_debug("handle = %d\n", event_args->handle);
-
-#ifdef CONFIG_MSM_RMT_STORAGE_CLIENT_STATS
-	stats = &client_stats[event_args->handle - 1];
-	stats->wr_stats.start = ktime_get();
-#endif
-	for (i = 0; i < ent; i++) {
-		xfer = &event_args->xfer_desc[i];
-		xdr_recv_uint32(xdr, &xfer->sector_addr);
-		xdr_recv_uint32(xdr, &xfer->data_phy_addr);
-		xdr_recv_uint32(xdr, &xfer->num_sector);
-
-		if (rmt_storage_validate_iovec(event_args->handle, xfer))
-			return -EINVAL;
-
-		pr_debug("sec_addr = %u, data_addr = %x, num_sec = %d\n",
-			xfer->sector_addr, xfer->data_phy_addr,
-			xfer->num_sector);
-	}
-	xdr_recv_uint32(xdr, &event_args->xfer_cnt);
-	event_args->id = RMT_STORAGE_WRITE;
-	if (atomic_inc_return(&rmc->wcount) == 1)
-		wake_lock(&rmc->wlock);
-
-	pr_debug("iovec transfer count = %d\n\n", event_args->xfer_cnt);
-	return RMT_STORAGE_NO_ERROR;
-}
-
-static int rmt_storage_event_read_iovec_cb(
-		struct rmt_storage_event *event_args,
-		struct msm_rpc_xdr *xdr)
-{
-	struct rmt_storage_iovec_desc *xfer;
-	uint32_t i, ent, event_type;
-#ifdef CONFIG_MSM_RMT_STORAGE_CLIENT_STATS
-	struct rmt_storage_stats *stats;
-#endif
-
-	xdr_recv_uint32(xdr, &event_type);
-	if (event_type != RMT_STORAGE_EVNT_READ_IOVEC)
-		return -EINVAL;
-
-	pr_info("%s: read iovec callback received\n", __func__);
-	xdr_recv_uint32(xdr, &event_args->handle);
-	xdr_recv_uint32(xdr, &ent);
-	pr_debug("handle = %d\n", event_args->handle);
-
-#ifdef CONFIG_MSM_RMT_STORAGE_CLIENT_STATS
-	stats = &client_stats[event_args->handle - 1];
-	stats->rd_stats.start = ktime_get();
-#endif
-	for (i = 0; i < ent; i++) {
-		xfer = &event_args->xfer_desc[i];
-		xdr_recv_uint32(xdr, &xfer->sector_addr);
-		xdr_recv_uint32(xdr, &xfer->data_phy_addr);
-		xdr_recv_uint32(xdr, &xfer->num_sector);
-
-		if (rmt_storage_validate_iovec(event_args->handle, xfer))
-			return -EINVAL;
-
-		pr_debug("sec_addr = %u, data_addr = %x, num_sec = %d\n",
-			xfer->sector_addr, xfer->data_phy_addr,
-			xfer->num_sector);
-	}
-	xdr_recv_uint32(xdr, &event_args->xfer_cnt);
-	event_args->id = RMT_STORAGE_READ;
-	if (atomic_inc_return(&rmc->wcount) == 1)
-		wake_lock(&rmc->wlock);
-
-	pr_debug("iovec transfer count = %d\n\n", event_args->xfer_cnt);
-	return RMT_STORAGE_NO_ERROR;
-}
-
-#ifdef CONFIG_MSM_SDIO_SMEM
-static int sdio_smem_cb(int event)
-{
-	pr_debug("%s: Received event %d\n", __func__, event);
-
-	switch (event) {
-	case SDIO_SMEM_EVENT_READ_DONE:
-		pr_debug("Read done\n");
-		break;
-	case SDIO_SMEM_EVENT_READ_ERR:
-		pr_err("Read overflow\n");
-		return -EIO;
-	default:
-		pr_err("Unhandled event\n");
-	}
-	return 0;
-}
-
-static int rmt_storage_sdio_smem_probe(struct platform_device *pdev)
-{
-	int ret = 0;
-	struct rmt_shrd_mem_param *shrd_mem;
-
-	sdio_smem = container_of(pdev, struct sdio_smem_client, plat_dev);
-
-	/* SDIO SMEM is supported only for MDM */
-	shrd_mem = rmt_storage_get_shrd_mem(RAMFS_MDM_STORAGE_ID);
-	if (!shrd_mem) {
-		pr_err("%s: No shared mem entry for sid=0x%08x\n",
-		       __func__, (uint32_t)RAMFS_MDM_STORAGE_ID);
-		return -ENOMEM;
-	}
-	sdio_smem->buf = __va(shrd_mem->start);
-	sdio_smem->size = shrd_mem->size;
-	sdio_smem->cb_func = sdio_smem_cb;
-	ret = sdio_smem_register_client();
-	if (ret)
-		pr_info("%s: Error (%d) registering sdio_smem client\n",
-			__func__, ret);
-	return ret;
-}
-
-static int rmt_storage_sdio_smem_remove(struct platform_device *pdev)
-{
-	sdio_smem_unregister_client();
-	queue_delayed_work(rmc->workq, &sdio_smem_work, 0);
-	return 0;
-}
-
-static int sdio_smem_drv_registered;
-static struct platform_driver sdio_smem_drv = {
-	.probe		= rmt_storage_sdio_smem_probe,
-	.remove		= rmt_storage_sdio_smem_remove,
-	.driver		= {
-		.name	= "SDIO_SMEM_CLIENT",
-		.owner	= THIS_MODULE,
-	},
-};
-
-static void rmt_storage_sdio_smem_work(struct work_struct *work)
-{
-	platform_driver_unregister(&sdio_smem_drv);
-	sdio_smem_drv_registered = 0;
-}
-#endif
-
-static int rmt_storage_event_alloc_rmt_buf_cb(
-		struct rmt_storage_event *event_args,
-		struct msm_rpc_xdr *xdr)
-{
-	struct rmt_storage_client *rs_client;
-	struct rmt_shrd_mem_param *shrd_mem;
-	uint32_t event_type, handle, size;
-#ifdef CONFIG_MSM_SDIO_SMEM
-	int ret;
-#endif
-	xdr_recv_uint32(xdr, &event_type);
-	if (event_type != RMT_STORAGE_EVNT_ALLOC_RMT_BUF)
-		return -EINVAL;
-
-	pr_info("%s: Alloc rmt buf callback received\n", __func__);
-	xdr_recv_uint32(xdr, &handle);
-	xdr_recv_uint32(xdr, &size);
-
-	pr_debug("%s: handle=0x%x size=0x%x\n", __func__, handle, size);
-
-	rs_client = rmt_storage_get_client(handle);
-	if (!rs_client) {
-		pr_err("%s: Unable to find client for handle=%d\n",
-		       __func__, handle);
-		return -EINVAL;
-	}
-
-	rs_client->sid = rmt_storage_get_sid(rs_client->path);
-	if (!rs_client->sid) {
-		pr_err("%s: No storage id found for %s\n",
-		       __func__, rs_client->path);
-		return -EINVAL;
-	}
-
-	shrd_mem = rmt_storage_get_shrd_mem(rs_client->sid);
-	if (!shrd_mem) {
-		pr_err("%s: No shared memory entry found\n",
-		       __func__);
-		return -ENOMEM;
-	}
-	if (shrd_mem->size < size) {
-		pr_err("%s: Size mismatch for handle=%d\n",
-		       __func__, rs_client->handle);
-		return -EINVAL;
-	}
-	pr_debug("%s: %d bytes at phys=0x%x for handle=%d found\n",
-		__func__, size, shrd_mem->start, rs_client->handle);
-
-#ifdef CONFIG_MSM_SDIO_SMEM
-	if (rs_client->srv->prog == MDM_RMT_STORAGE_APIPROG) {
-		if (!sdio_smem_drv_registered) {
-			ret = platform_driver_register(&sdio_smem_drv);
-			if (!ret)
-				sdio_smem_drv_registered = 1;
-			else
-				pr_err("%s: Cant register sdio smem client\n",
-				       __func__);
-		}
-	}
-#endif
-	event_args->id = RMT_STORAGE_NOOP;
-	return (int)shrd_mem->start;
-}
-
-static int handle_rmt_storage_call(struct msm_rpc_client *client,
-				struct rpc_request_hdr *req,
-				struct msm_rpc_xdr *xdr)
-{
-	int rc;
-	uint32_t result = RMT_STORAGE_NO_ERROR;
-	uint32_t rpc_status = RPC_ACCEPTSTAT_SUCCESS;
-	struct rmt_storage_event *event_args;
-	struct rmt_storage_kevent *kevent;
-
-	kevent = kzalloc(sizeof(struct rmt_storage_kevent), GFP_KERNEL);
-	if (!kevent) {
-		rpc_status = RPC_ACCEPTSTAT_SYSTEM_ERR;
-		goto out;
-	}
-	event_args = &kevent->event;
-
-	switch (req->procedure) {
-	case RMT_STORAGE_OPEN_CB_TYPE_PROC:
-		/* client created in cb needs a ref. to its server */
-		event_args->usr_data = client->prog;
-		/* fall through */
-
-	case RMT_STORAGE_WRITE_IOVEC_CB_TYPE_PROC:
-		/* fall through */
-
-	case RMT_STORAGE_READ_IOVEC_CB_TYPE_PROC:
-		/* fall through */
-
-	case RMT_STORAGE_ALLOC_RMT_BUF_CB_TYPE_PROC:
-		/* fall through */
-
-	case RMT_STORAGE_EVENT_CB_TYPE_PROC: {
-		uint32_t cb_id;
-		int (*cb_func)(struct rmt_storage_event *event_args,
-				struct msm_rpc_xdr *xdr);
-
-		xdr_recv_uint32(xdr, &cb_id);
-		cb_func = msm_rpc_get_cb_func(client, cb_id);
-
-		if (!cb_func) {
-			rpc_status = RPC_ACCEPTSTAT_GARBAGE_ARGS;
-			kfree(kevent);
-			goto out;
-		}
-
-		rc = cb_func(event_args, xdr);
-		if (IS_ERR_VALUE(rc)) {
-			pr_err("%s: Invalid parameters received\n", __func__);
-			if (req->procedure == RMT_STORAGE_OPEN_CB_TYPE_PROC)
-				result = 0; /* bad handle to signify err */
-			else
-				result = RMT_STORAGE_ERROR_PARAM;
-			kfree(kevent);
-			goto out;
-		}
-		result = (uint32_t) rc;
-		break;
-	}
-
-	default:
-		kfree(kevent);
-		pr_err("%s: unknown procedure %d\n", __func__, req->procedure);
-		rpc_status = RPC_ACCEPTSTAT_PROC_UNAVAIL;
-		goto out;
-	}
-
-	if (kevent->event.id != RMT_STORAGE_NOOP) {
-		put_event(rmc, kevent);
-		atomic_inc(&rmc->total_events);
-		wake_up(&rmc->event_q);
-	} else
-		kfree(kevent);
-
-out:
-	pr_debug("%s: Sending result=0x%x\n", __func__, result);
-	xdr_start_accepted_reply(xdr, rpc_status);
-	xdr_send_uint32(xdr, &result);
-	rc = xdr_send_msg(xdr);
-	if (rc)
-		pr_err("%s: send accepted reply failed: %d\n", __func__, rc);
-
-	return rc;
-}
-
-static int rmt_storage_open(struct inode *ip, struct file *fp)
-{
-	int ret = 0;
-
-	spin_lock(&rmc->lock);
-	if (!rmc->open_excl)
-		rmc->open_excl = 1;
-	else
-		ret = -EBUSY;
-	spin_unlock(&rmc->lock);
-
-	return ret;
-}
-
-static int rmt_storage_release(struct inode *ip, struct file *fp)
-{
-	spin_lock(&rmc->lock);
-	rmc->open_excl = 0;
-	spin_unlock(&rmc->lock);
-
-	return 0;
-}
-
-static long rmt_storage_ioctl(struct file *fp, unsigned int cmd,
-			    unsigned long arg)
-{
-	int ret = 0;
-	struct rmt_storage_kevent *kevent;
-	struct rmt_storage_send_sts status;
-	static struct msm_rpc_client *rpc_client;
-	struct rmt_shrd_mem_param usr_shrd_mem, *shrd_mem;
-
-#ifdef CONFIG_MSM_RMT_STORAGE_CLIENT_STATS
-	struct rmt_storage_stats *stats;
-	struct rmt_storage_op_stats *op_stats;
-	ktime_t curr_stat;
-#endif
-
-	switch (cmd) {
-
-	case RMT_STORAGE_SHRD_MEM_PARAM:
-		pr_debug("%s: get shared memory parameters ioctl\n", __func__);
-		if (copy_from_user(&usr_shrd_mem, (void __user *)arg,
-				sizeof(struct rmt_shrd_mem_param))) {
-			pr_err("%s: copy from user failed\n\n", __func__);
-			ret = -EFAULT;
-			break;
-		}
-
-		shrd_mem = rmt_storage_get_shrd_mem(usr_shrd_mem.sid);
-		if (!shrd_mem) {
-			pr_err("%s: invalid sid (0x%x)\n", __func__,
-			       usr_shrd_mem.sid);
-			ret = -EFAULT;
-			break;
-		}
-
-		if (copy_to_user((void __user *)arg, shrd_mem,
-			sizeof(struct rmt_shrd_mem_param))) {
-			pr_err("%s: copy to user failed\n\n", __func__);
-			ret = -EFAULT;
-		}
-		break;
-
-	case RMT_STORAGE_WAIT_FOR_REQ:
-		pr_debug("%s: wait for request ioctl\n", __func__);
-		if (atomic_read(&rmc->total_events) == 0) {
-			ret = wait_event_interruptible(rmc->event_q,
-				atomic_read(&rmc->total_events) != 0);
-		}
-		if (ret < 0)
-			break;
-		atomic_dec(&rmc->total_events);
-
-		kevent = get_event(rmc);
-		WARN_ON(kevent == NULL);
-		if (copy_to_user((void __user *)arg, &kevent->event,
-			sizeof(struct rmt_storage_event))) {
-			pr_err("%s: copy to user failed\n\n", __func__);
-			ret = -EFAULT;
-		}
-		kfree(kevent);
-		break;
-
-	case RMT_STORAGE_SEND_STATUS:
-		pr_info("%s: send status ioctl\n", __func__);
-		if (copy_from_user(&status, (void __user *)arg,
-				sizeof(struct rmt_storage_send_sts))) {
-			pr_err("%s: copy from user failed\n\n", __func__);
-			ret = -EFAULT;
-			if (atomic_dec_return(&rmc->wcount) == 0)
-				wake_unlock(&rmc->wlock);
-			break;
-		}
-#ifdef CONFIG_MSM_RMT_STORAGE_CLIENT_STATS
-		stats = &client_stats[status.handle - 1];
-		if (status.xfer_dir == RMT_STORAGE_WRITE)
-			op_stats = &stats->wr_stats;
-		else
-			op_stats = &stats->rd_stats;
-		curr_stat = ktime_sub(ktime_get(), op_stats->start);
-		op_stats->total = ktime_add(op_stats->total, curr_stat);
-		op_stats->count++;
-		if (curr_stat.tv64 < stats->min.tv64)
-			op_stats->min = curr_stat;
-		if (curr_stat.tv64 > stats->max.tv64)
-			op_stats->max = curr_stat;
-#endif
-		pr_debug("%s: \thandle=%d err_code=%d data=0x%x\n", __func__,
-			status.handle, status.err_code, status.data);
-		rpc_client = rmt_storage_get_rpc_client(status.handle);
-		if (rpc_client)
-			ret = msm_rpc_client_req2(rpc_client,
-				RMT_STORAGE_OP_FINISH_PROC,
-				rmt_storage_send_sts_arg,
-				&status, NULL, NULL, -1);
-		else
-			ret = -EINVAL;
-		if (ret < 0)
-			pr_err("%s: send status failed with ret val = %d\n",
-				__func__, ret);
-		if (atomic_dec_return(&rmc->wcount) == 0)
-			wake_unlock(&rmc->wlock);
-		break;
-
-	default:
-		ret = -EINVAL;
-		break;
-	}
-
-	return ret;
-}
-
-struct rmt_storage_sync_recv_arg {
-	int data;
-};
-
-static int rmt_storage_receive_sync_arg(struct msm_rpc_client *client,
-				struct msm_rpc_xdr *xdr, void *data)
-{
-	struct rmt_storage_sync_recv_arg *args = data;
-	struct rmt_storage_srv *srv;
-
-	srv = rmt_storage_get_srv(client->prog);
-	if (!srv)
-		return -EINVAL;
-	xdr_recv_int32(xdr, &args->data);
-	srv->sync_token = args->data;
-	return 0;
-}
-
-static int rmt_storage_force_sync(struct msm_rpc_client *client)
-{
-	struct rmt_storage_sync_recv_arg args;
-	int rc;
-	rc = msm_rpc_client_req2(client,
-			RMT_STORAGE_FORCE_SYNC_PROC, NULL, NULL,
-			rmt_storage_receive_sync_arg, &args, -1);
-	if (rc) {
-		pr_err("%s: force sync RPC req failed: %d\n", __func__, rc);
-		return rc;
-	}
-	return 0;
-}
-
-struct rmt_storage_sync_sts_arg {
-	int token;
-};
-
-static int rmt_storage_send_sync_sts_arg(struct msm_rpc_client *client,
-				struct msm_rpc_xdr *xdr, void *data)
-{
-	struct rmt_storage_sync_sts_arg *req = data;
-
-	xdr_send_int32(xdr, &req->token);
-	return 0;
-}
-
-static int rmt_storage_receive_sync_sts_arg(struct msm_rpc_client *client,
-				struct msm_rpc_xdr *xdr, void *data)
-{
-	struct rmt_storage_sync_recv_arg *args = data;
-
-	xdr_recv_int32(xdr, &args->data);
-	return 0;
-}
-
-static int rmt_storage_get_sync_status(struct msm_rpc_client *client)
-{
-	struct rmt_storage_sync_recv_arg recv_args;
-	struct rmt_storage_sync_sts_arg send_args;
-	struct rmt_storage_srv *srv;
-	int rc;
-
-	srv = rmt_storage_get_srv(client->prog);
-	if (!srv)
-		return -EINVAL;
-
-	if (srv->sync_token < 0)
-		return -EINVAL;
-
-	send_args.token = srv->sync_token;
-	rc = msm_rpc_client_req2(client,
-			RMT_STORAGE_GET_SYNC_STATUS_PROC,
-			rmt_storage_send_sync_sts_arg, &send_args,
-			rmt_storage_receive_sync_sts_arg, &recv_args, -1);
-	if (rc) {
-		pr_err("%s: sync status RPC req failed: %d\n", __func__, rc);
-		return rc;
-	}
-	return recv_args.data;
-}
-
-static int rmt_storage_mmap(struct file *file, struct vm_area_struct *vma)
-{
-	unsigned long vsize = vma->vm_end - vma->vm_start;
-	int ret = -EINVAL;
-
-	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
-
-	ret = io_remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
-				 vsize, vma->vm_page_prot);
-	if (ret < 0)
-		pr_err("%s: failed with return val %d\n", __func__, ret);
-	return ret;
-}
-
-struct rmt_storage_reg_cb_args {
-	uint32_t event;
-	uint32_t cb_id;
-};
-
-static int rmt_storage_arg_cb(struct msm_rpc_client *client,
-		struct msm_rpc_xdr *xdr, void *data)
-{
-	struct rmt_storage_reg_cb_args *args = data;
-
-	xdr_send_uint32(xdr, &args->event);
-	xdr_send_uint32(xdr, &args->cb_id);
-	return 0;
-}
-
-static int rmt_storage_reg_cb(struct msm_rpc_client *client,
-			      uint32_t proc, uint32_t event, void *callback)
-{
-	struct rmt_storage_reg_cb_args args;
-	int rc, cb_id;
-	int retries = 10;
-
-	cb_id = msm_rpc_add_cb_func(client, callback);
-	if ((cb_id < 0) && (cb_id != MSM_RPC_CLIENT_NULL_CB_ID))
-		return cb_id;
-
-	args.event = event;
-	args.cb_id = cb_id;
-
-	while (retries) {
-		rc = msm_rpc_client_req2(client, proc, rmt_storage_arg_cb,
-					 &args, NULL, NULL, -1);
-		if (rc != -ETIMEDOUT)
-			break;
-		retries--;
-		udelay(1000);
-	}
-	if (rc)
-		pr_err("%s: Failed to register callback for event %d\n",
-				__func__, event);
-	return rc;
-}
-
-#ifdef CONFIG_MSM_RMT_STORAGE_CLIENT_STATS
-static int rmt_storage_stats_open(struct inode *inode, struct file *file)
-{
-	return 0;
-}
-
-static ssize_t rmt_storage_stats_read(struct file *file, char __user *ubuf,
-		size_t count, loff_t *ppos)
-{
-	uint32_t tot_clients;
-	char buf[512];
-	int max, j, i = 0;
-	struct rmt_storage_stats *stats;
-
-	max = sizeof(buf) - 1;
-	tot_clients = find_first_zero_bit(&rmc->cids, sizeof(rmc->cids)) - 1;
-
-	for (j = 0; j < tot_clients; j++) {
-		stats = &client_stats[j];
-		i += scnprintf(buf + i, max - i, "stats for partition %s:\n",
-				stats->path);
-		i += scnprintf(buf + i, max - i, "Min read time: %lld us\n",
-				ktime_to_us(stats->rd_stats.min));
-		i += scnprintf(buf + i, max - i, "Max read time: %lld us\n",
-				ktime_to_us(stats->rd_stats.max));
-		i += scnprintf(buf + i, max - i, "Total read time: %lld us\n",
-				ktime_to_us(stats->rd_stats.total));
-		i += scnprintf(buf + i, max - i, "Total read requests: %ld\n",
-				stats->rd_stats.count);
-		if (stats->count)
-			i += scnprintf(buf + i, max - i,
-				"Avg read time: %lld us\n",
-				div_s64(ktime_to_us(stats->total),
-				stats->rd_stats.count));
-
-		i += scnprintf(buf + i, max - i, "Min write time: %lld us\n",
-				ktime_to_us(stats->wr_stats.min));
-		i += scnprintf(buf + i, max - i, "Max write time: %lld us\n",
-				ktime_to_us(stats->wr_stats.max));
-		i += scnprintf(buf + i, max - i, "Total write time: %lld us\n",
-				ktime_to_us(stats->wr_stats.total));
-		i += scnprintf(buf + i, max - i, "Total read requests: %ld\n",
-				stats->wr_stats.count);
-		if (stats->count)
-			i += scnprintf(buf + i, max - i,
-				"Avg write time: %lld us\n",
-				div_s64(ktime_to_us(stats->total),
-				stats->wr_stats.count));
-	}
-	return simple_read_from_buffer(ubuf, count, ppos, buf, i);
-}
-
-static const struct file_operations debug_ops = {
-	.owner = THIS_MODULE,
-	.open = rmt_storage_stats_open,
-	.read = rmt_storage_stats_read,
-};
-#endif
-
-const struct file_operations rmt_storage_fops = {
-	.owner = THIS_MODULE,
-	.open = rmt_storage_open,
-	.unlocked_ioctl	 = rmt_storage_ioctl,
-	.mmap = rmt_storage_mmap,
-	.release = rmt_storage_release,
-};
-
-static struct miscdevice rmt_storage_device = {
-	.minor = MISC_DYNAMIC_MINOR,
-	.name = "rmt_storage",
-	.fops = &rmt_storage_fops,
-};
-
-static int rmt_storage_get_ramfs(struct rmt_storage_srv *srv)
-{
-	struct shared_ramfs_table *ramfs_table;
-	struct shared_ramfs_entry *ramfs_entry;
-	int index, ret;
-
-	if (srv->prog != MSM_RMT_STORAGE_APIPROG)
-		return 0;
-
-	ramfs_table = smem_alloc(SMEM_SEFS_INFO,
-			sizeof(struct shared_ramfs_table));
-
-	if (!ramfs_table) {
-		pr_err("%s: No RAMFS table in SMEM\n", __func__);
-		return -ENOENT;
-	}
-
-	if ((ramfs_table->magic_id != (u32) RAMFS_INFO_MAGICNUMBER) ||
-	    (ramfs_table->version != (u32) RAMFS_INFO_VERSION)) {
-		pr_err("%s: Magic / Version mismatch:, "
-		       "magic_id=%#x, format_version=%#x\n", __func__,
-		       ramfs_table->magic_id, ramfs_table->version);
-		return -ENOENT;
-	}
-
-	for (index = 0; index < ramfs_table->entries; index++) {
-		ramfs_entry = &ramfs_table->ramfs_entry[index];
-		if (!ramfs_entry->client_id ||
-		    ramfs_entry->client_id == (u32) RAMFS_DEFAULT)
-			break;
-
-		pr_info("%s: RAMFS entry: addr = 0x%08x, size = 0x%08x\n",
-			__func__, ramfs_entry->base_addr, ramfs_entry->size);
-
-		ret = rmt_storage_add_shrd_mem(ramfs_entry->client_id,
-					       ramfs_entry->base_addr,
-					       ramfs_entry->size,
-					       NULL,
-					       ramfs_entry,
-					       srv);
-		if (ret) {
-			pr_err("%s: Error (%d) adding shared mem\n",
-			       __func__, ret);
-			return ret;
-		}
-	}
-	return 0;
-}
-
-static ssize_t
-show_force_sync(struct device *dev, struct device_attribute *attr,
-		char *buf)
-{
-	struct platform_device *pdev;
-	struct rpcsvr_platform_device *rpc_pdev;
-	struct rmt_storage_srv *srv;
-
-	pdev = container_of(dev, struct platform_device, dev);
-	rpc_pdev = container_of(pdev, struct rpcsvr_platform_device, base);
-	srv = rmt_storage_get_srv(rpc_pdev->prog);
-	if (!srv) {
-		pr_err("%s: Unable to find prog=0x%x\n", __func__,
-		       rpc_pdev->prog);
-		return -EINVAL;
-	}
-
-	return rmt_storage_force_sync(srv->rpc_client);
-}
-
-/* Returns -EINVAL for invalid sync token and an error value for any failure
- * in RPC call. Upon success, it returns a sync status of 1 (sync done)
- * or 0 (sync still pending).
- */
-static ssize_t
-show_sync_sts(struct device *dev, struct device_attribute *attr, char *buf)
-{
-	struct platform_device *pdev;
-	struct rpcsvr_platform_device *rpc_pdev;
-	struct rmt_storage_srv *srv;
-
-	pdev = container_of(dev, struct platform_device, dev);
-	rpc_pdev = container_of(pdev, struct rpcsvr_platform_device, base);
-	srv = rmt_storage_get_srv(rpc_pdev->prog);
-	if (!srv) {
-		pr_err("%s: Unable to find prog=0x%x\n", __func__,
-		       rpc_pdev->prog);
-		return -EINVAL;
-	}
-	return snprintf(buf, PAGE_SIZE, "%d\n",
-			rmt_storage_get_sync_status(srv->rpc_client));
-}
-
-/*
- * Initiate the remote storage force sync and wait until
- * sync status is done or maximum 4 seconds in the reboot notifier.
- * Usually RMT storage sync is not taking more than 2 seconds
- * for encryption and sync.
- */
-#define MAX_GET_SYNC_STATUS_TRIES 200
-#define RMT_SLEEP_INTERVAL_MS 20
-static int rmt_storage_reboot_call(
-	struct notifier_block *this, unsigned long code, void *cmd)
-{
-	int ret, count = 0;
-
-	/*
-	 * In recovery mode RMT daemon is not available,
-	 * so return from reboot notifier without initiating
-	 * force sync.
-	 */
-	spin_lock(&rmc->lock);
-	if (!rmc->open_excl) {
-		spin_unlock(&rmc->lock);
-		msm_rpc_unregister_client(rmt_srv->rpc_client);
-		return NOTIFY_DONE;
-	}
-
-	spin_unlock(&rmc->lock);
-	switch (code) {
-	case SYS_RESTART:
-	case SYS_HALT:
-	case SYS_POWER_OFF:
-		pr_info("%s: Sending force-sync RPC request\n", __func__);
-		ret = rmt_storage_force_sync(rmt_srv->rpc_client);
-		if (ret)
-			break;
-
-		do {
-			count++;
-			msleep(RMT_SLEEP_INTERVAL_MS);
-			ret = rmt_storage_get_sync_status(rmt_srv->rpc_client);
-		} while (ret != 1 && count < MAX_GET_SYNC_STATUS_TRIES);
-
-		if (ret == 1)
-			pr_info("%s: Final-sync successful\n", __func__);
-		else
-			pr_err("%s: Final-sync failed\n", __func__);
-
-		/*
-		 * Check if any ongoing efs_sync triggered just before force
-		 * sync is pending. If so, wait for 4sec for completing efs_sync
-		 * before unregistring client.
-		 */
-		count = 0;
-		while (count < MAX_GET_SYNC_STATUS_TRIES) {
-			if (atomic_read(&rmc->wcount) == 0) {
-				break;
-			} else {
-				count++;
-				msleep(RMT_SLEEP_INTERVAL_MS);
-			}
-		}
-		if (atomic_read(&rmc->wcount))
-			pr_err("%s: Efs_sync still incomplete\n", __func__);
-
-		pr_info("%s: Un-register RMT storage client\n", __func__);
-		msm_rpc_unregister_client(rmt_srv->rpc_client);
-		break;
-
-	default:
-		break;
-	}
-	return NOTIFY_DONE;
-}
-
-/*
- * For the RMT storage sync, RPC channels are required. If we do not
- * give max priority to RMT storage reboot notifier, RPC channels may get
- * closed before RMT storage sync completed if RPC reboot notifier gets
- * executed before this remotefs reboot notifier. Hence give the maximum
- * priority to this reboot notifier.
- */
-static struct notifier_block rmt_storage_reboot_notifier = {
-	.notifier_call = rmt_storage_reboot_call,
-	.priority = INT_MAX,
-};
-
-static int rmt_storage_init_ramfs(struct rmt_storage_srv *srv)
-{
-	struct shared_ramfs_table *ramfs_table;
-
-	if (srv->prog != MSM_RMT_STORAGE_APIPROG)
-		return 0;
-
-	ramfs_table = smem_alloc(SMEM_SEFS_INFO,
-				 sizeof(struct shared_ramfs_table));
-
-	if (!ramfs_table) {
-		pr_err("%s: No RAMFS table in SMEM\n", __func__);
-		return -ENOENT;
-	}
-
-	if (ramfs_table->magic_id == RAMFS_INFO_MAGICNUMBER) {
-		pr_debug("RAMFS table already filled... skipping %s", \
-			__func__);
-		return 0;
-	}
-
-	ramfs_table->ramfs_entry[0].client_id  = RAMFS_MODEMSTORAGE_ID;
-	ramfs_table->ramfs_entry[0].base_addr  = RAMFS_SHARED_EFS_RAM_BASE;
-	ramfs_table->ramfs_entry[0].size       = RAMFS_SHARED_EFS_RAM_SIZE;
-	ramfs_table->ramfs_entry[0].client_sts = RAMFS_DEFAULT;
-
-	ramfs_table->ramfs_entry[1].client_id  = RAMFS_SSD_STORAGE_ID;
-	ramfs_table->ramfs_entry[1].base_addr  = RAMFS_SHARED_SSD_RAM_BASE;
-	ramfs_table->ramfs_entry[1].size       = RAMFS_SHARED_SSD_RAM_SIZE;
-	ramfs_table->ramfs_entry[1].client_sts = RAMFS_DEFAULT;
-
-	ramfs_table->entries  = 2;
-	ramfs_table->version  = RAMFS_INFO_VERSION;
-	ramfs_table->magic_id = RAMFS_INFO_MAGICNUMBER;
-
-	return 0;
-}
-
-static void rmt_storage_set_client_status(struct rmt_storage_srv *srv,
-					  int enable)
-{
-	struct rmt_shrd_mem *shrd_mem;
-
-	spin_lock(&rmc->lock);
-	list_for_each_entry(shrd_mem, &rmc->shrd_mem_list, list)
-		if (shrd_mem->srv->prog == srv->prog)
-			if (shrd_mem->smem_info)
-				shrd_mem->smem_info->client_sts = !!enable;
-	spin_unlock(&rmc->lock);
-}
-
-static DEVICE_ATTR(force_sync, S_IRUGO | S_IWUSR, show_force_sync, NULL);
-static DEVICE_ATTR(sync_sts, S_IRUGO | S_IWUSR, show_sync_sts, NULL);
-static struct attribute *dev_attrs[] = {
-	&dev_attr_force_sync.attr,
-	&dev_attr_sync_sts.attr,
-	NULL,
-};
-static struct attribute_group dev_attr_grp = {
-	.attrs = dev_attrs,
-};
-
-static void handle_restart_teardown(struct msm_rpc_client *client)
-{
-	struct rmt_storage_srv *srv;
-
-	srv = rmt_storage_get_srv(client->prog);
-	if (!srv)
-		return;
-	pr_debug("%s: Modem restart for 0x%08x\n", __func__, srv->prog);
-	cancel_delayed_work_sync(&srv->restart_work);
-}
-
-#define RESTART_WORK_DELAY_MS	1000
-
-static void handle_restart_setup(struct msm_rpc_client *client)
-{
-	struct rmt_storage_srv *srv;
-
-	srv = rmt_storage_get_srv(client->prog);
-	if (!srv)
-		return;
-	pr_debug("%s: Scheduling restart for 0x%08x\n", __func__, srv->prog);
-	queue_delayed_work(rmc->workq, &srv->restart_work,
-			msecs_to_jiffies(RESTART_WORK_DELAY_MS));
-}
-
-static int rmt_storage_reg_callbacks(struct msm_rpc_client *client)
-{
-	int ret;
-
-	ret = rmt_storage_reg_cb(client,
-				 RMT_STORAGE_REGISTER_OPEN_PROC,
-				 RMT_STORAGE_EVNT_OPEN,
-				 rmt_storage_event_open_cb);
-	if (ret)
-		return ret;
-	ret = rmt_storage_reg_cb(client,
-				 RMT_STORAGE_REGISTER_CB_PROC,
-				 RMT_STORAGE_EVNT_CLOSE,
-				 rmt_storage_event_close_cb);
-	if (ret)
-		return ret;
-	ret = rmt_storage_reg_cb(client,
-				 RMT_STORAGE_REGISTER_CB_PROC,
-				 RMT_STORAGE_EVNT_WRITE_BLOCK,
-				 rmt_storage_event_write_block_cb);
-	if (ret)
-		return ret;
-	ret = rmt_storage_reg_cb(client,
-				 RMT_STORAGE_REGISTER_CB_PROC,
-				 RMT_STORAGE_EVNT_GET_DEV_ERROR,
-				 rmt_storage_event_get_err_cb);
-	if (ret)
-		return ret;
-	ret = rmt_storage_reg_cb(client,
-				 RMT_STORAGE_REGISTER_WRITE_IOVEC_PROC,
-				 RMT_STORAGE_EVNT_WRITE_IOVEC,
-				 rmt_storage_event_write_iovec_cb);
-	if (ret)
-		return ret;
-	ret = rmt_storage_reg_cb(client,
-				 RMT_STORAGE_REGISTER_READ_IOVEC_PROC,
-				 RMT_STORAGE_EVNT_READ_IOVEC,
-				 rmt_storage_event_read_iovec_cb);
-	if (ret)
-		return ret;
-	ret = rmt_storage_reg_cb(client,
-				 RMT_STORAGE_REGISTER_CB_PROC,
-				 RMT_STORAGE_EVNT_SEND_USER_DATA,
-				 rmt_storage_event_user_data_cb);
-	if (ret)
-		return ret;
-	ret = rmt_storage_reg_cb(client,
-				 RMT_STORAGE_REGISTER_ALLOC_RMT_BUF_PROC,
-				 RMT_STORAGE_EVNT_ALLOC_RMT_BUF,
-				 rmt_storage_event_alloc_rmt_buf_cb);
-	if (ret)
-		pr_info("%s: Unable (%d) registering aloc_rmt_buf\n",
-			__func__, ret);
-
-	pr_debug("%s: Callbacks (re)registered for 0x%08x\n\n", __func__,
-		 client->prog);
-	return 0;
-}
-
-static void rmt_storage_restart_work(struct work_struct *work)
-{
-	struct rmt_storage_srv *srv;
-	int ret;
-
-	srv = container_of((struct delayed_work *)work,
-			   struct rmt_storage_srv, restart_work);
-	if (!rmt_storage_get_srv(srv->prog)) {
-		pr_err("%s: Invalid server\n", __func__);
-		return;
-	}
-
-	ret = rmt_storage_reg_callbacks(srv->rpc_client);
-	if (!ret)
-		return;
-
-	pr_err("%s: Error (%d) re-registering callbacks for0x%08x\n",
-	       __func__, ret, srv->prog);
-
-	if (!msm_rpc_client_in_reset(srv->rpc_client))
-		queue_delayed_work(rmc->workq, &srv->restart_work,
-				msecs_to_jiffies(RESTART_WORK_DELAY_MS));
-}
-
-static int rmt_storage_probe(struct platform_device *pdev)
-{
-	struct rpcsvr_platform_device *dev;
-	int ret;
-
-	dev = container_of(pdev, struct rpcsvr_platform_device, base);
-	rmt_srv = rmt_storage_get_srv(dev->prog);
-
-	if (!rmt_srv) {
-		pr_err("%s: Invalid prog = %#x\n", __func__, dev->prog);
-		return -ENXIO;
-	}
-
-	rmt_storage_init_ramfs(rmt_srv);
-	rmt_storage_get_ramfs(rmt_srv);
-
-	INIT_DELAYED_WORK(&rmt_srv->restart_work, rmt_storage_restart_work);
-
-	/* Client Registration */
-	rmt_srv->rpc_client = msm_rpc_register_client2("rmt_storage",
-						   dev->prog, dev->vers, 1,
-						   handle_rmt_storage_call);
-	if (IS_ERR(rmt_srv->rpc_client)) {
-		pr_err("%s: Unable to register client (prog %.8x vers %.8x)\n",
-				__func__, dev->prog, dev->vers);
-		ret = PTR_ERR(rmt_srv->rpc_client);
-		return ret;
-	}
-
-	ret = msm_rpc_register_reset_callbacks(rmt_srv->rpc_client,
-		handle_restart_teardown,
-		handle_restart_setup);
-	if (ret)
-		goto unregister_client;
-
-	pr_info("%s: Remote storage RPC client (0x%x)initialized\n",
-		__func__, dev->prog);
-
-	/* register server callbacks */
-	ret = rmt_storage_reg_callbacks(rmt_srv->rpc_client);
-	if (ret)
-		goto unregister_client;
-
-	/* For targets that poll SMEM, set status to ready */
-	rmt_storage_set_client_status(rmt_srv, 1);
-
-	ret = register_reboot_notifier(&rmt_storage_reboot_notifier);
-	if (ret) {
-		pr_err("%s: Failed to register reboot notifier", __func__);
-		goto unregister_client;
-	}
-
-	ret = sysfs_create_group(&pdev->dev.kobj, &dev_attr_grp);
-	if (ret)
-		pr_err("%s: Failed to create sysfs node: %d\n", __func__, ret);
-
-	return 0;
-
-unregister_client:
-	msm_rpc_unregister_client(rmt_srv->rpc_client);
-	return ret;
-}
-
-static void rmt_storage_client_shutdown(struct platform_device *pdev)
-{
-	struct rpcsvr_platform_device *dev;
-	struct rmt_storage_srv *srv;
-
-	dev = container_of(pdev, struct rpcsvr_platform_device, base);
-	srv = rmt_storage_get_srv(dev->prog);
-	rmt_storage_set_client_status(srv, 0);
-}
-
-static void rmt_storage_destroy_rmc(void)
-{
-	wake_lock_destroy(&rmc->wlock);
-}
-
-static void __init rmt_storage_init_client_info(void)
-{
-	/* Initialization */
-	init_waitqueue_head(&rmc->event_q);
-	spin_lock_init(&rmc->lock);
-	atomic_set(&rmc->total_events, 0);
-	INIT_LIST_HEAD(&rmc->event_list);
-	INIT_LIST_HEAD(&rmc->client_list);
-	INIT_LIST_HEAD(&rmc->shrd_mem_list);
-	/* The client expects a non-zero return value for
-	 * its open requests. Hence reserve 0 bit.  */
-	__set_bit(0, &rmc->cids);
-	atomic_set(&rmc->wcount, 0);
-	wake_lock_init(&rmc->wlock, WAKE_LOCK_SUSPEND, "rmt_storage");
-}
-
-static struct rmt_storage_srv msm_srv = {
-	.prog = MSM_RMT_STORAGE_APIPROG,
-	.plat_drv = {
-		.probe	  = rmt_storage_probe,
-		.shutdown = rmt_storage_client_shutdown,
-		.driver	  = {
-			.name	= "rs300000a7",
-			.owner	= THIS_MODULE,
-		},
-	},
-};
-
-static struct rmt_storage_srv mdm_srv = {
-	.prog = MDM_RMT_STORAGE_APIPROG,
-	.plat_drv = {
-		.probe	  = rmt_storage_probe,
-		.shutdown = rmt_storage_client_shutdown,
-		.driver	  = {
-			.name	= "rs300100a7",
-			.owner	= THIS_MODULE,
-		},
-	},
-};
-
-static struct rmt_storage_srv *rmt_storage_get_srv(uint32_t prog)
-{
-	if (prog == MSM_RMT_STORAGE_APIPROG)
-		return &msm_srv;
-	if (prog == MDM_RMT_STORAGE_APIPROG)
-		return &mdm_srv;
-	return NULL;
-}
-
-
-static uint32_t rmt_storage_get_sid(const char *path)
-{
-	if (!strncmp(path, "/boot/modem_fs1", MAX_PATH_NAME))
-		return RAMFS_MODEMSTORAGE_ID;
-	if (!strncmp(path, "/boot/modem_fs2", MAX_PATH_NAME))
-		return RAMFS_MODEMSTORAGE_ID;
-	if (!strncmp(path, "/boot/modem_fsg", MAX_PATH_NAME))
-		return RAMFS_MODEMSTORAGE_ID;
-	if (!strncmp(path, "/q6_fs1_parti_id_0x59", MAX_PATH_NAME))
-		return RAMFS_MDM_STORAGE_ID;
-	if (!strncmp(path, "/q6_fs2_parti_id_0x5A", MAX_PATH_NAME))
-		return RAMFS_MDM_STORAGE_ID;
-	if (!strncmp(path, "/q6_fsg_parti_id_0x5B", MAX_PATH_NAME))
-		return RAMFS_MDM_STORAGE_ID;
-	if (!strncmp(path, "ssd", MAX_PATH_NAME))
-		return RAMFS_SSD_STORAGE_ID;
-	return 0;
-}
-
-static int __init rmt_storage_init(void)
-{
-#ifdef CONFIG_MSM_SDIO_SMEM
-	void *mdm_local_buf;
-#endif
-	int ret = 0;
-
-	rmc = kzalloc(sizeof(struct rmt_storage_client_info), GFP_KERNEL);
-	if (!rmc) {
-		pr_err("%s: Unable to allocate memory\n", __func__);
-		return  -ENOMEM;
-	}
-	rmt_storage_init_client_info();
-
-	ret = platform_driver_register(&msm_srv.plat_drv);
-	if (ret) {
-		pr_err("%s: Unable to register MSM RPC driver\n", __func__);
-		goto rmc_free;
-	}
-
-	ret = platform_driver_register(&mdm_srv.plat_drv);
-	if (ret) {
-		pr_err("%s: Unable to register MDM RPC driver\n", __func__);
-		goto unreg_msm_rpc;
-	}
-
-	ret = misc_register(&rmt_storage_device);
-	if (ret) {
-		pr_err("%s: Unable to register misc device %d\n", __func__,
-				MISC_DYNAMIC_MINOR);
-		goto unreg_mdm_rpc;
-	}
-
-#ifdef CONFIG_MSM_SDIO_SMEM
-	mdm_local_buf = kzalloc(MDM_LOCAL_BUF_SZ, GFP_KERNEL);
-	if (!mdm_local_buf) {
-		pr_err("%s: Unable to allocate shadow mem\n", __func__);
-		ret = -ENOMEM;
-		goto unreg_misc;
-	}
-
-	ret = rmt_storage_add_shrd_mem(RAMFS_MDM_STORAGE_ID,
-				       __pa(mdm_local_buf),
-				       MDM_LOCAL_BUF_SZ,
-				       NULL, NULL, &mdm_srv);
-	if (ret) {
-		pr_err("%s: Unable to add shadow mem entry\n", __func__);
-		goto free_mdm_local_buf;
-	}
-
-	pr_debug("%s: Shadow memory at %p (phys=%lx), %d bytes\n", __func__,
-		 mdm_local_buf, __pa(mdm_local_buf), MDM_LOCAL_BUF_SZ);
-#endif
-
-	rmc->workq = create_singlethread_workqueue("rmt_storage");
-	if (!rmc->workq)
-		return -ENOMEM;
-
-#ifdef CONFIG_MSM_RMT_STORAGE_CLIENT_STATS
-	stats_dentry = debugfs_create_file("rmt_storage_stats", 0444, 0,
-					NULL, &debug_ops);
-	if (!stats_dentry)
-		pr_err("%s: Failed to create stats debugfs file\n", __func__);
-#endif
-	return 0;
-
-#ifdef CONFIG_MSM_SDIO_SMEM
-free_mdm_local_buf:
-	kfree(mdm_local_buf);
-unreg_misc:
-	misc_deregister(&rmt_storage_device);
-#endif
-unreg_mdm_rpc:
-	platform_driver_unregister(&mdm_srv.plat_drv);
-unreg_msm_rpc:
-	platform_driver_unregister(&msm_srv.plat_drv);
-rmc_free:
-	rmt_storage_destroy_rmc();
-	kfree(rmc);
-	return ret;
-}
-
-module_init(rmt_storage_init);
-MODULE_DESCRIPTION("Remote Storage RPC Client");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index f230033..12fa799 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -627,7 +627,8 @@
 }
 
 static inline void refcount_group(struct adreno_perfcount_group *group,
-	unsigned int reg, unsigned int flags, unsigned int *lo)
+	unsigned int reg, unsigned int flags,
+	unsigned int *lo, unsigned int *hi)
 {
 	if (flags & PERFCOUNTER_FLAG_KERNEL)
 		group->regs[reg].kernelcount++;
@@ -636,6 +637,9 @@
 
 	if (lo)
 		*lo = group->regs[reg].offset;
+
+	if (hi)
+		*hi = group->regs[reg].offset_hi;
 }
 
 /**
@@ -643,7 +647,8 @@
  * @adreno_dev: Adreno device to configure
  * @groupid: Desired performance counter group
  * @countable: Countable desired to be in a counter
- * @offset: Return offset of the countable
+ * @offset: Return offset of the LO counter assigned
+ * @offset_hi: Return offset of the HI counter assigned
  * @flags: Used to setup kernel perf counters
  *
  * Try to place a countable in an available counter.  If the countable is
@@ -653,7 +658,7 @@
 
 int adreno_perfcounter_get(struct adreno_device *adreno_dev,
 	unsigned int groupid, unsigned int countable, unsigned int *offset,
-	unsigned int flags)
+	unsigned int *offset_hi, unsigned int flags)
 {
 	struct adreno_perfcounters *counters = adreno_dev->gpudev->perfcounters;
 	struct adreno_perfcount_group *group;
@@ -663,6 +668,8 @@
 	/* always clear return variables */
 	if (offset)
 		*offset = 0;
+	if (offset_hi)
+		*offset_hi = 0;
 
 	if (NULL == counters)
 		return -EINVAL;
@@ -684,7 +691,8 @@
 		/* If it is already reserved, just increase the refcounts */
 		if ((group->regs[countable].kernelcount != 0) ||
 			(group->regs[countable].usercount != 0)) {
-				refcount_group(group, countable, flags, offset);
+				refcount_group(group, countable, flags,
+					offset, offset_hi);
 				return 0;
 		}
 
@@ -700,7 +708,8 @@
 
 		for (i = 0; i < group->reg_count; i++) {
 			if (group->regs[i].countable == countable) {
-				refcount_group(group, i, flags, offset);
+				refcount_group(group, i, flags,
+					offset, offset_hi);
 				return 0;
 			} else if (group->regs[i].countable ==
 			KGSL_PERFCOUNTER_NOT_USED) {
@@ -733,6 +742,8 @@
 
 	if (offset)
 		*offset = group->regs[empty].offset;
+	if (offset_hi)
+		*offset_hi = group->regs[empty].offset_hi;
 
 	return ret;
 }
@@ -3352,7 +3363,8 @@
 		if (result)
 			break;
 		result = adreno_perfcounter_get(adreno_dev, get->groupid,
-			get->countable, &get->offset, PERFCOUNTER_FLAG_NONE);
+			get->countable, &get->offset, &get->offset_hi,
+			PERFCOUNTER_FLAG_NONE);
 		kgsl_active_count_put(device);
 		break;
 	}
diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h
index 3d9206b..c690801 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -240,6 +240,7 @@
 	unsigned int kernelcount;
 	unsigned int usercount;
 	unsigned int offset;
+	unsigned int offset_hi;
 	int load_bit;
 	unsigned int select;
 	uint64_t value;
@@ -530,7 +531,7 @@
 
 int adreno_perfcounter_get(struct adreno_device *adreno_dev,
 	unsigned int groupid, unsigned int countable, unsigned int *offset,
-	unsigned int flags);
+	unsigned int *offset_hi, unsigned int flags);
 
 int adreno_perfcounter_put(struct adreno_device *adreno_dev,
 	unsigned int groupid, unsigned int countable, unsigned int flags);
diff --git a/drivers/gpu/msm/adreno_a3xx.c b/drivers/gpu/msm/adreno_a3xx.c
index 2025d73..b0851a2 100644
--- a/drivers/gpu/msm/adreno_a3xx.c
+++ b/drivers/gpu/msm/adreno_a3xx.c
@@ -3814,141 +3814,158 @@
 
 static struct adreno_perfcount_register a3xx_perfcounters_cp[] = {
 	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_CP_0_LO,
-		0, A3XX_CP_PERFCOUNTER_SELECT },
+		A3XX_RBBM_PERFCTR_CP_0_HI, 0, A3XX_CP_PERFCOUNTER_SELECT },
 };
 
 static struct adreno_perfcount_register a3xx_perfcounters_rbbm[] = {
 	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_RBBM_0_LO,
-		1, A3XX_RBBM_PERFCOUNTER0_SELECT },
+		A3XX_RBBM_PERFCTR_RBBM_0_HI, 1, A3XX_RBBM_PERFCOUNTER0_SELECT },
 	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_RBBM_1_LO,
-		2, A3XX_RBBM_PERFCOUNTER1_SELECT },
+		A3XX_RBBM_PERFCTR_RBBM_1_HI, 2, A3XX_RBBM_PERFCOUNTER1_SELECT },
 };
 
 static struct adreno_perfcount_register a3xx_perfcounters_pc[] = {
 	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_PC_0_LO,
-		3, A3XX_PC_PERFCOUNTER0_SELECT },
+		A3XX_RBBM_PERFCTR_PC_0_HI, 3, A3XX_PC_PERFCOUNTER0_SELECT },
 	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_PC_1_LO,
-		4, A3XX_PC_PERFCOUNTER1_SELECT },
+		A3XX_RBBM_PERFCTR_PC_1_HI, 4, A3XX_PC_PERFCOUNTER1_SELECT },
 	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_PC_2_LO,
-		5, A3XX_PC_PERFCOUNTER2_SELECT },
+		A3XX_RBBM_PERFCTR_PC_2_HI, 5, A3XX_PC_PERFCOUNTER2_SELECT },
 	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_PC_3_LO,
-		6, A3XX_PC_PERFCOUNTER3_SELECT },
+		A3XX_RBBM_PERFCTR_PC_3_HI, 6, A3XX_PC_PERFCOUNTER3_SELECT },
 };
 
 static struct adreno_perfcount_register a3xx_perfcounters_vfd[] = {
 	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_VFD_0_LO,
-		7, A3XX_VFD_PERFCOUNTER0_SELECT },
+		A3XX_RBBM_PERFCTR_VFD_0_HI, 7, A3XX_VFD_PERFCOUNTER0_SELECT },
 	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_VFD_1_LO,
-		8, A3XX_VFD_PERFCOUNTER1_SELECT },
+		A3XX_RBBM_PERFCTR_VFD_1_HI, 8, A3XX_VFD_PERFCOUNTER1_SELECT },
 };
 
 static struct adreno_perfcount_register a3xx_perfcounters_hlsq[] = {
 	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_HLSQ_0_LO,
-		9, A3XX_HLSQ_PERFCOUNTER0_SELECT },
+		A3XX_RBBM_PERFCTR_HLSQ_0_HI, 9,
+		A3XX_HLSQ_PERFCOUNTER0_SELECT },
 	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_HLSQ_1_LO,
-		10, A3XX_HLSQ_PERFCOUNTER1_SELECT },
+		A3XX_RBBM_PERFCTR_HLSQ_1_HI, 10,
+		A3XX_HLSQ_PERFCOUNTER1_SELECT },
 	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_HLSQ_2_LO,
-		11, A3XX_HLSQ_PERFCOUNTER2_SELECT },
+		A3XX_RBBM_PERFCTR_HLSQ_2_HI, 11,
+		A3XX_HLSQ_PERFCOUNTER2_SELECT },
 	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_HLSQ_3_LO,
-		12, A3XX_HLSQ_PERFCOUNTER3_SELECT },
+		A3XX_RBBM_PERFCTR_HLSQ_3_HI, 12,
+		A3XX_HLSQ_PERFCOUNTER3_SELECT },
 	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_HLSQ_4_LO,
-		13, A3XX_HLSQ_PERFCOUNTER4_SELECT },
+		A3XX_RBBM_PERFCTR_HLSQ_4_HI, 13,
+		A3XX_HLSQ_PERFCOUNTER4_SELECT },
 	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_HLSQ_5_LO,
-		14, A3XX_HLSQ_PERFCOUNTER5_SELECT },
+		A3XX_RBBM_PERFCTR_HLSQ_5_HI, 14,
+		A3XX_HLSQ_PERFCOUNTER5_SELECT },
 };
 
 static struct adreno_perfcount_register a3xx_perfcounters_vpc[] = {
 	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_VPC_0_LO,
-		15, A3XX_VPC_PERFCOUNTER0_SELECT },
+		A3XX_RBBM_PERFCTR_VPC_0_HI, 15, A3XX_VPC_PERFCOUNTER0_SELECT },
 	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_VPC_1_LO,
-		16, A3XX_VPC_PERFCOUNTER1_SELECT },
+		A3XX_RBBM_PERFCTR_VPC_1_HI, 16, A3XX_VPC_PERFCOUNTER1_SELECT },
 };
 
 static struct adreno_perfcount_register a3xx_perfcounters_tse[] = {
 	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_TSE_0_LO,
-		17, A3XX_GRAS_PERFCOUNTER0_SELECT },
+		A3XX_RBBM_PERFCTR_TSE_0_HI, 17, A3XX_GRAS_PERFCOUNTER0_SELECT },
 	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_TSE_1_LO,
-		18, A3XX_GRAS_PERFCOUNTER1_SELECT },
+		A3XX_RBBM_PERFCTR_TSE_1_HI, 18, A3XX_GRAS_PERFCOUNTER1_SELECT },
 };
 
 static struct adreno_perfcount_register a3xx_perfcounters_ras[] = {
 	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_RAS_0_LO,
-		19, A3XX_GRAS_PERFCOUNTER2_SELECT },
+		A3XX_RBBM_PERFCTR_RAS_0_HI, 19, A3XX_GRAS_PERFCOUNTER2_SELECT },
 	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_RAS_1_LO,
-		20, A3XX_GRAS_PERFCOUNTER3_SELECT },
+		A3XX_RBBM_PERFCTR_RAS_1_HI, 20, A3XX_GRAS_PERFCOUNTER3_SELECT },
 };
 
 static struct adreno_perfcount_register a3xx_perfcounters_uche[] = {
 	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_UCHE_0_LO,
-		21, A3XX_UCHE_PERFCOUNTER0_SELECT },
+		A3XX_RBBM_PERFCTR_UCHE_0_HI, 21,
+		A3XX_UCHE_PERFCOUNTER0_SELECT },
 	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_UCHE_1_LO,
-		22, A3XX_UCHE_PERFCOUNTER1_SELECT },
+		A3XX_RBBM_PERFCTR_UCHE_1_HI, 22,
+		A3XX_UCHE_PERFCOUNTER1_SELECT },
 	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_UCHE_2_LO,
-		23, A3XX_UCHE_PERFCOUNTER2_SELECT },
+		A3XX_RBBM_PERFCTR_UCHE_2_HI, 23,
+		A3XX_UCHE_PERFCOUNTER2_SELECT },
 	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_UCHE_3_LO,
-		24, A3XX_UCHE_PERFCOUNTER3_SELECT },
+		A3XX_RBBM_PERFCTR_UCHE_3_HI, 24,
+		A3XX_UCHE_PERFCOUNTER3_SELECT },
 	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_UCHE_4_LO,
-		25, A3XX_UCHE_PERFCOUNTER4_SELECT },
+		A3XX_RBBM_PERFCTR_UCHE_4_HI, 25,
+		A3XX_UCHE_PERFCOUNTER4_SELECT },
 	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_UCHE_5_LO,
-		26, A3XX_UCHE_PERFCOUNTER5_SELECT },
+		A3XX_RBBM_PERFCTR_UCHE_5_HI, 26,
+		A3XX_UCHE_PERFCOUNTER5_SELECT },
 };
 
 static struct adreno_perfcount_register a3xx_perfcounters_tp[] = {
 	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_TP_0_LO,
-		27, A3XX_TP_PERFCOUNTER0_SELECT },
+		A3XX_RBBM_PERFCTR_TP_0_HI, 27, A3XX_TP_PERFCOUNTER0_SELECT },
 	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_TP_1_LO,
-		28, A3XX_TP_PERFCOUNTER1_SELECT },
+		A3XX_RBBM_PERFCTR_TP_1_HI, 28, A3XX_TP_PERFCOUNTER1_SELECT },
 	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_TP_2_LO,
-		29, A3XX_TP_PERFCOUNTER2_SELECT },
+		A3XX_RBBM_PERFCTR_TP_2_HI, 29, A3XX_TP_PERFCOUNTER2_SELECT },
 	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_TP_3_LO,
-		30, A3XX_TP_PERFCOUNTER3_SELECT },
+		A3XX_RBBM_PERFCTR_TP_3_HI, 30, A3XX_TP_PERFCOUNTER3_SELECT },
 	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_TP_4_LO,
-		31, A3XX_TP_PERFCOUNTER4_SELECT },
+		A3XX_RBBM_PERFCTR_TP_4_HI, 31, A3XX_TP_PERFCOUNTER4_SELECT },
 	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_TP_5_LO,
-		32, A3XX_TP_PERFCOUNTER5_SELECT },
+		A3XX_RBBM_PERFCTR_TP_5_HI, 32, A3XX_TP_PERFCOUNTER5_SELECT },
 };
 
 static struct adreno_perfcount_register a3xx_perfcounters_sp[] = {
 	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_SP_0_LO,
-		33, A3XX_SP_PERFCOUNTER0_SELECT },
+		A3XX_RBBM_PERFCTR_SP_0_HI, 33, A3XX_SP_PERFCOUNTER0_SELECT },
 	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_SP_1_LO,
-		34, A3XX_SP_PERFCOUNTER1_SELECT },
+		A3XX_RBBM_PERFCTR_SP_1_HI, 34, A3XX_SP_PERFCOUNTER1_SELECT },
 	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_SP_2_LO,
-		35, A3XX_SP_PERFCOUNTER2_SELECT },
+		A3XX_RBBM_PERFCTR_SP_2_HI, 35, A3XX_SP_PERFCOUNTER2_SELECT },
 	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_SP_3_LO,
-		36, A3XX_SP_PERFCOUNTER3_SELECT },
+		A3XX_RBBM_PERFCTR_SP_3_HI, 36, A3XX_SP_PERFCOUNTER3_SELECT },
 	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_SP_4_LO,
-		37, A3XX_SP_PERFCOUNTER4_SELECT },
+		A3XX_RBBM_PERFCTR_SP_4_HI, 37, A3XX_SP_PERFCOUNTER4_SELECT },
 	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_SP_5_LO,
-		38, A3XX_SP_PERFCOUNTER5_SELECT },
+		A3XX_RBBM_PERFCTR_SP_5_HI, 38, A3XX_SP_PERFCOUNTER5_SELECT },
 	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_SP_6_LO,
-		39, A3XX_SP_PERFCOUNTER6_SELECT },
+		A3XX_RBBM_PERFCTR_SP_6_HI, 39, A3XX_SP_PERFCOUNTER6_SELECT },
 	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_SP_7_LO,
-		40, A3XX_SP_PERFCOUNTER7_SELECT },
+		A3XX_RBBM_PERFCTR_SP_7_HI, 40, A3XX_SP_PERFCOUNTER7_SELECT },
 };
 
 static struct adreno_perfcount_register a3xx_perfcounters_rb[] = {
 	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_RB_0_LO,
-		41, A3XX_RB_PERFCOUNTER0_SELECT },
+		A3XX_RBBM_PERFCTR_RB_0_HI, 41, A3XX_RB_PERFCOUNTER0_SELECT },
 	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_RB_1_LO,
-		42, A3XX_RB_PERFCOUNTER1_SELECT },
+		A3XX_RBBM_PERFCTR_RB_1_HI, 42, A3XX_RB_PERFCOUNTER1_SELECT },
 };
 
 static struct adreno_perfcount_register a3xx_perfcounters_pwr[] = {
 	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_PWR_0_LO,
-		-1, 0 },
+		A3XX_RBBM_PERFCTR_PWR_0_HI, -1, 0 },
 	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_PWR_1_LO,
-		-1, 0 },
+		A3XX_RBBM_PERFCTR_PWR_1_HI, -1, 0 },
 };
 
 static struct adreno_perfcount_register a3xx_perfcounters_vbif[] = {
-	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_VBIF_PERF_CNT0_LO, -1, 0 },
-	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_VBIF_PERF_CNT1_LO, -1, 0 },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_VBIF_PERF_CNT0_LO,
+		A3XX_VBIF_PERF_CNT0_HI, -1, 0 },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_VBIF_PERF_CNT1_LO,
+		A3XX_VBIF_PERF_CNT1_HI, -1, 0 },
 };
 static struct adreno_perfcount_register a3xx_perfcounters_vbif_pwr[] = {
-	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_VBIF_PERF_PWR_CNT0_LO, -1, 0 },
-	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_VBIF_PERF_PWR_CNT1_LO, -1, 0 },
-	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_VBIF_PERF_PWR_CNT2_LO, -1, 0 },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_VBIF_PERF_PWR_CNT0_LO,
+		A3XX_VBIF_PERF_PWR_CNT0_HI, -1, 0 },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_VBIF_PERF_PWR_CNT1_LO,
+		A3XX_VBIF_PERF_PWR_CNT1_HI, -1, 0 },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_VBIF_PERF_PWR_CNT2_LO,
+		A3XX_VBIF_PERF_PWR_CNT2_HI, -1, 0 },
 };
 
 static struct adreno_perfcount_group a3xx_perfcounter_groups[] = {
@@ -3983,14 +4000,11 @@
 	int ret = 0;
 
 	if (*lo == 0) {
-		*hi = 0;
 
 		ret = adreno_perfcounter_get(adreno_dev, group, countable,
-			lo, PERFCOUNTER_FLAG_KERNEL);
+			lo, hi, PERFCOUNTER_FLAG_KERNEL);
 
-		if (ret == 0)
-			*hi = *lo + 1;
-		else {
+		if (ret) {
 			struct kgsl_device *device = &adreno_dev->dev;
 
 			KGSL_DRV_ERR(device,
@@ -4106,18 +4120,18 @@
 
 	/* Reserve and start countable 1 in the PWR perfcounter group */
 	ret = adreno_perfcounter_get(adreno_dev, KGSL_PERFCOUNTER_GROUP_PWR, 1,
-			NULL, PERFCOUNTER_FLAG_KERNEL);
+			NULL, NULL, PERFCOUNTER_FLAG_KERNEL);
 
 	if (device->pwrctrl.bus_control) {
 		/* VBIF waiting for RAM */
 		ret |= adreno_perfcounter_get(adreno_dev,
 				KGSL_PERFCOUNTER_GROUP_VBIF_PWR, 0,
-				NULL, PERFCOUNTER_FLAG_KERNEL);
+				NULL, NULL, PERFCOUNTER_FLAG_KERNEL);
 		/* VBIF DDR cycles */
 		ret |= adreno_perfcounter_get(adreno_dev,
 				KGSL_PERFCOUNTER_GROUP_VBIF,
 				VBIF_AXI_TOTAL_BEATS,
-				&adreno_dev->ram_cycles_lo,
+				&adreno_dev->ram_cycles_lo, NULL,
 				PERFCOUNTER_FLAG_KERNEL);
 	}
 
diff --git a/drivers/gpu/msm/adreno_profile.c b/drivers/gpu/msm/adreno_profile.c
index 38e0af8..45075a5 100644
--- a/drivers/gpu/msm/adreno_profile.c
+++ b/drivers/gpu/msm/adreno_profile.c
@@ -146,7 +146,7 @@
 				entry->offset, data_offset);
 		IB_CMD(ibcmds, CP_REG_TO_MEM, entry->offset,
 				gpuaddr + data_offset, data_offset);
-		IB_CMD(ibcmds, CP_REG_TO_MEM, entry->offset + 1,
+		IB_CMD(ibcmds, CP_REG_TO_MEM, entry->offset_hi,
 				gpuaddr + data_offset, data_offset);
 
 		/* skip over post_ib counter data */
@@ -185,7 +185,7 @@
 
 		IB_CMD(ibcmds, CP_REG_TO_MEM, entry->offset,
 				gpuaddr + data_offset, data_offset);
-		IB_CMD(ibcmds, CP_REG_TO_MEM, entry->offset + 1,
+		IB_CMD(ibcmds, CP_REG_TO_MEM, entry->offset_hi,
 				gpuaddr + data_offset, data_offset);
 	}
 
@@ -281,7 +281,7 @@
 
 static bool _add_to_assignments_list(struct adreno_profile *profile,
 		const char *str, unsigned int groupid, unsigned int countable,
-		unsigned int offset)
+		unsigned int offset, unsigned int offset_hi)
 {
 	struct adreno_profile_assigns_list *entry;
 
@@ -295,6 +295,7 @@
 	entry->countable = countable;
 	entry->groupid = groupid;
 	entry->offset = offset;
+	entry->offset_hi = offset_hi;
 
 	strlcpy(entry->name, str, sizeof(entry->name));
 
@@ -576,7 +577,7 @@
 		unsigned int groupid, unsigned int countable)
 {
 	struct adreno_profile *profile = &adreno_dev->profile;
-	unsigned int offset;
+	unsigned int offset, offset_hi;
 	const char *name = NULL;
 
 	name = adreno_perfcounter_get_name(adreno_dev, groupid);
@@ -588,13 +589,13 @@
 		return;
 
 	/* add to perf counter allocation, if fail skip it */
-	if (adreno_perfcounter_get(adreno_dev, groupid,
-				countable, &offset, PERFCOUNTER_FLAG_NONE))
+	if (adreno_perfcounter_get(adreno_dev, groupid, countable,
+				&offset, &offset_hi, PERFCOUNTER_FLAG_NONE))
 		return;
 
 	/* add to assignments list, put counter back if error */
 	if (!_add_to_assignments_list(profile, name, groupid,
-				countable, offset))
+				countable, offset, offset_hi))
 		adreno_perfcounter_put(adreno_dev, groupid,
 				countable, PERFCOUNTER_FLAG_KERNEL);
 }
diff --git a/drivers/gpu/msm/adreno_profile.h b/drivers/gpu/msm/adreno_profile.h
index 7e1ccb2..dfd22d8 100644
--- a/drivers/gpu/msm/adreno_profile.h
+++ b/drivers/gpu/msm/adreno_profile.h
@@ -27,7 +27,8 @@
 	char name[25];
 	unsigned int groupid;
 	unsigned int countable;
-	unsigned int offset;   /* LO offset,  HI offset is +1 */
+	unsigned int offset;    /* LO offset */
+	unsigned int offset_hi; /* HI offset */
 };
 
 struct adreno_profile {
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index 6269bb9..d1241e0 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -64,14 +64,8 @@
 	struct sg_table *table;
 };
 
-static void kgsl_put_process_private(struct kgsl_device *device,
-			 struct kgsl_process_private *private);
-
 static void kgsl_mem_entry_detach_process(struct kgsl_mem_entry *entry);
 
-static void
-kgsl_put_process_private(struct kgsl_device *device,
-			 struct kgsl_process_private *private);
 /**
  * kgsl_trace_issueibcmds() - Call trace_issueibcmds by proxy
  * device: KGSL device
@@ -352,8 +346,8 @@
 {
 	int ret;
 	struct kgsl_process_private *process = dev_priv->process_priv;
-	
-	ret = kref_get_unless_zero(&process->refcount);
+
+	ret = kgsl_process_private_get(process);
 	if (!ret)
 		return -EBADF;
 
@@ -392,7 +386,7 @@
 	return ret;
 
 err_put_proc_priv:
-	kgsl_put_process_private(dev_priv->device, process);
+	kgsl_process_private_put(process);
 	return ret;
 }
 
@@ -415,7 +409,7 @@
 
 	entry->priv->stats[entry->memtype].cur -= entry->memdesc.size;
 	spin_unlock(&entry->priv->mem_lock);
-	kgsl_put_process_private(entry->dev_priv->device, entry->priv);
+	kgsl_process_private_put(entry->priv);
 
 	entry->priv = NULL;
 }
@@ -473,7 +467,7 @@
 	 * the context is destroyed. This will also prevent the pagetable
 	 * from being destroyed
 	 */
-	if (!kref_get_unless_zero(&dev_priv->process_priv->refcount))
+	if (!kgsl_process_private_get(dev_priv->process_priv))
 		goto fail_free_id;
 	context->device = dev_priv->device;
 	context->dev_priv = dev_priv;
@@ -568,8 +562,7 @@
 	}
 	write_unlock(&device->context_lock);
 	kgsl_sync_timeline_destroy(context);
-	kgsl_put_process_private(device,
-				context->proc_priv);
+	kgsl_process_private_put(context->proc_priv);
 
 	device->ftbl->drawctxt_destroy(context);
 }
@@ -811,9 +804,8 @@
 	return;
 }
 
-static void
-kgsl_put_process_private(struct kgsl_device *device,
-			 struct kgsl_process_private *private)
+void
+kgsl_process_private_put(struct kgsl_process_private *private)
 {
 	mutex_lock(&kgsl_driver.process_mutex);
 
@@ -828,13 +820,32 @@
 }
 
 /**
- * find_process_private() - Helper function to search for process private
- * @cur_dev_priv: Pointer to device private structure which contains pointers
- * to device and process_private structs.
+ * kgsl_process_private_find() - Find the process associated with the specified
+ * name
+ * @name: pid_t of the process to search for
+ * Return the process struct for the given ID.
+ */
+struct kgsl_process_private *kgsl_process_private_find(pid_t pid)
+{
+	struct kgsl_process_private *p, *private = NULL;
+
+	mutex_lock(&kgsl_driver.process_mutex);
+	list_for_each_entry(p, &kgsl_driver.process_list, list) {
+		if (p->pid == pid) {
+			if (kgsl_process_private_get(p))
+				private = p;
+			break;
+		}
+	}
+	mutex_unlock(&kgsl_driver.process_mutex);
+	return private;
+}
+
+/**
+ * kgsl_process_private_new() - Helper function to search for process private
  * Returns: Pointer to the found/newly created private struct
  */
-static struct kgsl_process_private *
-kgsl_find_process_private(struct kgsl_device_private *cur_dev_priv)
+static struct kgsl_process_private *kgsl_process_private_new(void)
 {
 	struct kgsl_process_private *private;
 
@@ -842,18 +853,16 @@
 	mutex_lock(&kgsl_driver.process_mutex);
 	list_for_each_entry(private, &kgsl_driver.process_list, list) {
 		if (private->pid == task_tgid_nr(current)) {
-			kref_get(&private->refcount);
+			if (!kgsl_process_private_get(private))
+				private = NULL;
 			goto done;
 		}
 	}
 
 	/* no existing process private found for this dev_priv, create one */
 	private = kzalloc(sizeof(struct kgsl_process_private), GFP_KERNEL);
-	if (private == NULL) {
-		KGSL_DRV_ERR(cur_dev_priv->device, "kzalloc(%d) failed\n",
-			sizeof(struct kgsl_process_private));
+	if (private == NULL)
 		goto done;
-	}
 
 	kref_init(&private->refcount);
 
@@ -875,11 +884,11 @@
  * NULL if pagetable creation for this process private obj failed.
  */
 static struct kgsl_process_private *
-kgsl_get_process_private(struct kgsl_device_private *cur_dev_priv)
+kgsl_get_process_private(struct kgsl_device *device)
 {
 	struct kgsl_process_private *private;
 
-	private = kgsl_find_process_private(cur_dev_priv);
+	private = kgsl_process_private_new();
 
 	if (!private)
 		return NULL;
@@ -894,15 +903,15 @@
 
 	if ((!private->pagetable) && kgsl_mmu_enabled()) {
 		unsigned long pt_name;
-		struct kgsl_mmu *mmu = &cur_dev_priv->device->mmu;
 
 		pt_name = task_tgid_nr(current);
-		private->pagetable = kgsl_mmu_getpagetable(mmu, pt_name);
+		private->pagetable =
+			kgsl_mmu_getpagetable(&device->mmu, pt_name);
 		if (private->pagetable == NULL)
 			goto error;
 	}
 
-	if (kgsl_process_init_sysfs(cur_dev_priv->device, private))
+	if (kgsl_process_init_sysfs(device, private))
 		goto error;
 	if (kgsl_process_init_debugfs(private))
 		goto error;
@@ -915,7 +924,7 @@
 
 error:
 	mutex_unlock(&private->process_private_mutex);
-	kgsl_put_process_private(cur_dev_priv->device, private);
+	kgsl_process_private_put(private);
 	return NULL;
 }
 
@@ -1009,7 +1018,7 @@
 
 	kfree(dev_priv);
 
-	kgsl_put_process_private(device, private);
+	kgsl_process_private_put(private);
 
 	pm_runtime_put(device->parentdev);
 	return result;
@@ -1099,7 +1108,7 @@
 	 * after the first start so that the global pagetable mappings
 	 * are set up before we create the per-process pagetable.
 	 */
-	dev_priv->process_priv = kgsl_get_process_private(dev_priv);
+	dev_priv->process_priv = kgsl_get_process_private(device);
 	if (dev_priv->process_priv ==  NULL) {
 		result = -ENOMEM;
 		goto err_stop;
diff --git a/drivers/gpu/msm/kgsl_debugfs.c b/drivers/gpu/msm/kgsl_debugfs.c
index c1b3139..5645628 100644
--- a/drivers/gpu/msm/kgsl_debugfs.c
+++ b/drivers/gpu/msm/kgsl_debugfs.c
@@ -247,7 +247,7 @@
 
 static void print_mem_entry(struct seq_file *s, struct kgsl_mem_entry *entry)
 {
-	char flags[6];
+	char flags[7];
 	char usage[16];
 	struct kgsl_memdesc *m = &entry->memdesc;
 
@@ -256,11 +256,12 @@
 	flags[2] = get_alignflag(m);
 	flags[3] = get_cacheflag(m);
 	flags[4] = kgsl_memdesc_use_cpu_map(m) ? 'p' : '-';
-	flags[5] = '\0';
+	flags[5] = (m->useraddr) ? 'Y' : 'N';
+	flags[6] = '\0';
 
 	kgsl_get_memory_usage(usage, sizeof(usage), m->flags);
 
-	seq_printf(s, "%pK %pK %8zd %5d %5s %10s %16s %5d\n",
+	seq_printf(s, "%pK %pK %8zd %5d %6s %10s %16s %5d\n",
 			(unsigned long *) m->gpuaddr,
 			(unsigned long *) m->useraddr,
 			m->size, entry->id, flags,
@@ -274,7 +275,7 @@
 	struct kgsl_process_private *private = s->private;
 	int next = 0;
 
-	seq_printf(s, "%8s %8s %8s %5s %5s %10s %16s %5s\n",
+	seq_printf(s, "%8s %8s %8s %5s %6s %10s %16s %5s\n",
 		   "gpuaddr", "useraddr", "size", "id", "flags", "type",
 		   "usage", "sglen");
 
@@ -303,14 +304,38 @@
 
 static int process_mem_open(struct inode *inode, struct file *file)
 {
-	return single_open(file, process_mem_print, inode->i_private);
+	int ret;
+	pid_t pid = (pid_t) (unsigned long) inode->i_private;
+	struct kgsl_process_private *private = NULL;
+
+	private = kgsl_process_private_find(pid);
+
+	if (!private)
+		return -ENODEV;
+
+	ret = single_open(file, process_mem_print, private);
+	if (ret)
+		kgsl_process_private_put(private);
+
+	return ret;
+}
+
+static int process_mem_release(struct inode *inode, struct file *file)
+{
+	struct kgsl_process_private *private =
+		((struct seq_file *)file->private_data)->private;
+
+	if (private)
+		kgsl_process_private_put(private);
+
+	return single_release(inode, file);
 }
 
 static const struct file_operations process_mem_fops = {
 	.open = process_mem_open,
 	.read = seq_read,
 	.llseek = seq_lseek,
-	.release = single_release,
+	.release = process_mem_release,
 };
 
 
@@ -349,8 +374,8 @@
 	 * So if debugfs is disabled in kernel, return as
 	 * success.
 	 */
-	dentry = debugfs_create_file("mem", 0444, private->debug_root, private,
-			    &process_mem_fops);
+	dentry = debugfs_create_file("mem", 0444, private->debug_root,
+		(void *) ((unsigned long) private->pid), &process_mem_fops);
 
 	if (IS_ERR(dentry)) {
 		ret = PTR_ERR(dentry);
diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h
index bc8a02e..7f936ed 100644
--- a/drivers/gpu/msm/kgsl_device.h
+++ b/drivers/gpu/msm/kgsl_device.h
@@ -696,6 +696,27 @@
 void kgsl_cmdbatch_destroy_object(struct kref *kref);
 
 /**
+* kgsl_process_private_get() - increment the refcount on a kgsl_process_private
+*   struct
+* @process: Pointer to the KGSL process_private
+*
+* Returns 0 if the structure is invalid and a reference count could not be
+* obtained, nonzero otherwise.
+*/
+static inline int kgsl_process_private_get(struct kgsl_process_private *process)
+{
+	int ret = 0;
+	if (process != NULL)
+		ret = kref_get_unless_zero(&process->refcount);
+	return ret;
+}
+
+void kgsl_process_private_put(struct kgsl_process_private *private);
+
+
+struct kgsl_process_private *kgsl_process_private_find(pid_t pid);
+
+/**
  * kgsl_cmdbatch_put() - Decrement the refcount for a command batch object
  * @cmdbatch: Pointer to the command batch object
  */
diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
index 1704105..545e68f 100644
--- a/drivers/i2c/busses/i2c-qup.c
+++ b/drivers/i2c/busses/i2c-qup.c
@@ -193,6 +193,7 @@
 	int                          wr_sz;
 	struct msm_i2c_platform_data *pdata;
 	enum msm_i2c_state           pwr_state;
+	atomic_t		     xfer_progress;
 	struct mutex                 mlock;
 	void                         *complete;
 	int                          i2c_gpios[ARRAY_SIZE(i2c_rsrcs)];
@@ -230,8 +231,10 @@
 	uint32_t op_flgs = 0;
 	int err = 0;
 
-	if (pm_runtime_suspended(dev->dev))
+	if (atomic_read(&dev->xfer_progress) != 1) {
+		dev_err(dev->dev, "irq:%d when PM suspended\n", irq);
 		return IRQ_NONE;
+	}
 
 	status = readl_relaxed(dev->base + QUP_I2C_STATUS);
 	status1 = readl_relaxed(dev->base + QUP_ERROR_FLAGS);
@@ -1002,6 +1005,7 @@
 	if (dev->pdata->clk_ctl_xfer)
 		i2c_qup_pm_resume_clk(dev);
 
+	atomic_set(&dev->xfer_progress, 1);
 	/* Initialize QUP registers during first transfer */
 	if (dev->clk_ctl == 0) {
 		int fs_div;
@@ -1305,6 +1309,7 @@
 	dev->cnt = 0;
 	if (dev->pdata->clk_ctl_xfer)
 		i2c_qup_pm_suspend_clk(dev);
+	atomic_set(&dev->xfer_progress, 0);
 	mutex_unlock(&dev->mlock);
 	pm_runtime_mark_last_busy(dev->dev);
 	pm_runtime_put_autosuspend(dev->dev);
@@ -1655,6 +1660,7 @@
 
 	mutex_init(&dev->mlock);
 	dev->pwr_state = MSM_I2C_PM_SUSPENDED;
+	atomic_set(&dev->xfer_progress, 0);
 	/* If the same AHB clock is used on Modem side
 	 * switch it on here itself and don't switch it
 	 * on and off during suspend and resume.
diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c
index 937fb8c..3a3c370 100644
--- a/drivers/media/dvb/dvb-core/dmxdev.c
+++ b/drivers/media/dvb/dvb-core/dmxdev.c
@@ -3871,7 +3871,12 @@
 	if (ret > 0) {
 		dvb_dmxdev_notify_data_read(dmxdevfilter, ret);
 		spin_lock_irq(&dmxdevfilter->dev->lock);
-		dvb_dmxdev_update_events(&dmxdevfilter->events, ret);
+		/*
+		 * Updating the events in case of overflow might remove the
+		 * overflow event, so avoid that.
+		 */
+		if (dmxdevfilter->buffer.error != -EOVERFLOW)
+			dvb_dmxdev_update_events(&dmxdevfilter->events, ret);
 		spin_unlock_irq(&dmxdevfilter->dev->lock);
 
 		/*
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c b/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c
index f9855c0..4e73c5a 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c
@@ -675,7 +675,7 @@
 	struct msm_isp_bufq *bufq = NULL;
 	CDBG("%s: E\n", __func__);
 
-	if (!buf_request->num_buf) {
+	if (!buf_request->num_buf || buf_request->num_buf > VIDEO_MAX_FRAME) {
 		pr_err("Invalid buffer request\n");
 		return rc;
 	}
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
index 805ff0a..69c5190 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
@@ -396,6 +396,7 @@
 	atomic_t stats_comp_mask;
 	uint16_t stream_handle_cnt;
 	atomic_t stats_update;
+	uint32_t stats_mask;
 };
 
 struct msm_vfe_tasklet_queue_cmd {
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
index 81e9c74..e817680 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
@@ -350,6 +350,8 @@
 	msm_camera_io_w_mb(0xFEFFFFFF, vfe_dev->vfe_base + 0x2C);
 	msm_camera_io_w(0xFFFFFFFF, vfe_dev->vfe_base + 0x30);
 	msm_camera_io_w_mb(0xFEFFFFFF, vfe_dev->vfe_base + 0x34);
+	msm_camera_io_w(vfe_dev->stats_data.stats_mask,
+		vfe_dev->vfe_base + 0x44);
 }
 
 static void msm_vfe40_process_reset_irq(struct vfe_device *vfe_dev,
@@ -1272,6 +1274,7 @@
 	else
 		comp_mask &= ~stats_mask;
 	msm_camera_io_w(comp_mask << 16, vfe_dev->vfe_base + 0x44);
+	vfe_dev->stats_data.stats_mask = (comp_mask << 16);
 }
 
 static void msm_vfe40_stats_cfg_wm_irq_mask(
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
index f44f026..ebdca89 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
@@ -130,7 +130,10 @@
 	mutex_lock(&bandwidth_mgr_mutex);
 	if (!isp_bandwidth_mgr.use_count ||
 		!isp_bandwidth_mgr.bus_client) {
-		pr_err("%s: bandwidth manager inactive\n", __func__);
+		pr_err("%s:error bandwidth manager inactive use_cnt:%d bus_clnt:%d\n",
+			__func__, isp_bandwidth_mgr.use_count,
+			isp_bandwidth_mgr.bus_client);
+		mutex_unlock(&bandwidth_mgr_mutex);
 		return -EINVAL;
 	}
 
@@ -166,8 +169,11 @@
 		return;
 	}
 
-	if (!isp_bandwidth_mgr.bus_client)
+	if (!isp_bandwidth_mgr.bus_client) {
+		pr_err("%s:%d error: bus client invalid\n", __func__, __LINE__);
+		mutex_unlock(&bandwidth_mgr_mutex);
 		return;
+	}
 
 	msm_bus_scale_client_update_request(
 	   isp_bandwidth_mgr.bus_client, 0);
@@ -1137,6 +1143,11 @@
 
 	vfe_dev->hw_info->vfe_ops.irq_ops.
 		read_irq_status(vfe_dev, &irq_status0, &irq_status1);
+	if ((irq_status0 == 0) && (irq_status1 == 0)) {
+		pr_err_ratelimited("%s: irq_status0 & 1 are both 0\n",
+			__func__);
+		return IRQ_HANDLED;
+	}
 	msm_isp_process_overflow_irq(vfe_dev,
 		&irq_status0, &irq_status1);
 	vfe_dev->hw_info->vfe_ops.core_ops.
@@ -1152,7 +1163,7 @@
 	if ((irq_status0 == 0) && (irq_status1 == 0) &&
 		(!((error_mask0 != 0) || (error_mask1 != 0)) &&
 		 vfe_dev->error_info.error_count == 1)) {
-		ISP_DBG("%s: irq_status0 & 1 are both 0!\n", __func__);
+		ISP_DBG("%s: error_mask0/1 & error_count are set!\n", __func__);
 		return IRQ_HANDLED;
 	}
 
@@ -1205,7 +1216,7 @@
 		spin_unlock_irqrestore(&vfe_dev->tasklet_lock, flags);
 		if (atomic_read(&vfe_dev->error_info.overflow_state) !=
 			NO_OVERFLOW) {
-			pr_err("There is Overflow, kicking up recovery !!!!");
+			pr_err_ratelimited("There is Overflow, kicking up recovery !!!!");
 			msm_isp_process_overflow_recovery(vfe_dev,
 				irq_status0, irq_status1);
 			continue;
diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
index a53ac38..d3a848a 100644
--- a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
+++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
@@ -37,6 +37,7 @@
 #include <media/msmb_camera.h>
 #include <media/msmb_generic_buf_mgr.h>
 #include <media/msmb_pproc.h>
+#include <mach/clk-provider.h>
 #include "msm_cpp.h"
 #include "msm_isp_util.h"
 #include "msm_camera_io_util.h"
@@ -49,6 +50,7 @@
 #define CONFIG_MSM_CPP_DBG 0
 
 #define CPP_CMD_TIMEOUT_MS 300
+#define MSM_CPP_CORE_CLK_IDX 4
 #define MSM_MICRO_IFACE_CLK_IDX 7
 
 #define MSM_CPP_NOMINAL_CLOCK 266670000
@@ -98,6 +100,8 @@
 	qcmd;			 \
 })
 
+#define MSM_CPP_MAX_TIMEOUT_TRIAL 3
+
 static void msm_queue_init(struct msm_device_queue *queue, const char *name)
 {
 	CPP_DBG("E\n");
@@ -135,6 +139,23 @@
 	{"cpp_bus_clk", -1},
 	{"micro_iface_clk", -1},
 };
+
+#define msm_cpp_empty_list(queue, member) { \
+	unsigned long flags; \
+	struct msm_queue_cmd *qcmd = NULL; \
+	if (queue) { \
+		spin_lock_irqsave(&queue->lock, flags); \
+		while (!list_empty(&queue->list)) { \
+			queue->len--; \
+			qcmd = list_first_entry(&queue->list, \
+				struct msm_queue_cmd, member); \
+			list_del_init(&qcmd->member); \
+			kfree(qcmd); \
+		} \
+		spin_unlock_irqrestore(&queue->lock, flags); \
+	} \
+}
+
 static int msm_cpp_notify_frame_done(struct cpp_device *cpp_dev);
 static void cpp_load_fw(struct cpp_device *cpp_dev, char *fw_name_bin);
 static void cpp_timer_callback(unsigned long data);
@@ -147,6 +168,14 @@
 	writel_relaxed((data), cpp_base + MSM_CPP_MICRO_FIFO_RX_DATA);
 }
 
+static void msm_cpp_clear_timer(struct cpp_device *cpp_dev)
+{
+	atomic_set(&cpp_timer.used, 0);
+	del_timer(&cpp_timer.cpp_timer);
+	cpp_timer.data.processed_frame = NULL;
+	cpp_dev->timeout_trial_cnt = 0;
+}
+
 static uint32_t msm_cpp_read(void __iomem *cpp_base)
 {
 	uint32_t tmp, retry = 0;
@@ -572,7 +601,6 @@
 	uint32_t tx_fifo[MSM_CPP_TX_FIFO_LEVEL];
 	struct cpp_device *cpp_dev = (struct cpp_device *) data;
 	struct msm_cpp_tasklet_queue_cmd *queue_cmd;
-	struct msm_cpp_timer_t *timer = NULL;
 
 	while (atomic_read(&cpp_dev->irq_cnt)) {
 		spin_lock_irqsave(&cpp_dev->tasklet_lock, flags);
@@ -601,19 +629,13 @@
 					CPP_DBG("Frame done!!\n");
 					/* delete CPP timer */
 					CPP_DBG("delete timer.\n");
-					timer = &cpp_timer;
-					atomic_set(&timer->used, 0);
-					del_timer(&timer->cpp_timer);
-					timer->data.processed_frame = NULL;
+					msm_cpp_clear_timer(cpp_dev);
 					msm_cpp_notify_frame_done(cpp_dev);
 				} else if (msg_id ==
 					MSM_CPP_MSG_ID_FRAME_NACK) {
 					pr_err("NACK error from hw!!\n");
 					CPP_DBG("delete timer.\n");
-					timer = &cpp_timer;
-					atomic_set(&timer->used, 0);
-					del_timer(&timer->cpp_timer);
-					timer->data.processed_frame = NULL;
+					msm_cpp_clear_timer(cpp_dev);
 					msm_cpp_notify_frame_done(cpp_dev);
 				}
 				i += cmd_len + 2;
@@ -622,6 +644,27 @@
 	}
 }
 
+static void cpp_get_clk_freq_tbl(struct clk *clk, struct cpp_hw_info *hw_info)
+{
+	uint32_t count;
+	signed long freq_tbl_entry = 0;
+
+	if ((clk == NULL) || (hw_info == NULL) || (clk->ops == NULL) ||
+		(clk->ops->list_rate == NULL)) {
+		pr_err("Bad parameter\n");
+		return;
+	}
+
+	for (count = 0; count < MAX_FREQ_TBL; count++) {
+		freq_tbl_entry = clk->ops->list_rate(clk, count);
+		if (freq_tbl_entry >= 0)
+			hw_info->freq_tbl[count] = freq_tbl_entry;
+		else
+			break;
+	}
+
+	hw_info->freq_tbl_count = count;
+}
 static int cpp_init_hardware(struct cpp_device *cpp_dev)
 {
 	int rc = 0;
@@ -630,7 +673,6 @@
 		pr_err("%s: Bandwidth registration Failed!\n", __func__);
 		goto bus_scale_register_failed;
 	}
-	msm_isp_update_bandwidth(ISP_CPP, 981345600, 1066680000);
 
 	if (cpp_dev->fs_cpp == NULL) {
 		cpp_dev->fs_cpp =
@@ -735,11 +777,15 @@
 	pr_debug("CPP HW Version: 0x%x\n", cpp_dev->hw_info.cpp_hw_version);
 	cpp_dev->hw_info.cpp_hw_caps =
 		msm_camera_io_r(cpp_dev->cpp_hw_base + 0x4);
+	cpp_get_clk_freq_tbl(cpp_dev->cpp_clk[MSM_CPP_CORE_CLK_IDX],
+		&cpp_dev->hw_info);
 	pr_debug("CPP HW Caps: 0x%x\n", cpp_dev->hw_info.cpp_hw_caps);
 	msm_camera_io_w(0x1, cpp_dev->vbif_base + 0x4);
 	cpp_dev->taskletq_idx = 0;
 	atomic_set(&cpp_dev->irq_cnt, 0);
 	msm_cpp_create_buff_queue(cpp_dev, MSM_CPP_MAX_BUFF_QUEUE);
+	pr_debug("stream_cnt:%d\n", cpp_dev->stream_cnt);
+	cpp_dev->stream_cnt = 0;
 	if (cpp_dev->is_firmware_loaded == 1) {
 		disable_irq(cpp_dev->irq->start);
 		cpp_load_fw(cpp_dev, cpp_dev->fw_name_bin);
@@ -763,7 +809,6 @@
 	regulator_disable(cpp_dev->fs_cpp);
 	regulator_put(cpp_dev->fs_cpp);
 fs_failed:
-	msm_isp_update_bandwidth(ISP_CPP, 0, 0);
 	msm_isp_deinit_bandwidth_mgr(ISP_CPP);
 bus_scale_register_failed:
 	return rc;
@@ -790,7 +835,11 @@
 	regulator_disable(cpp_dev->fs_cpp);
 	regulator_put(cpp_dev->fs_cpp);
 	cpp_dev->fs_cpp = NULL;
-	msm_isp_update_bandwidth(ISP_CPP, 0, 0);
+	if (cpp_dev->stream_cnt > 0) {
+		pr_debug("error: stream count active\n");
+		msm_isp_update_bandwidth(ISP_CPP, 0, 0);
+	}
+	cpp_dev->stream_cnt = 0;
 	msm_isp_deinit_bandwidth_mgr(ISP_CPP);
 }
 
@@ -919,9 +968,19 @@
 {
 	uint32_t i;
 	struct cpp_device *cpp_dev = v4l2_get_subdevdata(sd);
+	struct msm_device_queue *processing_q = NULL;
+	struct msm_device_queue *eventData_q = NULL;
+
+	if (!cpp_dev) {
+		pr_err("failed: cpp_dev %p\n", cpp_dev);
+		return -EINVAL;
+	}
 
 	mutex_lock(&cpp_dev->mutex);
 
+	processing_q = &cpp_dev->processing_q;
+	eventData_q = &cpp_dev->eventData_q;
+
 	if (cpp_dev->cpp_open_cnt == 0) {
 		mutex_unlock(&cpp_dev->mutex);
 		return 0;
@@ -973,9 +1032,12 @@
 		pr_debug("DEBUG_R1: 0x%x\n",
 			msm_camera_io_r(cpp_dev->cpp_hw_base + 0x8C));
 		msm_camera_io_w(0x0, cpp_dev->base + MSM_CPP_MICRO_CLKEN_CTL);
+		msm_cpp_clear_timer(cpp_dev);
 		cpp_deinit_mem(cpp_dev);
 		iommu_detach_device(cpp_dev->domain, cpp_dev->iommu_ctx);
 		cpp_release_hardware(cpp_dev);
+		msm_cpp_empty_list(processing_q, list_frame);
+		msm_cpp_empty_list(eventData_q, list_eventdata);
 		cpp_dev->state = CPP_STATE_OFF;
 	}
 
@@ -1005,7 +1067,7 @@
 	struct v4l2_event v4l2_evt;
 	struct msm_queue_cmd *frame_qcmd = NULL;
 	struct msm_queue_cmd *event_qcmd = NULL;
-	struct msm_cpp_frame_info_t *processed_frame;
+	struct msm_cpp_frame_info_t *processed_frame = NULL;
 	struct msm_device_queue *queue = &cpp_dev->processing_q;
 	struct msm_buf_mngr_info buff_mgr_info;
 	int rc = 0;
@@ -1097,8 +1159,9 @@
 
 	pr_err("cpp_timer_callback called. (jiffies=%lu)\n",
 		jiffies);
-	if (!work) {
-		pr_err("Invalid work:%p\n", work);
+	if (!work || cpp_timer.data.cpp_dev->state != CPP_STATE_ACTIVE) {
+		pr_err("Invalid work:%p or state:%d\n", work,
+			cpp_timer.data.cpp_dev->state);
 		return;
 	}
 	if (!atomic_read(&cpp_timer.used)) {
@@ -1122,6 +1185,14 @@
 		return;
 	}
 
+	if (cpp_timer.data.cpp_dev->timeout_trial_cnt >=
+		MSM_CPP_MAX_TIMEOUT_TRIAL) {
+		pr_info("Max trial reached\n");
+		msm_cpp_notify_frame_done(cpp_timer.data.cpp_dev);
+		cpp_timer.data.cpp_dev->timeout_trial_cnt = 0;
+		return;
+	}
+
 	this_frame = cpp_timer.data.processed_frame;
 	pr_err("Starting timer to fire in %d ms. (jiffies=%lu)\n",
 		CPP_CMD_TIMEOUT_MS, jiffies);
@@ -1138,6 +1209,7 @@
 	for (i = 0; i < this_frame->msg_len; i++)
 		msm_cpp_write(this_frame->cpp_cmd_msg[i],
 			cpp_timer.data.cpp_dev->base);
+	cpp_timer.data.cpp_dev->timeout_trial_cnt++;
 	return;
 }
 
@@ -1394,6 +1466,26 @@
 	return rc;
 }
 
+void msm_cpp_clean_queue(struct cpp_device *cpp_dev)
+{
+	struct msm_queue_cmd *frame_qcmd = NULL;
+	struct msm_cpp_frame_info_t *processed_frame = NULL;
+	struct msm_device_queue *queue = NULL;
+
+	while (cpp_dev->processing_q.len) {
+		pr_info("queue len:%d\n", cpp_dev->processing_q.len);
+		queue = &cpp_dev->processing_q;
+		frame_qcmd = msm_dequeue(queue, list_frame);
+		if (frame_qcmd) {
+			processed_frame = frame_qcmd->command;
+			kfree(frame_qcmd);
+			if (processed_frame)
+				kfree(processed_frame->cpp_cmd_msg);
+			kfree(processed_frame);
+		}
+	}
+}
+
 long msm_cpp_subdev_ioctl(struct v4l2_subdev *sd,
 			unsigned int cmd, void *arg)
 {
@@ -1551,6 +1643,23 @@
 
 		kfree(k_stream_buff_info.buffer_info);
 		kfree(u_stream_buff_info);
+		if (cpp_dev->stream_cnt == 0) {
+			rc = msm_isp_update_bandwidth(ISP_CPP, 981345600,
+				1066680000);
+			if (rc < 0) {
+				pr_err("Bandwidth Set Failed!\n");
+				msm_isp_update_bandwidth(ISP_CPP, 0, 0);
+				mutex_unlock(&cpp_dev->mutex);
+				return -EINVAL;
+			}
+			cpp_dev->state = CPP_STATE_ACTIVE;
+			msm_cpp_clear_timer(cpp_dev);
+			msm_cpp_clean_queue(cpp_dev);
+		}
+		if (cmd != VIDIOC_MSM_CPP_APPEND_STREAM_BUFF_INFO) {
+			cpp_dev->stream_cnt++;
+			pr_debug("stream_cnt:%d\n", cpp_dev->stream_cnt);
+		}
 		break;
 	}
 	case VIDIOC_MSM_CPP_DEQUEUE_STREAM_BUFF_INFO: {
@@ -1558,7 +1667,7 @@
 		struct msm_cpp_buff_queue_info_t *buff_queue_info;
 
 		if ((ioctl_ptr->len == 0) ||
-		    (ioctl_ptr->len > sizeof(uint32_t)))
+			(ioctl_ptr->len > sizeof(uint32_t)))
 			return -EINVAL;
 
 		rc = (copy_from_user(&identity,
@@ -1583,6 +1692,21 @@
 		rc = msm_cpp_free_buff_queue_entry(cpp_dev,
 			buff_queue_info->session_id,
 			buff_queue_info->stream_id);
+		if (cpp_dev->stream_cnt > 0) {
+			cpp_dev->stream_cnt--;
+			pr_debug("stream_cnt:%d\n", cpp_dev->stream_cnt);
+			if (cpp_dev->stream_cnt == 0) {
+				rc = msm_isp_update_bandwidth(ISP_CPP, 0, 0);
+				if (rc < 0)
+					pr_err("Bandwidth Reset Failed!\n");
+				cpp_dev->state = CPP_STATE_IDLE;
+				msm_cpp_clear_timer(cpp_dev);
+				msm_cpp_clean_queue(cpp_dev);
+			}
+		} else {
+			pr_err("error: stream count underflow %d\n",
+				cpp_dev->stream_cnt);
+		}
 		break;
 	}
 	case VIDIOC_MSM_CPP_GET_EVENTPAYLOAD: {
@@ -1610,7 +1734,9 @@
 		break;
 	}
 	case VIDIOC_MSM_CPP_SET_CLOCK: {
-		long clock_rate = 0;
+		struct msm_cpp_clock_settings_t clock_settings;
+		unsigned long clock_rate = 0;
+		CPP_DBG("VIDIOC_MSM_CPP_SET_CLOCK\n");
 		if (ioctl_ptr->len == 0) {
 			pr_err("ioctl_ptr->len is 0\n");
 			mutex_unlock(&cpp_dev->mutex);
@@ -1623,13 +1749,13 @@
 			return -EINVAL;
 		}
 
-		if (ioctl_ptr->len > sizeof(clock_rate)) {
+		if (ioctl_ptr->len != sizeof(struct msm_cpp_clock_settings_t)) {
 			pr_err("Not valid ioctl_ptr->len\n");
 			mutex_unlock(&cpp_dev->mutex);
 			return -EINVAL;
 		}
 
-		rc = (copy_from_user(&clock_rate,
+		rc = (copy_from_user(&clock_settings,
 			(void __user *)ioctl_ptr->ioctl_ptr,
 			ioctl_ptr->len) ? -EFAULT : 0);
 		if (rc) {
@@ -1638,27 +1764,37 @@
 			return -EINVAL;
 		}
 
-		if (clock_rate > 0) {
-			clock_rate =
-				clk_round_rate(cpp_dev->cpp_clk[4], clock_rate);
-			CPP_DBG("clk:%ld\n", clock_rate);
-			clk_set_rate(cpp_dev->cpp_clk[4], clock_rate);
-			rc = msm_isp_update_bandwidth(ISP_CPP, clock_rate * 4,
-				clock_rate * 6);
+		if (clock_settings.clock_rate > 0) {
+			rc = msm_isp_update_bandwidth(ISP_CPP,
+				clock_settings.avg,
+				clock_settings.inst);
 			if (rc < 0) {
 				pr_err("Bandwidth Set Failed!\n");
 				msm_isp_update_bandwidth(ISP_CPP, 0, 0);
 				mutex_unlock(&cpp_dev->mutex);
 				return -EINVAL;
 			}
+			clock_rate = clk_round_rate(
+				cpp_dev->cpp_clk[MSM_CPP_CORE_CLK_IDX],
+				clock_settings.clock_rate);
+			if (clock_rate != clock_settings.clock_rate)
+				pr_err("clock rate differ from settings\n");
+			clk_set_rate(cpp_dev->cpp_clk[MSM_CPP_CORE_CLK_IDX],
+				clock_rate);
 		}
-
 		break;
 	}
 	case MSM_SD_SHUTDOWN: {
 		mutex_unlock(&cpp_dev->mutex);
+		pr_info("shutdown cpp node. open cnt:%d\n",
+			cpp_dev->cpp_open_cnt);
+
+		if (atomic_read(&cpp_timer.used))
+			pr_info("Timer state not cleared\n");
+
 		while (cpp_dev->cpp_open_cnt != 0)
 			cpp_close_node(sd, NULL);
+		mutex_lock(&cpp_dev->mutex);
 		rc = 0;
 		break;
 	}
diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h
index cf22e6c..bd73ab2 100644
--- a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h
+++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h
@@ -161,6 +161,13 @@
 	struct cpp_device *cpp_dev;
 };
 
+struct msm_cpp_clock_settings_t {
+	long clock_rate;
+	uint64_t avg;
+	uint64_t inst;
+};
+
+
 struct cpp_device {
 	struct platform_device *pdev;
 	struct msm_sd_subdev msm_sd;
@@ -182,6 +189,8 @@
 	char *fw_name_bin;
 	struct workqueue_struct *timer_wq;
 	struct msm_cpp_work_t *work;
+	uint8_t stream_cnt;
+	uint8_t timeout_trial_cnt;
 
 	int domain_num;
 	struct iommu_domain *domain;
diff --git a/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c b/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c
index 50f37db..cce6525 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c
@@ -27,6 +27,10 @@
 #define CDBG(fmt, args...) pr_debug(fmt, ##args)
 #endif
 
+
+static int32_t msm_actuator_power_up(struct msm_actuator_ctrl_t *a_ctrl);
+static int32_t msm_actuator_power_down(struct msm_actuator_ctrl_t *a_ctrl);
+
 static struct msm_actuator msm_vcm_actuator_table;
 static struct msm_actuator msm_piezo_actuator_table;
 
@@ -447,6 +451,31 @@
 	return rc;
 }
 
+static int32_t msm_actuator_vreg_control(struct msm_actuator_ctrl_t *a_ctrl,
+							int config)
+{
+	int rc = 0, i, cnt;
+	struct msm_actuator_vreg *vreg_cfg;
+
+	vreg_cfg = &a_ctrl->vreg_cfg;
+	cnt = vreg_cfg->num_vreg;
+	if (!cnt)
+		return 0;
+
+	if (cnt >= MSM_ACTUATOT_MAX_VREGS) {
+		pr_err("%s failed %d cnt %d\n", __func__, __LINE__, cnt);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < cnt; i++) {
+		rc = msm_camera_config_single_vreg(&(a_ctrl->pdev->dev),
+			&vreg_cfg->cam_vreg[i],
+			(struct regulator **)&vreg_cfg->data[i],
+			config);
+	}
+	return rc;
+}
+
 static int32_t msm_actuator_power_down(struct msm_actuator_ctrl_t *a_ctrl)
 {
 	int32_t rc = 0;
@@ -456,6 +485,11 @@
 		if (!rc)
 			gpio_free(a_ctrl->vcm_pwd);
 	}
+	rc = msm_actuator_vreg_control(a_ctrl, 0);
+	if (rc < 0) {
+		pr_err("%s failed %d\n", __func__, __LINE__);
+		return rc;
+	}
 
 	kfree(a_ctrl->step_position_table);
 	a_ctrl->step_position_table = NULL;
@@ -671,6 +705,13 @@
 		if (rc < 0)
 			pr_err("actuator_set_position failed %d\n", rc);
 		break;
+
+	case CFG_ACTUATOR_POWERUP:
+		rc = msm_actuator_power_up(a_ctrl);
+		if (rc < 0)
+			pr_err("Failed actuator power up%d\n", rc);
+		break;
+
 	default:
 		break;
 	}
@@ -794,6 +835,13 @@
 
 	CDBG("vcm info: %x %x\n", a_ctrl->vcm_pwd,
 		a_ctrl->vcm_enable);
+
+	rc = msm_actuator_vreg_control(a_ctrl, 1);
+	if (rc < 0) {
+		pr_err("%s failed %d\n", __func__, __LINE__);
+		return rc;
+	}
+
 	if (a_ctrl->vcm_enable) {
 		rc = gpio_request(a_ctrl->vcm_pwd, "msm_actuator");
 		if (!rc) {
@@ -909,6 +957,7 @@
 	int32_t rc = 0;
 	struct msm_camera_cci_client *cci_client = NULL;
 	struct msm_actuator_ctrl_t *msm_actuator_t = NULL;
+	struct msm_actuator_vreg *vreg_cfg;
 	CDBG("Enter\n");
 
 	if (!pdev->dev.of_node) {
@@ -940,6 +989,18 @@
 		return rc;
 	}
 
+	if (of_find_property((&pdev->dev)->of_node,
+			"qcom,cam-vreg-name", NULL)) {
+		vreg_cfg = &msm_actuator_t->vreg_cfg;
+		rc = msm_camera_get_dt_vreg_data((&pdev->dev)->of_node,
+			&vreg_cfg->cam_vreg, &vreg_cfg->num_vreg);
+		if (rc < 0) {
+			kfree(msm_actuator_t);
+			pr_err("failed rc %d\n", rc);
+			return rc;
+		}
+	}
+
 	msm_actuator_t->act_v4l2_subdev_ops = &msm_actuator_subdev_ops;
 	msm_actuator_t->actuator_mutex = &msm_actuator_mutex;
 	msm_actuator_t->cam_name = pdev->id;
@@ -952,6 +1013,7 @@
 	msm_actuator_t->i2c_client.cci_client = kzalloc(sizeof(
 		struct msm_camera_cci_client), GFP_KERNEL);
 	if (!msm_actuator_t->i2c_client.cci_client) {
+		kfree(msm_actuator_t->vreg_cfg.cam_vreg);
 		kfree(msm_actuator_t);
 		pr_err("failed no memory\n");
 		return -ENOMEM;
diff --git a/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.h b/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.h
index 772b12e..b0d9430 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.h
+++ b/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.h
@@ -18,10 +18,15 @@
 #include <media/v4l2-subdev.h>
 #include <media/msmb_camera.h>
 #include "msm_camera_i2c.h"
+#include "msm_camera_dt_util.h"
+#include "msm_camera_io_util.h"
+
 
 #define DEFINE_MSM_MUTEX(mutexname) \
 	static struct mutex mutexname = __MUTEX_INITIALIZER(mutexname)
 
+#define	MSM_ACTUATOT_MAX_VREGS (10)
+
 struct msm_actuator_ctrl_t;
 
 struct msm_actuator_func_tbl {
@@ -52,6 +57,12 @@
 	struct msm_actuator_func_tbl func_tbl;
 };
 
+struct msm_actuator_vreg {
+	struct camera_vreg_t *cam_vreg;
+	void *data[MSM_ACTUATOT_MAX_VREGS];
+	int num_vreg;
+};
+
 struct msm_actuator_ctrl_t {
 	struct i2c_driver *i2c_driver;
 	struct platform_driver *pdriver;
@@ -83,6 +94,7 @@
 	uint16_t i2c_tbl_index;
 	enum cci_i2c_master_t cci_master;
 	uint32_t subdev_id;
+	struct msm_actuator_vreg vreg_cfg;
 };
 
 #endif
diff --git a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_init.c b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_init.c
index bc96eb8..c50a623 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_init.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_init.c
@@ -48,21 +48,19 @@
 static int msm_sensor_wait_for_probe_done(struct msm_sensor_init_t *s_init)
 {
 	int rc;
-
+	int tm = 10000;
 	if (s_init->module_init_status == 1) {
 		pr_err("msm_cam_get_module_init_status -2\n");
 		return 0;
 	}
+	rc = wait_event_interruptible_timeout(s_init->state_wait,
+		(s_init->module_init_status == 1), msecs_to_jiffies(tm));
+	if (rc < 0)
+		pr_err("%s:%d wait failed\n", __func__, __LINE__);
+	else if (rc == 0)
+		pr_err("%s:%d wait timeout\n", __func__, __LINE__);
 
-	while (1) {
-		rc = wait_event_interruptible(s_init->state_wait,
-			(s_init->module_init_status == 1));
-		if (rc == -ETIMEDOUT)
-			continue;
-		else if (rc == 0)
-			break;
-	}
-	return 0;
+	return rc;
 }
 
 /* Static function definition */
diff --git a/drivers/media/platform/msm/vidc/hfi_response_handler.c b/drivers/media/platform/msm/vidc/hfi_response_handler.c
index c6fb382..0eee530 100644
--- a/drivers/media/platform/msm/vidc/hfi_response_handler.c
+++ b/drivers/media/platform/msm/vidc/hfi_response_handler.c
@@ -221,6 +221,7 @@
 	case HFI_ERR_SESSION_INVALID_SCALE_FACTOR:
 	case HFI_ERR_SESSION_UNSUPPORT_BUFFERTYPE:
 	case HFI_ERR_SESSION_UNSUPPORTED_SETTING:
+	case HFI_ERR_SESSION_UPSCALE_NOT_SUPPORTED:
 		dprintk(VIDC_INFO, "Non Fatal : HFI_EVENT_SESSION_ERROR\n");
 		break;
 	default:
diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c
index 810357e..bcd13b8 100644
--- a/drivers/media/platform/msm/vidc/msm_venc.c
+++ b/drivers/media/platform/msm/vidc/msm_venc.c
@@ -157,7 +157,7 @@
 		.name = "IDR Period",
 		.type = V4L2_CTRL_TYPE_INTEGER,
 		.minimum = 1,
-		.maximum = 10*MAX_FRAME_RATE,
+		.maximum = INT_MAX,
 		.default_value = DEFAULT_FRAME_RATE,
 		.step = 1,
 		.menu_skip_mask = 0,
@@ -168,7 +168,7 @@
 		.name = "Intra Period",
 		.type = V4L2_CTRL_TYPE_INTEGER,
 		.minimum = 1,
-		.maximum = 10*MAX_FRAME_RATE,
+		.maximum = INT_MAX,
 		.default_value = DEFAULT_FRAME_RATE,
 		.step = 1,
 		.menu_skip_mask = 0,
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index 7429466..071f698 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -2148,7 +2148,7 @@
 	int rc = 0;
 	struct msm_smem *handle;
 	struct internal_buf *binfo;
-	struct vidc_buffer_addr_info buffer_info;
+	struct vidc_buffer_addr_info buffer_info = {0};
 	u32 smem_flags = 0, buffer_size;
 	struct hal_buffer_requirements *output_buf, *extradata_buf;
 	int i;
@@ -2168,19 +2168,21 @@
 		output_buf->buffer_count_actual,
 		output_buf->buffer_size);
 
+	buffer_size = output_buf->buffer_size;
+
 	extradata_buf = get_buff_req_buffer(inst, HAL_BUFFER_EXTRADATA_OUTPUT);
-	if (!extradata_buf) {
+	if (extradata_buf) {
+		dprintk(VIDC_DBG,
+			"extradata: num = %d, size = %d\n",
+			extradata_buf->buffer_count_actual,
+			extradata_buf->buffer_size);
+		buffer_size += extradata_buf->buffer_size;
+	} else {
 		dprintk(VIDC_DBG,
 			"This extradata buffer not required, buffer_type: %x\n",
 			buffer_type);
-		return 0;
 	}
-	dprintk(VIDC_DBG,
-		"extradata: num = %d, size = %d\n",
-		extradata_buf->buffer_count_actual,
-		extradata_buf->buffer_size);
 
-	buffer_size = output_buf->buffer_size + extradata_buf->buffer_size;
 	if (inst->flags & VIDC_SECURE)
 		smem_flags |= SMEM_SECURE;
 
@@ -2218,7 +2220,10 @@
 			buffer_info.align_device_addr = handle->device_addr;
 			buffer_info.extradata_addr = handle->device_addr +
 				output_buf->buffer_size;
-			buffer_info.extradata_size = extradata_buf->buffer_size;
+			if (extradata_buf) {
+				buffer_info.extradata_size =
+					extradata_buf->buffer_size;
+			}
 			dprintk(VIDC_DBG, "Output buffer address: %x",
 					buffer_info.align_device_addr);
 			dprintk(VIDC_DBG, "Output extradata address: %x",
@@ -3462,20 +3467,14 @@
 				capability->height.min);
 			rc = -ENOTSUPP;
 		}
-		if (msm_vp8_low_tier &&
-			inst->fmts[OUTPUT_PORT]->fourcc == V4L2_PIX_FMT_VP8) {
-			capability->width.max = DEFAULT_WIDTH;
-			capability->width.max = DEFAULT_HEIGHT;
-		}
-		if (!rc && (inst->prop.width[CAPTURE_PORT] >
-			capability->width.max)) {
-			dprintk(VIDC_ERR,
-				"Unsupported width = %u supported max width = %u\n",
-				inst->prop.width[CAPTURE_PORT],
-				capability->width.max);
-				rc = -ENOTSUPP;
-		}
 
+		if (!rc) {
+			rc = call_hfi_op(hdev, capability_check,
+					inst->fmts[OUTPUT_PORT]->fourcc,
+					inst->prop.width[CAPTURE_PORT],
+					&capability->width.max,
+					&capability->height.max);
+		}
 		if (!rc && (inst->prop.height[CAPTURE_PORT]
 			* inst->prop.width[CAPTURE_PORT] >
 			capability->width.max * capability->height.max)) {
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_debug.c b/drivers/media/platform/msm/vidc/msm_vidc_debug.c
index 5a18265..475683c 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_debug.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_debug.c
@@ -255,8 +255,8 @@
 		inst->session_type == MSM_VIDC_ENCODER ? "Encoder" : "Decoder");
 	write_str(&dbg_buf, "===============================\n");
 	write_str(&dbg_buf, "core: 0x%p\n", inst->core);
-	write_str(&dbg_buf, "height: %d\n", inst->prop.height);
-	write_str(&dbg_buf, "width: %d\n", inst->prop.width);
+	write_str(&dbg_buf, "height: %d\n", inst->prop.height[CAPTURE_PORT]);
+	write_str(&dbg_buf, "width: %d\n", inst->prop.width[CAPTURE_PORT]);
 	write_str(&dbg_buf, "fps: %d\n", inst->prop.fps);
 	write_str(&dbg_buf, "state: %d\n", inst->state);
 	write_str(&dbg_buf, "-----------Formats-------------\n");
diff --git a/drivers/media/platform/msm/vidc/q6_hfi.c b/drivers/media/platform/msm/vidc/q6_hfi.c
index 486d740..bbba29a 100644
--- a/drivers/media/platform/msm/vidc/q6_hfi.c
+++ b/drivers/media/platform/msm/vidc/q6_hfi.c
@@ -1318,6 +1318,24 @@
 	return rc;
 }
 
+int q6_hfi_capability_check(u32 fourcc, u32 width,
+				u32 *max_width, u32 *max_height)
+{
+	int rc = 0;
+	if (!max_width || !max_height) {
+		dprintk(VIDC_ERR, "%s - invalid parameter\n", __func__);
+		return -EINVAL;
+	}
+
+	if (width > *max_width) {
+		dprintk(VIDC_ERR,
+			"Unsupported width = %u supported max width = %u\n",
+			width, *max_width);
+		rc = -ENOTSUPP;
+	}
+	return rc;
+}
+
 static void q6_hfi_unload_fw(void *hfi_device_data)
 {
 	struct q6_hfi_device *device = hfi_device_data;
@@ -1372,6 +1390,7 @@
 	hdev->unset_ocmem = q6_hfi_unset_ocmem;
 	hdev->iommu_get_domain_partition = q6_hfi_iommu_get_domain_partition;
 	hdev->load_fw = q6_hfi_load_fw;
+	hdev->capability_check = q6_hfi_capability_check;
 	hdev->unload_fw = q6_hfi_unload_fw;
 	hdev->get_stride_scanline = q6_hfi_get_stride_scanline;
 }
diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c
index 448fe3b..30ee45d 100644
--- a/drivers/media/platform/msm/vidc/venus_hfi.c
+++ b/drivers/media/platform/msm/vidc/venus_hfi.c
@@ -3747,6 +3747,29 @@
 	return rc;
 }
 
+int venus_hfi_capability_check(u32 fourcc, u32 width,
+				u32 *max_width, u32 *max_height)
+{
+	int rc = 0;
+	if (!max_width || !max_height) {
+		dprintk(VIDC_ERR, "%s - invalid parameter\n", __func__);
+		return -EINVAL;
+	}
+
+	if (msm_vp8_low_tier && fourcc == V4L2_PIX_FMT_VP8) {
+		*max_width = DEFAULT_WIDTH;
+		*max_height = DEFAULT_HEIGHT;
+	}
+
+	if (width > *max_width) {
+		dprintk(VIDC_ERR,
+			"Unsupported width = %u supported max width = %u\n",
+			width, *max_width);
+		rc = -ENOTSUPP;
+	}
+	return rc;
+}
+
 static void *venus_hfi_add_device(u32 device_id,
 			struct msm_vidc_platform_resources *res,
 			hfi_cmd_response_callback callback)
@@ -3909,6 +3932,7 @@
 	hdev->get_info = venus_hfi_get_info;
 	hdev->get_stride_scanline = venus_hfi_get_stride_scanline;
 	hdev->get_core_capabilities = venus_hfi_get_core_capabilities;
+	hdev->capability_check = venus_hfi_capability_check;
 	hdev->power_enable = venus_hfi_power_enable;
 }
 
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_api.h b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
index 38c5bdb..62507a1 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_api.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
@@ -1168,6 +1168,8 @@
 	int (*get_info) (void *dev, enum dev_info info);
 	int (*get_stride_scanline)(int color_fmt, int width,
 		int height,	int *stride, int *scanlines);
+	int (*capability_check)(u32 fourcc, u32 width,
+			u32 *max_width, u32 *max_height);
 	int (*session_clean)(void *sess);
 	int (*get_core_capabilities)(void);
 	int (*power_enable)(void *dev);
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
index 7c62e77..b3c20b6 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
@@ -70,6 +70,7 @@
 #define HFI_ERR_SESSION_UNSUPPORT_BUFFERTYPE	(HFI_COMMON_BASE + 0x1010)
 #define HFI_ERR_SESSION_BUFFERCOUNT_TOOSMALL	(HFI_COMMON_BASE + 0x1011)
 #define HFI_ERR_SESSION_INVALID_SCALE_FACTOR	(HFI_COMMON_BASE + 0x1012)
+#define HFI_ERR_SESSION_UPSCALE_NOT_SUPPORTED	(HFI_COMMON_BASE + 0x1013)
 
 #define HFI_EVENT_SYS_ERROR				(HFI_COMMON_BASE + 0x1)
 #define HFI_EVENT_SESSION_ERROR			(HFI_COMMON_BASE + 0x2)
diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c
index 05264b4..d06ec85 100644
--- a/drivers/net/wireless/wcnss/wcnss_wlan.c
+++ b/drivers/net/wireless/wcnss/wcnss_wlan.c
@@ -203,6 +203,7 @@
 #define	WCNSS_VBATT_LEVEL_IND         (WCNSS_CTRL_MSG_START + 8)
 #define	WCNSS_BUILD_VER_REQ           (WCNSS_CTRL_MSG_START + 9)
 #define	WCNSS_BUILD_VER_RSP           (WCNSS_CTRL_MSG_START + 10)
+#define	WCNSS_PM_CONFIG_REQ           (WCNSS_CTRL_MSG_START + 11)
 
 /* max 20mhz channel count */
 #define WCNSS_MAX_CH_NUM			45
@@ -377,6 +378,7 @@
 	struct delayed_work wcnss_work;
 	struct delayed_work vbatt_work;
 	struct work_struct wcnssctrl_version_work;
+	struct work_struct wcnss_pm_config_work;
 	struct work_struct wcnssctrl_nvbin_dnld_work;
 	struct work_struct wcnssctrl_rx_work;
 	struct wake_lock wcnss_wake_lock;
@@ -945,6 +947,7 @@
 		pr_debug("wcnss: opening WCNSS SMD channel :%s",
 				WCNSS_CTRL_CHANNEL);
 		schedule_work(&penv->wcnssctrl_version_work);
+		schedule_work(&penv->wcnss_pm_config_work);
 
 		break;
 
@@ -1800,6 +1803,52 @@
 	return;
 }
 
+static void wcnss_send_pm_config(struct work_struct *worker)
+{
+	struct smd_msg_hdr *hdr;
+	unsigned char *msg = NULL;
+	int rc, prop_len;
+	u32 *payload;
+
+	if (!of_find_property(penv->pdev->dev.of_node,
+				"qcom,wcnss-pm", &prop_len))
+		return;
+
+	msg = kmalloc((sizeof(struct smd_msg_hdr) + prop_len), GFP_KERNEL);
+
+	if (NULL == msg) {
+		pr_err("wcnss: %s: failed to allocate memory\n", __func__);
+		return;
+	}
+
+	payload = (u32 *)(msg + sizeof(struct smd_msg_hdr));
+
+	prop_len /= sizeof(int);
+
+	rc = of_property_read_u32_array(penv->pdev->dev.of_node,
+			"qcom,wcnss-pm", payload, prop_len);
+	if (rc < 0) {
+		pr_err("wcnss: property read failed\n");
+		kfree(msg);
+		return;
+	}
+
+	pr_debug("%s:size=%d: <%d, %d, %d, %d, %d>\n", __func__,
+			prop_len, *payload, *(payload+1), *(payload+2),
+			*(payload+3), *(payload+4));
+
+	hdr = (struct smd_msg_hdr *)msg;
+	hdr->msg_type = WCNSS_PM_CONFIG_REQ;
+	hdr->msg_len = sizeof(struct smd_msg_hdr) + prop_len;
+
+	rc = wcnss_smd_tx(msg, hdr->msg_len);
+	if (rc < 0)
+		pr_err("wcnss: smd tx failed\n");
+
+	kfree(msg);
+	return;
+}
+
 static DECLARE_RWSEM(wcnss_pm_sem);
 
 static void wcnss_nvbin_dnld(void)
@@ -2234,6 +2283,7 @@
 	}
 	INIT_WORK(&penv->wcnssctrl_rx_work, wcnssctrl_rx_handler);
 	INIT_WORK(&penv->wcnssctrl_version_work, wcnss_send_version_req);
+	INIT_WORK(&penv->wcnss_pm_config_work, wcnss_send_pm_config);
 	INIT_WORK(&penv->wcnssctrl_nvbin_dnld_work, wcnss_nvbin_dnld_main);
 
 	wake_lock_init(&penv->wcnss_wake_lock, WAKE_LOCK_SUSPEND, "wcnss");
diff --git a/drivers/platform/msm/Kconfig b/drivers/platform/msm/Kconfig
index 88e8d43..11b064a 100644
--- a/drivers/platform/msm/Kconfig
+++ b/drivers/platform/msm/Kconfig
@@ -120,6 +120,16 @@
 		This driver gets the Q6 out of power collapsed state and
 		exposes ioctl control to read avtimer tick.
 
+config PFT
+	bool "Per-File-Tagger driver"
+	default n
+	help
+		This driver is used for tagging enterprise files.
+		It is part of the Per-File-Encryption (PFE) feature.
+		The driver is tagging files when created by
+		registered application.
+		Tagged files are encrypted using the dm-req-crypt driver.
+
 config SSM
 	tristate "Qualcomm Secure Service Module"
 	depends on QSEECOM
diff --git a/drivers/platform/msm/Makefile b/drivers/platform/msm/Makefile
index e6493b1..e2be59d 100644
--- a/drivers/platform/msm/Makefile
+++ b/drivers/platform/msm/Makefile
@@ -3,7 +3,7 @@
 #
 
 ccflags-y += -Idrivers/misc/
-
+ccflags-y += -Isecurity/selinux -Isecurity/selinux/include
 
 obj-$(CONFIG_MSM_SSBI) += ssbi.o
 obj-$(CONFIG_USB_BAM) += usb_bam.o
@@ -16,4 +16,5 @@
 obj-$(CONFIG_QPNP_COINCELL) += qpnp-coincell.o
 obj-$(CONFIG_MSM_AVTIMER) += avtimer.o
 obj-$(CONFIG_SSM) += ssm.o
+obj-$(CONFIG_PFT) += pft.o
 obj-$(CONFIG_QPNP_REVID) += qpnp-revid.o
diff --git a/drivers/platform/msm/pft.c b/drivers/platform/msm/pft.c
new file mode 100644
index 0000000..20e7249
--- /dev/null
+++ b/drivers/platform/msm/pft.c
@@ -0,0 +1,1821 @@
+/*
+ * Copyright (c) 2014, 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
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/*
+ * Per-File-Tagger (PFT).
+ *
+ * This driver tags enterprise file for encryption/decryption,
+ * as part of the Per-File-Encryption (PFE) feature.
+ *
+ * Enterprise registered applications are identified by their UID.
+ *
+ * The PFT exposes character-device interface to the user-space application,
+ * to handle the following commands:
+ * 1. Update registered applications list
+ * 2. Encryption (in-place) of a file that was created before.
+ * 3. Set State - update the state.
+ *
+ * The PFT exposes kernel API hooks that are intercepting file operations
+ * like create/open/read/write for tagging files and also for access control.
+ * It utilizes the existing security framework hooks
+ * that calls the selinux hooks.
+ *
+ * The PFT exposes kernel API to the dm-req-crypt driver to provide the info
+ * if a file is tagged or not. The dm-req-crypt driver is doing the
+ * actual encryption/decryptiom.
+ *
+ * Tagging the file:
+ * 1. Non-volatile tagging on storage using file extra-attribute (xattr).
+ * 2. Volatile tagging on the file's inode, for fast access.
+ *
+ */
+
+/* Uncomment the line below to enable debug messages */
+/* #define DEBUG 1 */
+
+#define pr_fmt(fmt)	"pft [%s]: " fmt, __func__
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/cdev.h>
+#include <linux/sched.h>
+#include <linux/uaccess.h>
+#include <linux/cred.h>
+#include <linux/list.h>
+#include <linux/errno.h>
+#include <linux/printk.h>
+#include <linux/blkdev.h>
+#include <linux/elevator.h>
+#include <linux/bio.h>
+#include <linux/bitops.h>
+#include <linux/fdtable.h>
+#include <linux/selinux.h>
+
+#include <linux/pft.h>
+#include <linux/msm_pft.h>
+
+#include "objsec.h"
+
+/* File tagging as encrypted/non-encrypted is valid */
+#define PFT_TAG_MAGIC		((u32)(0xABC00000))
+
+/* File tagged as encrypted */
+#define PFT_TAG_ENCRYPTED	BIT(16)
+
+#define PFT_TAG_MAGIC_MASK	0xFFF00000
+#define PFT_TAG_FLAGS_MASK	0x000F0000
+#define PFT_TAG_KEY_MASK	0x0000FFFF
+
+/* The defualt encryption key index */
+#define PFT_DEFAULT_KEY_INDEX	1
+
+/* The defualt key index for non-encrypted files */
+#define PFT_NO_KEY		0
+
+/* PFT extended attribute name */
+#define XATTR_NAME_PFE "security.pfe"
+
+/* PFT driver requested major number */
+#define PFT_REQUESTED_MAJOR	213
+
+/* PFT driver name */
+#define DEVICE_NAME	"pft"
+
+/* Maximum registered applications */
+#define PFT_MAX_APPS	1000
+
+/* Maximum command size */
+#define PFT_MAX_COMMAND_SIZE (PAGE_SIZE)
+
+/* Current Process ID */
+#define current_pid() ((u32)(current->pid))
+
+static const char *pft_state_name[PFT_STATE_MAX_INDEX] = {
+	"deactivated",
+	"deactivating",
+	"key_removed",
+	"removing_key",
+	"key_loaded",
+};
+
+/**
+ * struct pft_file_info - pft file node info.
+ * @file:	pointer to file stucture.
+ * @pid:	process ID.
+ * @list:	next list item.
+ *
+ * A node in the list of the current open encrypted files.
+ */
+struct pft_file_info {
+	struct file *file;
+	pid_t pid;
+	struct list_head list;
+};
+
+/**
+ * struct pft_device - device state structure.
+ *
+ * @open_count:	device open count.
+ * @major:	device major number.
+ * @state:	Per-File-Encryption state.
+ * @response:	command response.
+ * @pfm_pid:	PFM process id.
+ * @inplace_file:	file for in-place encryption.
+ * @uid_table:	registered application array (UID).
+ * @uid_count:	number of registered applications.
+ * @open_file_list:	open encrypted file list.
+ * @lock:	lock protect list access.
+ *
+ * The open_count purpose is to ensure that only one user space
+ * application uses this driver.
+ * The open_file_list is used to close open encrypted files
+ * after the key is removed from the encryption hardware.
+ */
+struct pft_device {
+	struct cdev cdev;
+	dev_t device_no;
+	struct class *driver_class;
+	int open_count;
+	int major;
+	enum pft_state state;
+	struct pft_command_response response;
+	u32 pfm_pid;
+	struct file *inplace_file;
+	u32 *uid_table;
+	u32 uid_count;
+	struct list_head open_file_list;
+	struct mutex lock;
+};
+
+/* Device Driver State */
+static struct pft_device *pft_dev;
+
+/**
+ * pft_is_ready() - driver is initialized and ready.
+ *
+ * Return: true if the driver is ready.
+ */
+static bool pft_is_ready(void)
+{
+	return  (pft_dev != NULL);
+}
+
+/**
+ * file_to_filename() - get the filename from file pointer.
+ * @filp: file pointer
+ *
+ * it is used for debug prints.
+ *
+ * Return: filename string or "unknown".
+ */
+static char *file_to_filename(struct file *filp)
+{
+	struct dentry *dentry = NULL;
+	char *filename = NULL;
+
+	if (!filp || !filp->f_dentry)
+		return "unknown";
+
+	dentry = filp->f_dentry;
+	filename = dentry->d_iname;
+
+	return filename;
+}
+
+/**
+ * inode_to_filename() - get the filename from inode pointer.
+ * @inode: inode pointer
+ *
+ * it is used for debug prints.
+ *
+ * Return: filename string or "unknown".
+ */
+static char *inode_to_filename(struct inode *inode)
+{
+	struct dentry *dentry = NULL;
+	char *filename = NULL;
+
+	if (list_empty(&inode->i_dentry))
+		return "unknown";
+
+	dentry = list_first_entry(&inode->i_dentry, struct dentry, d_alias);
+
+	filename = dentry->d_iname;
+
+	return filename;
+}
+
+/**
+ * pft_set_response() - set response error code.
+ *
+ * @error_code: The error code to return on response.
+ */
+static inline void pft_set_response(u32 error_code)
+{
+	pft_dev->response.error_code = error_code;
+}
+
+/**
+ * pft_add_file()- Add the file to the list of opened encrypted
+ * files.
+ * @filp: file to add.
+ *
+ * Return: 0 of successful operation, negative value otherwise.
+ */
+static int pft_add_file(struct file *filp)
+{
+	struct pft_file_info *node = NULL;
+
+	node = kzalloc(sizeof(*node), GFP_KERNEL);
+	if (!node) {
+		pr_err("malloc failure\n");
+		return -ENOMEM;
+	}
+
+	node->file = filp;
+	INIT_LIST_HEAD(&node->list);
+
+	mutex_lock(&pft_dev->lock);
+	list_add(&node->list, &pft_dev->open_file_list);
+	pr_debug("adding file %s to open list.\n", file_to_filename(filp));
+	mutex_unlock(&pft_dev->lock);
+
+	return 0;
+}
+
+/**
+ * pft_remove_file()- Remove the given file from the list of
+ * open encrypted files.
+ * @filp: file to remove.
+ *
+ * Return: 0 on success, negative value on failure.
+ */
+static int pft_remove_file(struct file *filp)
+{
+	int ret = -ENOENT;
+	struct pft_file_info *tmp = NULL;
+	struct list_head *pos = NULL;
+	bool found = false;
+
+	mutex_lock(&pft_dev->lock);
+	list_for_each(pos, &pft_dev->open_file_list) {
+		tmp = list_entry(pos, struct pft_file_info, list);
+		if (filp == tmp->file) {
+			found = true;
+			break;
+		}
+	}
+
+	if (found) {
+		pr_debug("remove file %s. from open list.\n ",
+			 file_to_filename(filp));
+		list_del(&tmp->list);
+		kfree(tmp);
+		ret = 0;
+	}
+	mutex_unlock(&pft_dev->lock);
+
+	return ret;
+}
+
+/**
+ * pft_is_current_process_registered()- Check if current process
+ * is registered.
+ *
+ * Return: true if current process is registered.
+ */
+static bool pft_is_current_process_registered(void)
+{
+	int is_registered = false;
+	int i;
+	u32 uid = current_uid();
+
+	mutex_lock(&pft_dev->lock);
+	for (i = 0; i < pft_dev->uid_count; i++) {
+		if (pft_dev->uid_table[i] == uid) {
+			pr_debug("current UID [%u] is registerd.\n", uid);
+			is_registered = true;
+			break;
+		}
+	}
+	mutex_unlock(&pft_dev->lock);
+
+	return is_registered;
+}
+
+/**
+ * pft_is_xattr_supported() - Check if the filesystem supports
+ * extended attributes.
+ * @indoe: pointer to the file inode
+ *
+ * Return: true if supported, false if not.
+ */
+static bool pft_is_xattr_supported(struct inode *inode)
+{
+	if (inode == NULL) {
+		pr_err("invalid argument inode passed as NULL");
+		return false;
+	}
+
+	if (inode->i_security == NULL) {
+		pr_debug("i_security is NULL, not ready yet\n");
+		return false;
+	}
+
+	if (inode->i_op == NULL) {
+		pr_debug("i_op is NULL\n");
+		return false;
+	}
+
+	if (inode->i_op->getxattr == NULL) {
+		pr_debug_once("getxattr() not supported , filename=%s\n",
+			      inode_to_filename(inode));
+		return false;
+	}
+
+	if (inode->i_op->setxattr == NULL) {
+		pr_debug("setxattr() not supported\n");
+		return false;
+	}
+
+	return true;
+}
+
+/**
+ * pft_get_inode_tag() - get the file tag.
+ * @indoe: pointer to the file inode
+ *
+ * Return: tag
+ */
+static u32 pft_get_inode_tag(struct inode *inode)
+{
+	struct inode_security_struct *isec = inode->i_security;
+
+	if (isec == NULL)
+		return 0;
+
+	return isec->tag;
+}
+
+/**
+ * pft_get_inode_key_index() - get the file key.
+ * @indoe: pointer to the file inode
+ *
+ * Return: key index
+ */
+static inline u32 pft_get_inode_key_index(struct inode *inode)
+{
+	return pft_get_inode_tag(inode) & PFT_TAG_KEY_MASK;
+}
+
+/**
+ * pft_is_tag_valid() - is the tag valid
+ * @indoe: pointer to the file inode
+ *
+ * The tagging is set to valid when an enterprise file is created
+ * or when an file is opened first time after power up and the
+ * xattr was checked to see if the file is encrypted or not.
+ *
+ * Return: true if the tag is valid.
+ */
+static inline bool pft_is_tag_valid(struct inode *inode)
+{
+	struct inode_security_struct *isec = inode->i_security;
+
+	return ((isec->tag & PFT_TAG_MAGIC_MASK) == PFT_TAG_MAGIC) ?
+		true : false;
+}
+
+/**
+ * pft_is_file_encrypted() - is inode tagged as encrypted.
+ *
+ * @tag: holds the key index and tagging flags.
+ *
+ * Return: true if the file is encrypted.
+ */
+static inline bool pft_is_file_encrypted(u32 tag)
+{
+	return (tag & PFT_TAG_ENCRYPTED) ? true : false;
+}
+
+/**
+ * pft_tag_inode_non_encrypted() - Tag the inode as
+ * non-encrypted.
+ * @indoe: pointer to the file inode
+ *
+ * Tag file as non-encrypted, only the valid bit is set,
+ * the encrypted bit is not set.
+ */
+static inline void pft_tag_inode_non_encrypted(struct inode *inode)
+{
+	struct inode_security_struct *isec = inode->i_security;
+
+	isec->tag = (u32)(PFT_TAG_MAGIC);
+}
+
+/**
+ * pft_tag_inode_encrypted() - Tag the inode as encrypted.
+ * @indoe: pointer to the file inode
+ *
+ * Set the valid bit, the encrypted bit, and the key index.
+ */
+static void pft_tag_inode_encrypted(struct inode *inode, u32 key_index)
+{
+	struct inode_security_struct *isec = inode->i_security;
+
+	isec->tag = key_index | PFT_TAG_ENCRYPTED | PFT_TAG_MAGIC;
+}
+
+/**
+ * pft_get_file_tag()- get the file tag.
+ * @dentry:	pointer to file dentry.
+ * @tag_ptr:	pointer to tag.
+ *
+ * This is the major function for detecting tag files.
+ * Get the tag from the inode if tag is valid,
+ * or from the xattr if this is the 1st time after power up.
+ *
+ * Return: 0 on successe, negative value on failure.
+ */
+static int pft_get_file_tag(struct dentry *dentry, u32 *tag_ptr)
+{
+	ssize_t size = 0;
+	struct inode *inode;
+	const char *xattr_name = XATTR_NAME_PFE;
+	u32 key;
+
+	if (!dentry || !dentry->d_inode || !tag_ptr) {
+		pr_err("invalid param");
+		return -EINVAL;
+	}
+
+	inode = dentry->d_inode;
+	if (pft_is_tag_valid(inode)) {
+		*tag_ptr = pft_get_inode_tag(inode);
+		return 0;
+	}
+
+	/*
+	 * For the first time reading the tag, the tag is not valid, hence
+	 * get xattr.
+	 */
+	size = inode->i_op->getxattr(dentry, xattr_name, &key, sizeof(key));
+
+	if (size == -ENODATA || size == -EOPNOTSUPP) {
+		pft_tag_inode_non_encrypted(inode);
+		*tag_ptr = pft_get_inode_tag(inode);
+	} else if (size > 0) {
+		pr_debug("First time file %s opened, found xattr = %u.\n",
+		       inode_to_filename(inode), key);
+		pft_tag_inode_encrypted(inode, key);
+		*tag_ptr = pft_get_inode_tag(inode);
+	} else {
+		pr_err("getxattr() failure, ret=%d.\n", size);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/**
+ * pft_tag_file() - Tag the file saving the key_index.
+ * @dentry:	file dentry.
+ * @key_index:	encryption key index.
+ *
+ * This is the major fuction for tagging a file.
+ * Tag the file on both the xattr and the inode.
+ *
+ * Return: 0 on successe, negative value on failure.
+ */
+static int pft_tag_file(struct dentry *dentry, u32 key_index)
+{
+	int size = 0;
+	const char *xattr_name = XATTR_NAME_PFE;
+
+	if (!dentry || !dentry->d_inode) {
+		pr_err("invalid NULL param");
+		return -EINVAL;
+	}
+
+	if (!pft_is_xattr_supported(dentry->d_inode)) {
+		pr_err("set xattr for file %s is not support.\n",
+		       dentry->d_iname);
+		return -EINVAL;
+	}
+
+	size = dentry->d_inode->i_op->setxattr(dentry, xattr_name, &key_index,
+					       sizeof(key_index), 0);
+	if (size < 0) {
+		pr_err("failed to set xattr for file %s, ret =%d.\n",
+		       dentry->d_iname, size);
+		return -EFAULT;
+	}
+
+	pft_tag_inode_encrypted(dentry->d_inode, key_index);
+	pr_debug("file %s tagged encrypted\n", dentry->d_iname);
+
+	return 0;
+}
+
+/**
+ * pft_get_app_key_index() - get the application key index.
+ * @uid: registered application UID
+ *
+ * Get key index based on the given registered application UID.
+ * Currently only one key is supported.
+ *
+ * Return: encryption key index.
+ */
+static inline u32 pft_get_app_key_index(u32 uid)
+{
+	return PFT_DEFAULT_KEY_INDEX;
+}
+
+/**
+ * pft_is_encrypted_file() - is the file encrypted.
+ * @dentry: file pointer.
+ *
+ * Return: true if the file is encrypted, false otherwise.
+ */
+static bool pft_is_encrypted_file(struct dentry *dentry)
+{
+	int rc;
+	u32 tag;
+
+	if (!pft_is_ready())
+		return false;
+
+	if (!pft_is_xattr_supported(dentry->d_inode))
+		return false;
+
+	rc = pft_get_file_tag(dentry, &tag);
+	if (rc < 0)
+		return false;
+
+	return pft_is_file_encrypted(tag);
+}
+
+/**
+ * pft_is_encrypted_inode() - is the file encrypted.
+ * @inode: inode of file to check.
+ *
+ * Return: true if the file is encrypted, false otherwise.
+ */
+static bool pft_is_encrypted_inode(struct inode *inode)
+{
+	u32 tag;
+
+	if (!pft_is_ready())
+		return false;
+
+	if (!pft_is_xattr_supported(inode))
+		return false;
+
+	tag = pft_get_inode_tag(inode);
+
+	return pft_is_file_encrypted(tag);
+}
+
+/**
+ * pft_is_inplace_inode() - is this the inode of file for
+ * in-place encryption.
+ * @inode: inode of file to check.
+ *
+ * Return: true if this file is being encrypted, false
+ * otherwise.
+ */
+static bool pft_is_inplace_inode(struct inode *inode)
+{
+	if (!pft_dev->inplace_file || !pft_dev->inplace_file->f_path.dentry)
+		return false;
+
+	return (pft_dev->inplace_file->f_path.dentry->d_inode == inode);
+}
+
+/**
+ * pft_is_inplace_file() - is this the file for in-place
+ * encryption.
+ * @filp: file to check.
+ *
+ * A file struct might be allocated per process, inode should be
+ * only one.
+ *
+ * Return: true if this file is being encrypted, false
+ * otherwise.
+ */
+static inline bool pft_is_inplace_file(struct file *filp)
+{
+	if (!filp || !filp->f_path.dentry || !filp->f_path.dentry->d_inode)
+		return false;
+
+	return pft_is_inplace_inode(filp->f_path.dentry->d_inode);
+}
+
+/**
+ * pft_get_key_index() - get the key index and other indications
+ * @inode:	Pointer to inode struct
+ * @key_index:	Pointer to the return value of key index
+ * @is_encrypted:	Pointer to the return value.
+ * @is_inplace:	Pointer to the return value.
+ *
+ * Provides the given inode's encryption key index, and well as
+ * indications whether the file is encrypted or is it currently
+ * being in-placed encrypted.
+ * This API is called by the dm-req-crypt to decide if to
+ * encrypt/decrypt the file.
+ * File tagging depends on the hooks to be called from selinux,
+ * so if selinux is disabled then tagging is also not
+ * valid.
+ *
+ * Return: 0 on successe, negative value on failure.
+ */
+int pft_get_key_index(struct inode *inode, u32 *key_index,
+		      bool *is_encrypted, bool *is_inplace)
+{
+	u32 tag = 0;
+
+	if (!pft_is_ready())
+		return -ENODEV;
+
+	if (!selinux_is_enabled())
+		return -ENODEV;
+
+	if (!inode)
+		return -EPERM;
+
+	if (!is_encrypted) {
+		pr_err("is_encrypted is NULL\n");
+		return -EPERM;
+	}
+	if (!is_inplace) {
+		pr_err("is_inplace is NULL\n");
+		return -EPERM;
+	}
+	if (!key_index) {
+		pr_err("key_index is NULL\n");
+		return -EPERM;
+	}
+
+	if (!pft_is_tag_valid(inode)) {
+		pr_debug("file %s, Tag not valid\n", inode_to_filename(inode));
+		return -EINVAL;
+	}
+
+	if (!pft_is_xattr_supported(inode)) {
+		*is_encrypted = false;
+		*is_inplace = false;
+		*key_index = 0;
+		return 0;
+	}
+
+	tag = pft_get_inode_tag(inode);
+
+	*is_encrypted = pft_is_file_encrypted(tag);
+	*key_index = pft_get_inode_key_index(inode);
+	*is_inplace = pft_is_inplace_inode(inode);
+
+	if (*is_encrypted)
+		pr_debug("file %s is encrypted\n", inode_to_filename(inode));
+
+	return 0;
+}
+EXPORT_SYMBOL(pft_get_key_index);
+
+/**
+ * pft_bio_get_inode() - get the inode from a bio.
+ * @bio: Pointer to BIO structure.
+ *
+ * Walk the bio struct links to get the inode.
+ *
+ * Return: pointer to the inode struct if successful, or NULL otherwise.
+ */
+static struct inode *pft_bio_get_inode(struct bio *bio)
+{
+	if (!bio || !bio->bi_io_vec || !bio->bi_io_vec->bv_page ||
+	    !bio->bi_io_vec->bv_page->mapping)
+		return NULL;
+
+	return bio->bi_io_vec->bv_page->mapping->host;
+}
+
+/**
+ * pft_allow_merge_bio()- Check if 2 BIOs can be merged.
+ * @bio1:	Pointer to first BIO structure.
+ * @bio2:	Pointer to second BIO structure.
+ *
+ * Prevent merging of BIOs from encrypted and non-encrypted
+ * files, or files encrypted with different key.
+ * This API is called by the file system block layer.
+ *
+ * Return: true if the BIOs allowed to be merged, false
+ * otherwise.
+ */
+bool pft_allow_merge_bio(struct bio *bio1, struct bio *bio2)
+{
+	u32 key_index1 = 0, key_index2 = 0;
+	bool is_encrypted1 = false, is_encrypted2 = false;
+	bool allow = false;
+	bool is_inplace = false; /* N.A. */
+	int ret;
+
+	if (!pft_is_ready())
+		return true;
+
+	ret = pft_get_key_index(pft_bio_get_inode(bio1), &key_index1,
+				&is_encrypted1, &is_inplace);
+	if (ret)
+		is_encrypted1 = false;
+
+	ret = pft_get_key_index(pft_bio_get_inode(bio2), &key_index2,
+				&is_encrypted2, &is_inplace);
+	if (ret)
+		is_encrypted2 = false;
+
+	allow = ((is_encrypted1 == is_encrypted2) &&
+		 (key_index1 == key_index2));
+
+	return allow;
+}
+EXPORT_SYMBOL(pft_allow_merge_bio);
+
+/**
+ * pft_inode_create() - file creation callback.
+ * @dir:	directory inode pointer
+ * @dentry:	file dentry pointer
+ * @mode:	flags
+ *
+ * This hook is called when file is created by VFS.
+ * This hook is called from the selinux driver.
+ * This hooks check file creation permission for enterprise
+ * applications.
+ * Call path:
+ * vfs_create()->security_inode_create()->selinux_inode_create()
+ *
+ * Return: 0 on successe, negative value on failure.
+ */
+int pft_inode_create(struct inode *dir, struct dentry *dentry, umode_t mode)
+{
+	if (!dir || !dentry)
+		return 0;
+
+	if (!pft_is_ready())
+		return 0;
+
+	switch (pft_dev->state) {
+	case PFT_STATE_DEACTIVATED:
+	case PFT_STATE_KEY_LOADED:
+		break;
+	case PFT_STATE_KEY_REMOVED:
+	case PFT_STATE_DEACTIVATING:
+	case PFT_STATE_REMOVING_KEY:
+		/* At this state no new encrypted files can be created */
+		if (pft_is_current_process_registered()) {
+			pr_debug("key removed, registered uid %u is denied from creating new file %s\n",
+				current_uid(), dentry->d_iname);
+			return -EACCES;
+		}
+		break;
+	default:
+		BUG(); /* State is set by "set state" command */
+		break;
+	}
+
+	return 0;
+
+}
+EXPORT_SYMBOL(pft_inode_create);
+
+/**
+ * pft_inode_post_create() - file creation callback.
+ * @dir:	directory inode pointer
+ * @dentry:	file dentry pointer
+ * @mode:	flags
+ *
+ * This hook is called when file is created by VFS.
+ * This hook is called from the selinux driver.
+ * This hooks tags new files as encrypted when created by
+ * enterprise applications.
+ * Call path:
+ * vfs_create()->security_inode_post_create()->selinux_inode_post_create()
+ *
+ * Return: 0 on successe, negative value on failure.
+ */
+int pft_inode_post_create(struct inode *dir, struct dentry *dentry,
+			  umode_t mode)
+{
+	int ret;
+
+	if (!dir || !dentry)
+		return 0;
+
+	if (!pft_is_ready())
+		return 0;
+
+	switch (pft_dev->state) {
+	case PFT_STATE_DEACTIVATED:
+	case PFT_STATE_KEY_REMOVED:
+	case PFT_STATE_DEACTIVATING:
+	case PFT_STATE_REMOVING_KEY:
+		break;
+	case PFT_STATE_KEY_LOADED:
+		/* Check whether the new file should be encrypted */
+		if (pft_is_current_process_registered()) {
+			u32 key_index = pft_get_app_key_index(current_uid());
+			ret = pft_tag_file(dentry, key_index);
+			if (ret == 0)
+				pr_debug("key loaded, pid [%u] uid [%d] is creating file %s\n",
+					 current_pid(), current_uid(),
+					 dentry->d_iname);
+			else {
+				pr_err("Failed to tag file %s by pid %d\n",
+					dentry->d_iname, current_pid());
+				return -EFAULT;
+			}
+		}
+		break;
+	default:
+		BUG(); /* State is set by "set state" command */
+		break;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(pft_inode_post_create);
+
+/**
+ * pft_inode_mknod() - mknode file hook (callback)
+ * @dir:	directory inode pointer
+ * @dentry:	file dentry pointer
+ * @mode:	flags
+ * @dev:
+ *
+ * This hook checks encrypted file access permission by
+ * enterprise application.
+ * Call path:
+ * vfs_mknod()->security_inode_mknod()->selinux_inode_mknod()->pft_inode_mknod()
+ *
+ * Return: 0 on successful operation, negative value otherwise.
+ */
+int pft_inode_mknod(struct inode *dir, struct dentry *dentry,
+		    umode_t mode, dev_t dev)
+{
+	int rc;
+
+	/* Check if allowed to create new encrypted files */
+	rc = pft_inode_create(dir, dentry, mode);
+
+	return rc;
+}
+EXPORT_SYMBOL(pft_inode_mknod);
+
+/**
+ * pft_inode_symlink() - symlink file hook (callback)
+ * @dir:	directory inode pointer
+ * @dentry:	file dentry pointer
+ * @name:	Old file name
+ *
+ * Allow only enterprise app to create symlink to enterprise
+ * file.
+ * Call path:
+ * vfs_symlink()->security_inode_symlink()->selinux_inode_symlink()
+ *
+ * Return: 0 on allowed operation, negative value otherwise.
+ */
+int pft_inode_symlink(struct inode *dir, struct dentry *dentry,
+		      const char *name)
+{
+	struct inode *inode;
+
+	if (!dir) {
+		pr_err("dir is NULL.\n");
+		return 0;
+	}
+	if (!dentry) {
+		pr_err("dentry is NULL.\n");
+		return 0;
+	}
+	if (!name) {
+		pr_err("name is NULL.\n");
+		return 0;
+	}
+
+	pr_debug("symlink for file [%s] dir [%s] dentry [%s] started! ....\n",
+		 name, inode_to_filename(dir), dentry->d_iname);
+	inode = dentry->d_inode;
+
+	if (!dentry->d_inode) {
+		pr_debug("d_inode is NULL.\n");
+		return 0;
+	}
+
+	if (!pft_is_ready())
+		return 0;
+
+	/* do nothing for non-encrypted files */
+	if (!pft_is_encrypted_inode(inode))
+		return 0;
+
+	/*
+	 * Only PFM allowed to access in-place-encryption-file
+	 * during in-place-encryption process
+	 */
+	if (pft_is_inplace_inode(inode)) {
+		pr_err("symlink for in-place-encryption file %s by pid %d is blocked.\n",
+			 inode_to_filename(inode), current_pid());
+		return -EACCES;
+	}
+
+	switch (pft_dev->state) {
+	case PFT_STATE_DEACTIVATED:
+	case PFT_STATE_KEY_REMOVED:
+	case PFT_STATE_DEACTIVATING:
+	case PFT_STATE_REMOVING_KEY:
+		/* Block any access for encrypted files when key not loaded */
+		pr_debug("key not loaded. uid (%u) can not access file %s\n",
+			 current_uid(), inode_to_filename(inode));
+		return -EACCES;
+	case PFT_STATE_KEY_LOADED:
+		 /* Only registered apps may access encrypted files. */
+		if (!pft_is_current_process_registered()) {
+			pr_err("unregistered app uid %u pid %u is trying to access encrypted file %s\n",
+			       current_uid(), current_pid(), name);
+			return -EACCES;
+		}
+		break;
+	default:
+		BUG(); /* State is set by "set state" command */
+		break;
+	}
+
+	pr_debug("symlink for file %s ok.\n", name);
+
+	return 0;
+
+}
+EXPORT_SYMBOL(pft_inode_symlink);
+
+/**
+ * pft_inode_rename() - file rename hook.
+ * @inode:	directory inode
+ * @dentry:	file dentry
+ * @new_inode
+ * @new_dentry
+ *
+ * Block attempt to rename enterprise file.
+ *
+ * Return: 0 on allowed operation, negative value otherwise.
+ */
+int pft_inode_rename(struct inode *inode, struct dentry *dentry,
+		     struct inode *new_inode, struct dentry *new_dentry)
+{
+	if (!inode || !dentry || !new_inode || !new_dentry || !dentry->d_inode)
+		return 0;
+
+	if (!pft_is_ready())
+		return 0;
+
+	/* do nothing for non-encrypted files */
+	if (!pft_is_encrypted_file(dentry))
+		return 0;
+
+	pr_debug("attempt to rename encrypted file [%s]\n", dentry->d_iname);
+
+	if (pft_is_inplace_inode(dentry->d_inode)) {
+		pr_err("access in-place-encryption file %s by uid [%d] pid [%d] is blocked.\n",
+		       inode_to_filename(inode), current_uid(), current_pid());
+		return -EACCES;
+	}
+
+	if (!pft_is_current_process_registered()) {
+		pr_err("unregistered app (uid %u pid %u) is trying to access encrypted file %s\n",
+		       current_uid(), current_pid(), dentry->d_iname);
+		return -EACCES;
+	} else
+		pr_debug("rename file %s\n", dentry->d_iname);
+
+	return 0;
+}
+EXPORT_SYMBOL(pft_inode_rename);
+
+/**
+ * pft_file_open() - file open hook (callback).
+ * @filp:	file pointer
+ * @cred:	credentials pointer
+ *
+ * This hook is called when file is opened by VFS.
+ * It is called from the selinux driver.
+ * It checks enterprise file xattr when first opened.
+ * It adds encrypted file to the list of open files.
+ * Call path:
+ * do_filp_open()->security_dentry_open()->selinux_dentry_open()
+ *
+ * Return: 0 on successe, negative value on failure.
+ */
+int pft_file_open(struct file *filp, const struct cred *cred)
+{
+	if (!filp || !filp->f_path.dentry)
+		return 0;
+
+	if (!pft_is_ready())
+		return 0;
+
+	/* do nothing for non-encrypted files */
+	if (!pft_is_encrypted_file(filp->f_dentry))
+		return 0;
+
+	/*
+	 * Only PFM allowed to access in-place-encryption-file
+	 * during in-place-encryption process
+	 */
+	if (pft_is_inplace_file(filp) && current_pid() != pft_dev->pfm_pid) {
+		pr_err("Access in-place-encryption file %s by uid %d pid %d is blocked.\n",
+			 file_to_filename(filp), current_uid(), current_pid());
+		return -EACCES;
+	}
+
+	switch (pft_dev->state) {
+	case PFT_STATE_DEACTIVATED:
+	case PFT_STATE_KEY_REMOVED:
+	case PFT_STATE_DEACTIVATING:
+	case PFT_STATE_REMOVING_KEY:
+		/* Block any access for encrypted files when key not loaded */
+		pr_debug("key not loaded. uid (%u) can not access file %s\n",
+			 current_uid(), file_to_filename(filp));
+		return -EACCES;
+	case PFT_STATE_KEY_LOADED:
+		 /* Only registered apps may access encrypted files. */
+		if (!pft_is_current_process_registered()) {
+			pr_err("unregistered app (uid %u pid %u) is trying to access encrypted file %s\n",
+			       current_uid(), current_pid(),
+			       file_to_filename(filp));
+			return -EACCES;
+		}
+
+		pft_add_file(filp);
+		break;
+	default:
+		BUG(); /* State is set by "set state" command */
+		break;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(pft_file_open);
+
+/**
+ * pft_file_permission() - check file access permission.
+ * @filp:	file pointer
+ * @mask:	flags
+ *
+ * This hook is called when file is read/write by VFS.
+ * This hook is called from the selinux driver.
+ * This hook checks encrypted file access permission by
+ * enterprise application.
+ * Call path:
+ * vfs_read()->security_file_permission()->selinux_file_permission()
+ *
+ * Return: 0 on successe, negative value on failure.
+ */
+int pft_file_permission(struct file *filp, int mask)
+{
+	if (!filp)
+		return 0;
+
+	if (!pft_is_ready())
+		return 0;
+
+	/* do nothing for non-encrypted files */
+	if (!pft_is_encrypted_file(filp->f_dentry))
+		return 0;
+
+	/*
+	 * Only PFM allowed to access in-place-encryption-file
+	 * during in-place encryption process
+	 */
+	if (pft_is_inplace_file(filp)) {
+		if (current_pid() == pft_dev->pfm_pid) {
+			/* mask MAY_WRITE=2 / MAY_READ=4 */
+			pr_debug("r/w [mask 0x%x] in-place-encryption file %s by PFM (UID %d, PID %d).\n",
+				 mask, file_to_filename(filp),
+				 current_uid(), current_pid());
+			return 0;
+		} else {
+			pr_err("Access in-place-encryption file %s by App (UID %d, PID %d) is blocked.\n",
+			       file_to_filename(filp),
+			       current_uid(), current_pid());
+			return -EACCES;
+		}
+	}
+
+	switch (pft_dev->state) {
+	case PFT_STATE_DEACTIVATED:
+	case PFT_STATE_KEY_REMOVED:
+	case PFT_STATE_DEACTIVATING:
+	case PFT_STATE_REMOVING_KEY:
+		/* Block any access for encrypted files when key not loaded */
+		pr_debug("key not loaded. uid (%u) can not access file %s\n",
+			 current_uid(), file_to_filename(filp));
+		return -EACCES;
+	case PFT_STATE_KEY_LOADED:
+		 /* Only registered apps can access encrypted files. */
+		if (!pft_is_current_process_registered()) {
+			pr_err("unregistered app (uid %u pid %u) is trying to access encrypted file %s\n",
+			       current_uid(), current_pid(),
+			       file_to_filename(filp));
+			return -EACCES;
+		}
+		break;
+	default:
+		BUG(); /* State is set by "set state" command */
+		break;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(pft_file_permission);
+
+/**
+ * pft_sync_file() - sync the file.
+ * @filp:	file pointer
+ *
+ * Complete writting any pending write request of encrypted data
+ * before key is removed, to avoid writting garbage to
+ * enterprise files.
+ */
+static void pft_sync_file(struct file *filp)
+{
+	int ret;
+
+	ret = vfs_fsync(filp, false);
+
+	if (ret)
+		pr_debug("failed to sync file %s, ret = %d.\n",
+			 file_to_filename(filp), ret);
+	else
+		pr_debug("Sync file %s ok.\n",  file_to_filename(filp));
+
+}
+
+/**
+ * pft_file_close()- handle file close event
+ * @filp:	file pointer
+ *
+ * This hook is called when file is closed by VFS.
+ * This hook is called from the selinux driver.
+ *
+ * Return: 0 on successful operation, negative value otherwise.
+ */
+int pft_file_close(struct file *filp)
+{
+	if (!filp)
+		return 0;
+
+	if (!pft_is_ready())
+		return 0;
+
+	/* do nothing for non-encrypted files */
+	if (!pft_is_encrypted_file(filp->f_dentry))
+		return 0;
+
+	if (pft_is_inplace_file(filp)) {
+		pr_debug("pid [%u] uid [%u] is closing in-place-encryption file %s\n",
+			 current_pid(), current_uid(), file_to_filename(filp));
+		pft_dev->inplace_file = NULL;
+	}
+
+	pft_sync_file(filp);
+	pft_remove_file(filp);
+
+	return 0;
+}
+EXPORT_SYMBOL(pft_file_close);
+
+/**
+ * pft_inode_unlink() - Delete file hook.
+ * @dir:	directory inode pointer
+ * @dentry:	file dentry pointer
+ *
+ * call path: vfs_unlink()->security_inode_unlink().
+ *
+ * Return: 0 on successful operation, negative value otherwise.
+ */
+int pft_inode_unlink(struct inode *dir, struct dentry *dentry)
+{
+	struct inode *inode = NULL;
+
+	if (!dir || !dentry || !dentry->d_inode)
+		return 0;
+
+	if (!pft_is_ready())
+		return 0;
+
+	inode = dentry->d_inode;
+
+	/* do nothing for non-encrypted files */
+	if (!pft_is_encrypted_file(dentry))
+		return 0;
+
+	if (pft_is_inplace_inode(inode)) {
+		pr_err("block delete in-place-encryption file %s by uid [%d] pid [%d], while encryption in progress.\n",
+		       inode_to_filename(inode), current_uid(), current_pid());
+		return -EACCES;
+	}
+
+	if (!pft_is_current_process_registered()) {
+		pr_err("unregistered app (uid %u pid %u) is trying to access encrypted file %s\n",
+		       current_uid(), current_pid(), inode_to_filename(inode));
+		return -EACCES;
+	} else
+		pr_debug("delete file %s\n", inode_to_filename(inode));
+
+	return 0;
+}
+EXPORT_SYMBOL(pft_inode_unlink);
+
+/**
+ * pft_inode_set_xattr() - set/remove xattr callback.
+ * @dentry:	file dentry pointer
+ * @name:	xattr name.
+ *
+ * This hook checks attempt to set/remove PFE xattr.
+ * Only this kernel driver allows to set the PFE xattr, so block
+ * any attempt to do it from user space. Allow access for other
+ * xattr.
+ *
+ * Return: 0 on successful operation, negative value otherwise.
+ */
+int pft_inode_set_xattr(struct dentry *dentry, const char *name)
+{
+	struct inode *inode = NULL;
+
+	if (!dentry || !dentry->d_inode)
+		return 0;
+
+	inode = dentry->d_inode;
+
+	if (strcmp(name, XATTR_NAME_PFE) != 0) {
+		pr_debug("xattr name=%s file %s\n", name,
+		       inode_to_filename(inode));
+		return 0; /* Not PFE xattr so it is ok */
+	}
+
+	pr_err("Attemp to set/remove PFE xattr for file %s\n",
+	       inode_to_filename(inode));
+
+	/* Only PFT kernel driver allows to set the PFE xattr */
+	return -EACCES;
+}
+EXPORT_SYMBOL(pft_inode_set_xattr);
+
+/**
+ * pft_close_opened_enc_files() - Close all the currently open
+ * encrypted files
+ *
+ * Close all open encrypted file when removing key or
+ * deactivating.
+ */
+static void pft_close_opened_enc_files(void)
+{
+	struct pft_file_info *tmp = NULL;
+	struct list_head *pos = NULL;
+	struct list_head *next = NULL;
+
+	list_for_each_safe(pos, next, &pft_dev->open_file_list) {
+		struct file *filp;
+		tmp = list_entry(pos, struct pft_file_info, list);
+		filp = tmp->file;
+		pr_debug("closing file %s.\n", file_to_filename(filp));
+		/* filp_close() eventually calls pft_file_close() */
+		filp_close(filp, NULL);
+	}
+}
+
+/**
+ * pft_set_state() - Handle "Set State" command
+ * @command:	command buffer.
+ * @size:	size of command buffer.
+ *
+ * The command execution status is reported by the response.
+ *
+ * Return: 0 on successful operation, negative value otherwise.
+ */
+static int pft_set_state(struct pft_command *command, int size)
+{
+	u32 state = command->set_state.state;
+	int expected_size = sizeof(command->opcode) +
+		sizeof(command->set_state);
+
+	if (size != expected_size) {
+		pr_err("Invalid buffer size\n");
+		pft_set_response(PFT_CMD_RESP_INVALID_CMD_PARAMS);
+		return -EINVAL;
+	}
+
+	if (state >= PFT_STATE_MAX_INDEX) {
+		pr_err("Invalid state %d\n", command->set_state.state);
+		pft_set_response(PFT_CMD_RESP_INVALID_STATE);
+		return 0;
+	}
+
+	pr_debug("Set State %d [%s].\n", state, pft_state_name[state]);
+
+	switch (command->set_state.state) {
+	case PFT_STATE_DEACTIVATING:
+	case PFT_STATE_REMOVING_KEY:
+		pft_close_opened_enc_files();
+		/* Fall through */
+	case PFT_STATE_DEACTIVATED:
+	case PFT_STATE_KEY_LOADED:
+	case PFT_STATE_KEY_REMOVED:
+		pft_dev->state = command->set_state.state;
+		pft_set_response(PFT_CMD_RESP_SUCCESS);
+		break;
+	default:
+		pr_err("Invalid state %d\n", command->set_state.state);
+		pft_set_response(PFT_CMD_RESP_INVALID_STATE);
+		break;
+	}
+
+	return 0;
+}
+
+/**
+ * pft_get_process_open_file() - get file pointer using file
+ * descriptor index.
+ * @index: file descriptor index.
+ *
+ * Return: file pointer on success, NULL on failure.
+ */
+static struct file *pft_get_process_open_file(int index)
+{
+	struct fdtable *files_table;
+
+	files_table = files_fdtable(current->files);
+	if (files_table == NULL)
+		return NULL;
+
+	if (index >= files_table->max_fds)
+		return NULL;
+	else
+		return files_table->fd[index];
+}
+
+/**
+ *  pft_set_inplace_file() - handle "inplace file encryption"
+ *  command.
+ * @command:	command buffer.
+ * @size:	size of command buffer.
+ *
+ * The command execution status is reported by the response.
+ *
+ * Return: 0 if command is valid, negative value otherwise.
+ */
+static int pft_set_inplace_file(struct pft_command *command, int size)
+{
+	int expected_size;
+	u32 fd;
+	int rc;
+	struct file *filp = NULL;
+	struct inode *inode = NULL;
+	int writecount;
+
+	expected_size = sizeof(command->opcode) +
+		sizeof(command->preform_in_place_file_enc.file_descriptor);
+
+	if (size != expected_size) {
+		pr_err("invalid command size %d expected %d.\n",
+		       size, expected_size);
+		pft_set_response(PFT_CMD_RESP_INVALID_CMD_PARAMS);
+		return -EINVAL;
+	}
+
+	if (pft_dev->state != (u32) PFT_STATE_KEY_LOADED) {
+		pr_err("Key not loaded, state [%d], In-place-encryption is not allowed.\n",
+		       pft_dev->state);
+		pft_set_response(PFT_CMD_RESP_GENERAL_ERROR);
+		return 0;
+	}
+
+	/* allow only one in-place file encryption at a time */
+	if (pft_dev->inplace_file != NULL) {
+		pr_err("file %s in-place-encryption in progress.\n",
+		       file_to_filename(pft_dev->inplace_file));
+		/* @todo - use new error code */
+		pft_set_response(PFT_CMD_RESP_INPLACE_FILE_IS_OPEN);
+		return 0;
+	}
+
+	fd = command->preform_in_place_file_enc.file_descriptor;
+	filp = pft_get_process_open_file(fd);
+
+	if (filp == NULL) {
+		pr_err("failed to find file by fd %d.\n", fd);
+		pft_set_response(PFT_CMD_RESP_GENERAL_ERROR);
+		return 0;
+	}
+
+	/* Verify the file is not already open by other than PFM */
+	if (!filp->f_path.dentry || !filp->f_path.dentry->d_inode) {
+		pr_err("failed to get inode of inplace-file.\n");
+		pft_set_response(PFT_CMD_RESP_GENERAL_ERROR);
+		return 0;
+	}
+
+	inode = filp->f_path.dentry->d_inode;
+	writecount = atomic_read(&inode->i_writecount);
+	if (writecount > 1) {
+		pr_err("file %s is opened %d times for write.\n",
+		       file_to_filename(filp), writecount);
+		pft_set_response(PFT_CMD_RESP_INPLACE_FILE_IS_OPEN);
+		return 0;
+	}
+
+	/*
+	 * Check if the file was already encryprted.
+	 * In practice, it is unlikely to happen,
+	 * because PFM is not an enterprise application
+	 * it won't be able to open encrypted file.
+	 */
+	if (pft_is_encrypted_file(filp->f_dentry)) {
+		pr_err("file %s is already encrypted.\n",
+		       file_to_filename(filp));
+		pft_set_response(PFT_CMD_RESP_GENERAL_ERROR);
+		return 0;
+	}
+
+
+	/* Update the current in-place-encryption file */
+	pft_dev->inplace_file = filp;
+
+	/*
+	 * Now, any new access to this file is allowed only to PFM.
+	 * Lets make sure that all pending writes are completed
+	 * before encrypting the file.
+	 */
+	pft_sync_file(filp);
+
+	rc = pft_tag_file(pft_dev->inplace_file->f_dentry,
+			  pft_get_app_key_index(current_uid()));
+
+	if (!rc) {
+		pr_debug("tagged file %s to be encrypted.\n",
+			 file_to_filename(pft_dev->inplace_file));
+		pft_set_response(PFT_CMD_RESP_SUCCESS);
+	} else {
+		pr_err("failed to tag file %s for encryption.\n",
+			file_to_filename(pft_dev->inplace_file));
+		pft_set_response(PFT_CMD_RESP_GENERAL_ERROR);
+	}
+
+	return 0;
+}
+
+/**
+ * pft_update_reg_apps() - Update the registered application
+ * list.
+ * @command:	command buffer.
+ * @size:	size of command buffer.
+ *
+ * The command execution status is reported by the response.
+ *
+ * Return: 0 on successful operation, negative value otherwise.
+ */
+static int pft_update_reg_apps(struct pft_command *command, int size)
+{
+	int i;
+	int expected_size;
+	void *buf;
+	int buf_size;
+	u32 items_count = command->update_app_list.items_count;
+
+	if (items_count > PFT_MAX_APPS) {
+		pr_err("Number of apps [%d] > max apps [%d]\n",
+		       items_count , PFT_MAX_APPS);
+		pft_set_response(PFT_CMD_RESP_INVALID_CMD_PARAMS);
+		return -EINVAL;
+	}
+
+	expected_size =
+		sizeof(command->opcode) +
+		sizeof(command->update_app_list.items_count) +
+		(command->update_app_list.items_count * sizeof(u32));
+
+	if (size != expected_size) {
+		pr_err("invalid command size %d expected %d.\n",
+		       size, expected_size);
+		pft_set_response(PFT_CMD_RESP_INVALID_CMD_PARAMS);
+		return -EINVAL;
+	}
+
+	mutex_lock(&pft_dev->lock);
+
+	/* Free old table */
+	kfree(pft_dev->uid_table);
+	pft_dev->uid_table = NULL;
+	pft_dev->uid_count = 0;
+
+	if (items_count == 0) {
+		pr_info("empty app list - clear list.\n");
+		mutex_unlock(&pft_dev->lock);
+		return 0;
+	}
+
+	buf_size = command->update_app_list.items_count * sizeof(u32);
+	buf = kzalloc(buf_size, GFP_KERNEL);
+
+	if (!buf) {
+		pr_err("malloc failure\n");
+		pft_set_response(PFT_CMD_RESP_GENERAL_ERROR);
+		mutex_unlock(&pft_dev->lock);
+		return 0;
+	}
+
+	pft_dev->uid_table = buf;
+	pft_dev->uid_count = command->update_app_list.items_count;
+	pr_debug("uid_count = %d\n", pft_dev->uid_count);
+	for (i = 0; i < pft_dev->uid_count; i++)
+		pft_dev->uid_table[i] = command->update_app_list.table[i];
+	pft_set_response(PFT_CMD_RESP_SUCCESS);
+	mutex_unlock(&pft_dev->lock);
+
+	return 0;
+}
+
+/**
+ * pft_handle_command() - Handle user space app commands.
+ * @buf:	command buffer.
+ * @buf_size:	command buffer size.
+ *
+ * Return: 0 on successful operation, negative value otherwise.
+ */
+static int pft_handle_command(void *buf, int buf_size)
+{
+	size_t ret = 0;
+	struct pft_command *command = NULL;
+
+	/* opcode field is the minimum length of command */
+	if (buf_size < sizeof(command->opcode)) {
+		pr_err("Invalid argument used buffer size\n");
+		return -EINVAL;
+	}
+
+	command = (struct pft_command *)buf;
+
+	pft_dev->response.command_id = command->opcode;
+
+	switch (command->opcode) {
+	case PFT_CMD_OPCODE_SET_STATE:
+		ret = pft_set_state(command, buf_size);
+		break;
+	case PFT_CMD_OPCODE_UPDATE_REG_APP_UID:
+		ret = pft_update_reg_apps(command, buf_size);
+		break;
+	case PFT_CMD_OPCODE_PERFORM_IN_PLACE_FILE_ENC:
+		ret = pft_set_inplace_file(command, buf_size);
+		break;
+	default:
+		pr_err("Invalid command_op_code %u\n", command->opcode);
+		pft_set_response(PFT_CMD_RESP_INVALID_COMMAND);
+		return 0;
+	}
+
+	return ret;
+}
+
+static int pft_device_open(struct inode *inode, struct file *file)
+{
+	int ret;
+
+	mutex_lock(&pft_dev->lock);
+	if (pft_dev->open_count > 0) {
+		pr_err("PFT device is already opened (%d)\n",
+		       pft_dev->open_count);
+		ret = -EBUSY;
+	} else {
+		pft_dev->open_count++;
+		pft_dev->pfm_pid = current_pid();
+		pr_debug("PFT device opened by %d (%d)\n",
+			 pft_dev->pfm_pid, pft_dev->open_count);
+		ret = 0;
+	}
+	mutex_unlock(&pft_dev->lock);
+
+	pr_debug("device opened, count %d\n", pft_dev->open_count);
+
+	return ret;
+}
+
+static int pft_device_release(struct inode *inode, struct file *file)
+{
+	mutex_lock(&pft_dev->lock);
+	if (0 < pft_dev->open_count)
+		pft_dev->open_count--;
+	pft_dev->pfm_pid = UINT_MAX;
+	mutex_unlock(&pft_dev->lock);
+
+	pr_debug("device released, count %d\n", pft_dev->open_count);
+
+	return 0;
+}
+
+/**
+ * pft_device_write() - Get commands from user sapce.
+ *
+ * Return: number of bytes to write on success to get the
+ * command buffer, negative value on failure.
+ * The error code for handling the command should be retrive by
+ * reading the response.
+ * Note: any reurn value of 0..size-1 will cause retry by the
+ * OS, so avoid it.
+ */
+static ssize_t pft_device_write(struct file *filp, const char __user *user_buff,
+				size_t size, loff_t *f_pos)
+{
+	int ret;
+	char *cmd_buf;
+
+	if (size > PFT_MAX_COMMAND_SIZE || !user_buff || !f_pos) {
+		pr_err("inavlid parameters.\n");
+		return -EINVAL;
+	}
+
+	cmd_buf = kzalloc(size, GFP_KERNEL);
+	if (cmd_buf == NULL) {
+		pr_err("malloc failure for command buffer\n");
+		return -ENOMEM;
+	}
+
+	ret = copy_from_user(cmd_buf, user_buff, size);
+	if (ret) {
+		pr_err("Unable to copy from user (err %d)\n", ret);
+		kfree(cmd_buf);
+		return -EFAULT;
+	}
+
+	ret = pft_handle_command(cmd_buf, size);
+	if (ret) {
+		kfree(cmd_buf);
+		return -EFAULT;
+	}
+
+	kfree(cmd_buf);
+
+	return size;
+}
+
+/**
+ * pft_device_read() - return response of last command.
+ *
+ * Return: number of bytes to read on success, negative value on
+ * failure.
+ */
+static ssize_t pft_device_read(struct file *filp, char __user *buffer,
+			       size_t length, loff_t *f_pos)
+{
+	int ret = 0;
+
+	if (!buffer || !f_pos || length < sizeof(pft_dev->response)) {
+		pr_err("inavlid parameters.\n");
+		return -EFAULT;
+	}
+
+	ret = copy_to_user(buffer, &(pft_dev->response),
+			   sizeof(pft_dev->response));
+	if (ret) {
+		pr_err("Unable to copy to user, err = %d.\n", ret);
+		return -EINVAL;
+	}
+
+	return sizeof(pft_dev->response);
+}
+
+
+static const struct file_operations fops = {
+	.owner = THIS_MODULE,
+	.read = pft_device_read,
+	.write = pft_device_write,
+	.open = pft_device_open,
+	.release = pft_device_release,
+};
+
+static int __init pft_register_chardev(void)
+{
+	int rc;
+	unsigned baseminor = 0;
+	unsigned count = 1;
+	struct device *class_dev;
+
+	rc = alloc_chrdev_region(&pft_dev->device_no, baseminor, count,
+				 DEVICE_NAME);
+	if (rc < 0) {
+		pr_err("alloc_chrdev_region failed %d\n", rc);
+		return rc;
+	}
+
+	pft_dev->driver_class = class_create(THIS_MODULE, DEVICE_NAME);
+	if (IS_ERR(pft_dev->driver_class)) {
+		rc = -ENOMEM;
+		pr_err("class_create failed %d\n", rc);
+		goto exit_unreg_chrdev_region;
+	}
+
+	class_dev = device_create(pft_dev->driver_class, NULL,
+				  pft_dev->device_no, NULL,
+				  DEVICE_NAME);
+	if (!class_dev) {
+		pr_err("class_device_create failed %d\n", rc);
+		rc = -ENOMEM;
+		goto exit_destroy_class;
+	}
+
+	cdev_init(&pft_dev->cdev, &fops);
+	pft_dev->cdev.owner = THIS_MODULE;
+
+	rc = cdev_add(&pft_dev->cdev, MKDEV(MAJOR(pft_dev->device_no), 0), 1);
+	if (rc < 0) {
+		pr_err("cdev_add failed %d\n", rc);
+		goto exit_destroy_device;
+	}
+
+	return 0;
+
+exit_destroy_device:
+	device_destroy(pft_dev->driver_class, pft_dev->device_no);
+exit_destroy_class:
+	class_destroy(pft_dev->driver_class);
+exit_unreg_chrdev_region:
+	unregister_chrdev_region(pft_dev->device_no, 1);
+	return rc;
+}
+
+static void __exit pft_unregister_chrdev(void)
+{
+	cdev_del(&pft_dev->cdev);
+	device_destroy(pft_dev->driver_class, pft_dev->device_no);
+	class_destroy(pft_dev->driver_class);
+	unregister_chrdev_region(pft_dev->device_no, 1);
+
+}
+
+static void __exit pft_exit(void)
+{
+	if (pft_dev == NULL)
+		return;
+
+	pft_unregister_chrdev();
+
+	kfree(pft_dev->uid_table);
+	kfree(pft_dev);
+}
+
+static int __init pft_init(void)
+{
+	int ret;
+	struct pft_device *dev = NULL;
+
+	dev = kzalloc(sizeof(struct pft_device), GFP_KERNEL);
+	if (dev == NULL) {
+		pr_err("No memory for device structr\n");
+		return -ENOMEM;
+	}
+
+	dev->state = PFT_STATE_DEACTIVATED;
+	INIT_LIST_HEAD(&dev->open_file_list);
+	mutex_init(&dev->lock);
+
+	pft_dev = dev;
+
+	ret = pft_register_chardev();
+	if (ret) {
+		pr_err("create character device failed.\n");
+		goto fail;
+	}
+
+	pr_info("Drivr initialized successfully %s %s.n", __DATE__, __TIME__);
+
+	return 0;
+
+fail:
+	pr_err("Failed to init driver.\n");
+	kfree(dev);
+
+	return -ENODEV;
+}
+
+module_init(pft_init);
+module_exit(pft_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Per-File-Tagger driver");
diff --git a/drivers/thermal/msm_thermal.c b/drivers/thermal/msm_thermal.c
index 7b623e4..81b683d 100644
--- a/drivers/thermal/msm_thermal.c
+++ b/drivers/thermal/msm_thermal.c
@@ -30,6 +30,7 @@
 #include <linux/of.h>
 #include <linux/sysfs.h>
 #include <linux/types.h>
+#include <linux/io.h>
 #include <linux/android_alarm.h>
 #include <linux/thermal.h>
 #include <mach/rpm-regulator.h>
@@ -41,6 +42,8 @@
 #define MAX_RAILS 5
 #define MAX_THRESHOLD 2
 #define MONITOR_ALL_TSENS -1
+#define BYTES_PER_FUSE_ROW  8
+#define MAX_EFUSE_VALUE  16
 
 static struct msm_thermal_data msm_thermal_info;
 static struct delayed_work check_temp_work;
@@ -89,6 +92,10 @@
 static DEFINE_MUTEX(psm_mutex);
 static DEFINE_MUTEX(ocr_mutex);
 static uint32_t min_freq_limit;
+static uint32_t default_cpu_temp_limit;
+static bool default_temp_limit_enabled;
+static bool default_temp_limit_probed;
+static bool default_temp_limit_nodes_called;
 
 enum thermal_threshold {
 	HOTPLUG_THRESHOLD_HIGH,
@@ -175,6 +182,15 @@
 	uint32_t enabled;
 };
 
+enum efuse_data {
+	EFUSE_ADDRESS = 0,
+	EFUSE_SIZE,
+	EFUSE_ROW,
+	EFUSE_START_BIT,
+	EFUSE_BIT_MASK,
+	EFUSE_DATA_MAX,
+};
+
 /* For SMPS only*/
 enum PMIC_SW_MODE {
 	PMIC_AUTO_MODE  = RPM_REGULATOR_MODE_AUTO,
@@ -394,6 +410,12 @@
 	return fail_cnt ? (-EFAULT) : ret;
 }
 
+static ssize_t default_cpu_temp_limit_show(struct kobject *kobj,
+	struct kobj_attribute *attr, char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%d\n", default_cpu_temp_limit);
+}
+
 static int vdd_rstr_en_show(
 	struct kobject *kobj, struct kobj_attribute *attr, char *buf)
 {
@@ -2239,6 +2261,38 @@
 	return ret;
 }
 
+static struct kobj_attribute default_cpu_temp_limit_attr =
+		__ATTR_RO(default_cpu_temp_limit);
+
+static int msm_thermal_add_default_temp_limit_nodes(void)
+{
+	struct kobject *module_kobj = NULL;
+	int ret = 0;
+
+	if (!default_temp_limit_probed) {
+		default_temp_limit_nodes_called = true;
+		return ret;
+	}
+	if (!default_temp_limit_enabled)
+		return ret;
+
+	module_kobj = kset_find_obj(module_kset, KBUILD_MODNAME);
+	if (!module_kobj) {
+		pr_err("cannot find kobject\n");
+		return -ENOENT;
+	}
+
+	sysfs_attr_init(&default_cpu_temp_limit_attr.attr);
+	ret = sysfs_create_file(module_kobj, &default_cpu_temp_limit_attr.attr);
+	if (ret) {
+		pr_err(
+		"cannot create default_cpu_temp_limit attribute. err:%d\n",
+		ret);
+		return ret;
+	}
+	return ret;
+}
+
 static int msm_thermal_add_vdd_rstr_nodes(void)
 {
 	struct kobject *module_kobj = NULL;
@@ -2572,6 +2626,169 @@
 	return ret;
 }
 
+static int get_efuse_temp_map(struct device_node *node,
+				int *efuse_values,
+				int *efuse_temp)
+{
+	uint32_t i, j, efuse_arr_cnt = 0;
+	int ret = 0, efuse_map_cnt = 0;
+	uint32_t data[2 * MAX_EFUSE_VALUE];
+
+	char *key = "qcom,efuse-temperature-map";
+	if (!of_get_property(node, key, &efuse_map_cnt)
+		|| efuse_map_cnt <= 0) {
+		pr_debug("Property %s not defined.\n", key);
+		return -ENODEV;
+	}
+
+	if (efuse_map_cnt % (sizeof(__be32) * 2)) {
+		pr_err("Invalid number(%d) of entry for %s\n",
+				efuse_map_cnt, key);
+		return -EINVAL;
+	}
+
+	efuse_arr_cnt = efuse_map_cnt / sizeof(__be32);
+
+	ret = of_property_read_u32_array(node, key, data, efuse_arr_cnt);
+	if (ret)
+		return -EINVAL;
+
+	efuse_map_cnt /= (sizeof(__be32) * 2);
+
+	j = 0;
+	for (i = 0; i < efuse_map_cnt; i++) {
+		efuse_values[i] = data[j++];
+		efuse_temp[i] = data[j++];
+	}
+
+	return efuse_map_cnt;
+}
+
+static int probe_thermal_efuse_read(struct device_node *node,
+			struct msm_thermal_data *data,
+			struct platform_device *pdev)
+{
+	u64 efuse_bits;
+	int ret = 0;
+	int i = 0;
+	int efuse_map_cnt = 0;
+	int efuse_data_cnt = 0;
+	char *key = NULL;
+	void __iomem *efuse_base = NULL;
+	uint32_t efuse_data[EFUSE_DATA_MAX] = {0};
+	uint32_t efuse_values[MAX_EFUSE_VALUE] = {0};
+	uint32_t efuse_temp[MAX_EFUSE_VALUE] = {0};
+	uint32_t default_temp = 0;
+	uint8_t thermal_efuse_data = 0;
+
+	if (default_temp_limit_probed)
+		goto read_efuse_exit;
+
+	key = "qcom,default-temp";
+	if (of_property_read_u32(node, key, &default_temp))
+		default_temp = 0;
+
+	default_cpu_temp_limit = default_temp;
+
+	key = "qcom,efuse-data";
+	if (!of_get_property(node, key, &efuse_data_cnt) ||
+		efuse_data_cnt <= 0) {
+		ret = -ENODEV;
+		goto read_efuse_fail;
+	}
+	efuse_data_cnt /= sizeof(__be32);
+
+	if (efuse_data_cnt != EFUSE_DATA_MAX) {
+		pr_err("Invalid number of efuse data. data cnt %d\n",
+			efuse_data_cnt);
+		ret = -EINVAL;
+		goto read_efuse_fail;
+	}
+
+	ret = of_property_read_u32_array(node, key, efuse_data,
+						efuse_data_cnt);
+	if (ret)
+		goto read_efuse_fail;
+
+	if (efuse_data[EFUSE_ADDRESS] == 0 ||
+		efuse_data[EFUSE_SIZE] == 0 ||
+		efuse_data[EFUSE_BIT_MASK] == 0) {
+		pr_err("Invalid efuse data: address:%x len:%d bitmask%x\n",
+			efuse_data[EFUSE_ADDRESS], efuse_data[EFUSE_SIZE],
+			efuse_data[EFUSE_BIT_MASK]);
+		ret = -EINVAL;
+		goto read_efuse_fail;
+	}
+
+	efuse_map_cnt = get_efuse_temp_map(node, efuse_values,
+						efuse_temp);
+	if (efuse_map_cnt <= 0 ||
+		efuse_map_cnt > (efuse_data[EFUSE_BIT_MASK] + 1)) {
+		pr_err("Invalid efuse-temperature-map. cnt%d\n",
+			efuse_map_cnt);
+		ret = -EINVAL;
+		goto read_efuse_fail;
+	}
+
+	efuse_base = ioremap(efuse_data[EFUSE_ADDRESS], efuse_data[EFUSE_SIZE]);
+	if (!efuse_base) {
+		pr_err("Unable to map efuse_addr:%x with size%d\n",
+			efuse_data[EFUSE_ADDRESS],
+			efuse_data[EFUSE_SIZE]);
+		ret = -EINVAL;
+		goto read_efuse_fail;
+	}
+
+	efuse_bits = readll_relaxed(efuse_base
+		+ efuse_data[EFUSE_ROW] * BYTES_PER_FUSE_ROW);
+
+	thermal_efuse_data = (efuse_bits >> efuse_data[EFUSE_START_BIT]) &
+						efuse_data[EFUSE_BIT_MASK];
+
+	/* Get cpu limit temp from efuse truth table */
+	for (; i < efuse_map_cnt; i++) {
+		if (efuse_values[i] == thermal_efuse_data) {
+			default_cpu_temp_limit = efuse_temp[i];
+			break;
+		}
+	}
+	if (i >= efuse_map_cnt) {
+		if (!default_temp) {
+			pr_err("No matching efuse value. value:%d\n",
+				thermal_efuse_data);
+			ret = -EINVAL;
+			goto read_efuse_fail;
+		}
+	}
+
+	pr_debug(
+	"Efuse address:0x%x [row:%d] = 0x%llx @%d:mask:0x%x = 0x%x temp:%d\n",
+		efuse_data[EFUSE_ADDRESS], efuse_data[EFUSE_ROW], efuse_bits,
+		efuse_data[EFUSE_START_BIT], efuse_data[EFUSE_BIT_MASK],
+		thermal_efuse_data, default_cpu_temp_limit);
+
+	default_temp_limit_enabled = true;
+
+read_efuse_fail:
+	if (efuse_base)
+		iounmap(efuse_base);
+	default_temp_limit_probed = true;
+	if (ret) {
+		if (!default_temp) {
+			dev_info(&pdev->dev,
+			"%s:Failed reading node=%s, key=%s. KTM continues\n",
+				__func__, node->full_name, key);
+		} else {
+			default_temp_limit_enabled = true;
+			pr_debug("Default cpu temp limit is %d\n",
+					default_cpu_temp_limit);
+			ret = 0;
+		}
+	}
+read_efuse_exit:
+	return ret;
+}
+
 static int probe_ocr(struct device_node *node, struct msm_thermal_data *data,
 		struct platform_device *pdev)
 {
@@ -2884,6 +3101,7 @@
 	ret = probe_ocr(node, &data, pdev);
 	if (ret == -EPROBE_DEFER)
 		goto fail;
+	probe_thermal_efuse_read(node, &data, pdev);
 
 	/*
 	 * In case sysfs add nodes get called before probe function.
@@ -2901,6 +3119,10 @@
 		msm_thermal_add_ocr_nodes();
 		ocr_nodes_called = false;
 	}
+	if (default_temp_limit_nodes_called) {
+		msm_thermal_add_default_temp_limit_nodes();
+		default_temp_limit_nodes_called = false;
+	}
 	msm_thermal_ioctl_init();
 	ret = msm_thermal_init(&data);
 	msm_thermal_probed = true;
@@ -2958,6 +3180,7 @@
 	msm_thermal_add_psm_nodes();
 	msm_thermal_add_vdd_rstr_nodes();
 	msm_thermal_add_ocr_nodes();
+	msm_thermal_add_default_temp_limit_nodes();
 	alarm_init(&thermal_rtc, ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP,
 			thermal_rtc_callback);
 	INIT_WORK(&timer_work, timer_work_fn);
diff --git a/drivers/tty/serial/msm_serial_hs.c b/drivers/tty/serial/msm_serial_hs.c
index a701ec8..6078ef1 100644
--- a/drivers/tty/serial/msm_serial_hs.c
+++ b/drivers/tty/serial/msm_serial_hs.c
@@ -2938,6 +2938,7 @@
 		return ERR_PTR(-ENOMEM);
 	}
 
+	pdev->id = of_alias_get_id(pdev->dev.of_node, "uart");
 	/* UART TX GPIO */
 	pdata->uart_tx_gpio = of_get_named_gpio(node,
 					"qcom,tx-gpio", 0);
@@ -3201,13 +3202,47 @@
 	return rc;
 }
 
-#define BLSP_UART_NR	12
-static int deviceid[BLSP_UART_NR] = {0};
-static atomic_t msm_serial_hs_next_id = ATOMIC_INIT(0);
+
+static bool deviceid[UARTDM_NR] = {0};
+/*
+ * The mutex synchronizes grabbing next free device number
+ * both in case of an alias being used or not. When alias is
+ * used, the msm_hs_dt_to_pdata gets it and the boolean array
+ * is accordingly updated with device_id_set_used. If no alias
+ * is used, then device_id_grab_next_free sets that array.
+ */
+static DEFINE_MUTEX(mutex_next_device_id);
+
+static int device_id_grab_next_free(void)
+{
+	int i;
+	int ret = -ENODEV;
+	mutex_lock(&mutex_next_device_id);
+	for (i = 0; i < UARTDM_NR; i++)
+		if (!deviceid[i]) {
+			ret = i;
+			deviceid[i] = true;
+			break;
+		}
+	mutex_unlock(&mutex_next_device_id);
+	return ret;
+}
+
+static int device_id_set_used(int index)
+{
+	int ret = 0;
+	mutex_lock(&mutex_next_device_id);
+	if (deviceid[index])
+		ret = -ENODEV;
+	else
+		deviceid[index] = true;
+	mutex_unlock(&mutex_next_device_id);
+	return ret;
+}
 
 static int __devinit msm_hs_probe(struct platform_device *pdev)
 {
-	int ret = 0, alias_num = -1;
+	int ret = 0;
 	struct uart_port *uport;
 	struct msm_hs_port *msm_uport;
 	struct resource *core_resource;
@@ -3224,33 +3259,21 @@
 		if (IS_ERR(pdata))
 			return PTR_ERR(pdata);
 
-		if (pdev->id == -1) {
-			pdev->id = atomic_inc_return(&msm_serial_hs_next_id)-1;
-			deviceid[pdev->id] = 1;
-		}
-
-		/* Use alias from device tree if present
-		 * Alias is used as an optional property
-		 */
-		alias_num = of_alias_get_id(pdev->dev.of_node, "uart");
-		if (alias_num >= 0) {
-			/* If alias_num is between 0 and 11, check that it not
-			 * equal to previous incremented pdev-ids. If it is
-			 * equal to previous pdev.ids , fail deviceprobe.
-			 */
-			if (alias_num < BLSP_UART_NR) {
-				if (deviceid[alias_num] == 0) {
-					pdev->id = alias_num;
-				} else {
-					MSM_HS_ERR("alias_num=%d already used\n",
-								alias_num);
-					return -EINVAL;
-				}
-			} else {
-				pdev->id = alias_num;
+		if (pdev->id < 0) {
+			pdev->id = device_id_grab_next_free();
+			if (pdev->id < 0) {
+				dev_err(&pdev->dev,
+					"Error grabbing next free device id");
+				return pdev->id;
+			}
+		} else {
+			ret = device_id_set_used(pdev->id);
+			if (ret < 0) {
+				dev_err(&pdev->dev, "%d alias taken",
+					pdev->id);
+				return ret;
 			}
 		}
-
 		pdev->dev.platform_data = pdata;
 	}
 
diff --git a/drivers/usb/dwc3/dwc3_otg.c b/drivers/usb/dwc3/dwc3_otg.c
index e373b9b..e3d339c 100644
--- a/drivers/usb/dwc3/dwc3_otg.c
+++ b/drivers/usb/dwc3/dwc3_otg.c
@@ -552,7 +552,7 @@
 			dotg->charger->chg_type == DWC3_PROPRIETARY_CHARGER)
 		power_supply_type = POWER_SUPPLY_TYPE_USB_DCP;
 	else
-		power_supply_type = POWER_SUPPLY_TYPE_BATTERY;
+		power_supply_type = POWER_SUPPLY_TYPE_UNKNOWN;
 
 	power_supply_set_supply_type(dotg->psy, power_supply_type);
 
diff --git a/drivers/usb/gadget/android.c b/drivers/usb/gadget/android.c
index 6b01472..4de97f56 100644
--- a/drivers/usb/gadget/android.c
+++ b/drivers/usb/gadget/android.c
@@ -2723,6 +2723,8 @@
 	struct android_configuration	*conf;
 	int value = -EOPNOTSUPP;
 	unsigned long flags;
+	bool do_work = false;
+	bool prev_configured = false;
 
 	req->zero = 0;
 	req->complete = composite_setup_complete;
@@ -2741,6 +2743,12 @@
 			}
 		}
 
+	/*
+	 * skip the  work when 2nd set config arrives
+	 * with same value from the host.
+	 */
+	if (cdev->config)
+		prev_configured = true;
 	/* Special case the accessory function.
 	 * It needs to handle control requests before it is enabled.
 	 */
@@ -2753,13 +2761,15 @@
 	spin_lock_irqsave(&cdev->lock, flags);
 	if (!dev->connected) {
 		dev->connected = 1;
-		schedule_work(&dev->work);
+		do_work = true;
 	} else if (c->bRequest == USB_REQ_SET_CONFIGURATION &&
 						cdev->config) {
-		schedule_work(&dev->work);
+		if (!prev_configured)
+			do_work = true;
 	}
 	spin_unlock_irqrestore(&cdev->lock, flags);
-
+	if (do_work)
+		schedule_work(&dev->work);
 	return value;
 }
 
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index 7d63bf9..b13e8e5 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -604,6 +604,16 @@
 	unsigned		power = gadget_is_otg(gadget) ? 8 : 100;
 	int			tmp;
 
+	/*
+	 * ignore 2nd time SET_CONFIGURATION
+	 * only for same config value twice.
+	 */
+	if (cdev->config && (cdev->config->bConfigurationValue == number)) {
+		DBG(cdev, "already in the same config with value %d\n",
+				number);
+		return 0;
+	}
+
 	if (number) {
 		list_for_each_entry(c, &cdev->configs, list) {
 			if (c->bConfigurationValue == number) {
diff --git a/drivers/usb/host/ehci-msm2.c b/drivers/usb/host/ehci-msm2.c
index ebb226c..f319238 100644
--- a/drivers/usb/host/ehci-msm2.c
+++ b/drivers/usb/host/ehci-msm2.c
@@ -82,6 +82,7 @@
 	bool					wakeup_irq_enabled;
 	int					wakeup_irq;
 	enum usb_vdd_type			vdd_type;
+	void __iomem				*usb_phy_ctrl_reg;
 };
 
 static inline struct msm_hcd *hcd_to_mhcd(struct usb_hcd *hcd)
@@ -497,6 +498,9 @@
 		if (time_after(jiffies, timeout)) {
 			dev_err(mhcd->dev, "msm_ulpi_read: timeout %08x\n",
 				readl_relaxed(USB_ULPI_VIEWPORT));
+			dev_err(mhcd->dev, "PORTSC: %08x USBCMD: %08x\n",
+				readl_relaxed(USB_PORTSC),
+				readl_relaxed(USB_USBCMD));
 			return -ETIMEDOUT;
 		}
 		udelay(1);
@@ -521,6 +525,9 @@
 	while (readl_relaxed(USB_ULPI_VIEWPORT) & ULPI_RUN) {
 		if (time_after(jiffies, timeout)) {
 			dev_err(mhcd->dev, "msm_ulpi_write: timeout\n");
+			dev_err(mhcd->dev, "PORTSC: %08x USBCMD: %08x\n",
+				readl_relaxed(USB_PORTSC),
+				readl_relaxed(USB_USBCMD));
 			return -ETIMEDOUT;
 		}
 		udelay(1);
@@ -572,13 +579,13 @@
 	struct msm_usb_host_platform_data *pdata;
 	u32 val;
 	int ret;
-	int retries;
 
 	ret = msm_ehci_link_clk_reset(mhcd, 1);
 	if (ret)
 		return ret;
 
-	usleep_range(10, 12);
+	/* Minimum 10msec delay for block reset as per hardware spec */
+	usleep_range(10000, 12000);
 
 	ret = msm_ehci_link_clk_reset(mhcd, 0);
 	if (ret)
@@ -592,29 +599,34 @@
 	val = readl_relaxed(USB_PORTSC) & ~PORTSC_PTS_MASK;
 	writel_relaxed(val | PORTSC_PTS_ULPI, USB_PORTSC);
 
-	for (retries = 3; retries > 0; retries--) {
-		ret = msm_ulpi_write(mhcd, ULPI_FUNC_CTRL_SUSPENDM,
-				ULPI_CLR(ULPI_FUNC_CTRL));
-		if (!ret)
-			break;
-	}
-	if (!retries)
-		return -ETIMEDOUT;
-
-	/* Wakeup the PHY with a reg-access for calibration */
-	for (retries = 3; retries > 0; retries--) {
-		ret = msm_ulpi_read(mhcd, ULPI_DEBUG);
-		if (ret != -ETIMEDOUT)
-			break;
-	}
-	if (!retries)
-		return -ETIMEDOUT;
-
 	dev_info(mhcd->dev, "phy_reset: success\n");
 
 	return 0;
 }
 
+static void usb_phy_reset(struct msm_hcd *mhcd)
+{
+	u32 val;
+
+	/* Assert USB PHY_PON */
+	val =  readl_relaxed(mhcd->usb_phy_ctrl_reg);
+	val &= ~PHY_POR_BIT_MASK;
+	val |= PHY_POR_ASSERT;
+	writel_relaxed(val, mhcd->usb_phy_ctrl_reg);
+
+	/* wait for minimum 10 microseconds as suggested in hardware spec */
+	usleep_range(10, 15);
+
+	/* Deassert USB PHY_PON */
+	val =  readl_relaxed(mhcd->usb_phy_ctrl_reg);
+	val &= ~PHY_POR_BIT_MASK;
+	val |= PHY_POR_DEASSERT;
+	writel_relaxed(val, mhcd->usb_phy_ctrl_reg);
+
+	/* Ensure that RESET operation is completed. */
+	mb();
+}
+
 #define LINK_RESET_TIMEOUT_USEC		(250 * 1000)
 static int msm_hsusb_reset(struct msm_hcd *mhcd)
 {
@@ -649,6 +661,9 @@
 		writel_relaxed(readl_relaxed(USB_PHY_CTRL2) | (1<<16),
 								USB_PHY_CTRL2);
 
+	/* Reset USB PHY after performing USB Link RESET */
+	usb_phy_reset(mhcd);
+
 	msleep(100);
 
 	writel_relaxed(0x0, USB_AHBBURST);
@@ -1523,6 +1538,13 @@
 		goto disable_ldo;
 	}
 
+	pdata = mhcd->dev->platform_data;
+
+	if (pdata && pdata->use_sec_phy)
+		mhcd->usb_phy_ctrl_reg = USB_PHY_CTRL2;
+	else
+		mhcd->usb_phy_ctrl_reg = USB_PHY_CTRL;
+
 	ret = msm_hsusb_reset(mhcd);
 	if (ret) {
 		dev_err(&pdev->dev, "hsusb PHY initialization failed\n");
@@ -1535,7 +1557,6 @@
 		goto vbus_deinit;
 	}
 
-	pdata = mhcd->dev->platform_data;
 	if (pdata && (!pdata->dock_connect_irq ||
 				!irq_read_line(pdata->dock_connect_irq)))
 		msm_ehci_vbus_power(mhcd, 1);
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c
index c4e5962..ea724d6 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -2438,6 +2438,11 @@
 		 * Notify the charger type to power supply
 		 * owner as soon as we determine the charger.
 		 */
+		if (motg->chg_type == USB_DCP_CHARGER &&
+			motg->ext_chg_opened) {
+				init_completion(&motg->ext_chg_wait);
+				motg->ext_chg_active = DEFAULT;
+		}
 		msm_otg_notify_chg_type(motg);
 		msm_chg_block_off(motg);
 		msm_chg_enable_aca_det(motg);
@@ -2541,7 +2546,7 @@
 	 * detection is completed.
 	 */
 
-	if (motg->ext_chg_active) {
+	if (motg->ext_chg_active == ACTIVE) {
 
 do_wait:
 		pr_debug("before msm_otg ext chg wait\n");
@@ -2550,7 +2555,7 @@
 				msecs_to_jiffies(3000));
 		if (!t)
 			pr_err("msm_otg ext chg wait timeout\n");
-		else if (motg->ext_chg_active)
+		else if (motg->ext_chg_active == ACTIVE)
 			goto do_wait;
 		else
 			pr_debug("msm_otg ext chg wait done\n");
@@ -2627,11 +2632,6 @@
 				case USB_DCP_CHARGER:
 					/* Enable VDP_SRC */
 					ulpi_write(otg->phy, 0x2, 0x85);
-					if (motg->ext_chg_opened) {
-						init_completion(
-							&motg->ext_chg_wait);
-						motg->ext_chg_active = true;
-					}
 					/* fall through */
 				case USB_PROPRIETARY_CHARGER:
 					msm_otg_notify_charger(motg,
@@ -2701,6 +2701,8 @@
 			motg->chg_type = USB_INVALID_CHARGER;
 			msm_otg_notify_charger(motg, 0);
 			if (dcp) {
+				if (motg->ext_chg_active == DEFAULT)
+					motg->ext_chg_active = INACTIVE;
 				msm_otg_wait_for_ext_chg_done(motg);
 				/* Turn off VDP_SRC */
 				ulpi_write(otg->phy, 0x2, 0x86);
@@ -4054,7 +4056,7 @@
 		pr_debug("%s: LPM block request %d\n", __func__, val);
 		if (val) { /* block LPM */
 			if (motg->chg_type == USB_DCP_CHARGER) {
-				motg->ext_chg_active = true;
+				motg->ext_chg_active = ACTIVE;
 				/*
 				 * If device is already suspended, resume it.
 				 * The PM usage counter is incremented in
@@ -4067,12 +4069,12 @@
 				else
 					pm_runtime_get_sync(motg->phy.dev);
 			} else {
-				motg->ext_chg_active = false;
+				motg->ext_chg_active = INACTIVE;
 				complete(&motg->ext_chg_wait);
 				ret = -ENODEV;
 			}
 		} else {
-			motg->ext_chg_active = false;
+			motg->ext_chg_active = INACTIVE;
 			complete(&motg->ext_chg_wait);
 			/*
 			 * If usb cable is disconnected and then userspace
@@ -4910,7 +4912,7 @@
 	if (phy->state == OTG_STATE_UNDEFINED)
 		return -EAGAIN;
 
-	if (motg->ext_chg_active) {
+	if (motg->ext_chg_active == DEFAULT) {
 		dev_dbg(dev, "Deferring LPM\n");
 		/*
 		 * Charger detection may happen in user space.
diff --git a/drivers/video/msm/mdss/mdp3_ppp.c b/drivers/video/msm/mdss/mdp3_ppp.c
index afa0b7c..462f1d8 100644
--- a/drivers/video/msm/mdss/mdp3_ppp.c
+++ b/drivers/video/msm/mdss/mdp3_ppp.c
@@ -863,24 +863,6 @@
 	if (unlikely(req->dst_rect.h == 0 || req->dst_rect.w == 0))
 		return 0;
 
-	if (req->flags & MDP_ROT_90) {
-		if (((req->dst_rect.h == 1) && ((req->src_rect.w != 1) ||
-			(req->dst_rect.w == req->src_rect.h))) ||
-			((req->dst_rect.w == 1) && ((req->src_rect.h != 1) ||
-			(req->dst_rect.h == req->src_rect.w)))) {
-			pr_err("mdp_ppp: error scaling when size is 1!\n");
-			return -EINVAL;
-		}
-	} else {
-		if (((req->dst_rect.w == 1) && ((req->src_rect.w != 1) ||
-			(req->dst_rect.h == req->src_rect.h))) ||
-			((req->dst_rect.h == 1) && ((req->src_rect.h != 1) ||
-			(req->dst_rect.w == req->src_rect.w)))) {
-			pr_err("mdp_ppp: error scaling when size is 1!\n");
-			return -EINVAL;
-		}
-	}
-
 	/* MDP width split workaround */
 	remainder = (req->dst_rect.w) % 16;
 	ret = ppp_get_bpp(req->dst.format, mfd->fb_imgType);
diff --git a/drivers/video/msm/mdss/mdss.h b/drivers/video/msm/mdss/mdss.h
index 72cceaa..afa0bc1 100644
--- a/drivers/video/msm/mdss/mdss.h
+++ b/drivers/video/msm/mdss/mdss.h
@@ -220,7 +220,7 @@
 void mdss_enable_irq(struct mdss_hw *hw);
 void mdss_disable_irq(struct mdss_hw *hw);
 void mdss_disable_irq_nosync(struct mdss_hw *hw);
-void mdss_bus_bandwidth_ctrl(int enable);
+int mdss_bus_bandwidth_ctrl(int enable);
 
 static inline struct ion_client *mdss_get_ionclient(void)
 {
diff --git a/drivers/video/msm/mdss/mdss_debug.h b/drivers/video/msm/mdss/mdss_debug.h
index e2c9edd..684bd45 100644
--- a/drivers/video/msm/mdss/mdss_debug.h
+++ b/drivers/video/msm/mdss/mdss_debug.h
@@ -16,6 +16,7 @@
 
 #include <stdarg.h>
 #include "mdss.h"
+#include "mdss_mdp_trace.h"
 
 #define MISR_POLL_SLEEP		2000
 #define MISR_POLL_TIMEOUT	32000
@@ -30,6 +31,13 @@
 #define MDSS_XLOG_TOUT_HANDLER(...)	\
 	mdss_xlog_tout_handler(__func__, ##__VA_ARGS__, XLOG_TOUT_DATA_LIMITER)
 
+#define ATRACE_END(name) trace_tracing_mark_write(current->tgid, name, 0)
+#define ATRACE_BEGIN(name) trace_tracing_mark_write(current->tgid, name, 1)
+#define ATRACE_FUNC() ATRACE_BEGIN(__func__)
+
+#define ATRACE_INT(name, value) \
+	trace_mdp_trace_counter(current->tgid, name, value)
+
 #ifdef CONFIG_DEBUG_FS
 struct mdss_debug_base {
 	struct mdss_debug_data *mdd;
diff --git a/drivers/video/msm/mdss/mdss_dsi.c b/drivers/video/msm/mdss/mdss_dsi.c
index 40a458c..e724d68 100644
--- a/drivers/video/msm/mdss/mdss_dsi.c
+++ b/drivers/video/msm/mdss/mdss_dsi.c
@@ -1455,6 +1455,8 @@
 		pinfo->new_fps = pinfo->mipi.frame_rate;
 	}
 
+	pinfo->panel_max_fps = mdss_panel_get_framerate(pinfo);
+	pinfo->panel_max_vtotal = mdss_panel_get_vtotal(pinfo);
 	ctrl_pdata->disp_en_gpio = of_get_named_gpio(ctrl_pdev->dev.of_node,
 		"qcom,platform-enable-gpio", 0);
 
diff --git a/drivers/video/msm/mdss/mdss_dsi.h b/drivers/video/msm/mdss/mdss_dsi.h
index 962599d..f79391a 100644
--- a/drivers/video/msm/mdss/mdss_dsi.h
+++ b/drivers/video/msm/mdss/mdss_dsi.h
@@ -233,6 +233,7 @@
 
 #define DSI_EV_PLL_UNLOCKED		0x0001
 #define DSI_EV_MDP_FIFO_UNDERFLOW	0x0002
+#define DSI_EV_DSI_FIFO_EMPTY		0x0003
 #define DSI_EV_MDP_BUSY_RELEASE		0x80000000
 
 struct mdss_dsi_ctrl_pdata {
diff --git a/drivers/video/msm/mdss/mdss_dsi_host.c b/drivers/video/msm/mdss/mdss_dsi_host.c
index 95e7c6e..74d2739 100644
--- a/drivers/video/msm/mdss/mdss_dsi_host.c
+++ b/drivers/video/msm/mdss/mdss_dsi_host.c
@@ -252,6 +252,8 @@
 
 	if (pinfo->mode == DSI_VIDEO_MODE) {
 		data = 0;
+		if (pinfo->last_line_interleave_en)
+			data |= BIT(31);
 		if (pinfo->pulse_mode_hsa_he)
 			data |= BIT(28);
 		if (pinfo->hfp_power_stop)
@@ -1262,7 +1264,11 @@
 	 * also, axi bus bandwidth need since dsi controller will
 	 * fetch dcs commands from axi bus
 	 */
-	mdss_bus_bandwidth_ctrl(1);
+	ret = mdss_bus_bandwidth_ctrl(1);
+	if (ret) {
+		pr_err("bus bandwidth request failed ret=%d\n", ret);
+		goto need_lock;
+	}
 
 	pr_debug("%s:  from_mdp=%d pid=%d\n", __func__, from_mdp, current->pid);
 	mdss_dsi_clk_ctrl(ctrl, DSI_ALL_CLKS, 1);
@@ -1380,6 +1386,9 @@
 			}
 		}
 
+		if (todo & DSI_EV_DSI_FIFO_EMPTY)
+			mdss_dsi_sw_reset_restore(ctrl);
+
 		if (todo & DSI_EV_MDP_BUSY_RELEASE) {
 			spin_lock_irqsave(&ctrl->mdp_lock, flag);
 			ctrl->mdp_busy = false;
@@ -1452,7 +1461,7 @@
 
 	status = MIPI_INP(base + 0x000c);/* DSI_FIFO_STATUS */
 
-	/* fifo underflow, overflow */
+	/* fifo underflow, overflow and empty*/
 	if (status & 0xcccc4489) {
 		MIPI_OUTP(base + 0x000c, status);
 		pr_err("%s: status=%x\n", __func__, status);
@@ -1460,6 +1469,8 @@
 			dsi_send_events(ctrl, DSI_EV_MDP_FIFO_UNDERFLOW);
 			MDSS_XLOG_TOUT_HANDLER("mdp", "dsi0", "dsi1",
 						"edp", "hdmi", "panic");
+		if (status & 0x11110000) /* DLN_FIFO_EMPTY */
+			dsi_send_events(ctrl, DSI_EV_DSI_FIFO_EMPTY);
 	}
 }
 
diff --git a/drivers/video/msm/mdss/mdss_dsi_panel.c b/drivers/video/msm/mdss/mdss_dsi_panel.c
index f58e2a1..7575fe3 100644
--- a/drivers/video/msm/mdss/mdss_dsi_panel.c
+++ b/drivers/video/msm/mdss/mdss_dsi_panel.c
@@ -923,6 +923,8 @@
 		"qcom,mdss-dsi-hsa-power-mode");
 	pinfo->mipi.hbp_power_stop = of_property_read_bool(np,
 		"qcom,mdss-dsi-hbp-power-mode");
+	pinfo->mipi.last_line_interleave_en = of_property_read_bool(np,
+		"qcom,mdss-dsi-last-line-interleave");
 	pinfo->mipi.bllp_power_stop = of_property_read_bool(np,
 		"qcom,mdss-dsi-bllp-power-mode");
 	pinfo->mipi.eof_bllp_power_stop = of_property_read_bool(
diff --git a/drivers/video/msm/mdss/mdss_fb.c b/drivers/video/msm/mdss/mdss_fb.c
index 4395d1b..c14f936 100644
--- a/drivers/video/msm/mdss/mdss_fb.c
+++ b/drivers/video/msm/mdss/mdss_fb.c
@@ -815,17 +815,17 @@
 {
 	struct mdss_panel_data *pdata;
 
+	mutex_lock(&mfd->bl_lock);
 	if (mfd->unset_bl_level && !mfd->bl_updated) {
 		pdata = dev_get_platdata(&mfd->pdev->dev);
 		if ((pdata) && (pdata->set_backlight)) {
-			mutex_lock(&mfd->bl_lock);
 			mfd->bl_level = mfd->unset_bl_level;
 			pdata->set_backlight(pdata, mfd->bl_level);
 			mfd->bl_level_old = mfd->unset_bl_level;
-			mutex_unlock(&mfd->bl_lock);
 			mfd->bl_updated = 1;
 		}
 	}
+	mutex_unlock(&mfd->bl_lock);
 }
 
 static int mdss_fb_blank_sub(int blank_mode, struct fb_info *info,
@@ -880,7 +880,9 @@
 			mfd->op_enable = false;
 			curr_pwr_state = mfd->panel_power_on;
 			mfd->panel_power_on = false;
+			mutex_lock(&mfd->bl_lock);
 			mfd->bl_updated = 0;
+			mutex_unlock(&mfd->bl_lock);
 
 			ret = mfd->mdp.off_fnc(mfd);
 			if (ret)
diff --git a/drivers/video/msm/mdss/mdss_mdp.c b/drivers/video/msm/mdss/mdss_mdp.c
index 037a183..bf151f4 100644
--- a/drivers/video/msm/mdss/mdss_mdp.c
+++ b/drivers/video/msm/mdss/mdss_mdp.c
@@ -627,18 +627,29 @@
  * Function place bus bandwidth request to allocate saved bandwidth
  * if enabled or free bus bandwidth allocation if disabled.
  * Bus bandwidth is required by mdp.For dsi, it only requires to send
- * dcs coammnd.
+ * dcs coammnd. It returns error if bandwidth request fails.
  */
-void mdss_bus_bandwidth_ctrl(int enable)
+int mdss_bus_bandwidth_ctrl(int enable)
 {
 	struct mdss_data_type *mdata = mdss_mdp_get_mdata();
 	static int bus_bw_cnt;
 	int changed = 0;
+	int rc = 0;
 
 	mutex_lock(&bus_bw_lock);
 	if (enable) {
-		if (bus_bw_cnt == 0)
+		if (bus_bw_cnt == 0) {
 			changed++;
+			if (!mdata->handoff_pending) {
+				rc = mdss_iommu_attach(mdata);
+				if (rc) {
+					pr_err("iommu attach failed rc=%d\n",
+									rc);
+					goto end;
+				}
+			}
+		}
+
 		bus_bw_cnt++;
 	} else {
 		if (bus_bw_cnt) {
@@ -663,12 +674,12 @@
 			pm_runtime_get_sync(&mdata->pdev->dev);
 			msm_bus_scale_client_update_request(
 				mdata->bus_hdl, mdata->curr_bw_uc_idx);
-			if (!mdata->handoff_pending)
-				mdss_iommu_attach(mdata);
 		}
 	}
 
+end:
 	mutex_unlock(&bus_bw_lock);
+	return rc;
 }
 EXPORT_SYMBOL(mdss_bus_bandwidth_ctrl);
 
@@ -676,7 +687,7 @@
 {
 	struct mdss_data_type *mdata = mdss_mdp_get_mdata();
 	static int mdp_clk_cnt;
-	int changed = 0;
+	int changed = 0, rc;
 
 	mutex_lock(&mdp_clk_lock);
 	if (enable) {
@@ -709,7 +720,9 @@
 		if (mdata->vsync_ena)
 			mdss_mdp_clk_update(MDSS_CLK_MDP_VSYNC, enable);
 
-		mdss_bus_bandwidth_ctrl(enable);
+		rc = mdss_bus_bandwidth_ctrl(enable);
+		if (rc)
+			pr_err("bus bandwidth control failed rc=%d", rc);
 
 		if (!enable)
 			pm_runtime_put(&mdata->pdev->dev);
@@ -794,15 +807,14 @@
 {
 	struct iommu_domain *domain;
 	struct mdss_iommu_map_type *iomap;
-	int i;
+	int i, rc = 0;
 
 	mutex_lock(&mdp_iommu_lock);
 	MDSS_XLOG(mdata->iommu_attached);
 
 	if (mdata->iommu_attached) {
 		pr_debug("mdp iommu already attached\n");
-		mutex_unlock(&mdp_iommu_lock);
-		return 0;
+		goto end;
 	}
 
 	for (i = 0; i < MDSS_IOMMU_MAX_DOMAIN; i++) {
@@ -814,13 +826,23 @@
 				iomap->client_name, iomap->ctx_name);
 			continue;
 		}
-		iommu_attach_device(domain, iomap->ctx);
+
+		rc = iommu_attach_device(domain, iomap->ctx);
+		if (rc) {
+			WARN(1, "mdp::iommu device attach failed rc:%d\n", rc);
+			for (i--; i >= 0; i--) {
+				iomap = mdata->iommu_map + i;
+				iommu_detach_device(domain, iomap->ctx);
+			}
+			goto end;
+		}
 	}
 
 	mdata->iommu_attached = true;
+end:
 	mutex_unlock(&mdp_iommu_lock);
 
-	return 0;
+	return rc;
 }
 
 int mdss_iommu_dettach(struct mdss_data_type *mdata)
@@ -2558,22 +2580,31 @@
  * MDSS GDSC can be voted off during idle-screen usecase for MIPI DSI command
  * mode displays with Ultra-Low Power State (ULPS) feature enabled. Upon
  * subsequent frame update, MDSS GDSC needs to turned back on and hw state
- * needs to be restored.
+ * needs to be restored. It returns error if footswitch control API
+ * fails.
  */
-void mdss_mdp_footswitch_ctrl_ulps(int on, struct device *dev)
+int mdss_mdp_footswitch_ctrl_ulps(int on, struct device *dev)
 {
 	struct mdss_data_type *mdata = mdss_mdp_get_mdata();
+	int rc = 0;
 
 	pr_debug("called on=%d\n", on);
 	if (on) {
 		pm_runtime_get_sync(dev);
-		mdss_iommu_attach(mdata);
+		rc = mdss_iommu_attach(mdata);
+		if (rc) {
+			pr_err("mdss iommu attach failed rc=%d\n", rc);
+			goto end;
+		}
 		mdss_hw_init(mdata);
 		mdata->ulps = false;
 	} else {
 		mdata->ulps = true;
 		pm_runtime_put_sync(dev);
 	}
+
+end:
+	return rc;
 }
 
 static inline int mdss_mdp_suspend_sub(struct mdss_data_type *mdata)
diff --git a/drivers/video/msm/mdss/mdss_mdp.h b/drivers/video/msm/mdss/mdss_mdp.h
index 33a0806..8e83f51 100644
--- a/drivers/video/msm/mdss/mdss_mdp.h
+++ b/drivers/video/msm/mdss/mdss_mdp.h
@@ -440,6 +440,7 @@
 
 	struct mdss_data_type *mdata;
 	struct mutex ov_lock;
+        struct mutex dfps_lock;
 	struct mdss_mdp_ctl *ctl;
 	struct mdss_mdp_wb *wb;
 	struct list_head overlay_list;
@@ -735,7 +736,7 @@
 int mdss_mdp_wb_set_secure(struct msm_fb_data_type *mfd, int enable);
 int mdss_mdp_wb_get_secure(struct msm_fb_data_type *mfd, uint8_t *enable);
 void mdss_mdp_ctl_restore(struct mdss_mdp_ctl *ctl);
-void mdss_mdp_footswitch_ctrl_ulps(int on, struct device *dev);
+int mdss_mdp_footswitch_ctrl_ulps(int on, struct device *dev);
 
 int mdss_mdp_pipe_program_pixel_extn(struct mdss_mdp_pipe *pipe);
 #define mfd_to_mdp5_data(mfd) (mfd->mdp.private1)
diff --git a/drivers/video/msm/mdss/mdss_mdp_ctl.c b/drivers/video/msm/mdss/mdss_mdp_ctl.c
index 3449308..4b7f89d 100644
--- a/drivers/video/msm/mdss/mdss_mdp_ctl.c
+++ b/drivers/video/msm/mdss/mdss_mdp_ctl.c
@@ -24,6 +24,7 @@
 #include "mdss_mdp.h"
 #include "mdss_debug.h"
 #include "mdss_mdp_trace.h"
+#include "mdss_debug.h"
 
 static void mdss_mdp_xlog_mixer_reg(struct mdss_mdp_ctl *ctl);
 static inline u64 fudge_factor(u64 val, u32 numer, u32 denom)
@@ -339,8 +340,13 @@
 		struct mdss_panel_info *pinfo;
 
 		pinfo = &mixer->ctl->panel_data->panel_info;
-		fps = mdss_panel_get_framerate(pinfo);
-		v_total = mdss_panel_get_vtotal(pinfo);
+		if (pinfo->type == MIPI_VIDEO_PANEL) {
+			fps = pinfo->panel_max_fps;
+			v_total = pinfo->panel_max_vtotal;
+		} else {
+			fps = mdss_panel_get_framerate(pinfo);
+			v_total = mdss_panel_get_vtotal(pinfo);
+		}
 		xres = pinfo->xres;
 		is_fbc = pinfo->fbc.enabled;
 	} else {
@@ -460,8 +466,13 @@
 	if (!mixer->rotator_mode) {
 		if (mixer->type == MDSS_MDP_MIXER_TYPE_INTF) {
 			pinfo = &mixer->ctl->panel_data->panel_info;
-			fps = mdss_panel_get_framerate(pinfo);
-			v_total = mdss_panel_get_vtotal(pinfo);
+			if (pinfo->type == MIPI_VIDEO_PANEL) {
+				fps = pinfo->panel_max_fps;
+				v_total = pinfo->panel_max_vtotal;
+			} else {
+				fps = mdss_panel_get_framerate(pinfo);
+				v_total = mdss_panel_get_vtotal(pinfo);
+			}
 
 			if (pinfo->type == WRITEBACK_PANEL)
 				pinfo = NULL;
@@ -820,7 +831,7 @@
 
 	if (!ctl || !ctl->mdata)
 		return;
-
+	ATRACE_BEGIN(__func__);
 	mdata = ctl->mdata;
 	for (i = 0; i < mdata->nctl; i++) {
 		struct mdss_mdp_ctl *ctl;
@@ -835,8 +846,10 @@
 	bus_ab_quota = apply_fudge_factor(bw_sum_of_intfs,
 		&mdss_res->ab_factor);
 	trace_mdp_perf_update_bus(bus_ab_quota, bus_ib_quota);
+	ATRACE_INT("bus_quota", bus_ib_quota);
 	mdss_mdp_bus_scale_set_quota(bus_ab_quota, bus_ib_quota);
 	pr_debug("ab=%llu ib=%llu\n", bus_ab_quota, bus_ib_quota);
+	ATRACE_END(__func__);
 }
 
 /**
@@ -919,7 +932,7 @@
 
 	if (!ctl || !ctl->mdata)
 		return;
-
+	ATRACE_BEGIN(__func__);
 	mutex_lock(&mdss_mdp_ctl_lock);
 
 	mdata = ctl->mdata;
@@ -978,11 +991,13 @@
 		}
 
 		clk_rate  = mdss_mdp_select_clk_lvl(ctl, clk_rate);
+		ATRACE_INT("mdp_clk", clk_rate);
 		mdss_mdp_set_clk_rate(clk_rate);
 		pr_debug("update clk rate = %d HZ\n", clk_rate);
 	}
 
 	mutex_unlock(&mdss_mdp_ctl_lock);
+	ATRACE_END(__func__);
 }
 
 static struct mdss_mdp_ctl *mdss_mdp_ctl_alloc(struct mdss_data_type *mdata,
@@ -2489,8 +2504,10 @@
 		return 0;
 	}
 
+	ATRACE_BEGIN("wait_fnc");
 	if (ctl->wait_fnc)
 		ret = ctl->wait_fnc(ctl, NULL);
+	ATRACE_END("wait_fnc");
 
 	trace_mdp_commit(ctl);
 
@@ -2559,13 +2576,16 @@
 
 	if (is_bw_released || mixer1_changed || mixer2_changed
 			|| ctl->force_screen_state) {
+		ATRACE_BEGIN("prepare_fnc");
 		if (ctl->prepare_fnc)
 			ret = ctl->prepare_fnc(ctl, arg);
+		ATRACE_END("prepare_fnc");
 		if (ret) {
 			pr_err("error preparing display\n");
 			goto done;
 		}
 
+		ATRACE_BEGIN("mixer_programming");
 		mdss_mdp_ctl_perf_update(ctl, 1);
 
 		if (mixer1_changed)
@@ -2581,21 +2601,29 @@
 					sctl->opmode);
 			sctl->flush_bits |= BIT(17);
 		}
+		ATRACE_END("mixer_programming");
 	}
 
+	ATRACE_BEGIN("frame_ready");
 	if (!ctl->shared_lock)
 		mdss_mdp_ctl_notify(ctl, MDP_NOTIFY_FRAME_READY);
+	ATRACE_END("frame_ready");
 
+	ATRACE_BEGIN("wait_pingpong");
 	if (ctl->wait_pingpong)
 		ctl->wait_pingpong(ctl, NULL);
+	ATRACE_END("wait_pingpong");
 
 	ctl->roi_bkup.w = ctl->roi.w;
 	ctl->roi_bkup.h = ctl->roi.h;
 
+	ATRACE_BEGIN("postproc_programming");
 	if (ctl->mfd && ctl->mfd->dcm_state != DTM_ENTER)
 		/* postprocessing setup, including dspp */
 		mdss_mdp_pp_setup_locked(ctl);
+	ATRACE_END("postproc_programming");
 
+	ATRACE_BEGIN("flush_kickoff");
 	mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_FLUSH, ctl->flush_bits);
 	if (sctl) {
 		mdss_mdp_ctl_write(sctl, MDSS_MDP_REG_CTL_FLUSH,
@@ -2612,6 +2640,7 @@
 		pr_warn("error displaying frame\n");
 
 	ctl->play_cnt++;
+	ATRACE_END("flush_kickoff");
 
 done:
 	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
diff --git a/drivers/video/msm/mdss/mdss_mdp_hwio.h b/drivers/video/msm/mdss/mdss_mdp_hwio.h
index c11b438..ea41159 100644
--- a/drivers/video/msm/mdss/mdss_mdp_hwio.h
+++ b/drivers/video/msm/mdss/mdss_mdp_hwio.h
@@ -519,7 +519,7 @@
 #define MDSS_MDP_REG_INTF_FRAME_COUNT			0x0AC
 #define MDSS_MDP_REG_INTF_LINE_COUNT			0x0B0
 #define MDSS_MDP_PANEL_FORMAT_RGB888			0x213F
-#define MDSS_MDP_PANEL_FORMAT_RGB666			0x212A
+#define MDSS_MDP_PANEL_FORMAT_RGB666			0x21AA
 
 enum mdss_mdp_pingpong_index {
 	MDSS_MDP_PINGPONG0,
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_video.c b/drivers/video/msm/mdss/mdss_mdp_intf_video.c
index 92a4ae4..eff708c 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_video.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_video.c
@@ -634,9 +634,19 @@
 				usecs_to_jiffies(VSYNC_TIMEOUT_US));
 			WARN(rc <= 0, "timeout (%d) vsync interrupt on ctl=%d\n",
 				rc, ctl->num);
-			rc = 0;
-			video_vsync_irq_disable(ctl);
 
+			video_vsync_irq_disable(ctl);
+			/* Do not configure fps on vsync timeout */
+			if (rc <= 0)
+				return rc;
+
+			if (mdss_mdp_video_line_count(ctl) >=
+					pdata->panel_info.yres/2) {
+				pr_err("Too few lines left line_cnt = %d y_res/2 = %d\n",
+					mdss_mdp_video_line_count(ctl),
+					pdata->panel_info.yres/2);
+				return -EPERM;
+			}
 			rc = mdss_mdp_video_vfp_fps_update(ctl, new_fps);
 			if (rc < 0) {
 				pr_err("%s: Error during DFPS\n", __func__);
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index faa60fe..52c220f 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -277,7 +277,8 @@
 		 * mdp clock requirement
 		 */
 		if (mdata->has_decimation && (pipe->vert_deci < MAX_DECIMATION)
-			&& !pipe->bwc_mode && !pipe->src_fmt->tile)
+			&& !pipe->bwc_mode && !pipe->src_fmt->tile &&
+			!pipe->scale.enable_pxl_ext)
 			pipe->vert_deci++;
 		else
 			return -EPERM;
@@ -409,17 +410,33 @@
 	}
 
 	if (req->id == MSMFB_NEW_REQUEST) {
-		if (req->flags & MDP_OV_PIPE_FORCE_DMA)
-			pipe_type = MDSS_MDP_PIPE_TYPE_DMA;
-		else if (fmt->is_yuv || (req->flags & MDP_OV_PIPE_SHARE))
-			pipe_type = MDSS_MDP_PIPE_TYPE_VIG;
-		else
-			pipe_type = MDSS_MDP_PIPE_TYPE_RGB;
+		switch (req->pipe_type) {
+                case PIPE_TYPE_VIG:
+                        pipe_type = MDSS_MDP_PIPE_TYPE_VIG;
+                        break;
+                case PIPE_TYPE_RGB:
+                        pipe_type = MDSS_MDP_PIPE_TYPE_RGB;
+                        break;
+                case PIPE_TYPE_DMA:
+                        pipe_type = MDSS_MDP_PIPE_TYPE_DMA;
+                        break;
+                case PIPE_TYPE_AUTO:
+                default:
+                        if (req->flags & MDP_OV_PIPE_FORCE_DMA)
+                                pipe_type = MDSS_MDP_PIPE_TYPE_DMA;
+                        else if (fmt->is_yuv ||
+                                (req->flags & MDP_OV_PIPE_SHARE))
+                                pipe_type = MDSS_MDP_PIPE_TYPE_VIG;
+                        else
+                                pipe_type = MDSS_MDP_PIPE_TYPE_RGB;
+                        break;
+                }
 
 		pipe = mdss_mdp_pipe_alloc(mixer, pipe_type);
 
 		/* VIG pipes can also support RGB format */
-		if (!pipe && pipe_type == MDSS_MDP_PIPE_TYPE_RGB) {
+		if ((req->pipe_type == PIPE_TYPE_AUTO) && !pipe &&
+			(pipe_type == MDSS_MDP_PIPE_TYPE_RGB)) {
 			pipe_type = MDSS_MDP_PIPE_TYPE_VIG;
 			pipe = mdss_mdp_pipe_alloc(mixer, pipe_type);
 		}
@@ -573,14 +590,21 @@
 		}
 	}
 
-	if ((pipe->flags & MDP_DEINTERLACE) && !pipe->scale.enable_pxl_ext) {
+	/*
+	 * When scaling is enabled src crop and image
+	 * width and height is modified by user
+	 */
+	if ((pipe->flags & MDP_DEINTERLACE)) {
 		if (pipe->flags & MDP_SOURCE_ROTATED_90) {
 			pipe->src.x = DIV_ROUND_UP(pipe->src.x, 2);
 			pipe->src.x &= ~1;
-			pipe->src.w /= 2;
-			pipe->img_width /= 2;
+			if (!pipe->scale.enable_pxl_ext) {
+				pipe->src.w /= 2;
+				pipe->img_width /= 2;
+			}
 		} else {
-			pipe->src.h /= 2;
+			if (!pipe->scale.enable_pxl_ext)
+				pipe->src.h /= 2;
 			pipe->src.y = DIV_ROUND_UP(pipe->src.y, 2);
 			pipe->src.y &= ~1;
 		}
@@ -678,12 +702,15 @@
 					   int num_planes,
 					   u32 flags)
 {
-	int i, rc = 0;
+	int i, rc;
 
 	if ((num_planes <= 0) || (num_planes > MAX_PLANES))
 		return -EINVAL;
 
-	mdss_bus_bandwidth_ctrl(1);
+	rc = mdss_bus_bandwidth_ctrl(1);
+	if (rc)
+		goto end;
+
 	memset(data, 0, sizeof(*data));
 	for (i = 0; i < num_planes; i++) {
 		data->p[i].flags = flags;
@@ -701,21 +728,27 @@
 
 	data->num_planes = i;
 
+end:
 	return rc;
 }
 
 int mdss_mdp_overlay_free_buf(struct mdss_mdp_data *data)
 {
 	int i;
+	int rc;
 
-	mdss_bus_bandwidth_ctrl(1);
+	rc = mdss_bus_bandwidth_ctrl(1);
+	if (rc)
+		goto end;
+
 	for (i = 0; i < data->num_planes && data->p[i].len; i++)
 		mdss_mdp_put_img(&data->p[i]);
 	mdss_bus_bandwidth_ctrl(0);
 
 	data->num_planes = 0;
 
-	return 0;
+end:
+	return rc;
 }
 
 /**
@@ -874,14 +907,25 @@
 
 	if (ctl->power_on) {
 		if (mdp5_data->mdata->ulps) {
-			mdss_mdp_footswitch_ctrl_ulps(1, &mfd->pdev->dev);
+			rc = mdss_mdp_footswitch_ctrl_ulps(1, &mfd->pdev->dev);
+			if (rc) {
+				pr_err("footswtich control power on failed rc=%d\n",
+									rc);
+				goto end;
+			}
+
 			mdss_mdp_ctl_restore(ctl);
 		}
 
 		if (!mdp5_data->mdata->batfet)
 			mdss_mdp_batfet_ctrl(mdp5_data->mdata, true);
-		if (!mfd->panel_info->cont_splash_enabled)
-			mdss_iommu_attach(mdp5_data->mdata);
+		if (!mfd->panel_info->cont_splash_enabled) {
+			rc = mdss_iommu_attach(mdp5_data->mdata);
+			if (rc) {
+				pr_err("mdss iommu attach failed rc=%d\n", rc);
+				goto end;
+			}
+		}
 		mdss_mdp_release_splash_pipe(mfd);
 		return 0;
 	}
@@ -891,7 +935,7 @@
 	rc = pm_runtime_get_sync(&mfd->pdev->dev);
 	if (IS_ERR_VALUE(rc)) {
 		pr_err("unable to resume with pm_runtime_get_sync rc=%d\n", rc);
-		return rc;
+		goto end;
 	}
 
 	/*
@@ -903,8 +947,13 @@
 	 * we would have called in to TZ to restore security configs from LK.
 	 */
 	if (!is_mdss_iommu_attached()) {
-		if (!mfd->panel_info->cont_splash_enabled)
-			mdss_iommu_attach(mdss_res);
+		if (!mfd->panel_info->cont_splash_enabled) {
+			rc = mdss_iommu_attach(mdss_res);
+			if (rc) {
+				pr_err("mdss iommu attach failed rc=%d\n", rc);
+				goto pm_error;
+			}
+		}
 		mdss_hw_init(mdss_res);
 	}
 
@@ -916,17 +965,19 @@
 				&mfd->mdp_sync_pt_data.notifier);
 	} else {
 		pr_err("mdp ctl start failed.\n");
-		goto error;
+		goto ctl_error;
 	}
 
 	rc = mdss_mdp_splash_cleanup(mfd, true);
-error:
-	if (rc) {
-		mdss_mdp_ctl_destroy(ctl);
-		mdp5_data->ctl = NULL;
-		pm_runtime_put(&mfd->pdev->dev);
-	}
+	if (!rc)
+		goto end;
 
+ctl_error:
+	mdss_mdp_ctl_destroy(ctl);
+	mdp5_data->ctl = NULL;
+pm_error:
+	pm_runtime_put(&mfd->pdev->dev);
+end:
 	return rc;
 }
 
@@ -1033,7 +1084,9 @@
 	mdss_mdp_display_commit(ctl, NULL);
 	mdss_mdp_display_wait4comp(ctl);
 
+	ATRACE_BEGIN("sspp_programming");
 	__overlay_queue_pipes(mfd);
+	ATRACE_END("sspp_programming");
 
 	mdss_mdp_display_commit(ctl, NULL);
 	mdss_mdp_display_wait4comp(ctl);
@@ -1049,6 +1102,7 @@
 	int sd_in_pipe = 0;
 	bool need_cleanup = false;
 
+	ATRACE_BEGIN(__func__);
 	if (ctl->shared_lock) {
 		mdss_mdp_ctl_notify(ctl, MDP_NOTIFY_FRAME_BEGIN);
 		mdss_mdp_ctl_notify(ctl, MDP_NOTIFY_FRAME_READY);
@@ -1095,12 +1149,19 @@
 		need_cleanup = true;
 	}
 
+	ATRACE_BEGIN("sspp_programming");
 	ret = __overlay_queue_pipes(mfd);
+	ATRACE_END("sspp_programming");
 
-	if (mfd->panel.type == WRITEBACK_PANEL)
+	if (mfd->panel.type == WRITEBACK_PANEL) {
+		ATRACE_BEGIN("wb_kickoff");
 		ret = mdss_mdp_wb_kickoff(mfd);
-	else
+		ATRACE_END("wb_kickoff");
+	} else {
+		ATRACE_BEGIN("display_commit");
 		ret = mdss_mdp_display_commit(mdp5_data->ctl, NULL);
+		ATRACE_END("display_commit");
+	}
 
 	if (!need_cleanup) {
 		atomic_set(&mfd->kickoff_pending, 0);
@@ -1114,7 +1175,9 @@
 	mutex_unlock(&mdp5_data->ov_lock);
 	mdss_mdp_overlay_update_pm(mdp5_data);
 
+	ATRACE_BEGIN("display_wait4comp");
 	ret = mdss_mdp_display_wait4comp(mdp5_data->ctl);
+	ATRACE_END("display_wait4comp");
 	mutex_lock(&mdp5_data->ov_lock);
 
 	if (ret == 0) {
@@ -1129,7 +1192,9 @@
 
 	mdss_fb_update_notify_update(mfd);
 commit_fail:
+	ATRACE_BEGIN("overlay_cleanup");
 	mdss_mdp_overlay_cleanup(mfd);
+	ATRACE_END("overlay_cleanup");
 	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
 	mdss_mdp_ctl_notify(ctl, MDP_NOTIFY_FRAME_FLUSHED);
 	if (need_cleanup) {
@@ -1139,7 +1204,7 @@
 	mutex_unlock(&mdp5_data->ov_lock);
 	if (ctl->shared_lock)
 		mutex_unlock(ctl->shared_lock);
-
+	ATRACE_END(__func__);
 	return ret;
 }
 
@@ -1320,8 +1385,13 @@
 	flags = (pipe->flags & MDP_SECURE_OVERLAY_SESSION);
 	flags |= (pipe->flags & MDP_SECURE_DISPLAY_OVERLAY_SESSION);
 
-	if (!mfd->panel_info->cont_splash_enabled)
-		mdss_iommu_attach(mdata);
+	if (!mfd->panel_info->cont_splash_enabled) {
+		ret = mdss_iommu_attach(mdata);
+		if (ret) {
+			pr_err("mdss iommu attach failed ret=%d\n", ret);
+			goto end;
+		}
+	}
 
 	src_data = &pipe->back_buf;
 	if (src_data->num_planes) {
@@ -1334,6 +1404,8 @@
 	if (IS_ERR_VALUE(ret)) {
 		pr_err("src_data pmem error\n");
 	}
+
+end:
 	mdss_mdp_pipe_unmap(pipe);
 
 	return ret;
@@ -1718,10 +1790,12 @@
 		return -ENODEV;
 	}
 
+	mutex_lock(&mdp5_data->dfps_lock);
 	ret = snprintf(buf, PAGE_SIZE, "%d\n",
 		       pdata->panel_info.mipi.frame_rate);
 	pr_debug("%s: '%d'\n", __func__,
 		pdata->panel_info.mipi.frame_rate);
+	mutex_unlock(&mdp5_data->dfps_lock);
 
 	return ret;
 } /* dynamic_fps_sysfs_rda_dfps */
@@ -1756,6 +1830,7 @@
 		return count;
 	}
 
+	mutex_lock(&mdp5_data->dfps_lock);
 	if (dfps < 30) {
 		pr_err("Unsupported FPS. Configuring to min_fps = 30\n");
 		dfps = 30;
@@ -1772,9 +1847,11 @@
 	} else {
 		pr_err("Failed to configure '%d' FPS. rc = %d\n",
 							dfps, rc);
+		mutex_unlock(&mdp5_data->dfps_lock);
 		return rc;
 	}
 	pdata->panel_info.new_fps = dfps;
+	mutex_unlock(&mdp5_data->dfps_lock);
 	return count;
 } /* dynamic_fps_sysfs_wta_dfps */
 
@@ -2657,8 +2734,10 @@
 		(mfd->panel_info->type != DTV_PANEL)) {
 		rc = mdss_mdp_overlay_start(mfd);
 		if (!IS_ERR_VALUE(rc) &&
-			(mfd->panel_info->type != WRITEBACK_PANEL))
+			(mfd->panel_info->type != WRITEBACK_PANEL)) {
+			atomic_inc(&mfd->mdp_sync_pt_data.commit_cnt);
 			rc = mdss_mdp_overlay_kickoff(mfd, NULL);
+		}
 	} else {
 		rc = mdss_mdp_ctl_setup(mdp5_data->ctl);
 		if (rc)
@@ -3005,6 +3084,7 @@
 	INIT_LIST_HEAD(&mdp5_data->pipes_cleanup);
 	INIT_LIST_HEAD(&mdp5_data->rot_proc_list);
 	mutex_init(&mdp5_data->ov_lock);
+	mutex_init(&mdp5_data->dfps_lock);
 	mdp5_data->hw_refresh = true;
 	mdp5_data->overlay_play_enable = true;
 
diff --git a/drivers/video/msm/mdss/mdss_mdp_pp.c b/drivers/video/msm/mdss/mdss_mdp_pp.c
index 0c6eb2a..7159a0a 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pp.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pp.c
@@ -1094,39 +1094,51 @@
 		}
 	}
 
-	if (pipe->scale.enable_pxl_ext &&
-		pipe->type == MDSS_MDP_PIPE_TYPE_VIG) {
+	if (pipe->scale.enable_pxl_ext) {
+		if (pipe->type == MDSS_MDP_PIPE_TYPE_VIG) {
+			/*program x,y initial phase and phase step*/
+			writel_relaxed(pipe->scale.init_phase_x[0],
+				pipe->base +
+				MDSS_MDP_REG_VIG_QSEED2_C03_INIT_PHASEX);
+			writel_relaxed(pipe->scale.phase_step_x[0],
+				pipe->base +
+				MDSS_MDP_REG_VIG_QSEED2_C03_PHASESTEPX);
+			writel_relaxed(pipe->scale.init_phase_x[1],
+				pipe->base +
+				MDSS_MDP_REG_VIG_QSEED2_C12_INIT_PHASEX);
+			writel_relaxed(pipe->scale.phase_step_x[1],
+				pipe->base +
+				MDSS_MDP_REG_VIG_QSEED2_C12_PHASESTEPX);
 
-		/*program x,y initial phase and phase step*/
-		writel_relaxed(pipe->scale.init_phase_x[0],
-			pipe->base + MDSS_MDP_REG_VIG_QSEED2_C03_INIT_PHASEX);
-		writel_relaxed(pipe->scale.phase_step_x[0],
-			pipe->base + MDSS_MDP_REG_VIG_QSEED2_C03_PHASESTEPX);
-		writel_relaxed(pipe->scale.init_phase_x[1],
-			pipe->base + MDSS_MDP_REG_VIG_QSEED2_C12_INIT_PHASEX);
-		writel_relaxed(pipe->scale.phase_step_x[1],
-			pipe->base + MDSS_MDP_REG_VIG_QSEED2_C12_PHASESTEPX);
+			writel_relaxed(pipe->scale.init_phase_y[0],
+				pipe->base +
+				MDSS_MDP_REG_VIG_QSEED2_C03_INIT_PHASEY);
+			writel_relaxed(pipe->scale.phase_step_y[0],
+				pipe->base +
+				MDSS_MDP_REG_VIG_QSEED2_C03_PHASESTEPY);
+			writel_relaxed(pipe->scale.init_phase_y[1],
+				pipe->base +
+				MDSS_MDP_REG_VIG_QSEED2_C12_INIT_PHASEY);
+			writel_relaxed(pipe->scale.phase_step_y[1],
+				pipe->base +
+				MDSS_MDP_REG_VIG_QSEED2_C12_PHASESTEPY);
+		} else {
 
-		writel_relaxed(pipe->scale.init_phase_y[0],
-			pipe->base + MDSS_MDP_REG_VIG_QSEED2_C03_INIT_PHASEY);
-		writel_relaxed(pipe->scale.phase_step_y[0],
-			pipe->base + MDSS_MDP_REG_VIG_QSEED2_C03_PHASESTEPY);
-		writel_relaxed(pipe->scale.init_phase_y[1],
-			pipe->base + MDSS_MDP_REG_VIG_QSEED2_C12_INIT_PHASEY);
-		writel_relaxed(pipe->scale.phase_step_y[1],
-			pipe->base + MDSS_MDP_REG_VIG_QSEED2_C12_PHASESTEPY);
-
+			writel_relaxed(pipe->scale.phase_step_x[0],
+				pipe->base +
+				MDSS_MDP_REG_SCALE_PHASE_STEP_X);
+			writel_relaxed(pipe->scale.phase_step_y[0],
+				pipe->base +
+				MDSS_MDP_REG_SCALE_PHASE_STEP_Y);
+			writel_relaxed(pipe->scale.init_phase_x[0],
+				pipe->base +
+				MDSS_MDP_REG_SCALE_INIT_PHASE_X);
+			writel_relaxed(pipe->scale.init_phase_y[0],
+				pipe->base +
+				MDSS_MDP_REG_SCALE_INIT_PHASE_Y);
+		}
 		/*program pixel extn values for the SSPP*/
 		mdss_mdp_pipe_program_pixel_extn(pipe);
-	} else if (pipe->type == MDSS_MDP_PIPE_TYPE_VIG) {
-		writel_relaxed(phasex_step, pipe->base +
-		   MDSS_MDP_REG_SCALE_PHASE_STEP_X);
-		writel_relaxed(phasey_step, pipe->base +
-		   MDSS_MDP_REG_SCALE_PHASE_STEP_Y);
-		writel_relaxed(init_phasex, pipe->base +
-			MDSS_MDP_REG_SCALE_INIT_PHASE_X);
-		writel_relaxed(init_phasey, pipe->base +
-			MDSS_MDP_REG_SCALE_INIT_PHASE_Y);
 	} else {
 		writel_relaxed(phasex_step, pipe->base +
 		   MDSS_MDP_REG_SCALE_PHASE_STEP_X);
@@ -1612,6 +1624,7 @@
 	u32 disp_num;
 	int i;
 	bool valid_mixers = true;
+	bool valid_ad_panel = true;
 	if ((!ctl->mfd) || (!mdss_pp_res))
 		return -EINVAL;
 
@@ -1632,7 +1645,13 @@
 		if (mixer_id[i] >= mdata->nad_cfgs)
 			valid_mixers = false;
 	}
-	if (valid_mixers && (mixer_cnt <= mdata->nmax_concurrent_ad_hw)) {
+	valid_ad_panel = (ctl->mfd->panel_info->type != DTV_PANEL) &&
+		(((mdata->mdp_rev < MDSS_MDP_HW_REV_103) &&
+			(ctl->mfd->panel_info->type == WRITEBACK_PANEL)) ||
+		(ctl->mfd->panel_info->type != WRITEBACK_PANEL));
+
+	if (valid_mixers && (mixer_cnt <= mdata->nmax_concurrent_ad_hw) &&
+		valid_ad_panel) {
 		ret = mdss_mdp_ad_setup(ctl->mfd);
 		if (ret < 0)
 			pr_warn("ad_setup(disp%d) returns %d", disp_num, ret);
diff --git a/drivers/video/msm/mdss/mdss_mdp_rotator.c b/drivers/video/msm/mdss/mdss_mdp_rotator.c
index ee892e2..6953469 100755
--- a/drivers/video/msm/mdss/mdss_mdp_rotator.c
+++ b/drivers/video/msm/mdss/mdss_mdp_rotator.c
@@ -23,6 +23,7 @@
 #include "mdss_mdp.h"
 #include "mdss_mdp_rotator.h"
 #include "mdss_fb.h"
+#include "mdss_debug.h"
 
 #define MAX_ROTATOR_SESSIONS 8
 
@@ -281,8 +282,9 @@
 		pr_err("unable to queue rot data\n");
 		goto error;
 	}
-
+	ATRACE_BEGIN("rotator_kickoff");
 	ret = mdss_mdp_rotator_kickoff(rot_ctl, rot, dst_data);
+	ATRACE_END("rotator_kickoff");
 
 	return ret;
 error:
diff --git a/drivers/video/msm/mdss/mdss_mdp_splash_logo.c b/drivers/video/msm/mdss/mdss_mdp_splash_logo.c
index 77f6554..838f58f 100644
--- a/drivers/video/msm/mdss/mdss_mdp_splash_logo.c
+++ b/drivers/video/msm/mdss/mdss_mdp_splash_logo.c
@@ -504,8 +504,8 @@
 	}
 	unlock_fb_info(mfd->fbi);
 
-	mfd->bl_updated = true;
 	mutex_lock(&mfd->bl_lock);
+	mfd->bl_updated = true;
 	mdss_fb_set_backlight(mfd, mfd->panel_info->bl_max >> 1);
 	mutex_unlock(&mfd->bl_lock);
 
diff --git a/drivers/video/msm/mdss/mdss_mdp_trace.h b/drivers/video/msm/mdss/mdss_mdp_trace.h
index 0e0c1e7..33fe3a4 100644
--- a/drivers/video/msm/mdss/mdss_mdp_trace.h
+++ b/drivers/video/msm/mdss/mdss_mdp_trace.h
@@ -215,6 +215,40 @@
 			__entry->kickoff_cnt)
 );
 
+TRACE_EVENT(tracing_mark_write,
+	TP_PROTO(int pid, const char *name, bool trace_begin),
+	TP_ARGS(pid, name, trace_begin),
+	TP_STRUCT__entry(
+			__field(int, pid)
+			__string(trace_name, name)
+			__field(bool, trace_begin)
+	),
+	TP_fast_assign(
+			__entry->pid = pid;
+			__assign_str(trace_name, name);
+			__entry->trace_begin = trace_begin;
+	),
+	TP_printk("%s|%d|%s", __entry->trace_begin ? "B" : "E",
+		__entry->pid, __get_str(trace_name))
+);
+
+TRACE_EVENT(mdp_trace_counter,
+	TP_PROTO(int pid, char *name, int value),
+	TP_ARGS(pid, name, value),
+	TP_STRUCT__entry(
+			__field(int, pid)
+			__string(counter_name, name)
+			__field(int, value)
+	),
+	TP_fast_assign(
+			__entry->pid = current->tgid;
+			__assign_str(counter_name, name);
+			__entry->value = value;
+	),
+	TP_printk("%d|%s|%d", __entry->pid,
+			__get_str(counter_name), __entry->value)
+);
+
 #endif /* if !defined(TRACE_MDSS_MDP_H) || defined(TRACE_HEADER_MULTI_READ) */
 
 /* This part must be outside protection */
diff --git a/drivers/video/msm/mdss/mdss_mdp_wb.c b/drivers/video/msm/mdss/mdss_mdp_wb.c
index aa17472..0e59a26 100644
--- a/drivers/video/msm/mdss/mdss_mdp_wb.c
+++ b/drivers/video/msm/mdss/mdss_mdp_wb.c
@@ -481,8 +481,13 @@
 
 	pr_debug("fb%d queue\n", wb->fb_ndx);
 
-	if (!mfd->panel_info->cont_splash_enabled)
-		mdss_iommu_attach(mdp5_data->mdata);
+	if (!mfd->panel_info->cont_splash_enabled) {
+		ret  = mdss_iommu_attach(mdp5_data->mdata);
+		if (ret) {
+			pr_err("mdss iommu attach failed rc=%d", ret);
+			return ret;
+		}
+	}
 
 	mutex_lock(&wb->lock);
 	if (local)
diff --git a/drivers/video/msm/mdss/mdss_panel.h b/drivers/video/msm/mdss/mdss_panel.h
index c5ac72e..52c3e71 100644
--- a/drivers/video/msm/mdss/mdss_panel.h
+++ b/drivers/video/msm/mdss/mdss_panel.h
@@ -208,6 +208,7 @@
 	char hbp_power_stop;
 	char hsa_power_stop;
 	char eof_bllp_power_stop;
+	char last_line_interleave_en;
 	char bllp_power_stop;
 	char traffic_mode;
 	char frame_rate;
@@ -320,7 +321,8 @@
 	bool ulps_feature_enabled;
 	char dfps_update;
 	int new_fps;
-
+	int panel_max_fps;
+	int panel_max_vtotal;
 	u32 cont_splash_enabled;
 	u32 partial_update_enabled;
 	struct ion_handle *splash_ihdl;
diff --git a/include/linux/Kbuild b/include/linux/Kbuild
index 6d18d0f..c5adf38 100755
--- a/include/linux/Kbuild
+++ b/include/linux/Kbuild
@@ -454,4 +454,5 @@
 header-y += msm_audio_amrwbplus.h
 header-y += avtimer.h
 header-y += msm_ipa.h
+header-y += msm_pft.h
 header-y += msm_thermal_ioctl.h
diff --git a/include/linux/msm_kgsl.h b/include/linux/msm_kgsl.h
index 17986b5..bc80bda 100644
--- a/include/linux/msm_kgsl.h
+++ b/include/linux/msm_kgsl.h
@@ -692,7 +692,8 @@
  * struct kgsl_perfcounter_get - argument to IOCTL_KGSL_PERFCOUNTER_GET
  * @groupid: Performance counter group ID
  * @countable: Countable to select within the group
- * @offset: Return offset of the reserved counter
+ * @offset: Return offset of the reserved LO counter
+ * @offset_hi: Return offset of the reserved HI counter
  *
  * Get an available performance counter from a specified groupid.  The offset
  * of the performance counter will be returned after successfully assigning
@@ -707,8 +708,9 @@
 	unsigned int groupid;
 	unsigned int countable;
 	unsigned int offset;
+	unsigned int offset_hi;
 /* private: reserved for future use */
-	unsigned int __pad[2]; /* For future binary compatibility */
+	unsigned int __pad; /* For future binary compatibility */
 };
 
 #define IOCTL_KGSL_PERFCOUNTER_GET \
diff --git a/include/linux/msm_mdp.h b/include/linux/msm_mdp.h
index 00eba66..fd2cc6c 100644
--- a/include/linux/msm_mdp.h
+++ b/include/linux/msm_mdp.h
@@ -555,6 +555,23 @@
 };
 
 /**
+ * enum mdp_overlay_pipe_type - Different pipe type set by userspace
+ *
+ * @PIPE_TYPE_AUTO:    Not specified, pipe will be selected according to flags.
+ * @PIPE_TYPE_VIG:     VIG pipe.
+ * @PIPE_TYPE_RGB:     RGB pipe.
+ * @PIPE_TYPE_DMA:     DMA pipe.
+ * @PIPE_TYPE_MAX:     Used to track maximum number of pipe type.
+ */
+enum mdp_overlay_pipe_type {
+        PIPE_TYPE_AUTO = 0,
+        PIPE_TYPE_VIG,
+        PIPE_TYPE_RGB,
+        PIPE_TYPE_DMA,
+        PIPE_TYPE_MAX,
+};
+
+/**
  * struct mdp_overlay - overlay surface structure
  * @src:	Source image information (width, height, format).
  * @src_rect:	Source crop rectangle, portion of image that will be fetched.
@@ -576,6 +593,7 @@
  *		The color should be in same format as the source image format.
  * @flags:	This is used to customize operation of overlay. See MDP flags
  *		for more information.
+ * @pipe_type:  Used to specify the type of overlay pipe.
  * @user_data:	DEPRECATED* Used to store user application specific information.
  * @bg_color:	Solid color used to fill the overlay surface when no source
  *		buffer is provided.
@@ -608,6 +626,7 @@
 	uint32_t blend_op;
 	uint32_t transp_mask;
 	uint32_t flags;
+	uint32_t pipe_type;
 	uint32_t id;
 	uint32_t user_data[6];
 	uint32_t bg_color;
diff --git a/include/linux/msm_pft.h b/include/linux/msm_pft.h
new file mode 100644
index 0000000..4daf46b
--- /dev/null
+++ b/include/linux/msm_pft.h
@@ -0,0 +1,134 @@
+/* Copyright (c) 2014, 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
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef MSM_PFT_H_
+#define MSM_PFT_H_
+
+#include <linux/types.h>
+
+/**
+ *  enum pft_command_opcode - PFT driver command ID
+ *
+ *  @PFT_CMD_OPCODE_SET_STATE -
+ *      command ID to set PFT driver state
+ *  @PFT_CMD_OPCODE_UPDATE_REG_APP_UID -
+ *      command ID to update the list of registered application
+ *      UID
+ *  @PFT_CMD_OPCODE_PERFORM_IN_PLACE_FILE_ENC -
+ *      command ID to perfrom in-place file encryption
+ */
+enum pft_command_opcode {
+	PFT_CMD_OPCODE_SET_STATE,
+	PFT_CMD_OPCODE_UPDATE_REG_APP_UID,
+	PFT_CMD_OPCODE_PERFORM_IN_PLACE_FILE_ENC,
+	/* */
+	PFT_CMD_OPCODE_MAX_COMMAND_INDEX
+};
+
+/**
+ * enum pft_state - PFT driver operational states
+ *
+ * @PFT_STATE_DEACTIVATED - driver is deativated.
+ * @PFT_STATE_DEACTIVATING - driver is in the process of being deativated.
+ * @PFT_STATE_KEY_REMOVED - driver is active but no encryption key is loaded.
+ * @PFT_STATE_REMOVING_KEY - driver is active, but the encryption key is being
+ *      removed.
+ * @PFT_STATE_KEY_LOADED - driver is active, and the encryption key is loaded
+ *      to encryption block, hence registered apps can perform file operations
+ *      on encrypted files.
+ */
+enum pft_state {
+	PFT_STATE_DEACTIVATED,
+	PFT_STATE_DEACTIVATING,
+	PFT_STATE_KEY_REMOVED,
+	PFT_STATE_REMOVING_KEY,
+	PFT_STATE_KEY_LOADED,
+	/* Internal */
+	PFT_STATE_MAX_INDEX
+};
+
+/**
+ * enum pft_command_response_code - PFT response on the previous
+ * command
+ *
+ * @PFT_CMD_RESP_SUCCESS - The command was properly processed
+ *      without an error.
+ * @PFT_CMD_RESP_GENERAL_ERROR -
+ *      Indicates an error that cannot be better described by a
+ *      more specific errors below.
+ * @PFT_CMD_RESP_INVALID_COMMAND - Invalid or unsupported
+ *      command id.
+ * @PFT_CMD_RESP_INVALID_CMD_PARAMS - Invalid command
+ *	parameters.
+ * @PFT_CMD_RESP_INVALID_STATE - Invalid state
+ * @PFT_CMD_RESP_ALREADY_IN_STATE - Used to indicates that
+ *      the new state is equal to the existing one.
+ * @PFT_CMD_RESP_INPLACE_FILE_IS_OPEN - Used to indicates
+ *      that the file that should be encrypted is already open
+ *      and can be encrypted.
+ * @PFT_CMD_RESP_ENT_FILES_CLOSING_FAILURE
+ *	Indicates about failure of the PFT to close Enterprise files
+ * @PFT_CMD_RESP_MAX_INDEX
+ */
+enum pft_command_response_code {
+	PFT_CMD_RESP_SUCCESS,
+	PFT_CMD_RESP_GENERAL_ERROR,
+	PFT_CMD_RESP_INVALID_COMMAND,
+	PFT_CMD_RESP_INVALID_CMD_PARAMS,
+	PFT_CMD_RESP_INVALID_STATE,
+	PFT_CMD_RESP_ALREADY_IN_STATE,
+	PFT_CMD_RESP_INPLACE_FILE_IS_OPEN,
+	PFT_CMD_RESP_ENT_FILES_CLOSING_FAILURE,
+	/* Internal */
+	PFT_CMD_RESP_MAX_INDEX
+};
+
+/**
+ * struct pft_command_response - response structure
+ *
+ * @command_id - see enum pft_command_response_code
+ * @error_codee - see enum pft_command_response_code
+ */
+struct pft_command_response {
+	__u32 command_id;
+	__u32 error_code;
+};
+
+/**
+ * struct pft_command - pft command
+ *
+ * @opcode - see enum pft_command_opcode.
+ * @set_state.state - see enum pft_state.
+ * @update_app_list.count - number of items in the
+ *      registered applications list.
+ * @update_app_list.table - registered applications array
+ * @preform_in_place_file_enc.file_descriptor - file descriptor
+ *      of the opened file to be in-placed encrypted.
+ */
+struct pft_command {
+	__u32 opcode;
+	union {
+		struct {
+			/* @see pft_state */
+			__u32 state;
+		} set_state;
+		struct {
+			__u32 items_count; /* number of items */
+			__u32 table[0]; /* array of UIDs */
+		} update_app_list;
+		struct {
+			__u32 file_descriptor;
+		} preform_in_place_file_enc;
+	};
+};
+
+#endif /* MSM_PFT_H_ */
diff --git a/include/linux/pft.h b/include/linux/pft.h
new file mode 100644
index 0000000..36e9612
--- /dev/null
+++ b/include/linux/pft.h
@@ -0,0 +1,92 @@
+/* Copyright (c) 2014, 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
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef PFT_H_
+#define PFT_H_
+
+#include <linux/types.h>
+#include <linux/fs.h>
+
+#ifdef CONFIG_PFT
+
+/* dm-req-crypt API */
+int pft_get_key_index(struct inode *inode, u32 *key_index,
+		      bool *is_encrypted, bool *is_inplace);
+
+/* block layer API */
+bool pft_allow_merge_bio(struct bio *bio1, struct bio *bio2);
+
+/* --- security hooks , called from selinux --- */
+int pft_inode_create(struct inode *dir, struct dentry *dentry, umode_t mode);
+
+int pft_inode_post_create(struct inode *dir, struct dentry *dentry,
+			  umode_t mode);
+
+int pft_file_open(struct file *filp, const struct cred *cred);
+
+int pft_file_permission(struct file *file, int mask);
+
+int pft_file_close(struct file *filp);
+
+int pft_inode_unlink(struct inode *dir, struct dentry *dentry);
+
+int pft_inode_mknod(struct inode *dir, struct dentry *dentry, umode_t mode,
+		    dev_t dev);
+
+int pft_inode_rename(struct inode *inode, struct dentry *dentry,
+		     struct inode *new_inode, struct dentry *new_dentry);
+
+int pft_inode_set_xattr(struct dentry *dentry, const char *name);
+
+
+#else
+static inline int pft_get_key_index(struct inode *inode, u32 *key_index,
+				    bool *is_encrypted, bool *is_inplace)
+{ return -ENODEV; }
+
+static inline bool pft_allow_merge_bio(struct bio *bio1, struct bio *bio2)
+{ return true; }
+
+static inline int pft_file_permission(struct file *file, int mask)
+{ return 0; }
+
+static inline int pft_inode_create(
+	struct inode *dir, struct dentry *dentry, umode_t mode)
+{ return 0; }
+
+static inline int pft_inode_post_create(
+	struct inode *dir, struct dentry *dentry, umode_t mode)
+{ return 0; }
+
+static inline int pft_file_open(struct file *filp, const struct cred *cred)
+{ return 0; }
+
+static inline int pft_file_close(struct file *filp)
+{ return 0; }
+
+static inline int pft_inode_unlink(struct inode *dir, struct dentry *dentry)
+{ return 0; }
+
+static inline int pft_inode_mknod(struct inode *dir, struct dentry *dentry,
+				  umode_t mode, dev_t dev)
+{ return 0; }
+
+static inline int pft_inode_rename(struct inode *inode, struct dentry *dentry,
+		     struct inode *new_inode, struct dentry *new_dentry)
+{ return 0; }
+
+static inline int pft_inode_set_xattr(struct dentry *dentry, const char *name)
+{ return 0; }
+
+#endif /* CONFIG_PFT */
+
+#endif /* PFT_H */
diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h
index 4ecacc7..44fe134 100644
--- a/include/linux/usb/msm_hsusb.h
+++ b/include/linux/usb/msm_hsusb.h
@@ -191,6 +191,20 @@
 };
 
 /**
+ * Maintain state for hvdcp external charger status
+ * DEFAULT	This is used when DCP is detected
+ * ACTIVE	This is used when ioctl is called to block LPM
+ * INACTIVE	This is used when ioctl is called to unblock LPM
+ */
+
+enum usb_ext_chg_status {
+	DEFAULT = 1,
+	ACTIVE,
+	INACTIVE,
+};
+
+
+/**
  * struct msm_otg_platform_data - platform device data
  *              for msm_otg driver.
  * @phy_init_seq: PHY configuration sequence. val, reg pairs
@@ -463,7 +477,7 @@
 	struct class *ext_chg_class;
 	struct device *ext_chg_device;
 	bool ext_chg_opened;
-	bool ext_chg_active;
+	enum usb_ext_chg_status ext_chg_active;
 	struct completion ext_chg_wait;
 	int ui_enabled;
 	bool pm_done;
diff --git a/include/media/msm_cam_sensor.h b/include/media/msm_cam_sensor.h
index b1b54cb..d583601 100644
--- a/include/media/msm_cam_sensor.h
+++ b/include/media/msm_cam_sensor.h
@@ -486,6 +486,8 @@
 	CFG_SET_DEFAULT_FOCUS,
 	CFG_MOVE_FOCUS,
 	CFG_SET_POSITION,
+	CFG_ACTUATOR_POWERDOWN,
+	CFG_ACTUATOR_POWERUP,
 };
 
 enum actuator_type {
diff --git a/include/media/msmb_pproc.h b/include/media/msmb_pproc.h
index df9f9e7..59dcca9 100644
--- a/include/media/msmb_pproc.h
+++ b/include/media/msmb_pproc.h
@@ -15,6 +15,7 @@
 #define MSM_CPP_MAX_NUM_PLANES 3
 #define MSM_CPP_MAX_FRAME_LENGTH 1024
 #define MSM_CPP_MAX_FW_NAME_LEN 32
+#define MAX_FREQ_TBL 10
 
 enum msm_cpp_frame_type {
 	MSM_CPP_OFFLINE_FRAME,
@@ -126,6 +127,8 @@
 struct cpp_hw_info {
 	uint32_t cpp_hw_version;
 	uint32_t cpp_hw_caps;
+	unsigned long freq_tbl[MAX_FREQ_TBL];
+	uint32_t freq_tbl_count;
 };
 
 struct msm_vpe_frame_strip_info {
diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c
index 30b88d7..cada6a7 100644
--- a/net/ipv4/fib_trie.c
+++ b/net/ipv4/fib_trie.c
@@ -368,7 +368,7 @@
 
 static inline void free_leaf(struct leaf *l)
 {
-	call_rcu_bh(&l->rcu, __leaf_free_rcu);
+	call_rcu(&l->rcu, __leaf_free_rcu);
 }
 
 static inline void free_leaf_info(struct leaf_info *leaf)
diff --git a/net/ipv4/ping.c b/net/ipv4/ping.c
index a8d7ed0..87f05b2 100644
--- a/net/ipv4/ping.c
+++ b/net/ipv4/ping.c
@@ -879,10 +879,12 @@
 	/* Copy the address and add cmsg data. */
 	if (family == AF_INET) {
 		sin = (struct sockaddr_in *) msg->msg_name;
-		sin->sin_family = AF_INET;
-		sin->sin_port = 0 /* skb->h.uh->source */;
-		sin->sin_addr.s_addr = ip_hdr(skb)->saddr;
-		memset(sin->sin_zero, 0, sizeof(sin->sin_zero));
+		if (sin) {
+			sin->sin_family = AF_INET;
+			sin->sin_port = 0 /* skb->h.uh->source */;
+			sin->sin_addr.s_addr = ip_hdr(skb)->saddr;
+			memset(sin->sin_zero, 0, sizeof(sin->sin_zero));
+		}
 
 		if (isk->cmsg_flags)
 			ip_cmsg_recv(msg, skb);
@@ -892,17 +894,19 @@
 		struct ipv6_pinfo *np = inet6_sk(sk);
 		struct ipv6hdr *ip6 = ipv6_hdr(skb);
 		sin6 = (struct sockaddr_in6 *) msg->msg_name;
-		sin6->sin6_family = AF_INET6;
-		sin6->sin6_port = 0;
-		sin6->sin6_addr = ip6->saddr;
+		if (sin6) {
+			sin6->sin6_family = AF_INET6;
+			sin6->sin6_port = 0;
+			sin6->sin6_addr = ip6->saddr;
 
-		sin6->sin6_flowinfo = 0;
-		if (np->sndflow)
-			sin6->sin6_flowinfo =
-				*(__be32 *)ip6 & IPV6_FLOWINFO_MASK;
+			sin6->sin6_flowinfo = 0;
+			if (np->sndflow)
+				sin6->sin6_flowinfo =
+					*(__be32 *)ip6 & IPV6_FLOWINFO_MASK;
 
-		sin6->sin6_scope_id = ipv6_iface_scope_id(&sin6->sin6_addr,
-							  IP6CB(skb)->iif);
+			sin6->sin6_scope_id = ipv6_iface_scope_id(&sin6->sin6_addr,
+								  IP6CB(skb)->iif);
+		}
 
 		if (inet6_sk(sk)->rxopt.all)
 			pingv6_ops.datagram_recv_ctl(sk, msg, skb);
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index bc4888d..76e2afe 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -1971,7 +1971,8 @@
 restart:
 	read_lock_bh(&table->tb6_lock);
 	for (rt = table->tb6_root.leaf; rt; rt = rt->dst.rt6_next) {
-		if (rt->rt6i_flags & (RTF_DEFAULT | RTF_ADDRCONF)) {
+		if (rt->rt6i_flags & (RTF_DEFAULT | RTF_ADDRCONF) &&
+		    (!rt->rt6i_idev || rt->rt6i_idev->cnf.accept_ra != 2)) {
 			dst_hold(&rt->dst);
 			read_unlock_bh(&table->tb6_lock);
 			ip6_del_rt(rt);
diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h
index 26c7eee..d160760 100644
--- a/security/selinux/include/objsec.h
+++ b/security/selinux/include/objsec.h
@@ -43,6 +43,7 @@
 	u32 sid;		/* SID of this object */
 	u16 sclass;		/* security class of this object */
 	unsigned char initialized;	/* initialization flag */
+	u32 tag;		/* Per-File-Encryption tag */
 	struct mutex lock;
 };
 
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index 185f849..72b20b1 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -1229,6 +1229,10 @@
 	struct context context;
 	int rc = 0;
 
+	/* An empty security context is never valid. */
+	if (!scontext_len)
+		return -EINVAL;
+
 	if (!ss_initialized) {
 		int i;
 
diff --git a/sound/soc/codecs/msm8x10-wcd.c b/sound/soc/codecs/msm8x10-wcd.c
index a5e0bb3..bbe1ac7 100644
--- a/sound/soc/codecs/msm8x10-wcd.c
+++ b/sound/soc/codecs/msm8x10-wcd.c
@@ -2834,7 +2834,7 @@
 		rc = snd_soc_dapm_force_enable_pin(&codec->dapm,
 			DAPM_MICBIAS_EXTERNAL_STANDALONE);
 	else {
-		if (msm8x10_wcd->micb_en_count > 0) {
+		if (msm8x10_wcd->micb_en_count > 1) {
 			msm8x10_wcd->micb_en_count--;
 			pr_debug("%s micb_en_count : %d", __func__,
 					msm8x10_wcd->micb_en_count);
diff --git a/sound/soc/codecs/wcd9xxx-mbhc.c b/sound/soc/codecs/wcd9xxx-mbhc.c
index 8a71891..9bd1652 100644
--- a/sound/soc/codecs/wcd9xxx-mbhc.c
+++ b/sound/soc/codecs/wcd9xxx-mbhc.c
@@ -1649,9 +1649,9 @@
 		}
 	}
 
-	if (type == PLUG_TYPE_HEADSET && dvddio) {
-		if ((dvddio->_vdces > hs_max) ||
-		    (dvddio->_vdces > minv + WCD9XXX_THRESHOLD_MIC_THRESHOLD)) {
+	if (type == PLUG_TYPE_HEADSET) {
+		if (dvddio && ((dvddio->_vdces > hs_max) ||
+		   (dvddio->_vdces > minv + WCD9XXX_THRESHOLD_MIC_THRESHOLD))) {
 			pr_debug("%s: Headset with threshold on MIC detected\n",
 				 __func__);
 			if (mbhc->mbhc_cfg->micbias_enable_flags &
diff --git a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c
index aa4d88d..fce1940 100644
--- a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c
@@ -177,8 +177,31 @@
 			pr_debug("%s: call q6asm_set_lrgain\n", __func__);
 			rc = q6asm_set_lrgain(prtd->audio_client,
 						volume_l, volume_r);
+			if (rc < 0) {
+				pr_err("%s: set lrgain command failed rc=%d\n",
+				__func__, rc);
+				return rc;
+			}
+			/*
+			 * set master gain to unity so that only lr gain
+			 * is effective
+			 */
+			rc = q6asm_set_volume(prtd->audio_client,
+						COMPRESSED_LR_VOL_MAX_STEPS);
 		} else {
 			pr_debug("%s: call q6asm_set_volume\n", __func__);
+			/*
+			 * set left and right channel gain to unity so that
+			 * only master gain is effective
+			 */
+			rc = q6asm_set_lrgain(prtd->audio_client,
+						COMPRESSED_LR_VOL_MAX_STEPS,
+						COMPRESSED_LR_VOL_MAX_STEPS);
+			if (rc < 0) {
+				pr_err("%s: set lrgain command failed rc=%d\n",
+				__func__, rc);
+				return rc;
+			}
 			rc = q6asm_set_volume(prtd->audio_client, volume_l);
 		}
 		if (rc < 0) {
@@ -574,10 +597,6 @@
 				prtd->session_id,
 				SNDRV_PCM_STREAM_PLAYBACK);
 
-	ret = msm_compr_set_volume(cstream, 0, 0);
-	if (ret < 0)
-		pr_err("%s : Set Volume failed : %d", __func__, ret);
-
 	ret = q6asm_set_softvolume(ac, &softvol);
 	if (ret < 0)
 		pr_err("%s: Send SoftVolume Param failed ret=%d\n",
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
index 7c6f0ea..a5d42d5 100644
--- a/sound/soc/soc-pcm.c
+++ b/sound/soc/soc-pcm.c
@@ -1703,25 +1703,22 @@
 	}
 
 	ret = dpcm_be_dai_prepare(fe, substream->stream);
-	if (ret < 0)
+	if (ret < 0) {
+		dev_err(fe->dev, "ASoC: prepare FE %s failed\n",
+						fe->dai_link->name);
 		goto out;
+	}
 
 	/* call prepare on the frontend */
 	if (!fe->fe_compr) {
 		ret = soc_pcm_prepare(substream);
 		if (ret < 0) {
-			dev_err(fe->dev,"ASoC: prepare FE %s failed\n",
+			dev_err(fe->dev, "ASoC: prepare FE %s failed\n",
 							fe->dai_link->name);
 			goto out;
 		}
 	}
 
-	ret = soc_pcm_prepare(substream);
-	if (ret < 0) {
-		dev_err(fe->dev,"dpcm: prepare FE %s failed\n", fe->dai_link->name);
-		goto out;
-	}
-
 	/* run the stream event for each BE */
 	if (stream == SNDRV_PCM_STREAM_PLAYBACK)
 		dpcm_dapm_stream_event(fe, stream,