Merge "USB: ci13xxx_udc:  Add support for UI interrupts counting"
diff --git a/AndroidKernel.mk b/AndroidKernel.mk
index d97d3c3..588688c 100644
--- a/AndroidKernel.mk
+++ b/AndroidKernel.mk
@@ -1,6 +1,11 @@
 #Android makefile to build kernel as a part of Android Build
 PERL		= perl
 
+KERNEL_TARGET := $(strip $(INSTALLED_KERNEL_TARGET))
+ifeq ($(KERNEL_TARGET),)
+INSTALLED_KERNEL_TARGET := $(PRODUCT_OUT)/kernel
+endif
+
 ifeq ($(TARGET_PREBUILT_KERNEL),)
 
 KERNEL_OUT := $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ
diff --git a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
index 3144045..afbae5e 100644
--- a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
@@ -290,6 +290,18 @@
 - qcom,mdss-tear-check-frame-rate:	Specify the value to be a real frame rate(fps) x 100 factor to tune the
 					timing of TE simulation with more precision.
 					The default value is 6000 with 60 fps.
+- qcom,panel-roi-alignment:		Specifies the panel ROI alignment restrictions on its
+					left, top, width, height alignments and minimum width and
+					height values
+- qcom,dynamic-mode-switch-enabled:		Boolean used to mention whether panel supports
+					dynamic switching from video mode to command mode
+					and vice versa.
+- qcom,video-to-cmd-mode-switch-commands:	List of commands that need to be sent
+					to panel in order to switch from video mode to command mode dynamically.
+					Refer to "qcom,mdss-dsi-on-command" section for adding commands.
+- qcom,cmd-to-video-mode-switch-commands:	List of commands that need to be sent
+					to panel in order to switch from command mode to video mode dynamically.
+					Refer to "qcom,mdss-dsi-on-command" section for adding commands.
 
 Note, if a given optional qcom,* binding is not present, then the driver will configure
 the default values specified.
@@ -395,5 +407,10 @@
 		qcom,mdss-tear-check-start-pos = <1280>;
 		qcom,mdss-tear-check-rd-ptr-trigger-intr = <1281>;
 		qcom,mdss-tear-check-frame-rate = <6000>;
+		qcom,panel-roi-alignment = <4 4 2 2 20 20>;
+		qcom,dynamic-mode-switch-enabled;
+		qcom,video-to-cmd-mode-switch-commands = [15 01 00 00 00 00 02 C2 0B
+						15 01 00 00 00 00 02 C2 08];
+		qcom,cmd-to-video-mode-switch-commands = [15 01 00 00 00 00 02 C2 03];
 	};
 };
diff --git a/Documentation/devicetree/bindings/platform/msm/avtimer.txt b/Documentation/devicetree/bindings/platform/msm/avtimer.txt
new file mode 100644
index 0000000..86c9b67
--- /dev/null
+++ b/Documentation/devicetree/bindings/platform/msm/avtimer.txt
@@ -0,0 +1,21 @@
+* avtimer
+
+Avtimer provides an interface for clients to enable avtimer block
+on qdsp6. 64 bit AVtimer exposed by qdsp6 is used for audio and video
+stream synchronization during capture and playback usecases.
+
+Required properties:
+- reg : physical address and length of avtimer register
+- reg-names : AVtimer register name
+  Required register resource entries are:
+  "avtimer_lsb_addr" : AVtimer lsb physical address
+  "avtimer_msb_addr" : AVtimer msb physical address
+- compatible : Must be "qcom,avtimer"
+
+Example:
+	qcom,avtimer {
+		compatible = "qcom,avtimer";
+		reg = <0xfe053008 0x4>,
+			<0xfe05300c 0x4>;
+		reg-names = "avtimer_lsb_addr", "avtimer_msb_addr";
+	};
diff --git a/Documentation/devicetree/bindings/power/qpnp-charger.txt b/Documentation/devicetree/bindings/power/qpnp-charger.txt
index 87ecc64..ff89757 100644
--- a/Documentation/devicetree/bindings/power/qpnp-charger.txt
+++ b/Documentation/devicetree/bindings/power/qpnp-charger.txt
@@ -110,6 +110,8 @@
 					DC and USB OVP FETs. Please note that this should only
 					be enabled in board designs with PM8941 which have DC_IN
 					and USB_IN connected via a short.
+ - qcom,ext-ovp-isns-enable-gpio	External OVP enable GPIO.
+ - qcom,ext-ovp-isns-r-ohm			External ISNS OVP resistance in ohm.
 
 Sub node required structure:
 - A qcom,chg node must be a child of an SPMI node that has specified
diff --git a/Documentation/devicetree/bindings/tty/serial/msm_serial_hs.txt b/Documentation/devicetree/bindings/tty/serial/msm_serial_hs.txt
index 762d40f..031be45 100644
--- a/Documentation/devicetree/bindings/tty/serial/msm_serial_hs.txt
+++ b/Documentation/devicetree/bindings/tty/serial/msm_serial_hs.txt
@@ -64,6 +64,9 @@
 receiving interrupt with UART RX GPIO IRQ line (i.e. above wakeup_irq property),
 HSUART driver injects provided character with property rx_to_inject.
 - qcom, rx-char-to-inject : The character to be inserted on wakeup.
+- qcom, no-suspend-delay : This decides system to go to suspend immediately
+or not
+
 - Refer to "Documentation/devicetree/bindings/arm/msm/msm_bus.txt" for
 below optional properties:
     - qcom,msm_bus,name
diff --git a/arch/arm/boot/dts/dsi-panel-nt35590-720p-video.dtsi b/arch/arm/boot/dts/dsi-panel-nt35590-720p-video.dtsi
index 9a18a31..bab1735 100644
--- a/arch/arm/boot/dts/dsi-panel-nt35590-720p-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-nt35590-720p-video.dtsi
@@ -511,6 +511,10 @@
 					05 01 00 00 78 00 02 10 00];
 		qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
 		qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
+		qcom,dynamic-mode-switch-enabled;
+		qcom,video-to-cmd-mode-switch-commands = [15 01 00 00 14 00 02 C2 0B
+					15 01 00 00 00 00 02 C2 08];
+		qcom,cmd-to-video-mode-switch-commands = [15 01 00 00 00 00 02 C2 03];
 		qcom,mdss-dsi-h-sync-pulse = <1>;
 		qcom,mdss-dsi-traffic-mode = "burst_mode";
 		qcom,mdss-dsi-bllp-eof-power-mode;
diff --git a/arch/arm/boot/dts/msm8610.dtsi b/arch/arm/boot/dts/msm8610.dtsi
index d243b78..ad029ee 100644
--- a/arch/arm/boot/dts/msm8610.dtsi
+++ b/arch/arm/boot/dts/msm8610.dtsi
@@ -470,14 +470,25 @@
 
 	qcom,clock-a7@f9011050 {
 		compatible = "qcom,clock-a7-8226";
-		reg = <0xf9011050 0x8>;
-		reg-names = "rcg-base";
+		reg = <0xf9011050 0x8>,
+		      <0xfc4b80b8 0x8>;
+		reg-names = "rcg-base", "efuse";
 		clock-names = "clk-4", "clk-5";
 		qcom,speed0-bin-v0 =
 			<         0 0>,
 			< 384000000 1>,
 			< 787200000 2>,
 			<1190400000 3>;
+		qcom,speed1-bin-v0 =
+			<         0 0>,
+			< 384000000 1>,
+			< 787200000 2>,
+			<1094400000 3>;
+		qcom,speed1-bin-v2 =
+			<         0 0>,
+			< 384000000 1>,
+			< 787200000 2>,
+			<1094400000 3>;
 
 		cpu-vdd-supply = <&apc_vreg_corner>;
 	};
@@ -500,6 +511,7 @@
 			<  600000 1525 >,
 			<  787200 1525 >,
 			<  998400 2540 >,
+			< 1094400 2540 >,
 			< 1190400 2540 >;
 	};
 
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index 4eb26a2..99dbec8 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-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
@@ -2523,6 +2523,13 @@
 			qcom,smdtty-dev-name = "LOOPBACK_TTY";
 		};
 	};
+
+	qcom,avtimer {
+		compatible = "qcom,avtimer";
+		reg = <0xfe053008 0x4>,
+			<0xfe05300c 0x4>;
+		reg-names = "avtimer_lsb_addr", "avtimer_msb_addr";
+	};
 };
 
 &gdsc_venus {
diff --git a/arch/arm/boot/dts/msm8974pro-pma8084-regulator.dtsi b/arch/arm/boot/dts/msm8974pro-pma8084-regulator.dtsi
index 49bf4ea..433d466 100644
--- a/arch/arm/boot/dts/msm8974pro-pma8084-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8974pro-pma8084-regulator.dtsi
@@ -483,6 +483,7 @@
 		qcom,use-phase-scaling-factor;
 		qcom,phase-scaling-factor-bits-pos = <16>;
 		qcom,valid-scaling-factor-versions = <0 1 1 0>;
+		qcom,force-auto-mode;
 
 		krait0_vreg: regulator@f9088000 {
 			compatible = "qcom,krait-regulator";
diff --git a/arch/arm/boot/dts/msm8974pro.dtsi b/arch/arm/boot/dts/msm8974pro.dtsi
index bb4c619..3e00a46 100644
--- a/arch/arm/boot/dts/msm8974pro.dtsi
+++ b/arch/arm/boot/dts/msm8974pro.dtsi
@@ -1723,7 +1723,11 @@
 		<3240000 1600000>,
 		<4048000 1600000>,
 		<4264000 1600000>;
-	qcom,max-hw-load = <1216800>; /* 3840 X 2160 @ 30 fps + 1920 X 1088 @ 30 fps */
+    /*
+     * Performance is guaranteed only upto POR specification. Anything
+     * above that specification is best effort and might even be rejected.
+     */
+	qcom,max-hw-load = <1281600>; /* max(4k X 2304 @ 24, 4k X 2160 @ 30) + 1080p @ 30 */
 	qcom,buffer-type-tz-usage-table = <0x241 0x1>,
 					<0x106 0x2>,
 					<0x480 0x3>;
diff --git a/arch/arm/common/gic.c b/arch/arm/common/gic.c
index b4574aa..3f40def 100644
--- a/arch/arm/common/gic.c
+++ b/arch/arm/common/gic.c
@@ -48,6 +48,7 @@
 #include <asm/system.h>
 
 #include <mach/socinfo.h>
+#include <mach/msm_rtb.h>
 
 union gic_base {
 	void __iomem *common_base;
@@ -310,7 +311,7 @@
 
 	if (gic->need_access_lock)
 		raw_spin_lock(&irq_controller_lock);
-	writel_relaxed(gic_irq(d), gic_cpu_base(d) + GIC_CPU_EOI);
+	writel_relaxed_no_log(gic_irq(d), gic_cpu_base(d) + GIC_CPU_EOI);
 	if (gic->need_access_lock)
 		raw_spin_unlock(&irq_controller_lock);
 }
@@ -388,8 +389,8 @@
 	bit = 1 << (cpu_logical_map(cpu) + shift);
 
 	raw_spin_lock(&irq_controller_lock);
-	val = readl_relaxed(reg) & ~mask;
-	writel_relaxed(val | bit, reg);
+	val = readl_relaxed_no_log(reg) & ~mask;
+	writel_relaxed_no_log(val | bit, reg);
 	raw_spin_unlock(&irq_controller_lock);
 
 	return IRQ_SET_MASK_OK;
@@ -434,7 +435,7 @@
 	do {
 		if (gic->need_access_lock)
 			raw_spin_lock(&irq_controller_lock);
-		irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK);
+		irqstat = readl_relaxed_no_log(cpu_base + GIC_CPU_INTACK);
 		if (gic->need_access_lock)
 			raw_spin_unlock(&irq_controller_lock);
 		irqnr = irqstat & ~0x1c00;
@@ -442,16 +443,18 @@
 		if (likely(irqnr > 15 && irqnr < 1021)) {
 			irqnr = irq_find_mapping(gic->domain, irqnr);
 			handle_IRQ(irqnr, regs);
+			uncached_logk(LOGK_IRQ, (void *)(uintptr_t)irqnr);
 			continue;
 		}
 		if (irqnr < 16) {
 			if (gic->need_access_lock)
 				raw_spin_lock(&irq_controller_lock);
-			writel_relaxed(irqstat, cpu_base + GIC_CPU_EOI);
+			writel_relaxed_no_log(irqstat, cpu_base + GIC_CPU_EOI);
 			if (gic->need_access_lock)
 				raw_spin_unlock(&irq_controller_lock);
 #ifdef CONFIG_SMP
 			handle_IPI(irqnr, regs);
+			uncached_logk(LOGK_IRQ, (void *)(uintptr_t)irqnr);
 #endif
 			continue;
 		}
@@ -713,19 +716,22 @@
 	if (!dist_base || !cpu_base)
 		return;
 
-	saved_cpu_ctrl = readl_relaxed(cpu_base + GIC_CPU_CTRL);
+	saved_cpu_ctrl = readl_relaxed_no_log(cpu_base + GIC_CPU_CTRL);
 
 	for (i = 0; i < DIV_ROUND_UP(32, 4); i++)
-		gic_data[gic_nr].saved_dist_pri[i] = readl_relaxed(dist_base +
+		gic_data[gic_nr].saved_dist_pri[i] = readl_relaxed_no_log(
+							dist_base +
 							GIC_DIST_PRI + i * 4);
 
 	ptr = __this_cpu_ptr(gic_data[gic_nr].saved_ppi_enable);
 	for (i = 0; i < DIV_ROUND_UP(32, 32); i++)
-		ptr[i] = readl_relaxed(dist_base + GIC_DIST_ENABLE_SET + i * 4);
+		ptr[i] = readl_relaxed_no_log(dist_base +
+				GIC_DIST_ENABLE_SET + i * 4);
 
 	ptr = __this_cpu_ptr(gic_data[gic_nr].saved_ppi_conf);
 	for (i = 0; i < DIV_ROUND_UP(32, 16); i++)
-		ptr[i] = readl_relaxed(dist_base + GIC_DIST_CONFIG + i * 4);
+		ptr[i] = readl_relaxed_no_log(dist_base +
+				GIC_DIST_CONFIG + i * 4);
 
 }
 
@@ -747,18 +753,20 @@
 
 	ptr = __this_cpu_ptr(gic_data[gic_nr].saved_ppi_enable);
 	for (i = 0; i < DIV_ROUND_UP(32, 32); i++)
-		writel_relaxed(ptr[i], dist_base + GIC_DIST_ENABLE_SET + i * 4);
+		writel_relaxed_no_log(ptr[i], dist_base +
+			GIC_DIST_ENABLE_SET + i * 4);
 
 	ptr = __this_cpu_ptr(gic_data[gic_nr].saved_ppi_conf);
 	for (i = 0; i < DIV_ROUND_UP(32, 16); i++)
-		writel_relaxed(ptr[i], dist_base + GIC_DIST_CONFIG + i * 4);
+		writel_relaxed_no_log(ptr[i], dist_base +
+			GIC_DIST_CONFIG + i * 4);
 
 	for (i = 0; i < DIV_ROUND_UP(32, 4); i++)
-		writel_relaxed(gic_data[gic_nr].saved_dist_pri[i],
+		writel_relaxed_no_log(gic_data[gic_nr].saved_dist_pri[i],
 			dist_base + GIC_DIST_PRI + i * 4);
 
-	writel_relaxed(0xf0, cpu_base + GIC_CPU_PRIMASK);
-	writel_relaxed(saved_cpu_ctrl, cpu_base + GIC_CPU_CTRL);
+	writel_relaxed_no_log(0xf0, cpu_base + GIC_CPU_PRIMASK);
+	writel_relaxed_no_log(saved_cpu_ctrl, cpu_base + GIC_CPU_CTRL);
 }
 
 static int gic_notifier(struct notifier_block *self, unsigned long cmd,	void *v)
@@ -993,7 +1001,7 @@
 	if (gic->need_access_lock)
 		raw_spin_lock_irqsave(&irq_controller_lock, flags);
 	/* this always happens on GIC0 */
-	writel_relaxed(sgir, gic_data_dist_base(gic) + GIC_DIST_SOFTINT);
+	writel_relaxed_no_log(sgir, gic_data_dist_base(gic) + GIC_DIST_SOFTINT);
 	if (gic->need_access_lock)
 		raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
 	mb();
diff --git a/arch/arm/configs/msm8974-perf_defconfig b/arch/arm/configs/msm8974-perf_defconfig
index 478e766..414a4df 100755
--- a/arch/arm/configs/msm8974-perf_defconfig
+++ b/arch/arm/configs/msm8974-perf_defconfig
@@ -503,8 +503,10 @@
 CONFIG_CRYPTO_DEV_QCRYPTO=m
 CONFIG_CRYPTO_DEV_QCE=y
 CONFIG_CRYPTO_DEV_QCEDEV=y
+CONFIG_PFT=y
 CONFIG_SND_SOC_MSM_HDMI_CODEC_RX=y
 CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE=y
 CONFIG_MSM_RDBG=m
 CONFIG_DEVMEM=n
 CONFIG_DEVKMEM=n
+CONFIG_MSM_AVTIMER=y
diff --git a/arch/arm/configs/msm8974_defconfig b/arch/arm/configs/msm8974_defconfig
index c5c16c2..3b2f2b5 100755
--- a/arch/arm/configs/msm8974_defconfig
+++ b/arch/arm/configs/msm8974_defconfig
@@ -561,6 +561,8 @@
 CONFIG_CRYPTO_DEV_QCRYPTO=y
 CONFIG_CRYPTO_DEV_QCE=y
 CONFIG_CRYPTO_DEV_QCEDEV=y
+CONFIG_PFT=y
 CONFIG_SND_SOC_MSM_HDMI_CODEC_RX=y
 CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE=y
 CONFIG_MSM_RDBG=m
+CONFIG_MSM_AVTIMER=y
diff --git a/arch/arm/mach-msm/clock-8610.c b/arch/arm/mach-msm/clock-8610.c
index e9c749a..482981c 100644
--- a/arch/arm/mach-msm/clock-8610.c
+++ b/arch/arm/mach-msm/clock-8610.c
@@ -559,6 +559,7 @@
 	F_APCS_PLL( 768000000, 40, 0x0, 0x1, 0x0, 0x0, 0x0),
 	F_APCS_PLL( 787200000, 41, 0x0, 0x1, 0x0, 0x0, 0x0),
 	F_APCS_PLL( 998400000, 52, 0x0, 0x1, 0x0, 0x0, 0x0),
+	F_APCS_PLL(1094400000, 57, 0x0, 0x1, 0x0, 0x0, 0x0),
 	F_APCS_PLL(1190400000, 62, 0x0, 0x1, 0x0, 0x0, 0x0),
 	PLL_F_END
 };
diff --git a/arch/arm/mach-msm/include/mach/msm_rtb.h b/arch/arm/mach-msm/include/mach/msm_rtb.h
index b33e8b6..c419a3d 100644
--- a/arch/arm/mach-msm/include/mach/msm_rtb.h
+++ b/arch/arm/mach-msm/include/mach/msm_rtb.h
@@ -27,6 +27,7 @@
 	LOGK_TIMESTAMP = 6,
 	LOGK_L2CPREAD = 7,
 	LOGK_L2CPWRITE = 8,
+	LOGK_IRQ = 9,
 };
 
 #define LOGTYPE_NOPC 0x80
diff --git a/arch/arm/mach-msm/include/mach/msm_serial_hs.h b/arch/arm/mach-msm/include/mach/msm_serial_hs.h
index e6b677e..edc85ba 100644
--- a/arch/arm/mach-msm/include/mach/msm_serial_hs.h
+++ b/arch/arm/mach-msm/include/mach/msm_serial_hs.h
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2008 Google, Inc.
- * Copyright (C) 2010-2013, The Linux Foundation. All rights reserved.
+ * Copyright (C) 2010-2014, The Linux Foundation. All rights reserved.
  * Author: Nick Pelly <npelly@google.com>
  *
  * This software is licensed under the terms of the GNU General Public
@@ -32,6 +32,8 @@
  * @uart_rfr_gpio: GPIO number for UART RFR Line.
  * @bam_tx_ep_pipe_index : BAM TX Endpoint Pipe Index for HSUART
  * @bam_tx_ep_pipe_index : BAM RX Endpoint Pipe Index for HSUART
+ * @no_suspend_delay : Flag used to make system go to suspend
+ * immediately or not
  */
 struct msm_serial_hs_platform_data {
 	int wakeup_irq;  /* wakeup irq */
@@ -46,6 +48,7 @@
 	int uart_rfr_gpio;
 	unsigned bam_tx_ep_pipe_index;
 	unsigned bam_rx_ep_pipe_index;
+	bool no_suspend_delay;
 };
 
 unsigned int msm_hs_tx_empty(struct uart_port *uport);
diff --git a/block/blk-merge.c b/block/blk-merge.c
index 5d74cc3..9fa7765 100644
--- a/block/blk-merge.c
+++ b/block/blk-merge.c
@@ -6,6 +6,7 @@
 #include <linux/bio.h>
 #include <linux/blkdev.h>
 #include <linux/scatterlist.h>
+#include <linux/security.h>
 
 #include "blk.h"
 
@@ -509,6 +510,10 @@
 	if (bio_integrity(bio) != blk_integrity_rq(rq))
 		return false;
 
+	/* Don't merge bios of files with different encryption */
+	if (!security_allow_merge_bio(rq->bio, bio))
+		return false;
+
 	return true;
 }
 
diff --git a/block/row-iosched.c b/block/row-iosched.c
index dfb46b4..9b39741 100644
--- a/block/row-iosched.c
+++ b/block/row-iosched.c
@@ -1,7 +1,7 @@
 /*
  * ROW (Read Over Write) I/O scheduler.
  *
- * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-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
@@ -331,10 +331,6 @@
 	struct row_queue *rqueue = RQ_ROWQ(rq);
 	s64 diff_ms;
 	bool queue_was_empty = list_empty(&rqueue->fifo);
-	unsigned long bv_page_flags = 0;
-
-	if (rq->bio && rq->bio->bi_io_vec && rq->bio->bi_io_vec->bv_page)
-		bv_page_flags = rq->bio->bi_io_vec->bv_page->flags;
 
 	list_add_tail(&rq->queuelist, &rqueue->fifo);
 	rd->nr_reqs[rq_data_dir(rq)]++;
@@ -367,9 +363,7 @@
 			rqueue->idle_data.begin_idling = false;
 			return;
 		}
-
-		if ((bv_page_flags & (1L << PG_readahead)) ||
-		    (diff_ms < rd->rd_idle_data.freq_ms)) {
+		if (diff_ms < rd->rd_idle_data.freq_ms) {
 			rqueue->idle_data.begin_idling = true;
 			row_log_rowq(rd, rqueue->prio, "Enable idling");
 		} else {
diff --git a/drivers/char/diag/diag_dci.c b/drivers/char/diag/diag_dci.c
index 0edfdad..653e299 100644
--- a/drivers/char/diag/diag_dci.c
+++ b/drivers/char/diag/diag_dci.c
@@ -22,7 +22,10 @@
 #include <linux/platform_device.h>
 #include <linux/pm_wakeup.h>
 #include <linux/spinlock.h>
+#include <linux/ratelimit.h>
+#include <linux/reboot.h>
 #include <asm/current.h>
+#include <mach/restart.h>
 #ifdef CONFIG_DIAG_OVER_USB
 #include <mach/usbdiag.h>
 #endif
@@ -33,6 +36,10 @@
 #include "diagfwd_cntl.h"
 #include "diag_dci.h"
 
+static struct timer_list dci_drain_timer;
+static int dci_timer_in_progress;
+static struct work_struct dci_data_drain_work;
+
 unsigned int dci_max_reg = 100;
 unsigned int dci_max_clients = 10;
 unsigned char dci_cumulative_log_mask[DCI_LOG_MASK_SIZE];
@@ -47,14 +54,15 @@
 /* Number of milliseconds anticipated to process the DCI data */
 #define DCI_WAKEUP_TIMEOUT 1
 
-#define DCI_CHK_CAPACITY(entry, new_data_len)				\
-((entry->data_len + new_data_len > entry->total_capacity) ? 1 : 0)	\
+#define DCI_CAN_ADD_BUF_TO_LIST(buf)					\
+	(buf && buf->data && !buf->in_busy && buf->data_len > 0)	\
 
 #ifdef CONFIG_DEBUG_FS
 struct diag_dci_data_info *dci_data_smd;
 struct mutex dci_stat_mutex;
 
-void diag_dci_smd_record_info(int read_bytes, uint8_t ch_type)
+void diag_dci_smd_record_info(int read_bytes, uint8_t ch_type,
+			      uint8_t peripheral)
 {
 	static int curr_dci_data_smd;
 	static unsigned long iteration;
@@ -67,6 +75,7 @@
 	temp_data += curr_dci_data_smd;
 	temp_data->iteration = iteration + 1;
 	temp_data->data_size = read_bytes;
+	temp_data->peripheral = peripheral;
 	temp_data->ch_type = ch_type;
 	diag_get_timestamp(temp_data->time_stamp);
 	curr_dci_data_smd++;
@@ -74,50 +83,393 @@
 	mutex_unlock(&dci_stat_mutex);
 }
 #else
-void diag_dci_smd_record_info(int read_bytes, uint8_t ch_type) { }
+void diag_dci_smd_record_info(int read_bytes, uint8_t ch_type,
+			      uint8_t peripheral) { }
 #endif
 
+static void dci_drain_data(unsigned long data)
+{
+	queue_work(driver->diag_dci_wq, &dci_data_drain_work);
+}
+
+static void dci_check_drain_timer(void)
+{
+	if (!dci_timer_in_progress) {
+		dci_timer_in_progress = 1;
+		 mod_timer(&dci_drain_timer, jiffies + msecs_to_jiffies(500));
+	}
+}
+
+static int diag_dci_init_buffer(struct diag_dci_buffer_t *buffer, int type)
+{
+	if (!buffer || buffer->data)
+		return -EINVAL;
+
+	switch (type) {
+	case DCI_BUF_PRIMARY:
+		buffer->data = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
+		if (!buffer->data)
+			return -ENOMEM;
+		buffer->capacity = IN_BUF_SIZE;
+		break;
+	case DCI_BUF_SECONDARY:
+		buffer->data = NULL;
+		buffer->capacity = IN_BUF_SIZE;
+		break;
+	case DCI_BUF_CMD:
+		buffer->data = kzalloc(PKT_SIZE, GFP_KERNEL);
+		if (!buffer->data)
+			return -ENOMEM;
+		buffer->capacity = PKT_SIZE;
+		break;
+	default:
+		pr_err("diag: In %s, unknown type %d", __func__, type);
+		return -EINVAL;
+	}
+
+	buffer->data_len = 0;
+	buffer->in_busy = 0;
+	buffer->buf_type = type;
+	mutex_init(&buffer->data_mutex);
+
+	return 0;
+}
+
+static inline int diag_dci_check_buffer(struct diag_dci_buffer_t *buf, int len)
+{
+	if (!buf)
+		return -EINVAL;
+
+	/* Return 1 if the buffer is not busy and can hold new data */
+	if ((buf->data_len + len < buf->capacity) && !buf->in_busy)
+		return 1;
+
+	return 0;
+}
+
+static void dci_add_buffer_to_list(struct diag_dci_client_tbl *client,
+				   struct diag_dci_buffer_t *buf)
+{
+	if (!buf || !client || !buf->data)
+		return;
+
+	if (buf->in_list || buf->data_len == 0)
+		return;
+
+	mutex_lock(&client->write_buf_mutex);
+	list_add_tail(&buf->buf_track, &client->list_write_buf);
+	mutex_lock(&buf->data_mutex);
+	buf->in_busy = 1;
+	buf->in_list = 1;
+	mutex_unlock(&buf->data_mutex);
+	mutex_unlock(&client->write_buf_mutex);
+}
+
+static int diag_dci_get_buffer(struct diag_dci_client_tbl *client,
+			       int data_source, int len)
+{
+	struct diag_dci_buffer_t *buf_primary = NULL;
+	struct diag_dci_buffer_t *buf_temp = NULL;
+	struct diag_dci_buffer_t *curr = NULL;
+
+	if (!client)
+		return -EINVAL;
+	if (len < 0 || len > IN_BUF_SIZE)
+		return -EINVAL;
+
+	curr = client->buffers[data_source].buf_curr;
+	buf_primary = client->buffers[data_source].buf_primary;
+
+	if (curr && diag_dci_check_buffer(curr, len) == 1)
+		return 0;
+
+	dci_add_buffer_to_list(client, curr);
+	client->buffers[data_source].buf_curr = NULL;
+
+	if (diag_dci_check_buffer(buf_primary, len) == 1) {
+		client->buffers[data_source].buf_curr = buf_primary;
+		return 0;
+	}
+
+	buf_temp = kzalloc(sizeof(struct diag_dci_buffer_t), GFP_KERNEL);
+	if (!buf_temp)
+		return -EIO;
+
+	if (!diag_dci_init_buffer(buf_temp, DCI_BUF_SECONDARY)) {
+		buf_temp->data = diagmem_alloc(driver, driver->itemsize_dci,
+					       POOL_TYPE_DCI);
+		if (!buf_temp->data) {
+			kfree(buf_temp);
+			buf_temp = NULL;
+			return -ENOMEM;
+		}
+		client->buffers[data_source].buf_curr = buf_temp;
+		return 0;
+	}
+
+	kfree(buf_temp);
+	buf_temp = NULL;
+	return -EIO;
+}
+
+void diag_dci_wakeup_clients()
+{
+	struct list_head *start, *temp;
+	struct diag_dci_client_tbl *entry = NULL;
+
+	list_for_each_safe(start, temp, &driver->dci_client_list) {
+		entry = list_entry(start, struct diag_dci_client_tbl, track);
+
+		/*
+		 * Don't wake up the client when there is no pending buffer to
+		 * write or when it is writing to user space
+		 */
+		if (!list_empty(&entry->list_write_buf) && !entry->in_service) {
+			mutex_lock(&entry->write_buf_mutex);
+			entry->in_service = 1;
+			mutex_unlock(&entry->write_buf_mutex);
+			diag_update_sleeping_process(entry->client->tgid,
+						     DCI_DATA_TYPE);
+		}
+	}
+}
+
+void dci_data_drain_work_fn(struct work_struct *work)
+{
+	int i;
+	struct list_head *start, *temp;
+	struct diag_dci_client_tbl *entry = NULL;
+	struct diag_dci_buf_peripheral_t *proc_buf = NULL;
+	struct diag_dci_buffer_t *buf_temp = NULL;
+
+	list_for_each_safe(start, temp, &driver->dci_client_list) {
+		entry = list_entry(start, struct diag_dci_client_tbl, track);
+		for (i = 0; i < NUM_DCI_PROC; i++) {
+			proc_buf = &entry->buffers[i];
+
+			buf_temp = proc_buf->buf_primary;
+			if (DCI_CAN_ADD_BUF_TO_LIST(buf_temp))
+				dci_add_buffer_to_list(entry, buf_temp);
+
+			buf_temp = proc_buf->buf_cmd;
+			if (DCI_CAN_ADD_BUF_TO_LIST(buf_temp))
+				dci_add_buffer_to_list(entry, buf_temp);
+
+			buf_temp = proc_buf->buf_curr;
+			if (DCI_CAN_ADD_BUF_TO_LIST(buf_temp)) {
+				dci_add_buffer_to_list(entry, buf_temp);
+				mutex_lock(&proc_buf->buf_mutex);
+				proc_buf->buf_curr = NULL;
+				mutex_unlock(&proc_buf->buf_mutex);
+			}
+		}
+		if (!list_empty(&entry->list_write_buf) && !entry->in_service) {
+			mutex_lock(&entry->write_buf_mutex);
+			entry->in_service = 1;
+			mutex_unlock(&entry->write_buf_mutex);
+			diag_update_sleeping_process(entry->client->tgid,
+						     DCI_DATA_TYPE);
+		}
+	}
+	dci_timer_in_progress = 0;
+}
+
+/* Process the data read from apps userspace client */
+void diag_process_apps_dci_read_data(int data_type, void *buf, int recd_bytes)
+{
+	uint8_t cmd_code;
+
+	if (!buf) {
+		pr_err_ratelimited("diag: In %s, Null buf pointer\n", __func__);
+		return;
+	}
+
+	if (data_type != DATA_TYPE_DCI_LOG && data_type != DATA_TYPE_DCI_EVENT
+						&& data_type != DCI_PKT_TYPE) {
+		pr_err("diag: In %s, unsupported data_type: 0x%x\n",
+				__func__, (unsigned int)data_type);
+		return;
+	}
+
+	cmd_code = *(uint8_t *)buf;
+
+	switch (cmd_code) {
+	case LOG_CMD_CODE:
+		extract_dci_log(buf, recd_bytes, APPS_DATA);
+		break;
+	case EVENT_CMD_CODE:
+		extract_dci_events(buf, recd_bytes, APPS_DATA);
+		break;
+	case DCI_PKT_RSP_CODE:
+	case DCI_DELAYED_RSP_CODE:
+		extract_dci_pkt_rsp(buf, recd_bytes, APPS_DATA, NULL);
+		break;
+	default:
+		pr_err("diag: In %s, unsupported command code: 0x%x, not log or event\n",
+		       __func__, cmd_code);
+		return;
+
+	}
+
+	/* wake up all sleeping DCI clients which have some data */
+	diag_dci_wakeup_clients();
+	dci_check_drain_timer();
+}
+
 /* Process the data read from the smd dci channel */
 int diag_process_smd_dci_read_data(struct diag_smd_info *smd_info, void *buf,
 								int recd_bytes)
 {
-	int read_bytes, dci_pkt_len, i;
+	int read_bytes, dci_pkt_len;
 	uint8_t recv_pkt_cmd_code;
 
-	diag_dci_smd_record_info(recd_bytes, (uint8_t)smd_info->type);
+	/*
+	 * Release wakeup source when there are no more clients to
+	 * process DCI data
+	 */
+	if (driver->num_dci_client == 0) {
+		diag_dci_try_deactivate_wakeup_source();
+		return 0;
+	}
+
+	diag_dci_smd_record_info(recd_bytes, (uint8_t)smd_info->type,
+				 (uint8_t)smd_info->peripheral);
 	/* Each SMD read can have multiple DCI packets */
 	read_bytes = 0;
 	while (read_bytes < recd_bytes) {
 		/* read actual length of dci pkt */
 		dci_pkt_len = *(uint16_t *)(buf+2);
+
+		/* Check if the length of the current packet is lesser than the
+		 * remaining bytes in the received buffer. This includes space
+		 * for the Start byte (1), Version byte (1), length bytes (2)
+		 * and End byte (1)
+		 */
+		if ((dci_pkt_len+5) > (recd_bytes-read_bytes)) {
+			pr_err("diag: Invalid length in %s, len: %d, dci_pkt_len: %d",
+					__func__, recd_bytes, dci_pkt_len);
+			diag_dci_try_deactivate_wakeup_source();
+			return 0;
+		}
 		/* process one dci packet */
-		pr_debug("diag: bytes read = %d, single dci pkt len = %d\n",
-			read_bytes, dci_pkt_len);
+		pr_debug("diag: dci: peripheral = %d bytes read = %d, single dci pkt len = %d\n",
+			 smd_info->peripheral, read_bytes, dci_pkt_len);
 		/* print_hex_dump(KERN_DEBUG, "Single DCI packet :",
 		 DUMP_PREFIX_ADDRESS, 16, 1, buf, 5 + dci_pkt_len, 1); */
 		recv_pkt_cmd_code = *(uint8_t *)(buf+4);
-		if (recv_pkt_cmd_code == LOG_CMD_CODE)
-			extract_dci_log(buf+4);
-		else if (recv_pkt_cmd_code == EVENT_CMD_CODE)
-			extract_dci_events(buf+4);
-		else
-			extract_dci_pkt_rsp(smd_info, buf); /* pkt response */
+		if (recv_pkt_cmd_code == LOG_CMD_CODE) {
+			/* Don't include the 4 bytes for command code */
+			extract_dci_log(buf + 4, recd_bytes - 4,
+					smd_info->peripheral);
+		} else if (recv_pkt_cmd_code == EVENT_CMD_CODE) {
+			/* Don't include the 4 bytes for command code */
+			extract_dci_events(buf + 4, recd_bytes - 4,
+					   smd_info->peripheral);
+		} else
+			extract_dci_pkt_rsp(buf + 4, dci_pkt_len,
+					    smd_info->peripheral, smd_info);
 		read_bytes += 5 + dci_pkt_len;
 		buf += 5 + dci_pkt_len; /* advance to next DCI pkt */
 	}
-	/* Release wakeup source when there are no more clients to
-	   process DCI data */
-	if (driver->num_dci_client == 0)
-		diag_dci_try_deactivate_wakeup_source(smd_info->ch);
 
 	/* wake up all sleeping DCI clients which have some data */
-	for (i = 0; i < MAX_DCI_CLIENTS; i++) {
-		if (driver->dci_client_tbl[i].client &&
-			driver->dci_client_tbl[i].data_len) {
-			smd_info->in_busy_1 = 1;
-			diag_update_sleeping_process(
-				driver->dci_client_tbl[i].client->tgid,
-					 DCI_DATA_TYPE);
+	diag_dci_wakeup_clients();
+	dci_check_drain_timer();
+	diag_dci_try_deactivate_wakeup_source();
+	return 0;
+}
+
+static inline struct diag_dci_client_tbl *__diag_dci_get_client_entry(
+								int client_id)
+{
+	struct list_head *start, *temp;
+	struct diag_dci_client_tbl *entry = NULL;
+	list_for_each_safe(start, temp, &driver->dci_client_list) {
+		entry = list_entry(start, struct diag_dci_client_tbl, track);
+		if (entry->client->tgid == client_id)
+			return entry;
+	}
+	return NULL;
+}
+
+static inline int __diag_dci_query_log_mask(struct diag_dci_client_tbl *entry,
+							uint16_t log_code)
+{
+	uint16_t item_num;
+	uint8_t equip_id, *log_mask_ptr, byte_mask;
+	int byte_index, offset;
+
+	if (!entry) {
+		pr_err("diag: In %s, invalid client entry\n", __func__);
+		return 0;
+	}
+
+	equip_id = LOG_GET_EQUIP_ID(log_code);
+	item_num = LOG_GET_ITEM_NUM(log_code);
+	byte_index = item_num/8 + 2;
+	byte_mask = 0x01 << (item_num % 8);
+	offset = equip_id * 514;
+
+	if (offset + byte_index > DCI_LOG_MASK_SIZE) {
+		pr_err("diag: In %s, invalid offset: %d, log_code: %d, byte_index: %d\n",
+				__func__, offset, log_code, byte_index);
+		return 0;
+	}
+
+	log_mask_ptr = entry->dci_log_mask;
+	log_mask_ptr = log_mask_ptr + offset + byte_index;
+	return ((*log_mask_ptr & byte_mask) == byte_mask) ? 1 : 0;
+
+}
+
+static inline int __diag_dci_query_event_mask(struct diag_dci_client_tbl *entry,
+							uint16_t event_id)
+{
+	uint8_t *event_mask_ptr, byte_mask;
+	int byte_index, bit_index;
+
+	if (!entry) {
+		pr_err("diag: In %s, invalid client entry\n", __func__);
+		return 0;
+	}
+
+	byte_index = event_id/8;
+	bit_index = event_id % 8;
+	byte_mask = 0x1 << bit_index;
+
+	if (byte_index > DCI_EVENT_MASK_SIZE) {
+		pr_err("diag: In %s, invalid, event_id: %d, byte_index: %d\n",
+				__func__, event_id, byte_index);
+		return 0;
+	}
+
+	event_mask_ptr = entry->dci_event_mask;
+	event_mask_ptr = event_mask_ptr + byte_index;
+	return ((*event_mask_ptr & byte_mask) == byte_mask) ? 1 : 0;
+}
+
+static int diag_dci_filter_commands(struct diag_pkt_header_t *header)
+{
+	if (!header)
+		return -ENOMEM;
+
+	switch (header->cmd_code) {
+	case 0x7d: /* Msg Mask Configuration */
+	case 0x73: /* Log Mask Configuration */
+	case 0x81: /* Event Mask Configuration */
+	case 0x82: /* Event Mask Change */
+	case 0x60: /* Event Mask Toggle */
+		return 1;
+	}
+
+	if (header->cmd_code == 0x4b && header->subsys_id == 0x12) {
+		switch (header->subsys_cmd_code) {
+		case 0x60: /* Extended Event Mask Config */
+		case 0x61: /* Extended Msg Mask Config */
+		case 0x62: /* Extended Log Mask Config */
+		case 0x20C: /* Set current Preset ID */
+		case 0x20D: /* Get current Preset ID */
+			return 1;
 		}
 	}
 
@@ -204,96 +556,181 @@
 	return 0;
 }
 
-void extract_dci_pkt_rsp(struct diag_smd_info *smd_info, unsigned char *buf)
+void extract_dci_pkt_rsp(unsigned char *buf, int len, int data_source,
+			 struct diag_smd_info *smd_info)
 {
-	int i = 0, cmd_code_len = 1;
-	int curr_client_pid = 0, write_len, *tag = NULL;
-	struct diag_dci_client_tbl *entry;
+	int tag, curr_client_pid = 0;
+	struct diag_dci_client_tbl *entry = NULL;
 	void *temp_buf = NULL;
-	uint8_t recv_pkt_cmd_code, delete_flag = 0;
+	uint8_t dci_cmd_code, cmd_code_len, delete_flag = 0;
+	uint32_t rsp_len = 0;
+	struct diag_dci_buffer_t *rsp_buf = NULL;
 	struct dci_pkt_req_entry_t *req_entry = NULL;
-	recv_pkt_cmd_code = *(uint8_t *)(buf+4);
-	if (recv_pkt_cmd_code != DCI_PKT_RSP_CODE)
-		cmd_code_len = 4; /* delayed response */
-	write_len = (int)(*(uint16_t *)(buf+2)) - cmd_code_len;
-	if (write_len <= 0) {
-		pr_err("diag: Invalid length in %s, write_len: %d",
-					__func__, write_len);
+	unsigned char *temp = buf;
+
+	if (!buf) {
+		pr_err("diag: Invalid pointer in %s\n", __func__);
 		return;
 	}
-	pr_debug("diag: len = %d\n", write_len);
-	tag = (int *)(buf + (4 + cmd_code_len)); /* Retrieve the Tag field */
-	req_entry = diag_dci_get_request_entry(*tag);
+	dci_cmd_code = *(uint8_t *)(temp);
+	if (dci_cmd_code == DCI_PKT_RSP_CODE) {
+		cmd_code_len = sizeof(uint8_t);
+	} else if (dci_cmd_code == DCI_DELAYED_RSP_CODE) {
+		cmd_code_len = sizeof(uint32_t);
+	} else {
+		pr_err("diag: In %s, invalid command code %d\n", __func__,
+								dci_cmd_code);
+		return;
+	}
+	temp += cmd_code_len;
+	tag = *(int *)temp;
+	temp += sizeof(int);
+
+	/*
+	 * The size of the response is (total length) - (length of the command
+	 * code, the tag (int)
+	 */
+	rsp_len = len - (cmd_code_len + sizeof(int));
+	/*
+	 * Check if the length embedded in the packet is correct.
+	 * Include the start (1), version (1), length (2) and the end
+	 * (1) bytes while checking. Total = 5 bytes
+	 */
+	if ((rsp_len == 0) || (rsp_len > (len - 5))) {
+		pr_err("diag: Invalid length in %s, len: %d, rsp_len: %d",
+						__func__, len, rsp_len);
+		return;
+	}
+
+	req_entry = diag_dci_get_request_entry(tag);
 	if (!req_entry) {
-		pr_alert("diag: No matching PID for DCI data\n");
+		pr_err("diag: No matching PID for DCI data\n");
 		return;
 	}
-	*tag = req_entry->uid;
 	curr_client_pid = req_entry->pid;
 
 	/* Remove the headers and send only the response to this function */
-	delete_flag = diag_dci_remove_req_entry(buf + 8 + cmd_code_len,
-						write_len - 4,
-						req_entry);
+	delete_flag = diag_dci_remove_req_entry(temp, rsp_len, req_entry);
 	if (delete_flag < 0)
 		return;
 
-	/* Using PID of client process, find client buffer */
-	i = diag_dci_find_client_index(curr_client_pid);
-	if (i != DCI_CLIENT_INDEX_INVALID) {
-		/* copy pkt rsp in client buf */
-		entry = &(driver->dci_client_tbl[i]);
-		mutex_lock(&entry->data_mutex);
-		/*
-		 * Check if we can fit the data in the rsp buffer. The total
-		 * length of the rsp is the rsp length (write_len) +
-		 * DCI_PKT_RSP_TYPE header (int) + field for length (int) +
-		 * delete_flag (uint8_t)
-		 */
-		if (DCI_CHK_CAPACITY(entry, 9+write_len)) {
-			pr_alert("diag: create capacity for pkt rsp\n");
-			entry->total_capacity += 9+write_len;
-			temp_buf = krealloc(entry->dci_data,
-			entry->total_capacity, GFP_KERNEL);
-			if (!temp_buf) {
-				pr_err("diag: DCI realloc failed\n");
-				mutex_unlock(&entry->data_mutex);
-				return;
-			} else {
-				entry->dci_data = temp_buf;
-			}
-		}
-		*(int *)(entry->dci_data+entry->data_len) =
-					DCI_PKT_RSP_TYPE;
-		entry->data_len += 4;
-		*(int *)(entry->dci_data+entry->data_len)
-						= write_len;
-		entry->data_len += 4;
-		*(uint8_t *)(entry->dci_data + entry->data_len) = delete_flag;
-		entry->data_len += sizeof(uint8_t);
-		memcpy(entry->dci_data+entry->data_len,
-			buf+4+cmd_code_len, write_len);
-		entry->data_len += write_len;
-		mutex_unlock(&entry->data_mutex);
+	entry = __diag_dci_get_client_entry(curr_client_pid);
+	if (!entry) {
+		pr_err("diag: In %s, couldn't find entry\n", __func__);
+		return;
 	}
+
+	rsp_buf = entry->buffers[data_source].buf_cmd;
+
+	mutex_lock(&rsp_buf->data_mutex);
+	/*
+	 * Check if we can fit the data in the rsp buffer. The total length of
+	 * the rsp is the rsp length (write_len) + DCI_PKT_RSP_TYPE header (int)
+	 * + field for length (int) + delete_flag (uint8_t)
+	 */
+	if ((rsp_buf->data_len + 9 + rsp_len) > rsp_buf->capacity) {
+		pr_alert("diag: create capacity for pkt rsp\n");
+		rsp_buf->capacity += 9 + rsp_len;
+		temp_buf = krealloc(rsp_buf->data, rsp_buf->capacity,
+				    GFP_KERNEL);
+		if (!temp_buf) {
+			pr_err("diag: DCI realloc failed\n");
+			mutex_unlock(&rsp_buf->data_mutex);
+			return;
+		} else {
+			rsp_buf->data = temp_buf;
+		}
+	}
+
+	/* Fill in packet response header information */
+	*(int *)(rsp_buf->data + rsp_buf->data_len) = DCI_PKT_RSP_TYPE;
+	rsp_buf->data_len += sizeof(int);
+	/* Packet Length = Response Length + Length of uid field (int) */
+	*(int *)(rsp_buf->data + rsp_buf->data_len) = rsp_len + sizeof(int);
+	rsp_buf->data_len += sizeof(int);
+	*(uint8_t *)(rsp_buf->data + rsp_buf->data_len) = delete_flag;
+	rsp_buf->data_len += sizeof(uint8_t);
+	*(int *)(rsp_buf->data + rsp_buf->data_len) = req_entry->uid;
+	rsp_buf->data_len += sizeof(int);
+	memcpy(rsp_buf->data + rsp_buf->data_len, temp, rsp_len);
+	rsp_buf->data_len += rsp_len;
+	rsp_buf->data_source = data_source;
+	if (smd_info)
+		smd_info->in_busy_1 = 1;
+	mutex_unlock(&rsp_buf->data_mutex);
+
+
+	/*
+	 * Add directly to the list for writing responses to the
+	 * userspace as these shouldn't be buffered and shouldn't wait
+	 * for log and event buffers to be full
+	 */
+	dci_add_buffer_to_list(entry, rsp_buf);
 }
 
-void extract_dci_events(unsigned char *buf)
+static void copy_dci_event(unsigned char *buf, int len,
+			   struct diag_dci_client_tbl *client, int data_source)
+{
+	struct diag_dci_buffer_t *data_buffer = NULL;
+	struct diag_dci_buf_peripheral_t *proc_buf = NULL;
+	int err = 0, total_len = 0;
+
+	if (!buf || !client) {
+		pr_err("diag: Invalid pointers in %s", __func__);
+		return;
+	}
+
+	total_len = sizeof(int) + len;
+
+	proc_buf = &client->buffers[data_source];
+	mutex_lock(&proc_buf->buf_mutex);
+	mutex_lock(&proc_buf->health_mutex);
+	err = diag_dci_get_buffer(client, data_source, total_len);
+	if (err) {
+		if (err == -ENOMEM)
+			proc_buf->health.dropped_events++;
+		else
+			pr_err("diag: In %s, invalid packet\n", __func__);
+		mutex_unlock(&proc_buf->health_mutex);
+		mutex_unlock(&proc_buf->buf_mutex);
+		return;
+	}
+
+	data_buffer = proc_buf->buf_curr;
+
+	proc_buf->health.received_events++;
+	mutex_unlock(&proc_buf->health_mutex);
+	mutex_unlock(&proc_buf->buf_mutex);
+
+	mutex_lock(&data_buffer->data_mutex);
+	*(int *)(data_buffer->data + data_buffer->data_len) = DCI_EVENT_TYPE;
+	data_buffer->data_len += sizeof(int);
+	memcpy(data_buffer->data + data_buffer->data_len, buf, len);
+	data_buffer->data_len += len;
+	data_buffer->data_source = data_source;
+	mutex_unlock(&data_buffer->data_mutex);
+
+}
+
+void extract_dci_events(unsigned char *buf, int len, int data_source)
 {
 	uint16_t event_id, event_id_packet, length, temp_len;
-	uint8_t *event_mask_ptr, byte_mask, payload_len, payload_len_field;
-	uint8_t timestamp[8] = {0}, bit_index, timestamp_len;
-	uint8_t event_data[MAX_EVENT_SIZE];
-	unsigned int byte_index, total_event_len, i;
-	struct diag_dci_client_tbl *entry;
+	uint8_t payload_len, payload_len_field;
+	uint8_t timestamp[8], timestamp_len;
+	unsigned char event_data[MAX_EVENT_SIZE];
+	unsigned int total_event_len;
+	struct list_head *start, *temp;
+	struct diag_dci_client_tbl *entry = NULL;
 
 	length =  *(uint16_t *)(buf + 1); /* total length of event series */
 	if (length == 0) {
 		pr_err("diag: Incoming dci event length is invalid\n");
 		return;
 	}
-	temp_len = 0;
-	buf = buf + 3; /* start of event series */
+	/* Move directly to the start of the event series. 1 byte for
+	 * event code and 2 bytes for the length field.
+	 */
+	temp_len = 3;
 	while (temp_len < (length - 1)) {
 		event_id_packet = *(uint16_t *)(buf + temp_len);
 		event_id = event_id_packet & 0x0FFF; /* extract 12 bits */
@@ -334,6 +771,22 @@
 			memcpy(event_data + 12, buf + temp_len + 2 +
 						timestamp_len, payload_len);
 		}
+
+		/* Before copying the data to userspace, check if we are still
+		 * within the buffer limit. This is an error case, don't count
+		 * it towards the health statistics.
+		 *
+		 * Here, the offset of 2 bytes(uint16_t) is for the
+		 * event_id_packet length
+		 */
+		temp_len += sizeof(uint16_t) + timestamp_len +
+						payload_len_field + payload_len;
+		if (temp_len > len) {
+			pr_err("diag: Invalid length in %s, len: %d, read: %d",
+						__func__, len, temp_len);
+			return;
+		}
+
 		/* 2 bytes for the event id & timestamp len is hard coded to 8,
 		   as individual events have full timestamp */
 		*(uint16_t *)(event_data) = 10 +
@@ -343,108 +796,114 @@
 		/* 2 bytes for the event length field which is added to
 		   the event data */
 		total_event_len = 2 + 10 + payload_len_field + payload_len;
-		byte_index = event_id / 8;
-		bit_index = event_id % 8;
-		byte_mask = 0x1 << bit_index;
 		/* parse through event mask tbl of each client and check mask */
-		for (i = 0; i < MAX_DCI_CLIENTS; i++) {
-			if (driver->dci_client_tbl[i].client) {
-				entry = &(driver->dci_client_tbl[i]);
-				event_mask_ptr = entry->dci_event_mask +
-								 byte_index;
-				mutex_lock(&dci_health_mutex);
-				mutex_lock(&entry->data_mutex);
-				if (*event_mask_ptr & byte_mask) {
-					/* copy to client buffer */
-					if (DCI_CHK_CAPACITY(entry,
-							 4 + total_event_len)) {
-						pr_err("diag: DCI event drop\n");
-						driver->dci_client_tbl[i].
-							dropped_events++;
-						mutex_unlock(
-							&entry->data_mutex);
-						mutex_unlock(
-							&dci_health_mutex);
-						break;
-					}
-					driver->dci_client_tbl[i].
-							received_events++;
-					*(int *)(entry->dci_data+
-					entry->data_len) = DCI_EVENT_TYPE;
-					/* 4 bytes for DCI_EVENT_TYPE */
-					memcpy(entry->dci_data +
-						entry->data_len + 4, event_data
-						, total_event_len);
-					entry->data_len += 4 + total_event_len;
-				}
-				mutex_unlock(&entry->data_mutex);
-				mutex_unlock(&dci_health_mutex);
+		list_for_each_safe(start, temp, &driver->dci_client_list) {
+			entry = list_entry(start, struct diag_dci_client_tbl,
+									track);
+			if (__diag_dci_query_event_mask(entry, event_id)) {
+				/* copy to client buffer */
+				copy_dci_event(event_data, total_event_len,
+					       entry, data_source);
 			}
 		}
-		temp_len += 2 + timestamp_len + payload_len_field + payload_len;
 	}
 }
 
-void extract_dci_log(unsigned char *buf)
+static void copy_dci_log(unsigned char *buf, int len,
+			 struct diag_dci_client_tbl *client, int data_source)
 {
-	uint16_t log_code, item_num, log_length;
-	uint8_t equip_id, *log_mask_ptr, byte_mask;
-	unsigned int i, byte_index, byte_offset = 0;
-	struct diag_dci_client_tbl *entry;
+	uint16_t log_length = 0;
+	struct diag_dci_buffer_t *data_buffer = NULL;
+	struct diag_dci_buf_peripheral_t *proc_buf = NULL;
+	int err = 0, total_len = 0;
+
+	if (!buf || !client) {
+		pr_err("diag: Invalid pointers in %s", __func__);
+		return;
+	}
 
 	log_length = *(uint16_t *)(buf + 2);
-	log_code = *(uint16_t *)(buf + 6);
-	equip_id = LOG_GET_EQUIP_ID(log_code);
-	item_num = LOG_GET_ITEM_NUM(log_code);
-	byte_index = item_num/8 + 2;
-	byte_mask = 0x01 << (item_num % 8);
-
 	if (log_length > USHRT_MAX - 4) {
-		pr_err("diag: Integer overflow in %s, log_len:%d",
+		pr_err("diag: Integer overflow in %s, log_len: %d",
 				__func__, log_length);
 		return;
 	}
-	byte_offset = (equip_id * 514) + byte_index;
-	if (byte_offset >=  DCI_LOG_MASK_SIZE) {
-		pr_err("diag: Invalid byte_offset %d in dci log\n",
-							byte_offset);
+	total_len = sizeof(int) + log_length;
+
+	/* Check if we are within the len. The check should include the
+	 * first 4 bytes for the Log code(2) and the length bytes (2)
+	 */
+	if ((log_length + sizeof(uint16_t) + 2) > len) {
+		pr_err("diag: Invalid length in %s, log_len: %d, len: %d",
+						__func__, log_length, len);
+		return;
+	}
+
+	proc_buf = &client->buffers[data_source];
+	mutex_lock(&proc_buf->buf_mutex);
+	mutex_lock(&proc_buf->health_mutex);
+	err = diag_dci_get_buffer(client, data_source, total_len);
+	if (err) {
+		if (err == -ENOMEM)
+			proc_buf->health.dropped_logs++;
+		else
+			pr_err("diag: In %s, invalid packet\n", __func__);
+		mutex_unlock(&proc_buf->health_mutex);
+		mutex_unlock(&proc_buf->buf_mutex);
+		return;
+	}
+
+	data_buffer = proc_buf->buf_curr;
+	proc_buf->health.received_logs++;
+	mutex_unlock(&proc_buf->health_mutex);
+	mutex_unlock(&proc_buf->buf_mutex);
+
+	mutex_lock(&data_buffer->data_mutex);
+	if (!data_buffer->data) {
+		mutex_unlock(&data_buffer->data_mutex);
+		return;
+	}
+
+	*(int *)(data_buffer->data + data_buffer->data_len) = DCI_LOG_TYPE;
+	data_buffer->data_len += sizeof(int);
+	memcpy(data_buffer->data + data_buffer->data_len, buf + sizeof(int),
+	       log_length);
+	data_buffer->data_len += log_length;
+	data_buffer->data_source = data_source;
+	mutex_unlock(&data_buffer->data_mutex);
+}
+
+void extract_dci_log(unsigned char *buf, int len, int data_source)
+{
+	uint16_t log_code, read_bytes = 0;
+	struct list_head *start, *temp;
+	struct diag_dci_client_tbl *entry = NULL;
+
+	if (!buf) {
+		pr_err("diag: In %s buffer is NULL\n", __func__);
+		return;
+	}
+
+	/* The first six bytes for the incoming log packet contains
+	 * Command code (2), the length of the packet (2) and the length
+	 * of the log (2)
+	 */
+	log_code = *(uint16_t *)(buf + 6);
+	read_bytes += sizeof(uint16_t) + 6;
+	if (read_bytes > len) {
+		pr_err("diag: Invalid length in %s, len: %d, read: %d",
+						__func__, len, read_bytes);
 		return;
 	}
 
 	/* parse through log mask table of each client and check mask */
-	for (i = 0; i < MAX_DCI_CLIENTS; i++) {
-		if (driver->dci_client_tbl[i].client) {
-			entry = &(driver->dci_client_tbl[i]);
-			log_mask_ptr = entry->dci_log_mask;
-			if (!log_mask_ptr)
-				return;
-			log_mask_ptr = log_mask_ptr + byte_offset;
-			mutex_lock(&dci_health_mutex);
-			mutex_lock(&entry->data_mutex);
-			if (*log_mask_ptr & byte_mask) {
-				pr_debug("\t log code %x needed by client %d",
-					 log_code, entry->client->tgid);
-				/* copy to client buffer */
-				if (DCI_CHK_CAPACITY(entry,
-						 4 + *(uint16_t *)(buf + 2))) {
-						pr_err("diag: DCI log drop\n");
-						driver->dci_client_tbl[i].
-								dropped_logs++;
-						mutex_unlock(
-							&entry->data_mutex);
-						mutex_unlock(
-							&dci_health_mutex);
-						return;
-				}
-				driver->dci_client_tbl[i].received_logs++;
-				*(int *)(entry->dci_data+entry->data_len) =
-								DCI_LOG_TYPE;
-				memcpy(entry->dci_data + entry->data_len + 4,
-					    buf + 4, log_length);
-				entry->data_len += 4 + log_length;
-			}
-			mutex_unlock(&entry->data_mutex);
-			mutex_unlock(&dci_health_mutex);
+	list_for_each_safe(start, temp, &driver->dci_client_list) {
+		entry = list_entry(start, struct diag_dci_client_tbl, track);
+		if (__diag_dci_query_log_mask(entry, log_code)) {
+			pr_debug("\t log code %x needed by client %d",
+				 log_code, entry->client->tgid);
+			/* copy to client buffer */
+			copy_dci_log(buf, len, entry, data_source);
 		}
 	}
 }
@@ -459,14 +918,10 @@
 	uint8_t *client_log_mask_ptr;
 	uint8_t *log_mask_ptr;
 	int ret;
-	int index = smd_info->peripheral;
+	struct list_head *start, *temp;
+	struct diag_dci_client_tbl *entry = NULL;
 
-	/* Update the peripheral(s) with the dci log and event masks */
-
-	/* If the cntl channel is not up, we can't update logs and events */
-	if (!driver->smd_cntl[index].ch)
-		return;
-
+	/* Update apps and peripheral(s) with the dci log and event masks */
 	memset(dirty_bits, 0, 16 * sizeof(uint8_t));
 
 	/*
@@ -474,15 +929,13 @@
 	 * which log entries in the cumulative logs that need
 	 * to be updated on the peripheral.
 	 */
-	for (i = 0; i < MAX_DCI_CLIENTS; i++) {
-		if (driver->dci_client_tbl[i].client) {
-			client_log_mask_ptr =
-				driver->dci_client_tbl[i].dci_log_mask;
-			for (j = 0; j < 16; j++) {
-				if (*(client_log_mask_ptr+1))
-					dirty_bits[j] = 1;
-				client_log_mask_ptr += 514;
-			}
+	list_for_each_safe(start, temp, &driver->dci_client_list) {
+		entry = list_entry(start, struct diag_dci_client_tbl, track);
+		client_log_mask_ptr = entry->dci_log_mask;
+		for (j = 0; j < 16; j++) {
+			if (*(client_log_mask_ptr+1))
+				dirty_bits[j] = 1;
+			client_log_mask_ptr += 514;
 		}
 	}
 
@@ -497,41 +950,48 @@
 	}
 	mutex_unlock(&dci_log_mask_mutex);
 
-	ret = diag_send_dci_log_mask(&driver->smd_cntl[index]);
+	/* Send updated mask to userspace clients */
+	diag_update_userspace_clients(DCI_LOG_MASKS_TYPE);
+	/* Send updated log mask to peripherals */
+	ret = diag_send_dci_log_mask();
 
-	ret = diag_send_dci_event_mask(&driver->smd_cntl[index]);
+	/* Send updated event mask to userspace clients */
+	diag_update_userspace_clients(DCI_EVENT_MASKS_TYPE);
+	/* Send updated event mask to peripheral */
+	ret = diag_send_dci_event_mask();
 
 	smd_info->notify_context = 0;
 }
 
 void diag_dci_notify_client(int peripheral_mask, int data)
 {
-	int i, stat;
+	int stat;
 	struct siginfo info;
+	struct list_head *start, *temp;
+	struct diag_dci_client_tbl *entry = NULL;
+
 	memset(&info, 0, sizeof(struct siginfo));
 	info.si_code = SI_QUEUE;
 	info.si_int = (peripheral_mask | data);
 
 	/* Notify the DCI process that the peripheral DCI Channel is up */
-	for (i = 0; i < MAX_DCI_CLIENTS; i++) {
-		if (!driver->dci_client_tbl[i].client)
-			continue;
-		if (driver->dci_client_tbl[i].list & peripheral_mask) {
-			info.si_signo = driver->dci_client_tbl[i].signal_type;
-			stat = send_sig_info(
-				driver->dci_client_tbl[i].signal_type,
-				&info, driver->dci_client_tbl[i].client);
+	list_for_each_safe(start, temp, &driver->dci_client_list) {
+		entry = list_entry(start, struct diag_dci_client_tbl, track);
+		if (entry->client_info.notification_list & peripheral_mask) {
+			info.si_signo = entry->client_info.signal_type;
+			stat = send_sig_info(entry->client_info.signal_type,
+					     &info, entry->client);
 			if (stat)
 				pr_err("diag: Err sending dci signal to client, signal data: 0x%x, stat: %d\n",
-				info.si_int, stat);
+							info.si_int, stat);
 		}
-	} /* end of loop for all DCI clients */
+	}
 }
 
-static int diag_send_dci_pkt(struct diag_master_table entry, unsigned char *buf,
-					 int len, int tag)
+static int diag_send_dci_pkt(struct diag_master_table entry,
+			     unsigned char *buf, int len, int tag)
 {
-	int i, status = 0;
+	int i, status = DIAG_DCI_NO_ERROR;
 	unsigned int read_len = 0;
 
 	/* The first 4 bytes is the uid tag and the next four bytes is
@@ -565,48 +1025,289 @@
 		mutex_unlock(&driver->dci_mutex);
 		return -EIO;
 	}
-
-	for (i = 0; i < NUM_SMD_DCI_CHANNELS; i++) {
-		struct diag_smd_info *smd_info = driver->separate_cmdrsp[i] ?
-					&driver->smd_dci_cmd[i] :
-					&driver->smd_dci[i];
-		if (entry.client_id == smd_info->peripheral) {
-			if (smd_info->ch) {
-				mutex_lock(&smd_info->smd_ch_mutex);
-				smd_write(smd_info->ch,
-					driver->apps_dci_buf, len + 10);
-				mutex_unlock(&smd_info->smd_ch_mutex);
-				status = DIAG_DCI_NO_ERROR;
-			}
-			break;
-		}
+	/* This command is registered locally on the Apps */
+	if (entry.client_id == APPS_DATA) {
+		driver->dci_pkt_length = len + 10;
+		diag_update_pkt_buffer(driver->apps_dci_buf, DCI_PKT_TYPE);
+		diag_update_sleeping_process(entry.process_id, DCI_PKT_TYPE);
+		mutex_unlock(&driver->dci_mutex);
+		return DIAG_DCI_NO_ERROR;
 	}
 
-	if (status != DIAG_DCI_NO_ERROR) {
-		pr_alert("diag: check DCI channel\n");
+	for (i = 0; i < NUM_SMD_DCI_CHANNELS; i++)
+		if (entry.client_id == i) {
+			status = 1;
+			break;
+		}
+
+	if (status) {
+		status = diag_dci_write_proc(entry.client_id,
+					     DIAG_DATA_TYPE,
+					     driver->apps_dci_buf,
+					     len + 10);
+	} else {
+		pr_err("diag: Cannot send packet to peripheral %d",
+		       entry.client_id);
 		status = DIAG_DCI_SEND_DATA_FAIL;
 	}
 	mutex_unlock(&driver->dci_mutex);
 	return status;
 }
 
+static int diag_dci_process_apps_pkt(struct diag_pkt_header_t *pkt_header,
+				     unsigned char *req_buf, int tag)
+{
+	uint8_t cmd_code, subsys_id, i, goto_download = 0;
+	uint8_t header_len = sizeof(struct diag_dci_pkt_header_t);
+	uint16_t ss_cmd_code;
+	uint32_t write_len = 0;
+	unsigned char *dest_buf = driver->apps_dci_buf;
+	unsigned char *payload_ptr = driver->apps_dci_buf + header_len;
+	struct diag_dci_pkt_header_t dci_header;
+
+	if (!pkt_header || !req_buf || tag < 0)
+		return -EIO;
+
+	cmd_code = pkt_header->cmd_code;
+	subsys_id = pkt_header->subsys_id;
+	ss_cmd_code = pkt_header->subsys_cmd_code;
+
+	if (cmd_code == DIAG_CMD_DOWNLOAD) {
+		*payload_ptr = DIAG_CMD_DOWNLOAD;
+		write_len = sizeof(uint8_t);
+		goto_download = 1;
+		goto fill_buffer;
+	} else if (cmd_code == DIAG_CMD_VERSION) {
+		if (chk_polling_response()) {
+			for (i = 0; i < 55; i++, write_len++, payload_ptr++)
+				*(payload_ptr) = 0;
+			goto fill_buffer;
+		}
+	} else if (cmd_code == DIAG_CMD_EXT_BUILD) {
+		if (chk_polling_response()) {
+			*payload_ptr = DIAG_CMD_EXT_BUILD;
+			write_len = sizeof(uint8_t);
+			payload_ptr += sizeof(uint8_t);
+			for (i = 0; i < 8; i++, write_len++, payload_ptr++)
+				*(payload_ptr) = 0;
+			*(int *)(payload_ptr) = chk_config_get_id();
+			write_len += sizeof(int);
+			goto fill_buffer;
+		}
+	} else if (cmd_code == DIAG_CMD_LOG_ON_DMND) {
+		if (driver->log_on_demand_support) {
+			*payload_ptr = DIAG_CMD_LOG_ON_DMND;
+			write_len = sizeof(uint8_t);
+			payload_ptr += sizeof(uint8_t);
+			*(uint16_t *)(payload_ptr) = *(uint16_t *)(req_buf + 1);
+			write_len += sizeof(uint16_t);
+			payload_ptr += sizeof(uint16_t);
+			*payload_ptr = 0x1; /* Unknown */
+			write_len += sizeof(uint8_t);
+			goto fill_buffer;
+		}
+	} else if (cmd_code != DIAG_CMD_DIAG_SUBSYS) {
+		return DIAG_DCI_TABLE_ERR;
+	}
+
+	if (subsys_id == DIAG_SS_DIAG) {
+		if (ss_cmd_code == DIAG_DIAG_MAX_PKT_SZ) {
+			memcpy(payload_ptr, pkt_header,
+					sizeof(struct diag_pkt_header_t));
+			write_len = sizeof(struct diag_pkt_header_t);
+			*(uint32_t *)(payload_ptr + write_len) = PKT_SIZE;
+			write_len += sizeof(uint32_t);
+		} else if (ss_cmd_code == DIAG_DIAG_STM) {
+			write_len = diag_process_stm_cmd(req_buf, payload_ptr);
+		}
+	} else if (subsys_id == DIAG_SS_PARAMS) {
+		if (ss_cmd_code == DIAG_DIAG_POLL) {
+			if (chk_polling_response()) {
+				memcpy(payload_ptr, pkt_header,
+					sizeof(struct diag_pkt_header_t));
+				write_len = sizeof(struct diag_pkt_header_t);
+				payload_ptr += write_len;
+				for (i = 0; i < 12; i++, write_len++) {
+					*(payload_ptr) = 0;
+					payload_ptr++;
+				}
+			}
+		} else if (ss_cmd_code == DIAG_DEL_RSP_WRAP) {
+			memcpy(payload_ptr, pkt_header,
+					sizeof(struct diag_pkt_header_t));
+			write_len = sizeof(struct diag_pkt_header_t);
+			*(int *)(payload_ptr + write_len) = wrap_enabled;
+			write_len += sizeof(int);
+		} else if (ss_cmd_code == DIAG_DEL_RSP_WRAP_CNT) {
+			wrap_enabled = true;
+			memcpy(payload_ptr, pkt_header,
+					sizeof(struct diag_pkt_header_t));
+			write_len = sizeof(struct diag_pkt_header_t);
+			*(uint16_t *)(payload_ptr + write_len) = wrap_count;
+			write_len += sizeof(uint16_t);
+		}
+	}
+
+fill_buffer:
+	if (write_len > 0) {
+		/* Check if we are within the range of the buffer*/
+		if (write_len + header_len > PKT_SIZE) {
+			pr_err("diag: In %s, invalid length %d\n", __func__,
+						write_len + header_len);
+			return -ENOMEM;
+		}
+		dci_header.start = CONTROL_CHAR;
+		dci_header.version = 1;
+		/*
+		 * Length of the rsp pkt = actual data len + pkt rsp code
+		 * (uint8_t) + tag (int)
+		 */
+		dci_header.len = write_len + sizeof(uint8_t) + sizeof(int);
+		dci_header.pkt_code = DCI_PKT_RSP_CODE;
+		dci_header.tag = tag;
+		driver->in_busy_dcipktdata = 1;
+		memcpy(dest_buf, &dci_header, header_len);
+		diag_process_apps_dci_read_data(DCI_PKT_TYPE, dest_buf + 4,
+						dci_header.len);
+		driver->in_busy_dcipktdata = 0;
+
+		if (goto_download) {
+			/*
+			 * Sleep for sometime so that the response reaches the
+			 * client. The value 5000 empirically as an optimum
+			 * time for the response to reach the client.
+			 */
+			usleep_range(5000, 5100);
+			/* call download API */
+			msm_set_restart_mode(RESTART_DLOAD);
+			pr_alert("diag: download mode set, Rebooting SoC..\n");
+			kernel_restart(NULL);
+		}
+		return DIAG_DCI_NO_ERROR;
+	}
+
+	return DIAG_DCI_TABLE_ERR;
+}
+
+static int diag_process_dci_pkt_rsp(unsigned char *buf, int len)
+{
+	int req_uid, ret = DIAG_DCI_TABLE_ERR, i;
+	struct diag_pkt_header_t *header = NULL;
+	unsigned char *temp = buf;
+	unsigned char *req_buf = NULL;
+	uint8_t retry_count = 0, max_retries = 3, found = 0;
+	uint32_t read_len = 0;
+	struct diag_master_table entry;
+	struct dci_pkt_req_entry_t *req_entry = NULL;
+
+	if (!buf)
+		return -EIO;
+
+	if (len < DCI_PKT_REQ_MIN_LEN || len > USER_SPACE_DATA) {
+		pr_err("diag: dci: Invalid length %d len in %s", len, __func__);
+		return -EIO;
+	}
+
+	req_uid = *(int *)temp; /* UID of the request */
+	temp += sizeof(int);
+	req_buf = temp; /* Start of the Request */
+	header = (struct diag_pkt_header_t *)temp;
+	temp += sizeof(struct diag_pkt_header_t);
+	read_len = sizeof(int) + sizeof(struct diag_pkt_header_t);
+	if (read_len >= USER_SPACE_DATA) {
+		pr_err("diag: dci: Invalid length in %s\n", __func__);
+		return -EIO;
+	}
+
+	/* Check if the command is allowed on DCI */
+	if (diag_dci_filter_commands(header)) {
+		pr_debug("diag: command not supported %d %d %d",
+			 header->cmd_code, header->subsys_id,
+			 header->subsys_cmd_code);
+		return DIAG_DCI_SEND_DATA_FAIL;
+	}
+
+	/*
+	 * Previous packet is yet to be consumed by the client. Wait
+	 * till the buffer is free.
+	 */
+	while (retry_count < max_retries) {
+		retry_count++;
+		if (driver->in_busy_dcipktdata)
+			usleep_range(10000, 10100);
+		else
+			break;
+	}
+	/* The buffer is still busy */
+	if (driver->in_busy_dcipktdata) {
+		pr_err("diag: In %s, apps dci buffer is still busy. Dropping packet\n",
+								__func__);
+		return -EAGAIN;
+	}
+
+	/* Register this new DCI packet */
+	req_entry = diag_register_dci_transaction(req_uid);
+	if (!req_entry) {
+		pr_alert("diag: registering new DCI transaction failed\n");
+		return DIAG_DCI_NO_REG;
+	}
+
+	/* Check if it is a dedicated Apps command */
+	ret = diag_dci_process_apps_pkt(header, req_buf, req_entry->tag);
+	if (ret == DIAG_DCI_NO_ERROR || ret < 0)
+		return ret;
+
+	/* Check the registration table for command entries */
+	for (i = 0; i < diag_max_reg && !found; i++) {
+		entry = driver->table[i];
+		if (entry.process_id == NO_PROCESS)
+			continue;
+		if (entry.cmd_code == header->cmd_code &&
+			    entry.subsys_id == header->subsys_id &&
+			    entry.cmd_code_lo <= header->subsys_cmd_code &&
+			    entry.cmd_code_hi >= header->subsys_cmd_code) {
+			ret = diag_send_dci_pkt(entry, buf, len,
+						req_entry->tag);
+			found = 1;
+		} else if (entry.cmd_code == 255 && header->cmd_code == 75) {
+			if (entry.subsys_id == header->subsys_id &&
+			    entry.cmd_code_lo <= header->subsys_cmd_code &&
+			    entry.cmd_code_hi >= header->subsys_cmd_code) {
+				ret = diag_send_dci_pkt(entry, buf, len,
+							req_entry->tag);
+				found = 1;
+			}
+		} else if (entry.cmd_code == 255 && entry.subsys_id == 255) {
+			if (entry.cmd_code_lo <= header->cmd_code &&
+			    entry.cmd_code_hi >= header->cmd_code) {
+				/*
+				 * If its a Mode reset command, make sure it is
+				 * registered on the Apps Processor
+				 */
+				if (entry.cmd_code_lo == MODE_CMD &&
+				    entry.cmd_code_hi == MODE_CMD)
+					if (entry.client_id != APPS_DATA)
+						continue;
+					ret = diag_send_dci_pkt(entry, buf, len,
+								req_entry->tag);
+					found = 1;
+			}
+		}
+	}
+
+	return ret;
+}
+
 int diag_process_dci_transaction(unsigned char *buf, int len)
 {
 	unsigned char *temp = buf;
-	uint16_t subsys_cmd_code, log_code, item_num;
-	int subsys_id, cmd_code, ret = -1, found = 0;
-	struct diag_master_table entry;
-	int count, set_mask, num_codes, bit_index, event_id, offset = 0, i;
+	uint16_t log_code, item_num;
+	int ret = -1, found = 0;
+	int count, set_mask, num_codes, bit_index, event_id, offset = 0;
 	unsigned int byte_index, read_len = 0;
 	uint8_t equip_id, *log_mask_ptr, *head_log_mask_ptr, byte_mask;
 	uint8_t *event_mask_ptr;
-	struct dci_pkt_req_entry_t *req_entry = NULL;
-
-	if (!driver->smd_dci[MODEM_DATA].ch) {
-		pr_err("diag: DCI smd channel for peripheral %d not valid for dci updates\n",
-			driver->smd_dci[MODEM_DATA].peripheral);
-		return DIAG_DCI_SEND_DATA_FAIL;
-	}
+	struct diag_dci_client_tbl *dci_entry = NULL;
 
 	if (!temp) {
 		pr_err("diag: Invalid buffer in %s\n", __func__);
@@ -615,68 +1316,7 @@
 
 	/* This is Pkt request/response transaction */
 	if (*(int *)temp > 0) {
-		if (len < DCI_PKT_REQ_MIN_LEN || len > USER_SPACE_DATA) {
-			pr_err("diag: dci: Invalid length %d len in %s", len,
-								__func__);
-			return -EIO;
-		}
-		/* enter this UID into kernel table and return index */
-		req_entry = diag_register_dci_transaction(*(int *)temp);
-		if (!req_entry) {
-			pr_alert("diag: registering new DCI transaction failed\n");
-			return DIAG_DCI_NO_REG;
-		}
-		temp += sizeof(int);
-		/*
-		 * Check for registered peripheral and fwd pkt to
-		 * appropriate proc
-		 */
-		cmd_code = (int)(*(char *)temp);
-		temp++;
-		subsys_id = (int)(*(char *)temp);
-		temp++;
-		subsys_cmd_code = *(uint16_t *)temp;
-		temp += sizeof(uint16_t);
-		read_len += sizeof(int) + 2 + sizeof(uint16_t);
-		if (read_len >= USER_SPACE_DATA) {
-			pr_err("diag: dci: Invalid length in %s\n", __func__);
-			return -EIO;
-		}
-		pr_debug("diag: %d %d %d", cmd_code, subsys_id,
-			subsys_cmd_code);
-		for (i = 0; i < diag_max_reg; i++) {
-			entry = driver->table[i];
-			if (entry.process_id != NO_PROCESS) {
-				if (entry.cmd_code == cmd_code &&
-					entry.subsys_id == subsys_id &&
-					entry.cmd_code_lo <= subsys_cmd_code &&
-					entry.cmd_code_hi >= subsys_cmd_code) {
-					ret = diag_send_dci_pkt(entry, buf,
-								len,
-								req_entry->tag);
-				} else if (entry.cmd_code == 255
-					  && cmd_code == 75) {
-					if (entry.subsys_id == subsys_id &&
-						entry.cmd_code_lo <=
-						subsys_cmd_code &&
-						entry.cmd_code_hi >=
-						subsys_cmd_code) {
-						ret = diag_send_dci_pkt(entry,
-							buf, len,
-							req_entry->tag);
-					}
-				} else if (entry.cmd_code == 255 &&
-					entry.subsys_id == 255) {
-					if (entry.cmd_code_lo <= cmd_code &&
-						entry.cmd_code_hi >=
-							cmd_code) {
-						ret = diag_send_dci_pkt(entry,
-							buf, len,
-							req_entry->tag);
-					}
-				}
-			}
-		}
+		return diag_process_dci_pkt_rsp(buf, len);
 	} else if (*(int *)temp == DCI_LOG_TYPE) {
 		/* Minimum length of a log mask config is 12 + 2 bytes for
 		   atleast one log code to be set or reset */
@@ -684,12 +1324,13 @@
 			pr_err("diag: dci: Invalid length in %s\n", __func__);
 			return -EIO;
 		}
-		/* find client id and table */
-		i = diag_dci_find_client_index(current->tgid);
-		if (i == DCI_CLIENT_INDEX_INVALID) {
-			pr_err("diag: dci client not registered/found\n");
+		/* find client table entry */
+		dci_entry = diag_dci_get_client_entry();
+		if (!dci_entry) {
+			pr_err("diag: In %s, invalid client\n", __func__);
 			return ret;
 		}
+
 		/* Extract each log code and put in client table */
 		temp += sizeof(int);
 		read_len += sizeof(int);
@@ -706,7 +1347,7 @@
 			return -EIO;
 		}
 
-		head_log_mask_ptr = driver->dci_client_tbl[i].dci_log_mask;
+		head_log_mask_ptr = dci_entry->dci_log_mask;
 		if (!head_log_mask_ptr) {
 			pr_err("diag: dci: Invalid Log mask pointer in %s\n",
 								__func__);
@@ -768,8 +1409,10 @@
 			count++;
 			ret = DIAG_DCI_NO_ERROR;
 		}
+		/* send updated mask to userspace clients */
+		diag_update_userspace_clients(DCI_LOG_MASKS_TYPE);
 		/* send updated mask to peripherals */
-		ret = diag_send_dci_log_mask(&driver->smd_cntl[MODEM_DATA]);
+		ret = diag_send_dci_log_mask();
 	} else if (*(int *)temp == DCI_EVENT_TYPE) {
 		/* Minimum length of a event mask config is 12 + 4 bytes for
 		  atleast one event id to be set or reset. */
@@ -777,10 +1420,10 @@
 			pr_err("diag: dci: Invalid length in %s\n", __func__);
 			return -EIO;
 		}
-		/* find client id and table */
-		i = diag_dci_find_client_index(current->tgid);
-		if (i == DCI_CLIENT_INDEX_INVALID) {
-			pr_err("diag: dci client not registered/found\n");
+		/* find client table entry */
+		dci_entry = diag_dci_get_client_entry();
+		if (!dci_entry) {
+			pr_err("diag: In %s, invalid client\n", __func__);
 			return ret;
 		}
 		/* Extract each log code and put in client table */
@@ -802,7 +1445,7 @@
 			return -EIO;
 		}
 
-		event_mask_ptr = driver->dci_client_tbl[i].dci_event_mask;
+		event_mask_ptr = dci_entry->dci_event_mask;
 		if (!event_mask_ptr) {
 			pr_err("diag: dci: Invalid event mask pointer in %s\n",
 								__func__);
@@ -839,58 +1482,35 @@
 			count++;
 			ret = DIAG_DCI_NO_ERROR;
 		}
+		/* send updated mask to userspace clients */
+		diag_update_userspace_clients(DCI_EVENT_MASKS_TYPE);
 		/* send updated mask to peripherals */
-		ret = diag_send_dci_event_mask(&driver->smd_cntl[MODEM_DATA]);
+		ret = diag_send_dci_event_mask();
 	} else {
 		pr_alert("diag: Incorrect DCI transaction\n");
 	}
 	return ret;
 }
 
-int diag_dci_find_client_index_health(int client_id)
+
+struct diag_dci_client_tbl *diag_dci_get_client_entry()
 {
-	int i, ret = DCI_CLIENT_INDEX_INVALID;
-
-	for (i = 0; i < MAX_DCI_CLIENTS; i++) {
-		if (driver->dci_client_tbl[i].client != NULL) {
-			if (driver->dci_client_tbl[i].client_id ==
-					client_id) {
-				ret = i;
-				break;
-			}
-		}
-	}
-	return ret;
-}
-
-int diag_dci_find_client_index(int client_id)
-{
-	int i, ret = DCI_CLIENT_INDEX_INVALID;
-
-	for (i = 0; i < MAX_DCI_CLIENTS; i++) {
-		if (driver->dci_client_tbl[i].client != NULL) {
-			if (driver->dci_client_tbl[i].client->tgid ==
-					client_id) {
-				ret = i;
-				break;
-			}
-		}
-	}
-	return ret;
+	return __diag_dci_get_client_entry(current->tgid);
 }
 
 void update_dci_cumulative_event_mask(int offset, uint8_t byte_mask)
 {
-	int i;
 	uint8_t *event_mask_ptr;
 	uint8_t *update_ptr = dci_cumulative_event_mask;
+	struct list_head *start, *temp;
+	struct diag_dci_client_tbl *entry = NULL;
 	bool is_set = false;
 
 	mutex_lock(&dci_event_mask_mutex);
 	update_ptr += offset;
-	for (i = 0; i < MAX_DCI_CLIENTS; i++) {
-		event_mask_ptr =
-			driver->dci_client_tbl[i].dci_event_mask;
+	list_for_each_safe(start, temp, &driver->dci_client_list) {
+		entry = list_entry(start, struct diag_dci_client_tbl, track);
+		event_mask_ptr = entry->dci_event_mask;
 		event_mask_ptr += offset;
 		if ((*event_mask_ptr & byte_mask) == byte_mask) {
 			is_set = true;
@@ -905,75 +1525,29 @@
 	mutex_unlock(&dci_event_mask_mutex);
 }
 
-void clear_client_dci_cumulative_event_mask(int client_index)
+void diag_dci_invalidate_cumulative_event_mask()
 {
-	int i, j;
-	uint8_t *update_ptr = dci_cumulative_event_mask;
-	uint8_t *event_mask_ptr, *client_event_mask_ptr, byte_mask = 0;
-	bool is_set = false;
-
-	event_mask_ptr =
-		(driver->dci_client_tbl[client_index].dci_event_mask);
+	int i = 0;
+	struct list_head *start, *temp;
+	struct diag_dci_client_tbl *entry = NULL;
+	uint8_t *update_ptr, *event_mask_ptr;
+	update_ptr = dci_cumulative_event_mask;
 
 	mutex_lock(&dci_event_mask_mutex);
-	for (i = 0; i < DCI_EVENT_MASK_SIZE; i++) {
-		is_set = false;
-		/* Already cleared event masks need not to be considered */
-		if (*event_mask_ptr != 0) {
-			byte_mask = *event_mask_ptr;
-		} else {
-			update_ptr++;
-			event_mask_ptr++;
-			continue;
-		}
-		for (j = 0; j < MAX_DCI_CLIENTS; j++) {
-			/* continue searching for valid client */
-			if (driver->dci_client_tbl[j].client == NULL ||
-				client_index == j)
-				continue;
-			client_event_mask_ptr =
-				(driver->dci_client_tbl[j].dci_event_mask);
-			client_event_mask_ptr += i;
-			if (*client_event_mask_ptr & byte_mask) {
-				/*
-				* Break if another client has same
-				* event mask set
-				*/
-				if ((*client_event_mask_ptr &
-					byte_mask) == byte_mask) {
-					is_set = true;
-					break;
-				} else {
-					byte_mask =
-					(~(*client_event_mask_ptr) &
-					byte_mask);
-					is_set = false;
-				}
-			}
-		}
-		/*
-		* Clear only if this client has event mask set else
-		* don't update cumulative event mask ptr
-		*/
-		if (is_set == false)
-			*update_ptr &= ~byte_mask;
-
-		update_ptr++;
-		event_mask_ptr++;
+	list_for_each_safe(start, temp, &driver->dci_client_list) {
+		entry = list_entry(start, struct diag_dci_client_tbl, track);
+		event_mask_ptr = entry->dci_event_mask;
+		for (i = 0; i < DCI_EVENT_MASK_SIZE; i++)
+			*(update_ptr+i) |= *(event_mask_ptr+i);
 	}
-	event_mask_ptr =
-		(driver->dci_client_tbl[client_index].dci_event_mask);
-	memset(event_mask_ptr, 0, DCI_EVENT_MASK_SIZE);
 	mutex_unlock(&dci_event_mask_mutex);
 }
 
-
-int diag_send_dci_event_mask(struct diag_smd_info *smd_info)
+int diag_send_dci_event_mask()
 {
 	void *buf = driver->buf_event_mask_update;
 	int header_size = sizeof(struct diag_ctrl_event_mask);
-	int wr_size = -ENOMEM, retry_count = 0, timer;
-	int ret = DIAG_DCI_NO_ERROR, i;
+	int ret = DIAG_DCI_NO_ERROR, err = DIAG_DCI_NO_ERROR, i;
 
 	mutex_lock(&driver->diag_cntl_mutex);
 	/* send event mask update */
@@ -991,28 +1565,18 @@
 	}
 	memcpy(buf, driver->event_mask, header_size);
 	memcpy(buf+header_size, dci_cumulative_event_mask, DCI_EVENT_MASK_SIZE);
-	if (smd_info && smd_info->ch) {
-		while (retry_count < 3) {
-			mutex_lock(&smd_info->smd_ch_mutex);
-			wr_size = smd_write(smd_info->ch, buf,
-					 header_size + DCI_EVENT_MASK_SIZE);
-			mutex_unlock(&smd_info->smd_ch_mutex);
-			if (wr_size == -ENOMEM) {
-				retry_count++;
-				for (timer = 0; timer < 5; timer++)
-					udelay(2000);
-			} else {
-				break;
-			}
-		}
-		if (wr_size != header_size + DCI_EVENT_MASK_SIZE) {
-			pr_err("diag: error writing dci event mask %d, tried %d\n",
-				 wr_size, header_size + DCI_EVENT_MASK_SIZE);
+	for (i = 0; i < NUM_SMD_DCI_CHANNELS; i++) {
+		/*
+		 * Don't send to peripheral if its regular channel
+		 * is down. It may also mean that the peripheral doesn't
+		 * support DCI.
+		 */
+		if (!driver->smd_dci[i].ch)
+			continue;
+		err = diag_dci_write_proc(i, DIAG_CNTL_TYPE, buf,
+					  header_size + DCI_EVENT_MASK_SIZE);
+		if (err != DIAG_DCI_NO_ERROR)
 			ret = DIAG_DCI_SEND_DATA_FAIL;
-		}
-	} else {
-		pr_err("diag: ch not valid for dci event mask update\n");
-		ret = DIAG_DCI_SEND_DATA_FAIL;
 	}
 	mutex_unlock(&driver->diag_cntl_mutex);
 
@@ -1026,6 +1590,8 @@
 	uint8_t *update_ptr = dci_cumulative_log_mask;
 	uint8_t *log_mask_ptr;
 	bool is_set = false;
+	struct list_head *start, *temp;
+	struct diag_dci_client_tbl *entry = NULL;
 
 	mutex_lock(&dci_log_mask_mutex);
 	*update_ptr = 0;
@@ -1037,9 +1603,9 @@
 	/* update the dirty bit */
 	*(update_ptr+1) = 1;
 	update_ptr = update_ptr + byte_index;
-	for (i = 0; i < MAX_DCI_CLIENTS; i++) {
-		log_mask_ptr =
-			(driver->dci_client_tbl[i].dci_log_mask);
+	list_for_each_safe(start, temp, &driver->dci_client_list) {
+		entry = list_entry(start, struct diag_dci_client_tbl, track);
+		log_mask_ptr = entry->dci_log_mask;
 		log_mask_ptr = log_mask_ptr + offset + byte_index;
 		if ((*log_mask_ptr & byte_mask) == byte_mask) {
 			is_set = true;
@@ -1055,103 +1621,35 @@
 	mutex_unlock(&dci_log_mask_mutex);
 }
 
-void clear_client_dci_cumulative_log_mask(int client_index)
+void diag_dci_invalidate_cumulative_log_mask()
 {
-	int i, j, k;
-	uint8_t *update_ptr = dci_cumulative_log_mask;
-	uint8_t *log_mask_ptr, *client_log_mask_ptr, byte_mask = 0;
-	bool is_set = false;
-
-	log_mask_ptr = driver->dci_client_tbl[client_index].dci_log_mask;
+	int i = 0;
+	struct list_head *start, *temp;
+	struct diag_dci_client_tbl *entry = NULL;
+	uint8_t *update_ptr, *log_mask_ptr;
+	update_ptr = dci_cumulative_log_mask;
 
 	mutex_lock(&dci_log_mask_mutex);
-	*update_ptr = 0;
-	/* set the equipment IDs */
-	for (i = 0; i < 16; i++)
-		*(update_ptr + (i*514)) = i;
-
-	/* update cumulative log mask ptr*/
-	update_ptr += 2;
-	log_mask_ptr += 2;
-	for (i = 0; i < 16; i++) {
-		for (j = 0; j < 512; j++) {
-			is_set = false;
-			/*
-			* Already cleared log masks need
-			* not to be considered
-			*/
-			if (*log_mask_ptr != 0) {
-				byte_mask = *log_mask_ptr;
-			} else {
-				update_ptr++;
-				log_mask_ptr++;
-				continue;
-			}
-			for (k = 0; k < MAX_DCI_CLIENTS; k++) {
-				/* continue searching for valid client */
-				if (driver->dci_client_tbl[k].client == NULL ||
-					client_index == k)
-					continue;
-				client_log_mask_ptr =
-				 (driver->dci_client_tbl[k].dci_log_mask);
-				client_log_mask_ptr += (i*514) + 2 + j;
-				if (*client_log_mask_ptr & byte_mask) {
-					/*
-					* Break if another client has same
-					* log mask set
-					*/
-					if ((*client_log_mask_ptr &
-						byte_mask) == byte_mask) {
-						is_set = true;
-						break;
-					} else {
-						byte_mask =
-						 (~(*client_log_mask_ptr) &
-						 byte_mask);
-						is_set = false;
-					}
-				}
-			}
-			/*
-			* Clear only if this client has log mask set else
-			* don't update cumulative log mask ptr
-			*/
-			if (is_set == false) {
-				/*
-				* Update the dirty bit for the equipment
-				* whose mask is changing
-				*/
-				dci_cumulative_log_mask[1+(i*514)] = 1;
-				*update_ptr &= ~byte_mask;
-			}
-
-			update_ptr++;
-			log_mask_ptr++;
-		}
-		update_ptr += 2;
-		log_mask_ptr += 2;
+	list_for_each_safe(start, temp, &driver->dci_client_list) {
+		entry = list_entry(start, struct diag_dci_client_tbl, track);
+		log_mask_ptr = entry->dci_log_mask;
+		for (i = 0; i < DCI_LOG_MASK_SIZE; i++)
+			*(update_ptr+i) |= *(log_mask_ptr+i);
 	}
-	log_mask_ptr = driver->dci_client_tbl[client_index].dci_log_mask;
-	memset(log_mask_ptr, 0, DCI_LOG_MASK_SIZE);
 	mutex_unlock(&dci_log_mask_mutex);
 }
 
-int diag_send_dci_log_mask(struct diag_smd_info *smd_info)
+int diag_send_dci_log_mask()
 {
 	void *buf = driver->buf_log_mask_update;
 	int header_size = sizeof(struct diag_ctrl_log_mask);
 	uint8_t *log_mask_ptr = dci_cumulative_log_mask;
-	int i, wr_size = -ENOMEM, retry_count = 0, timer;
-	int ret = DIAG_DCI_NO_ERROR;
-
-	if (!smd_info || !smd_info->ch) {
-		pr_err("diag: ch not valid for dci log mask update\n");
-		return DIAG_DCI_SEND_DATA_FAIL;
-	}
+	int i, j, ret = DIAG_DCI_NO_ERROR, err = DIAG_DCI_NO_ERROR;
+	int updated;
 
 	mutex_lock(&driver->diag_cntl_mutex);
 	for (i = 0; i < 16; i++) {
-		retry_count = 0;
+		updated = 1;
 		driver->log_mask->cmd_type = DIAG_CTRL_MSG_LOG_MASK;
 		driver->log_mask->num_items = 512;
 		driver->log_mask->data_len  = 11 + 512;
@@ -1162,31 +1660,26 @@
 		memcpy(buf, driver->log_mask, header_size);
 		memcpy(buf+header_size, log_mask_ptr+2, 512);
 		/* if dirty byte is set and channel is valid */
-		if (smd_info->ch && *(log_mask_ptr+1)) {
-			while (retry_count < 3) {
-				mutex_lock(&smd_info->smd_ch_mutex);
-				wr_size = smd_write(smd_info->ch, buf,
-							header_size + 512);
-				mutex_unlock(&smd_info->smd_ch_mutex);
-				if (wr_size == -ENOMEM) {
-					retry_count++;
-					for (timer = 0; timer < 5; timer++)
-						udelay(2000);
-				} else
-					break;
-			}
-			if (wr_size != header_size + 512) {
-				pr_err("diag: dci log mask update failed %d, tried %d for equip_id %d\n",
-					wr_size, header_size + 512,
-					driver->log_mask->equip_id);
-				ret = DIAG_DCI_SEND_DATA_FAIL;
+		for (j = 0; j < NUM_SMD_DCI_CHANNELS; j++) {
+			/*
+			 * Don't send to peripheral if its regular channel
+			 * is down. It may also mean that the peripheral
+			 * doesn't support DCI.
+			 */
+			if (!driver->smd_dci[j].ch)
+				continue;
 
-			} else {
-				*(log_mask_ptr+1) = 0; /* clear dirty byte */
-				pr_debug("diag: updated dci log equip ID %d\n",
-						 *log_mask_ptr);
+			if (!(*(log_mask_ptr+1)))
+				continue;
+			err = diag_dci_write_proc(j, DIAG_CNTL_TYPE, buf,
+				header_size + DCI_MAX_ITEMS_PER_LOG_CODE);
+			if (err != DIAG_DCI_NO_ERROR) {
+				updated = 0;
+				ret = DIAG_DCI_SEND_DATA_FAIL;
 			}
 		}
+		if (updated)
+			*(log_mask_ptr+1) = 0; /* clear dirty byte */
 		log_mask_ptr += 514;
 	}
 	mutex_unlock(&driver->diag_cntl_mutex);
@@ -1198,6 +1691,9 @@
 {
 	uint8_t i; int count = 0;
 
+	if (!tbl_buf)
+		return;
+
 	/* create hard coded table for log mask with 16 categories */
 	for (i = 0; i < 16; i++) {
 		*(uint8_t *)tbl_buf = i;
@@ -1220,17 +1716,15 @@
 
 	if (pdev->id == SMD_APPS_MODEM) {
 		index = MODEM_DATA;
-		err = smd_open("DIAG_2",
+		err = smd_named_open_on_edge("DIAG_2",
+			SMD_APPS_MODEM,
 			&driver->smd_dci[index].ch,
 			&driver->smd_dci[index],
 			diag_smd_notify);
 		driver->smd_dci[index].ch_save =
 			driver->smd_dci[index].ch;
-		driver->dci_device = &pdev->dev;
-		driver->dci_device->power.wakeup = wakeup_source_register
-							("DIAG_DCI_WS");
 		if (err)
-			pr_err("diag: In %s, cannot open DCI port, Id = %d, err: %d\n",
+			pr_err("diag: In %s, cannot open DCI Modem port, Id = %d, err: %d\n",
 				__func__, pdev->id, err);
 	}
 
@@ -1251,11 +1745,8 @@
 			diag_smd_notify);
 		driver->smd_dci_cmd[index].ch_save =
 			driver->smd_dci_cmd[index].ch;
-		driver->dci_cmd_device = &pdev->dev;
-		driver->dci_cmd_device->power.wakeup = wakeup_source_register
-							("DIAG_DCI_CMD_WS");
 		if (err)
-			pr_err("diag: In %s, cannot open DCI port, Id = %d, err: %d\n",
+			pr_err("diag: In %s, cannot open DCI Modem CMD port, Id = %d, err: %d\n",
 				__func__, pdev->id, err);
 	}
 
@@ -1305,8 +1796,6 @@
 	driver->dci_tag = 0;
 	driver->dci_client_id = 0;
 	driver->num_dci_client = 0;
-	driver->dci_device = NULL;
-	driver->dci_cmd_device = NULL;
 	mutex_init(&driver->dci_mutex);
 	mutex_init(&dci_log_mask_mutex);
 	mutex_init(&dci_event_mask_mutex);
@@ -1328,19 +1817,17 @@
 				goto err;
 		}
 	}
+
 	if (driver->apps_dci_buf == NULL) {
 		driver->apps_dci_buf = kzalloc(APPS_BUF_SIZE, GFP_KERNEL);
 		if (driver->apps_dci_buf == NULL)
 			goto err;
 	}
-	if (driver->dci_client_tbl == NULL) {
-		driver->dci_client_tbl = kzalloc(MAX_DCI_CLIENTS *
-			sizeof(struct diag_dci_client_tbl), GFP_KERNEL);
-		if (driver->dci_client_tbl == NULL)
-			goto err;
-	}
-	driver->diag_dci_wq = create_singlethread_workqueue("diag_dci_wq");
+	INIT_LIST_HEAD(&driver->dci_client_list);
 	INIT_LIST_HEAD(&driver->dci_req_list);
+
+	driver->diag_dci_wq = create_singlethread_workqueue("diag_dci_wq");
+	INIT_WORK(&dci_data_drain_work, dci_data_drain_work_fn);
 	success = platform_driver_register(&msm_diag_dci_driver);
 	if (success) {
 		pr_err("diag: Could not register DCI driver\n");
@@ -1353,10 +1840,10 @@
 			goto err;
 		}
 	}
+	setup_timer(&dci_drain_timer, dci_drain_data, 0);
 	return DIAG_DCI_NO_ERROR;
 err:
 	pr_err("diag: Could not initialize diag DCI buffers");
-	kfree(driver->dci_client_tbl);
 	kfree(driver->apps_dci_buf);
 	for (i = 0; i < NUM_SMD_DCI_CHANNELS; i++)
 		diag_smd_destructor(&driver->smd_dci[i]);
@@ -1383,21 +1870,12 @@
 
 	platform_driver_unregister(&msm_diag_dci_driver);
 
-	if (driver->dci_client_tbl) {
-		for (i = 0; i < MAX_DCI_CLIENTS; i++) {
-			kfree(driver->dci_client_tbl[i].dci_data);
-			mutex_destroy(&driver->dci_client_tbl[i].data_mutex);
-		}
-	}
-
 	if (driver->supports_separate_cmdrsp) {
 		for (i = 0; i < NUM_SMD_DCI_CMD_CHANNELS; i++)
 			diag_smd_destructor(&driver->smd_dci_cmd[i]);
 
 		platform_driver_unregister(&msm_diag_dci_cmd_driver);
 	}
-
-	kfree(driver->dci_client_tbl);
 	kfree(driver->apps_dci_buf);
 	mutex_destroy(&driver->dci_mutex);
 	mutex_destroy(&dci_log_mask_mutex);
@@ -1408,153 +1886,483 @@
 
 int diag_dci_clear_log_mask()
 {
-	int i, j, k, err = DIAG_DCI_NO_ERROR;
+	int j, k, err = DIAG_DCI_NO_ERROR;
 	uint8_t *log_mask_ptr, *update_ptr;
+	struct list_head *start, *temp;
+	struct diag_dci_client_tbl *entry = NULL;
 
-	i = diag_dci_find_client_index(current->tgid);
-	if (i == DCI_CLIENT_INDEX_INVALID)
+	entry = diag_dci_get_client_entry();
+	if (!entry) {
+		pr_err("diag: In %s, invalid client entry\n", __func__);
 		return DIAG_DCI_TABLE_ERR;
+	}
 
 	mutex_lock(&dci_log_mask_mutex);
-	create_dci_log_mask_tbl(
-			driver->dci_client_tbl[i].dci_log_mask);
-	memset(dci_cumulative_log_mask,
-				0x0, DCI_LOG_MASK_SIZE);
-	for (i = 0; i < MAX_DCI_CLIENTS; i++) {
+	create_dci_log_mask_tbl(entry->dci_log_mask);
+	memset(dci_cumulative_log_mask, 0x0, DCI_LOG_MASK_SIZE);
+	list_for_each_safe(start, temp, &driver->dci_client_list) {
+		entry = list_entry(start, struct diag_dci_client_tbl, track);
 		update_ptr = dci_cumulative_log_mask;
-		if (driver->dci_client_tbl[i].client) {
-			log_mask_ptr =
-				driver->dci_client_tbl[i].dci_log_mask;
-			for (j = 0; j < 16; j++) {
-				*update_ptr = j;
-				*(update_ptr + 1) = 1;
-				update_ptr += 2;
-				log_mask_ptr += 2;
-				for (k = 0; k < 513; k++) {
-					*update_ptr |= *log_mask_ptr;
-					update_ptr++;
-					log_mask_ptr++;
-				}
+		log_mask_ptr = entry->dci_log_mask;
+		for (j = 0; j < 16; j++) {
+			*update_ptr = j;
+			*(update_ptr + 1) = 1;
+			update_ptr += 2;
+			log_mask_ptr += 2;
+			for (k = 0; k < 513; k++) {
+				*update_ptr |= *log_mask_ptr;
+				update_ptr++;
+				log_mask_ptr++;
 			}
 		}
 	}
 	mutex_unlock(&dci_log_mask_mutex);
-	err = diag_send_dci_log_mask(&driver->smd_cntl[MODEM_DATA]);
+	/* send updated mask to userspace clients */
+	diag_update_userspace_clients(DCI_LOG_MASKS_TYPE);
+	/* Send updated mask to peripherals */
+	err = diag_send_dci_log_mask();
 	return err;
 }
 
 int diag_dci_clear_event_mask()
 {
-	int i, j, err = DIAG_DCI_NO_ERROR;
+	int j, err = DIAG_DCI_NO_ERROR;
 	uint8_t *event_mask_ptr, *update_ptr;
+	struct list_head *start, *temp;
+	struct diag_dci_client_tbl *entry = NULL;
 
-	i = diag_dci_find_client_index(current->tgid);
-	if (i == DCI_CLIENT_INDEX_INVALID)
+	entry = diag_dci_get_client_entry();
+	if (!entry) {
+		pr_err("diag: In %s, invalid client entry\n", __func__);
 		return DIAG_DCI_TABLE_ERR;
+	}
 
 	mutex_lock(&dci_event_mask_mutex);
-	memset(driver->dci_client_tbl[i].dci_event_mask,
-			0x0, DCI_EVENT_MASK_SIZE);
-	memset(dci_cumulative_event_mask,
-			0x0, DCI_EVENT_MASK_SIZE);
+	memset(entry->dci_event_mask, 0x0, DCI_EVENT_MASK_SIZE);
+	memset(dci_cumulative_event_mask, 0x0, DCI_EVENT_MASK_SIZE);
 	update_ptr = dci_cumulative_event_mask;
-	for (i = 0; i < MAX_DCI_CLIENTS; i++) {
-		event_mask_ptr =
-			driver->dci_client_tbl[i].dci_event_mask;
+
+	list_for_each_safe(start, temp, &driver->dci_client_list) {
+		entry = list_entry(start, struct diag_dci_client_tbl, track);
+		event_mask_ptr = entry->dci_event_mask;
 		for (j = 0; j < DCI_EVENT_MASK_SIZE; j++)
 			*(update_ptr + j) |= *(event_mask_ptr + j);
 	}
 	mutex_unlock(&dci_event_mask_mutex);
-	err = diag_send_dci_event_mask(&driver->smd_cntl[MODEM_DATA]);
+	/* send updated mask to userspace clients */
+	diag_update_userspace_clients(DCI_EVENT_MASKS_TYPE);
+	/* Send updated mask to peripherals */
+	err = diag_send_dci_event_mask();
 	return err;
 }
 
 int diag_dci_query_log_mask(uint16_t log_code)
 {
-	uint16_t item_num;
-	uint8_t equip_id, *log_mask_ptr, byte_mask;
-	int i, byte_index, offset;
-
-	equip_id = LOG_GET_EQUIP_ID(log_code);
-	item_num = LOG_GET_ITEM_NUM(log_code);
-	byte_index = item_num/8 + 2;
-	byte_mask = 0x01 << (item_num % 8);
-	offset = equip_id * 514;
-
-	i = diag_dci_find_client_index(current->tgid);
-	if (i != DCI_CLIENT_INDEX_INVALID) {
-		log_mask_ptr = driver->dci_client_tbl[i].dci_log_mask;
-		log_mask_ptr = log_mask_ptr + offset + byte_index;
-		return ((*log_mask_ptr & byte_mask) == byte_mask) ?
-								1 : 0;
-	}
-	return 0;
+	return __diag_dci_query_log_mask(diag_dci_get_client_entry(),
+					 log_code);
 }
 
-
 int diag_dci_query_event_mask(uint16_t event_id)
 {
-	uint8_t *event_mask_ptr, byte_mask;
-	int i, byte_index, bit_index;
-	byte_index = event_id/8;
-	bit_index = event_id % 8;
-	byte_mask = 0x1 << bit_index;
-
-	i = diag_dci_find_client_index(current->tgid);
-	if (i != DCI_CLIENT_INDEX_INVALID) {
-		event_mask_ptr =
-		driver->dci_client_tbl[i].dci_event_mask;
-		event_mask_ptr = event_mask_ptr + byte_index;
-		if ((*event_mask_ptr & byte_mask) == byte_mask)
-			return 1;
-		else
-			return 0;
-	}
-	return 0;
+	return __diag_dci_query_event_mask(diag_dci_get_client_entry(),
+					   event_id);
 }
 
 uint8_t diag_dci_get_cumulative_real_time()
 {
-	uint8_t real_time = MODE_NONREALTIME, i;
-	for (i = 0; i < MAX_DCI_CLIENTS; i++)
-		if (driver->dci_client_tbl[i].client &&
-				driver->dci_client_tbl[i].real_time ==
-				MODE_REALTIME) {
+	uint8_t real_time = MODE_NONREALTIME;
+	struct list_head *start, *temp;
+	struct diag_dci_client_tbl *entry = NULL;
+
+	list_for_each_safe(start, temp, &driver->dci_client_list) {
+		entry = list_entry(start, struct diag_dci_client_tbl, track);
+		if (entry->real_time == MODE_REALTIME) {
 			real_time = 1;
 			break;
 		}
+	}
 	return real_time;
 }
 
-int diag_dci_set_real_time(int client_id, uint8_t real_time)
+int diag_dci_set_real_time(uint8_t real_time)
 {
-	int i = DCI_CLIENT_INDEX_INVALID;
-	i = diag_dci_find_client_index(client_id);
-
-	if (i != DCI_CLIENT_INDEX_INVALID)
-		driver->dci_client_tbl[i].real_time = real_time;
-	return i;
-}
-
-void diag_dci_try_activate_wakeup_source(smd_channel_t *channel)
-{
-	spin_lock_irqsave(&ws_lock, ws_lock_flags);
-	if (channel == driver->smd_dci[MODEM_DATA].ch) {
-		pm_wakeup_event(driver->dci_device, DCI_WAKEUP_TIMEOUT);
-		pm_stay_awake(driver->dci_device);
-	} else if (channel == driver->smd_dci_cmd[MODEM_DATA].ch) {
-		pm_wakeup_event(driver->dci_cmd_device, DCI_WAKEUP_TIMEOUT);
-		pm_stay_awake(driver->dci_cmd_device);
+	struct diag_dci_client_tbl *entry = NULL;
+	entry = diag_dci_get_client_entry();
+	if (!entry) {
+		pr_err("diag: In %s, invalid client entry\n", __func__);
+		return 0;
 	}
+	entry->real_time = real_time;
+	return 1;
+}
+
+void diag_dci_try_activate_wakeup_source()
+{
+	spin_lock_irqsave(&ws_lock, ws_lock_flags);
+	pm_wakeup_event(driver->diag_dev, DCI_WAKEUP_TIMEOUT);
+	pm_stay_awake(driver->diag_dev);
 	spin_unlock_irqrestore(&ws_lock, ws_lock_flags);
 }
 
-void diag_dci_try_deactivate_wakeup_source(smd_channel_t *channel)
+void diag_dci_try_deactivate_wakeup_source()
 {
 	spin_lock_irqsave(&ws_lock, ws_lock_flags);
-	if (channel == driver->smd_dci[MODEM_DATA].ch)
-		pm_relax(driver->dci_device);
-	else if (channel == driver->smd_dci_cmd[MODEM_DATA].ch)
-		pm_relax(driver->dci_cmd_device);
+	pm_relax(driver->diag_dev);
 	spin_unlock_irqrestore(&ws_lock, ws_lock_flags);
 }
+
+int diag_dci_register_client(struct diag_dci_reg_tbl_t *reg_entry)
+{
+	int i, err = 0;
+	struct diag_dci_client_tbl *new_entry = NULL;
+	struct diag_dci_buf_peripheral_t *proc_buf = NULL;
+
+	if (!reg_entry)
+		return DIAG_DCI_NO_REG;
+
+	if (driver->dci_state == DIAG_DCI_NO_REG)
+		return DIAG_DCI_NO_REG;
+
+	if (driver->num_dci_client >= MAX_DCI_CLIENTS)
+		return DIAG_DCI_NO_REG;
+
+	new_entry = kzalloc(sizeof(struct diag_dci_client_tbl), GFP_KERNEL);
+	if (new_entry == NULL) {
+		pr_err("diag: unable to alloc memory\n");
+		return DIAG_DCI_NO_REG;
+	}
+
+	mutex_lock(&driver->dci_mutex);
+	if (!(driver->num_dci_client)) {
+		for (i = 0; i < NUM_SMD_DCI_CHANNELS; i++)
+			driver->smd_dci[i].in_busy_1 = 0;
+		if (driver->supports_separate_cmdrsp)
+			for (i = 0; i < NUM_SMD_DCI_CMD_CHANNELS; i++)
+				driver->smd_dci_cmd[i].in_busy_1 = 0;
+	}
+
+	new_entry->client = current;
+	new_entry->client_info.notification_list =
+				reg_entry->notification_list;
+	new_entry->client_info.signal_type =
+				reg_entry->signal_type;
+	new_entry->real_time = MODE_REALTIME;
+	new_entry->in_service = 0;
+	INIT_LIST_HEAD(&new_entry->list_write_buf);
+	mutex_init(&new_entry->write_buf_mutex);
+	new_entry->dci_log_mask =  kzalloc(DCI_LOG_MASK_SIZE, GFP_KERNEL);
+	if (!new_entry->dci_log_mask) {
+		pr_err("diag: Unable to create log mask for client, %d",
+							driver->dci_client_id);
+		goto fail_alloc;
+	}
+	create_dci_log_mask_tbl(new_entry->dci_log_mask);
+
+	new_entry->dci_event_mask =  kzalloc(DCI_EVENT_MASK_SIZE, GFP_KERNEL);
+	if (!new_entry->dci_event_mask) {
+		pr_err("diag: Unable to create event mask for client, %d",
+							driver->dci_client_id);
+		goto fail_alloc;
+	}
+	create_dci_event_mask_tbl(new_entry->dci_event_mask);
+
+	for (i = 0; i < NUM_DCI_PROC; i++) {
+		proc_buf = &new_entry->buffers[i];
+		if (!proc_buf)
+			goto fail_alloc;
+
+		mutex_init(&proc_buf->health_mutex);
+		mutex_init(&proc_buf->buf_mutex);
+		proc_buf->health.dropped_events = 0;
+		proc_buf->health.dropped_logs = 0;
+		proc_buf->health.received_events = 0;
+		proc_buf->health.received_logs = 0;
+		proc_buf->buf_primary = kzalloc(
+					sizeof(struct diag_dci_buffer_t),
+					GFP_KERNEL);
+		if (!proc_buf->buf_primary)
+			goto fail_alloc;
+		proc_buf->buf_cmd = kzalloc(sizeof(struct diag_dci_buffer_t),
+					    GFP_KERNEL);
+		if (!proc_buf->buf_cmd)
+			goto fail_alloc;
+		err = diag_dci_init_buffer(proc_buf->buf_primary,
+					   DCI_BUF_PRIMARY);
+		if (err)
+			goto fail_alloc;
+		err = diag_dci_init_buffer(proc_buf->buf_cmd, DCI_BUF_CMD);
+		if (err)
+			goto fail_alloc;
+		proc_buf->buf_curr = proc_buf->buf_primary;
+	}
+
+	list_add_tail(&new_entry->track, &driver->dci_client_list);
+	driver->dci_client_id++;
+	new_entry->client_info.client_id = driver->dci_client_id;
+	reg_entry->client_id = driver->dci_client_id;
+	driver->num_dci_client++;
+	if (driver->num_dci_client == 1)
+		diag_update_proc_vote(DIAG_PROC_DCI, VOTE_UP);
+	queue_work(driver->diag_real_time_wq, &driver->diag_real_time_work);
+	mutex_unlock(&driver->dci_mutex);
+
+	return driver->dci_client_id;
+
+fail_alloc:
+	if (new_entry) {
+		for (i = 0; i < NUM_DCI_PROC; i++) {
+			proc_buf = &new_entry->buffers[i];
+			mutex_destroy(&proc_buf->health_mutex);
+			mutex_destroy(&proc_buf->buf_primary->data_mutex);
+			mutex_destroy(&proc_buf->buf_cmd->data_mutex);
+			if (proc_buf->buf_primary)
+				kfree(proc_buf->buf_primary->data);
+			kfree(proc_buf->buf_primary);
+			if (proc_buf->buf_cmd)
+				kfree(proc_buf->buf_cmd->data);
+			kfree(proc_buf->buf_cmd);
+		}
+		kfree(new_entry->dci_event_mask);
+		kfree(new_entry->dci_log_mask);
+	}
+	kfree(new_entry);
+	mutex_unlock(&driver->dci_mutex);
+	return DIAG_DCI_NO_REG;
+}
+
+int diag_dci_deinit_client()
+{
+	int ret = DIAG_DCI_NO_ERROR, real_time = MODE_REALTIME, i, peripheral;
+	struct diag_dci_buf_peripheral_t *proc_buf = NULL;
+	struct diag_dci_client_tbl *entry = diag_dci_get_client_entry();
+	struct diag_dci_buffer_t *buf_entry, *temp;
+	struct list_head *start, *req_temp;
+	struct dci_pkt_req_entry_t *req_entry = NULL;
+	struct diag_smd_info *smd_info = NULL;
+
+	if (!entry)
+		return DIAG_DCI_NOT_SUPPORTED;
+
+	mutex_lock(&driver->dci_mutex);
+	/*
+	 * Remove the entry from the list before freeing the buffers
+	 * to ensure that we don't have any invalid access.
+	 */
+	list_del(&entry->track);
+	driver->num_dci_client--;
+	/*
+	 * Clear the client's log and event masks, update the cumulative
+	 * masks and send the masks to peripherals
+	 */
+	kfree(entry->dci_log_mask);
+	diag_update_userspace_clients(DCI_LOG_MASKS_TYPE);
+	diag_dci_invalidate_cumulative_log_mask();
+	ret = diag_send_dci_event_mask();
+	if (ret != DIAG_DCI_NO_ERROR) {
+		mutex_unlock(&driver->dci_mutex);
+		return ret;
+	}
+	kfree(entry->dci_event_mask);
+	diag_update_userspace_clients(DCI_EVENT_MASKS_TYPE);
+	diag_dci_invalidate_cumulative_event_mask();
+	ret = diag_send_dci_log_mask();
+	if (ret != DIAG_DCI_NO_ERROR) {
+		mutex_unlock(&driver->dci_mutex);
+		return ret;
+	}
+
+	list_for_each_safe(start, req_temp, &driver->dci_req_list) {
+		req_entry = list_entry(start, struct dci_pkt_req_entry_t,
+				       track);
+		if (req_entry->pid == current->tgid) {
+			list_del(&req_entry->track);
+			kfree(req_entry);
+		}
+	}
+
+	/* Clean up any buffer that is pending write */
+	mutex_lock(&entry->write_buf_mutex);
+	list_for_each_entry_safe(buf_entry, temp, &entry->list_write_buf,
+							buf_track) {
+		list_del(&buf_entry->buf_track);
+		if (buf_entry->buf_type == DCI_BUF_SECONDARY) {
+			mutex_lock(&buf_entry->data_mutex);
+			diagmem_free(driver, buf_entry->data, POOL_TYPE_DCI);
+			buf_entry->data = NULL;
+			mutex_unlock(&buf_entry->data_mutex);
+			kfree(buf_entry);
+		} else if (buf_entry->buf_type == DCI_BUF_CMD) {
+			peripheral = buf_entry->data_source;
+			if (peripheral == APPS_DATA)
+				continue;
+			mutex_lock(&buf_entry->data_mutex);
+			smd_info = driver->separate_cmdrsp[peripheral] ?
+					&driver->smd_dci_cmd[peripheral] :
+					&driver->smd_dci[peripheral];
+			smd_info->in_busy_1 = 0;
+			mutex_unlock(&buf_entry->data_mutex);
+		}
+		diag_dci_try_deactivate_wakeup_source();
+	}
+	mutex_unlock(&entry->write_buf_mutex);
+
+	for (i = 0; i < NUM_DCI_PROC; i++) {
+		proc_buf = &entry->buffers[i];
+		buf_entry = proc_buf->buf_curr;
+		mutex_lock(&proc_buf->buf_mutex);
+		/* Clean up secondary buffer from mempool that is active */
+		if (buf_entry && buf_entry->buf_type == DCI_BUF_SECONDARY) {
+			mutex_lock(&buf_entry->data_mutex);
+			diagmem_free(driver, buf_entry->data, POOL_TYPE_DCI);
+			buf_entry->data = NULL;
+			mutex_unlock(&buf_entry->data_mutex);
+			mutex_destroy(&buf_entry->data_mutex);
+			kfree(buf_entry);
+		}
+
+		mutex_lock(&proc_buf->buf_primary->data_mutex);
+		kfree(proc_buf->buf_primary->data);
+		mutex_unlock(&proc_buf->buf_primary->data_mutex);
+
+		mutex_lock(&proc_buf->buf_cmd->data_mutex);
+		kfree(proc_buf->buf_cmd->data);
+		mutex_unlock(&proc_buf->buf_cmd->data_mutex);
+
+		mutex_destroy(&proc_buf->health_mutex);
+		mutex_destroy(&proc_buf->buf_primary->data_mutex);
+		mutex_destroy(&proc_buf->buf_cmd->data_mutex);
+
+		kfree(proc_buf->buf_primary);
+		kfree(proc_buf->buf_cmd);
+		mutex_unlock(&proc_buf->buf_mutex);
+	}
+	mutex_destroy(&entry->write_buf_mutex);
+
+	kfree(entry);
+
+	if (driver->num_dci_client == 0) {
+		diag_update_proc_vote(DIAG_PROC_DCI, VOTE_DOWN);
+	} else {
+		real_time = diag_dci_get_cumulative_real_time();
+		diag_update_real_time_vote(DIAG_PROC_DCI, real_time);
+	}
+	queue_work(driver->diag_real_time_wq, &driver->diag_real_time_work);
+
+	mutex_unlock(&driver->dci_mutex);
+
+	return DIAG_DCI_NO_ERROR;
+}
+
+int diag_dci_write_proc(int peripheral, int pkt_type, char *buf, int len)
+{
+	struct diag_smd_info *smd_info = NULL;
+	int wr_size = 0, retry = 0, err = -EAGAIN, timer = 0, i;
+
+	if (!buf || (peripheral < 0 || peripheral > NUM_SMD_DCI_CHANNELS)
+								|| len < 0) {
+		pr_err("diag: In %s, invalid data 0x%p, peripheral: %d, len: %d\n",
+				__func__, buf, peripheral, len);
+		return -EINVAL;
+	}
+
+	if (pkt_type == DIAG_DATA_TYPE) {
+		for (i = 0; i < NUM_SMD_DCI_CMD_CHANNELS; i++)
+			if (peripheral == i)
+				smd_info = &driver->smd_dci_cmd[peripheral];
+		/*
+		 * This peripheral doesn't support separate channel for
+		 * command response.
+		 */
+		if (!smd_info)
+			smd_info = &driver->smd_dci[peripheral];
+	} else if (pkt_type == DIAG_CNTL_TYPE) {
+		smd_info = &driver->smd_cntl[peripheral];
+	} else {
+		pr_err("diag: Invalid DCI pkt type in %s", __func__);
+		return -EINVAL;
+	}
+
+	if (!smd_info || !smd_info->ch)
+		return -EINVAL;
+
+	while (retry < 3) {
+		mutex_lock(&smd_info->smd_ch_mutex);
+		wr_size = smd_write(smd_info->ch, buf, len);
+		if (wr_size == len) {
+			pr_debug("diag: successfully wrote pkt_type %d of len %d to %d in trial %d",
+					pkt_type, len, peripheral, (retry+1));
+			err = DIAG_DCI_NO_ERROR;
+			mutex_unlock(&smd_info->smd_ch_mutex);
+			break;
+		}
+		pr_debug("diag: cannot write pkt_type %d of len %d to %d in trial %d",
+					pkt_type, len, peripheral, (retry+1));
+		retry++;
+		mutex_unlock(&smd_info->smd_ch_mutex);
+
+		/*
+		 * Sleep for sometime before retrying. The delay of 2000 was
+		 * determined empirically as best value to use.
+		 */
+		for (timer = 0; timer < 5; timer++)
+			usleep(2000);
+	}
+	return err;
+}
+
+int diag_dci_copy_health_stats(struct diag_dci_health_stats *stats, int proc)
+{
+	struct diag_dci_client_tbl *entry = NULL;
+	struct diag_dci_health_t *health = NULL;
+	int i;
+
+	if (!stats)
+		return -EINVAL;
+
+	if (proc < ALL_PROC || proc > APPS_DATA)
+		return -EINVAL;
+
+	entry = diag_dci_get_client_entry();
+	if (!entry)
+		return DIAG_DCI_NOT_SUPPORTED;
+
+	stats->stats.dropped_logs = 0;
+	stats->stats.dropped_events = 0;
+	stats->stats.received_logs = 0;
+	stats->stats.received_events = 0;
+
+	if (proc != ALL_PROC) {
+		health = &entry->buffers[proc].health;
+		stats->stats.dropped_logs = health->dropped_logs;
+		stats->stats.dropped_events = health->dropped_events;
+		stats->stats.received_logs = health->received_logs;
+		stats->stats.received_events = health->received_events;
+		if (stats->reset_status) {
+			mutex_lock(&entry->buffers[proc].health_mutex);
+			health->dropped_logs = 0;
+			health->dropped_events = 0;
+			health->received_logs = 0;
+			health->received_events = 0;
+			mutex_unlock(&entry->buffers[proc].health_mutex);
+		}
+		return DIAG_DCI_NO_ERROR;
+	}
+
+
+	for (i = 0; i < NUM_DCI_PROC; i++) {
+		health = &entry->buffers[i].health;
+		stats->stats.dropped_logs += health->dropped_logs;
+		stats->stats.dropped_events += health->dropped_events;
+		stats->stats.received_logs += health->received_logs;
+		stats->stats.received_events += health->received_events;
+		if (stats->reset_status) {
+			mutex_lock(&entry->buffers[i].health_mutex);
+			health->dropped_logs = 0;
+			health->dropped_events = 0;
+			health->received_logs = 0;
+			health->received_events = 0;
+			mutex_unlock(&entry->buffers[i].health_mutex);
+		}
+	}
+	return DIAG_DCI_NO_ERROR;
+}
diff --git a/drivers/char/diag/diag_dci.h b/drivers/char/diag/diag_dci.h
index 870b0f3..ccd1a71 100644
--- a/drivers/char/diag/diag_dci.h
+++ b/drivers/char/diag/diag_dci.h
@@ -28,6 +28,13 @@
 #define DCI_LOG_CON_MIN_LEN		14
 #define DCI_EVENT_CON_MIN_LEN		16
 
+#define DIAG_DATA_TYPE		1
+#define DIAG_CNTL_TYPE		2
+
+#define DCI_BUF_PRIMARY		1
+#define DCI_BUF_SECONDARY	2
+#define DCI_BUF_CMD		3
+
 #ifdef CONFIG_DEBUG_FS
 #define DIAG_DCI_DEBUG_CNT	100
 #define DIAG_DCI_DEBUG_LEN	100
@@ -46,6 +53,8 @@
 
 extern unsigned int dci_max_reg;
 extern unsigned int dci_max_clients;
+extern unsigned char dci_cumulative_log_mask[DCI_LOG_MASK_SIZE];
+extern unsigned char dci_cumulative_event_mask[DCI_EVENT_MASK_SIZE];
 extern struct mutex dci_health_mutex;
 
 struct dci_pkt_req_entry_t {
@@ -55,34 +64,63 @@
 	struct list_head track;
 } __packed;
 
-struct diag_dci_client_tbl {
+struct diag_dci_reg_tbl_t {
 	uint32_t client_id;
-	struct task_struct *client;
-	uint16_t list; /* bit mask */
+	uint16_t notification_list;
 	int signal_type;
-	unsigned char dci_log_mask[DCI_LOG_MASK_SIZE];
-	unsigned char dci_event_mask[DCI_EVENT_MASK_SIZE];
-	unsigned char *dci_data;
-	int data_len;
-	int total_capacity;
-	int dropped_logs;
-	int dropped_events;
-	int received_logs;
-	int received_events;
-	struct mutex data_mutex;
-	uint8_t real_time;
 };
 
-/* This is used for DCI health stats */
-struct diag_dci_health_stats {
-	int client_id;
+struct diag_dci_health_t {
 	int dropped_logs;
 	int dropped_events;
 	int received_logs;
 	int received_events;
+};
+
+struct diag_dci_buffer_t {
+	unsigned char *data;
+	unsigned int data_len;
+	struct mutex data_mutex;
+	uint8_t in_busy;
+	uint8_t buf_type;
+	int data_source;
+	int capacity;
+	uint8_t in_list;
+	struct list_head buf_track;
+};
+
+struct diag_dci_buf_peripheral_t {
+	struct diag_dci_buffer_t *buf_curr;
+	struct diag_dci_buffer_t *buf_primary;
+	struct diag_dci_buffer_t *buf_cmd;
+	struct diag_dci_health_t health;
+	struct mutex health_mutex;
+	struct mutex buf_mutex;
+};
+
+struct diag_dci_client_tbl {
+	struct diag_dci_reg_tbl_t client_info;
+	struct task_struct *client;
+	unsigned char *dci_log_mask;
+	unsigned char *dci_event_mask;
+	uint8_t real_time;
+	struct list_head track;
+	struct diag_dci_buf_peripheral_t buffers[NUM_DCI_PROC];
+	uint8_t in_service;
+	struct list_head list_write_buf;
+	struct mutex write_buf_mutex;
+};
+
+struct diag_dci_health_stats {
+	struct diag_dci_health_t stats;
 	int reset_status;
 };
 
+struct diag_dci_health_stats_proc {
+	struct diag_dci_health_stats *health;
+	int proc;
+};
+
 /* This is used for querying DCI Log
    or Event Mask */
 struct diag_log_event_stats {
@@ -90,6 +128,14 @@
 	int is_set;
 };
 
+struct diag_dci_pkt_header_t {
+	uint8_t start;
+	uint8_t version;
+	uint16_t len;
+	uint8_t pkt_code;
+	int tag;
+} __packed;
+
 enum {
 	DIAG_DCI_NO_ERROR = 1001,	/* No error */
 	DIAG_DCI_NO_REG,		/* Could not register */
@@ -106,6 +152,7 @@
 	unsigned long iteration;
 	int data_size;
 	char time_stamp[DIAG_TS_SIZE];
+	uint8_t peripheral;
 	uint8_t ch_type;
 };
 
@@ -115,36 +162,42 @@
 
 int diag_dci_init(void);
 void diag_dci_exit(void);
+int diag_dci_register_client(struct diag_dci_reg_tbl_t *reg_entry);
+int diag_dci_deinit_client(void);
 void diag_update_smd_dci_work_fn(struct work_struct *);
 void diag_dci_notify_client(int peripheral_mask, int data);
+void diag_dci_wakeup_clients(void);
+void diag_process_apps_dci_read_data(int data_type, void *buf, int recd_bytes);
 int diag_process_smd_dci_read_data(struct diag_smd_info *smd_info, void *buf,
 								int recd_bytes);
 int diag_process_dci_transaction(unsigned char *buf, int len);
-void extract_dci_pkt_rsp(struct diag_smd_info *smd_info, unsigned char *buf);
-
-int diag_dci_find_client_index_health(int client_id);
-int diag_dci_find_client_index(int client_id);
+void extract_dci_pkt_rsp(unsigned char *buf, int len, int data_source,
+			 struct diag_smd_info *smd_info);
+struct diag_dci_client_tbl *diag_dci_get_client_entry(void);
 /* DCI Log streaming functions */
 void create_dci_log_mask_tbl(unsigned char *tbl_buf);
 void update_dci_cumulative_log_mask(int offset, unsigned int byte_index,
 						uint8_t byte_mask);
-void clear_client_dci_cumulative_log_mask(int client_index);
-int diag_send_dci_log_mask(struct diag_smd_info *smd_info);
-void extract_dci_log(unsigned char *buf);
+void diag_dci_invalidate_cumulative_log_mask(void);
+int diag_send_dci_log_mask(void);
+void extract_dci_log(unsigned char *buf, int len, int data_source);
 int diag_dci_clear_log_mask(void);
 int diag_dci_query_log_mask(uint16_t log_code);
 /* DCI event streaming functions */
 void update_dci_cumulative_event_mask(int offset, uint8_t byte_mask);
-void clear_client_dci_cumulative_event_mask(int client_index);
-int diag_send_dci_event_mask(struct diag_smd_info *smd_info);
-void extract_dci_events(unsigned char *buf);
+void diag_dci_invalidate_cumulative_event_mask(void);
+int diag_send_dci_event_mask(void);
+void extract_dci_events(unsigned char *buf, int len, int data_source);
 void create_dci_event_mask_tbl(unsigned char *tbl_buf);
 int diag_dci_clear_event_mask(void);
 int diag_dci_query_event_mask(uint16_t event_id);
-void diag_dci_smd_record_info(int read_bytes, uint8_t ch_type);
+void diag_dci_smd_record_info(int read_bytes, uint8_t ch_type,
+			      uint8_t peripheral);
 uint8_t diag_dci_get_cumulative_real_time(void);
-int diag_dci_set_real_time(int client_id, uint8_t real_time);
+int diag_dci_set_real_time(uint8_t real_time);
+int diag_dci_copy_health_stats(struct diag_dci_health_stats *stats, int proc);
 /* Functions related to DCI wakeup sources */
-void diag_dci_try_activate_wakeup_source(smd_channel_t *channel);
-void diag_dci_try_deactivate_wakeup_source(smd_channel_t *channel);
+void diag_dci_try_activate_wakeup_source(void);
+void diag_dci_try_deactivate_wakeup_source(void);
+int diag_dci_write_proc(int peripheral, int pkt_type, char *buf, int len);
 #endif
diff --git a/drivers/char/diag/diag_debugfs.c b/drivers/char/diag/diag_debugfs.c
index 3a1c96b..4dd0845 100644
--- a/drivers/char/diag/diag_debugfs.c
+++ b/drivers/char/diag/diag_debugfs.c
@@ -233,38 +233,30 @@
 		bytes_in_buf += bytes_written;
 		bytes_remaining -= bytes_written;
 #endif
-		if (driver->dci_device) {
-			bytes_written = scnprintf(buf+bytes_in_buf,
-						  bytes_remaining,
-				"dci power active, relax: %lu, %lu\n",
-				driver->dci_device->power.wakeup->active_count,
-				driver->dci_device->power.wakeup->relax_count);
-			bytes_in_buf += bytes_written;
-			bytes_remaining -= bytes_written;
-		}
-		if (driver->dci_cmd_device) {
-			bytes_written = scnprintf(buf+bytes_in_buf,
-						  bytes_remaining,
-				"dci cmd power active, relax: %lu, %lu\n",
-				driver->dci_cmd_device->power.wakeup->
-						  active_count,
-				driver->dci_cmd_device->power.wakeup->
-						  relax_count);
-			bytes_in_buf += bytes_written;
-			bytes_remaining -= bytes_written;
-		}
+		bytes_written = scnprintf(buf+bytes_in_buf,
+					  bytes_remaining,
+					  "dci power: active, relax: %lu, %lu\n",
+					  driver->diag_dev->power.wakeup->
+						active_count,
+					  driver->diag_dev->
+						power.wakeup->relax_count);
+		bytes_in_buf += bytes_written;
+		bytes_remaining -= bytes_written;
+
 	}
 	temp_data += diag_dbgfs_dci_data_index;
 	for (i = diag_dbgfs_dci_data_index; i < DIAG_DCI_DEBUG_CNT; i++) {
 		if (temp_data->iteration != 0) {
 			bytes_written = scnprintf(
 				buf + bytes_in_buf, bytes_remaining,
-				"i %-10ld\t"
-				"s %-10d\t"
-				"c %-10d\t"
+				"i %-5ld\t"
+				"s %-5d\t"
+				"p %-5d\t"
+				"c %-5d\t"
 				"t %-15s\n",
 				temp_data->iteration,
 				temp_data->data_size,
+				temp_data->peripheral,
 				temp_data->ch_type,
 				temp_data->time_stamp);
 			bytes_in_buf += bytes_written;
@@ -446,7 +438,8 @@
 		"POOL_TYPE_COPY: [0x%p : 0x%p] count = %d\n"
 		"POOL_TYPE_HDLC: [0x%p : 0x%p] count = %d\n"
 		"POOL_TYPE_USER: [0x%p : 0x%p] count = %d\n"
-		"POOL_TYPE_WRITE_STRUCT: [0x%p : 0x%p] count = %d\n",
+		"POOL_TYPE_WRITE_STRUCT: [0x%p : 0x%p] count = %d\n"
+		"POOL_TYPE_DCI: [0x%p : 0x%p] count = %d\n",
 		driver->diagpool,
 		diag_pools_array[POOL_COPY_IDX],
 		driver->count,
@@ -458,7 +451,10 @@
 		driver->count_user_pool,
 		driver->diag_write_struct_pool,
 		diag_pools_array[POOL_WRITE_STRUCT_IDX],
-		driver->count_write_struct_pool);
+		driver->count_write_struct_pool,
+		driver->diag_dci_pool,
+		diag_pools_array[POOL_DCI_IDX],
+		driver->count_dci_pool);
 
 	for (i = 0; i < MAX_HSIC_CH; i++) {
 		if (!diag_hsic[i].hsic_inited)
@@ -506,7 +502,8 @@
 		"POOL_TYPE_COPY: [0x%p : 0x%p] count = %d\n"
 		"POOL_TYPE_HDLC: [0x%p : 0x%p] count = %d\n"
 		"POOL_TYPE_USER: [0x%p : 0x%p] count = %d\n"
-		"POOL_TYPE_WRITE_STRUCT: [0x%p : 0x%p] count = %d\n",
+		"POOL_TYPE_WRITE_STRUCT: [0x%p : 0x%p] count = %d\n"
+		"POOL_TYPE_DCI: [0x%p : 0x%p] count = %d\n",
 		driver->diagpool,
 		diag_pools_array[POOL_COPY_IDX],
 		driver->count,
@@ -518,7 +515,10 @@
 		driver->count_user_pool,
 		driver->diag_write_struct_pool,
 		diag_pools_array[POOL_WRITE_STRUCT_IDX],
-		driver->count_write_struct_pool);
+		driver->count_write_struct_pool,
+		driver->diag_dci_pool,
+		diag_pools_array[POOL_DCI_IDX],
+		driver->count_dci_pool);
 
 	ret = simple_read_from_buffer(ubuf, count, ppos, buf, ret);
 
diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h
index 95d90b3..eda745f 100644
--- a/drivers/char/diag/diagchar.h
+++ b/drivers/char/diag/diagchar.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2008-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
@@ -17,13 +17,13 @@
 #include <linux/module.h>
 #include <linux/mempool.h>
 #include <linux/mutex.h>
+#include <linux/list.h>
 #include <linux/spinlock.h>
 #include <linux/workqueue.h>
 #include <linux/sched.h>
 #include <linux/wakelock.h>
 #include <mach/msm_smd.h>
 #include <asm/atomic.h>
-#include <asm/mach-types.h>
 
 /* Size of the USB buffers used for read and write*/
 #define USB_MAX_OUT_BUF 4096
@@ -44,28 +44,32 @@
 #define POOL_TYPE_HSIC_WRITE	11
 #define POOL_TYPE_HSIC_2_WRITE	12
 #define POOL_TYPE_ALL		10
+#define POOL_TYPE_DCI		20
 
 #define POOL_COPY_IDX		0
 #define POOL_HDLC_IDX		1
 #define POOL_USER_IDX		2
 #define POOL_WRITE_STRUCT_IDX	3
-#define POOL_HSIC_IDX		4
-#define POOL_HSIC_2_IDX		5
-#define POOL_HSIC_3_IDX		6
-#define POOL_HSIC_4_IDX		7
-#define POOL_HSIC_WRITE_IDX	8
-#define POOL_HSIC_2_WRITE_IDX	9
-#define POOL_HSIC_3_WRITE_IDX	10
-#define POOL_HSIC_4_WRITE_IDX	11
+#define POOL_DCI_IDX		4
+#define POOL_BRIDGE_BASE	POOL_DCI_IDX
+#define POOL_HSIC_IDX		(POOL_BRIDGE_BASE + 1)
+#define POOL_HSIC_2_IDX		(POOL_BRIDGE_BASE + 2)
+#define POOL_HSIC_3_IDX		(POOL_BRIDGE_BASE + 3)
+#define POOL_HSIC_4_IDX		(POOL_BRIDGE_BASE + 4)
+#define POOL_HSIC_WRITE_IDX	(POOL_BRIDGE_BASE + 5)
+#define POOL_HSIC_2_WRITE_IDX	(POOL_BRIDGE_BASE + 6)
+#define POOL_HSIC_3_WRITE_IDX	(POOL_BRIDGE_BASE + 7)
+#define POOL_HSIC_4_WRITE_IDX	(POOL_BRIDGE_BASE + 8)
 
 #ifdef CONFIG_DIAGFWD_BRIDGE_CODE
-#define NUM_MEMORY_POOLS	12
+#define NUM_MEMORY_POOLS	13
 #else
-#define NUM_MEMORY_POOLS	4
+#define NUM_MEMORY_POOLS	5
 #endif
 
 #define MAX_SSID_PER_RANGE	200
 
+#define ALL_PROC		-1
 #define MODEM_DATA		0
 #define LPASS_DATA		1
 #define WCNSS_DATA		2
@@ -107,10 +111,26 @@
 #define DIAG_STM_WCNSS	0x04
 #define DIAG_STM_APPS	0x08
 
-#define DIAG_DIAG_STM		0x214
-
 #define BAD_PARAM_RESPONSE_MESSAGE 20
 
+#define DIAG_CMD_VERSION	0
+#define DIAG_CMD_DOWNLOAD	0x3A
+#define DIAG_CMD_DIAG_SUBSYS	0x4B
+#define DIAG_CMD_LOG_ON_DMND	0x78
+#define DIAG_CMD_EXT_BUILD	0x7c
+
+#define DIAG_SS_DIAG		0x12
+#define DIAG_SS_PARAMS		0x32
+
+#define DIAG_DIAG_MAX_PKT_SZ	0x55
+#define DIAG_DIAG_STM		0x20E
+#define DIAG_DIAG_POLL		0x03
+#define DIAG_DEL_RSP_WRAP	0x04
+#define DIAG_DEL_RSP_WRAP_CNT	0x05
+
+#define MODE_CMD	41
+#define RESET_ID	2
+
 /*
  * The status bit masks when received in a signal handler are to be
  * used in conjunction with the peripheral list bit mask to determine the
@@ -129,6 +149,13 @@
 #define NUM_SMD_CMD_CHANNELS 1
 #define NUM_SMD_DCI_CMD_CHANNELS 1
 
+/*
+ * Indicates number of peripherals that can support DCI and Apps
+ * processor. This doesn't mean that a peripheral has the
+ * feature.
+ */
+#define NUM_DCI_PROC	(NUM_SMD_DATA_CHANNELS + 1)
+
 #define SMD_DATA_TYPE 0
 #define SMD_CNTL_TYPE 1
 #define SMD_DCI_TYPE 2
@@ -165,6 +192,12 @@
 	QSC = 5,
 };
 
+struct diag_pkt_header_t {
+	uint8_t cmd_code;
+	uint8_t subsys_id;
+	uint16_t subsys_cmd_code;
+} __packed;
+
 struct diag_master_table {
 	uint16_t cmd_code;
 	uint16_t subsys_id;
@@ -286,6 +319,7 @@
 	char *name;
 	int dropped_count;
 	struct class *diagchar_class;
+	struct device *diag_dev;
 	int ref_count;
 	struct mutex diagchar_mutex;
 	wait_queue_head_t wait_q;
@@ -307,7 +341,7 @@
 	int peripheral_supports_stm[NUM_SMD_CONTROL_CHANNELS];
 	/* DCI related variables */
 	struct list_head dci_req_list;
-	struct diag_dci_client_tbl *dci_client_tbl;
+	struct list_head dci_client_list;
 	int dci_tag;
 	int dci_client_id;
 	struct mutex dci_mutex;
@@ -324,17 +358,21 @@
 	unsigned int poolsize_user;
 	unsigned int itemsize_write_struct;
 	unsigned int poolsize_write_struct;
+	unsigned int itemsize_dci;
+	unsigned int poolsize_dci;
 	unsigned int debug_flag;
 	/* State for the mempool for the char driver */
 	mempool_t *diagpool;
 	mempool_t *diag_hdlc_pool;
 	mempool_t *diag_user_pool;
 	mempool_t *diag_write_struct_pool;
+	mempool_t *diag_dci_pool;
 	spinlock_t diag_mem_lock;
 	int count;
 	int count_hdlc_pool;
 	int count_user_pool;
 	int count_write_struct_pool;
+	int count_dci_pool;
 	int used;
 	/* Buffers for masks */
 	struct mutex diag_cntl_mutex;
@@ -365,8 +403,6 @@
 	unsigned hdlc_count;
 	unsigned hdlc_escape;
 	int in_busy_pktdata;
-	struct device *dci_device;
-	struct device *dci_cmd_device;
 	/* Variables for non real time mode */
 	int real_time_mode;
 	int real_time_update_busy;
@@ -397,6 +433,9 @@
 	struct diag_master_table *table;
 	uint8_t *pkt_buf;
 	int pkt_length;
+	uint8_t *dci_pkt_buf; /* For Apps DCI packets */
+	uint32_t dci_pkt_length;
+	int in_busy_dcipktdata;
 	struct diag_request *usb_read_ptr;
 	struct diag_request *write_ptr_svc;
 	int logging_mode;
@@ -441,5 +480,6 @@
 
 void diag_get_timestamp(char *time_str);
 int diag_find_polling_reg(int i);
+void check_drain_timer(void);
 
 #endif
diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c
index 93e932a..263715d 100644
--- a/drivers/char/diag/diagchar_core.c
+++ b/drivers/char/diag/diagchar_core.c
@@ -71,6 +71,9 @@
 /* for write structure buffer */
 static unsigned int itemsize_write_struct = 20; /*Size of item in the mempool */
 static unsigned int poolsize_write_struct = 10;/* Num of items in the mempool */
+/* For the dci memory pool */
+static unsigned int itemsize_dci = IN_BUF_SIZE; /*Size of item in the mempool */
+static unsigned int poolsize_dci = 10;  /*Number of items in the mempool */
 /* This is the max number of user-space clients supported at initialization*/
 static unsigned int max_clients = 15;
 static unsigned int threshold_client_limit = 30;
@@ -144,6 +147,16 @@
 	mutex_unlock(&driver->diagchar_mutex);
 }
 
+void check_drain_timer(void)
+{
+	int ret = 0;
+
+	if (!timer_in_progress) {
+		timer_in_progress = 1;
+		ret = mod_timer(&drain_timer, jiffies + msecs_to_jiffies(500));
+	}
+}
+
 #ifdef CONFIG_DIAGFWD_BRIDGE_CODE
 void diag_clear_hsic_tbl(void)
 {
@@ -266,9 +279,7 @@
 	* This will specially help in case of ungraceful exit of any DCI client
 	* This call will remove any pending registrations of such client
 	*/
-	if (diag_dci_find_client_index(current->tgid) !=
-		 DCI_CLIENT_INDEX_INVALID)
-		diagchar_ioctl(NULL, DIAG_IOCTL_DCI_DEINIT, 0);
+	diag_dci_deinit_client();
 	/* If the exiting process is the socket process */
 	mutex_lock(&driver->diagchar_mutex);
 	if (driver->socket_process &&
@@ -303,11 +314,12 @@
 
 	mutex_lock(&driver->diagchar_mutex);
 	driver->ref_count--;
-	/* On Client exit, try to destroy all 4 pools */
+	/* On Client exit, try to destroy all 5 pools */
 	diagmem_exit(driver, POOL_TYPE_COPY);
 	diagmem_exit(driver, POOL_TYPE_HDLC);
 	diagmem_exit(driver, POOL_TYPE_USER);
 	diagmem_exit(driver, POOL_TYPE_WRITE_STRUCT);
+	diagmem_exit(driver, POOL_TYPE_DCI);
 	for (i = 0; i < driver->num_clients; i++) {
 		if (NULL != diagpriv_data && diagpriv_data->pid ==
 						driver->client_map[i].pid) {
@@ -552,6 +564,87 @@
 			    int *pnum_data) { return 0; }
 #endif
 
+static int diag_copy_dci(char __user *buf, size_t count,
+			struct diag_dci_client_tbl *entry, int *pret)
+{
+	int total_data_len = 0;
+	int ret = 0;
+	int exit_stat = 1;
+	struct diag_dci_buffer_t *buf_entry, *temp;
+	struct diag_smd_info *smd_info = NULL;
+
+	if (!buf || !entry || !pret)
+		return exit_stat;
+
+	ret = *pret;
+
+	ret += 4;
+
+	mutex_lock(&entry->write_buf_mutex);
+	list_for_each_entry_safe(buf_entry, temp, &entry->list_write_buf,
+								buf_track) {
+		list_del(&buf_entry->buf_track);
+		mutex_lock(&buf_entry->data_mutex);
+		if ((buf_entry->data_len > 0) &&
+		    (buf_entry->in_busy) &&
+		    (buf_entry->data)) {
+			if (copy_to_user(buf+ret, (void *)buf_entry->data,
+					 buf_entry->data_len))
+				goto drop;
+			ret += buf_entry->data_len;
+			total_data_len += buf_entry->data_len;
+drop:
+			buf_entry->in_busy = 0;
+			buf_entry->data_len = 0;
+			buf_entry->in_list = 0;
+			if (buf_entry->buf_type == DCI_BUF_CMD) {
+				if (buf_entry->data_source == APPS_DATA) {
+					mutex_unlock(&buf_entry->data_mutex);
+					continue;
+				}
+				if (driver->separate_cmdrsp[
+						buf_entry->data_source]) {
+					smd_info = &driver->smd_dci_cmd[
+						buf_entry->data_source];
+				} else {
+					smd_info = &driver->smd_dci[
+						buf_entry->data_source];
+				}
+				smd_info->in_busy_1 = 0;
+				mutex_unlock(&buf_entry->data_mutex);
+				continue;
+			} else if (buf_entry->buf_type == DCI_BUF_SECONDARY) {
+				diagmem_free(driver, buf_entry->data,
+					     POOL_TYPE_DCI);
+				buf_entry->data = NULL;
+				mutex_unlock(&buf_entry->data_mutex);
+				kfree(buf_entry);
+				continue;
+			}
+
+		}
+		mutex_unlock(&buf_entry->data_mutex);
+	}
+
+	if (total_data_len > 0) {
+		/* Copy the total data length */
+		COPY_USER_SPACE_OR_EXIT(buf+4, total_data_len, 4);
+		ret -= 4;
+	} else {
+		pr_debug("diag: In %s, Trying to copy ZERO bytes, total_data_len: %d\n",
+			__func__, total_data_len);
+	}
+
+	entry->in_service = 0;
+	mutex_unlock(&entry->write_buf_mutex);
+
+	exit_stat = 0;
+exit:
+	*pret = ret;
+
+	return exit_stat;
+}
+
 int diag_command_reg(unsigned long ioarg)
 {
 	int i = 0, success = -EINVAL, j;
@@ -877,13 +970,11 @@
 	int i, result = -EINVAL, interim_size = 0, client_id = 0, real_time = 0;
 	int retry_count = 0, timer = 0;
 	uint16_t support_list = 0, interim_rsp_id, remote_dev;
-	struct diag_dci_client_tbl *dci_params;
-	struct diag_dci_health_stats stats;
+	struct diag_dci_reg_tbl_t *dci_reg_params;
+	struct diag_dci_health_stats_proc stats;
 	struct diag_log_event_stats le_stats;
 	struct diagpkt_delay_params delay_params;
 	struct real_time_vote_t rt_vote;
-	struct list_head *start, *req_temp;
-	struct dci_pkt_req_entry_t *req_entry = NULL;
 
 	switch (iocmd) {
 	case DIAG_IOCTL_COMMAND_REG:
@@ -909,127 +1000,25 @@
 		}
 		break;
 	case DIAG_IOCTL_DCI_REG:
-		if (driver->dci_state == DIAG_DCI_NO_REG)
-			return DIAG_DCI_NO_REG;
-		if (driver->num_dci_client >= MAX_DCI_CLIENTS)
-			return DIAG_DCI_NO_REG;
-		dci_params = kzalloc(sizeof(struct diag_dci_client_tbl),
+		dci_reg_params = kzalloc(sizeof(struct diag_dci_reg_tbl_t),
 								 GFP_KERNEL);
-		if (dci_params == NULL) {
+		if (dci_reg_params == NULL) {
 			pr_err("diag: unable to alloc memory\n");
 			return -ENOMEM;
 		}
-		if (copy_from_user(dci_params, (void *)ioarg,
-				 sizeof(struct diag_dci_client_tbl))) {
-			kfree(dci_params);
+		if (copy_from_user(dci_reg_params, (void *)ioarg,
+				 sizeof(struct diag_dci_reg_tbl_t))) {
+			kfree(dci_reg_params);
 			return -EFAULT;
 		}
-		mutex_lock(&driver->dci_mutex);
-		if (!(driver->num_dci_client)) {
-			for (i = 0; i < NUM_SMD_DCI_CHANNELS; i++)
-				driver->smd_dci[i].in_busy_1 = 0;
-			if (driver->supports_separate_cmdrsp)
-				for (i = 0; i < NUM_SMD_DCI_CMD_CHANNELS; i++)
-					driver->smd_dci_cmd[i].in_busy_1 = 0;
-		}
-		driver->num_dci_client++;
-		if (driver->num_dci_client == 1)
-			diag_update_proc_vote(DIAG_PROC_DCI, VOTE_UP);
-		queue_work(driver->diag_real_time_wq,
-				 &driver->diag_real_time_work);
-		pr_debug("diag: In %s, id = %d\n",
-				__func__, driver->dci_client_id);
-		driver->dci_client_id++;
-		for (i = 0; i < MAX_DCI_CLIENTS; i++) {
-			if (driver->dci_client_tbl[i].client == NULL) {
-				driver->dci_client_tbl[i].client = current;
-				driver->dci_client_tbl[i].client_id =
-							driver->dci_client_id;
-				driver->dci_client_tbl[i].list =
-							 dci_params->list;
-				driver->dci_client_tbl[i].signal_type =
-					 dci_params->signal_type;
-				create_dci_log_mask_tbl(driver->
-					dci_client_tbl[i].dci_log_mask);
-				create_dci_event_mask_tbl(driver->
-					dci_client_tbl[i].dci_event_mask);
-				driver->dci_client_tbl[i].data_len = 0;
-				driver->dci_client_tbl[i].dci_data =
-					 kzalloc(IN_BUF_SIZE, GFP_KERNEL);
-				driver->dci_client_tbl[i].total_capacity =
-								 IN_BUF_SIZE;
-				driver->dci_client_tbl[i].dropped_logs = 0;
-				driver->dci_client_tbl[i].dropped_events = 0;
-				driver->dci_client_tbl[i].received_logs = 0;
-				driver->dci_client_tbl[i].received_events = 0;
-				driver->dci_client_tbl[i].real_time = 1;
-				mutex_init(&driver->dci_client_tbl[i].
-								data_mutex);
-				break;
-			}
-		}
-		kfree(dci_params);
-		mutex_unlock(&driver->dci_mutex);
-		result = driver->dci_client_id;
+		result = diag_dci_register_client(dci_reg_params);
+		kfree(dci_reg_params);
 		break;
 	case DIAG_IOCTL_DCI_DEINIT:
-		result = -EIO;
-		/* Delete this process from DCI table */
-		mutex_lock(&driver->dci_mutex);
-		i = diag_dci_find_client_index(current->tgid);
-		if (i == DCI_CLIENT_INDEX_INVALID) {
-			result = DIAG_DCI_NOT_SUPPORTED;
-		} else {
-			/* clear respective cumulative log masks */
-			clear_client_dci_cumulative_log_mask(i);
-			/* send updated log mask to peripherals */
-			result =
-			diag_send_dci_log_mask(&driver->smd_cntl[MODEM_DATA]);
-			if (result != DIAG_DCI_NO_ERROR) {
-				mutex_unlock(&driver->dci_mutex);
-				return result;
-			}
-			/* clear respective cumulative event masks */
-			clear_client_dci_cumulative_event_mask(i);
-			/* send updated event mask to peripherals */
-			result =
-			diag_send_dci_event_mask(
-				&driver->smd_cntl[MODEM_DATA]);
-			if (result != DIAG_DCI_NO_ERROR) {
-				mutex_unlock(&driver->dci_mutex);
-				return result;
-			}
-			result = i;
-			/* Delete this process from DCI table */
-			list_for_each_safe(start, req_temp,
-							&driver->dci_req_list) {
-				req_entry = list_entry(start,
-						struct dci_pkt_req_entry_t,
-						track);
-				if (req_entry->pid == current->tgid) {
-					list_del(&req_entry->track);
-					kfree(req_entry);
-				}
-			}
-			driver->dci_client_tbl[result].client = NULL;
-			kfree(driver->dci_client_tbl[result].dci_data);
-			driver->dci_client_tbl[result].dci_data = NULL;
-			mutex_destroy(&driver->dci_client_tbl[result].
-								data_mutex);
-			driver->num_dci_client--;
-			if (driver->num_dci_client == 0) {
-				diag_update_proc_vote(DIAG_PROC_DCI, VOTE_DOWN);
-			} else {
-				real_time = diag_dci_get_cumulative_real_time();
-				diag_update_real_time_vote(DIAG_PROC_DCI,
-								real_time);
-			}
-			queue_work(driver->diag_real_time_wq,
-				   &driver->diag_real_time_work);
-		}
-		mutex_unlock(&driver->dci_mutex);
+		result = diag_dci_deinit_client();
 		break;
 	case DIAG_IOCTL_DCI_SUPPORT:
+		support_list |= DIAG_CON_APSS;
 		for (i = 0; i < NUM_SMD_DCI_CHANNELS; i++) {
 			if (driver->smd_dci[i].ch)
 				support_list |=
@@ -1042,29 +1031,16 @@
 		break;
 	case DIAG_IOCTL_DCI_HEALTH_STATS:
 		if (copy_from_user(&stats, (void *)ioarg,
-				 sizeof(struct diag_dci_health_stats)))
+				 sizeof(struct diag_dci_health_stats_proc)))
 			return -EFAULT;
-		mutex_lock(&dci_health_mutex);
-		i = diag_dci_find_client_index_health(stats.client_id);
-		if (i != DCI_CLIENT_INDEX_INVALID) {
-			dci_params = &(driver->dci_client_tbl[i]);
-			stats.dropped_logs = dci_params->dropped_logs;
-			stats.dropped_events =
-					dci_params->dropped_events;
-			stats.received_logs =
-					dci_params->received_logs;
-			stats.received_events =
-					dci_params->received_events;
-			if (stats.reset_status) {
-				dci_params->dropped_logs = 0;
-				dci_params->dropped_events = 0;
-				dci_params->received_logs = 0;
-				dci_params->received_events = 0;
-			}
-		}
-		mutex_unlock(&dci_health_mutex);
+
+		result = diag_dci_copy_health_stats(stats.health,
+						    stats.proc);
+		if (result != DIAG_DCI_NO_ERROR)
+			break;
+
 		if (copy_to_user((void *)ioarg, &stats,
-				   sizeof(struct diag_dci_health_stats)))
+				   sizeof(struct diag_dci_health_stats_proc)))
 			return -EFAULT;
 		result = DIAG_DCI_NO_ERROR;
 		break;
@@ -1126,8 +1102,7 @@
 			return -EFAULT;
 		driver->real_time_update_busy++;
 		if (rt_vote.proc == DIAG_PROC_DCI) {
-			diag_dci_set_real_time(current->tgid,
-						rt_vote.real_time_vote);
+			diag_dci_set_real_time(rt_vote.real_time_vote);
 			real_time = diag_dci_get_cumulative_real_time();
 		} else {
 			real_time = rt_vote.real_time_vote;
@@ -1181,7 +1156,10 @@
 		pr_err("diag: Client PID not found in table");
 		return -EINVAL;
 	}
-
+	if (!buf) {
+		pr_err("diag: bad address from user side\n");
+		return -EFAULT;
+	}
 	wait_event_interruptible(driver->wait_q, driver->data_ready[index]);
 
 	mutex_lock(&driver->diagchar_mutex);
@@ -1389,32 +1367,55 @@
 		goto exit;
 	}
 
+	if (driver->data_ready[index] & DCI_PKT_TYPE) {
+		/* Copy the type of data being passed */
+		data_type = driver->data_ready[index] & DCI_PKT_TYPE;
+		COPY_USER_SPACE_OR_EXIT(buf, data_type, 4);
+		COPY_USER_SPACE_OR_EXIT(buf+4, *(driver->dci_pkt_buf),
+					driver->dci_pkt_length);
+		driver->data_ready[index] ^= DCI_PKT_TYPE;
+		driver->in_busy_dcipktdata = 0;
+		goto exit;
+	}
+
+	if (driver->data_ready[index] & DCI_EVENT_MASKS_TYPE) {
+		/*Copy the type of data being passed*/
+		data_type = driver->data_ready[index] & DCI_EVENT_MASKS_TYPE;
+		COPY_USER_SPACE_OR_EXIT(buf, data_type, 4);
+		COPY_USER_SPACE_OR_EXIT(buf+4, driver->num_dci_client, 4);
+		COPY_USER_SPACE_OR_EXIT(buf+8, *(dci_cumulative_event_mask),
+							DCI_EVENT_MASK_SIZE);
+		driver->data_ready[index] ^= DCI_EVENT_MASKS_TYPE;
+		goto exit;
+	}
+
+	if (driver->data_ready[index] & DCI_LOG_MASKS_TYPE) {
+		/*Copy the type of data being passed*/
+		data_type = driver->data_ready[index] & DCI_LOG_MASKS_TYPE;
+		COPY_USER_SPACE_OR_EXIT(buf, data_type, 4);
+		COPY_USER_SPACE_OR_EXIT(buf+4, driver->num_dci_client, 4);
+		COPY_USER_SPACE_OR_EXIT(buf+8, *(dci_cumulative_log_mask),
+							DCI_LOG_MASK_SIZE);
+		driver->data_ready[index] ^= DCI_LOG_MASKS_TYPE;
+		goto exit;
+	}
+
 	if (driver->data_ready[index] & DCI_DATA_TYPE) {
 		/* Copy the type of data being passed */
 		data_type = driver->data_ready[index] & DCI_DATA_TYPE;
-		COPY_USER_SPACE_OR_EXIT(buf, data_type, 4);
-		/* check the current client and copy its data */
-		for (i = 0; i < MAX_DCI_CLIENTS; i++) {
-			entry = &(driver->dci_client_tbl[i]);
-			if (entry && entry->client) {
-				if (current->tgid == entry->client->tgid) {
-					mutex_lock(&entry->data_mutex);
-					COPY_USER_SPACE_OR_EXIT(buf+4,
-							entry->data_len, 4);
-					COPY_USER_SPACE_OR_EXIT(buf+8,
-					*(entry->dci_data), entry->data_len);
-					entry->data_len = 0;
-					mutex_unlock(&entry->data_mutex);
-					break;
-				}
-			}
-		}
 		driver->data_ready[index] ^= DCI_DATA_TYPE;
+		/* check the current client and copy its data */
+		entry = diag_dci_get_client_entry();
+		if (entry) {
+			if (!entry->in_service)
+				goto exit;
+			COPY_USER_SPACE_OR_EXIT(buf, data_type, 4);
+			exit_stat = diag_copy_dci(buf, count, entry, &ret);
+			if (exit_stat == 1)
+				goto exit;
+		}
 		for (i = 0; i < NUM_SMD_DCI_CHANNELS; i++) {
-			driver->smd_dci[i].in_busy_1 = 0;
 			if (driver->smd_dci[i].ch) {
-				diag_dci_try_deactivate_wakeup_source(
-						driver->smd_dci[i].ch);
 				queue_work(driver->diag_dci_wq,
 				&(driver->smd_dci[i].diag_read_smd_work));
 			}
@@ -1423,10 +1424,7 @@
 			for (i = 0; i < NUM_SMD_DCI_CMD_CHANNELS; i++) {
 				if (!driver->separate_cmdrsp[i])
 					continue;
-				driver->smd_dci_cmd[i].in_busy_1 = 0;
 				if (driver->smd_dci_cmd[i].ch) {
-					diag_dci_try_deactivate_wakeup_source(
-						driver->smd_dci_cmd[i].ch);
 					queue_work(driver->diag_dci_wq,
 						&(driver->smd_dci_cmd[i].
 							diag_read_smd_work));
@@ -1449,7 +1447,7 @@
 				size_t count, loff_t *ppos)
 {
 	int err, ret = 0, pkt_type, token_offset = 0;
-	int remote_proc = 0;
+	int remote_proc = 0, data_type;
 	uint8_t index;
 #ifdef DIAG_DEBUG
 	int length = 0, i;
@@ -1480,9 +1478,11 @@
 		return -EBADMSG;
 	}
 #ifdef CONFIG_DIAG_OVER_USB
-	if (((pkt_type != DCI_DATA_TYPE) && (driver->logging_mode == USB_MODE)
-				&& (!driver->usb_connected)) ||
-				(driver->logging_mode == NO_LOGGING_MODE)) {
+	if (driver->logging_mode == NO_LOGGING_MODE ||
+	    (!((pkt_type == DCI_DATA_TYPE) ||
+	       ((pkt_type & (DATA_TYPE_DCI_LOG | DATA_TYPE_DCI_EVENT)) == 0))
+		&& (driver->logging_mode == USB_MODE) &&
+		(!driver->usb_connected))) {
 		/*Drop the diag payload */
 		return -EIO;
 	}
@@ -1541,9 +1541,9 @@
 		}
 		/* The packet is for the remote processor */
 		if (payload_size <= MIN_SIZ_ALLOW) {
-				pr_err("diag: Integer underflow in %s, payload size: %d",
-							__func__, payload_size);
-		return -EBADMSG;
+			pr_err("diag: Integer underflow in %s, payload size: %d",
+					__func__, payload_size);
+			return -EBADMSG;
 		}
 		token_offset = 4;
 		payload_size -= 4;
@@ -1761,20 +1761,47 @@
 		return -EBADMSG;
 	}
 
-	mutex_lock(&driver->diagchar_mutex);
 	buf_copy = diagmem_alloc(driver, payload_size, POOL_TYPE_COPY);
 	if (!buf_copy) {
 		driver->dropped_count++;
-		mutex_unlock(&driver->diagchar_mutex);
 		return -ENOMEM;
 	}
 
 	err = copy_from_user(buf_copy, buf + 4, payload_size);
 	if (err) {
 		printk(KERN_INFO "diagchar : copy_from_user failed\n");
-		ret = -EFAULT;
-		goto fail_free_copy;
+		diagmem_free(driver, buf_copy, POOL_TYPE_COPY);
+		buf_copy = NULL;
+		return -EFAULT;
 	}
+
+	data_type = pkt_type &
+		    (DATA_TYPE_DCI_LOG | DATA_TYPE_DCI_EVENT | DCI_PKT_TYPE);
+	if (data_type) {
+		diag_process_apps_dci_read_data(data_type, buf_copy,
+						payload_size);
+		if (pkt_type & DATA_TYPE_DCI_LOG)
+			pkt_type ^= DATA_TYPE_DCI_LOG;
+		else if (pkt_type & DATA_TYPE_DCI_EVENT) {
+			pkt_type ^= DATA_TYPE_DCI_EVENT;
+		} else {
+			pkt_type ^= DCI_PKT_TYPE;
+			diagmem_free(driver, buf_copy, POOL_TYPE_COPY);
+			return 0;
+		}
+
+		/*
+		 * If the data is not headed for normal processing or the usb
+		 * is unplugged and we are in usb mode
+		 */
+		if ((pkt_type != DATA_TYPE_LOG && pkt_type != DATA_TYPE_EVENT)
+			|| ((driver->logging_mode == USB_MODE) &&
+			(!driver->usb_connected))) {
+			diagmem_free(driver, buf_copy, POOL_TYPE_COPY);
+			return 0;
+		}
+	}
+
 	if (driver->stm_state[APPS_DATA] &&
 		(pkt_type >= DATA_TYPE_EVENT && pkt_type <= DATA_TYPE_LOG)) {
 		int stm_size = 0;
@@ -1809,6 +1836,7 @@
 			length++;
 	}
 #endif
+	mutex_lock(&driver->diagchar_mutex);
 	if (!buf_hdlc)
 		buf_hdlc = diagmem_alloc(driver, HDLC_OUT_BUF_SIZE,
 						 POOL_TYPE_HDLC);
@@ -1882,10 +1910,9 @@
 	diagmem_free(driver, buf_copy, POOL_TYPE_COPY);
 	buf_copy = NULL;
 	mutex_unlock(&driver->diagchar_mutex);
-	if (!timer_in_progress)	{
-		timer_in_progress = 1;
-		ret = mod_timer(&drain_timer, jiffies + msecs_to_jiffies(500));
-	}
+
+	check_drain_timer();
+
 	return 0;
 
 fail_free_hdlc:
@@ -2017,9 +2044,13 @@
 		return -1;
 	}
 
-	device_create(driver->diagchar_class, NULL, devno,
-				  (void *)driver, "diag");
+	driver->diag_dev = device_create(driver->diagchar_class, NULL, devno,
+					 (void *)driver, "diag");
 
+	if (!driver->diag_dev)
+		return -EIO;
+
+	driver->diag_dev->power.wakeup = wakeup_source_register("DIAG_WS");
 	return 0;
 
 }
@@ -2110,12 +2141,15 @@
 		driver->poolsize_user = poolsize_user;
 		driver->itemsize_write_struct = itemsize_write_struct;
 		driver->poolsize_write_struct = poolsize_write_struct;
+		driver->itemsize_dci = itemsize_dci;
+		driver->poolsize_dci = poolsize_dci;
 		driver->num_clients = max_clients;
 		driver->logging_mode = USB_MODE;
 		driver->socket_process = NULL;
 		driver->callback_process = NULL;
 		driver->mask_check = 0;
 		driver->in_busy_pktdata = 0;
+		driver->in_busy_dcipktdata = 0;
 		mutex_init(&driver->diagchar_mutex);
 		init_waitqueue_head(&driver->wait_q);
 		init_waitqueue_head(&driver->smd_wait_q);
diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c
index f7e720f..eb8a75b 100644
--- a/drivers/char/diag/diagfwd.c
+++ b/drivers/char/diag/diagfwd.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2008-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
@@ -43,9 +43,6 @@
 #include "diag_masks.h"
 #include "diagfwd_bridge.h"
 
-#define MODE_CMD		41
-#define RESET_ID		2
-
 #define STM_CMD_VERSION_OFFSET	4
 #define STM_CMD_MASK_OFFSET	5
 #define STM_CMD_DATA_OFFSET	6
@@ -695,15 +692,14 @@
 
 	if (!buf && (smd_info->type == SMD_DCI_TYPE ||
 					smd_info->type == SMD_DCI_CMD_TYPE))
-		diag_dci_try_deactivate_wakeup_source(smd_info->ch);
+		diag_dci_try_deactivate_wakeup_source();
 
 	if (smd_info->ch && buf) {
-		pkt_len = smd_cur_packet_size(smd_info->ch);
 
+		pkt_len = smd_cur_packet_size(smd_info->ch);
 		if (pkt_len == 0 && (smd_info->type == SMD_DCI_TYPE ||
 					smd_info->type == SMD_DCI_CMD_TYPE))
-			diag_dci_try_deactivate_wakeup_source(smd_info->ch);
-
+			diag_dci_try_deactivate_wakeup_source();
 		if (pkt_len > buf_size)
 			resize_success = diag_smd_resize_buf(smd_info, &buf,
 							&buf_size, pkt_len);
@@ -811,7 +807,7 @@
 fail_return:
 	if (smd_info->type == SMD_DCI_TYPE ||
 					smd_info->type == SMD_DCI_CMD_TYPE)
-		diag_dci_try_deactivate_wakeup_source(smd_info->ch);
+		diag_dci_try_deactivate_wakeup_source();
 	return;
 }
 
@@ -1049,17 +1045,46 @@
     return err;
 }
 
-static void diag_update_pkt_buffer(unsigned char *buf)
+void diag_update_pkt_buffer(unsigned char *buf, int type)
 {
-	unsigned char *ptr = driver->pkt_buf;
+	unsigned char *ptr = NULL;
 	unsigned char *temp = buf;
+	unsigned int length;
+	int *in_busy = NULL;
 
+	if (!buf) {
+		pr_err("diag: Invalid buffer in %s\n", __func__);
+		return;
+	}
+
+	switch (type) {
+	case PKT_TYPE:
+		ptr = driver->pkt_buf;
+		length = driver->pkt_length;
+		in_busy = &driver->in_busy_pktdata;
+		break;
+	case DCI_PKT_TYPE:
+		ptr = driver->dci_pkt_buf;
+		length = driver->dci_pkt_length;
+		in_busy = &driver->in_busy_dcipktdata;
+		break;
+	default:
+		pr_err("diag: Invalid type %d in %s\n", type, __func__);
+		return;
+	}
+
+	if (!ptr || length == 0) {
+		pr_err("diag: Invalid ptr %p and length %d in %s",
+						ptr, length, __func__);
+		return;
+	}
 	mutex_lock(&driver->diagchar_mutex);
-	if (CHK_OVERFLOW(ptr, ptr, ptr + PKT_SIZE, driver->pkt_length)) {
-		memcpy(ptr, temp , driver->pkt_length);
-		driver->in_busy_pktdata = 1;
-	} else
+	if (CHK_OVERFLOW(ptr, ptr, ptr + PKT_SIZE, length)) {
+		memcpy(ptr, temp , length);
+		*in_busy = 1;
+	} else {
 		printk(KERN_CRIT " Not enough buffer space for PKT_RESP\n");
+	}
 	mutex_unlock(&driver->diagchar_mutex);
 }
 
@@ -1108,7 +1133,7 @@
 	if (entry.process_id != NON_APPS_PROC) {
 		/* If the message is to be sent to the apps process */
 		if (type != MODEM_DATA) {
-			diag_update_pkt_buffer(buf);
+			diag_update_pkt_buffer(buf, PKT_TYPE);
 			diag_update_sleeping_process(entry.process_id,
 							PKT_TYPE);
 		}
@@ -2191,7 +2216,7 @@
 	if (smd_info->type == SMD_DCI_TYPE ||
 					smd_info->type == SMD_DCI_CMD_TYPE) {
 		if (event == SMD_EVENT_DATA)
-			diag_dci_try_activate_wakeup_source(smd_info->ch);
+			diag_dci_try_activate_wakeup_source();
 		queue_work(driver->diag_dci_wq,
 				&(smd_info->diag_read_smd_work));
 	} else if (smd_info->type == SMD_DATA_TYPE) {
@@ -2659,6 +2684,12 @@
 			 GFP_KERNEL)) == NULL)
 		goto err;
 	kmemleak_not_leak(driver->pkt_buf);
+	if (driver->dci_pkt_buf == NULL) {
+		driver->dci_pkt_buf = kzalloc(PKT_SIZE, GFP_KERNEL);
+		if (!driver->dci_pkt_buf)
+			goto err;
+	}
+	kmemleak_not_leak(driver->dci_pkt_buf);
 	if (driver->apps_rsp_buf == NULL) {
 		driver->apps_rsp_buf = kzalloc(APPS_BUF_SIZE, GFP_KERNEL);
 		if (driver->apps_rsp_buf == NULL)
@@ -2709,6 +2740,7 @@
 	kfree(driver->data_ready);
 	kfree(driver->table);
 	kfree(driver->pkt_buf);
+	kfree(driver->dci_pkt_buf);
 	kfree(driver->usb_read_ptr);
 	kfree(driver->apps_rsp_buf);
 	kfree(driver->user_space_data_buf);
@@ -2749,6 +2781,7 @@
 	kfree(driver->data_ready);
 	kfree(driver->table);
 	kfree(driver->pkt_buf);
+	kfree(driver->dci_pkt_buf);
 	kfree(driver->usb_read_ptr);
 	kfree(driver->apps_rsp_buf);
 	kfree(driver->user_space_data_buf);
diff --git a/drivers/char/diag/diagfwd.h b/drivers/char/diag/diagfwd.h
index 1a4601a..7b2ded3 100644
--- a/drivers/char/diag/diagfwd.h
+++ b/drivers/char/diag/diagfwd.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2008-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
@@ -54,6 +54,8 @@
 int diag_process_apps_pkt(unsigned char *buf, int len);
 void diag_reset_smd_data(int queue);
 int diag_apps_responds(void);
+void diag_update_pkt_buffer(unsigned char *buf, int type);
+int diag_process_stm_cmd(unsigned char *buf, unsigned char *dest_buf);
 /* State for diag forwarding */
 #ifdef CONFIG_DIAG_OVER_USB
 int diagfwd_connect(void);
diff --git a/drivers/char/diag/diagmem.c b/drivers/char/diag/diagmem.c
index 4ceca4f..db01e9b 100644
--- a/drivers/char/diag/diagmem.c
+++ b/drivers/char/diag/diagmem.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2008-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
@@ -70,6 +70,16 @@
 				driver->diag_write_struct_pool, GFP_ATOMIC);
 			}
 		}
+	} else if (pool_type == POOL_TYPE_DCI) {
+		if (driver->diag_dci_pool) {
+			if ((driver->count_dci_pool < driver->poolsize_dci) &&
+				(size <= driver->itemsize_dci)) {
+				atomic_add(1,
+					(atomic_t *)&driver->count_dci_pool);
+				buf = mempool_alloc(driver->diag_dci_pool,
+								GFP_ATOMIC);
+			}
+		}
 #ifdef CONFIG_DIAGFWD_BRIDGE_CODE
 	} else if (pool_type == POOL_TYPE_HSIC ||
 				pool_type == POOL_TYPE_HSIC_2) {
@@ -155,6 +165,16 @@
 			pr_err("diag: Unable to destroy STRUCT mempool");
 		}
 	}
+
+	if (driver->diag_dci_pool) {
+		if (driver->count_dci_pool == 0 && driver->ref_count == 0) {
+			mempool_destroy(driver->diag_dci_pool);
+			driver->diag_dci_pool = NULL;
+		} else if (driver->ref_count == 0 && pool_type ==
+							POOL_TYPE_ALL) {
+				pr_err("diag: Unable to destroy DCI mempool");
+		}
+	}
 #ifdef CONFIG_DIAGFWD_BRIDGE_CODE
 	for (index = 0; index < MAX_HSIC_CH; index++) {
 		if (diag_hsic[index].diag_hsic_pool &&
@@ -231,6 +251,15 @@
 		} else
 			pr_err("diag: Attempt to free up DIAG driver USB structure mempool which is already free %d ",
 					driver->count_write_struct_pool);
+	} else if (pool_type == POOL_TYPE_DCI) {
+		if (driver->diag_dci_pool != NULL &&
+			driver->count_dci_pool > 0) {
+				mempool_free(buf, driver->diag_dci_pool);
+				atomic_add(-1,
+					(atomic_t *)&driver->count_dci_pool);
+		} else
+			pr_err("diag: Attempt to free up DIAG driver DCI mempool which is already free %d ",
+					driver->count_dci_pool);
 #ifdef CONFIG_DIAGFWD_BRIDGE_CODE
 	} else if (pool_type == POOL_TYPE_HSIC ||
 				pool_type == POOL_TYPE_HSIC_2) {
@@ -294,6 +323,12 @@
 						driver->diag_write_struct_pool;
 	}
 
+	if (driver->count_dci_pool == 0) {
+		driver->diag_dci_pool = mempool_create_kmalloc_pool(
+			driver->poolsize_dci, driver->itemsize_dci);
+		diag_pools_array[POOL_DCI_IDX] = driver->diag_dci_pool;
+	}
+
 	if (!driver->diagpool)
 		pr_err("diag: Cannot allocate diag mempool\n");
 
@@ -305,6 +340,10 @@
 
 	if (!driver->diag_write_struct_pool)
 		pr_err("diag: Cannot allocate diag USB struct mempool\n");
+
+	if (!driver->diag_dci_pool)
+		pr_err("diag: Cannot allocate diag DCI mempool\n");
+
 }
 
 #ifdef CONFIG_DIAGFWD_BRIDGE_CODE
diff --git a/drivers/crypto/msm/qce50.c b/drivers/crypto/msm/qce50.c
index ad7dd31..b93a82f 100644
--- a/drivers/crypto/msm/qce50.c
+++ b/drivers/crypto/msm/qce50.c
@@ -4820,9 +4820,9 @@
 	if (_qce_sps_add_sg_data(pce_dev, areq->src, areq->nbytes,
 						 &pce_dev->ce_sps.in_transfer))
 		goto bad;
-	_qce_set_flag(&pce_dev->ce_sps.in_transfer,
-				SPS_IOVEC_FLAG_EOT|SPS_IOVEC_FLAG_NWD);
-
+	if (areq->nbytes)
+		_qce_set_flag(&pce_dev->ce_sps.in_transfer,
+					SPS_IOVEC_FLAG_EOT|SPS_IOVEC_FLAG_NWD);
 	if (_qce_sps_add_data(GET_PHYS_ADDR(pce_dev->ce_sps.result_dump),
 					CRYPTO_RESULT_DUMP_SIZE,
 					  &pce_dev->ce_sps.out_transfer))
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index 12fa799..d163317 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2002,2007-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2002,2007-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
@@ -461,6 +461,7 @@
 	struct kgsl_perfcounter_read_group __user *reads, unsigned int count)
 {
 	struct adreno_perfcounters *counters = adreno_dev->gpudev->perfcounters;
+	struct kgsl_device *device = &adreno_dev->dev;
 	struct adreno_perfcount_group *group;
 	struct kgsl_perfcounter_read_group *list = NULL;
 	unsigned int i, j;
@@ -488,6 +489,13 @@
 		goto done;
 	}
 
+	kgsl_mutex_lock(&device->mutex, &device->mutex_owner);
+	ret = kgsl_active_count_get(device);
+	if (ret) {
+		kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
+		goto done;
+	}
+
 	/* list iterator */
 	for (j = 0; j < count; j++) {
 
@@ -496,7 +504,7 @@
 		/* Verify that the group ID is within range */
 		if (list[j].groupid >= counters->group_count) {
 			ret = -EINVAL;
-			goto done;
+			break;
 		}
 
 		group = &(counters->groups[list[j].groupid]);
@@ -512,11 +520,13 @@
 		}
 	}
 
+	kgsl_active_count_put(device);
+	kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
+
 	/* write the data */
-	if (copy_to_user(reads, list,
-			sizeof(struct kgsl_perfcounter_read_group) *
-			count) != 0)
-		ret = -EFAULT;
+	if (ret == 0)
+		ret = copy_to_user(reads, list,
+			sizeof(struct kgsl_perfcounter_read_group) * count);
 
 done:
 	kfree(list);
@@ -592,8 +602,11 @@
 	unsigned int *max_counters)
 {
 	struct adreno_perfcounters *counters = adreno_dev->gpudev->perfcounters;
+	struct kgsl_device *device = &adreno_dev->dev;
 	struct adreno_perfcount_group *group;
-	unsigned int i;
+	unsigned int i, t;
+	int ret;
+	unsigned int *buf;
 
 	*max_counters = 0;
 
@@ -603,6 +616,8 @@
 	if (groupid >= counters->group_count)
 		return -EINVAL;
 
+	kgsl_mutex_lock(&device->mutex, &device->mutex_owner);
+
 	group = &(counters->groups[groupid]);
 	*max_counters = group->reg_count;
 
@@ -610,20 +625,28 @@
 	 * if NULL countable or *count of zero, return max reg_count in
 	 * *max_counters and return success
 	 */
-	if (countables == NULL || count == 0)
+	if (countables == NULL || count == 0) {
+		kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
 		return 0;
-
-	/*
-	 * Go through all available counters.  Write upto *count * countable
-	 * values.
-	 */
-	for (i = 0; i < group->reg_count && i < count; i++) {
-		if (copy_to_user(&countables[i], &(group->regs[i].countable),
-				sizeof(unsigned int)) != 0)
-			return -EFAULT;
 	}
 
-	return 0;
+	t = min_t(int, group->reg_count, count);
+
+	buf = kmalloc(t * sizeof(unsigned int), GFP_KERNEL);
+	if (buf == NULL) {
+		kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
+		return -ENOMEM;
+	}
+
+	for (i = 0; i < t; i++)
+		buf[i] = group->regs[i].countable;
+
+	kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
+
+	ret = copy_to_user(countables, buf, sizeof(unsigned int) * t);
+	kfree(buf);
+
+	return ret;
 }
 
 static inline void refcount_group(struct adreno_perfcount_group *group,
@@ -2832,6 +2855,8 @@
 				break;
 			}
 
+			kgsl_mutex_lock(&device->mutex, &device->mutex_owner);
+
 			if (enable) {
 				device->pwrctrl.ctrl_flags = 0;
 				adreno_dev->fast_hang_detect = 1;
@@ -2851,6 +2876,7 @@
 				kgsl_pwrscale_disable(device);
 			}
 
+			kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
 			status = 0;
 		}
 		break;
@@ -2869,10 +2895,13 @@
 
 			context = kgsl_context_get_owner(dev_priv,
 							constraint.context_id);
+
 			if (context == NULL)
 				break;
+
 			status = adreno_set_constraint(device, context,
 								&constraint);
+
 			kgsl_context_put(context);
 		}
 		break;
@@ -3354,24 +3383,28 @@
 	}
 	case IOCTL_KGSL_PERFCOUNTER_GET: {
 		struct kgsl_perfcounter_get *get = data;
+		kgsl_mutex_lock(&device->mutex, &device->mutex_owner);
 		/*
 		 * adreno_perfcounter_get() is called by kernel clients
 		 * during start(), so it is not safe to take an
 		 * active count inside this function.
 		 */
 		result = kgsl_active_count_get(device);
-		if (result)
-			break;
-		result = adreno_perfcounter_get(adreno_dev, get->groupid,
-			get->countable, &get->offset, &get->offset_hi,
-			PERFCOUNTER_FLAG_NONE);
-		kgsl_active_count_put(device);
+		if (result == 0) {
+			result = adreno_perfcounter_get(adreno_dev,
+				get->groupid, get->countable, &get->offset,
+				&get->offset_hi, PERFCOUNTER_FLAG_NONE);
+			kgsl_active_count_put(device);
+		}
+		kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
 		break;
 	}
 	case IOCTL_KGSL_PERFCOUNTER_PUT: {
 		struct kgsl_perfcounter_put *put = data;
+		kgsl_mutex_lock(&device->mutex, &device->mutex_owner);
 		result = adreno_perfcounter_put(adreno_dev, put->groupid,
 			put->countable, PERFCOUNTER_FLAG_NONE);
+		kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
 		break;
 	}
 	case IOCTL_KGSL_PERFCOUNTER_QUERY: {
@@ -3383,12 +3416,8 @@
 	}
 	case IOCTL_KGSL_PERFCOUNTER_READ: {
 		struct kgsl_perfcounter_read *read = data;
-		result = kgsl_active_count_get(device);
-		if (result)
-			break;
 		result = adreno_perfcounter_read_group(adreno_dev,
 			read->reads, read->count);
-		kgsl_active_count_put(device);
 		break;
 	}
 	default:
diff --git a/drivers/gpu/msm/adreno_dispatch.c b/drivers/gpu/msm/adreno_dispatch.c
index 588c243..5f80fcf 100644
--- a/drivers/gpu/msm/adreno_dispatch.c
+++ b/drivers/gpu/msm/adreno_dispatch.c
@@ -155,6 +155,7 @@
 		struct adreno_context *drawctxt)
 {
 	struct kgsl_cmdbatch *cmdbatch = NULL;
+	int pending;
 
 	mutex_lock(&drawctxt->mutex);
 	if (drawctxt->cmdqueue_head != drawctxt->cmdqueue_tail) {
@@ -164,7 +165,32 @@
 		 * Don't dequeue a cmdbatch that is still waiting for other
 		 * events
 		 */
-		if (kgsl_cmdbatch_sync_pending(cmdbatch)) {
+
+		spin_lock(&cmdbatch->lock);
+		pending = list_empty(&cmdbatch->synclist) ? 0 : 1;
+
+		/*
+		 * If changes are pending and the canary timer hasn't been
+		 * started yet, start it
+		 */
+		if (pending) {
+			/*
+			 * If syncpoints are pending start the canary timer if
+			 * it hasn't already been started
+			 */
+			if (!timer_pending(&cmdbatch->timer))
+				mod_timer(&cmdbatch->timer, jiffies + (5 * HZ));
+			spin_unlock(&cmdbatch->lock);
+		} else {
+			/*
+			 * Otherwise, delete the timer to make sure it is good
+			 * and dead before queuing the buffer
+			 */
+			spin_unlock(&cmdbatch->lock);
+			del_timer_sync(&cmdbatch->timer);
+		}
+
+		if (pending) {
 			cmdbatch = ERR_PTR(-EAGAIN);
 			goto done;
 		}
diff --git a/drivers/gpu/msm/adreno_profile.c b/drivers/gpu/msm/adreno_profile.c
index 45075a5..7785f3b 100644
--- a/drivers/gpu/msm/adreno_profile.c
+++ b/drivers/gpu/msm/adreno_profile.c
@@ -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
@@ -680,6 +680,15 @@
 	if (adreno_is_a2xx(adreno_dev))
 		return -ENOSPC;
 
+	buf = kmalloc(len + 1, GFP_KERNEL);
+	if (buf == NULL)
+		return -ENOMEM;
+
+	if (copy_from_user(buf, user_buf, len)) {
+		size = -EFAULT;
+		goto error_free;
+	}
+
 	kgsl_mutex_lock(&device->mutex, &device->mutex_owner);
 
 	if (adreno_profile_enabled(profile)) {
@@ -688,8 +697,10 @@
 	}
 
 	ret = kgsl_active_count_get(device);
-	if (ret)
-		return -EINVAL;
+	if (ret) {
+		size = ret;
+		goto error_unlock;
+	}
 
 	/*
 	 * When adding/removing assignments, ensure that the GPU is done with
@@ -697,19 +708,13 @@
 	 * GPU and avoid racey conditions.
 	 */
 	if (adreno_idle(device)) {
-		size = -EINVAL;
+		size = -ETIMEDOUT;
 		goto error_put;
 	}
 
 	/* clear all shared buffer results */
 	adreno_profile_process_results(device);
 
-	buf = kmalloc(len + 1, GFP_KERNEL);
-	if (!buf) {
-		size = -EINVAL;
-		goto error_put;
-	}
-
 	pbuf = buf;
 
 	/* clear the log buffer */
@@ -718,10 +723,6 @@
 		profile->log_tail = profile->log_buffer;
 	}
 
-	if (copy_from_user(buf, user_buf, len)) {
-		size = -EFAULT;
-		goto error_free;
-	}
 
 	/* for sanity and parsing, ensure it is null terminated */
 	buf[len] = '\0';
@@ -741,12 +742,12 @@
 
 	size = len;
 
-error_free:
-	kfree(buf);
 error_put:
 	kgsl_active_count_put(device);
 error_unlock:
 	kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
+error_free:
+	kfree(buf);
 	return size;
 }
 
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index 5d78879..5a33d9d 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2008-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
@@ -105,52 +105,108 @@
 }
 EXPORT_SYMBOL(kgsl_trace_regwrite);
 
-int kgsl_memfree_hist_init(void)
-{
-	void *base;
+/*
+ * The memfree list contains the last N blocks of memory that have been freed.
+ * On a GPU fault we walk the list to see if the faulting address had been
+ * recently freed and print out a message to that effect
+ */
 
-	base = kzalloc(KGSL_MEMFREE_HIST_SIZE, GFP_KERNEL);
-	kgsl_driver.memfree_hist.base_hist_rb = base;
-	if (base == NULL)
-		return -ENOMEM;
-	kgsl_driver.memfree_hist.size = KGSL_MEMFREE_HIST_SIZE;
-	kgsl_driver.memfree_hist.wptr = base;
+#define MEMFREE_ENTRIES 512
+
+static DEFINE_SPINLOCK(memfree_lock);
+
+struct memfree_entry {
+	unsigned long gpuaddr;
+	unsigned long size;
+	pid_t pid;
+	unsigned int flags;
+};
+
+static struct {
+	struct memfree_entry *list;
+	int head;
+	int tail;
+} memfree;
+
+static int kgsl_memfree_init(void)
+{
+	memfree.list = kzalloc(MEMFREE_ENTRIES * sizeof(struct memfree_entry),
+		GFP_KERNEL);
+
+	return (memfree.list) ? 0 : -ENOMEM;
+}
+
+static void kgsl_memfree_exit(void)
+{
+	kfree(memfree.list);
+	memset(&memfree, 0, sizeof(memfree));
+}
+
+int kgsl_memfree_find_entry(pid_t pid, unsigned long *gpuaddr,
+	unsigned long *size, unsigned int *flags)
+{
+	int ptr;
+
+	if (memfree.list == NULL)
+		return 0;
+
+	spin_lock(&memfree_lock);
+
+	ptr = memfree.head - 1;
+	if (ptr < 0)
+		ptr = MEMFREE_ENTRIES - 1;
+
+	/* Walk backwards through the list looking for the last match  */
+	while (ptr != memfree.tail) {
+		struct memfree_entry *entry = &memfree.list[ptr];
+
+		if ((entry->pid == pid) &&
+			(*gpuaddr >= entry->gpuaddr &&
+			 *gpuaddr < (entry->gpuaddr + entry->size))) {
+			*gpuaddr = entry->gpuaddr;
+			*flags = entry->flags;
+			*size = entry->size;
+
+			spin_unlock(&memfree_lock);
+			return 1;
+		}
+
+		ptr = ptr - 1;
+
+		if (ptr < 0)
+			ptr = MEMFREE_ENTRIES - 1;
+	}
+
+	spin_unlock(&memfree_lock);
 	return 0;
 }
 
-void kgsl_memfree_hist_exit(void)
+static void kgsl_memfree_add(pid_t pid, unsigned int gpuaddr,
+		unsigned int size, int flags)
+
 {
-	kfree(kgsl_driver.memfree_hist.base_hist_rb);
-	kgsl_driver.memfree_hist.base_hist_rb = NULL;
-}
+	struct memfree_entry *entry;
 
-void kgsl_memfree_hist_set_event(unsigned int pid, unsigned int gpuaddr,
-			unsigned int size, int flags)
-{
-	struct kgsl_memfree_hist_elem *p;
-
-	void *base = kgsl_driver.memfree_hist.base_hist_rb;
-	int rbsize = kgsl_driver.memfree_hist.size;
-
-	if (base == NULL)
+	if (memfree.list == NULL)
 		return;
 
-	mutex_lock(&kgsl_driver.memfree_hist_mutex);
-	p = kgsl_driver.memfree_hist.wptr;
-	p->pid = pid;
-	p->gpuaddr = gpuaddr;
-	p->size = size;
-	p->flags = flags;
+	spin_lock(&memfree_lock);
 
-	kgsl_driver.memfree_hist.wptr++;
-	if ((void *)kgsl_driver.memfree_hist.wptr >= base+rbsize) {
-		kgsl_driver.memfree_hist.wptr =
-			(struct kgsl_memfree_hist_elem *)base;
-	}
-	mutex_unlock(&kgsl_driver.memfree_hist_mutex);
+	entry = &memfree.list[memfree.head];
+
+	entry->pid = pid;
+	entry->gpuaddr = gpuaddr;
+	entry->size = size;
+	entry->flags = flags;
+
+	memfree.head = (memfree.head + 1) % MEMFREE_ENTRIES;
+
+	if (memfree.head == memfree.tail)
+		memfree.tail = (memfree.tail + 1) % MEMFREE_ENTRIES;
+
+	spin_unlock(&memfree_lock);
 }
 
-
 /* kgsl_get_mem_entry - get the mem_entry structure for the specified object
  * @device - Pointer to the device structure
  * @ptbase - the pagetable base of the object
@@ -557,6 +613,13 @@
 
 	write_lock(&device->context_lock);
 	if (context->id != KGSL_CONTEXT_INVALID) {
+
+		/* Clear the timestamps in the memstore during destroy */
+		kgsl_sharedmem_writel(device, &device->memstore,
+			KGSL_MEMSTORE_OFFSET(context->id, soptimestamp), 0);
+		kgsl_sharedmem_writel(device, &device->memstore,
+			KGSL_MEMSTORE_OFFSET(context->id, eoptimestamp), 0);
+
 		idr_remove(&device->context_idr, context->id);
 		context->id = KGSL_CONTEXT_INVALID;
 	}
@@ -1415,7 +1478,6 @@
 				      kgsl_readtimestamp(device, context,
 							KGSL_TIMESTAMP_RETIRED),
 				      result);
-
 	return result;
 }
 
@@ -1424,9 +1486,14 @@
 						void *data)
 {
 	struct kgsl_device_waittimestamp *param = data;
+	struct kgsl_device *device = dev_priv->device;
+	long result = -EINVAL;
 
-	return _device_waittimestamp(dev_priv, NULL,
+	kgsl_mutex_lock(&device->mutex, &device->mutex_owner);
+	result = _device_waittimestamp(dev_priv, NULL,
 			param->timestamp, param->timeout);
+	kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
+	return result;
 }
 
 static long kgsl_ioctl_device_waittimestamp_ctxtid(struct kgsl_device_private
@@ -1435,8 +1502,10 @@
 {
 	struct kgsl_device_waittimestamp_ctxtid *param = data;
 	struct kgsl_context *context;
+	struct kgsl_device *device = dev_priv->device;
 	long result = -EINVAL;
 
+	kgsl_mutex_lock(&device->mutex, &device->mutex_owner);
 	context = kgsl_context_get_owner(dev_priv, param->context_id);
 
 	if (context)
@@ -1444,6 +1513,7 @@
 			param->timestamp, param->timeout);
 
 	kgsl_context_put(context);
+	kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
 	return result;
 }
 
@@ -1484,6 +1554,49 @@
 	struct kref refcount;
 };
 
+static void _kgsl_cmdbatch_timer(unsigned long data)
+{
+	struct kgsl_cmdbatch *cmdbatch = (struct kgsl_cmdbatch *) data;
+	struct kgsl_cmdbatch_sync_event *event;
+
+	if (cmdbatch == NULL || cmdbatch->context == NULL)
+		return;
+
+	spin_lock(&cmdbatch->lock);
+	if (list_empty(&cmdbatch->synclist))
+		goto done;
+
+	pr_err("kgsl: possible gpu syncpoint deadlock for context %d timestamp %d\n",
+		cmdbatch->context->id, cmdbatch->timestamp);
+	pr_err(" Active sync points:\n");
+
+	/* Print all the pending sync objects */
+	list_for_each_entry(event, &cmdbatch->synclist, node) {
+
+		switch (event->type) {
+		case KGSL_CMD_SYNCPOINT_TYPE_TIMESTAMP: {
+			unsigned int retired;
+
+			 retired = kgsl_readtimestamp(event->device,
+				event->context, KGSL_TIMESTAMP_RETIRED);
+
+			pr_err("  [timestamp] context %d timestamp %d (retired %d)\n",
+				event->context->id, event->timestamp,
+				retired);
+			break;
+		}
+		case KGSL_CMD_SYNCPOINT_TYPE_FENCE:
+			pr_err("  fence: [%p] %s\n", event->handle,
+				(event->handle && event->handle->fence)
+					? event->handle->fence->name : "NULL");
+			break;
+		}
+	}
+
+done:
+	spin_unlock(&cmdbatch->lock);
+}
+
 /**
  * kgsl_cmdbatch_sync_event_destroy() - Destroy a sync event object
  * @kref: Pointer to the kref structure for this object
@@ -1558,6 +1671,10 @@
 	sched = list_empty(&event->cmdbatch->synclist) ? 1 : 0;
 	spin_unlock(&event->cmdbatch->lock);
 
+	/* If the list is empty delete the canary timer */
+	if (sched)
+		del_timer_sync(&event->cmdbatch->timer);
+
 	/*
 	 * if this is the last event in the list then tell
 	 * the GPU device that the cmdbatch can be submitted
@@ -1600,10 +1717,12 @@
 	struct kgsl_cmdbatch_sync_event *event, *tmp;
 	LIST_HEAD(cancel_synclist);
 
-	/*
-	 * Empty the synclist before canceling events
-	 */
+	/* Zap the canary timer */
+	del_timer_sync(&cmdbatch->timer);
+
 	spin_lock(&cmdbatch->lock);
+
+	/* Empty the synclist before canceling events */
 	list_splice_init(&cmdbatch->synclist, &cancel_synclist);
 	spin_unlock(&cmdbatch->lock);
 
@@ -1782,6 +1901,7 @@
 	event->cmdbatch = cmdbatch;
 	event->context = context;
 	event->timestamp = sync->timestamp;
+	event->device = device;
 
 	/*
 	 * Two krefs are required to support events. The first kref is for
@@ -1917,6 +2037,10 @@
 	cmdbatch->context = context;
 	cmdbatch->flags = flags & ~KGSL_CONTEXT_SUBMIT_IB_LIST;
 
+	/* Add a timer to help debug sync deadlocks */
+	setup_timer(&cmdbatch->timer, _kgsl_cmdbatch_timer,
+		(unsigned long) cmdbatch);
+
 	return cmdbatch;
 }
 
@@ -2179,9 +2303,14 @@
 						void *data)
 {
 	struct kgsl_cmdstream_readtimestamp *param = data;
+	struct kgsl_device *device = dev_priv->device;
+	long result = -EINVAL;
 
-	return _cmdstream_readtimestamp(dev_priv, NULL,
+	kgsl_mutex_lock(&device->mutex, &device->mutex_owner);
+	result = _cmdstream_readtimestamp(dev_priv, NULL,
 			param->type, &param->timestamp);
+	kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
+	return result;
 }
 
 static long kgsl_ioctl_cmdstream_readtimestamp_ctxtid(struct kgsl_device_private
@@ -2189,9 +2318,11 @@
 						void *data)
 {
 	struct kgsl_cmdstream_readtimestamp_ctxtid *param = data;
+	struct kgsl_device *device = dev_priv->device;
 	struct kgsl_context *context;
 	long result = -EINVAL;
 
+	kgsl_mutex_lock(&device->mutex, &device->mutex_owner);
 	context = kgsl_context_get_owner(dev_priv, param->context_id);
 
 	if (context)
@@ -2199,6 +2330,7 @@
 			param->type, &param->timestamp);
 
 	kgsl_context_put(context);
+	kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
 	return result;
 }
 
@@ -2250,9 +2382,14 @@
 						    void *data)
 {
 	struct kgsl_cmdstream_freememontimestamp *param = data;
+	struct kgsl_device *device = dev_priv->device;
+	long result = -EINVAL;
 
-	return _cmdstream_freememontimestamp(dev_priv, param->gpuaddr,
+	kgsl_mutex_lock(&device->mutex, &device->mutex_owner);
+	result = _cmdstream_freememontimestamp(dev_priv, param->gpuaddr,
 			NULL, param->timestamp, param->type);
+	kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
+	return result;
 }
 
 static long kgsl_ioctl_cmdstream_freememontimestamp_ctxtid(
@@ -2262,13 +2399,16 @@
 {
 	struct kgsl_cmdstream_freememontimestamp_ctxtid *param = data;
 	struct kgsl_context *context;
+	struct kgsl_device *device = dev_priv->device;
 	long result = -EINVAL;
 
+	kgsl_mutex_lock(&device->mutex, &device->mutex_owner);
 	context = kgsl_context_get_owner(dev_priv, param->context_id);
 	if (context)
 		result = _cmdstream_freememontimestamp(dev_priv, param->gpuaddr,
 			context, param->timestamp, param->type);
 	kgsl_context_put(context);
+	kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
 	return result;
 }
 
@@ -2280,6 +2420,7 @@
 	struct kgsl_context *context = NULL;
 	struct kgsl_device *device = dev_priv->device;
 
+	kgsl_mutex_lock(&device->mutex, &device->mutex_owner);
 	context = device->ftbl->drawctxt_create(dev_priv, &param->flags);
 	if (IS_ERR(context)) {
 		result = PTR_ERR(context);
@@ -2288,6 +2429,7 @@
 	trace_kgsl_context_create(dev_priv->device, context, param->flags);
 	param->drawctxt_id = context->id;
 done:
+	kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
 	return result;
 }
 
@@ -2295,18 +2437,44 @@
 					unsigned int cmd, void *data)
 {
 	struct kgsl_drawctxt_destroy *param = data;
+	struct kgsl_device *device = dev_priv->device;
 	struct kgsl_context *context;
 	long result;
 
+	kgsl_mutex_lock(&device->mutex, &device->mutex_owner);
 	context = kgsl_context_get_owner(dev_priv, param->drawctxt_id);
 
 	result = kgsl_context_detach(context);
 
 	kgsl_context_put(context);
+	kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
 	return result;
 }
 
-static long kgsl_ioctl_sharedmem_free(struct kgsl_device_private *dev_priv,
+static long _sharedmem_free_entry(struct kgsl_mem_entry *entry)
+{
+	if (!kgsl_mem_entry_set_pend(entry)) {
+		kgsl_mem_entry_put(entry);
+		return -EBUSY;
+	}
+
+	trace_kgsl_mem_free(entry);
+
+	kgsl_memfree_add(entry->priv->pid, entry->memdesc.gpuaddr,
+		entry->memdesc.size, entry->memdesc.flags);
+
+	/*
+	 * First kgsl_mem_entry_put is for the reference that we took in
+	 * this function when calling kgsl_sharedmem_find, second one is
+	 * to free the memory since this is a free ioctl
+	 */
+	kgsl_mem_entry_put(entry);
+	kgsl_mem_entry_put(entry);
+
+	return 0;
+}
+
+long kgsl_ioctl_sharedmem_free(struct kgsl_device_private *dev_priv,
 					unsigned int cmd, void *data)
 {
 	struct kgsl_sharedmem_free *param = data;
@@ -2319,29 +2487,11 @@
 				param->gpuaddr);
 		return -EINVAL;
 	}
-	if (!kgsl_mem_entry_set_pend(entry)) {
-		kgsl_mem_entry_put(entry);
-		return -EBUSY;
-	}
 
-	trace_kgsl_mem_free(entry);
-
-	kgsl_memfree_hist_set_event(entry->priv->pid,
-				    entry->memdesc.gpuaddr,
-				    entry->memdesc.size,
-				    entry->memdesc.flags);
-
-	/*
-	 * First kgsl_mem_entry_put is for the reference that we took in
-	 * this function when calling kgsl_sharedmem_find, second one is
-	 * to free the memory since this is a free ioctl
-	 */
-	kgsl_mem_entry_put(entry);
-	kgsl_mem_entry_put(entry);
-	return 0;
+	return _sharedmem_free_entry(entry);
 }
 
-static long kgsl_ioctl_gpumem_free_id(struct kgsl_device_private *dev_priv,
+long kgsl_ioctl_gpumem_free_id(struct kgsl_device_private *dev_priv,
 					unsigned int cmd, void *data)
 {
 	struct kgsl_gpumem_free_id *param = data;
@@ -2355,26 +2505,7 @@
 		return -EINVAL;
 	}
 
-	if (!kgsl_mem_entry_set_pend(entry)) {
-		kgsl_mem_entry_put(entry);
-		return -EBUSY;
-	}
-
-	trace_kgsl_mem_free(entry);
-
-	kgsl_memfree_hist_set_event(entry->priv->pid,
-				    entry->memdesc.gpuaddr,
-				    entry->memdesc.size,
-				    entry->memdesc.flags);
-
-	/*
-	 * First kgsl_mem_entry_put is for the reference that we took in
-	 * this function when calling kgsl_sharedmem_find_id, second one is
-	 * to free the memory since this is a free ioctl
-	 */
-	kgsl_mem_entry_put(entry);
-	kgsl_mem_entry_put(entry);
-	return 0;
+	return _sharedmem_free_entry(entry);
 }
 
 static struct vm_area_struct *kgsl_get_vma_from_start_addr(unsigned int addr)
@@ -3385,78 +3516,65 @@
 typedef long (*kgsl_ioctl_func_t)(struct kgsl_device_private *,
 	unsigned int, void *);
 
-#define KGSL_IOCTL_FUNC(_cmd, _func, _flags) \
+#define KGSL_IOCTL_FUNC(_cmd, _func) \
 	[_IOC_NR((_cmd))] = \
-		{ .cmd = (_cmd), .func = (_func), .flags = (_flags) }
+		{ .cmd = (_cmd), .func = (_func) }
 
-#define KGSL_IOCTL_LOCK		BIT(0)
 
 static const struct {
 	unsigned int cmd;
 	kgsl_ioctl_func_t func;
-	unsigned int flags;
 } kgsl_ioctl_funcs[] = {
 	KGSL_IOCTL_FUNC(IOCTL_KGSL_DEVICE_GETPROPERTY,
-			kgsl_ioctl_device_getproperty,
-			KGSL_IOCTL_LOCK),
+			kgsl_ioctl_device_getproperty),
 	KGSL_IOCTL_FUNC(IOCTL_KGSL_DEVICE_WAITTIMESTAMP,
-			kgsl_ioctl_device_waittimestamp,
-			KGSL_IOCTL_LOCK),
+			kgsl_ioctl_device_waittimestamp),
 	KGSL_IOCTL_FUNC(IOCTL_KGSL_DEVICE_WAITTIMESTAMP_CTXTID,
-			kgsl_ioctl_device_waittimestamp_ctxtid,
-			KGSL_IOCTL_LOCK),
+			kgsl_ioctl_device_waittimestamp_ctxtid),
 	KGSL_IOCTL_FUNC(IOCTL_KGSL_RINGBUFFER_ISSUEIBCMDS,
-			kgsl_ioctl_rb_issueibcmds, 0),
+			kgsl_ioctl_rb_issueibcmds),
 	KGSL_IOCTL_FUNC(IOCTL_KGSL_SUBMIT_COMMANDS,
-			kgsl_ioctl_submit_commands, 0),
+			kgsl_ioctl_submit_commands),
 	KGSL_IOCTL_FUNC(IOCTL_KGSL_CMDSTREAM_READTIMESTAMP,
-			kgsl_ioctl_cmdstream_readtimestamp,
-			KGSL_IOCTL_LOCK),
+			kgsl_ioctl_cmdstream_readtimestamp),
 	KGSL_IOCTL_FUNC(IOCTL_KGSL_CMDSTREAM_READTIMESTAMP_CTXTID,
-			kgsl_ioctl_cmdstream_readtimestamp_ctxtid,
-			KGSL_IOCTL_LOCK),
+			kgsl_ioctl_cmdstream_readtimestamp_ctxtid),
 	KGSL_IOCTL_FUNC(IOCTL_KGSL_CMDSTREAM_FREEMEMONTIMESTAMP,
-			kgsl_ioctl_cmdstream_freememontimestamp,
-			KGSL_IOCTL_LOCK),
+			kgsl_ioctl_cmdstream_freememontimestamp),
 	KGSL_IOCTL_FUNC(IOCTL_KGSL_CMDSTREAM_FREEMEMONTIMESTAMP_CTXTID,
-			kgsl_ioctl_cmdstream_freememontimestamp_ctxtid,
-			KGSL_IOCTL_LOCK),
+			kgsl_ioctl_cmdstream_freememontimestamp_ctxtid),
 	KGSL_IOCTL_FUNC(IOCTL_KGSL_DRAWCTXT_CREATE,
-			kgsl_ioctl_drawctxt_create,
-			KGSL_IOCTL_LOCK),
+			kgsl_ioctl_drawctxt_create),
 	KGSL_IOCTL_FUNC(IOCTL_KGSL_DRAWCTXT_DESTROY,
-			kgsl_ioctl_drawctxt_destroy,
-			KGSL_IOCTL_LOCK),
+			kgsl_ioctl_drawctxt_destroy),
 	KGSL_IOCTL_FUNC(IOCTL_KGSL_MAP_USER_MEM,
-			kgsl_ioctl_map_user_mem, 0),
+			kgsl_ioctl_map_user_mem),
 	KGSL_IOCTL_FUNC(IOCTL_KGSL_SHAREDMEM_FROM_PMEM,
-			kgsl_ioctl_map_user_mem, 0),
+			kgsl_ioctl_map_user_mem),
 	KGSL_IOCTL_FUNC(IOCTL_KGSL_SHAREDMEM_FREE,
-			kgsl_ioctl_sharedmem_free, 0),
+			kgsl_ioctl_sharedmem_free),
 	KGSL_IOCTL_FUNC(IOCTL_KGSL_SHAREDMEM_FLUSH_CACHE,
-			kgsl_ioctl_sharedmem_flush_cache, 0),
+			kgsl_ioctl_sharedmem_flush_cache),
 	KGSL_IOCTL_FUNC(IOCTL_KGSL_GPUMEM_ALLOC,
-			kgsl_ioctl_gpumem_alloc, 0),
+			kgsl_ioctl_gpumem_alloc),
 	KGSL_IOCTL_FUNC(IOCTL_KGSL_CFF_SYNCMEM,
-			kgsl_ioctl_cff_syncmem, 0),
+			kgsl_ioctl_cff_syncmem),
 	KGSL_IOCTL_FUNC(IOCTL_KGSL_CFF_USER_EVENT,
-			kgsl_ioctl_cff_user_event, 0),
+			kgsl_ioctl_cff_user_event),
 	KGSL_IOCTL_FUNC(IOCTL_KGSL_TIMESTAMP_EVENT,
-			kgsl_ioctl_timestamp_event,
-			KGSL_IOCTL_LOCK),
+			kgsl_ioctl_timestamp_event),
 	KGSL_IOCTL_FUNC(IOCTL_KGSL_SETPROPERTY,
-			kgsl_ioctl_device_setproperty,
-			KGSL_IOCTL_LOCK),
+			kgsl_ioctl_device_setproperty),
 	KGSL_IOCTL_FUNC(IOCTL_KGSL_GPUMEM_ALLOC_ID,
-			kgsl_ioctl_gpumem_alloc_id, 0),
+			kgsl_ioctl_gpumem_alloc_id),
 	KGSL_IOCTL_FUNC(IOCTL_KGSL_GPUMEM_FREE_ID,
-			kgsl_ioctl_gpumem_free_id, 0),
+			kgsl_ioctl_gpumem_free_id),
 	KGSL_IOCTL_FUNC(IOCTL_KGSL_GPUMEM_GET_INFO,
-			kgsl_ioctl_gpumem_get_info, 0),
+			kgsl_ioctl_gpumem_get_info),
 	KGSL_IOCTL_FUNC(IOCTL_KGSL_GPUMEM_SYNC_CACHE,
-			kgsl_ioctl_gpumem_sync_cache, 0),
+			kgsl_ioctl_gpumem_sync_cache),
 	KGSL_IOCTL_FUNC(IOCTL_KGSL_GPUMEM_SYNC_CACHE_BULK,
-			kgsl_ioctl_gpumem_sync_cache_bulk, 0),
+			kgsl_ioctl_gpumem_sync_cache_bulk),
 };
 
 static long kgsl_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
@@ -3464,7 +3582,7 @@
 	struct kgsl_device_private *dev_priv = filep->private_data;
 	unsigned int nr;
 	kgsl_ioctl_func_t func;
-	int lock, ret;
+	int ret;
 	char ustack[64];
 	void *uptr = NULL;
 
@@ -3521,7 +3639,6 @@
 		}
 
 		func = kgsl_ioctl_funcs[nr].func;
-		lock = kgsl_ioctl_funcs[nr].flags & KGSL_IOCTL_LOCK;
 	} else {
 		func = dev_priv->device->ftbl->ioctl;
 		if (!func) {
@@ -3530,19 +3647,10 @@
 			ret = -ENOIOCTLCMD;
 			goto done;
 		}
-		lock = 1;
 	}
 
-	if (lock)
-		kgsl_mutex_lock(&dev_priv->device->mutex,
-			&dev_priv->device->mutex_owner);
-
 	ret = func(dev_priv, cmd, uptr);
 
-	if (lock)
-		kgsl_mutex_unlock(&dev_priv->device->mutex,
-			&dev_priv->device->mutex_owner);
-
 	/*
 	 * Still copy back on failure, but assume function took
 	 * all necessary precautions sanitizing the return values.
@@ -3902,8 +4010,6 @@
 	.process_mutex = __MUTEX_INITIALIZER(kgsl_driver.process_mutex),
 	.ptlock = __SPIN_LOCK_UNLOCKED(kgsl_driver.ptlock),
 	.devlock = __MUTEX_INITIALIZER(kgsl_driver.devlock),
-	.memfree_hist_mutex =
-		__MUTEX_INITIALIZER(kgsl_driver.memfree_hist_mutex),
 	/*
 	 * Full cache flushes are faster than line by line on at least
 	 * 8064 and 8974 once the region to be flushed is > 16mb.
@@ -4247,7 +4353,7 @@
 		kgsl_driver.class = NULL;
 	}
 
-	kgsl_memfree_hist_exit();
+	kgsl_memfree_exit();
 	unregister_chrdev_region(kgsl_driver.major, KGSL_DEVICE_MAX);
 }
 
@@ -4319,8 +4425,7 @@
 			goto err;
 	}
 
-	if (kgsl_memfree_hist_init())
-		KGSL_CORE_ERR("failed to init memfree_hist");
+	kgsl_memfree_init();
 
 	return 0;
 
diff --git a/drivers/gpu/msm/kgsl.h b/drivers/gpu/msm/kgsl.h
index 6da4a86..0bd71cb 100644
--- a/drivers/gpu/msm/kgsl.h
+++ b/drivers/gpu/msm/kgsl.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2008-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
@@ -75,25 +75,8 @@
 #define KGSL_STATS_ADD(_size, _stat, _max) \
 	do { _stat += (_size); if (_stat > _max) _max = _stat; } while (0)
 
-
-#define KGSL_MEMFREE_HIST_SIZE	((int)(PAGE_SIZE * 2))
-
 #define KGSL_MAX_NUMIBS 100000
 
-struct kgsl_memfree_hist_elem {
-	unsigned int pid;
-	unsigned int gpuaddr;
-	unsigned int size;
-	unsigned int flags;
-};
-
-struct kgsl_memfree_hist {
-	void *base_hist_rb;
-	unsigned int size;
-	struct kgsl_memfree_hist_elem *wptr;
-};
-
-
 struct kgsl_device;
 struct kgsl_context;
 
@@ -122,9 +105,6 @@
 
 	void *ptpool;
 
-	struct mutex memfree_hist_mutex;
-	struct kgsl_memfree_hist memfree_hist;
-
 	struct {
 		unsigned int vmalloc;
 		unsigned int vmalloc_max;
diff --git a/drivers/gpu/msm/kgsl_debugfs.c b/drivers/gpu/msm/kgsl_debugfs.c
index 5645628..ccb2312 100644
--- a/drivers/gpu/msm/kgsl_debugfs.c
+++ b/drivers/gpu/msm/kgsl_debugfs.c
@@ -123,52 +123,6 @@
 KGSL_DEBUGFS_LOG(mem_log);
 KGSL_DEBUGFS_LOG(pwr_log);
 
-static int memfree_hist_print(struct seq_file *s, void *unused)
-{
-	void *base = kgsl_driver.memfree_hist.base_hist_rb;
-
-	struct kgsl_memfree_hist_elem *wptr = kgsl_driver.memfree_hist.wptr;
-	struct kgsl_memfree_hist_elem *p;
-	char str[16];
-
-	seq_printf(s, "%8s %8s %8s %11s\n",
-			"pid", "gpuaddr", "size", "flags");
-
-	mutex_lock(&kgsl_driver.memfree_hist_mutex);
-	p = wptr;
-	for (;;) {
-		kgsl_get_memory_usage(str, sizeof(str), p->flags);
-		/*
-		 * if the ring buffer is not filled up yet
-		 * all its empty elems have size==0
-		 * just skip them ...
-		*/
-		if (p->size)
-			seq_printf(s, "%8d %08x %8d %11s\n",
-				p->pid, p->gpuaddr, p->size, str);
-		p++;
-		if ((void *)p >= base + kgsl_driver.memfree_hist.size)
-			p = (struct kgsl_memfree_hist_elem *) base;
-
-		if (p == kgsl_driver.memfree_hist.wptr)
-			break;
-	}
-	mutex_unlock(&kgsl_driver.memfree_hist_mutex);
-	return 0;
-}
-
-static int memfree_hist_open(struct inode *inode, struct file *file)
-{
-	return single_open(file, memfree_hist_print, inode->i_private);
-}
-
-static const struct file_operations memfree_hist_fops = {
-	.open = memfree_hist_open,
-	.read = seq_read,
-	.llseek = seq_lseek,
-	.release = single_release,
-};
-
 void kgsl_device_debugfs_init(struct kgsl_device *device)
 {
 	if (kgsl_debugfs_dir && !IS_ERR(kgsl_debugfs_dir))
@@ -188,8 +142,6 @@
 				&mem_log_fops);
 	debugfs_create_file("log_level_pwr", 0644, device->d_debugfs, device,
 				&pwr_log_fops);
-	debugfs_create_file("memfree_history", 0444, device->d_debugfs, device,
-				&memfree_hist_fops);
 
 	/* Create postmortem dump control files */
 
diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h
index 1e6fbc9..6f17d56c 100644
--- a/drivers/gpu/msm/kgsl_device.h
+++ b/drivers/gpu/msm/kgsl_device.h
@@ -173,10 +173,9 @@
  * @ibcount: Number of IBs in the command list
  * @ibdesc: Pointer to the list of IBs
  * @expires: Point in time when the cmdbatch is considered to be hung
- * @invalid:  non-zero if the dispatcher determines the command and the owning
- * context should be invalidated
  * @refcount: kref structure to maintain the reference count
  * @synclist: List of context/timestamp tuples to wait for before issuing
+ * @timer: a timer used to track possible sync timeouts for this cmdbatch
  *
  * This struture defines an atomic batch of command buffers issued from
  * userspace.
@@ -193,9 +192,9 @@
 	uint32_t ibcount;
 	struct kgsl_ibdesc *ibdesc;
 	unsigned long expires;
-	int invalid;
 	struct kref refcount;
 	struct list_head synclist;
+	struct timer_list timer;
 };
 
 /**
@@ -548,6 +547,9 @@
 		*context);
 int kgsl_context_detach(struct kgsl_context *context);
 
+int kgsl_memfree_find_entry(pid_t pid, unsigned long *gpuaddr,
+	unsigned long *size, unsigned int *flags);
+
 /**
  * kgsl_context_put() - Release context reference count
  * @context: Pointer to the KGSL context to be released
@@ -728,27 +730,6 @@
 }
 
 /**
- * kgsl_cmdbatch_sync_pending() - return true if the cmdbatch is waiting
- * @cmdbatch: Pointer to the command batch object to check
- *
- * Return non-zero if the specified command batch is still waiting for sync
- * point dependencies to be satisfied
- */
-static inline int kgsl_cmdbatch_sync_pending(struct kgsl_cmdbatch *cmdbatch)
-{
-	int ret;
-
-	if (cmdbatch == NULL)
-		return 0;
-
-	spin_lock(&cmdbatch->lock);
-	ret = list_empty(&cmdbatch->synclist) ? 0 : 1;
-	spin_unlock(&cmdbatch->lock);
-
-	return ret;
-}
-
-/**
  * kgsl_sysfs_store() - parse a string from a sysfs store function
  * @buf: Incoming string to parse
  * @ptr: Pointer to an unsigned int to store the value
diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c
index 488e5a8..c4fa8af 100644
--- a/drivers/gpu/msm/kgsl_iommu.c
+++ b/drivers/gpu/msm/kgsl_iommu.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-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
@@ -281,39 +281,20 @@
 static void _check_if_freed(struct kgsl_iommu_device *iommu_dev,
 	unsigned long addr, unsigned int pid)
 {
-	void *base = kgsl_driver.memfree_hist.base_hist_rb;
-	struct kgsl_memfree_hist_elem *wptr;
-	struct kgsl_memfree_hist_elem *p;
+	unsigned long gpuaddr = addr;
+	unsigned long size = 0;
+	unsigned int flags = 0;
+
 	char name[32];
 	memset(name, 0, sizeof(name));
 
-	mutex_lock(&kgsl_driver.memfree_hist_mutex);
-	wptr = kgsl_driver.memfree_hist.wptr;
-	p = wptr;
-	for (;;) {
-		if (p->size && p->pid == pid)
-			if (addr >= p->gpuaddr &&
-				addr < (p->gpuaddr + p->size)) {
-
-				kgsl_get_memory_usage(name, sizeof(name) - 1,
-					p->flags);
-				KGSL_LOG_DUMP(iommu_dev->kgsldev,
-					"---- premature free ----\n");
-				KGSL_LOG_DUMP(iommu_dev->kgsldev,
-					"[%8.8X-%8.8X] (%s) was already freed by pid %d\n",
-					p->gpuaddr,
-					p->gpuaddr + p->size,
-					name,
-					p->pid);
-			}
-		p++;
-		if ((void *)p >= base + kgsl_driver.memfree_hist.size)
-			p = (struct kgsl_memfree_hist_elem *) base;
-
-		if (p == kgsl_driver.memfree_hist.wptr)
-			break;
+	if (kgsl_memfree_find_entry(pid, &gpuaddr, &size, &flags)) {
+		kgsl_get_memory_usage(name, sizeof(name) - 1, flags);
+		KGSL_LOG_DUMP(iommu_dev->kgsldev, "---- premature free ----\n");
+		KGSL_LOG_DUMP(iommu_dev->kgsldev,
+			"[%8.8lX-%8.8lX] (%s) was already freed by pid %d\n",
+			gpuaddr, gpuaddr + size, name, pid);
 	}
-	mutex_unlock(&kgsl_driver.memfree_hist_mutex);
 }
 
 static int kgsl_iommu_fault_handler(struct iommu_domain *domain,
diff --git a/drivers/gpu/msm/kgsl_mmu.c b/drivers/gpu/msm/kgsl_mmu.c
old mode 100644
new mode 100755
index 65e607b..4591165
--- a/drivers/gpu/msm/kgsl_mmu.c
+++ b/drivers/gpu/msm/kgsl_mmu.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2002,2007-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2002,2007-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
@@ -85,8 +85,17 @@
 	return status;
 }
 
-static void _kgsl_destroy_pagetable(struct kgsl_pagetable *pagetable)
+static void kgsl_destroy_pagetable(struct kref *kref)
 {
+	struct kgsl_pagetable *pagetable = container_of(kref,
+		struct kgsl_pagetable, refcount);
+
+	unsigned long flags;
+
+	spin_lock_irqsave(&kgsl_driver.ptlock, flags);
+	list_del(&pagetable->list);
+	spin_unlock_irqrestore(&kgsl_driver.ptlock, flags);
+
 	pagetable_remove_sysfs_objects(pagetable);
 
 	kgsl_cleanup_pt(pagetable);
@@ -101,29 +110,6 @@
 	kfree(pagetable);
 }
 
-static void kgsl_destroy_pagetable(struct kref *kref)
-{
-	struct kgsl_pagetable *pagetable = container_of(kref,
-		struct kgsl_pagetable, refcount);
-	unsigned long flags;
-
-	spin_lock_irqsave(&kgsl_driver.ptlock, flags);
-	list_del(&pagetable->list);
-	spin_unlock_irqrestore(&kgsl_driver.ptlock, flags);
-
-	_kgsl_destroy_pagetable(pagetable);
-}
-
-static void kgsl_destroy_pagetable_locked(struct kref *kref)
-{
-	struct kgsl_pagetable *pagetable = container_of(kref,
-		struct kgsl_pagetable, refcount);
-
-	list_del(&pagetable->list);
-
-	_kgsl_destroy_pagetable(pagetable);
-}
-
 static inline void kgsl_put_pagetable(struct kgsl_pagetable *pagetable)
 {
 	if (pagetable)
@@ -138,12 +124,9 @@
 
 	spin_lock_irqsave(&kgsl_driver.ptlock, flags);
 	list_for_each_entry(pt, &kgsl_driver.pagetable_list, list) {
-		if (kref_get_unless_zero(&pt->refcount)) {
-			if (pt->name == name) {
-				ret = pt;
-				break;
-			}
-			kref_put(&pt->refcount, kgsl_destroy_pagetable_locked);
+		if (name == pt->name && kref_get_unless_zero(&pt->refcount)) {
+			ret = pt;
+			break;
 		}
 	}
 
@@ -340,14 +323,9 @@
 		return KGSL_MMU_GLOBAL_PT;
 	spin_lock(&kgsl_driver.ptlock);
 	list_for_each_entry(pt, &kgsl_driver.pagetable_list, list) {
-		if (kref_get_unless_zero(&pt->refcount)) {
-			if (mmu->mmu_ops->mmu_pt_equal(mmu, pt, pt_base)) {
-				ptid = (int) pt->name;
-				kref_put(&pt->refcount,
-					kgsl_destroy_pagetable_locked);
-				break;
-			}
-			kref_put(&pt->refcount, kgsl_destroy_pagetable_locked);
+		if (mmu->mmu_ops->mmu_pt_equal(mmu, pt, pt_base)) {
+			ptid = (int) pt->name;
+			break;
 		}
 	}
 	spin_unlock(&kgsl_driver.ptlock);
@@ -367,23 +345,16 @@
 		return 0;
 	spin_lock(&kgsl_driver.ptlock);
 	list_for_each_entry(pt, &kgsl_driver.pagetable_list, list) {
-		if (kref_get_unless_zero(&pt->refcount)) {
-			if (mmu->mmu_ops->mmu_pt_equal(mmu, pt, pt_base)) {
-				if ((addr & ~(PAGE_SIZE-1)) == pt->fault_addr) {
-					ret = 1;
-					kref_put(&pt->refcount,
-						kgsl_destroy_pagetable_locked);
-					break;
-				} else {
-					pt->fault_addr =
-						(addr & ~(PAGE_SIZE-1));
-					ret = 0;
-					kref_put(&pt->refcount,
-						kgsl_destroy_pagetable_locked);
-					break;
-				}
+		if (mmu->mmu_ops->mmu_pt_equal(mmu, pt, pt_base)) {
+			if ((addr & ~(PAGE_SIZE-1)) == pt->fault_addr) {
+				ret = 1;
+				break;
+			} else {
+				pt->fault_addr =
+					(addr & ~(PAGE_SIZE-1));
+				ret = 0;
+				break;
 			}
-			kref_put(&pt->refcount, kgsl_destroy_pagetable_locked);
 		}
 	}
 	spin_unlock(&kgsl_driver.ptlock);
diff --git a/drivers/gpu/msm/kgsl_sync.c b/drivers/gpu/msm/kgsl_sync.c
index dc3ad21..cef052d 100644
--- a/drivers/gpu/msm/kgsl_sync.c
+++ b/drivers/gpu/msm/kgsl_sync.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-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
@@ -118,6 +118,9 @@
 	struct sync_pt *pt;
 	struct sync_fence *fence = NULL;
 	int ret = -EINVAL;
+	char fence_name[sizeof(fence->name)] = {};
+
+	priv.fence_fd = -1;
 
 	if (len != sizeof(priv))
 		return -EINVAL;
@@ -126,10 +129,12 @@
 	if (event == NULL)
 		return -ENOMEM;
 
+	kgsl_mutex_lock(&device->mutex, &device->mutex_owner);
+
 	context = kgsl_context_get_owner(owner, context_id);
 
 	if (context == NULL)
-		goto fail_pt;
+		goto unlock;
 
 	event->context = context;
 	event->timestamp = timestamp;
@@ -138,51 +143,67 @@
 	if (pt == NULL) {
 		KGSL_DRV_ERR(device, "kgsl_sync_pt_create failed\n");
 		ret = -ENOMEM;
-		goto fail_pt;
+		goto unlock;
 	}
+	snprintf(fence_name, sizeof(fence_name),
+		"%s-pid-%d-ctx-%d-ts-%d",
+		device->name, current->group_leader->pid,
+		context_id, timestamp);
 
-	fence = sync_fence_create("kgsl-fence", pt);
+
+	fence = sync_fence_create(fence_name, pt);
 	if (fence == NULL) {
 		/* only destroy pt when not added to fence */
 		kgsl_sync_pt_destroy(pt);
 		KGSL_DRV_ERR(device, "sync_fence_create failed\n");
 		ret = -ENOMEM;
-		goto fail_fence;
+		goto unlock;
 	}
 
 	priv.fence_fd = get_unused_fd_flags(0);
 	if (priv.fence_fd < 0) {
-		KGSL_DRV_ERR(device, "invalid fence fd\n");
-		ret = -EINVAL;
-		goto fail_fd;
+		KGSL_DRV_ERR(device, "Unable to get a file descriptor: %d\n",
+			priv.fence_fd);
+		ret = priv.fence_fd;
+		goto unlock;
 	}
 	sync_fence_install(fence, priv.fence_fd);
 
+	/* Unlock the mutex before copying to user */
+	kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
+
 	if (copy_to_user(data, &priv, sizeof(priv))) {
 		ret = -EFAULT;
-		goto fail_copy_fd;
+		goto out;
 	}
 
 	/*
 	 * Hold the context ref-count for the event - it will get released in
 	 * the callback
 	 */
+
+	kgsl_mutex_lock(&device->mutex, &device->mutex_owner);
+
 	ret = kgsl_add_event(device, context_id, timestamp,
 			kgsl_fence_event_cb, event, owner);
+
+	kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
+
 	if (ret)
-		goto fail_event;
+		goto out;
 
 	return 0;
 
-fail_event:
-fail_copy_fd:
-	/* clean up sync_fence_install */
-	put_unused_fd(priv.fence_fd);
-fail_fd:
-	/* clean up sync_fence_create */
-	sync_fence_put(fence);
-fail_fence:
-fail_pt:
+unlock:
+	kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
+
+out:
+	if (priv.fence_fd >= 0)
+		put_unused_fd(priv.fence_fd);
+
+	if (fence)
+		sync_fence_put(fence);
+
 	kgsl_context_put(context);
 	kfree(event);
 	return ret;
diff --git a/drivers/md/dm-req-crypt.c b/drivers/md/dm-req-crypt.c
index 87a4ab9..ef8f37c 100644
--- a/drivers/md/dm-req-crypt.c
+++ b/drivers/md/dm-req-crypt.c
@@ -23,6 +23,10 @@
 #include <linux/backing-dev.h>
 #include <linux/atomic.h>
 #include <linux/scatterlist.h>
+#include <linux/device-mapper.h>
+#include <linux/printk.h>
+#include <linux/pft.h>
+
 #include <crypto/scatterwalk.h>
 #include <asm/page.h>
 #include <asm/unaligned.h>
@@ -31,9 +35,6 @@
 #include <crypto/algapi.h>
 #include <mach/qcrypto.h>
 
-#include <linux/device-mapper.h>
-
-
 #define DM_MSG_PREFIX "req-crypt"
 
 #define MAX_SG_LIST	1024
@@ -52,13 +53,17 @@
 	int err;
 };
 
-struct dm_dev *dev;
+#define FDE_KEY_ID	0
+#define PFE_KEY_ID	1
+
+static struct dm_dev *dev;
 static struct kmem_cache *_req_crypt_io_pool;
-sector_t start_sector_orig;
-struct workqueue_struct *req_crypt_queue;
-mempool_t *req_io_pool;
-mempool_t *req_page_pool;
-struct crypto_ablkcipher *tfm;
+static sector_t start_sector_orig;
+static struct workqueue_struct *req_crypt_queue;
+static mempool_t *req_io_pool;
+static mempool_t *req_page_pool;
+static bool is_fde_enabled;
+static struct crypto_ablkcipher *tfm;
 
 struct req_dm_crypt_io {
 	struct work_struct work;
@@ -66,12 +71,69 @@
 	int error;
 	atomic_t pending;
 	struct timespec start_time;
+	bool should_encrypt;
+	bool should_decrypt;
+	u32 key_id;
 };
 
 static void req_crypt_cipher_complete
 		(struct crypto_async_request *req, int err);
 
 
+static  bool req_crypt_should_encrypt(struct req_dm_crypt_io *req)
+{
+	int ret;
+	bool should_encrypt = false;
+	struct bio *bio = NULL;
+	u32 key_id = 0;
+	bool is_encrypted = false;
+	bool is_inplace = false;
+
+	if (!req || !req->cloned_request || !req->cloned_request->bio)
+		return false;
+
+	bio = req->cloned_request->bio;
+
+	ret = pft_get_key_index(bio, &key_id, &is_encrypted, &is_inplace);
+	/* req->key_id = key_id; @todo support more than 1 pfe key */
+	if ((ret == 0) && (is_encrypted || is_inplace)) {
+		should_encrypt = true;
+		req->key_id = PFE_KEY_ID;
+	} else if (is_fde_enabled) {
+		should_encrypt = true;
+		req->key_id = FDE_KEY_ID;
+	}
+
+	return should_encrypt;
+}
+
+static  bool req_crypt_should_deccrypt(struct req_dm_crypt_io *req)
+{
+	int ret;
+	bool should_deccrypt = false;
+	struct bio *bio = NULL;
+	u32 key_id = 0;
+	bool is_encrypted = false;
+	bool is_inplace = false;
+
+	if (!req || !req->cloned_request || !req->cloned_request->bio)
+		return false;
+
+	bio = req->cloned_request->bio;
+
+	ret = pft_get_key_index(bio, &key_id, &is_encrypted, &is_inplace);
+	/* req->key_id = key_id; @todo support more than 1 pfe key */
+	if ((ret == 0) && (is_encrypted && !is_inplace)) {
+		should_deccrypt = true;
+		req->key_id = PFE_KEY_ID;
+	} else if (is_fde_enabled) {
+		should_deccrypt = true;
+		req->key_id = FDE_KEY_ID;
+	}
+
+	return should_deccrypt;
+}
+
 static void req_crypt_inc_pending(struct req_dm_crypt_io *io)
 {
 	atomic_inc(&io->pending);
@@ -196,6 +258,13 @@
 	ablkcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
 					req_crypt_cipher_complete, &result);
 	init_completion(&result.completion);
+	err = qcrypto_cipher_set_device(req, io->key_id);
+	if (err != 0) {
+		DMERR("%s qcrypto_cipher_set_device failed with err %d\n",
+				__func__, err);
+		error = DM_REQ_CRYPT_ERROR;
+		goto ablkcipher_req_alloc_failure;
+	}
 	qcrypto_cipher_set_flag(req,
 		QCRYPTO_CTX_USE_PIPE_KEY | QCRYPTO_CTX_XTS_DU_SIZE_512B);
 	crypto_ablkcipher_clear_flags(tfm, ~0);
@@ -270,6 +339,26 @@
 }
 
 /*
+ * This callback is called by the worker queue to perform non-decrypt reads
+ * and use the dm function to complete the bios and requests.
+ */
+static void req_cryptd_crypt_read_plain(struct req_dm_crypt_io *io)
+{
+	struct request *clone = NULL;
+	int error = 0;
+
+	if (!io || !io->cloned_request) {
+		DMERR("%s io is invalid\n", __func__);
+		BUG(); /* should not happen */
+	}
+
+	clone = io->cloned_request;
+
+	dm_end_request(clone, error);
+	mempool_free(io, req_io_pool);
+}
+
+/*
  * The callback that will be called by the worker queue to perform Encryption
  * for writes and submit the request using the elevelator.
  */
@@ -291,6 +380,7 @@
 	struct page *page = NULL;
 	u8 IV[AES_XTS_IV_LEN];
 	int remaining_size = 0;
+	int err = 0;
 
 	if (io) {
 		if (io->cloned_request) {
@@ -322,6 +412,13 @@
 				req_crypt_cipher_complete, &result);
 
 	init_completion(&result.completion);
+	err = qcrypto_cipher_set_device(req, io->key_id);
+	if (err != 0) {
+		DMERR("%s qcrypto_cipher_set_device failed with err %d\n",
+				__func__, err);
+		error = DM_REQ_CRYPT_ERROR;
+		goto ablkcipher_req_alloc_failure;
+	}
 	qcrypto_cipher_set_flag(req,
 		QCRYPTO_CTX_USE_PIPE_KEY | QCRYPTO_CTX_XTS_DU_SIZE_512B);
 	crypto_ablkcipher_clear_flags(tfm, ~0);
@@ -460,19 +557,44 @@
 	req_crypt_dec_pending_encrypt(io);
 }
 
+/*
+ * This callback is called by the worker queue to perform non-encrypted writes
+ * and submit the request using the elevelator.
+ */
+static void req_cryptd_crypt_write_plain(struct req_dm_crypt_io *io)
+{
+	struct request *clone = NULL;
+
+	if (!io || !io->cloned_request) {
+		DMERR("%s io is invalid\n", __func__);
+		BUG(); /* should not happen */
+	}
+
+	clone = io->cloned_request;
+	io->error = 0;
+	dm_dispatch_request(clone);
+}
+
 /* Queue callback function that will get triggered */
 static void req_cryptd_crypt(struct work_struct *work)
 {
 	struct req_dm_crypt_io *io =
 			container_of(work, struct req_dm_crypt_io, work);
 
-	if (rq_data_dir(io->cloned_request) == WRITE)
-		req_cryptd_crypt_write_convert(io);
-	else if (rq_data_dir(io->cloned_request) == READ)
-		req_cryptd_crypt_read_convert(io);
-	else
-		DMERR("%s received non-read/write request for Clone %u\n",
+	if (rq_data_dir(io->cloned_request) == WRITE) {
+		if (io->should_encrypt)
+			req_cryptd_crypt_write_convert(io);
+		else
+			req_cryptd_crypt_write_plain(io);
+	} else if (rq_data_dir(io->cloned_request) == READ) {
+		if (io->should_decrypt)
+			req_cryptd_crypt_read_convert(io);
+		else
+			req_cryptd_crypt_read_plain(io);
+	} else {
+		DMERR("%s received non-write request for Clone %u\n",
 				__func__, (unsigned int)io->cloned_request);
+	}
 }
 
 static void req_cryptd_queue_crypt(struct req_dm_crypt_io *io)
@@ -537,7 +659,7 @@
 	bvec = NULL;
 	if (rq_data_dir(clone) == WRITE) {
 		rq_for_each_segment(bvec, clone, iter1) {
-			if (bvec->bv_offset == 0) {
+			if (req_io->should_encrypt && bvec->bv_offset == 0) {
 				mempool_free(bvec->bv_page, req_page_pool);
 				bvec->bv_page = NULL;
 			} else
@@ -565,7 +687,6 @@
  * For a read request no pre-processing is required the request
  * is returned to dm once mapping is done
  */
-
 static int req_crypt_map(struct dm_target *ti, struct request *clone,
 			 union map_info *map_context)
 {
@@ -594,6 +715,11 @@
 	map_context->ptr = req_io;
 	atomic_set(&req_io->pending, 0);
 
+	if (rq_data_dir(clone) == WRITE)
+		req_io->should_encrypt = req_crypt_should_encrypt(req_io);
+	if (rq_data_dir(clone) == READ)
+		req_io->should_decrypt = req_crypt_should_deccrypt(req_io);
+
 	/* Get the queue of the underlying original device */
 	clone->q = bdev_get_queue(dev->bdev);
 	clone->rq_disk = dev->bdev->bd_disk;
@@ -641,6 +767,8 @@
 
 static void req_crypt_dtr(struct dm_target *ti)
 {
+	DMDEBUG("dm-req-crypt Destructor.\n");
+
 	if (req_crypt_queue) {
 		destroy_workqueue(req_crypt_queue);
 		req_crypt_queue = NULL;
@@ -670,6 +798,8 @@
 	char dummy;
 	int err = DM_REQ_CRYPT_ERROR;
 
+	DMDEBUG("dm-req-crypt Constructor.\n");
+
 	if (argc < 5) {
 		DMERR(" %s Not enough args\n", __func__);
 		err = DM_REQ_CRYPT_ERROR;
@@ -696,13 +826,24 @@
 			goto ctr_exit;
 		}
 	} else {
-		DMERR(" %s Arg[4]invalid\n", __func__);
+		DMERR(" %s Arg[4] invalid\n", __func__);
 		err =  DM_REQ_CRYPT_ERROR;
 		goto ctr_exit;
 	}
 
 	start_sector_orig = tmpll;
 
+	if (argv[5]) {
+		if (!strcmp(argv[5], "fde_enabled"))
+			is_fde_enabled = true;
+		else
+			is_fde_enabled = false;
+	} else {
+		DMERR(" %s Arg[5] invalid, set FDE eanbled.\n", __func__);
+		is_fde_enabled = true; /* backward compatible */
+	}
+	DMDEBUG("%s is_fde_enabled=%d\n", __func__, is_fde_enabled);
+
 	req_crypt_queue = alloc_workqueue("req_cryptd",
 					WQ_NON_REENTRANT |
 					WQ_HIGHPRI |
@@ -725,6 +866,7 @@
 	}
 
 	req_io_pool = mempool_create_slab_pool(MIN_IOS, _req_crypt_io_pool);
+	BUG_ON(!req_io_pool);
 	if (!req_io_pool) {
 		DMERR("%s req_io_pool not allocated\n", __func__);
 		err =  DM_REQ_CRYPT_ERROR;
@@ -791,6 +933,8 @@
 		kmem_cache_destroy(_req_crypt_io_pool);
 	}
 
+	DMINFO("dm-req-crypt successfully initalized.\n");
+
 	return r;
 }
 
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 69c5190..e8702e4 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
@@ -355,6 +355,7 @@
 	struct msm_vfe_src_info src_info[VFE_SRC_MAX];
 	uint16_t stream_handle_cnt;
 	unsigned long event_mask;
+	uint32_t burst_len;
 };
 
 struct msm_vfe_stats_hardware_info {
@@ -397,6 +398,7 @@
 	uint16_t stream_handle_cnt;
 	atomic_t stats_update;
 	uint32_t stats_mask;
+	uint32_t stats_burst_len;
 };
 
 struct msm_vfe_tasklet_queue_cmd {
@@ -480,8 +482,7 @@
 	struct list_head tasklet_q;
 	struct tasklet_struct vfe_tasklet;
 	struct msm_vfe_tasklet_queue_cmd
-		tasklet_queue_cmd[MSM_VFE_TASKLETQ_SIZE];
-
+	tasklet_queue_cmd[MSM_VFE_TASKLETQ_SIZE];
 	uint32_t soc_hw_version;
 	uint32_t vfe_hw_version;
 	struct msm_vfe_hardware_info *hw_info;
@@ -498,6 +499,7 @@
 	void __iomem *p_avtimer_lsw;
 	uint8_t ignore_error;
 	struct msm_isp_statistics *stats;
+	uint32_t vfe_ub_size;
 };
 
 #endif
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 e817680..353b55f 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
@@ -36,10 +36,10 @@
 #define VFE40_8x26_VERSION 0x20000013
 #define VFE40_8x26V2_VERSION 0x20010014
 
-#define VFE40_BURST_LEN 1
-#define VFE40_STATS_BURST_LEN 1
-#define VFE40_UB_SIZE 1536
-#define VFE40_EQUAL_SLICE_UB 228
+
+/* STATS_SIZE (BE + BG + BF+ RS + CS + IHIST + BHIST ) = 392 */
+#define VFE40_STATS_SIZE 392
+
 #define VFE40_WM_BASE(idx) (0x6C + 0x24 * idx)
 #define VFE40_RDI_BASE(idx) (0x2E8 + 0x4 * idx)
 #define VFE40_XBAR_BASE(idx) (0x58 + 0x4 * (idx / 2))
@@ -971,6 +971,11 @@
 	uint8_t plane_idx)
 {
 	uint32_t val;
+
+	struct msm_vfe_axi_shared_data *axi_data =
+		&vfe_dev->axi_data;
+	uint32_t burst_len = axi_data->burst_len;
+
 	uint32_t wm_base = VFE40_WM_BASE(stream_info->wm[plane_idx]);
 
 	if (!stream_info->frame_based) {
@@ -992,7 +997,7 @@
 				plane_idx].output_stride) << 16 |
 			(stream_info->plane_cfg[
 				plane_idx].output_height - 1) << 4 |
-			VFE40_BURST_LEN;
+			burst_len;
 		msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x18);
 	} else {
 		msm_camera_io_w(0x2, vfe_dev->vfe_base + wm_base);
@@ -1002,7 +1007,7 @@
 				plane_idx].output_width) << 16 |
 			(stream_info->plane_cfg[
 				plane_idx].output_height - 1) << 4 |
-			VFE40_BURST_LEN;
+			burst_len;
 		msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x18);
 	}
 
@@ -1117,6 +1122,7 @@
 	uint8_t num_used_wms = 0;
 	uint32_t prop_size = 0;
 	uint32_t wm_ub_size;
+	uint32_t axi_wm_ub;
 
 	for (i = 0; i < axi_data->hw_info->num_wm; i++) {
 		if (axi_data->free_wm[i] > 0) {
@@ -1124,7 +1130,9 @@
 			total_image_size += axi_data->wm_image_size[i];
 		}
 	}
-	prop_size = MSM_ISP40_TOTAL_WM_UB -
+	axi_wm_ub = vfe_dev->vfe_ub_size - VFE40_STATS_SIZE;
+
+	prop_size = axi_wm_ub -
 		axi_data->hw_info->min_wm_ub * num_used_wms;
 	for (i = 0; i < axi_data->hw_info->num_wm; i++) {
 		if (axi_data->free_wm[i]) {
@@ -1149,10 +1157,14 @@
 	int i;
 	uint32_t ub_offset = 0;
 	struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
+	uint32_t axi_equal_slice_ub =
+		(vfe_dev->vfe_ub_size - VFE40_STATS_SIZE)/
+			(axi_data->hw_info->num_wm - 1);
+
 	for (i = 0; i < axi_data->hw_info->num_wm; i++) {
-		msm_camera_io_w(ub_offset << 16 | (VFE40_EQUAL_SLICE_UB - 1),
+		msm_camera_io_w(ub_offset << 16 | (axi_equal_slice_ub - 1),
 			vfe_dev->vfe_base + VFE40_WM_BASE(i) + 0x10);
-		ub_offset += VFE40_EQUAL_SLICE_UB;
+		ub_offset += axi_equal_slice_ub;
 	}
 }
 
@@ -1334,7 +1346,11 @@
 static void msm_vfe40_stats_cfg_ub(struct vfe_device *vfe_dev)
 {
 	int i;
-	uint32_t ub_offset = VFE40_UB_SIZE;
+	struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data;
+	uint32_t ub_offset = vfe_dev->vfe_ub_size;
+	uint32_t stats_burst_len = stats_data->stats_burst_len;
+
+
 	uint32_t ub_size[VFE40_NUM_STATS_TYPE] = {
 		64, /*MSM_ISP_STATS_BE*/
 		128, /*MSM_ISP_STATS_BG*/
@@ -1348,7 +1364,7 @@
 
 	for (i = 0; i < VFE40_NUM_STATS_TYPE; i++) {
 		ub_offset -= ub_size[i];
-		msm_camera_io_w(VFE40_STATS_BURST_LEN << 30 |
+		msm_camera_io_w(stats_burst_len << 30 |
 			ub_offset << 16 | (ub_size[i] - 1),
 			vfe_dev->vfe_base + VFE40_STATS_BASE(i) + 0xC);
 	}
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
index 4c3a3d5..d11ea68 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
@@ -524,7 +524,9 @@
 			stream_info->format_factor / ISP_Q2;
 	} else {
 		int rdi = SRC_TO_INTF(stream_info->stream_src);
-		stream_info->bandwidth = axi_data->src_info[rdi].pixel_clock;
+		if (rdi < VFE_SRC_MAX)
+			stream_info->bandwidth =
+				axi_data->src_info[rdi].pixel_clock;
 	}
 }
 
@@ -534,6 +536,7 @@
 	uint32_t io_format = 0;
 	struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd = arg;
 	struct msm_vfe_axi_stream *stream_info;
+	struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
 
 	rc = msm_isp_axi_create_stream(
 		&vfe_dev->axi_data, stream_cfg_cmd);
@@ -581,6 +584,8 @@
 
 	msm_isp_calculate_framedrop(&vfe_dev->axi_data, stream_cfg_cmd);
 	stream_info->vt_enable = stream_cfg_cmd->vt_enable;
+	axi_data->burst_len = stream_cfg_cmd->burst_len;
+
 	if (stream_info->vt_enable) {
 		vfe_dev->vt_enable = stream_info->vt_enable;
 	#ifdef CONFIG_MSM_AVTIMER
@@ -853,8 +858,11 @@
 	struct msm_isp_event_data buf_event;
 	struct timeval *time_stamp;
 	uint32_t stream_idx = HANDLE_TO_IDX(stream_info->stream_handle);
-	uint32_t frame_id = vfe_dev->axi_data.
-		src_info[SRC_TO_INTF(stream_info->stream_src)].frame_id;
+	uint32_t src_intf = SRC_TO_INTF(stream_info->stream_src);
+	uint32_t frame_id = 0;
+	if (src_intf < VFE_SRC_MAX) {
+		frame_id = vfe_dev->axi_data.src_info[src_intf].frame_id;
+	}
 
 	if (buf && ts) {
 		if (vfe_dev->vt_enable) {
@@ -1196,7 +1204,7 @@
 			enum msm_isp_camif_update_state camif_update)
 {
 	int i, rc = 0;
-	uint8_t src_state, wait_for_complete = 0;
+	uint8_t src_state = 0, wait_for_complete = 0;
 	uint32_t wm_reload_mask = 0x0;
 	struct msm_vfe_axi_stream *stream_info;
 	struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
@@ -1212,8 +1220,9 @@
 		}
 		stream_info = &axi_data->stream_info[
 			HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i])];
-		src_state = axi_data->src_info[
-			SRC_TO_INTF(stream_info->stream_src)].active;
+		if (SRC_TO_INTF(stream_info->stream_src) < VFE_SRC_MAX)
+			src_state = axi_data->src_info[
+				SRC_TO_INTF(stream_info->stream_src)].active;
 
 		msm_isp_calculate_bandwidth(axi_data, stream_info);
 		msm_isp_reset_framedrop(vfe_dev, stream_info);
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c
index 6bd7585..d4c86a5 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c
@@ -490,6 +490,9 @@
 {
 	int rc = 0;
 	struct msm_vfe_stats_stream_cfg_cmd *stream_cfg_cmd = arg;
+	struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data;
+	stats_data->stats_burst_len =  stream_cfg_cmd->stats_burst_len;
+
 	if (vfe_dev->stats_data.num_active_stream == 0)
 		vfe_dev->hw_info->vfe_ops.stats_ops.cfg_ub(vfe_dev);
 
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 b1521df..a81c7bb 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
@@ -701,6 +701,10 @@
 		}
 		break;
 	}
+	case SET_WM_UB_SIZE: {
+		vfe_dev->vfe_ub_size = *cfg_data;
+		break;
+	}
 	}
 	return 0;
 }
@@ -1143,6 +1147,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.
@@ -1158,7 +1167,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;
 	}
 
@@ -1211,7 +1220,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/jpeg_10/msm_jpeg_platform.c b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_platform.c
index 407b81f..2f943a4 100644
--- a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_platform.c
+++ b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_platform.c
@@ -347,8 +347,12 @@
 		JPEG_DBG("%s:%d]", __func__, __LINE__);
 	}
 #endif
+	if (pgmn_dev->jpeg_bus_client) {
+		msm_bus_scale_client_update_request(
+			pgmn_dev->jpeg_bus_client, 0);
+		msm_bus_scale_unregister_client(pgmn_dev->jpeg_bus_client);
+	}
 
-	msm_bus_scale_unregister_client(pgmn_dev->jpeg_bus_client);
 	msm_cam_clk_enable(&pgmn_dev->pdev->dev, jpeg_8x_clk_info,
 	pgmn_dev->jpeg_clk, ARRAY_SIZE(jpeg_8x_clk_info), 0);
 	JPEG_DBG("%s:%d] clock disbale done", __func__, __LINE__);
diff --git a/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c b/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c
index bf66442..22498a4 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c
@@ -1102,7 +1102,7 @@
 {
 	struct cci_device *new_cci_dev;
 	int rc = 0;
-	pr_err("%s: pdev %p device id = %d\n", __func__, pdev, pdev->id);
+	CDBG("%s: pdev %p device id = %d\n", __func__, pdev, pdev->id);
 	new_cci_dev = kzalloc(sizeof(struct cci_device), GFP_KERNEL);
 	if (!new_cci_dev) {
 		CDBG("%s: no enough memory\n", __func__);
diff --git a/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c b/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c
index 7649a40..059780d 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c
@@ -131,12 +131,6 @@
 		e_ctrl->cal_data.mapdata,
 		cdata->cfg.read_data.num_bytes);
 
-	/* should only be called once.  free kernel resource */
-	if (!rc) {
-		kfree(e_ctrl->cal_data.mapdata);
-		kfree(e_ctrl->cal_data.map);
-		memset(&e_ctrl->cal_data, 0, sizeof(e_ctrl->cal_data));
-	}
 	return rc;
 }
 
diff --git a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_dt_util.c b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_dt_util.c
index cc301ae..c321a68 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_dt_util.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_dt_util.c
@@ -1068,11 +1068,6 @@
 	return 0;
 power_up_failed:
 	pr_err("%s:%d failed\n", __func__, __LINE__);
-	if (device_type == MSM_CAMERA_PLATFORM_DEVICE) {
-		sensor_i2c_client->i2c_func_tbl->i2c_util(
-			sensor_i2c_client, MSM_CCI_RELEASE);
-	}
-
 	for (index--; index >= 0; index--) {
 		CDBG("%s index %d\n", __func__, index);
 		power_setting = &ctrl->power_setting[index];
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 c50a623..c848287 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
@@ -50,7 +50,7 @@
 	int rc;
 	int tm = 10000;
 	if (s_init->module_init_status == 1) {
-		pr_err("msm_cam_get_module_init_status -2\n");
+		CDBG("msm_cam_get_module_init_status -2\n");
 		return 0;
 	}
 	rc = wait_event_interruptible_timeout(s_init->state_wait,
@@ -137,7 +137,7 @@
 		return -ENOMEM;
 	}
 
-	pr_err("MSM_SENSOR_INIT_MODULE %p", NULL);
+	CDBG("MSM_SENSOR_INIT_MODULE %p", NULL);
 
 	/* Initialize mutex */
 	mutex_init(&s_init->imutex);
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
old mode 100644
new mode 100755
index 071f698..9f0dac4
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -3467,13 +3467,13 @@
 				capability->height.min);
 			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.width[CAPTURE_PORT] >
+			capability->width.max)) {
+			dprintk(VIDC_ERR,
+				"Unsupported width = %u supported max width = %u",
+				inst->prop.width[CAPTURE_PORT],
+				capability->width.max);
+				rc = -ENOTSUPP;
 		}
 		if (!rc && (inst->prop.height[CAPTURE_PORT]
 			* inst->prop.width[CAPTURE_PORT] >
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_debug.c b/drivers/media/platform/msm/vidc/msm_vidc_debug.c
old mode 100644
new mode 100755
index 475683c..0ac6fc4
--- a/drivers/media/platform/msm/vidc/msm_vidc_debug.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_debug.c
@@ -20,7 +20,6 @@
 int msm_fw_debug = 0x18;
 int msm_fw_debug_mode = 0x1;
 int msm_fw_low_power_mode = 0x1;
-int msm_vp8_low_tier = 0x1;
 int msm_vidc_hw_rsp_timeout = 1000;
 
 struct debug_buffer {
@@ -184,11 +183,6 @@
 		dprintk(VIDC_ERR, "debugfs_create_file: fail\n");
 		goto failed_create_dir;
 	}
-	if (!debugfs_create_u32("vp8_low_tier", S_IRUGO | S_IWUSR,
-			parent, &msm_vp8_low_tier)) {
-		dprintk(VIDC_ERR, "debugfs_create_file: fail\n");
-		goto failed_create_dir;
-	}
 	if (!debugfs_create_u32("debug_output", S_IRUGO | S_IWUSR,
 			parent, &msm_vidc_debug_out)) {
 		dprintk(VIDC_ERR, "debugfs_create_file: fail\n");
diff --git a/drivers/media/platform/msm/vidc/q6_hfi.c b/drivers/media/platform/msm/vidc/q6_hfi.c
old mode 100644
new mode 100755
index bbba29a..52bbe12
--- a/drivers/media/platform/msm/vidc/q6_hfi.c
+++ b/drivers/media/platform/msm/vidc/q6_hfi.c
@@ -1033,6 +1033,11 @@
 		dprintk(VIDC_ERR, "Invalid Params");
 		return -EINVAL;
 	}
+	if (ptype == HAL_PARAM_VDEC_CONTINUE_DATA_TRANSFER) {
+		dprintk(VIDC_WARN, "Smoothstreaming is not supported\n");
+		return -ENOTSUPP;
+	}
+
 	dev = session->device;
 	dprintk(VIDC_DBG, "in set_prop,with prop id: 0x%x", ptype);
 
@@ -1318,24 +1323,6 @@
 	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;
@@ -1390,7 +1377,6 @@
 	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
old mode 100644
new mode 100755
index 30ee45d..448fe3b
--- a/drivers/media/platform/msm/vidc/venus_hfi.c
+++ b/drivers/media/platform/msm/vidc/venus_hfi.c
@@ -3747,29 +3747,6 @@
 	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)
@@ -3932,7 +3909,6 @@
 	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
old mode 100644
new mode 100755
index 62507a1..38c5bdb
--- a/drivers/media/platform/msm/vidc/vidc_hfi_api.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
@@ -1168,8 +1168,6 @@
 	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/misc/qseecom.c b/drivers/misc/qseecom.c
index 23edc8a..7c20d1e 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -917,6 +917,7 @@
 		}
 		spin_unlock_irqrestore(
 		&qseecom.registered_app_list_lock, flags);
+		ret = 0;
 	} else {
 		pr_warn("App (%s) does'nt exist, loading apps for first time\n",
 			(char *)(load_img_req.img_name));
@@ -2947,9 +2948,10 @@
 	struct qseecom_command_scm_resp resp;
 	int ret;
 
-	if (usage != QSEOS_KM_USAGE_DISK_ENCRYPTION) {
-		pr_err("Error:: unsupported usage %d\n", usage);
-		return -EFAULT;
+	if (usage < QSEOS_KM_USAGE_DISK_ENCRYPTION ||
+		usage >= QSEOS_KM_USAGE_MAX) {
+			pr_err("Error:: unsupported usage %d\n", usage);
+			return -EFAULT;
 	}
 
 	__qseecom_enable_clk(CLK_QSEE);
diff --git a/drivers/misc/tspp.c b/drivers/misc/tspp.c
index 2dfa404..405c626 100644
--- a/drivers/misc/tspp.c
+++ b/drivers/misc/tspp.c
@@ -459,6 +459,7 @@
 	struct tspp_global_performance_regs *tspp_global_performance;
 	struct tspp_pipe_context_regs *tspp_pipe_context;
 	struct tspp_pipe_performance_regs *tspp_pipe_performance;
+	bool req_irqs;
 
 	struct dentry *dent;
 	struct dentry *debugfs_regs[ARRAY_SIZE(debugfs_tspp_regs)];
@@ -1064,12 +1065,6 @@
 	writel_relaxed(TSPP_RST_RESET, pdev->base + TSPP_RST);
 	wmb();
 
-	/* BAM */
-	if (sps_device_reset(pdev->bam_handle) != 0) {
-		pr_err("tspp: error resetting bam");
-		return -EBUSY;
-	}
-
 	/* TSPP tables */
 	for (i = 0; i < TSPP_FILTER_TABLES; i++)
 		memset(pdev->filters[i],
@@ -1367,7 +1362,7 @@
 			goto failed;
 		}
 	}
-
+	device->req_irqs = true;
 	return 0;
 
 failed:
@@ -1389,6 +1384,7 @@
 
 	if (device->tspp_irq)
 		free_irq(device->tspp_irq, device);
+	device->req_irqs = false;
 }
 
 /*** TSPP API functions ***/
@@ -1408,9 +1404,9 @@
 {
 	u32 val;
 	int rc;
-	bool req_irq = false;
 	struct tspp_device *pdev;
 	struct tspp_channel *channel;
+	bool req_irqs = false;
 
 	TSPP_DEBUG("tspp_open_stream %i %i %i %i",
 		dev, channel_id, source->source, source->mode);
@@ -1438,15 +1434,14 @@
 			source->enable_inverse);
 
 	/* Request IRQ resources on first open */
-	if ((source->source == TSPP_SOURCE_TSIF0 ||
-		source->source == TSPP_SOURCE_TSIF1) &&
-		(pdev->tsif[0].ref_count + pdev->tsif[1].ref_count) == 0) {
+	if (!pdev->req_irqs && (source->source == TSPP_SOURCE_TSIF0 ||
+		source->source == TSPP_SOURCE_TSIF1)) {
 		rc = msm_tspp_req_irqs(pdev);
 		if (rc) {
 			pr_err("tspp: error requesting irqs\n");
 			return rc;
 		}
-		req_irq = true;
+		req_irqs = true;
 	}
 
 	switch (source->source) {
@@ -1499,7 +1494,8 @@
 	return 0;
 
 free_irq:
-	if (req_irq)
+	/* Free irqs only if were requested during opening of this stream */
+	if (req_irqs)
 		msm_tspp_free_irqs(pdev);
 	return rc;
 }
@@ -1576,6 +1572,26 @@
 }
 EXPORT_SYMBOL(tspp_close_stream);
 
+static int tspp_init_sps_device(struct tspp_device *dev)
+{
+	int ret;
+
+	ret = sps_register_bam_device(&dev->bam_props, &dev->bam_handle);
+	if (ret) {
+		pr_err("tspp: failed to register bam device, err-%d\n", ret);
+		return ret;
+	}
+
+	ret = sps_device_reset(dev->bam_handle);
+	if (ret) {
+		sps_deregister_bam_device(dev->bam_handle);
+		pr_err("tspp: error resetting bam device, err=%d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
 /**
  * tspp_open_channel - open a TSPP channel.
  *
@@ -1618,6 +1634,16 @@
 		if (rc)
 			return rc;
 
+		if (pdev->bam_handle == SPS_DEV_HANDLE_INVALID) {
+			rc = tspp_init_sps_device(pdev);
+			if (rc) {
+				pr_err("tspp: failed to init sps device, err=%d\n",
+					rc);
+				tspp_clock_stop(pdev);
+				return rc;
+			}
+		}
+
 		wake_lock(&pdev->wake_lock);
 	}
 
@@ -1698,6 +1724,7 @@
 err_desc_alloc:
 	sps_free_endpoint(channel->pipe);
 err_sps_alloc:
+	channel->used = 0;
 	return rc;
 }
 EXPORT_SYMBOL(tspp_open_channel);
@@ -1805,6 +1832,9 @@
 	channel->locked = NULL;
 
 	if (tspp_channels_in_use(pdev) == 0) {
+		sps_deregister_bam_device(pdev->bam_handle);
+		pdev->bam_handle = SPS_DEV_HANDLE_INVALID;
+
 		wake_unlock(&pdev->wake_lock);
 		tspp_clock_stop(pdev);
 	}
@@ -2210,6 +2240,7 @@
 	struct tspp_mem_buffer *buffer;
 	struct tspp_channel *channel;
 	struct tspp_device *pdev;
+	unsigned long flags;
 
 	if (channel_id >= TSPP_NUM_CHANNELS) {
 		pr_err("tspp: channel id out of range");
@@ -2220,9 +2251,13 @@
 		pr_err("tspp_get: can't find device %i", dev);
 		return NULL;
 	}
+
+	spin_lock_irqsave(&pdev->spinlock, flags);
+
 	channel = &pdev->channels[channel_id];
 
 	if (!channel->read) {
+		spin_unlock_irqrestore(&pdev->spinlock, flags);
 		pr_warn("tspp: no buffer to get on channel %i!",
 			channel->id);
 		return NULL;
@@ -2230,8 +2265,10 @@
 
 	buffer = channel->read;
 	/* see if we have any buffers ready to read */
-	if (buffer->state != TSPP_BUF_STATE_DATA)
-		return 0;
+	if (buffer->state != TSPP_BUF_STATE_DATA) {
+		spin_unlock_irqrestore(&pdev->spinlock, flags);
+		return NULL;
+	}
 
 	if (buffer->state == TSPP_BUF_STATE_DATA) {
 		/* mark the buffer as busy */
@@ -2241,6 +2278,8 @@
 		channel->read = channel->read->next;
 	}
 
+	spin_unlock_irqrestore(&pdev->spinlock, flags);
+
 	return &buffer->desc;
 }
 EXPORT_SYMBOL(tspp_get_buffer);
@@ -2261,6 +2300,7 @@
 	struct tspp_mem_buffer *buffer;
 	struct tspp_channel *channel;
 	struct tspp_device *pdev;
+	unsigned long flags;
 
 	if (channel_id >= TSPP_NUM_CHANNELS) {
 		pr_err("tspp: channel id out of range");
@@ -2271,6 +2311,9 @@
 		pr_err("tspp: can't find device %i", dev);
 		return -ENODEV;
 	}
+
+	spin_lock_irqsave(&pdev->spinlock, flags);
+
 	channel = &pdev->channels[channel_id];
 
 	if (descriptor_id > channel->buffer_count)
@@ -2288,12 +2331,14 @@
 	channel->locked = channel->locked->next;
 
 	if (!found) {
+		spin_unlock_irqrestore(&pdev->spinlock, flags);
 		pr_err("tspp: cant find desc %i", descriptor_id);
 		return -EINVAL;
 	}
 
 	/* make sure the buffer is in the expected state */
 	if (buffer->state != TSPP_BUF_STATE_LOCKED) {
+		spin_unlock_irqrestore(&pdev->spinlock, flags);
 		pr_err("tspp: buffer %i not locked", descriptor_id);
 		return -EINVAL;
 	}
@@ -2302,6 +2347,9 @@
 
 	if (tspp_queue_buffer(channel, buffer))
 		pr_warn("tspp: can't requeue buffer");
+
+	spin_unlock_irqrestore(&pdev->spinlock, flags);
+
 	return 0;
 }
 EXPORT_SYMBOL(tspp_release_buffer);
@@ -3103,6 +3151,7 @@
 
 	if (msm_tspp_map_irqs(pdev, device))
 		goto err_irq;
+	device->req_irqs = false;
 
 	/* power management */
 	pm_runtime_set_active(&pdev->dev);
@@ -3137,11 +3186,7 @@
 		goto err_clock;
 	}
 
-	if (sps_register_bam_device(&device->bam_props,
-		&device->bam_handle) != 0) {
-		pr_err("tspp: failed to register bam");
-		goto err_bam;
-	}
+	device->bam_handle = SPS_DEV_HANDLE_INVALID;
 
 	spin_lock_init(&device->spinlock);
 	tasklet_init(&device->tlet, tspp_sps_complete_tlet,
@@ -3184,7 +3229,6 @@
 
 	sps_deregister_bam_device(device->bam_handle);
 err_clock:
-err_bam:
 	tspp_debugfs_exit(device);
 	for (i = 0; i < TSPP_TSIF_INSTANCES; i++)
 		tsif_debugfs_exit(&device->tsif[i]);
@@ -3222,7 +3266,6 @@
 {
 	struct tspp_channel *channel;
 	u32 i;
-	int rc;
 
 	struct tspp_device *device = platform_get_drvdata(pdev);
 
@@ -3234,24 +3277,15 @@
 		cdev_del(&channel->cdev);
 	}
 
-	/* de-registering BAM device requires clocks */
-	rc = tspp_clock_start(device);
-	if (rc == 0) {
-		sps_deregister_bam_device(device->bam_handle);
-		tspp_clock_stop(device);
-	}
-
-	for (i = 0; i < TSPP_TSIF_INSTANCES; i++) {
+	for (i = 0; i < TSPP_TSIF_INSTANCES; i++)
 		tsif_debugfs_exit(&device->tsif[i]);
-		if (device->tsif[i].tsif_irq)
-			free_irq(device->tsif[i].tsif_irq,  &device->tsif[i]);
-	}
 
 	if (device->tsif_bus_client)
 		msm_bus_scale_unregister_client(device->tsif_bus_client);
 
 	wake_lock_destroy(&device->wake_lock);
-	free_irq(device->tspp_irq, device);
+	if (device->req_irqs)
+		msm_tspp_free_irqs(device);
 
 	iounmap(device->bam_props.virt_addr);
 	iounmap(device->base);
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 0c70746..97de664 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -30,6 +30,7 @@
 #include <linux/blkdev.h>
 #include <linux/mutex.h>
 #include <linux/scatterlist.h>
+#include <linux/bitops.h>
 #include <linux/string_helpers.h>
 #include <linux/delay.h>
 #include <linux/capability.h>
@@ -2469,7 +2470,7 @@
 		areq = mmc_start_req(card->host, areq, (int *) &status);
 		if (!areq) {
 			if (status == MMC_BLK_NEW_REQUEST)
-				mq->flags |= MMC_QUEUE_NEW_REQUEST;
+				set_bit(MMC_QUEUE_NEW_REQUEST, &mq->flags);
 			return 0;
 		}
 
@@ -2490,7 +2491,7 @@
 				mmc_blk_reinsert_req(areq);
 			}
 
-			mq->flags |= MMC_QUEUE_URGENT_REQUEST;
+			set_bit(MMC_QUEUE_URGENT_REQUEST, &mq->flags);
 			ret = 0;
 			break;
 		case MMC_BLK_URGENT_DONE:
@@ -2649,6 +2650,7 @@
 	struct mmc_card *card = md->queue.card;
 	struct mmc_host *host = card->host;
 	unsigned long flags;
+	unsigned int cmd_flags = req ? req->cmd_flags : 0;
 
 	if (req && !mq->mqrq_prev->req) {
 		mmc_rpm_hold(host, &card->dev);
@@ -2674,23 +2676,23 @@
 
 	mmc_blk_write_packing_control(mq, req);
 
-	mq->flags &= ~MMC_QUEUE_NEW_REQUEST;
-	mq->flags &= ~MMC_QUEUE_URGENT_REQUEST;
-	if (req && req->cmd_flags & REQ_SANITIZE) {
+	clear_bit(MMC_QUEUE_NEW_REQUEST, &mq->flags);
+	clear_bit(MMC_QUEUE_URGENT_REQUEST, &mq->flags);
+	if (cmd_flags & REQ_SANITIZE) {
 		/* complete ongoing async transfer before issuing sanitize */
 		if (card->host && card->host->areq)
 			mmc_blk_issue_rw_rq(mq, NULL);
 		ret = mmc_blk_issue_sanitize_rq(mq, req);
-	} else if (req && req->cmd_flags & REQ_DISCARD) {
+	} else if (cmd_flags & REQ_DISCARD) {
 		/* complete ongoing async transfer before issuing discard */
 		if (card->host->areq)
 			mmc_blk_issue_rw_rq(mq, NULL);
-		if (req->cmd_flags & REQ_SECURE &&
+		if (cmd_flags & REQ_SECURE &&
 			!(card->quirks & MMC_QUIRK_SEC_ERASE_TRIM_BROKEN))
 			ret = mmc_blk_issue_secdiscard_rq(mq, req);
 		else
 			ret = mmc_blk_issue_discard_rq(mq, req);
-	} else if (req && req->cmd_flags & REQ_FLUSH) {
+	} else if (cmd_flags & REQ_FLUSH) {
 		/* complete ongoing async transfer before issuing flush */
 		if (card->host->areq)
 			mmc_blk_issue_rw_rq(mq, NULL);
@@ -2711,10 +2713,9 @@
 	 * - urgent notification in progress and current request is not urgent
 	 *   (all existing requests completed or reinserted to the block layer)
 	 */
-	if ((!req && !(mq->flags & MMC_QUEUE_NEW_REQUEST)) ||
-			((mq->flags & MMC_QUEUE_URGENT_REQUEST) &&
-			 !(mq->mqrq_cur->req->cmd_flags &
-				MMC_REQ_NOREINSERT_MASK))) {
+	if ((!req && !(test_bit(MMC_QUEUE_NEW_REQUEST, &mq->flags))) ||
+			((test_bit(MMC_QUEUE_URGENT_REQUEST, &mq->flags)) &&
+			 !(cmd_flags & MMC_REQ_NOREINSERT_MASK))) {
 		if (mmc_card_need_bkops(card))
 			mmc_start_bkops(card, false);
 		/* release host only when there are no more requests */
diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c
index fa3dcdc..cceb8d9 100644
--- a/drivers/mmc/card/queue.c
+++ b/drivers/mmc/card/queue.c
@@ -15,6 +15,7 @@
 #include <linux/freezer.h>
 #include <linux/kthread.h>
 #include <linux/scatterlist.h>
+#include <linux/bitops.h>
 
 #include <linux/mmc/card.h>
 #include <linux/mmc/host.h>
@@ -75,12 +76,12 @@
 		if (req || mq->mqrq_prev->req) {
 			set_current_state(TASK_RUNNING);
 			mq->issue_fn(mq, req);
-			if (mq->flags & MMC_QUEUE_NEW_REQUEST) {
+			if (test_bit(MMC_QUEUE_NEW_REQUEST, &mq->flags)) {
 				continue; /* fetch again */
-			} else if ((mq->flags & MMC_QUEUE_URGENT_REQUEST) &&
-				   (mq->mqrq_cur->req &&
-				!(mq->mqrq_cur->req->cmd_flags &
-				       MMC_REQ_NOREINSERT_MASK))) {
+			} else if (test_bit(MMC_QUEUE_URGENT_REQUEST,
+					&mq->flags) && (mq->mqrq_cur->req &&
+					!(mq->mqrq_cur->req->cmd_flags &
+						MMC_REQ_NOREINSERT_MASK))) {
 				/*
 				 * clean current request when urgent request
 				 * processing in progress and current request is
@@ -474,9 +475,7 @@
 	unsigned long flags;
 	int rc = 0;
 
-	if (!(mq->flags & MMC_QUEUE_SUSPENDED)) {
-		mq->flags |= MMC_QUEUE_SUSPENDED;
-
+	if (!(test_and_set_bit(MMC_QUEUE_SUSPENDED, &mq->flags))) {
 		spin_lock_irqsave(q->queue_lock, flags);
 		blk_stop_queue(q);
 		spin_unlock_irqrestore(q->queue_lock, flags);
@@ -487,7 +486,7 @@
 			 * Failed to take the lock so better to abort the
 			 * suspend because mmcqd thread is processing requests.
 			 */
-			mq->flags &= ~MMC_QUEUE_SUSPENDED;
+			clear_bit(MMC_QUEUE_SUSPENDED, &mq->flags);
 			spin_lock_irqsave(q->queue_lock, flags);
 			blk_start_queue(q);
 			spin_unlock_irqrestore(q->queue_lock, flags);
@@ -509,8 +508,7 @@
 	struct request_queue *q = mq->queue;
 	unsigned long flags;
 
-	if (mq->flags & MMC_QUEUE_SUSPENDED) {
-		mq->flags &= ~MMC_QUEUE_SUSPENDED;
+	if (test_and_clear_bit(MMC_QUEUE_SUSPENDED, &mq->flags)) {
 
 		up(&mq->thread_sem);
 
diff --git a/drivers/mmc/card/queue.h b/drivers/mmc/card/queue.h
index d1fe01c..0ed7f36 100644
--- a/drivers/mmc/card/queue.h
+++ b/drivers/mmc/card/queue.h
@@ -38,10 +38,10 @@
 	struct mmc_card		*card;
 	struct task_struct	*thread;
 	struct semaphore	thread_sem;
-	unsigned int		flags;
-#define MMC_QUEUE_SUSPENDED		(1 << 0)
-#define MMC_QUEUE_NEW_REQUEST		(1 << 1)
-#define MMC_QUEUE_URGENT_REQUEST	(1 << 2)
+	unsigned long		flags;
+#define MMC_QUEUE_SUSPENDED		0
+#define MMC_QUEUE_NEW_REQUEST		1
+#define MMC_QUEUE_URGENT_REQUEST	2
 
 	int			(*issue_fn)(struct mmc_queue *, struct request *);
 	void			*data;
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 36bf643..da62cb0 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -3129,6 +3129,19 @@
 		return 1;
 
 	ret = host->bus_ops->alive(host);
+
+	/*
+	 * Card detect status and alive check may be out of sync if card is
+	 * removed slowly, when card detect switch changes while card/slot
+	 * pads are still contacted in hardware (refer to "SD Card Mechanical
+	 * Addendum, Appendix C: Card Detection Switch"). So reschedule a
+	 * detect work 200ms later for this case.
+	 */
+	if (!ret && host->ops->get_cd && !host->ops->get_cd(host)) {
+		mmc_detect_change(host, msecs_to_jiffies(200));
+		pr_debug("%s: card removed too slowly\n", mmc_hostname(host));
+	}
+
 	if (ret) {
 		mmc_card_set_removed(host->card);
 		pr_debug("%s: card remove detected\n", mmc_hostname(host));
@@ -3229,8 +3242,12 @@
 	 */
 	mmc_bus_put(host);
 
-	if (host->ops->get_cd && host->ops->get_cd(host) == 0)
+	if (host->ops->get_cd && host->ops->get_cd(host) == 0) {
+		mmc_claim_host(host);
+		mmc_power_off(host);
+		mmc_release_host(host);
 		goto out;
+	}
 
 	mmc_rpm_hold(host, &host->class_dev);
 	mmc_claim_host(host);
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 277aef5..ba07348 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -1567,6 +1567,7 @@
 					MMC_SEND_TUNING_BLOCK_HS200 :
 					MMC_SEND_TUNING_BLOCK;
 				host->mrq = NULL;
+				host->flags &= ~SDHCI_NEEDS_RETUNING;
 				spin_unlock_irqrestore(&host->lock, flags);
 				sdhci_execute_tuning(mmc, tuning_opcode);
 				spin_lock_irqsave(&host->lock, flags);
@@ -2561,6 +2562,7 @@
 static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask)
 {
 	u16 auto_cmd_status;
+	u32 command;
 	BUG_ON(intmask == 0);
 
 	if (!host->cmd) {
@@ -2592,8 +2594,13 @@
 	}
 
 	if (host->cmd->error) {
-		if (host->cmd->error == -EILSEQ)
-			host->flags |= SDHCI_NEEDS_RETUNING;
+		command = SDHCI_GET_CMD(sdhci_readw(host,
+						    SDHCI_COMMAND));
+		if (host->cmd->error == -EILSEQ &&
+		    (command != MMC_SEND_TUNING_BLOCK_HS400) &&
+		    (command != MMC_SEND_TUNING_BLOCK_HS200) &&
+		    (command != MMC_SEND_TUNING_BLOCK))
+				host->flags |= SDHCI_NEEDS_RETUNING;
 		tasklet_schedule(&host->finish_tasklet);
 		return;
 	}
diff --git a/drivers/net/ethernet/msm/msm_rmnet_bam.c b/drivers/net/ethernet/msm/msm_rmnet_bam.c
index 7ec317a..ff6a79c 100644
--- a/drivers/net/ethernet/msm/msm_rmnet_bam.c
+++ b/drivers/net/ethernet/msm/msm_rmnet_bam.c
@@ -118,7 +118,8 @@
 				    struct device_attribute *attr,
 				    char *buf)
 {
-	return sprintf(buf, "%lu\n", (unsigned long) timeout_suspend_us);
+	return snprintf(buf, PAGE_SIZE, "%lu\n",
+			(unsigned long) timeout_suspend_us);
 }
 
 static DEVICE_ATTR(timeout_suspend, 0664, timeout_suspend_show,
@@ -177,7 +178,7 @@
 				 char *buf)
 {
 	struct rmnet_private *p = netdev_priv(to_net_dev(d));
-	return sprintf(buf, "%lu\n", p->wakeups_xmit);
+	return snprintf(buf, PAGE_SIZE, "%lu\n", p->wakeups_xmit);
 }
 
 DEVICE_ATTR(wakeups_xmit, 0444, wakeups_xmit_show, NULL);
@@ -186,7 +187,7 @@
 				char *buf)
 {
 	struct rmnet_private *p = netdev_priv(to_net_dev(d));
-	return sprintf(buf, "%lu\n", p->wakeups_rcv);
+	return snprintf(buf, PAGE_SIZE, "%lu\n", p->wakeups_rcv);
 }
 
 DEVICE_ATTR(wakeups_rcv, 0444, wakeups_rcv_show, NULL);
@@ -210,7 +211,7 @@
 {
 	struct rmnet_private *p = netdev_priv(to_net_dev(d));
 	p = netdev_priv(to_net_dev(d));
-	return sprintf(buf, "%lu\n", timeout_us);
+	return snprintf(buf, PAGE_SIZE, "%lu\n", timeout_us);
 }
 
 DEVICE_ATTR(timeout, 0664, timeout_show, timeout_store);
diff --git a/drivers/platform/msm/Kconfig b/drivers/platform/msm/Kconfig
index 88e8d43..7c40677 100644
--- a/drivers/platform/msm/Kconfig
+++ b/drivers/platform/msm/Kconfig
@@ -115,11 +115,21 @@
 	  to configure IPA core.
 config MSM_AVTIMER
 	tristate "Avtimer Driver"
-	depends on ARCH_MSM8960
+	depends on MSM_QDSP6_APRV2
 	help
 		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/avtimer.c b/drivers/platform/msm/avtimer.c
index f513ceb..d5fa885 100644
--- a/drivers/platform/msm/avtimer.c
+++ b/drivers/platform/msm/avtimer.c
@@ -1,5 +1,4 @@
-
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-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
@@ -21,71 +20,102 @@
 #include <linux/io.h>
 #include <linux/platform_device.h>
 #include <linux/avtimer.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/wait.h>
+#include <linux/sched.h>
 #include <mach/qdsp6v2/apr.h>
 
 #define DEVICE_NAME "avtimer"
+#define TIMEOUT_MS 1000
+#define CORE_CLIENT 1
+#define TEMP_PORT ((CORE_CLIENT << 8) | 0x0001)
 
+#define AVCS_CMD_REMOTE_AVTIMER_VOTE_REQUEST 0x00012914
+#define AVCS_CMD_RSP_REMOTE_AVTIMER_VOTE_REQUEST 0x00012915
+#define AVCS_CMD_REMOTE_AVTIMER_RELEASE_REQUEST 0x00012916
+#define AVTIMER_REG_CNT 2
 
-#define ADSP_CMD_SET_POWER_COLLAPSE_STATE 0x0001115C
+struct adsp_avt_timer {
+	struct apr_hdr hdr;
+	union {
+		char client_name[8];
+		u32 avtimer_handle;
+	};
+} __packed;
 
-static int major;	/* Major number assigned to our device driver */
+static int major;
+
 struct avtimer_t {
+	struct apr_svc *core_handle_q;
 	struct cdev myc;
 	struct class *avtimer_class;
 	struct mutex avtimer_lock;
 	int avtimer_open_cnt;
-	struct dev_avtimer_data *avtimer_pdata;
+	struct dev_avtimer_data avtimer_pdata;
+	wait_queue_head_t adsp_resp_wait;
+	int enable_timer_resp_recieved;
+	int timer_handle;
+	void __iomem *p_avtimer_msw;
+	void __iomem *p_avtimer_lsw;
 };
+
 static struct avtimer_t avtimer;
 
-static struct apr_svc *core_handle;
-
-struct adsp_power_collapse {
-	struct apr_hdr hdr;
-	uint32_t power_collapse;
-};
-
-static int32_t avcs_core_callback(struct apr_client_data *data, void *priv)
+static int32_t aprv2_core_fn_q(struct apr_client_data *data, void *priv)
 {
-	uint32_t *payload;
+	uint32_t *payload1;
 
-	pr_debug("core msg: payload len = %u, apr resp opcode = 0x%X\n",
-		data->payload_size, data->opcode);
+	pr_debug("%s: core msg: payload len = %u, apr resp opcode = 0x%X\n",
+		__func__, data->payload_size, data->opcode);
+
+	if (!data) {
+		pr_err("%s: Invalid params\n", __func__);
+		return -EINVAL;
+	}
 
 	switch (data->opcode) {
 
 	case APR_BASIC_RSP_RESULT:{
 
-		if (data->payload_size == 0) {
+		if (!data->payload_size) {
 			pr_err("%s: APR_BASIC_RSP_RESULT No Payload ",
 					__func__);
 			return 0;
 		}
 
-		payload = data->payload;
-
-		switch (payload[0]) {
-
-		case ADSP_CMD_SET_POWER_COLLAPSE_STATE:
-			pr_debug("CMD_SET_POWER_COLLAPSE_STATE status[0x%x]\n",
-					payload[1]);
+		payload1 = data->payload;
+		switch (payload1[0]) {
+		case AVCS_CMD_REMOTE_AVTIMER_RELEASE_REQUEST:
+			pr_debug("%s: Cmd = TIMER RELEASE status[0x%x]\n",
+			__func__, payload1[1]);
 			break;
 		default:
 			pr_err("Invalid cmd rsp[0x%x][0x%x]\n",
-					payload[0], payload[1]);
+					payload1[0], payload1[1]);
 			break;
 		}
 		break;
 	}
+
 	case RESET_EVENTS:{
-		pr_debug("Reset event received in Core service");
-		apr_reset(core_handle);
-		core_handle = NULL;
+		pr_debug("%s: Reset event received in AV timer\n", __func__);
+		apr_reset(avtimer.core_handle_q);
+		avtimer.core_handle_q = NULL;
 		break;
 	}
 
+	case AVCS_CMD_RSP_REMOTE_AVTIMER_VOTE_REQUEST:
+		payload1 = data->payload;
+		pr_debug("%s: RSP_REMOTE_AVTIMER_VOTE_REQUEST handle %x\n",
+			__func__, payload1[0]);
+		avtimer.timer_handle = payload1[0];
+		avtimer.enable_timer_resp_recieved = 1;
+		wake_up(&avtimer.adsp_resp_wait);
+		break;
 	default:
-		pr_err("Message id from adsp core svc: %d\n", data->opcode);
+		pr_err("%s: Message adspcore svc: %d\n",
+				__func__, data->opcode);
 		break;
 	}
 
@@ -94,104 +124,147 @@
 
 int avcs_core_open(void)
 {
-	if (core_handle == NULL)
-		core_handle = apr_register("ADSP", "CORE",
-					avcs_core_callback, 0xFFFFFFFF, NULL);
-
-	pr_debug("Open_q %p\n", core_handle);
-	if (core_handle == NULL) {
+	if (!avtimer.core_handle_q)
+		avtimer.core_handle_q = apr_register("ADSP", "CORE",
+					aprv2_core_fn_q, TEMP_PORT, NULL);
+	pr_debug("%s: Open_q %p\n", __func__, avtimer.core_handle_q);
+	if (!avtimer.core_handle_q) {
 		pr_err("%s: Unable to register CORE\n", __func__);
-		return -ENODEV;
+		return -EINVAL;
 	}
 	return 0;
 }
+EXPORT_SYMBOL(avcs_core_open);
 
-int avcs_core_disable_power_collapse(int disable)
+static int avcs_core_disable_avtimer(int timerhandle)
 {
-	struct adsp_power_collapse pc;
-	int rc = 0;
+	int rc = -EINVAL;
+	struct adsp_avt_timer payload;
 
-	if (core_handle) {
-		pc.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_EVENT,
-			APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
-		pc.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
-					sizeof(uint32_t));
-		pc.hdr.src_port = 0;
-		pc.hdr.dest_port = 0;
-		pc.hdr.token = 0;
-		pc.hdr.opcode = ADSP_CMD_SET_POWER_COLLAPSE_STATE;
-		/*
-		* When power_collapse set to 1 -- If the aDSP is in the power
-		* collapsed state when this command is received, it is awakened
-		* from this state. The aDSP does not power collapse again until
-		* the client revokes this	command
-		* When power_collapse set to 0 -- This indicates to the aDSP
-		* that the remote client does not need it to be out of power
-		* collapse any longer. This may not always put the aDSP into
-		* power collapse; the aDSP must honor an internal client's
-		* power requirements as well.
-		*/
-		pc.power_collapse = disable;
-		rc = apr_send_pkt(core_handle, (uint32_t *)&pc);
-		if (rc < 0) {
-			pr_debug("disable power collapse = %d failed\n",
-				disable);
-			return rc;
-		}
-		pr_debug("disable power collapse = %d\n", disable);
+	if (!timerhandle) {
+		pr_err("%s: Invalid timer handle\n", __func__);
+		return -EINVAL;
 	}
-	return 0;
+	memset(&payload, 0, sizeof(payload));
+	rc = avcs_core_open();
+	if (!rc && avtimer.core_handle_q) {
+		payload.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+			APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+		payload.hdr.pkt_size =
+			sizeof(struct adsp_avt_timer);
+		payload.hdr.src_svc = avtimer.core_handle_q->id;
+		payload.hdr.src_domain = APR_DOMAIN_APPS;
+		payload.hdr.dest_domain = APR_DOMAIN_ADSP;
+		payload.hdr.dest_svc = APR_SVC_ADSP_CORE;
+		payload.hdr.src_port = TEMP_PORT;
+		payload.hdr.dest_port = TEMP_PORT;
+		payload.hdr.token = CORE_CLIENT;
+		payload.hdr.opcode = AVCS_CMD_REMOTE_AVTIMER_RELEASE_REQUEST;
+		payload.avtimer_handle = timerhandle;
+		pr_debug("%s: disable avtimer opcode %x handle %x\n",
+			__func__, payload.hdr.opcode, payload.avtimer_handle);
+		rc = apr_send_pkt(avtimer.core_handle_q,
+						(uint32_t *)&payload);
+		if (rc < 0)
+			pr_err("%s: Enable AVtimer failed op[0x%x]rc[%d]\n",
+				__func__, payload.hdr.opcode, rc);
+		else
+			rc = 0;
+	}
+	return rc;
 }
 
+static int avcs_core_enable_avtimer(char *client_name)
+{
+	int rc = -EINVAL, ret = -EINVAL;
+	struct adsp_avt_timer payload;
+
+	if (!client_name) {
+		pr_err("%s: Invalid params\n", __func__);
+		return -EINVAL;
+	}
+	memset(&payload, 0, sizeof(payload));
+	rc = avcs_core_open();
+	if (!rc && avtimer.core_handle_q) {
+		avtimer.enable_timer_resp_recieved = 0;
+		payload.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_EVENT,
+			APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+		payload.hdr.pkt_size =
+			sizeof(struct adsp_avt_timer);
+		payload.hdr.src_svc = avtimer.core_handle_q->id;
+		payload.hdr.src_domain = APR_DOMAIN_APPS;
+		payload.hdr.dest_domain = APR_DOMAIN_ADSP;
+		payload.hdr.dest_svc = APR_SVC_ADSP_CORE;
+		payload.hdr.src_port = TEMP_PORT;
+		payload.hdr.dest_port = TEMP_PORT;
+		payload.hdr.token = CORE_CLIENT;
+		payload.hdr.opcode = AVCS_CMD_REMOTE_AVTIMER_VOTE_REQUEST;
+		strlcpy(payload.client_name, client_name,
+			   sizeof(payload.client_name));
+		pr_debug("%s: enable avtimer opcode %x client name %s\n",
+			__func__, payload.hdr.opcode, payload.client_name);
+		rc = apr_send_pkt(avtimer.core_handle_q,
+						(uint32_t *)&payload);
+		if (rc < 0) {
+			pr_err("%s: Enable AVtimer failed op[0x%x]rc[%d]\n",
+				__func__, payload.hdr.opcode, rc);
+			goto bail;
+		} else
+			rc = 0;
+		ret = wait_event_timeout(avtimer.adsp_resp_wait,
+			(avtimer.enable_timer_resp_recieved == 1),
+			msecs_to_jiffies(TIMEOUT_MS));
+		if (!ret) {
+			pr_err("%s: wait_event timeout for Enable timer\n",
+					__func__);
+			rc = -ETIMEDOUT;
+		}
+		if (rc)
+			avtimer.timer_handle = 0;
+	}
+bail:
+	return rc;
+}
+
+int avcs_core_disable_power_collapse(int enable)
+{
+	int rc = 0;
+	mutex_lock(&avtimer.avtimer_lock);
+	if (enable) {
+		if (avtimer.avtimer_open_cnt) {
+			avtimer.avtimer_open_cnt++;
+			pr_debug("%s: opened avtimer open count=%d\n",
+				__func__, avtimer.avtimer_open_cnt);
+			rc = 0;
+			goto done;
+		}
+		rc = avcs_core_enable_avtimer("timer");
+		if (!rc)
+			avtimer.avtimer_open_cnt++;
+	} else {
+		if (avtimer.avtimer_open_cnt > 0) {
+			avtimer.avtimer_open_cnt--;
+			if (!avtimer.avtimer_open_cnt) {
+				rc = avcs_core_disable_avtimer(
+				avtimer.timer_handle);
+				avtimer.timer_handle = 0;
+			}
+		}
+	}
+done:
+	mutex_unlock(&avtimer.avtimer_lock);
+	return rc;
+}
+EXPORT_SYMBOL(avcs_core_disable_power_collapse);
+
 static int avtimer_open(struct inode *inode, struct file *file)
 {
-	int rc = 0;
-	struct avtimer_t *pavtimer = &avtimer;
-
-	pr_debug("avtimer_open\n");
-	mutex_lock(&pavtimer->avtimer_lock);
-
-	if (pavtimer->avtimer_open_cnt != 0) {
-		pavtimer->avtimer_open_cnt++;
-		pr_debug("%s: opened avtimer open count=%d\n",
-			__func__, pavtimer->avtimer_open_cnt);
-		mutex_unlock(&pavtimer->avtimer_lock);
-		return 0;
-	}
-	try_module_get(THIS_MODULE);
-
-	rc = avcs_core_open();
-	if (core_handle)
-		rc = avcs_core_disable_power_collapse(1);
-
-	pavtimer->avtimer_open_cnt++;
-	pr_debug("%s: opened avtimer open count=%d\n",
-		__func__, pavtimer->avtimer_open_cnt);
-	mutex_unlock(&pavtimer->avtimer_lock);
-	pr_debug("avtimer_open leave rc=%d\n", rc);
-
-	return rc;
+	return avcs_core_disable_power_collapse(1);
 }
 
 static int avtimer_release(struct inode *inode, struct file *file)
 {
-	int rc = 0;
-	struct avtimer_t *pavtimer = &avtimer;
-
-	mutex_lock(&pavtimer->avtimer_lock);
-	pavtimer->avtimer_open_cnt--;
-
-	if (core_handle && pavtimer->avtimer_open_cnt == 0)
-		rc = avcs_core_disable_power_collapse(0);
-
-	pr_debug("device_release(%p,%p) open count=%d\n",
-		inode, file, pavtimer->avtimer_open_cnt);
-
-	module_put(THIS_MODULE);
-
-	mutex_unlock(&pavtimer->avtimer_lock);
-
-	return rc;
+	return avcs_core_disable_power_collapse(0);
 }
 
 /*
@@ -200,56 +273,35 @@
 static long avtimer_ioctl(struct file *file, unsigned int ioctl_num,
 				unsigned long ioctl_param)
 {
-	struct avtimer_t *pavtimer = &avtimer;
-	pr_debug("avtimer_ioctl: ioctlnum=%d,param=%lx\n",
-				ioctl_num, ioctl_param);
-
 	switch (ioctl_num) {
 	case IOCTL_GET_AVTIMER_TICK:
 	{
-		void __iomem *p_avtimer_msw = NULL, *p_avtimer_lsw = NULL;
 		uint32_t avtimer_msw_1st = 0, avtimer_lsw = 0;
 		uint32_t avtimer_msw_2nd = 0;
 		uint64_t avtimer_tick;
-
-		if (pavtimer->avtimer_pdata) {
-			p_avtimer_lsw = ioremap(
-			pavtimer->avtimer_pdata->avtimer_lsw_phy_addr, 4);
-			p_avtimer_msw = ioremap(
-			pavtimer->avtimer_pdata->avtimer_msw_phy_addr, 4);
-		}
-		if (!p_avtimer_lsw || !p_avtimer_msw) {
-			pr_err("ioremap failed\n");
-			return -EIO;
-		}
 		do {
-			avtimer_msw_1st = ioread32(p_avtimer_msw);
-			avtimer_lsw = ioread32(p_avtimer_lsw);
-			avtimer_msw_2nd = ioread32(p_avtimer_msw);
+			avtimer_msw_1st = ioread32(avtimer.p_avtimer_msw);
+			avtimer_lsw = ioread32(avtimer.p_avtimer_lsw);
+			avtimer_msw_2nd = ioread32(avtimer.p_avtimer_msw);
 		} while (avtimer_msw_1st != avtimer_msw_2nd);
 
 		avtimer_tick =
 		((uint64_t) avtimer_msw_1st << 32) | avtimer_lsw;
 
-		pr_debug("AV Timer tick: msw: %d, lsw: %d\n", avtimer_msw_1st,
-				avtimer_lsw);
+		pr_debug("%s: AV Timer tick: msw: %x, lsw: %x time %llx\n",
+		__func__, avtimer_msw_1st, avtimer_lsw, avtimer_tick);
 		if (copy_to_user((void *) ioctl_param, &avtimer_tick,
 				sizeof(avtimer_tick))) {
 					pr_err("copy_to_user failed\n");
-					iounmap(p_avtimer_lsw);
-					iounmap(p_avtimer_msw);
 					return -EFAULT;
 			}
-		iounmap(p_avtimer_lsw);
-		iounmap(p_avtimer_msw);
 		}
 		break;
 
 	default:
-		pr_err("invalid cmd\n");
-		break;
+		pr_err("%s: invalid cmd\n", __func__);
+		return -EINVAL;
 	}
-
 	return 0;
 }
 
@@ -261,11 +313,44 @@
 
 static int dev_avtimer_probe(struct platform_device *pdev)
 {
-	int result;
+	int result = 0;
 	dev_t dev = MKDEV(major, 0);
 	struct device *device_handle;
-	struct avtimer_t *pavtimer = &avtimer;
+	struct resource *reg_lsb = NULL, *reg_msb = NULL;
 
+	if (!pdev) {
+		pr_err("%s: Invalid params\n", __func__);
+		return -EINVAL;
+	}
+	reg_lsb = platform_get_resource_byname(pdev,
+		IORESOURCE_MEM, "avtimer_lsb_addr");
+	if (!reg_lsb) {
+		dev_err(&pdev->dev, "%s: Looking up %s property",
+			"avtimer_lsb_addr", __func__);
+		return -EINVAL;
+	}
+	reg_msb = platform_get_resource_byname(pdev,
+		IORESOURCE_MEM, "avtimer_msb_addr");
+	if (!reg_msb) {
+		dev_err(&pdev->dev, "%s: Looking up %s property",
+			"avtimer_msb_addr", __func__);
+		return -EINVAL;
+	}
+	avtimer.p_avtimer_lsw = devm_ioremap_nocache(&pdev->dev,
+				reg_lsb->start, resource_size(reg_lsb));
+	if (!avtimer.p_avtimer_lsw) {
+		dev_err(&pdev->dev, "%s: ioremap failed for lsb avtimer register",
+			__func__);
+		return -ENOMEM;
+	}
+
+	avtimer.p_avtimer_msw = devm_ioremap_nocache(&pdev->dev,
+				reg_msb->start, resource_size(reg_msb));
+	if (!avtimer.p_avtimer_msw) {
+		dev_err(&pdev->dev, "%s: ioremap failed for msb avtimer register",
+			__func__);
+		goto unmap;
+	}
 	/* get the device number */
 	if (major)
 		result = register_chrdev_region(dev, 1, DEVICE_NAME);
@@ -275,68 +360,84 @@
 	}
 
 	if (result < 0) {
-		pr_err("Registering avtimer device failed\n");
-		return result;
+		pr_err("%s: Registering avtimer device failed\n", __func__);
+		goto unmap;
 	}
 
-	pavtimer->avtimer_class = class_create(THIS_MODULE, "avtimer");
-	if (IS_ERR(pavtimer->avtimer_class)) {
-		result = PTR_ERR(pavtimer->avtimer_class);
-		pr_err("Error creating avtimer class: %d\n", result);
+	avtimer.avtimer_class = class_create(THIS_MODULE, "avtimer");
+	if (IS_ERR(avtimer.avtimer_class)) {
+		result = PTR_ERR(avtimer.avtimer_class);
+		pr_err("%s: Error creating avtimer class: %d\n",
+			__func__, result);
 		goto unregister_chrdev_region;
 	}
-	pavtimer->avtimer_pdata = pdev->dev.platform_data;
 
-	cdev_init(&pavtimer->myc, &avtimer_fops);
-	result = cdev_add(&pavtimer->myc, dev, 1);
+	cdev_init(&avtimer.myc, &avtimer_fops);
+	result = cdev_add(&avtimer.myc, dev, 1);
 
 	if (result < 0) {
-		pr_err("Registering file operations failed\n");
+		pr_err("%s: Registering file operations failed\n", __func__);
 		goto class_destroy;
 	}
 
-	device_handle = device_create(pavtimer->avtimer_class,
-			NULL, pavtimer->myc.dev, NULL, "avtimer");
+	device_handle = device_create(avtimer.avtimer_class,
+			NULL, avtimer.myc.dev, NULL, "avtimer");
 	if (IS_ERR(device_handle)) {
 		result = PTR_ERR(device_handle);
-		pr_err("device_create failed: %d\n", result);
+		pr_err("%s: device_create failed: %d\n", __func__, result);
 		goto class_destroy;
 	}
+	init_waitqueue_head(&avtimer.adsp_resp_wait);
+	mutex_init(&avtimer.avtimer_lock);
+	avtimer.avtimer_open_cnt = 0;
 
-	mutex_init(&pavtimer->avtimer_lock);
-	core_handle = NULL;
-	pavtimer->avtimer_open_cnt = 0;
-
-	pr_debug("Device create done for avtimer major=%d\n", major);
+	pr_debug("%s: Device create done for avtimer major=%d\n",
+			__func__, major);
 
 	return 0;
 
 class_destroy:
-	class_destroy(pavtimer->avtimer_class);
+	class_destroy(avtimer.avtimer_class);
 unregister_chrdev_region:
 	unregister_chrdev_region(MKDEV(major, 0), 1);
+unmap:
+	if (avtimer.p_avtimer_lsw)
+		devm_iounmap(&pdev->dev, avtimer.p_avtimer_lsw);
+	if (avtimer.p_avtimer_msw)
+		devm_iounmap(&pdev->dev, avtimer.p_avtimer_msw);
+	avtimer.p_avtimer_lsw = NULL;
+	avtimer.p_avtimer_msw = NULL;
 	return result;
 
 }
 
 static int __devexit dev_avtimer_remove(struct platform_device *pdev)
 {
-	struct avtimer_t *pavtimer = &avtimer;
+	pr_debug("%s: dev_avtimer_remove\n", __func__);
 
-	pr_debug("dev_avtimer_remove\n");
-
-	device_destroy(pavtimer->avtimer_class, pavtimer->myc.dev);
-	cdev_del(&pavtimer->myc);
-	class_destroy(pavtimer->avtimer_class);
+	if (avtimer.p_avtimer_lsw)
+		devm_iounmap(&pdev->dev, avtimer.p_avtimer_lsw);
+	if (avtimer.p_avtimer_msw)
+		devm_iounmap(&pdev->dev, avtimer.p_avtimer_msw);
+	device_destroy(avtimer.avtimer_class, avtimer.myc.dev);
+	cdev_del(&avtimer.myc);
+	class_destroy(avtimer.avtimer_class);
 	unregister_chrdev_region(MKDEV(major, 0), 1);
 
 	return 0;
 }
 
+static const struct of_device_id avtimer_machine_of_match[]  = {
+	{ .compatible = "qcom,avtimer", },
+	{},
+};
 static struct platform_driver dev_avtimer_driver = {
 	.probe = dev_avtimer_probe,
-	.remove = __exit_p(dev_avtimer_remove),
-	.driver = {.name = "dev_avtimer"}
+	.remove = dev_avtimer_remove,
+	.driver = {
+		.name = "dev_avtimer",
+		.of_match_table = avtimer_machine_of_match,
+	},
 };
 
 static int  __init avtimer_init(void)
@@ -344,21 +445,21 @@
 	s32 rc;
 	rc = platform_driver_register(&dev_avtimer_driver);
 	if (IS_ERR_VALUE(rc)) {
-		pr_err("platform_driver_register failed.\n");
+		pr_err("%s: platform_driver_register failed\n", __func__);
 		goto error_platform_driver;
 	}
-	pr_debug("dev_avtimer_init : done\n");
+	pr_debug("%s: dev_avtimer_init : done\n", __func__);
 
 	return 0;
 error_platform_driver:
 
-	pr_err("encounterd error\n");
-	return -ENODEV;
+	pr_err("%s: encounterd error\n", __func__);
+	return rc;
 }
 
 static void __exit avtimer_exit(void)
 {
-	pr_debug("avtimer_exit\n");
+	pr_debug("%s: avtimer_exit\n", __func__);
 	platform_driver_unregister(&dev_avtimer_driver);
 }
 
diff --git a/drivers/platform/msm/pft.c b/drivers/platform/msm/pft.c
new file mode 100644
index 0000000..513aefb
--- /dev/null
+++ b/drivers/platform/msm/pft.c
@@ -0,0 +1,1773 @@
+/*
+ * 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;
+
+static struct inode *pft_bio_get_inode(struct bio *bio);
+
+/**
+ * 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;
+	struct list_head *next = NULL;
+	bool found = false;
+
+	mutex_lock(&pft_dev->lock);
+	list_for_each_safe(pos, next, &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;
+
+	if (isec == NULL)
+		return false;
+
+	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_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 bio *bio, u32 *key_index,
+		      bool *is_encrypted, bool *is_inplace)
+{
+	u32 tag = 0;
+	struct inode *inode = NULL;
+
+	if (!pft_is_ready())
+		return -ENODEV;
+
+	if (!selinux_is_enabled())
+		return -ENODEV;
+
+	if (!bio)
+		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;
+	}
+
+	inode = pft_bio_get_inode(bio);
+	if (!inode)
+		return -EINVAL;
+
+	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)
+		return NULL;
+	if (!bio->bi_io_vec)
+		return NULL;
+	if (!bio->bi_io_vec->bv_page)
+		return NULL;
+
+	if (PageAnon(bio->bi_io_vec->bv_page)) {
+		struct inode *inode;
+
+		/* Using direct-io (O_DIRECT) without page cache */
+		inode = dio_bio_get_inode(bio);
+		pr_debug("inode on direct-io, inode = 0x%x.\n", (int) inode);
+
+		return inode;
+	}
+
+	if (!bio->bi_io_vec->bv_page->mapping)
+		return NULL;
+
+	if (!bio->bi_io_vec->bv_page->mapping->host)
+		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(bio1, &key_index1,
+				&is_encrypted1, &is_inplace);
+	if (ret)
+		is_encrypted1 = false;
+
+	ret = pft_get_key_index(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_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)
+{
+	int ret;
+
+	if (!filp || !filp->f_path.dentry)
+		return 0;
+
+	if (!pft_is_ready())
+		return 0;
+
+	if (filp->f_flags & O_DIRECT)
+		pr_debug("file %s using O_DIRECT.\n", file_to_filename(filp));
+
+	/* 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;
+		}
+
+		ret = pft_add_file(filp);
+		if (ret) {
+			pr_err("failed to add file %s to the list.\n",
+			       file_to_filename(filp));
+			return -EFAULT;
+		}
+		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 -EBUSY;
+	}
+
+	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)
+{
+	int 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 (pft_dev->open_count > 0)
+		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_free_open_files_list(void)
+{
+	struct pft_file_info *tmp = NULL;
+	struct list_head *pos = NULL;
+	struct list_head *next = NULL;
+
+	mutex_lock(&pft_dev->lock);
+	list_for_each_safe(pos, next, &pft_dev->open_file_list) {
+		tmp = list_entry(pos, struct pft_file_info, list);
+		list_del(&tmp->list);
+		kfree(tmp);
+	}
+	mutex_unlock(&pft_dev->lock);
+}
+
+static void __exit pft_exit(void)
+{
+	if (pft_dev == NULL)
+		return;
+
+	pft_unregister_chrdev();
+	pft_free_open_files_list();
+
+	kfree(pft_dev->uid_table);
+	kfree(pft_dev);
+	pft_dev = NULL;
+}
+
+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;
+	}
+	pft_dev = dev;
+
+	dev->state = PFT_STATE_DEACTIVATED;
+	dev->pfm_pid = UINT_MAX;
+
+	INIT_LIST_HEAD(&dev->open_file_list);
+	mutex_init(&dev->lock);
+
+	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);
+	pft_dev = NULL;
+
+	return -ENODEV;
+}
+
+module_init(pft_init);
+module_exit(pft_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Per-File-Tagger driver");
diff --git a/drivers/power/qpnp-charger.c b/drivers/power/qpnp-charger.c
index d5c753f..94d48e6 100644
--- a/drivers/power/qpnp-charger.c
+++ b/drivers/power/qpnp-charger.c
@@ -32,6 +32,9 @@
 #include <linux/qpnp-revid.h>
 #include <linux/android_alarm.h>
 #include <linux/spinlock.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <linux/qpnp/pin.h>
 
 /* Interrupt offsets */
 #define INT_RT_STS(base)			(base + 0x10)
@@ -95,6 +98,8 @@
 #define CHGR_BUCK_PSTG_CTRL			0x73
 #define CHGR_BUCK_COMPARATOR_OVRIDE_1		0xEB
 #define CHGR_BUCK_COMPARATOR_OVRIDE_3		0xED
+#define CHG_OVR0				0xED
+#define CHG_TRICKLE_CLAMP			0xE3
 #define CHGR_BUCK_BCK_VBAT_REG_MODE		0x74
 #define MISC_REVISION2				0x01
 #define USB_OVP_CTL				0x42
@@ -388,6 +393,9 @@
 	struct work_struct		reduce_power_stage_work;
 	bool				power_stage_workaround_running;
 	bool				power_stage_workaround_enable;
+	bool				ext_ovp_ic_gpio_enabled;
+	unsigned int			ext_ovp_isns_gpio;
+	unsigned int			usb_trim_default;
 };
 
 static void
@@ -430,6 +438,81 @@
 	USBIN_OVP,
 };
 
+static int ext_ovp_isns_present;
+module_param(ext_ovp_isns_present, int, 0444);
+static int ext_ovp_isns_r;
+module_param(ext_ovp_isns_r, int, 0444);
+
+static bool ext_ovp_isns_online;
+static long ext_ovp_isns_ua;
+#define MAX_CURRENT_LENGTH_9A	10
+#define ISNS_CURRENT_RATIO	2500
+static int ext_ovp_isns_read(char *buffer, const struct kernel_param *kp)
+{
+	int rc;
+	struct qpnp_vadc_result results;
+	struct power_supply *batt_psy = power_supply_get_by_name("battery");
+	struct qpnp_chg_chip *chip = container_of(batt_psy,
+				struct qpnp_chg_chip, batt_psy);
+
+	if (!ext_ovp_isns_present)
+		return 0;
+
+	rc = qpnp_vadc_read(chip->vadc_dev, P_MUX7_1_1, &results);
+	if (rc) {
+		pr_err("Unable to read vbat rc=%d\n", rc);
+		return 0;
+	}
+
+	pr_debug("voltage %lld uV, current: %d\n mA", results.physical,
+			((int) results.physical /
+			 (ext_ovp_isns_r / ISNS_CURRENT_RATIO)));
+
+	return snprintf(buffer, MAX_CURRENT_LENGTH_9A, "%d\n",
+			((int)results.physical /
+			 (ext_ovp_isns_r / ISNS_CURRENT_RATIO)));
+}
+
+static int ext_ovp_isns_enable(const char *val, const struct kernel_param *kp)
+{
+	int rc;
+	struct power_supply *batt_psy = power_supply_get_by_name("battery");
+	struct qpnp_chg_chip *chip = container_of(batt_psy,
+				struct qpnp_chg_chip, batt_psy);
+
+	rc = param_set_bool(val, kp);
+	if (rc) {
+		pr_err("Unable to set gpio en: %d\n", rc);
+		return rc;
+	}
+
+	if (*(bool *)kp->arg) {
+		gpio_direction_output(
+						chip->ext_ovp_isns_gpio, 1);
+		chip->ext_ovp_ic_gpio_enabled = 1;
+		pr_debug("enabled GPIO\n");
+	} else {
+		gpio_direction_output(
+						chip->ext_ovp_isns_gpio, 0);
+		chip->ext_ovp_ic_gpio_enabled = 0;
+		pr_debug("disabled GPIO\n");
+	}
+
+	return rc;
+}
+
+static struct kernel_param_ops ext_ovp_isns_ops = {
+	.get = ext_ovp_isns_read,
+};
+module_param_cb(ext_ovp_isns_ua, &ext_ovp_isns_ops, &ext_ovp_isns_ua, 0644);
+
+static struct kernel_param_ops ext_ovp_en_ops = {
+	.set = ext_ovp_isns_enable,
+	.get = param_get_bool,
+};
+module_param_cb(ext_ovp_isns_online, &ext_ovp_en_ops,
+		&ext_ovp_isns_online, 0664);
+
 static inline int
 get_bpd(const char *name)
 {
@@ -886,6 +969,7 @@
 	return rc;
 }
 
+#define IOVP_USB_WALL_TRSH_MA   150
 static int
 qpnp_chg_iusbmax_set(struct qpnp_chg_chip *chip, int mA)
 {
@@ -1319,7 +1403,13 @@
 	if ((qpnp_chg_is_usb_chg_plugged_in(chip)
 			|| qpnp_chg_is_dc_chg_plugged_in(chip))
 			&& (usb_sts & CHG_GONE_IRQ)) {
+		if (ext_ovp_isns_present) {
+			pr_debug("EXT OVP IC ISNS disabled due to ARB WA\n");
+			gpio_direction_output(chip->ext_ovp_isns_gpio, 0);
+		}
+
 		qpnp_chg_charge_en(chip, 0);
+
 		qpnp_chg_force_run_on_batt(chip, 1);
 		schedule_delayed_work(&chip->arb_stop_work,
 			msecs_to_jiffies(ARB_STOP_WORK_MS));
@@ -1652,6 +1742,7 @@
 
 			qpnp_chg_usb_suspend_enable(chip, 0);
 			qpnp_chg_iusbmax_set(chip, QPNP_CHG_I_MAX_MIN_100);
+			qpnp_chg_iusb_trim_set(chip, chip->usb_trim_default);
 			chip->prev_usb_max_ma = -EINVAL;
 			chip->aicl_settled = false;
 		} else {
@@ -1814,7 +1905,8 @@
 		chip->dc_present = dc_present;
 		if (qpnp_chg_is_otg_en_set(chip))
 			qpnp_chg_force_run_on_batt(chip, !dc_present ? 1 : 0);
-		if (!dc_present && !qpnp_chg_is_usb_chg_plugged_in(chip)) {
+		if (!dc_present && (!qpnp_chg_is_usb_chg_plugged_in(chip) ||
+					qpnp_chg_is_otg_en_set(chip))) {
 			chip->delta_vddmax_mv = 0;
 			qpnp_chg_set_appropriate_vddmax(chip);
 			chip->chg_done = false;
@@ -1983,6 +2075,13 @@
 			}
 			if (chip->parallel_ovp_mode)
 				switch_parallel_ovp_mode(chip, 1);
+
+			if (ext_ovp_isns_present &&
+					chip->ext_ovp_ic_gpio_enabled) {
+				pr_debug("EXT OVP IC ISNS enabled\n");
+				gpio_direction_output(
+						chip->ext_ovp_isns_gpio, 1);
+			}
 		} else {
 			if (chip->parallel_ovp_mode)
 				switch_parallel_ovp_mode(chip, 0);
@@ -2211,7 +2310,7 @@
 static int ext_ovp_present;
 module_param(ext_ovp_present, int, 0444);
 
-#define OVP_USB_WALL_TRSH_MA	200
+#define OVP_USB_WALL_TRSH_MA   200
 static int
 qpnp_power_get_property_mains(struct power_supply *psy,
 				  enum power_supply_property psp,
@@ -2594,12 +2693,18 @@
 					if (!qpnp_is_dc_higher_prio(chip))
 						qpnp_chg_idcmax_set(chip,
 							QPNP_CHG_I_MAX_MIN_100);
-					if (!ext_ovp_present)
-						qpnp_chg_iusbmax_set(chip,
-							USB_WALL_THRESHOLD_MA);
-					else
+					if (unlikely(ext_ovp_present)) {
 						qpnp_chg_iusbmax_set(chip,
 							OVP_USB_WALL_TRSH_MA);
+					} else if (unlikely(
+							ext_ovp_isns_present)) {
+						qpnp_chg_iusb_trim_set(chip, 0);
+						qpnp_chg_iusbmax_set(chip,
+							IOVP_USB_WALL_TRSH_MA);
+					} else {
+						qpnp_chg_iusbmax_set(chip,
+							USB_WALL_THRESHOLD_MA);
+					}
 			} else {
 				qpnp_chg_iusbmax_set(chip, ret.intval / 1000);
 			}
@@ -3141,6 +3246,12 @@
 
 	if (qpnp_chg_is_usb_chg_plugged_in(chip) &&
 			(chip->flags & BOOST_FLASH_WA)) {
+
+		if (ext_ovp_isns_present && chip->ext_ovp_ic_gpio_enabled) {
+			pr_debug("EXT OVP IC ISNS disabled\n");
+			gpio_direction_output(chip->ext_ovp_isns_gpio, 0);
+		}
+
 		qpnp_chg_usb_suspend_enable(chip, 1);
 
 		rc = qpnp_chg_masked_write(chip,
@@ -3258,6 +3369,11 @@
 		qpnp_chg_usb_suspend_enable(chip, 0);
 	}
 
+	if (ext_ovp_isns_present && chip->ext_ovp_ic_gpio_enabled) {
+		pr_debug("EXT OVP IC ISNS enable\n");
+		gpio_direction_output(chip->ext_ovp_isns_gpio, 1);
+	}
+
 	return rc;
 }
 
@@ -4470,6 +4586,25 @@
 			CHGR_IBAT_TERM_CHGR,
 			0xFF, 0x08, 1);
 
+		/* HACK: trkl stuck workaround */
+
+		rc = qpnp_chg_masked_write(chip,
+			chip->chgr_base + SEC_ACCESS,
+			0xFF,
+			0xA5, 1);
+
+		rc = qpnp_chg_masked_write(chip, chip->chgr_base +
+			CHG_OVR0,
+			0xFF, 0x00, 1);
+
+		rc = qpnp_chg_masked_write(chip,
+			chip->chgr_base + SEC_ACCESS,
+			0xFF,
+			0xA5, 1);
+
+		rc = qpnp_chg_masked_write(chip, chip->chgr_base +
+			CHG_TRICKLE_CLAMP,
+			0xFF, 0x00, 1);
 		break;
 	case SMBB_BUCK_SUBTYPE:
 	case SMBBP_BUCK_SUBTYPE:
@@ -4797,6 +4932,17 @@
 	ext_ovp_present = of_property_read_bool(chip->spmi->dev.of_node,
 					"qcom,ext-ovp-present");
 
+	/* Check if external IOVP part is configured */
+	chip->ext_ovp_isns_gpio = of_get_named_gpio(chip->spmi->dev.of_node,
+					"qcom,ext-ovp-isns-enable-gpio", 0);
+	if (gpio_is_valid(chip->ext_ovp_isns_gpio)) {
+		ext_ovp_isns_present = true;
+		rc = of_property_read_u32(chip->spmi->dev.of_node,
+				"qcom,ext-ovp-isns-r-ohm", &ext_ovp_isns_r);
+		if (rc)
+			return rc;
+	}
+
 	/* Get the charging-disabled property */
 	chip->charging_disabled = of_property_read_bool(chip->spmi->dev.of_node,
 					"qcom,charging-disabled");
@@ -4902,6 +5048,9 @@
 	if (rc)
 		return rc;
 
+	if (ext_ovp_isns_present)
+		chip->ext_ovp_ic_gpio_enabled = 0;
+
 	/*
 	 * Check if bat_if is set in DT and make sure VADC is present
 	 * Also try loading the battery data profile if bat_if exists
@@ -5183,6 +5332,7 @@
 		goto unregister_dc_psy;
 	}
 
+	chip->usb_trim_default = qpnp_chg_iusb_trim_get(chip);
 	qpnp_chg_charge_en(chip, !chip->charging_disabled);
 	qpnp_chg_force_run_on_batt(chip, chip->charging_disabled);
 	qpnp_chg_set_appropriate_vddmax(chip);
diff --git a/drivers/spi/spi_qsd.c b/drivers/spi/spi_qsd.c
index d8dc6f9..5686107 100644
--- a/drivers/spi/spi_qsd.c
+++ b/drivers/spi/spi_qsd.c
@@ -854,19 +854,6 @@
 	dd->bam.curr_rx_bytes_recvd += data_xfr_size;
 	*bytes_to_send -= data_xfr_size;
 	dd->bam.bam_rx_len -= data_xfr_size;
-
-	if (!(dd->cur_rx_transfer->len - dd->bam.curr_rx_bytes_recvd)) {
-		struct spi_transfer *t = dd->cur_rx_transfer;
-		struct spi_transfer *next;
-		if (t->transfer_list.next != &dd->cur_msg->transfers) {
-			next = list_entry(t->transfer_list.next,
-					struct spi_transfer,
-					transfer_list);
-			dd->read_buf  = next->rx_buf;
-			dd->cur_rx_transfer = next;
-			dd->bam.curr_rx_bytes_recvd = 0;
-		}
-	}
 	return data_xfr_size;
 }
 
@@ -904,19 +891,6 @@
 	dd->bam.curr_tx_bytes_sent	+= data_xfr_size;
 	*bytes_to_send	-= data_xfr_size;
 	dd->bam.bam_tx_len -= data_xfr_size;
-
-	if (!(dd->cur_tx_transfer->len - dd->bam.curr_tx_bytes_sent)) {
-		struct spi_transfer *t = dd->cur_tx_transfer;
-		struct spi_transfer *next;
-		if (t->transfer_list.next != &dd->cur_msg->transfers) {
-			next = list_entry(t->transfer_list.next,
-					struct spi_transfer,
-					transfer_list);
-			dd->write_buf = next->tx_buf;
-			dd->cur_tx_transfer = next;
-			dd->bam.curr_tx_bytes_sent = 0;
-		}
-	}
 	return data_xfr_size;
 }
 
@@ -939,7 +913,6 @@
 	u32 cons_desc_cnt = SPI_BAM_MAX_DESC_NUM - 1;
 	u32 byte_count = 0;
 
-
 	rx_bytes_to_recv = min_t(u32, dd->bam.bam_rx_len,
 				SPI_MAX_TRFR_BTWN_RESETS);
 	tx_bytes_to_send = min_t(u32, dd->bam.bam_tx_len,
@@ -958,11 +931,17 @@
 
 	while ((rx_bytes_to_recv + tx_bytes_to_send) &&
 		((cons_desc_cnt + prod_desc_cnt) > 0)) {
+		struct spi_transfer *t = NULL, *next;
+
 		if (dd->read_buf && (prod_desc_cnt > 0)) {
 			ret = msm_spi_bam_process_rx(dd, &rx_bytes_to_recv,
 							prod_desc_cnt);
 			if (ret < 0)
 				goto xfr_err;
+
+			if (!(dd->cur_rx_transfer->len
+				- dd->bam.curr_rx_bytes_recvd))
+				t = dd->cur_rx_transfer;
 			prod_desc_cnt--;
 		}
 
@@ -971,8 +950,25 @@
 							cons_desc_cnt);
 			if (ret < 0)
 				goto xfr_err;
+
+			if (!(dd->cur_tx_transfer->len
+				- dd->bam.curr_tx_bytes_sent))
+				t = dd->cur_tx_transfer;
 			cons_desc_cnt--;
 		}
+
+		if (t && (t->transfer_list.next != &dd->cur_msg->transfers)) {
+			next = list_entry(t->transfer_list.next,
+					struct spi_transfer,
+					transfer_list);
+			dd->read_buf  = next->rx_buf;
+			dd->write_buf = next->tx_buf;
+			dd->cur_rx_transfer = next;
+			dd->cur_tx_transfer = next;
+			dd->bam.curr_rx_bytes_recvd = 0;
+			dd->bam.curr_tx_bytes_sent = 0;
+		}
+
 		byte_count += ret;
 	}
 
@@ -1918,9 +1914,12 @@
 			goto transfer_end;
 		msm_spi_start_write(dd, read_count);
 	} else if (dd->mode == SPI_BAM_MODE) {
-		if ((msm_spi_bam_begin_transfer(dd)) < 0)
+		if ((msm_spi_bam_begin_transfer(dd)) < 0) {
 			dev_err(dd->dev, "%s: BAM transfer setup failed\n",
 				__func__);
+			dd->cur_msg->status = -EIO;
+			goto transfer_end;
+		}
 	}
 
 	/*
@@ -1960,6 +1959,8 @@
 	msm_spi_udelay(dd->xfrs_delay_usec);
 
 transfer_end:
+	if (dd->mode == SPI_BAM_MODE)
+		msm_spi_bam_flush(dd);
 	msm_spi_dma_unmap_buffers(dd);
 	dd->mode = SPI_MODE_NONE;
 
diff --git a/drivers/spmi/spmi-pmic-arb.c b/drivers/spmi/spmi-pmic-arb.c
index e3284d5..81640a0 100644
--- a/drivers/spmi/spmi-pmic-arb.c
+++ b/drivers/spmi/spmi-pmic-arb.c
@@ -33,7 +33,9 @@
 /* PMIC Arbiter configuration registers */
 #define PMIC_ARB_VERSION		0x0000
 #define PMIC_ARB_INT_EN			0x0004
-
+#define PMIC_ARB_PROTOCOL_IRQ_STATUS	(0x700 + 0x820)
+#define PMIC_ARB_GENI_CTRL		0x0024
+#define PMIC_ARB_GENI_STATUS	0x0028
 /* PMIC Arbiter channel registers */
 #define PMIC_ARB_CMD(N)			(0x0800 + (0x80 * (N)))
 #define PMIC_ARB_CONFIG(N)		(0x0804 + (0x80 * (N)))
@@ -125,6 +127,7 @@
 	u8			max_apid;
 	u16			periph_id_map[PMIC_ARB_MAX_PERIPHS];
 	u32			mapping_table[SPMI_MAPPING_TABLE_LEN];
+	u32			prev_prtcl_irq_stat;
 };
 
 static struct spmi_pmic_arb_dev *the_pmic_arb;
@@ -143,6 +146,37 @@
 	writel_relaxed(val, dev->base + offset);
 }
 
+static void pmic_arb_save_stat_before_txn(struct spmi_pmic_arb_dev *dev)
+{
+	dev->prev_prtcl_irq_stat =
+		readl_relaxed(dev->cnfg + PMIC_ARB_PROTOCOL_IRQ_STATUS);
+}
+
+static int pmic_arb_diagnosis(struct spmi_pmic_arb_dev *dev, u32 status)
+{
+	if (status & PMIC_ARB_STATUS_DENIED) {
+		dev_err(dev->dev,
+		    "wait_for_done: transaction denied by SPMI master (0x%x)\n",
+		    status);
+		return -EPERM;
+	}
+
+	if (status & PMIC_ARB_STATUS_FAILURE) {
+		dev_err(dev->dev,
+		    "wait_for_done: transaction failed (0x%x)\n", status);
+		return -EIO;
+	}
+
+	if (status & PMIC_ARB_STATUS_DROPPED) {
+		dev_err(dev->dev,
+		    "wait_for_done: transaction dropped pmic-arb busy (0x%x)\n",
+		    status);
+		return -EAGAIN;
+	}
+
+	return 0;
+}
+
 static int pmic_arb_wait_for_done(struct spmi_pmic_arb_dev *dev)
 {
 	u32 status = 0;
@@ -152,34 +186,13 @@
 	while (timeout--) {
 		status = pmic_arb_read(dev, offset);
 
-		if (status & PMIC_ARB_STATUS_DONE) {
-			if (status & PMIC_ARB_STATUS_DENIED) {
-				dev_err(dev->dev,
-					"%s: transaction denied (0x%x)\n",
-					__func__, status);
-				return -EPERM;
-			}
+		if (status & PMIC_ARB_STATUS_DONE)
+			return pmic_arb_diagnosis(dev, status);
 
-			if (status & PMIC_ARB_STATUS_FAILURE) {
-				dev_err(dev->dev,
-					"%s: transaction failed (0x%x)\n",
-					__func__, status);
-				return -EIO;
-			}
-
-			if (status & PMIC_ARB_STATUS_DROPPED) {
-				dev_err(dev->dev,
-					"%s: transaction dropped (0x%x)\n",
-					__func__, status);
-				return -EIO;
-			}
-
-			return 0;
-		}
 		udelay(1);
 	}
 
-	dev_err(dev->dev, "%s: timeout, status 0x%x\n", __func__, status);
+	dev_err(dev->dev, "wait_for_done:: timeout, status 0x%x\n", status);
 	return -ETIMEDOUT;
 }
 
@@ -209,6 +222,29 @@
 	pmic_arb_write(dev, reg, data);
 }
 
+static void pmic_arb_dbg_err_dump(struct spmi_pmic_arb_dev *pmic_arb, int ret,
+		const char *msg, u8 opc, u8 sid, u16 addr, u8 bc, u8 *buf)
+{
+	u32 irq_stat  = readl_relaxed(pmic_arb->cnfg
+				+ PMIC_ARB_PROTOCOL_IRQ_STATUS);
+	u32 geni_stat = readl_relaxed(pmic_arb->cnfg + PMIC_ARB_GENI_STATUS);
+	u32 geni_ctrl = readl_relaxed(pmic_arb->cnfg + PMIC_ARB_GENI_CTRL);
+
+	bc += 1; /* actual byte count */
+
+	if (buf)
+		dev_err(pmic_arb->dev,
+		"error:%d on data %s  opcode:0x%x sid:%d addr:0x%x bc:%d buf:%*phC\n",
+			ret, msg, opc, sid, addr, bc, bc, buf);
+	else
+		dev_err(pmic_arb->dev,
+		"error:%d on non-data-cmd opcode:0x%x sid:%d\n",
+			ret, opc, sid);
+	dev_err(pmic_arb->dev,
+		"PROTOCOL_IRQ_STATUS before:0x%x after:0x%x GENI_STATUS:0x%x GENI_CTRL:0x%x\n",
+		irq_stat, pmic_arb->prev_prtcl_irq_stat, geni_stat, geni_ctrl);
+}
+
 /* Non-data command */
 static int pmic_arb_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid)
 {
@@ -228,10 +264,13 @@
 	cmd = (opc << 27) | ((sid & 0xf) << 20);
 
 	spin_lock_irqsave(&pmic_arb->lock, flags);
+	pmic_arb_save_stat_before_txn(pmic_arb);
 	pmic_arb_write(pmic_arb, PMIC_ARB_CMD(pmic_arb->channel), cmd);
 	rc = pmic_arb_wait_for_done(pmic_arb);
 	spin_unlock_irqrestore(&pmic_arb->lock, flags);
 
+	if (rc)
+		pmic_arb_dbg_err_dump(pmic_arb, rc, "cmd", opc, sid, 0, 0, 0);
 	return rc;
 }
 
@@ -249,7 +288,8 @@
 					, PMIC_ARB_MAX_TRANS_BYTES, bc+1);
 		return  -EINVAL;
 	}
-	pr_debug("op:0x%x sid:%d bc:%d addr:0x%x\n", opc, sid, bc, addr);
+	dev_dbg(pmic_arb->dev, "client-rd op:0x%x sid:%d addr:0x%x bc:%d\n",
+							opc, sid, addr, bc + 1);
 
 	/* Check the opcode */
 	if (opc >= 0x60 && opc <= 0x7F)
@@ -264,6 +304,7 @@
 	cmd = (opc << 27) | ((sid & 0xf) << 20) | (addr << 4) | (bc & 0x7);
 
 	spin_lock_irqsave(&pmic_arb->lock, flags);
+	pmic_arb_save_stat_before_txn(pmic_arb);
 	pmic_arb_write(pmic_arb, PMIC_ARB_CMD(pmic_arb->channel), cmd);
 	rc = pmic_arb_wait_for_done(pmic_arb);
 	if (rc)
@@ -279,6 +320,9 @@
 
 done:
 	spin_unlock_irqrestore(&pmic_arb->lock, flags);
+	if (rc)
+		pmic_arb_dbg_err_dump(pmic_arb, rc, "read", opc, sid, addr, bc,
+									buf);
 	return rc;
 }
 
@@ -296,7 +340,8 @@
 					, PMIC_ARB_MAX_TRANS_BYTES, bc+1);
 		return  -EINVAL;
 	}
-	pr_debug("op:0x%x sid:%d bc:%d addr:0x%x\n", opc, sid, bc, addr);
+	dev_dbg(pmic_arb->dev, "client-wr op:0x%x sid:%d addr:0x%x bc:%d\n",
+							opc, sid, addr, bc + 1);
 
 	/* Check the opcode */
 	if (opc >= 0x40 && opc <= 0x5F)
@@ -314,6 +359,7 @@
 
 	/* Write data to FIFOs */
 	spin_lock_irqsave(&pmic_arb->lock, flags);
+	pmic_arb_save_stat_before_txn(pmic_arb);
 	pa_write_data(pmic_arb, buf, PMIC_ARB_WDATA0(pmic_arb->channel)
 							, min_t(u8, bc, 3));
 	if (bc > 3)
@@ -325,6 +371,10 @@
 	rc = pmic_arb_wait_for_done(pmic_arb);
 	spin_unlock_irqrestore(&pmic_arb->lock, flags);
 
+	if (rc)
+		pmic_arb_dbg_err_dump(pmic_arb, rc, "write", opc, sid, addr, bc,
+									buf);
+
 	return rc;
 }
 
@@ -501,7 +551,9 @@
 	int i;
 
 	if (!is_apid_valid(pmic_arb, apid)) {
-		dev_err(pmic_arb->dev, "unknown peripheral id 0x%x\n", ppid);
+		dev_err(pmic_arb->dev,
+		"periph_interrupt(apid:0x%x sid:0x%x pid:0x%x) unknown peripheral\n",
+			apid, sid, pid);
 		/* return IRQ_NONE; */
 	}
 
diff --git a/drivers/staging/android/binder.c b/drivers/staging/android/binder.c
index b7bf74e..e0b066a 100644
--- a/drivers/staging/android/binder.c
+++ b/drivers/staging/android/binder.c
@@ -1404,6 +1404,7 @@
 	struct binder_transaction *t;
 	struct binder_work *tcomplete;
 	size_t *offp, *off_end;
+	size_t off_min;
 	struct binder_proc *target_proc;
 	struct binder_thread *target_thread = NULL;
 	struct binder_node *target_node = NULL;
@@ -1604,18 +1605,23 @@
 		goto err_bad_offset;
 	}
 	off_end = (void *)offp + tr->offsets_size;
+	off_min = 0;
 	for (; offp < off_end; offp++) {
 		struct flat_binder_object *fp;
 		if (*offp > t->buffer->data_size - sizeof(*fp) ||
+		    *offp < off_min ||
 		    t->buffer->data_size < sizeof(*fp) ||
-		    !IS_ALIGNED(*offp, sizeof(void *))) {
-			binder_user_error("binder: %d:%d got transaction with "
-				"invalid offset, %zd\n",
-				proc->pid, thread->pid, *offp);
+		    !IS_ALIGNED(*offp, sizeof(u32))) {
+			binder_user_error("%d:%d got transaction with invalid offset, %lld (min %lld, max %lld)\n",
+					  proc->pid, thread->pid, (u64)*offp,
+					  (u64)off_min,
+					  (u64)(t->buffer->data_size -
+					  sizeof(*fp)));
 			return_error = BR_FAILED_REPLY;
 			goto err_bad_offset;
 		}
 		fp = (struct flat_binder_object *)(t->buffer->data + *offp);
+		off_min = *offp + sizeof(struct flat_binder_object);
 		switch (fp->type) {
 		case BINDER_TYPE_BINDER:
 		case BINDER_TYPE_WEAK_BINDER: {
@@ -2847,9 +2853,15 @@
 	binder_defer_work(proc, BINDER_DEFERRED_PUT_FILES);
 }
 
+static int binder_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
+{
+	return VM_FAULT_SIGBUS;
+}
+
 static struct vm_operations_struct binder_vm_ops = {
 	.open = binder_vma_open,
 	.close = binder_vma_close,
+	.fault = binder_vm_fault,
 };
 
 static int binder_mmap(struct file *filp, struct vm_area_struct *vma)
diff --git a/drivers/thermal/msm_thermal.c b/drivers/thermal/msm_thermal.c
index 81b683d..e5eb9b2 100644
--- a/drivers/thermal/msm_thermal.c
+++ b/drivers/thermal/msm_thermal.c
@@ -11,6 +11,8 @@
  *
  */
 
+#define pr_fmt(fmt) "%s:%s " fmt, KBUILD_MODNAME, __func__
+
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/module.h>
@@ -257,8 +259,8 @@
 
 	switch (event) {
 	case CPUFREQ_INCOMPATIBLE:
-		pr_debug("%s: mitigating cpu %d to freq max: %u min: %u\n",
-		KBUILD_MODNAME, policy->cpu, max_freq_req, min_freq_req);
+		pr_debug("mitigating CPU%d to freq max: %u min: %u\n",
+		policy->cpu, max_freq_req, min_freq_req);
 
 		cpufreq_verify_within_limits(policy, min_freq_req,
 			max_freq_req);
@@ -283,7 +285,7 @@
 
 	table = cpufreq_frequency_get_table(0);
 	if (!table) {
-		pr_debug("%s: error reading cpufreq table\n", __func__);
+		pr_debug("error reading cpufreq table\n");
 		return -EINVAL;
 	}
 	freq_table_get = 1;
@@ -293,9 +295,13 @@
 
 static void update_cpu_freq(int cpu)
 {
+	int ret = 0;
+
 	if (cpu_online(cpu)) {
-		if (cpufreq_update_policy(cpu))
-			pr_err("Unable to update policy for cpu:%d\n", cpu);
+		ret = cpufreq_update_policy(cpu);
+		if (ret)
+			pr_err("Unable to update policy for cpu:%d. err:%d\n",
+				cpu, ret);
 	}
 }
 
@@ -307,13 +313,14 @@
 	if (!freq_table_get) {
 		ret = check_freq_table();
 		if (ret) {
-			pr_err("%s:Fail to get freq table\n", KBUILD_MODNAME);
+			pr_err("Fail to get freq table. err:%d\n", ret);
 			return ret;
 		}
 	}
 	/* If min is larger than allowed max */
 	min = min(min, table[limit_idx_high].frequency);
 
+	pr_debug("Requesting min freq:%u for all CPU's\n", min);
 	if (freq_mitigation_task) {
 		min_freq_limit = min;
 		complete(&freq_mitigation_complete);
@@ -362,7 +369,7 @@
 	int ret = 0;
 
 	if (r->reg == NULL) {
-		pr_info("Do not have regulator handle:%s, can't apply vdd\n",
+		pr_err("%s don't have regulator handle. can't apply vdd\n",
 				r->name);
 		return -EFAULT;
 	}
@@ -375,11 +382,15 @@
 			r->levels[r->num_levels - 1]);
 		if (!ret)
 			r->curr_level = -1;
+		pr_debug("Requested min level for %s. curr level: %d\n",
+				r->name, r->curr_level);
 	} else if (level >= 0 && level < (r->num_levels)) {
 		ret = regulator_set_voltage(r->reg, r->levels[level],
 			r->levels[r->num_levels - 1]);
 		if (!ret)
 			r->curr_level = level;
+		pr_debug("Requesting level %d for %s. curr level: %d\n",
+			r->levels[level], r->name, r->levels[r->curr_level]);
 	} else {
 		pr_err("level input:%d is not within range\n", level);
 		return -EINVAL;
@@ -395,12 +406,13 @@
 	int fail_cnt = 0;
 	int ret = 0;
 
+	pr_debug("Requesting PMIC Mode: %d\n", mode);
 	for (i = 0; i < psm_rails_cnt; i++) {
 		if (psm_rails[i].mode != mode) {
 			ret = rpm_regulator_set_mode(psm_rails[i].reg, mode);
 			if (ret) {
-				pr_err("Cannot set mode:%d for %s",
-					mode, psm_rails[i].name);
+				pr_err("Cannot set mode:%d for %s. err:%d",
+					mode, psm_rails[i].name, ret);
 				fail_cnt++;
 			} else
 				psm_rails[i].mode = mode;
@@ -473,6 +485,8 @@
 		en->enabled = 1;
 	else if (!val && (dis_cnt == rails_cnt))
 		en->enabled = 0;
+	pr_debug("%s vdd restriction. curr: %d\n",
+			(val) ? "Enable" : "Disable", en->enabled);
 
 done_vdd_rstr_en:
 	mutex_unlock(&vdd_rstr_mutex);
@@ -547,12 +561,14 @@
 			ret = vdd_restriction_apply_voltage(reg, val);
 			if (ret) {
 				pr_err( \
-				"Set vdd restriction for regulator %s failed\n",
-				reg->name);
+				"Set vdd restriction for regulator %s failed. err:%d\n",
+				reg->name, ret);
 				goto done_store_level;
 			}
 		}
 		reg->curr_level = val;
+		pr_debug("Request level %d for %s\n",
+				reg->curr_level, reg->name);
 	}
 
 done_store_level:
@@ -668,16 +684,15 @@
 	}
 
 	if ((val != PMIC_PWM_MODE) && (val != PMIC_AUTO_MODE)) {
-		pr_err(" Invalid number %d for mode\n", val);
+		pr_err("Invalid number %d for mode\n", val);
 		goto done_psm_store;
 	}
 
 	if (val != reg->mode) {
 		ret = rpm_regulator_set_mode(reg->reg, val);
 		if (ret) {
-			pr_err( \
-			"Fail to set PMIC SW Mode:%d for %s\n",
-			val, reg->name);
+			pr_err("Fail to set Mode:%d for %s. err:%d\n",
+			val, reg->name, ret);
 			goto done_psm_store;
 		}
 		reg->mode = val;
@@ -701,7 +716,7 @@
 		}
 	}
 	if (!hw_id_found) {
-		pr_err("%s: Invalid sensor hw id :%d\n", __func__, sensor_id);
+		pr_err("Invalid sensor hw id:%d\n", sensor_id);
 		return -EINVAL;
 	}
 
@@ -716,8 +731,7 @@
 	tsens_id_map = kzalloc(sizeof(int) * max_tsens_num,
 			GFP_KERNEL);
 	if (!tsens_id_map) {
-		pr_err("%s: Cannot allocate memory for tsens_id_map\n",
-				__func__);
+		pr_err("Cannot allocate memory for tsens_id_map\n");
 		return -ENOMEM;
 	}
 
@@ -729,9 +743,8 @@
 				tsens_id_map[i] = i;
 				ret = 0;
 			} else {
-				pr_err( \
-				"%s: Failed to get hw id for sw id %d\n",
-				__func__, i);
+				pr_err("Failed to get hw id for id:%d.err:%d\n",
+						i, ret);
 				goto fail;
 			}
 		}
@@ -760,7 +773,9 @@
 			ret = vdd_restriction_apply_voltage(&rails[i],
 					en ? 0 : -1);
 		if (ret) {
-			pr_err("Cannot set voltage for %s", rails[i].name);
+			pr_err("Failed to %s for %s. err:%d",
+					(en) ? "enable" : "disable",
+					rails[i].name, ret);
 			fail_cnt++;
 		} else {
 			if (en)
@@ -792,7 +807,7 @@
 
 	table = cpufreq_frequency_get_table(0);
 	if (table == NULL) {
-		pr_debug("%s: error reading cpufreq table\n", KBUILD_MODNAME);
+		pr_err("error reading cpufreq table\n");
 		ret = -EINVAL;
 		goto fail;
 	}
@@ -814,15 +829,15 @@
 
 	ret = sensor_set_trip(sensor_id, threshold);
 	if (ret != 0) {
-		pr_err("%s: Error in setting trip %d\n",
-			KBUILD_MODNAME, threshold->trip);
+		pr_err("sensor:%u Error in setting trip:%d. err:%d\n",
+			sensor_id, threshold->trip, ret);
 		goto set_done;
 	}
 
 	ret = sensor_activate_trip(sensor_id, threshold, true);
 	if (ret != 0) {
-		pr_err("%s: Error in enabling trip %d\n",
-			KBUILD_MODNAME, threshold->trip);
+		pr_err("sensor:%u Error in enabling trip:%d. err:%d\n",
+			sensor_id, threshold->trip, ret);
 		goto set_done;
 	}
 
@@ -857,7 +872,7 @@
 
 	ret = tsens_get_temp(&tsens_dev, temp);
 	if (ret) {
-		pr_err("Unable to read TSENS sensor %d\n",
+		pr_err("Unable to read TSENS sensor:%d\n",
 			tsens_dev.sensor_num);
 		goto get_temp_exit;
 	}
@@ -873,14 +888,17 @@
 	long temp;
 
 	if ((!threshold) || (zone_id >= max_tsens_num)) {
-		pr_err("%s: Invalid input\n", KBUILD_MODNAME);
+		pr_err("Invalid input\n");
 		ret = -EINVAL;
 		goto set_threshold_exit;
 	}
 
 	ret = therm_get_temp(zone_id, THERM_ZONE_ID, &temp);
-	if (ret)
+	if (ret) {
+		pr_err("Unable to read temperature for zone:%d. err:%d\n",
+			zone_id, ret);
 		goto set_threshold_exit;
+	}
 
 	while (i < MAX_THRESHOLD) {
 		switch (threshold[i].trip) {
@@ -901,6 +919,8 @@
 			}
 			break;
 		default:
+			pr_err("zone:%u Invalid trip:%d\n", zone_id,
+					threshold[i].trip);
 			break;
 		}
 		i++;
@@ -926,12 +946,12 @@
 				continue;
 			if (cpus_offlined & BIT(i) && !cpu_online(i))
 				continue;
-			pr_info("%s: Set Offline: CPU%d Temp: %ld\n",
-					KBUILD_MODNAME, i, temp);
+			pr_info("Set Offline: CPU%d Temp: %ld\n",
+					i, temp);
 			ret = cpu_down(i);
 			if (ret)
-				pr_err("%s: Error %d offline core %d\n",
-					KBUILD_MODNAME, ret, i);
+				pr_err("Error %d offline core %d\n",
+					ret, i);
 			cpus_offlined |= BIT(i);
 			break;
 		}
@@ -942,8 +962,8 @@
 			if (!(cpus_offlined & BIT(i)))
 				continue;
 			cpus_offlined &= ~BIT(i);
-			pr_info("%s: Allow Online CPU%d Temp: %ld\n",
-					KBUILD_MODNAME, i, temp);
+			pr_info("Allow Online CPU%d Temp: %ld\n",
+					i, temp);
 			/*
 			 * If this core is already online, then bring up the
 			 * next offlined core.
@@ -952,8 +972,8 @@
 				continue;
 			ret = cpu_up(i);
 			if (ret)
-				pr_err("%s: Error %d online core %d\n",
-						KBUILD_MODNAME, ret, i);
+				pr_err("Error %d online core %d\n",
+						ret, i);
 			break;
 		}
 	}
@@ -977,8 +997,10 @@
 			continue;
 		ret = cpu_down(cpu);
 		if (ret)
-			pr_err("%s: Unable to offline cpu%d\n",
-				KBUILD_MODNAME, cpu);
+			pr_err("Unable to offline CPU%d. err:%d\n",
+				cpu, ret);
+		else
+			pr_debug("Offlined CPU%d\n", cpu);
 	}
 	return ret;
 }
@@ -988,8 +1010,10 @@
 	int ret = 0;
 	uint32_t cpu = 0, mask = 0;
 
-	if (!core_control_enabled)
+	if (!core_control_enabled) {
+		pr_debug("Core control disabled\n");
 		return -EINVAL;
+	}
 
 	while (!kthread_should_stop()) {
 		while (wait_for_completion_interruptible(
@@ -1056,7 +1080,11 @@
 					ocr_rails[j].init = OPTIMUM_CURRENT_NR;
 			ret = ocr_set_mode_all(OPTIMUM_CURRENT_MAX);
 			if (ret)
-				pr_err("Error setting max optimum current\n");
+				pr_err("Error setting max ocr. err:%d\n",
+					ret);
+			else
+				pr_debug("Requested MAX OCR. tsens:%d Temp:%ld",
+					tsens_id_map[i], temp);
 			goto do_ocr_exit;
 		} else if (temp <= (msm_thermal_info.ocr_temp_degC -
 			msm_thermal_info.ocr_temp_hyst_degC))
@@ -1077,6 +1105,8 @@
 		if (ret) {
 			pr_err("Error setting min optimum current\n");
 			goto do_ocr_exit;
+		} else {
+			pr_debug("Requested MIN OCR. Temp:%ld", temp);
 		}
 	}
 
@@ -1104,8 +1134,8 @@
 	for (i = 0; i < max_tsens_num; i++) {
 		ret = therm_get_temp(tsens_id_map[i], THERM_TSENS_ID, &temp);
 		if (ret) {
-			pr_debug("Unable to read TSENS sensor %d\n",
-				tsens_id_map[i]);
+			pr_err("Unable to read TSENS sensor:%d. err:%d\n",
+				tsens_id_map[i], ret);
 			dis_cnt++;
 			continue;
 		}
@@ -1113,9 +1143,13 @@
 			ret = vdd_restriction_apply_all(1);
 			if (ret) {
 				pr_err( \
-				"Enable vdd rstr votlage for all failed\n");
+				"Enable vdd rstr for all failed. err:%d\n",
+					ret);
 				goto exit;
 			}
+			pr_debug("Enabled Vdd Restriction tsens:%d. Temp:%ld\n",
+			thresh[MSM_VDD_RESTRICTION].thresh_list[i].sensor_id,
+			temp);
 			goto exit;
 		} else if (temp > msm_thermal_info.vdd_rstr_temp_hyst_degC)
 			dis_cnt++;
@@ -1123,9 +1157,11 @@
 	if (dis_cnt == max_tsens_num) {
 		ret = vdd_restriction_apply_all(0);
 		if (ret) {
-			pr_err("Disable vdd rstr votlage for all failed\n");
+			pr_err("Disable vdd rstr for all failed. err:%d\n",
+					ret);
 			goto exit;
 		}
+		pr_debug("Disabled Vdd Restriction\n");
 	}
 exit:
 	mutex_unlock(&vdd_rstr_mutex);
@@ -1143,8 +1179,8 @@
 	for (i = 0; i < max_tsens_num; i++) {
 		ret = therm_get_temp(tsens_id_map[i], THERM_TSENS_ID, &temp);
 		if (ret) {
-			pr_debug("%s: Unable to read TSENS sensor %d\n",
-					__func__, tsens_id_map[i]);
+			pr_err("Unable to read TSENS sensor:%d. err:%d\n",
+					tsens_id_map[i], ret);
 			auto_cnt++;
 			continue;
 		}
@@ -1157,9 +1193,12 @@
 		if (temp >  msm_thermal_info.psm_temp_degC) {
 			ret = psm_set_mode_all(PMIC_PWM_MODE);
 			if (ret) {
-				pr_err("Set pwm mode for all failed\n");
+				pr_err("Set pwm mode for all failed. err:%d\n",
+						ret);
 				goto exit;
 			}
+			pr_debug("Requested PMIC PWM Mode tsens:%d. Temp:%ld\n",
+					tsens_id_map[i], temp);
 			break;
 		} else if (temp <= msm_thermal_info.psm_temp_hyst_degC)
 			auto_cnt++;
@@ -1168,9 +1207,10 @@
 	if (auto_cnt == max_tsens_num) {
 		ret = psm_set_mode_all(PMIC_AUTO_MODE);
 		if (ret) {
-			pr_err("Set auto mode for all failed\n");
+			pr_err("Set auto mode for all failed. err:%d\n", ret);
 			goto exit;
 		}
+		pr_debug("Requested PMIC AUTO Mode\n");
 	}
 
 exit:
@@ -1212,6 +1252,8 @@
 	for_each_possible_cpu(cpu) {
 		if (!(msm_thermal_info.bootup_freq_control_mask & BIT(cpu)))
 			continue;
+		pr_info("Limiting CPU%d max frequency to %u. Temp:%ld\n",
+			cpu, max_freq, temp);
 		cpus[cpu].limited_max_freq = max_freq;
 		update_cpu_freq(cpu);
 	}
@@ -1226,8 +1268,8 @@
 
 	ret = therm_get_temp(msm_thermal_info.sensor_id, THERM_TSENS_ID, &temp);
 	if (ret) {
-		pr_debug("Unable to read TSENS sensor %d\n",
-				msm_thermal_info.sensor_id);
+		pr_err("Unable to read TSENS sensor:%d. err:%d\n",
+				msm_thermal_info.sensor_id, ret);
 		goto reschedule;
 	}
 
@@ -1260,14 +1302,13 @@
 		if (core_control_enabled &&
 			(msm_thermal_info.core_control_mask & BIT(cpu)) &&
 			(cpus_offlined & BIT(cpu))) {
-			pr_debug(
-			"%s: Preventing cpu%d from coming online.\n",
-				KBUILD_MODNAME, cpu);
+			pr_debug("Preventing CPU%d from coming online.\n",
+				cpu);
 			return NOTIFY_BAD;
 		}
 	}
 
-
+	pr_debug("voting for CPU%d to be online\n", cpu);
 	return NOTIFY_OK;
 }
 
@@ -1312,8 +1353,7 @@
 {
 	struct cpu_info *cpu_node = (struct cpu_info *)data;
 
-	pr_info("%s: %s reach temp threshold: %d\n", KBUILD_MODNAME,
-			cpu_node->sensor_type, temp);
+	pr_info("%s reach temp threshold: %d\n", cpu_node->sensor_type, temp);
 
 	if (!(msm_thermal_info.core_control_mask & BIT(cpu_node->cpu)))
 		return 0;
@@ -1333,7 +1373,7 @@
 		cpu_node->hotplug_thresh_clear = true;
 		complete(&hotplug_notify_complete);
 	} else {
-		pr_err("%s: Hotplug task is not initialized\n", KBUILD_MODNAME);
+		pr_err("Hotplug task is not initialized\n");
 	}
 	return 0;
 }
@@ -1352,8 +1392,8 @@
 			continue;
 		if (therm_get_temp(cpus[cpu].sensor_id, cpus[cpu].id_type,
 					&temp)) {
-			pr_err("%s: Unable to read TSENS sensor %d\n",
-				KBUILD_MODNAME, cpus[cpu].sensor_id);
+			pr_err("Unable to read TSENS sensor:%d.\n",
+				cpus[cpu].sensor_id);
 			mutex_unlock(&core_control_mutex);
 			return -EINVAL;
 		}
@@ -1369,8 +1409,7 @@
 	if (hotplug_task)
 		complete(&hotplug_notify_complete);
 	else {
-		pr_err("%s: Hotplug task is not initialized\n",
-					KBUILD_MODNAME);
+		pr_err("Hotplug task is not initialized\n");
 		return -EINVAL;
 	}
 	return 0;
@@ -1410,8 +1449,8 @@
 	init_completion(&hotplug_notify_complete);
 	hotplug_task = kthread_run(do_hotplug, NULL, "msm_thermal:hotplug");
 	if (IS_ERR(hotplug_task)) {
-		pr_err("%s: Failed to create do_hotplug thread\n",
-				KBUILD_MODNAME);
+		pr_err("Failed to create do_hotplug thread. err:%ld\n",
+				PTR_ERR(hotplug_task));
 		return;
 	}
 	/*
@@ -1471,7 +1510,7 @@
 {
 	struct cpu_info *cpu_node = (struct cpu_info *) data;
 
-	pr_debug("%s: %s reached temp threshold: %d\n", KBUILD_MODNAME,
+	pr_debug("%s reached temp threshold: %d\n",
 		cpu_node->sensor_type, temp);
 
 	if (!(msm_thermal_info.freq_mitig_control_mask &
@@ -1481,8 +1520,8 @@
 	switch (type) {
 	case THERMAL_TRIP_CONFIGURABLE_HI:
 		if (!cpu_node->max_freq) {
-			pr_info("%s: Mitigating cpu %d frequency to %d\n",
-				KBUILD_MODNAME, cpu_node->cpu,
+			pr_info("Mitigating CPU%d frequency to %d\n",
+				cpu_node->cpu,
 				msm_thermal_info.freq_limit);
 
 			cpu_node->max_freq = true;
@@ -1490,8 +1529,8 @@
 		break;
 	case THERMAL_TRIP_CONFIGURABLE_LOW:
 		if (cpu_node->max_freq) {
-			pr_info("%s: Removing frequency mitigation for cpu%d\n",
-				KBUILD_MODNAME, cpu_node->cpu);
+			pr_info("Removing frequency mitigation for CPU%d\n",
+				cpu_node->cpu);
 
 			cpu_node->max_freq = false;
 		}
@@ -1504,8 +1543,7 @@
 		cpu_node->freq_thresh_clear = true;
 		complete(&freq_mitigation_complete);
 	} else {
-		pr_err("%s: Frequency mitigation task is not initialized\n",
-			KBUILD_MODNAME);
+		pr_err("Frequency mitigation task is not initialized\n");
 	}
 
 	return 0;
@@ -1544,8 +1582,8 @@
 		"msm_thermal:freq_mitig");
 
 	if (IS_ERR(freq_mitigation_task)) {
-		pr_err("%s: Failed to create frequency mitigation thread\n",
-				KBUILD_MODNAME);
+		pr_err("Failed to create frequency mitigation thread. err:%ld\n",
+				PTR_ERR(freq_mitigation_task));
 		return;
 	}
 }
@@ -1555,11 +1593,13 @@
 	int ret = 0;
 
 	if (cpu >= num_possible_cpus()) {
-		pr_err("%s: Invalid input\n", KBUILD_MODNAME);
+		pr_err("Invalid input\n");
 		ret = -EINVAL;
 		goto set_freq_exit;
 	}
 
+	pr_debug("Userspace requested %s frequency %u for CPU%u\n",
+			(is_max) ? "Max" : "Min", freq, cpu);
 	if (is_max) {
 		if (cpus[cpu].user_max_freq == freq)
 			goto set_freq_exit;
@@ -1575,8 +1615,7 @@
 	if (freq_mitigation_task) {
 		complete(&freq_mitigation_complete);
 	} else {
-		pr_err("%s: Frequency mitigation task is not initialized\n",
-			KBUILD_MODNAME);
+		pr_err("Frequency mitigation task is not initialized\n");
 		ret = -ESRCH;
 		goto set_freq_exit;
 	}
@@ -1591,8 +1630,7 @@
 	struct therm_threshold *thresh_ptr;
 
 	if (!thresh_inp) {
-		pr_err("%s: %s: Invalid input\n",
-			KBUILD_MODNAME, __func__);
+		pr_err("Invalid input\n");
 		ret = -EINVAL;
 		goto therm_set_exit;
 	}
@@ -1621,16 +1659,17 @@
 	if (!vdd_rstr_enabled)
 		return;
 	if (!trig_thresh) {
-		pr_err("%s:%s Invalid input\n", KBUILD_MODNAME, __func__);
+		pr_err("Invalid input\n");
 		return;
 	}
 	if (trig_thresh->trip_triggered < 0)
 		goto set_and_exit;
 
 	mutex_lock(&vdd_rstr_mutex);
-	pr_debug("%s: sensor%d reached %d thresh for Vdd restriction\n",
-		KBUILD_MODNAME, trig_thresh->sensor_id,
-		trig_thresh->trip_triggered);
+	pr_debug("sensor:%d reached %s thresh for Vdd restriction\n",
+		tsens_id_map[trig_thresh->sensor_id],
+		(trig_thresh->trip_triggered == THERMAL_TRIP_CONFIGURABLE_HI) ?
+		"high" : "low");
 	switch (trig_thresh->trip_triggered) {
 	case THERMAL_TRIP_CONFIGURABLE_HI:
 		if (vdd_sens_status & BIT(trig_thresh->sensor_id))
@@ -1640,8 +1679,7 @@
 		vdd_sens_status |= BIT(trig_thresh->sensor_id);
 		break;
 	default:
-		pr_err("%s:%s: Unsupported trip type\n",
-			KBUILD_MODNAME, __func__);
+		pr_err("Unsupported trip type\n");
 		goto unlock_and_exit;
 		break;
 	}
@@ -1697,8 +1735,8 @@
 	thermal_monitor_task = kthread_run(do_thermal_monitor, NULL,
 		"msm_thermal:therm_monitor");
 	if (IS_ERR(thermal_monitor_task)) {
-		pr_err("%s: Failed to create thermal monitor thread\n",
-				KBUILD_MODNAME);
+		pr_err("Failed to create thermal monitor thread. err:%ld\n",
+				PTR_ERR(thermal_monitor_task));
 		goto init_exit;
 	}
 
@@ -1718,8 +1756,7 @@
 		thresh_data->parent->thresh_triggered = true;
 		complete(&thermal_monitor_complete);
 	} else {
-		pr_err("%s: Thermal monitor task is not initialized\n",
-			KBUILD_MODNAME);
+		pr_err("Thermal monitor task is not initialized\n");
 	}
 	return 0;
 }
@@ -1733,14 +1770,13 @@
 
 	if (!callback || index >= MSM_LIST_MAX_NR || index < 0
 		|| sensor_id == -ENODEV) {
-		pr_err("%s: Invalid input to init_threshold\n",
-			KBUILD_MODNAME);
+		pr_err("Invalid input. sensor:%d. index:%d\n",
+				sensor_id, index);
 		ret = -EINVAL;
 		goto init_thresh_exit;
 	}
 	if (thresh[index].thresh_list) {
-		pr_err("%s: threshold already initialized\n",
-			KBUILD_MODNAME);
+		pr_err("threshold id:%d already initialized\n", index);
 		ret = -EEXIST;
 		goto init_thresh_exit;
 	}
@@ -1751,7 +1787,7 @@
 	thresh[index].thresh_list = kzalloc(sizeof(struct therm_threshold) *
 					thresh[index].thresh_ct, GFP_KERNEL);
 	if (!thresh[index].thresh_list) {
-		pr_err("%s: kzalloc failed\n", KBUILD_MODNAME);
+		pr_err("kzalloc failed for thresh index:%d\n", index);
 		ret = -ENOMEM;
 		goto init_thresh_exit;
 	}
@@ -1813,6 +1849,7 @@
 		if (cpus[cpu].limited_max_freq == UINT_MAX &&
 			cpus[cpu].limited_min_freq == 0)
 			continue;
+		pr_info("Max frequency reset for CPU%d\n", cpu);
 		cpus[cpu].limited_max_freq = UINT_MAX;
 		cpus[cpu].limited_min_freq = 0;
 		update_cpu_freq(cpu);
@@ -1827,7 +1864,7 @@
 		return;
 	}
 	if (polling_enabled) {
-		pr_info("%s: Interrupt mode init\n", KBUILD_MODNAME);
+		pr_info("Interrupt mode init\n");
 		polling_enabled = 0;
 		disable_msm_thermal();
 		hotplug_init();
@@ -1844,10 +1881,10 @@
 	if (!enabled)
 		interrupt_mode_init();
 	else
-		pr_info("%s: no action for enabled = %d\n",
-			KBUILD_MODNAME, enabled);
+		pr_info("no action for enabled = %d\n",
+			enabled);
 
-	pr_info("%s: enabled = %d\n", KBUILD_MODNAME, enabled);
+	pr_info("enabled = %d\n", enabled);
 
 	return ret;
 }
@@ -1874,7 +1911,7 @@
 
 	ret = kstrtoint(buf, 10, &val);
 	if (ret) {
-		pr_err("%s: Invalid input %s\n", KBUILD_MODNAME, buf);
+		pr_err("Invalid input %s. err:%d\n", buf, ret);
 		goto done_store_cc;
 	}
 
@@ -1883,15 +1920,14 @@
 
 	core_control_enabled = !!val;
 	if (core_control_enabled) {
-		pr_info("%s: Core control enabled\n", KBUILD_MODNAME);
+		pr_info("Core control enabled\n");
 		register_cpu_notifier(&msm_thermal_cpu_notifier);
 		if (hotplug_task)
 			complete(&hotplug_notify_complete);
 		else
-			pr_err("%s: Hotplug task is not initialized\n",
-					KBUILD_MODNAME);
+			pr_err("Hotplug task is not initialized\n");
 	} else {
-		pr_info("%s: Core control disabled\n", KBUILD_MODNAME);
+		pr_info("Core control disabled\n");
 		unregister_cpu_notifier(&msm_thermal_cpu_notifier);
 	}
 
@@ -1915,13 +1951,12 @@
 	mutex_lock(&core_control_mutex);
 	ret = kstrtouint(buf, 10, &val);
 	if (ret) {
-		pr_err("%s: Invalid input %s\n", KBUILD_MODNAME, buf);
+		pr_err("Invalid input %s. err:%d\n", buf, ret);
 		goto done_cc;
 	}
 
 	if (polling_enabled) {
-		pr_err("%s: Ignoring request; polling thread is enabled.\n",
-				KBUILD_MODNAME);
+		pr_err("Ignoring request; polling thread is enabled.\n");
 		goto done_cc;
 	}
 
@@ -1929,12 +1964,15 @@
 		if (!(msm_thermal_info.core_control_mask & BIT(cpu)))
 			continue;
 		cpus[cpu].user_offline = !!(val & BIT(cpu));
+		pr_debug("\"%s\"(PID:%i) requests %s CPU%d.\n", current->comm,
+			current->pid, (cpus[cpu].user_offline) ? "offline" :
+			"online", cpu);
 	}
 
 	if (hotplug_task)
 		complete(&hotplug_notify_complete);
 	else
-		pr_err("%s: Hotplug task is not initialized\n", KBUILD_MODNAME);
+		pr_err("Hotplug task is not initialized\n");
 done_cc:
 	mutex_unlock(&core_control_mutex);
 	return count;
@@ -2009,23 +2047,21 @@
 
 	module_kobj = kset_find_obj(module_kset, KBUILD_MODNAME);
 	if (!module_kobj) {
-		pr_err("%s: cannot find kobject for module\n",
-			KBUILD_MODNAME);
+		pr_err("cannot find kobject\n");
 		ret = -ENOENT;
 		goto done_cc_nodes;
 	}
 
 	cc_kobj = kobject_create_and_add("core_control", module_kobj);
 	if (!cc_kobj) {
-		pr_err("%s: cannot create core control kobj\n",
-				KBUILD_MODNAME);
+		pr_err("cannot create core control kobj\n");
 		ret = -ENOMEM;
 		goto done_cc_nodes;
 	}
 
 	ret = sysfs_create_group(cc_kobj, &cc_attr_group);
 	if (ret) {
-		pr_err("%s: cannot create group\n", KBUILD_MODNAME);
+		pr_err("cannot create sysfs group. err:%d\n", ret);
 		goto done_cc_nodes;
 	}
 
@@ -2078,6 +2114,7 @@
 
 	tsens_get_max_sensor_num(&max_tsens_num);
 	if (create_sensor_id_map()) {
+		pr_err("Creating sensor id map failed\n");
 		ret = -EINVAL;
 		goto pre_init_exit;
 	}
@@ -2087,8 +2124,7 @@
 				sizeof(struct threshold_info) * MSM_LIST_MAX_NR,
 				GFP_KERNEL);
 		if (!thresh) {
-			pr_err("%s:%s: kzalloc failed\n",
-				KBUILD_MODNAME, __func__);
+			pr_err("kzalloc failed\n");
 			ret = -ENOMEM;
 			goto pre_init_exit;
 		}
@@ -2119,16 +2155,19 @@
 	BUG_ON(!pdata);
 	memcpy(&msm_thermal_info, pdata, sizeof(struct msm_thermal_data));
 
-	if (check_sensor_id(msm_thermal_info.sensor_id))
+	if (check_sensor_id(msm_thermal_info.sensor_id)) {
+		pr_err("Invalid sensor:%d for polling\n",
+				msm_thermal_info.sensor_id);
 		return -EINVAL;
+	}
 
 	enabled = 1;
 	polling_enabled = 1;
 	ret = cpufreq_register_notifier(&msm_thermal_cpufreq_notifier,
 			CPUFREQ_POLICY_NOTIFIER);
 	if (ret)
-		pr_err("%s: cannot register cpufreq notifier\n",
-			KBUILD_MODNAME);
+		pr_err("cannot register cpufreq notifier. err:%d\n", ret);
+
 	INIT_DELAYED_WORK(&check_temp_work, check_temp);
 	schedule_delayed_work(&check_temp_work, 0);
 
@@ -2190,8 +2229,7 @@
 			if (freq_table_get)
 				ret = vdd_restriction_apply_freq(&rails[i], 0);
 			else
-				pr_info("%s:Defer vdd rstr freq init\n",
-						__func__);
+				pr_info("Defer vdd rstr freq init.\n");
 		} else {
 			rails[i].reg = devm_regulator_get(&pdev->dev,
 					rails[i].name);
@@ -2199,12 +2237,14 @@
 				ret = PTR_ERR(rails[i].reg);
 				if (ret != -EPROBE_DEFER) {
 					pr_err( \
-					"%s, could not get regulator: %s\n",
-					rails[i].name, __func__);
+					"could not get regulator: %s. err:%d\n",
+					rails[i].name, ret);
 					rails[i].reg = NULL;
 					rails[i].curr_level = -2;
 					return ret;
 				}
+				pr_info("Defer regulator %s probe\n",
+					rails[i].name);
 				return ret;
 			}
 			/*
@@ -2230,11 +2270,13 @@
 		if (IS_ERR_OR_NULL(psm_rails[i].reg)) {
 			ret = PTR_ERR(psm_rails[i].reg);
 			if (ret != -EPROBE_DEFER) {
-				pr_err("%s, could not get rpm regulator: %s\n",
-					psm_rails[i].name, __func__);
+				pr_err("couldn't get rpm regulator %s. err%d\n",
+					psm_rails[i].name, ret);
 				psm_rails[i].reg = NULL;
 				goto psm_reg_exit;
 			}
+			pr_info("Defer regulator %s probe\n",
+					psm_rails[i].name);
 			return ret;
 		}
 		/* Apps default vote for PWM mode */
@@ -2242,7 +2284,7 @@
 		ret = rpm_regulator_set_mode(psm_rails[i].reg,
 				psm_rails[i].init);
 		if (ret) {
-			pr_err("%s: Cannot set PMIC PWM mode\n", __func__);
+			pr_err("Cannot set PMIC PWM mode. err:%d\n", ret);
 			return ret;
 		} else
 			psm_rails[i].mode = PMIC_PWM_MODE;
@@ -2311,22 +2353,21 @@
 
 	module_kobj = kset_find_obj(module_kset, KBUILD_MODNAME);
 	if (!module_kobj) {
-		pr_err("%s: cannot find kobject for module %s\n",
-			__func__, KBUILD_MODNAME);
+		pr_err("cannot find kobject\n");
 		rc = -ENOENT;
 		goto thermal_sysfs_add_exit;
 	}
 
 	vdd_rstr_kobj = kobject_create_and_add("vdd_restriction", module_kobj);
 	if (!vdd_rstr_kobj) {
-		pr_err("%s: cannot create vdd_restriction kobject\n", __func__);
+		pr_err("cannot create vdd_restriction kobject\n");
 		rc = -ENOMEM;
 		goto thermal_sysfs_add_exit;
 	}
 
 	rc = sysfs_create_group(vdd_rstr_kobj, &vdd_rstr_en_attribs_gp);
 	if (rc) {
-		pr_err("%s: cannot create kobject attribute group\n", __func__);
+		pr_err("cannot create kobject attribute group. err:%d\n", rc);
 		rc = -ENOMEM;
 		goto thermal_sysfs_add_exit;
 	}
@@ -2335,8 +2376,8 @@
 		vdd_rstr_reg_kobj[i] = kobject_create_and_add(rails[i].name,
 					vdd_rstr_kobj);
 		if (!vdd_rstr_reg_kobj[i]) {
-			pr_err("%s: cannot create for kobject for %s\n",
-					__func__, rails[i].name);
+			pr_err("cannot create kobject for %s\n",
+					rails[i].name);
 			rc = -ENOMEM;
 			goto thermal_sysfs_add_exit;
 		}
@@ -2344,6 +2385,7 @@
 		rails[i].attr_gp.attrs = kzalloc(sizeof(struct attribute *) * 3,
 					GFP_KERNEL);
 		if (!rails[i].attr_gp.attrs) {
+			pr_err("kzalloc failed\n");
 			rc = -ENOMEM;
 			goto thermal_sysfs_add_exit;
 		}
@@ -2355,8 +2397,8 @@
 		rc = sysfs_create_group(vdd_rstr_reg_kobj[i],
 				&rails[i].attr_gp);
 		if (rc) {
-			pr_err("%s: cannot create attribute group for %s\n",
-					__func__, rails[i].name);
+			pr_err("cannot create attribute group for %s. err:%d\n",
+					rails[i].name, rc);
 			goto thermal_sysfs_add_exit;
 		}
 	}
@@ -2467,15 +2509,14 @@
 
 	module_kobj = kset_find_obj(module_kset, KBUILD_MODNAME);
 	if (!module_kobj) {
-		pr_err("%s: cannot find kobject for module %s\n",
-			__func__, KBUILD_MODNAME);
+		pr_err("cannot find kobject\n");
 		rc = -ENOENT;
 		goto psm_node_exit;
 	}
 
 	psm_kobj = kobject_create_and_add("pmic_sw_mode", module_kobj);
 	if (!psm_kobj) {
-		pr_err("%s: cannot create psm kobject\n", KBUILD_MODNAME);
+		pr_err("cannot create psm kobject\n");
 		rc = -ENOMEM;
 		goto psm_node_exit;
 	}
@@ -2484,14 +2525,15 @@
 		psm_reg_kobj[i] = kobject_create_and_add(psm_rails[i].name,
 					psm_kobj);
 		if (!psm_reg_kobj[i]) {
-			pr_err("%s: cannot create for kobject for %s\n",
-					KBUILD_MODNAME, psm_rails[i].name);
+			pr_err("cannot create kobject for %s\n",
+					psm_rails[i].name);
 			rc = -ENOMEM;
 			goto psm_node_exit;
 		}
 		psm_rails[i].attr_gp.attrs = kzalloc( \
 				sizeof(struct attribute *) * 2, GFP_KERNEL);
 		if (!psm_rails[i].attr_gp.attrs) {
+			pr_err("kzalloc failed\n");
 			rc = -ENOMEM;
 			goto psm_node_exit;
 		}
@@ -2501,8 +2543,8 @@
 
 		rc = sysfs_create_group(psm_reg_kobj[i], &psm_rails[i].attr_gp);
 		if (rc) {
-			pr_err("%s: cannot create attribute group for %s\n",
-					KBUILD_MODNAME, psm_rails[i].name);
+			pr_err("cannot create attribute group for %s. err:%d\n",
+					psm_rails[i].name, rc);
 			goto psm_node_exit;
 		}
 	}
@@ -2549,14 +2591,14 @@
 	if (rails_cnt == 0)
 		goto read_node_fail;
 	if (rails_cnt >= MAX_RAILS) {
-		pr_err("%s: Too many rails.\n", __func__);
+		pr_err("Too many rails:%d.\n", rails_cnt);
 		return -EFAULT;
 	}
 
 	rails = kzalloc(sizeof(struct rail) * rails_cnt,
 				GFP_KERNEL);
 	if (!rails) {
-		pr_err("%s: Fail to allocate memory for rails.\n", __func__);
+		pr_err("Fail to allocate memory for rails.\n");
 		return -ENOMEM;
 	}
 
@@ -2573,7 +2615,8 @@
 		rails[i].num_levels = arr_size/sizeof(__be32);
 		if (rails[i].num_levels >
 			sizeof(rails[i].levels)/sizeof(uint32_t)) {
-			pr_err("%s: Array size too large\n", __func__);
+			pr_err("Array size:%d too large for index:%d\n",
+				rails[i].num_levels, i);
 			return -EFAULT;
 		}
 		ret = of_property_read_u32_array(child_node, key,
@@ -2601,23 +2644,26 @@
 	if (rails_cnt) {
 		ret = vdd_restriction_reg_init(pdev);
 		if (ret) {
-			pr_info("%s:Failed to get regulators. KTM continues.\n",
-				__func__);
+			pr_err("Err regulator init. err:%d. KTM continues.\n",
+					ret);
 			goto read_node_fail;
 		}
 		ret = init_threshold(MSM_VDD_RESTRICTION, MONITOR_ALL_TSENS,
 			data->vdd_rstr_temp_hyst_degC, data->vdd_rstr_temp_degC,
 			vdd_restriction_notify);
-		if (ret)
+		if (ret) {
+			pr_err("Error in initializing thresholds. err:%d\n",
+					ret);
 			goto read_node_fail;
+		}
 		vdd_rstr_enabled = true;
 	}
 read_node_fail:
 	vdd_rstr_probed = true;
 	if (ret) {
 		dev_info(&pdev->dev,
-			"%s:Failed reading node=%s, key=%s. KTM continues\n",
-			__func__, node->full_name, key);
+		"%s:Failed reading node=%s, key=%s. err=%d. KTM continues\n",
+			__func__, node->full_name, key, ret);
 		kfree(rails);
 		rails_cnt = 0;
 	}
@@ -2890,7 +2936,7 @@
 	psm_rails = kzalloc(sizeof(struct psm_rail) * psm_rails_cnt,
 			GFP_KERNEL);
 	if (!psm_rails) {
-		pr_err("%s: Fail to allocate memory for psm rails\n", __func__);
+		pr_err("Fail to allocate memory for psm rails\n");
 		psm_rails_cnt = 0;
 		return -ENOMEM;
 	}
@@ -2905,8 +2951,8 @@
 	if (psm_rails_cnt) {
 		ret = psm_reg_init(pdev);
 		if (ret) {
-			pr_info("%s:Failed to get regulators. KTM continues.\n",
-					__func__);
+			pr_err("Err regulator init. err:%d. KTM continues.\n",
+					ret);
 			goto read_node_fail;
 		}
 		psm_enabled = true;
@@ -2916,8 +2962,8 @@
 	psm_probed = true;
 	if (ret) {
 		dev_info(&pdev->dev,
-			"%s:Failed reading node=%s, key=%s. KTM continues\n",
-			__func__, node->full_name, key);
+		"%s:Failed reading node=%s, key=%s. err=%d. KTM continues\n",
+			__func__, node->full_name, key, ret);
 		kfree(psm_rails);
 		psm_rails_cnt = 0;
 	}
@@ -2968,7 +3014,7 @@
 	key = "qcom,cpu-sensors";
 	cpu_cnt = of_property_count_strings(node, key);
 	if (cpu_cnt < num_possible_cpus()) {
-		pr_err("%s: Wrong number of cpu sensors\n", KBUILD_MODNAME);
+		pr_err("Wrong number of cpu sensors:%d\n", cpu_cnt);
 		ret = -EINVAL;
 		goto hotplug_node_fail;
 	}
@@ -2983,8 +3029,8 @@
 read_node_fail:
 	if (ret) {
 		dev_info(&pdev->dev,
-			"%s:Failed reading node=%s, key=%s. KTM continues\n",
-			KBUILD_MODNAME, node->full_name, key);
+		"%s:Failed reading node=%s, key=%s. err=%d. KTM continues\n",
+			KBUILD_MODNAME, node->full_name, key, ret);
 		core_control_enabled = 0;
 	}
 
@@ -2993,8 +3039,8 @@
 hotplug_node_fail:
 	if (ret) {
 		dev_info(&pdev->dev,
-			"%s:Failed reading node=%s, key=%s. KTM continues\n",
-			KBUILD_MODNAME, node->full_name, key);
+		"%s:Failed reading node=%s, key=%s. err=%d. KTM continues\n",
+			KBUILD_MODNAME, node->full_name, key, ret);
 		hotplug_enabled = 0;
 	}
 
@@ -3034,8 +3080,8 @@
 PROBE_FREQ_EXIT:
 	if (ret) {
 		dev_info(&pdev->dev,
-			"%s:Failed reading node=%s, key=%s. KTM continues\n",
-			__func__, node->full_name, key);
+		"%s:Failed reading node=%s, key=%s. err=%d. KTM continues\n",
+			__func__, node->full_name, key, ret);
 		freq_mitigation_enabled = 0;
 	}
 	return ret;
@@ -3050,8 +3096,10 @@
 
 	memset(&data, 0, sizeof(struct msm_thermal_data));
 	ret = msm_thermal_pre_init();
-	if (ret)
+	if (ret) {
+		pr_err("thermal pre init failed. err:%d\n", ret);
 		goto fail;
+	}
 
 	key = "qcom,sensor-id";
 	ret = of_property_read_u32(node, key, &data.sensor_id);
@@ -3135,8 +3183,8 @@
 	return ret;
 fail:
 	if (ret)
-		pr_err("%s: Failed reading node=%s, key=%s\n",
-			__func__, node->full_name, key);
+		pr_err("Failed reading node=%s, key=%s. err:%d\n",
+			node->full_name, key, ret);
 
 	return ret;
 }
diff --git a/drivers/tty/serial/msm_serial_hs.c b/drivers/tty/serial/msm_serial_hs.c
index 6078ef1..6be6599 100644
--- a/drivers/tty/serial/msm_serial_hs.c
+++ b/drivers/tty/serial/msm_serial_hs.c
@@ -62,8 +62,6 @@
 #include <asm/atomic.h>
 #include <asm/irq.h>
 
-#include <mach/hardware.h>
-#include <mach/dma.h>
 #include <mach/sps.h>
 #include <mach/msm_serial_hs.h>
 #include <mach/msm_bus.h>
@@ -176,11 +174,6 @@
 	unsigned int dma_in_flight;    /* tx dma in progress */
 	enum flush_reason flush;
 	wait_queue_head_t wait;
-	struct msm_dmov_cmd xfer;
-	dmov_box *command_ptr;
-	u32 *command_ptr_ptr;
-	dma_addr_t mapped_cmd_ptr;
-	dma_addr_t mapped_cmd_ptr_ptr;
 	int tx_count;
 	dma_addr_t dma_base;
 	struct tasklet_struct tlet;
@@ -189,11 +182,6 @@
 
 struct msm_hs_rx {
 	enum flush_reason flush;
-	struct msm_dmov_cmd xfer;
-	dma_addr_t cmdptr_dmaaddr;
-	dmov_box *command_ptr;
-	u32 *command_ptr_ptr;
-	dma_addr_t mapped_cmd_ptr;
 	wait_queue_head_t wait;
 	dma_addr_t rbuffer;
 	unsigned char *buffer;
@@ -230,14 +218,6 @@
 	struct clk *pclk;
 	struct msm_hs_tx tx;
 	struct msm_hs_rx rx;
-	/* gsbi uarts have to do additional writes to gsbi memory */
-	/* block and top control status block. The following pointers */
-	/* keep a handle to these blocks. */
-	unsigned char __iomem	*mapped_gsbi;
-	int dma_tx_channel;
-	int dma_rx_channel;
-	int dma_tx_crci;
-	int dma_rx_crci;
 	struct hrtimer clk_off_timer;  /* to poll TXEMT before clock off */
 	ktime_t clk_off_delay;
 	enum msm_hs_clk_states_e clk_state;
@@ -266,70 +246,15 @@
 	u32 bus_perf_client;
 	/* BLSP UART required BUS Scaling data */
 	struct msm_bus_scale_pdata *bus_scale_table;
-	bool rx_discard_flush_issued;
 	int rx_count_callback;
 	bool rx_bam_inprogress;
-	unsigned int *reg_ptr;
 	wait_queue_head_t bam_disconnect_wait;
 
 };
 
-unsigned int regmap_nonblsp[UART_DM_LAST] = {
-		[UART_DM_MR1] = UARTDM_MR1_ADDR,
-		[UART_DM_MR2] = UARTDM_MR2_ADDR,
-		[UART_DM_IMR] = UARTDM_IMR_ADDR,
-		[UART_DM_SR] = UARTDM_SR_ADDR,
-		[UART_DM_CR] = UARTDM_CR_ADDR,
-		[UART_DM_CSR] = UARTDM_CSR_ADDR,
-		[UART_DM_IPR] = UARTDM_IPR_ADDR,
-		[UART_DM_ISR] = UARTDM_ISR_ADDR,
-		[UART_DM_RX_TOTAL_SNAP] = UARTDM_RX_TOTAL_SNAP_ADDR,
-		[UART_DM_TFWR] = UARTDM_TFWR_ADDR,
-		[UART_DM_RFWR] = UARTDM_RFWR_ADDR,
-		[UART_DM_RF] = UARTDM_RF_ADDR,
-		[UART_DM_TF] = UARTDM_TF_ADDR,
-		[UART_DM_MISR] = UARTDM_MISR_ADDR,
-		[UART_DM_DMRX] = UARTDM_DMRX_ADDR,
-		[UART_DM_NCF_TX] = UARTDM_NCF_TX_ADDR,
-		[UART_DM_DMEN] = UARTDM_DMEN_ADDR,
-		[UART_DM_TXFS] = UARTDM_TXFS_ADDR,
-		[UART_DM_RXFS] = UARTDM_RXFS_ADDR,
-		[UART_DM_RX_TRANS_CTRL] = UARTDM_RX_TRANS_CTRL_ADDR,
-};
-
-unsigned int regmap_blsp[UART_DM_LAST] = {
-		[UART_DM_MR1] = 0x0,
-		[UART_DM_MR2] = 0x4,
-		[UART_DM_IMR] = 0xb0,
-		[UART_DM_SR] = 0xa4,
-		[UART_DM_CR] = 0xa8,
-		[UART_DM_CSR] = 0xa0,
-		[UART_DM_IPR] = 0x18,
-		[UART_DM_ISR] = 0xb4,
-		[UART_DM_RX_TOTAL_SNAP] = 0xbc,
-		[UART_DM_TFWR] = 0x1c,
-		[UART_DM_RFWR] = 0x20,
-		[UART_DM_RF] = 0x140,
-		[UART_DM_TF] = 0x100,
-		[UART_DM_MISR] = 0xac,
-		[UART_DM_DMRX] = 0x34,
-		[UART_DM_NCF_TX] = 0x40,
-		[UART_DM_DMEN] = 0x3c,
-		[UART_DM_TXFS] = 0x4c,
-		[UART_DM_RXFS] = 0x50,
-		[UART_DM_RX_TRANS_CTRL] = 0xcc,
-		[UART_DM_BCR] = 0xc8,
-};
-
 static struct of_device_id msm_hs_match_table[] = {
 	{ .compatible = "qcom,msm-hsuart-v14",
-	  .data = regmap_blsp
 	},
-	{
-	  .compatible = "qcom,msm-hsuart-v13",
-	  .data = regmap_nonblsp
-	},
-	{}
 };
 
 
@@ -404,30 +329,34 @@
 {
 	int rc = 0;
 
+	mutex_lock(&msm_uport->clk_mutex);
 	if (1 == atomic_inc_return(&msm_uport->clk_count)) {
 		msm_hs_bus_voting(msm_uport, BUS_SCALING);
 		/* Turn on core clk and iface clk */
+		if (msm_uport->pclk) {
+			rc = clk_prepare_enable(msm_uport->pclk);
+			if (rc) {
+				dev_err(msm_uport->uport.dev,
+					"%s: Could not turn on pclk [%d]\n",
+					__func__, rc);
+				mutex_unlock(&msm_uport->clk_mutex);
+				return rc;
+			}
+		}
+
 		rc = clk_prepare_enable(msm_uport->clk);
 		if (rc) {
 			dev_err(msm_uport->uport.dev,
 				"%s: Could not turn on core clk [%d]\n",
 				__func__, rc);
+			clk_disable_unprepare(msm_uport->pclk);
+			mutex_unlock(&msm_uport->clk_mutex);
 			return rc;
 		}
-
-		if (msm_uport->pclk) {
-			rc = clk_prepare_enable(msm_uport->pclk);
-			if (rc) {
-				clk_disable_unprepare(msm_uport->clk);
-				dev_err(msm_uport->uport.dev,
-					"%s: Could not turn on pclk [%d]\n",
-					__func__, rc);
-				return rc;
-			}
-		}
 		msm_uport->clk_state = MSM_HS_CLK_ON;
 		MSM_HS_DBG("%s: Clock ON successful\n", __func__);
 	}
+	mutex_unlock(&msm_uport->clk_mutex);
 
 
 	return rc;
@@ -444,6 +373,7 @@
 		return;
 	}
 
+	mutex_lock(&msm_uport->clk_mutex);
 	rc = atomic_dec_return(&msm_uport->clk_count);
 	if (0 == rc) {
 		/* Turn off the core clk and iface clk*/
@@ -455,6 +385,7 @@
 		msm_uport->clk_state = MSM_HS_CLK_OFF;
 		MSM_HS_DBG("%s: Clock OFF successful\n", __func__);
 	}
+	mutex_unlock(&msm_uport->clk_mutex);
 }
 
 /* Check if the uport line number matches with user id stored in pdata.
@@ -536,21 +467,11 @@
 	return (msm_uport->wakeup.irq > 0);
 }
 
-static inline int is_gsbi_uart(struct msm_hs_port *msm_uport)
-{
-	/* assume gsbi uart if gsbi resource found in pdata */
-	return ((msm_uport->mapped_gsbi != NULL));
-}
-static unsigned int is_blsp_uart(struct msm_hs_port *msm_uport)
-{
-	return (msm_uport->uart_type == BLSP_HSUART);
-}
-
 static void msm_hs_bus_voting(struct msm_hs_port *msm_uport, unsigned int vote)
 {
 	int ret;
 
-	if (is_blsp_uart(msm_uport) && msm_uport->bus_perf_client) {
+	if (msm_uport->bus_perf_client) {
 		MSM_HS_DBG("Bus voting:%d\n", vote);
 		ret = msm_bus_scale_client_update_request(
 				msm_uport->bus_perf_client, vote);
@@ -563,22 +484,13 @@
 static inline unsigned int msm_hs_read(struct uart_port *uport,
 				       unsigned int index)
 {
-	struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
-	unsigned int offset;
-
-	offset = *(msm_uport->reg_ptr + index);
-
-	return readl_relaxed(uport->membase + offset);
+	return readl_relaxed(uport->membase + index);
 }
 
 static inline void msm_hs_write(struct uart_port *uport, unsigned int index,
 				 unsigned int value)
 {
-	struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
-	unsigned int offset;
-
-	offset = *(msm_uport->reg_ptr + index);
-	writel_relaxed(value, uport->membase + offset);
+	writel_relaxed(value, uport->membase + index);
 }
 
 static int sps_rx_disconnect(struct sps_pipe *sps_pipe_handler)
@@ -642,55 +554,6 @@
 	MSM_HS_DBG("clk_state:%d", msm_uport->clk_state);
 }
 
-static void msm_hs_release_port(struct uart_port *port)
-{
-	struct msm_hs_port *msm_uport = UARTDM_TO_MSM(port);
-	struct platform_device *pdev = to_platform_device(port->dev);
-	struct resource *gsbi_resource;
-	resource_size_t size;
-
-	if (is_gsbi_uart(msm_uport)) {
-		iowrite32(GSBI_PROTOCOL_IDLE, msm_uport->mapped_gsbi +
-			  GSBI_CONTROL_ADDR);
-		gsbi_resource = platform_get_resource_byname(pdev,
-							     IORESOURCE_MEM,
-							     "gsbi_resource");
-		if (unlikely(!gsbi_resource))
-			return;
-
-		size = resource_size(gsbi_resource);
-		release_mem_region(gsbi_resource->start, size);
-		iounmap(msm_uport->mapped_gsbi);
-		msm_uport->mapped_gsbi = NULL;
-	}
-}
-
-static int msm_hs_request_port(struct uart_port *port)
-{
-	struct msm_hs_port *msm_uport = UARTDM_TO_MSM(port);
-	struct platform_device *pdev = to_platform_device(port->dev);
-	struct resource *gsbi_resource;
-	resource_size_t size;
-
-	gsbi_resource = platform_get_resource_byname(pdev,
-						     IORESOURCE_MEM,
-						     "gsbi_resource");
-	if (gsbi_resource) {
-		size = resource_size(gsbi_resource);
-		if (unlikely(!request_mem_region(gsbi_resource->start, size,
-						 "msm_serial_hs")))
-			return -EBUSY;
-		msm_uport->mapped_gsbi = ioremap(gsbi_resource->start,
-						 size);
-		if (!msm_uport->mapped_gsbi) {
-			release_mem_region(gsbi_resource->start, size);
-			return -EBUSY;
-		}
-	}
-	/* no gsbi uart */
-	return 0;
-}
-
 static int msm_serial_loopback_enable_set(void *data, u64 val)
 {
 	struct msm_hs_port *msm_uport = data;
@@ -703,21 +566,15 @@
 	if (val) {
 		spin_lock_irqsave(&uport->lock, flags);
 		ret = msm_hs_read(uport, UART_DM_MR2);
-		if (is_blsp_uart(msm_uport))
-			ret |= (UARTDM_MR2_LOOP_MODE_BMSK |
-				UARTDM_MR2_RFR_CTS_LOOP_MODE_BMSK);
-		else
-			ret |= UARTDM_MR2_LOOP_MODE_BMSK;
+		ret |= (UARTDM_MR2_LOOP_MODE_BMSK |
+			UARTDM_MR2_RFR_CTS_LOOP_MODE_BMSK);
 		msm_hs_write(uport, UART_DM_MR2, ret);
 		spin_unlock_irqrestore(&uport->lock, flags);
 	} else {
 		spin_lock_irqsave(&uport->lock, flags);
 		ret = msm_hs_read(uport, UART_DM_MR2);
-		if (is_blsp_uart(msm_uport))
-			ret &= ~(UARTDM_MR2_LOOP_MODE_BMSK |
-				UARTDM_MR2_RFR_CTS_LOOP_MODE_BMSK);
-		else
-			ret &= ~UARTDM_MR2_LOOP_MODE_BMSK;
+		ret &= ~(UARTDM_MR2_LOOP_MODE_BMSK |
+			UARTDM_MR2_RFR_CTS_LOOP_MODE_BMSK);
 		msm_hs_write(uport, UART_DM_MR2, ret);
 		spin_unlock_irqrestore(&uport->lock, flags);
 	}
@@ -791,19 +648,10 @@
 	sysfs_remove_file(&pdev->dev.kobj, &dev_attr_clock.attr);
 	debugfs_remove(msm_uport->loopback_dir);
 
-	dma_unmap_single(dev, msm_uport->rx.mapped_cmd_ptr, sizeof(dmov_box),
-			 DMA_TO_DEVICE);
 	dma_pool_free(msm_uport->rx.pool, msm_uport->rx.buffer,
 		      msm_uport->rx.rbuffer);
 	dma_pool_destroy(msm_uport->rx.pool);
 
-	dma_unmap_single(dev, msm_uport->rx.cmdptr_dmaaddr, sizeof(u32),
-			 DMA_TO_DEVICE);
-	dma_unmap_single(dev, msm_uport->tx.mapped_cmd_ptr_ptr, sizeof(u32),
-			 DMA_TO_DEVICE);
-	dma_unmap_single(dev, msm_uport->tx.mapped_cmd_ptr, sizeof(dmov_box),
-			 DMA_TO_DEVICE);
-
 	wake_lock_destroy(&msm_uport->rx.wake_lock);
 	wake_lock_destroy(&msm_uport->dma_wake_lock);
 	destroy_workqueue(msm_uport->hsuart_wq);
@@ -814,14 +662,6 @@
 	if (msm_uport->pclk)
 		clk_put(msm_uport->pclk);
 
-	/* Free the tx resources */
-	kfree(msm_uport->tx.command_ptr);
-	kfree(msm_uport->tx.command_ptr_ptr);
-
-	/* Free the rx resources */
-	kfree(msm_uport->rx.command_ptr);
-	kfree(msm_uport->rx.command_ptr_ptr);
-
 	iounmap(msm_uport->uport.membase);
 
 	return 0;
@@ -873,14 +713,14 @@
 	ret = sps_connect(sps_pipe_handle, sps_config);
 	if (ret) {
 		MSM_HS_ERR("msm_serial_hs: sps_connect() failed for tx!!\n"
-		"pipe_handle=0x%x ret=%d", (u32)sps_pipe_handle, ret);
+		"pipe_handle=0x%p ret=%d", sps_pipe_handle, ret);
 		return ret;
 	}
 	/* Register callback event for EOT (End of transfer) event. */
 	ret = sps_register_event(sps_pipe_handle, sps_event);
 	if (ret) {
 		MSM_HS_ERR("msm_serial_hs: sps_connect() failed for tx!!\n"
-		"pipe_handle=0x%x ret=%d", (u32)sps_pipe_handle, ret);
+		"pipe_handle=0x%p ret=%d", sps_pipe_handle, ret);
 		goto reg_event_err;
 	}
 	return 0;
@@ -914,14 +754,14 @@
 	ret = sps_connect(sps_pipe_handle, sps_config);
 	if (ret) {
 		MSM_HS_ERR("msm_serial_hs: sps_connect() failed for rx!!\n"
-		"pipe_handle=0x%x ret=%d", (u32)sps_pipe_handle, ret);
+		"pipe_handle=0x%p ret=%d", sps_pipe_handle, ret);
 		return ret;
 	}
 	/* Register callback event for DESC_DONE event. */
 	ret = sps_register_event(sps_pipe_handle, sps_event);
 	if (ret) {
 		MSM_HS_ERR("msm_serial_hs: sps_connect() failed for rx!!\n"
-		"pipe_handle=0x%x ret=%d", (u32)sps_pipe_handle, ret);
+		"pipe_handle=0x%p ret=%d", sps_pipe_handle, ret);
 		goto reg_event_err;
 	}
 	return 0;
@@ -1037,17 +877,15 @@
 	mb();
 	if (bps > 460800) {
 		uport->uartclk = bps * 16;
-		if (is_blsp_uart(msm_uport)) {
-			/* BLSP based UART supports maximum clock frequency
-			 * of 63.16 Mhz. With this (63.16 Mhz) clock frequency
-			 * UART can support baud rate of 3.94 Mbps which is
-			 * equivalent to 4 Mbps.
-			 * UART hardware is robust enough to handle this
-			 * deviation to achieve baud rate ~4 Mbps.
-			 */
-			if (bps == 4000000)
-				uport->uartclk = BLSP_UART_CLK_FMAX;
-		}
+		/* BLSP based UART supports maximum clock frequency
+		 * of 63.16 Mhz. With this (63.16 Mhz) clock frequency
+		 * UART can support baud rate of 3.94 Mbps which is
+		 * equivalent to 4 Mbps.
+		 * UART hardware is robust enough to handle this
+		 * deviation to achieve baud rate ~4 Mbps.
+		 */
+		if (bps == 4000000)
+			uport->uartclk = BLSP_UART_CLK_FMAX;
 	} else {
 		uport->uartclk = 7372800;
 	}
@@ -1139,10 +977,12 @@
 	struct msm_hs_rx *rx = &msm_uport->rx;
 	struct sps_pipe *sps_pipe_handle = rx->prod.pipe_handle;
 
-	if (msm_uport->clk_state != MSM_HS_CLK_ON) {
-		MSM_HS_WARN("%s: Failed.Clocks are OFF\n", __func__);
-		return;
-	}
+	/**
+	 * set_termios can be invoked from the framework when
+	 * the clocks are off and the client has not had a chance
+	 * to turn them on. Make sure that they are on
+	 */
+	msm_hs_clock_vote(msm_uport);
 	mutex_lock(&msm_uport->clk_mutex);
 	msm_hs_write(uport, UART_DM_IMR, 0);
 
@@ -1169,12 +1009,8 @@
 	 * suggested to do disable/reset or reset/disable at the same time.
 	 */
 	data = msm_hs_read(uport, UART_DM_DMEN);
-	if (is_blsp_uart(msm_uport)) {
-		/* Disable UARTDM RX BAM Interface */
-		data &= ~UARTDM_RX_BAM_ENABLE_BMSK;
-	} else {
-		data &= ~UARTDM_RX_DM_EN_BMSK;
-	}
+	/* Disable UARTDM RX BAM Interface */
+	data &= ~UARTDM_RX_BAM_ENABLE_BMSK;
 
 	msm_hs_write(uport, UART_DM_DMEN, data);
 
@@ -1250,37 +1086,18 @@
 	if (msm_uport->rx.flush == FLUSH_NONE) {
 		wake_lock(&msm_uport->rx.wake_lock);
 		msm_uport->rx.flush = FLUSH_DATA_INVALID;
-		/*
-		 * Before using dmov APIs make sure that
-		 * previous writel are completed. Hence
-		 * dsb requires here.
-		 */
 		mb();
-		if (is_blsp_uart(msm_uport)) {
-			if (msm_uport->rx_bam_inprogress)
-				ret = wait_event_timeout(msm_uport->rx.wait,
-					msm_uport->rx_bam_inprogress == false,
-					RX_FLUSH_COMPLETE_TIMEOUT);
-			ret = sps_rx_disconnect(sps_pipe_handle);
-			if (ret)
-				MSM_HS_ERR("%s(): sps_disconnect failed\n",
-							__func__);
-			msm_hs_spsconnect_rx(uport);
-			msm_uport->rx.flush = FLUSH_IGNORE;
-			msm_serial_hs_rx_tlet((unsigned long) &rx->tlet);
-		} else {
-			msm_uport->rx_discard_flush_issued = true;
-			/* do discard flush */
-			msm_dmov_flush(msm_uport->dma_rx_channel, 0);
-			MSM_HS_DBG("%s(): wainting for flush completion.\n",
-								__func__);
+		if (msm_uport->rx_bam_inprogress)
 			ret = wait_event_timeout(msm_uport->rx.wait,
-				msm_uport->rx_discard_flush_issued == false,
+				msm_uport->rx_bam_inprogress == false,
 				RX_FLUSH_COMPLETE_TIMEOUT);
-			if (!ret)
-				MSM_HS_ERR("%s(): Discard flush pending.\n",
-								__func__);
-		}
+		ret = sps_rx_disconnect(sps_pipe_handle);
+		if (ret)
+			MSM_HS_ERR("%s(): sps_disconnect failed\n",
+						__func__);
+		msm_hs_spsconnect_rx(uport);
+		msm_uport->rx.flush = FLUSH_IGNORE;
+		msm_serial_hs_rx_tlet((unsigned long) &rx->tlet);
 	}
 
 	/* Configure HW flow control
@@ -1302,6 +1119,7 @@
 	mutex_unlock(&msm_uport->clk_mutex);
 	MSM_HS_DBG("Exit %s\n", __func__);
 	dump_uart_hs_registers(msm_uport);
+	msm_hs_clock_unvote(msm_uport);
 }
 
 /*
@@ -1343,15 +1161,25 @@
 {
 	struct msm_hs_port *msm_uport = container_of(w, struct msm_hs_port,
 						disconnect_rx_endpoint);
+	struct uart_port *uport = &msm_uport->uport;
 	struct msm_hs_rx *rx = &msm_uport->rx;
 	struct sps_pipe *sps_pipe_handle = rx->prod.pipe_handle;
+	struct platform_device *pdev = to_platform_device(uport->dev);
+	const struct msm_serial_hs_platform_data *pdata =
+					pdev->dev.platform_data;
 	int ret = 0;
 
+	msm_hs_clock_vote(msm_uport);
 	ret = sps_rx_disconnect(sps_pipe_handle);
+	msm_hs_clock_unvote(msm_uport);
+
 	if (ret)
 		MSM_HS_ERR("%s(): sps_disconnect failed\n", __func__);
-
-	wake_lock_timeout(&msm_uport->rx.wake_lock, HZ / 2);
+	if (pdata->no_suspend_delay)
+		wake_unlock(&msm_uport->rx.wake_lock);
+	else
+		wake_lock_timeout(&msm_uport->rx.wake_lock,
+						HZ / 2);
 	msm_uport->rx.flush = FLUSH_SHUTDOWN;
 	MSM_HS_DBG("%s: Calling Completion\n", __func__);
 	wake_up(&msm_uport->bam_disconnect_wait);
@@ -1376,10 +1204,7 @@
 	if (msm_uport->clk_state != MSM_HS_CLK_OFF) {
 		/* disable dlink */
 		data = msm_hs_read(uport, UART_DM_DMEN);
-		if (is_blsp_uart(msm_uport))
-			data &= ~UARTDM_RX_BAM_ENABLE_BMSK;
-		else
-			data &= ~UARTDM_RX_DM_EN_BMSK;
+		data &= ~UARTDM_RX_BAM_ENABLE_BMSK;
 		msm_hs_write(uport, UART_DM_DMEN, data);
 
 		/* calling DMOV or CLOCK API. Hence mb() */
@@ -1388,19 +1213,11 @@
 	/* Disable the receiver */
 	if (msm_uport->rx.flush == FLUSH_NONE) {
 		wake_lock(&msm_uport->rx.wake_lock);
-		if (is_blsp_uart(msm_uport)) {
-			msm_uport->rx.flush = FLUSH_STOP;
-			/* workqueue for BAM rx endpoint disconnect */
-			queue_work(msm_uport->hsuart_wq,
-				&msm_uport->disconnect_rx_endpoint);
-		} else {
-			/* do discard flush */
-			msm_dmov_flush(msm_uport->dma_rx_channel, 0);
-		}
-	}
-	if (!is_blsp_uart(msm_uport) && msm_uport->rx.flush != FLUSH_SHUTDOWN)
 		msm_uport->rx.flush = FLUSH_STOP;
-
+		/* workqueue for BAM rx endpoint disconnect */
+		queue_work(msm_uport->hsuart_wq,
+			&msm_uport->disconnect_rx_endpoint);
+	}
 }
 
 /*  Transmit the next chunk of data */
@@ -1424,6 +1241,7 @@
 								__func__);
 			queue_work(msm_uport->hsuart_wq,
 						&msm_uport->clock_off_w);
+			wake_up(&msm_uport->tx.wait);
 		}
 		return;
 	}
@@ -1450,43 +1268,15 @@
 	dma_sync_single_for_device(uport->dev, aligned_src_addr,
 			aligned_tx_count, DMA_TO_DEVICE);
 
-	if (is_blsp_uart(msm_uport))
-		tx->tx_count = tx_count;
-	else {
-		tx->command_ptr->num_rows =
-				(((tx_count + 15) >> 4) << 16) |
-				((tx_count + 15) >> 4);
-		tx->command_ptr->src_row_addr = src_addr;
-
-		dma_sync_single_for_device(uport->dev, tx->mapped_cmd_ptr,
-				sizeof(dmov_box), DMA_TO_DEVICE);
-
-		*tx->command_ptr_ptr = CMD_PTR_LP |
-				DMOV_CMD_ADDR(tx->mapped_cmd_ptr);
-		/* Save tx_count to use in Callback */
-		tx->tx_count = tx_count;
-		msm_hs_write(uport, UART_DM_NCF_TX, tx_count);
-		msm_uport->imr_reg &= ~UARTDM_ISR_TX_READY_BMSK;
-		msm_hs_write(uport, UART_DM_IMR, msm_uport->imr_reg);
-		/* Calling next DMOV API. Hence mb() here. */
-		mb();
-
-	}
+	tx->tx_count = tx_count;
 
 	msm_uport->tx.flush = FLUSH_NONE;
 
-	if (is_blsp_uart(msm_uport)) {
-		sps_pipe_handle = tx->cons.pipe_handle;
-		/* Queue transfer request to SPS */
-		sps_transfer_one(sps_pipe_handle, src_addr, tx_count,
-					msm_uport, flags);
-	} else {
-		dma_sync_single_for_device(uport->dev, tx->mapped_cmd_ptr_ptr,
-			sizeof(u32), DMA_TO_DEVICE);
+	sps_pipe_handle = tx->cons.pipe_handle;
+	/* Queue transfer request to SPS */
+	sps_transfer_one(sps_pipe_handle, src_addr, tx_count,
+				msm_uport, flags);
 
-		msm_dmov_enqueue_cmd(msm_uport->dma_tx_channel, &tx->xfer);
-
-	}
 	MSM_HS_DBG("%s:Enqueue Tx Cmd\n", __func__);
 	dump_uart_hs_registers(msm_uport);
 }
@@ -1524,43 +1314,34 @@
 	 * disable in set_termios before configuring baud rate.
 	 */
 	data = msm_hs_read(uport, UART_DM_DMEN);
-	if (is_blsp_uart(msm_uport)) {
-		/* Enable UARTDM Rx BAM Interface */
-		data |= UARTDM_RX_BAM_ENABLE_BMSK;
-	} else {
-		data |= UARTDM_RX_DM_EN_BMSK;
-	}
+	/* Enable UARTDM Rx BAM Interface */
+	data |= UARTDM_RX_BAM_ENABLE_BMSK;
 
 	msm_hs_write(uport, UART_DM_DMEN, data);
 	msm_hs_write(uport, UART_DM_IMR, msm_uport->imr_reg);
 	/* Calling next DMOV API. Hence mb() here. */
 	mb();
 
-	if (is_blsp_uart(msm_uport)) {
-		/*
-		 * RX-transfer will be automatically re-activated
-		 * after last data of previous transfer was read.
-		 */
-		data = (RX_STALE_AUTO_RE_EN | RX_TRANS_AUTO_RE_ACTIVATE |
-					RX_DMRX_CYCLIC_EN);
-		msm_hs_write(uport, UART_DM_RX_TRANS_CTRL, data);
-		/* Issue RX BAM Start IFC command */
-		msm_hs_write(uport, UART_DM_CR, START_RX_BAM_IFC);
-		mb();
-	}
+	/*
+	 * RX-transfer will be automatically re-activated
+	 * after last data of previous transfer was read.
+	 */
+	data = (RX_STALE_AUTO_RE_EN | RX_TRANS_AUTO_RE_ACTIVATE |
+				RX_DMRX_CYCLIC_EN);
+	msm_hs_write(uport, UART_DM_RX_TRANS_CTRL, data);
+	/* Issue RX BAM Start IFC command */
+	msm_hs_write(uport, UART_DM_CR, START_RX_BAM_IFC);
+	mb();
 
 	msm_uport->rx.flush = FLUSH_NONE;
-
-	if (is_blsp_uart(msm_uport)) {
-		msm_uport->rx_bam_inprogress = true;
-		sps_pipe_handle = rx->prod.pipe_handle;
-		/* Queue transfer request to SPS */
-		sps_transfer_one(sps_pipe_handle, rx->rbuffer,
-			UARTDM_RX_BUF_SIZE, msm_uport, flags);
-		msm_uport->rx_bam_inprogress = false;
-		msm_uport->rx.rx_cmd_queued = true;
-		wake_up(&msm_uport->rx.wait);
-	}
+	msm_uport->rx_bam_inprogress = true;
+	sps_pipe_handle = rx->prod.pipe_handle;
+	/* Queue transfer request to SPS */
+	sps_transfer_one(sps_pipe_handle, rx->rbuffer,
+		UARTDM_RX_BUF_SIZE, msm_uport, flags);
+	msm_uport->rx_bam_inprogress = false;
+	msm_uport->rx.rx_cmd_queued = true;
+	wake_up(&msm_uport->rx.wait);
 	MSM_HS_DBG("%s:Enqueue Rx Cmd\n", __func__);
 	dump_uart_hs_registers(msm_uport);
 }
@@ -1631,6 +1412,8 @@
 	struct msm_hs_rx *rx;
 	struct sps_pipe *sps_pipe_handle;
 	u32 sps_flags = SPS_IOVEC_FLAG_INT;
+	struct platform_device *pdev;
+	const struct msm_serial_hs_platform_data *pdata;
 
 	msm_uport = container_of((struct tasklet_struct *)tlet_ptr,
 				 struct msm_hs_port, rx.tlet);
@@ -1638,6 +1421,8 @@
 	tty = uport->state->port.tty;
 	notify = &msm_uport->notify;
 	rx = &msm_uport->rx;
+	pdev = to_platform_device(uport->dev);
+	pdata = pdev->dev.platform_data;
 
 	msm_uport->rx.rx_cmd_queued = false;
 	msm_uport->rx.rx_cmd_exec = false;
@@ -1646,9 +1431,6 @@
 
 	spin_lock_irqsave(&uport->lock, flags);
 
-	if (!is_blsp_uart(msm_uport))
-		msm_hs_write(uport, UART_DM_CR, STALE_EVENT_DISABLE);
-
 	MSM_HS_DBG("In %s\n", __func__);
 	dump_uart_hs_registers(msm_uport);
 
@@ -1705,16 +1487,7 @@
 	if (flush >= FLUSH_DATA_INVALID)
 		goto out;
 
-	if (is_blsp_uart(msm_uport)) {
-		rx_count = msm_uport->rx_count_callback;
-	} else {
-		if (msm_uport->clk_state == MSM_HS_CLK_ON) {
-			rx_count = msm_hs_read(uport, UART_DM_RX_TOTAL_SNAP);
-			/* order the read of rx.buffer */
-			rmb();
-		} else
-			MSM_HS_WARN("%s: Failed.Clocks are OFF\n", __func__);
-	}
+	rx_count = msm_uport->rx_count_callback;
 
 	MSM_HS_DBG("%s():[UART_RX]<%d>\n", __func__, rx_count);
 	hex_dump_ipc("HSUART Read: ", msm_uport->rx.buffer, rx_count);
@@ -1729,20 +1502,16 @@
 		}
 	}
 	if (!msm_uport->rx.buffer_pending && !msm_uport->rx.rx_cmd_queued) {
-		if (is_blsp_uart(msm_uport)) {
-			msm_uport->rx.flush = FLUSH_NONE;
-			msm_uport->rx_bam_inprogress = true;
-			sps_pipe_handle = rx->prod.pipe_handle;
-			MSM_HS_DBG("Queing bam descriptor\n");
-			/* Queue transfer request to SPS */
-			sps_transfer_one(sps_pipe_handle, rx->rbuffer,
-				UARTDM_RX_BUF_SIZE, msm_uport, sps_flags);
-			msm_uport->rx_bam_inprogress = false;
-			msm_uport->rx.rx_cmd_queued = true;
-			wake_up(&msm_uport->rx.wait);
-
-		} else
-			msm_hs_start_rx_locked(uport);
+		msm_uport->rx.flush = FLUSH_NONE;
+		msm_uport->rx_bam_inprogress = true;
+		sps_pipe_handle = rx->prod.pipe_handle;
+		MSM_HS_DBG("Queing bam descriptor\n");
+		/* Queue transfer request to SPS */
+		sps_transfer_one(sps_pipe_handle, rx->rbuffer,
+			UARTDM_RX_BUF_SIZE, msm_uport, sps_flags);
+		msm_uport->rx_bam_inprogress = false;
+		msm_uport->rx.rx_cmd_queued = true;
+		wake_up(&msm_uport->rx.wait);
 	}
 out:
 	if (msm_uport->rx.buffer_pending) {
@@ -1751,8 +1520,12 @@
 				      , msecs_to_jiffies(RETRY_TIMEOUT));
 	}
 	/* release wakelock in 500ms, not immediately, because higher layers
-	 * don't always take wakelocks when they should */
-	wake_lock_timeout(&msm_uport->rx.wake_lock, HZ / 2);
+	 * don't always take wakelocks when they should
+	 */
+	if (pdata->no_suspend_delay)
+		wake_unlock(&msm_uport->rx.wake_lock);
+	else
+		wake_lock_timeout(&msm_uport->rx.wake_lock, HZ / 2);
 	/* tty_flip_buffer_push() might call msm_hs_start(), so unlock */
 	spin_unlock_irqrestore(&uport->lock, flags);
 	if (flush < FLUSH_DATA_INVALID)
@@ -1767,12 +1540,9 @@
 	if (msm_uport->clk_state != MSM_HS_CLK_ON) {
 		MSM_HS_WARN("%s: Failed.Clocks are OFF\n", __func__);
 	}
-	if (msm_uport->tx.tx_ready_int_en == 0) {
-		if (!is_blsp_uart(msm_uport))
-			msm_uport->tx.tx_ready_int_en = 1;
-		if (msm_uport->tx.dma_in_flight == 0)
+	if ((msm_uport->tx.tx_ready_int_en == 0) &&
+		(msm_uport->tx.dma_in_flight == 0))
 			msm_hs_submit_tx_locked(uport);
-	}
 }
 
 /**
@@ -1792,7 +1562,7 @@
 
 	msm_uport->notify = *notify;
 	MSM_HS_DBG("%s: ev_id=%d, addr=0x%x, size=0x%x, flags=0x%x, line=%d\n",
-			__func__, notify->event_id,
+		 __func__, notify->event_id,
 	notify->data.transfer.iovec.addr,
 	notify->data.transfer.iovec.size,
 	notify->data.transfer.iovec.flags,
@@ -1801,30 +1571,6 @@
 	tasklet_schedule(&msm_uport->tx.tlet);
 }
 
-/*
- *  This routine is called when we are done with a DMA transfer
- *
- *  This routine is registered with Data mover when we set
- *  up a Data Mover transfer. It is called from Data mover ISR
- *  when the DMA transfer is done.
- */
-static void msm_hs_dmov_tx_callback(struct msm_dmov_cmd *cmd_ptr,
-					unsigned int result,
-					struct msm_dmov_errdata *err)
-{
-	struct msm_hs_port *msm_uport;
-
-	msm_uport = container_of(cmd_ptr, struct msm_hs_port, tx.xfer);
-	if (msm_uport->tx.flush == FLUSH_STOP)
-		/* DMA FLUSH unsuccesfful */
-		WARN_ON(!(result & DMOV_RSLT_FLUSH));
-	else
-		/* DMA did not finish properly */
-		WARN_ON(!(result & DMOV_RSLT_DONE));
-
-	tasklet_schedule(&msm_uport->tx.tlet);
-}
-
 static void msm_serial_hs_tx_tlet(unsigned long tlet_ptr)
 {
 	unsigned long flags;
@@ -1868,15 +1614,6 @@
 		return;
 	}
 
-	/* TX_READY_BMSK only if non BAM mode */
-	if (!is_blsp_uart(msm_uport)) {
-		msm_uport->imr_reg |= UARTDM_ISR_TX_READY_BMSK;
-		msm_hs_write(&(msm_uport->uport), UART_DM_IMR,
-					msm_uport->imr_reg);
-		/* Calling clk API. Hence mb() requires. */
-		mb();
-	}
-
 	spin_unlock_irqrestore(&(msm_uport->uport.lock), flags);
 	MSM_HS_DBG("In %s()\n", __func__);
 	dump_uart_hs_registers(msm_uport);
@@ -1918,39 +1655,6 @@
 }
 
 /*
- * This routine is called when we are done with a DMA transfer or the
- * a flush has been sent to the data mover driver.
- *
- * This routine is registered with Data mover when we set up a Data Mover
- *  transfer. It is called from Data mover ISR when the DMA transfer is done.
- */
-static void msm_hs_dmov_rx_callback(struct msm_dmov_cmd *cmd_ptr,
-					unsigned int result,
-					struct msm_dmov_errdata *err)
-{
-	struct msm_hs_port *msm_uport;
-	struct uart_port *uport;
-	unsigned long flags;
-
-	msm_uport = container_of(cmd_ptr, struct msm_hs_port, rx.xfer);
-	uport = &(msm_uport->uport);
-
-	MSM_HS_DBG("%s(): called result:%x\n", __func__, result);
-	if (!(result & DMOV_RSLT_ERROR)) {
-		if (result & DMOV_RSLT_FLUSH) {
-			if (msm_uport->rx_discard_flush_issued) {
-				spin_lock_irqsave(&uport->lock, flags);
-				msm_uport->rx_discard_flush_issued = false;
-				spin_unlock_irqrestore(&uport->lock, flags);
-				wake_up(&msm_uport->rx.wait);
-			}
-		}
-	}
-
-	tasklet_schedule(&msm_uport->rx.tlet);
-}
-
-/*
  *  Standard API, Current states of modem control inputs
  *
  * Since CTS can be handled entirely by HARDWARE we always
@@ -2060,24 +1764,9 @@
 
 static void msm_hs_config_port(struct uart_port *uport, int cfg_flags)
 {
-	unsigned long flags;
-	struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
-
-	if (cfg_flags & UART_CONFIG_TYPE) {
+	if (cfg_flags & UART_CONFIG_TYPE)
 		uport->type = PORT_MSM;
-		msm_hs_request_port(uport);
-	}
 
-	if (is_gsbi_uart(msm_uport)) {
-		if (msm_uport->pclk)
-			clk_prepare_enable(msm_uport->pclk);
-		spin_lock_irqsave(&uport->lock, flags);
-		iowrite32(GSBI_PROTOCOL_UART, msm_uport->mapped_gsbi +
-			  GSBI_CONTROL_ADDR);
-		spin_unlock_irqrestore(&uport->lock, flags);
-		if (msm_uport->pclk)
-			clk_disable_unprepare(msm_uport->pclk);
-	}
 }
 
 /*  Handle CTS changes (Called from interrupt handler) */
@@ -2115,6 +1804,11 @@
 	mutex_lock(&msm_uport->clk_mutex);
 	spin_lock_irqsave(&uport->lock, flags);
 
+	if (msm_uport->clk_state == MSM_HS_CLK_OFF) {
+		spin_unlock_irqrestore(&uport->lock, flags);
+		mutex_unlock(&msm_uport->clk_mutex);
+		return 1;
+	}
 	MSM_HS_DBG("In %s:\n", __func__);
 	/* Cancel if tx tty buffer is not empty, dma is in flight,
 	 * or tx fifo is not empty
@@ -2122,8 +1816,6 @@
 	if (msm_uport->clk_state != MSM_HS_CLK_REQUEST_OFF ||
 	    !uart_circ_empty(tx_buf) || msm_uport->tx.dma_in_flight ||
 	    msm_uport->imr_reg & UARTDM_ISR_TXLEV_BMSK) {
-		spin_unlock_irqrestore(&uport->lock, flags);
-		mutex_unlock(&msm_uport->clk_mutex);
 		if (msm_uport->clk_state == MSM_HS_CLK_REQUEST_OFF) {
 			msm_uport->clk_state = MSM_HS_CLK_ON;
 			/* Pulling RFR line high */
@@ -2134,6 +1826,8 @@
 			msm_hs_write(uport, UART_DM_MR1, data);
 			mb();
 		}
+		spin_unlock_irqrestore(&uport->lock, flags);
+		mutex_unlock(&msm_uport->clk_mutex);
 		MSM_HS_DBG("%s(): clkstate %d", __func__, msm_uport->clk_state);
 		return -1;
 	}
@@ -2150,11 +1844,8 @@
 	}
 
 	if (msm_uport->rx.flush != FLUSH_SHUTDOWN) {
-		if (msm_uport->rx.flush == FLUSH_NONE) {
+		if (msm_uport->rx.flush == FLUSH_NONE)
 			msm_hs_stop_rx_locked(uport);
-			if (!is_blsp_uart(msm_uport))
-				msm_uport->rx_discard_flush_issued = true;
-		}
 
 		MSM_HS_DBG("%s: rx.flush %d clk_state %d\n", __func__,
 			msm_uport->rx.flush, msm_uport->clk_state);
@@ -2174,7 +1865,9 @@
 	mb();
 
 	/* we really want to clock off */
+	mutex_unlock(&msm_uport->clk_mutex);
 	msm_hs_clock_unvote(msm_uport);
+	mutex_lock(&msm_uport->clk_mutex);
 
 	spin_lock_irqsave(&uport->lock, flags);
 	if (use_low_power_wakeup(msm_uport)) {
@@ -2247,11 +1940,6 @@
 		 */
 		mb();
 		MSM_HS_DBG("%s:Stal Interrupt\n", __func__);
-
-		if (!is_blsp_uart(msm_uport) && (rx->flush == FLUSH_NONE)) {
-			rx->flush = FLUSH_DATA_READY;
-			msm_dmov_flush(msm_uport->dma_rx_channel, 1);
-		}
 	}
 	/* tx ready interrupt */
 	if (isr_status & UARTDM_ISR_TX_READY_BMSK) {
@@ -2390,7 +2078,9 @@
 			disable_irq_nosync(msm_uport->wakeup.irq);
 		spin_unlock_irqrestore(&uport->lock, flags);
 
+		mutex_unlock(&msm_uport->clk_mutex);
 		ret = msm_hs_clock_vote(msm_uport);
+		mutex_lock(&msm_uport->clk_mutex);
 		if (ret) {
 			MSM_HS_INFO("Clock ON Failure"
 			"For UART CLK Stalling HSUART\n");
@@ -2405,8 +2095,10 @@
 			spin_unlock_irqrestore(&uport->lock, flags);
 			MSM_HS_DBG("%s:Calling wait forxcompletion\n",
 					__func__);
+			mutex_unlock(&msm_uport->clk_mutex);
 			ret = wait_event_timeout(msm_uport->bam_disconnect_wait,
 				msm_uport->rx.flush == FLUSH_SHUTDOWN, 300);
+			mutex_lock(&msm_uport->clk_mutex);
 			if (!ret)
 				MSM_HS_ERR("BAM Disconnect not happened\n");
 			spin_lock_irqsave(&uport->lock, flags);
@@ -2420,10 +2112,7 @@
 		    msm_uport->rx.flush == FLUSH_SHUTDOWN) {
 			msm_hs_write(uport, UART_DM_CR, RESET_RX);
 			data = msm_hs_read(uport, UART_DM_DMEN);
-			if (is_blsp_uart(msm_uport))
-				data |= UARTDM_RX_BAM_ENABLE_BMSK;
-			else
-				data |= UARTDM_RX_DM_EN_BMSK;
+			data |= UARTDM_RX_BAM_ENABLE_BMSK;
 			msm_hs_write(uport, UART_DM_DMEN, data);
 			/* Complete above device write. Hence mb() here. */
 			mb();
@@ -2431,11 +2120,9 @@
 
 		MSM_HS_DBG("%s: rx.flush %d\n", __func__, msm_uport->rx.flush);
 		if (msm_uport->rx.flush == FLUSH_SHUTDOWN) {
-			if (is_blsp_uart(msm_uport)) {
-				spin_unlock_irqrestore(&uport->lock, flags);
-				msm_hs_spsconnect_rx(uport);
-				spin_lock_irqsave(&uport->lock, flags);
-			}
+			spin_unlock_irqrestore(&uport->lock, flags);
+			msm_hs_spsconnect_rx(uport);
+			spin_lock_irqsave(&uport->lock, flags);
 			msm_hs_start_rx_locked(uport);
 		}
 		if (msm_uport->rx.flush == FLUSH_STOP)
@@ -2601,9 +2288,6 @@
 	unsigned long flags;
 	unsigned int data;
 	struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
-	struct platform_device *pdev = to_platform_device(uport->dev);
-	const struct msm_serial_hs_platform_data *pdata =
-					pdev->dev.platform_data;
 	struct circ_buf *tx_buf = &uport->state->xmit;
 	struct msm_hs_tx *tx = &msm_uport->tx;
 	struct msm_hs_rx *rx = &msm_uport->rx;
@@ -2626,33 +2310,25 @@
 		return ret;
 	}
 
-	if (is_blsp_uart(msm_uport)) {
-		ret = msm_hs_config_uart_gpios(uport);
-		if (ret) {
-			MSM_HS_ERR("Uart GPIO request failed\n");
-			goto deinit_uart_clk;
-		}
-	} else {
-		if (pdata && pdata->gpio_config)
-			if (unlikely(pdata->gpio_config(1)))
-				dev_err(uport->dev, "Cannot configure gpios\n");
+	ret = msm_hs_config_uart_gpios(uport);
+	if (ret) {
+		MSM_HS_ERR("Uart GPIO request failed\n");
+		goto deinit_uart_clk;
 	}
 
 	/* SPS Connect for BAM endpoints */
-	if (is_blsp_uart(msm_uport)) {
-		/* SPS connect for TX */
-		ret = msm_hs_spsconnect_tx(uport);
-		if (ret) {
-			MSM_HS_ERR("msm_serial_hs: SPS connect failed for TX");
-			goto unconfig_uart_gpios;
-		}
+	/* SPS connect for TX */
+	ret = msm_hs_spsconnect_tx(uport);
+	if (ret) {
+		MSM_HS_ERR("msm_serial_hs: SPS connect failed for TX");
+		goto unconfig_uart_gpios;
+	}
 
-		/* SPS connect for RX */
-		ret = msm_hs_spsconnect_rx(uport);
-		if (ret) {
-			MSM_HS_ERR("msm_serial_hs: SPS connect failed for RX");
-			goto sps_disconnect_tx;
-		}
+	/* SPS connect for RX */
+	ret = msm_hs_spsconnect_rx(uport);
+	if (ret) {
+		MSM_HS_ERR("msm_serial_hs: SPS connect failed for RX");
+		goto sps_disconnect_tx;
 	}
 
 	data = (UARTDM_BCR_TX_BREAK_DISABLE | UARTDM_BCR_STALE_IRQ_EMPTY |
@@ -2675,13 +2351,8 @@
 		msm_hs_write(uport, UART_DM_IPR, data);
 	}
 
-	if (is_blsp_uart(msm_uport)) {
-		/* Enable BAM mode */
-		data  = UARTDM_TX_BAM_ENABLE_BMSK | UARTDM_RX_BAM_ENABLE_BMSK;
-	} else {
-		/* Enable Data Mover Mode */
-		data = UARTDM_TX_DM_EN_BMSK | UARTDM_RX_DM_EN_BMSK;
-	}
+	/* Enable BAM mode */
+	data  = UARTDM_TX_BAM_ENABLE_BMSK | UARTDM_RX_BAM_ENABLE_BMSK;
 	msm_hs_write(uport, UART_DM_DMEN, data);
 
 	/* Reset TX */
@@ -2703,23 +2374,6 @@
 	tx->dma_in_flight = 0;
 	rx->rx_cmd_exec = false;
 
-	if (!is_blsp_uart(msm_uport)) {
-		tx->xfer.complete_func = msm_hs_dmov_tx_callback;
-
-		tx->command_ptr->cmd = CMD_LC |
-			CMD_DST_CRCI(msm_uport->dma_tx_crci) | CMD_MODE_BOX;
-
-		tx->command_ptr->src_dst_len = (MSM_UARTDM_BURST_SIZE << 16)
-					   | (MSM_UARTDM_BURST_SIZE);
-
-		tx->command_ptr->row_offset = (MSM_UARTDM_BURST_SIZE << 16);
-
-		tx->command_ptr->dst_row_addr =
-			msm_uport->uport.mapbase + UARTDM_TF_ADDR;
-
-		msm_uport->imr_reg |= UARTDM_ISR_RXSTALE_BMSK;
-	}
-
 	/* Enable reading the current CTS, no harm even if CTS is ignored */
 	msm_uport->imr_reg |= UARTDM_ISR_CURRENT_CTS_BMSK;
 
@@ -2774,14 +2428,11 @@
 	if (use_low_power_wakeup(msm_uport))
 		irq_set_irq_wake(msm_uport->wakeup.irq, 0);
 sps_disconnect_rx:
-	if (is_blsp_uart(msm_uport))
-		sps_disconnect(sps_pipe_handle_rx);
+	sps_disconnect(sps_pipe_handle_rx);
 sps_disconnect_tx:
-	if (is_blsp_uart(msm_uport))
-		sps_disconnect(sps_pipe_handle_tx);
+	sps_disconnect(sps_pipe_handle_tx);
 unconfig_uart_gpios:
-	if (is_blsp_uart(msm_uport))
-		msm_hs_unconfig_uart_gpios(uport);
+	msm_hs_unconfig_uart_gpios(uport);
 deinit_uart_clk:
 	msm_hs_clock_unvote(msm_uport);
 	wake_unlock(&msm_uport->dma_wake_lock);
@@ -2814,7 +2465,7 @@
 	if (!rx->pool) {
 		MSM_HS_ERR("%s(): cannot allocate rx_buffer_pool", __func__);
 		ret = -ENOMEM;
-		goto exit_tasket_init;
+		goto exit_tasklet_init;
 	}
 
 	rx->buffer = dma_pool_alloc(rx->pool, GFP_KERNEL, &rx->rbuffer);
@@ -2825,99 +2476,15 @@
 	}
 
 	/* Set up Uart Receive */
-	if (is_blsp_uart(msm_uport))
-		msm_hs_write(uport, UART_DM_RFWR, 32);
-	else
-		msm_hs_write(uport, UART_DM_RFWR, 0);
+	msm_hs_write(uport, UART_DM_RFWR, 32);
 
 	INIT_DELAYED_WORK(&rx->flip_insert_work, flip_insert_work);
 
-	if (is_blsp_uart(msm_uport))
-		return ret;
-
-	/* Allocate the command pointer. Needs to be 64 bit aligned */
-	tx->command_ptr = kmalloc(sizeof(dmov_box), GFP_KERNEL | __GFP_DMA);
-	if (!tx->command_ptr) {
-		return -ENOMEM;
-		goto free_rx_buffer;
-	}
-
-	tx->command_ptr_ptr = kmalloc(sizeof(u32), GFP_KERNEL | __GFP_DMA);
-	if (!tx->command_ptr_ptr) {
-		ret = -ENOMEM;
-		goto free_tx_command_ptr;
-	}
-
-	tx->mapped_cmd_ptr = dma_map_single(uport->dev, tx->command_ptr,
-					sizeof(dmov_box), DMA_TO_DEVICE);
-	tx->mapped_cmd_ptr_ptr = dma_map_single(uport->dev,
-						tx->command_ptr_ptr,
-						sizeof(u32), DMA_TO_DEVICE);
-	tx->xfer.cmdptr = DMOV_CMD_ADDR(tx->mapped_cmd_ptr_ptr);
-
-	/* Allocate the command pointer. Needs to be 64 bit aligned */
-	rx->command_ptr = kmalloc(sizeof(dmov_box), GFP_KERNEL | __GFP_DMA);
-	if (!rx->command_ptr) {
-		MSM_HS_ERR("%s(): cannot allocate rx->command_ptr", __func__);
-		ret = -ENOMEM;
-		goto free_tx_command_ptr_ptr;
-	}
-
-	rx->command_ptr_ptr = kmalloc(sizeof(u32), GFP_KERNEL | __GFP_DMA);
-	if (!rx->command_ptr_ptr) {
-		MSM_HS_ERR("%s(): cannot allocate rx->command_ptr_ptr",
-			 __func__);
-		ret = -ENOMEM;
-		goto free_rx_command_ptr;
-	}
-
-	rx->command_ptr->num_rows = ((UARTDM_RX_BUF_SIZE >> 4) << 16) |
-					 (UARTDM_RX_BUF_SIZE >> 4);
-
-	rx->command_ptr->dst_row_addr = rx->rbuffer;
-
-	rx->xfer.complete_func = msm_hs_dmov_rx_callback;
-
-	rx->command_ptr->cmd = CMD_LC |
-	    CMD_SRC_CRCI(msm_uport->dma_rx_crci) | CMD_MODE_BOX;
-
-	rx->command_ptr->src_dst_len = (MSM_UARTDM_BURST_SIZE << 16)
-					   | (MSM_UARTDM_BURST_SIZE);
-	rx->command_ptr->row_offset =  MSM_UARTDM_BURST_SIZE;
-	rx->command_ptr->src_row_addr = uport->mapbase + UARTDM_RF_ADDR;
-
-	rx->mapped_cmd_ptr = dma_map_single(uport->dev, rx->command_ptr,
-					    sizeof(dmov_box), DMA_TO_DEVICE);
-
-	*rx->command_ptr_ptr = CMD_PTR_LP | DMOV_CMD_ADDR(rx->mapped_cmd_ptr);
-
-	rx->cmdptr_dmaaddr = dma_map_single(uport->dev, rx->command_ptr_ptr,
-					    sizeof(u32), DMA_TO_DEVICE);
-	rx->xfer.cmdptr = DMOV_CMD_ADDR(rx->cmdptr_dmaaddr);
-
 	return ret;
-
-free_rx_command_ptr:
-	kfree(rx->command_ptr);
-
-free_tx_command_ptr_ptr:
-	kfree(msm_uport->tx.command_ptr_ptr);
-	dma_unmap_single(uport->dev, msm_uport->tx.mapped_cmd_ptr_ptr,
-			sizeof(u32), DMA_TO_DEVICE);
-	dma_unmap_single(uport->dev, msm_uport->tx.mapped_cmd_ptr,
-			sizeof(dmov_box), DMA_TO_DEVICE);
-
-free_tx_command_ptr:
-	kfree(msm_uport->tx.command_ptr);
-
-free_rx_buffer:
-	dma_pool_free(msm_uport->rx.pool, msm_uport->rx.buffer,
-			msm_uport->rx.rbuffer);
-
 free_pool:
 	dma_pool_destroy(msm_uport->rx.pool);
 
-exit_tasket_init:
+exit_tasklet_init:
 	wake_lock_destroy(&msm_uport->rx.wake_lock);
 	wake_lock_destroy(&msm_uport->dma_wake_lock);
 	tasklet_kill(&msm_uport->tx.tlet);
@@ -2963,6 +2530,9 @@
 	if (pdata->uart_rfr_gpio < 0)
 		MSM_HS_DBG("uart_rfr_gpio is not available\n");
 
+	pdata->no_suspend_delay = of_property_read_bool(node,
+				"qcom,no-suspend-delay");
+
 	pdata->inject_rx_on_wakeup = of_property_read_bool(node,
 				"qcom,inject-rx-on-wakeup");
 
@@ -3058,8 +2628,8 @@
 	/* Allocate endpoint context */
 	sps_pipe_handle = sps_alloc_endpoint();
 	if (!sps_pipe_handle) {
-		MSM_HS_ERR("msm_serial_hs: sps_alloc_endpoint() failed!!\n"
-			"is_producer=%d", is_producer);
+		MSM_HS_ERR("%s(): sps_alloc_endpoint() failed!!\n"
+			"is_producer=%d", __func__, is_producer);
 		rc = -ENOMEM;
 		goto out;
 	}
@@ -3067,8 +2637,8 @@
 	/* Get default connection configuration for an endpoint */
 	rc = sps_get_config(sps_pipe_handle, sps_config);
 	if (rc) {
-		MSM_HS_ERR("msm_serial_hs: sps_get_config() failed!!\n"
-		"pipe_handle=0x%x rc=%d", (u32)sps_pipe_handle, rc);
+		MSM_HS_ERR("%s(): failed! pipe_handle=0x%p rc=%d",
+			__func__, sps_pipe_handle, rc);
 		goto get_config_err;
 	}
 
@@ -3120,10 +2690,10 @@
 
 	/* Now save the sps pipe handle */
 	ep->pipe_handle = sps_pipe_handle;
-	MSM_HS_DBG("msm_serial_hs: success !! %s: pipe_handle=0x%x\n"
-		"desc_fifo.phys_base=0x%llx\n",
+	MSM_HS_DBG("msm_serial_hs: success !! %s: pipe_handle=0x%p\n"
+		"desc_fifo.phys_base=0x%pa\n",
 		is_producer ? "READ" : "WRITE",
-		(u32) sps_pipe_handle, (u64) sps_config->desc.phys_base);
+		sps_pipe_handle, &sps_config->desc.phys_base);
 	return 0;
 
 get_config_err:
@@ -3164,10 +2734,10 @@
 		bam.irq = (u32)msm_uport->bam_irq;
 		bam.manage = SPS_BAM_MGR_DEVICE_REMOTE;
 
-		MSM_HS_DBG("msm_serial_hs: bam physical base=0x%x\n",
-							(u32)bam.phys_addr);
-		MSM_HS_DBG("msm_serial_hs: bam virtual base=0x%x\n",
-							(u32)bam.virt_addr);
+		MSM_HS_DBG("msm_serial_hs: bam physical base=0x%pa\n",
+							&bam.phys_addr);
+		MSM_HS_DBG("msm_serial_hs: bam virtual base=0x%p\n",
+							bam.virt_addr);
 
 		/* Register UART Peripheral BAM device to SPS driver */
 		rc = sps_register_bam_device(&bam, &bam_handle);
@@ -3247,10 +2817,8 @@
 	struct msm_hs_port *msm_uport;
 	struct resource *core_resource;
 	struct resource *bam_resource;
-	struct resource *resource;
 	int core_irqres, bam_irqres, wakeup_irqres;
 	struct msm_serial_hs_platform_data *pdata = pdev->dev.platform_data;
-	const struct of_device_id *match;
 	unsigned long data;
 
 	if (pdev->dev.of_node) {
@@ -3288,97 +2856,71 @@
 	uport = &msm_uport->uport;
 	uport->dev = &pdev->dev;
 
-	match = of_match_device(msm_hs_match_table, &pdev->dev);
-	if (match)
-		msm_uport->reg_ptr = (unsigned int *)match->data;
-	else if (is_gsbi_uart(msm_uport))
-		msm_uport->reg_ptr = regmap_nonblsp;
-
 	if (pdev->dev.of_node)
 		msm_uport->uart_type = BLSP_HSUART;
 
 	/* Get required resources for BAM HSUART */
-	if (is_blsp_uart(msm_uport)) {
-		core_resource = platform_get_resource_byname(pdev,
-					IORESOURCE_MEM, "core_mem");
-		bam_resource = platform_get_resource_byname(pdev,
-					IORESOURCE_MEM, "bam_mem");
-		core_irqres = platform_get_irq_byname(pdev, "core_irq");
-		bam_irqres = platform_get_irq_byname(pdev, "bam_irq");
-		wakeup_irqres = platform_get_irq_byname(pdev, "wakeup_irq");
+	core_resource = platform_get_resource_byname(pdev,
+				IORESOURCE_MEM, "core_mem");
+	if (!core_resource) {
+		MSM_HS_ERR("Invalid core HSUART Resources.\n");
+		return -ENXIO;
+	}
+	bam_resource = platform_get_resource_byname(pdev,
+				IORESOURCE_MEM, "bam_mem");
+	if (!bam_resource) {
+		MSM_HS_ERR("Invalid BAM HSUART Resources.\n");
+		return -ENXIO;
+	}
+	core_irqres = platform_get_irq_byname(pdev, "core_irq");
+	if (core_irqres < 0) {
+		MSM_HS_ERR("Invalid core irqres Resources.\n");
+		return -ENXIO;
+	}
+	bam_irqres = platform_get_irq_byname(pdev, "bam_irq");
+	if (bam_irqres < 0) {
+		MSM_HS_ERR("Invalid bam irqres Resources.\n");
+		return -ENXIO;
+	}
+	wakeup_irqres = platform_get_irq_byname(pdev, "wakeup_irq");
+	if (wakeup_irqres < 0) {
+		wakeup_irqres = -1;
+		MSM_HS_DBG("Wakeup irq not specified.\n");
+	}
 
-		if (!core_resource) {
-			MSM_HS_ERR("Invalid core HSUART Resources.\n");
-			return -ENXIO;
-		}
+	uport->mapbase = core_resource->start;
 
-		if (!bam_resource) {
-			MSM_HS_ERR("Invalid BAM HSUART Resources.\n");
-			return -ENXIO;
-		}
+	uport->membase = ioremap(uport->mapbase,
+				resource_size(core_resource));
+	if (unlikely(!uport->membase)) {
+		MSM_HS_ERR("UART Resource ioremap Failed.\n");
+		return -ENOMEM;
+	}
+	msm_uport->bam_mem = bam_resource->start;
+	msm_uport->bam_base = ioremap(msm_uport->bam_mem,
+				resource_size(bam_resource));
+	if (unlikely(!msm_uport->bam_base)) {
+		MSM_HS_ERR("UART BAM Resource ioremap Failed.\n");
+		iounmap(uport->membase);
+		return -ENOMEM;
+	}
 
-		if (!core_irqres) {
-			MSM_HS_ERR("Invalid core irqres Resources.\n");
-			return -ENXIO;
-		}
-		if (!bam_irqres) {
-			MSM_HS_ERR("Invalid bam irqres Resources.\n");
-			return -ENXIO;
-		}
-		if (!wakeup_irqres)
-			MSM_HS_DBG("Wakeup irq not specified.\n");
+	uport->irq = core_irqres;
+	msm_uport->bam_irq = bam_irqres;
+	pdata->wakeup_irq = wakeup_irqres;
 
-		uport->mapbase = core_resource->start;
-
-		uport->membase = ioremap(uport->mapbase,
-					resource_size(core_resource));
-		if (unlikely(!uport->membase)) {
-			MSM_HS_ERR("UART Resource ioremap Failed.\n");
-			return -ENOMEM;
-		}
-		msm_uport->bam_mem = bam_resource->start;
-		msm_uport->bam_base = ioremap(msm_uport->bam_mem,
-					resource_size(bam_resource));
-		if (unlikely(!msm_uport->bam_base)) {
-			MSM_HS_ERR("UART BAM Resource ioremap Failed.\n");
-			iounmap(uport->membase);
-			return -ENOMEM;
-		}
-
-		uport->irq = core_irqres;
-		msm_uport->bam_irq = bam_irqres;
-		pdata->wakeup_irq = wakeup_irqres;
-
-		msm_uport->bus_scale_table = msm_bus_cl_get_pdata(pdev);
-		if (!msm_uport->bus_scale_table) {
-			MSM_HS_ERR("BLSP UART: Bus scaling is disabled.\n");
-		} else {
-			msm_uport->bus_perf_client =
-				msm_bus_scale_register_client
-					(msm_uport->bus_scale_table);
-			if (IS_ERR(&msm_uport->bus_perf_client)) {
-				MSM_HS_ERR("%s(): Bus client register failed.\n",
-								__func__);
-				ret = -EINVAL;
-				goto unmap_memory;
-			}
-		}
+	msm_uport->bus_scale_table = msm_bus_cl_get_pdata(pdev);
+	if (!msm_uport->bus_scale_table) {
+		MSM_HS_ERR("BLSP UART: Bus scaling is disabled.\n");
 	} else {
-
-		resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-		if (unlikely(!resource))
-			return -ENXIO;
-		uport->mapbase = resource->start;
-		uport->membase = ioremap(uport->mapbase,
-					resource_size(resource));
-		if (unlikely(!uport->membase))
-			return -ENOMEM;
-
-		uport->irq = platform_get_irq(pdev, 0);
-		if (unlikely((int)uport->irq < 0)) {
-			MSM_HS_ERR("UART IRQ Failed.\n");
-			iounmap(uport->membase);
-			return -ENXIO;
+		msm_uport->bus_perf_client =
+			msm_bus_scale_register_client
+				(msm_uport->bus_scale_table);
+		if (IS_ERR(&msm_uport->bus_perf_client)) {
+			MSM_HS_ERR("%s():Bus client register failed\n",
+				   __func__);
+			ret = -EINVAL;
+			goto unmap_memory;
 		}
 	}
 
@@ -3390,40 +2932,10 @@
 		msm_uport->wakeup.inject_rx = pdata->inject_rx_on_wakeup;
 		msm_uport->wakeup.rx_to_inject = pdata->rx_to_inject;
 
-		if (unlikely(msm_uport->wakeup.irq < 0)) {
-			ret = -ENXIO;
-			goto deregister_bus_client;
-		}
-
-		if (is_blsp_uart(msm_uport)) {
-			msm_uport->bam_tx_ep_pipe_index =
-					pdata->bam_tx_ep_pipe_index;
-			msm_uport->bam_rx_ep_pipe_index =
-					pdata->bam_rx_ep_pipe_index;
-		}
-	}
-
-	if (!is_blsp_uart(msm_uport)) {
-
-		resource = platform_get_resource_byname(pdev,
-					IORESOURCE_DMA, "uartdm_channels");
-		if (unlikely(!resource)) {
-			ret =  -ENXIO;
-			goto deregister_bus_client;
-		}
-
-		msm_uport->dma_tx_channel = resource->start;
-		msm_uport->dma_rx_channel = resource->end;
-
-		resource = platform_get_resource_byname(pdev,
-					IORESOURCE_DMA, "uartdm_crci");
-		if (unlikely(!resource)) {
-			ret = -ENXIO;
-			goto deregister_bus_client;
-		}
-
-		msm_uport->dma_tx_crci = resource->start;
-		msm_uport->dma_rx_crci = resource->end;
+		msm_uport->bam_tx_ep_pipe_index =
+				pdata->bam_tx_ep_pipe_index;
+		msm_uport->bam_rx_ep_pipe_index =
+				pdata->bam_rx_ep_pipe_index;
 	}
 
 	uport->iotype = UPIO_MEM;
@@ -3472,12 +2984,10 @@
 
 
 	/* Initialize SPS HW connected with UART core */
-	if (is_blsp_uart(msm_uport)) {
-		ret = msm_hs_sps_init(msm_uport);
-		if (unlikely(ret)) {
-			MSM_HS_ERR("SPS Initialization failed ! err=%d", ret);
-			goto destroy_mutex;
-		}
+	ret = msm_hs_sps_init(msm_uport);
+	if (unlikely(ret)) {
+		MSM_HS_ERR("SPS Initialization failed ! err=%d", ret);
+		goto destroy_mutex;
 	}
 
 	msm_hs_clock_vote(msm_uport);
@@ -3544,12 +3054,10 @@
 		clk_put(msm_uport->clk);
 
 deregister_bus_client:
-	if (is_blsp_uart(msm_uport))
-		msm_bus_scale_unregister_client(msm_uport->bus_perf_client);
+	msm_bus_scale_unregister_client(msm_uport->bus_perf_client);
 unmap_memory:
 	iounmap(uport->membase);
-	if (is_blsp_uart(msm_uport))
-		iounmap(msm_uport->bam_base);
+	iounmap(msm_uport->bam_base);
 
 	return ret;
 }
@@ -3592,54 +3100,51 @@
 static void msm_hs_shutdown(struct uart_port *uport)
 {
 	int ret;
-	unsigned int data;
-	unsigned long flags;
 	struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
-	struct platform_device *pdev = to_platform_device(uport->dev);
-	const struct msm_serial_hs_platform_data *pdata =
-				pdev->dev.platform_data;
+	struct circ_buf *tx_buf = &uport->state->xmit;
 	struct msm_hs_tx *tx = &msm_uport->tx;
 	struct sps_pipe *sps_pipe_handle = tx->cons.pipe_handle;
 
-	msm_hs_clock_vote(msm_uport);
-	if (msm_uport->tx.dma_in_flight) {
-		if (!is_blsp_uart(msm_uport)) {
-			spin_lock_irqsave(&uport->lock, flags);
-			/* disable UART TX interface to DM */
-			data = msm_hs_read(uport, UART_DM_DMEN);
-			data &= ~UARTDM_TX_DM_EN_BMSK;
-			msm_hs_write(uport, UART_DM_DMEN, data);
-			/* turn OFF UART Transmitter */
-			msm_hs_write(uport, UART_DM_CR,
-				UARTDM_CR_TX_DISABLE_BMSK);
-			/* reset UART TX */
-			msm_hs_write(uport, UART_DM_CR, RESET_TX);
-			/* reset UART TX Error */
-			msm_hs_write(uport, UART_DM_CR, RESET_TX_ERROR);
-			msm_uport->tx.flush = FLUSH_STOP;
-			spin_unlock_irqrestore(&uport->lock, flags);
-			/* discard flush */
-			msm_dmov_flush(msm_uport->dma_tx_channel, 0);
-			ret = wait_event_timeout(msm_uport->tx.wait,
-				msm_uport->tx.flush == FLUSH_SHUTDOWN, 100);
-			if (!ret)
-				MSM_HS_ERR("%s():HSUART TX Stalls.\n", __func__);
-		} else {
-			/* BAM Disconnect for TX */
-			ret = sps_disconnect(sps_pipe_handle);
-			if (ret)
-				MSM_HS_ERR("%s(): sps_disconnect failed\n",
-							__func__);
-		}
+	/*
+	 * cancel the hrtimer first so that
+	 * clk_state can not change in flight
+	 */
+	hrtimer_cancel(&msm_uport->clk_off_timer);
+	flush_work(&msm_uport->clock_off_w);
+
+	if (use_low_power_wakeup(msm_uport))
+		irq_set_irq_wake(msm_uport->wakeup.irq, 0);
+
+	/* wake irq or uart irq is active depending on clk_state */
+	if (msm_uport->clk_state == MSM_HS_CLK_OFF) {
+		if (use_low_power_wakeup(msm_uport))
+			disable_irq(msm_uport->wakeup.irq);
+	} else {
+		disable_irq(uport->irq);
+		wake_unlock(&msm_uport->dma_wake_lock);
 	}
+
+	/* make sure tx tasklet finishes */
 	tasklet_kill(&msm_uport->tx.tlet);
-	BUG_ON(msm_uport->rx.flush < FLUSH_STOP);
-	wait_event(msm_uport->rx.wait, msm_uport->rx.flush == FLUSH_SHUTDOWN);
+	ret = wait_event_timeout(msm_uport->tx.wait,
+			uart_circ_empty(tx_buf), 500);
+	if (!ret)
+		MSM_HS_WARN("Shutdown called when tx buff not empty");
+
+	/* make sure rx tasklet finishes */
 	tasklet_kill(&msm_uport->rx.tlet);
+	wait_event(msm_uport->rx.wait, msm_uport->rx.flush == FLUSH_SHUTDOWN);
 	cancel_delayed_work_sync(&msm_uport->rx.flip_insert_work);
 	flush_workqueue(msm_uport->hsuart_wq);
-	pm_runtime_disable(uport->dev);
 
+	msm_hs_clock_vote(msm_uport);
+	mutex_lock(&msm_uport->clk_mutex);
+	/* BAM Disconnect for TX */
+	ret = sps_disconnect(sps_pipe_handle);
+	if (ret)
+		MSM_HS_ERR("%s(): sps_disconnect failed\n",
+					__func__);
+	WARN_ON(msm_uport->rx.flush < FLUSH_STOP);
 	/* Disable the transmitter */
 	msm_hs_write(uport, UART_DM_CR, UARTDM_CR_TX_DISABLE_BMSK);
 	/* Disable the receiver */
@@ -3652,33 +3157,27 @@
 	 * Hence mb() requires here.
 	 */
 	mb();
+	mutex_unlock(&msm_uport->clk_mutex);
 
+	msm_uport->rx.buffer_pending = NONE_PENDING;
+	MSM_HS_DBG("%s(): tx, rx events complete", __func__);
 	msm_hs_clock_unvote(msm_uport);
 	if (msm_uport->clk_state != MSM_HS_CLK_OFF) {
 		/* to balance clk_state */
 		msm_hs_clock_unvote(msm_uport);
-		wake_unlock(&msm_uport->dma_wake_lock);
 	}
 
+	pm_runtime_disable(uport->dev);
 	msm_uport->clk_state = MSM_HS_CLK_PORT_OFF;
 	dma_unmap_single(uport->dev, msm_uport->tx.dma_base,
 			 UART_XMIT_SIZE, DMA_TO_DEVICE);
 
-	if (use_low_power_wakeup(msm_uport))
-		irq_set_irq_wake(msm_uport->wakeup.irq, 0);
-
 	/* Free the interrupt */
 	free_irq(uport->irq, msm_uport);
 	if (use_low_power_wakeup(msm_uport))
 		free_irq(msm_uport->wakeup.irq, msm_uport);
 
-	if (is_blsp_uart(msm_uport)) {
-		msm_hs_unconfig_uart_gpios(uport);
-	} else {
-		if (pdata && pdata->gpio_config)
-			if (pdata->gpio_config(0))
-				dev_err(uport->dev, "GPIO config error\n");
-	}
+	msm_hs_unconfig_uart_gpios(uport);
 }
 
 static void __exit msm_serial_hs_exit(void)
@@ -3764,8 +3263,6 @@
 	.set_termios = msm_hs_set_termios,
 	.type = msm_hs_type,
 	.config_port = msm_hs_config_port,
-	.release_port = msm_hs_release_port,
-	.request_port = msm_hs_request_port,
 	.flush_buffer = NULL,
 	.ioctl = msm_hs_ioctl,
 };
diff --git a/drivers/tty/serial/msm_serial_hs_hwreg.h b/drivers/tty/serial/msm_serial_hs_hwreg.h
index 064bbda..47f9dca 100644
--- a/drivers/tty/serial/msm_serial_hs_hwreg.h
+++ b/drivers/tty/serial/msm_serial_hs_hwreg.h
@@ -1,6 +1,6 @@
 /* drivers/serial/msm_serial_hs_hwreg.h
  *
- * Copyright (c) 2007-2009, 2012-2013,The Linux Foundation. All rights reserved.
+ * Copyright (c) 2007-2009, 2012-2014,The Linux Foundation. All rights reserved.
  * 
  * All source code in this file is licensed under the following license
  * except where indicated.
@@ -61,28 +61,27 @@
 };
 
 enum msm_hs_regs {
-	UART_DM_MR1,
-	UART_DM_MR2,
-	UART_DM_IMR,
-	UART_DM_SR,
-	UART_DM_CR,
-	UART_DM_CSR,
-	UART_DM_IPR,
-	UART_DM_ISR,
-	UART_DM_RX_TOTAL_SNAP,
-	UART_DM_RFWR,
-	UART_DM_TFWR,
-	UART_DM_RF,
-	UART_DM_TF,
-	UART_DM_MISR,
-	UART_DM_DMRX,
-	UART_DM_NCF_TX,
-	UART_DM_DMEN,
-	UART_DM_TXFS,
-	UART_DM_RXFS,
-	UART_DM_RX_TRANS_CTRL,
-	UART_DM_BCR,
-	UART_DM_LAST,
+	UART_DM_MR1 = 0x0,
+	UART_DM_MR2 = 0x4,
+	UART_DM_IMR = 0xb0,
+	UART_DM_SR = 0xa4,
+	UART_DM_CR = 0xa8,
+	UART_DM_CSR = 0xa0,
+	UART_DM_IPR = 0x18,
+	UART_DM_ISR = 0xb4,
+	UART_DM_RX_TOTAL_SNAP = 0xbc,
+	UART_DM_TFWR = 0x1c,
+	UART_DM_RFWR = 0x20,
+	UART_DM_RF = 0x140,
+	UART_DM_TF = 0x100,
+	UART_DM_MISR = 0xac,
+	UART_DM_DMRX = 0x34,
+	UART_DM_NCF_TX = 0x40,
+	UART_DM_DMEN = 0x3c,
+	UART_DM_TXFS = 0x4c,
+	UART_DM_RXFS = 0x50,
+	UART_DM_RX_TRANS_CTRL = 0xcc,
+	UART_DM_BCR = 0xc8,
 };
 
 #define UARTDM_MR1_ADDR 0x0
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c
index ea724d6..f5a9ad3 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -25,6 +25,7 @@
 #include <linux/debugfs.h>
 #include <linux/seq_file.h>
 #include <linux/pm_runtime.h>
+#include <linux/suspend.h>
 #include <linux/of.h>
 #include <linux/dma-mapping.h>
 
@@ -3394,10 +3395,12 @@
 		return;
 	}
 
-	if (atomic_read(&motg->pm_suspended))
+	if (atomic_read(&motg->pm_suspended)) {
 		motg->sm_work_pending = true;
-	else
+	} else if (!motg->sm_work_pending) {
+		/* process event only if previous one is not pending */
 		queue_work(system_nrt_wq, &motg->sm_work);
+	}
 }
 
 static void msm_pmic_id_status_w(struct work_struct *w)
@@ -3406,6 +3409,8 @@
 						pmic_id_status_work.work);
 	int work = 0;
 
+	dev_dbg(motg->phy.dev, "ID status_w\n");
+
 	if (msm_otg_read_pmic_id_state(motg)) {
 		if (!test_and_set_bit(ID, &motg->inputs)) {
 			pr_debug("PMIC: ID set\n");
@@ -3420,10 +3425,12 @@
 	}
 
 	if (work && (motg->phy.state != OTG_STATE_UNDEFINED)) {
-		if (atomic_read(&motg->pm_suspended))
+		if (atomic_read(&motg->pm_suspended)) {
 			motg->sm_work_pending = true;
-		else
+		} else if (!motg->sm_work_pending) {
+			/* process event only if previous one is not pending */
 			queue_work(system_nrt_wq, &motg->sm_work);
+		}
 	}
 
 }
@@ -3447,6 +3454,34 @@
 	return IRQ_HANDLED;
 }
 
+int msm_otg_pm_notify(struct notifier_block *notify_block,
+					unsigned long mode, void *unused)
+{
+	struct msm_otg *motg = container_of(
+		notify_block, struct msm_otg, pm_notify);
+
+	dev_dbg(motg->phy.dev, "OTG PM notify:%lx, sm_pending:%u\n", mode,
+					motg->sm_work_pending);
+
+	switch (mode) {
+	case PM_POST_SUSPEND:
+		/* OTG sm_work can be armed now */
+		atomic_set(&motg->pm_suspended, 0);
+
+		/* Handle any deferred wakeup events from USB during suspend */
+		if (motg->sm_work_pending) {
+			motg->sm_work_pending = false;
+			queue_work(system_nrt_wq, &motg->sm_work);
+		}
+		break;
+
+	default:
+		break;
+	}
+
+	return NOTIFY_OK;
+}
+
 static int msm_otg_mode_show(struct seq_file *s, void *unused)
 {
 	struct msm_otg *motg = s->private;
@@ -4745,6 +4780,9 @@
 	if (ret)
 		dev_dbg(&pdev->dev, "fail to setup cdev\n");
 
+	motg->pm_notify.notifier_call = msm_otg_pm_notify;
+	register_pm_notifier(&motg->pm_notify);
+
 	return 0;
 
 remove_phy:
@@ -4807,6 +4845,8 @@
 	if (phy->otg->host || phy->otg->gadget)
 		return -EBUSY;
 
+	unregister_pm_notifier(&motg->pm_notify);
+
 	if (!motg->ext_chg_device) {
 		device_destroy(motg->ext_chg_class, motg->ext_chg_dev);
 		cdev_del(&motg->ext_chg_cdev);
@@ -4975,7 +5015,8 @@
 	dev_dbg(dev, "OTG PM resume\n");
 
 	motg->pm_done = 0;
-	atomic_set(&motg->pm_suspended, 0);
+	if (!motg->host_bus_suspend)
+		atomic_set(&motg->pm_suspended, 0);
 	if (motg->async_int || motg->sm_work_pending) {
 		pm_runtime_get_noresume(dev);
 		ret = msm_otg_resume(motg);
@@ -4985,7 +5026,12 @@
 		pm_runtime_set_active(dev);
 		pm_runtime_enable(dev);
 
-		if (motg->sm_work_pending) {
+		/*
+		 * Defer any host mode disconnect events until
+		 * all devices are RESUMED
+		 *
+		 */
+		if (motg->sm_work_pending && !motg->host_bus_suspend) {
 			motg->sm_work_pending = false;
 			queue_work(system_nrt_wq, &motg->sm_work);
 		}
diff --git a/drivers/video/msm/mdss/dsi_host_v2.c b/drivers/video/msm/mdss/dsi_host_v2.c
index 99e1c21..454fd15 100644
--- a/drivers/video/msm/mdss/dsi_host_v2.c
+++ b/drivers/video/msm/mdss/dsi_host_v2.c
@@ -578,15 +578,20 @@
 	pr_debug("msm_dsi_op_mode_config\n");
 
 	dsi_ctrl = MIPI_INP(ctrl_base + DSI_CTRL);
-	/*If Video enabled, Keep Video and Cmd mode ON */
 
-
-	dsi_ctrl &= ~0x06;
-
-	if (mode == DSI_VIDEO_MODE)
-		dsi_ctrl |= 0x02;
+	if (dsi_ctrl & DSI_VIDEO_MODE_EN)
+		dsi_ctrl &= ~(DSI_CMD_MODE_EN|DSI_EN);
 	else
-		dsi_ctrl |= 0x04;
+		dsi_ctrl &= ~(DSI_CMD_MODE_EN|DSI_VIDEO_MODE_EN|DSI_EN);
+
+	if (mode == DSI_VIDEO_MODE) {
+		dsi_ctrl |= (DSI_VIDEO_MODE_EN|DSI_EN);
+	} else {		/* command mode */
+		dsi_ctrl |= (DSI_CMD_MODE_EN|DSI_EN);
+		/*For Video mode panel, keep Video and Cmd mode ON */
+		if (pdata->panel_info.type == MIPI_VIDEO_PANEL)
+			dsi_ctrl |= DSI_VIDEO_MODE_EN;
+	}
 
 	pr_debug("%s: dsi_ctrl=%x\n", __func__, dsi_ctrl);
 
@@ -1070,13 +1075,15 @@
 
 	mutex_lock(&ctrl_pdata->mutex);
 
-	ret = msm_dss_enable_vreg(
-		ctrl_pdata->power_data.vreg_config,
-		ctrl_pdata->power_data.num_vreg, 1);
-	if (ret) {
-		pr_err("%s: DSI power on failed\n", __func__);
-		mutex_unlock(&ctrl_pdata->mutex);
-		return ret;
+	if (!pdata->panel_info.dynamic_switch_pending) {
+		ret = msm_dss_enable_vreg(
+			ctrl_pdata->power_data.vreg_config,
+			ctrl_pdata->power_data.num_vreg, 1);
+		if (ret) {
+			pr_err("%s: DSI power on failed\n", __func__);
+			mutex_unlock(&ctrl_pdata->mutex);
+			return ret;
+		}
 	}
 
 	msm_dsi_ahb_ctrl(1);
@@ -1194,11 +1201,13 @@
 	msm_dsi_phy_off(dsi_host_private->dsi_base);
 	msm_dsi_ahb_ctrl(0);
 
-	ret = msm_dss_enable_vreg(
-		ctrl_pdata->power_data.vreg_config,
-		ctrl_pdata->power_data.num_vreg, 0);
-	if (ret) {
-		pr_err("%s: Panel power off failed\n", __func__);
+	if (!pdata->panel_info.dynamic_switch_pending) {
+		ret = msm_dss_enable_vreg(
+			ctrl_pdata->power_data.vreg_config,
+			ctrl_pdata->power_data.num_vreg, 0);
+		if (ret) {
+			pr_err("%s: Panel power off failed\n", __func__);
+		}
 	}
 	dsi_host_private->clk_count = 0;
 	dsi_host_private->dsi_on = 0;
diff --git a/drivers/video/msm/mdss/dsi_host_v2.h b/drivers/video/msm/mdss/dsi_host_v2.h
index 0f3ea8d..991a769 100644
--- a/drivers/video/msm/mdss/dsi_host_v2.h
+++ b/drivers/video/msm/mdss/dsi_host_v2.h
@@ -171,4 +171,8 @@
 #define DSI_DSIPHY_BIST_CTRL4			0x049C
 #define DSI_DSIPHY_BIST_CTRL5			0x04A0
 
+#define DSI_EN			BIT(0)
+#define DSI_VIDEO_MODE_EN	BIT(1)
+#define DSI_CMD_MODE_EN		BIT(2)
+
 #endif /* DSI_HOST_V2_H */
diff --git a/drivers/video/msm/mdss/dsi_status_6g.c b/drivers/video/msm/mdss/dsi_status_6g.c
index 4f7e4da..2dcd1c8 100644
--- a/drivers/video/msm/mdss/dsi_status_6g.c
+++ b/drivers/video/msm/mdss/dsi_status_6g.c
@@ -65,6 +65,14 @@
 		return;
 	}
 
+	if (!ctl->power_on) {
+		schedule_delayed_work(&pstatus_data->check_status,
+			msecs_to_jiffies(interval));
+		pr_err("%s: ctl not powered on\n", __func__);
+		return;
+	}
+
+	mutex_lock(&ctrl_pdata->mutex);
 	if (ctl->shared_lock)
 		mutex_lock(ctl->shared_lock);
 	mutex_lock(&mdp5_data->ov_lock);
@@ -73,7 +81,8 @@
 		mutex_unlock(&mdp5_data->ov_lock);
 		if (ctl->shared_lock)
 			mutex_unlock(ctl->shared_lock);
-		pr_err("%s: DSI turning off, avoiding BTA status check\n",
+		mutex_unlock(&ctrl_pdata->mutex);
+		pr_err("%s: DSI turning off, avoiding panel status check\n",
 							__func__);
 		return;
 	}
@@ -100,6 +109,7 @@
 	mutex_unlock(&mdp5_data->ov_lock);
 	if (ctl->shared_lock)
 		mutex_unlock(ctl->shared_lock);
+	mutex_unlock(&ctrl_pdata->mutex);
 
 	if ((pstatus_data->mfd->panel_power_on)) {
 		if (ret > 0) {
diff --git a/drivers/video/msm/mdss/dsi_v2.c b/drivers/video/msm/mdss/dsi_v2.c
index bc76fd0..f12d03a 100644
--- a/drivers/video/msm/mdss/dsi_v2.c
+++ b/drivers/video/msm/mdss/dsi_v2.c
@@ -52,6 +52,37 @@
 	return rc;
 }
 
+static int dsi_update_pconfig(struct mdss_panel_data *pdata,
+				int mode)
+{
+	int ret = 0;
+	struct mdss_panel_info *pinfo = &pdata->panel_info;
+	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
+	if (!pdata)
+		return -ENODEV;
+	ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
+				panel_data);
+
+	if (mode == DSI_CMD_MODE) {
+		pinfo->mipi.mode = DSI_CMD_MODE;
+		pinfo->type = MIPI_CMD_PANEL;
+		pinfo->mipi.vsync_enable = 1;
+		pinfo->mipi.hw_vsync_mode = 1;
+	} else {
+		pinfo->mipi.mode = DSI_VIDEO_MODE;
+		pinfo->type = MIPI_VIDEO_PANEL;
+		pinfo->mipi.vsync_enable = 0;
+		pinfo->mipi.hw_vsync_mode = 0;
+	}
+
+	ctrl_pdata->panel_mode = pinfo->mipi.mode;
+	mdss_panel_get_dst_fmt(pinfo->bpp, pinfo->mipi.mode,
+			pinfo->mipi.pixel_packing, &(pinfo->mipi.dst_format));
+	pinfo->cont_splash_enabled = 0;
+
+	return ret;
+}
+
 static int dsi_panel_handler(struct mdss_panel_data *pdata, int enable)
 {
 	int rc = 0;
@@ -64,19 +95,47 @@
 				panel_data);
 
 	if (enable) {
-		dsi_ctrl_gpio_request(ctrl_pdata);
-		mdss_dsi_panel_reset(pdata, 1);
+		if (!pdata->panel_info.dynamic_switch_pending) {
+			if (pdata->panel_info.type == MIPI_CMD_PANEL)
+				dsi_ctrl_gpio_request(ctrl_pdata);
+			mdss_dsi_panel_reset(pdata, 1);
+		}
 		pdata->panel_info.panel_power_on = 1;
-		rc = ctrl_pdata->on(pdata);
-		if (rc)
-			pr_err("dsi_panel_handler panel on failed %d\n", rc);
+		if (!pdata->panel_info.dynamic_switch_pending) {
+			rc = ctrl_pdata->on(pdata);
+			if (rc)
+				pr_err("%s: panel on failed!\n", __func__);
+		}
+		if (pdata->panel_info.type == MIPI_CMD_PANEL &&
+				pdata->panel_info.dynamic_switch_pending) {
+			dsi_ctrl_gpio_request(ctrl_pdata);
+			mdss_dsi_set_tear_on(ctrl_pdata);
+		}
 	} else {
+		msm_dsi_sw_reset();
 		if (dsi_intf.op_mode_config)
 			dsi_intf.op_mode_config(DSI_CMD_MODE, pdata);
-		rc = ctrl_pdata->off(pdata);
+		if (pdata->panel_info.dynamic_switch_pending) {
+			pr_info("%s: switching to %s mode\n", __func__,
+			(pdata->panel_info.mipi.mode ? "video" : "command"));
+			if (pdata->panel_info.type == MIPI_CMD_PANEL) {
+				ctrl_pdata->switch_mode(pdata, DSI_VIDEO_MODE);
+				dsi_ctrl_gpio_free(ctrl_pdata);
+			} else if (pdata->panel_info.type == MIPI_VIDEO_PANEL) {
+				ctrl_pdata->switch_mode(pdata, DSI_CMD_MODE);
+				dsi_ctrl_gpio_request(ctrl_pdata);
+				mdss_dsi_set_tear_off(ctrl_pdata);
+				dsi_ctrl_gpio_free(ctrl_pdata);
+			}
+		}
+		if (!pdata->panel_info.dynamic_switch_pending)
+			rc = ctrl_pdata->off(pdata);
 		pdata->panel_info.panel_power_on = 0;
-		mdss_dsi_panel_reset(pdata, 0);
-		dsi_ctrl_gpio_free(ctrl_pdata);
+		if (!pdata->panel_info.dynamic_switch_pending) {
+			if (pdata->panel_info.type == MIPI_CMD_PANEL)
+				mdss_dsi_panel_reset(pdata, 0);
+			dsi_ctrl_gpio_free(ctrl_pdata);
+		}
 	}
 	return rc;
 }
@@ -138,6 +197,9 @@
 	case MDSS_EVENT_PANEL_CLK_CTRL:
 		rc = dsi_clk_ctrl(pdata, (int)arg);
 		break;
+	case MDSS_EVENT_DSI_DYNAMIC_SWITCH:
+		rc = dsi_update_pconfig(pdata, (int)(unsigned long) arg);
+		break;
 	default:
 		pr_debug("%s: unhandled event=%d\n", __func__, event);
 		break;
@@ -158,7 +220,8 @@
 						__func__, __LINE__);
 
 	ctrl_pdata->disp_te_gpio = -1;
-	if (ctrl_pdata->panel_data.panel_info.mipi.mode == DSI_CMD_MODE) {
+	if (ctrl_pdata->panel_data.panel_info.mipi.mode == DSI_CMD_MODE ||
+		ctrl_pdata->panel_data.panel_info.mipi.dynamic_switch_enabled) {
 		ctrl_pdata->disp_te_gpio = of_get_named_gpio(np,
 						"qcom,platform-te-gpio", 0);
 		if (!gpio_is_valid(ctrl_pdata->disp_te_gpio))
diff --git a/drivers/video/msm/mdss/dsi_v2.h b/drivers/video/msm/mdss/dsi_v2.h
index b8c91da..1474570 100644
--- a/drivers/video/msm/mdss/dsi_v2.h
+++ b/drivers/video/msm/mdss/dsi_v2.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-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
@@ -56,4 +56,5 @@
 
 int mdp3_panel_get_boot_cfg(void);
 
+void msm_dsi_sw_reset(void);
 #endif /* DSI_V2_H */
diff --git a/drivers/video/msm/mdss/mdp3_ctrl.c b/drivers/video/msm/mdss/mdp3_ctrl.c
index 8acb9b0..f448c46 100644
--- a/drivers/video/msm/mdss/mdp3_ctrl.c
+++ b/drivers/video/msm/mdss/mdp3_ctrl.c
@@ -672,16 +672,16 @@
 
 	mdp3_histogram_stop(mdp3_session, MDP_BLOCK_DMA_P);
 
-	rc = mdp3_session->dma->stop(mdp3_session->dma, mdp3_session->intf);
-	if (rc)
-		pr_debug("fail to stop the MDP3 dma\n");
-
-
 	if (panel->event_handler)
 		rc = panel->event_handler(panel, MDSS_EVENT_PANEL_OFF, NULL);
 	if (rc)
 		pr_err("fail to turn off the panel\n");
 
+	rc = mdp3_session->dma->stop(mdp3_session->dma, mdp3_session->intf);
+	if (rc)
+		pr_debug("fail to stop the MDP3 dma\n");
+	msleep(20);
+
 	mdp3_irq_deregister();
 
 	pr_debug("mdp3_ctrl_off stop clock\n");
@@ -708,10 +708,12 @@
 	mdp3_session->in_splash_screen = 0;
 off_error:
 	mdp3_session->status = 0;
-	mdp3_bufq_deinit(&mdp3_session->bufq_out);
-	if (mdp3_session->overlay.id != MSMFB_NEW_REQUEST) {
-		mdp3_session->overlay.id = MSMFB_NEW_REQUEST;
-		mdp3_bufq_deinit(&mdp3_session->bufq_in);
+	if (!panel->panel_info.dynamic_switch_pending) {
+		mdp3_bufq_deinit(&mdp3_session->bufq_out);
+		if (mdp3_session->overlay.id != MSMFB_NEW_REQUEST) {
+			mdp3_session->overlay.id = MSMFB_NEW_REQUEST;
+			mdp3_bufq_deinit(&mdp3_session->bufq_in);
+		}
 	}
 	mutex_unlock(&mdp3_session->lock);
 	return 0;
@@ -1775,6 +1777,48 @@
 	return rc;
 }
 
+static int mdp3_update_panel_info(struct msm_fb_data_type *mfd, int mode)
+{
+	int ret = 0;
+	struct mdp3_session_data *mdp3_session;
+	struct mdss_panel_data *panel;
+	u32 intf_type = 0;
+
+	if (!mfd || !mfd->mdp.private1)
+		return -EINVAL;
+
+	mdp3_session = mfd->mdp.private1;
+	panel = mdp3_session->panel;
+
+	if (!panel->event_handler)
+		return 0;
+	ret = panel->event_handler(panel, MDSS_EVENT_DSI_DYNAMIC_SWITCH,
+						(void *)(unsigned long)mode);
+	if (ret)
+		pr_err("Dynamic switch to %s mode failed!\n",
+					mode ? "command" : "video");
+	if (mode == 1)
+		mfd->panel.type = MIPI_CMD_PANEL;
+	else
+		mfd->panel.type = MIPI_VIDEO_PANEL;
+
+	if (mfd->panel.type != MIPI_VIDEO_PANEL)
+		mdp3_session->wait_for_dma_done = mdp3_wait_for_dma_done;
+
+	intf_type = mdp3_ctrl_get_intf_type(mfd);
+	mdp3_session->intf->cfg.type = intf_type;
+	mdp3_session->intf->available = 1;
+	mdp3_session->intf->in_use = 1;
+	mdp3_res->intf[intf_type].in_use = 1;
+
+	mdp3_intf_init(mdp3_session->intf);
+
+	mdp3_session->dma->output_config.out_sel = intf_type;
+	mdp3_session->status = mdp3_session->intf->active;
+
+	return 0;
+}
+
 int mdp3_ctrl_init(struct msm_fb_data_type *mfd)
 {
 	struct device *dev = mfd->fbi->dev;
@@ -1797,6 +1841,7 @@
 	mdp3_interface->ioctl_handler = mdp3_ctrl_ioctl_handler;
 	mdp3_interface->kickoff_fnc = mdp3_ctrl_display_commit_kickoff;
 	mdp3_interface->lut_update = mdp3_ctrl_lut_update;
+	mdp3_interface->configure_panel = mdp3_update_panel_info;
 
 	mdp3_session = kmalloc(sizeof(struct mdp3_session_data), GFP_KERNEL);
 	if (!mdp3_session) {
diff --git a/drivers/video/msm/mdss/mdss.h b/drivers/video/msm/mdss/mdss.h
index afa0bc1..e8c938b 100644
--- a/drivers/video/msm/mdss/mdss.h
+++ b/drivers/video/msm/mdss/mdss.h
@@ -94,6 +94,15 @@
 	u32 fbc_lines;
 };
 
+enum mdss_hw_index {
+	MDSS_HW_MDP,
+	MDSS_HW_DSI0,
+	MDSS_HW_DSI1,
+	MDSS_HW_HDMI,
+	MDSS_HW_EDP,
+	MDSS_MAX_HW_BLK
+};
+
 struct mdss_data_type {
 	u32 mdp_rev;
 	struct clk *mdp_clk[MDSS_MAX_CLK];
@@ -198,18 +207,13 @@
 	int handoff_pending;
 	struct mdss_prefill_data prefill_data;
 	bool ulps;
+	int iommu_ref_cnt;
+
+	u64 ab[MDSS_MAX_HW_BLK];
+	u64 ib[MDSS_MAX_HW_BLK];
 };
 extern struct mdss_data_type *mdss_res;
 
-enum mdss_hw_index {
-	MDSS_HW_MDP,
-	MDSS_HW_DSI0,
-	MDSS_HW_DSI1,
-	MDSS_HW_HDMI,
-	MDSS_HW_EDP,
-	MDSS_MAX_HW_BLK
-};
-
 struct mdss_hw {
 	u32 hw_ndx;
 	void *ptr;
@@ -220,7 +224,9 @@
 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);
-int mdss_bus_bandwidth_ctrl(int enable);
+void mdss_bus_bandwidth_ctrl(int enable);
+int mdss_iommu_ctrl(int enable);
+int mdss_bus_scale_set_quota(int client, u64 ab_quota, u64 ib_quota);
 
 static inline struct ion_client *mdss_get_ionclient(void)
 {
diff --git a/drivers/video/msm/mdss/mdss_dsi.c b/drivers/video/msm/mdss/mdss_dsi.c
index e724d68..993645a 100644
--- a/drivers/video/msm/mdss/mdss_dsi.c
+++ b/drivers/video/msm/mdss/mdss_dsi.c
@@ -62,6 +62,9 @@
 				panel_data);
 	pr_debug("%s: enable=%d\n", __func__, enable);
 
+	if (pdata->panel_info.dynamic_switch_pending)
+		return 0;
+
 	if (enable) {
 		ret = msm_dss_enable_vreg(
 			ctrl_pdata->power_data.vreg_config,
@@ -316,6 +319,7 @@
 	ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
 				panel_data);
 
+	mutex_lock(&ctrl_pdata->mutex);
 	panel_info = &ctrl_pdata->panel_data.panel_info;
 	pr_debug("%s+: ctrl=%p ndx=%d\n", __func__,
 				ctrl_pdata, ctrl_pdata->ndx);
@@ -333,6 +337,7 @@
 
 	ret = mdss_dsi_panel_power_on(pdata, 0);
 	if (ret) {
+		mutex_unlock(&ctrl_pdata->mutex);
 		pr_err("%s: Panel power off failed\n", __func__);
 		return ret;
 	}
@@ -342,6 +347,7 @@
 	    && (panel_info->new_fps != panel_info->mipi.frame_rate))
 		panel_info->mipi.frame_rate = panel_info->new_fps;
 
+	mutex_unlock(&ctrl_pdata->mutex);
 	pr_debug("%s-:\n", __func__);
 
 	return ret;
@@ -591,6 +597,31 @@
 	return ret;
 }
 
+static int mdss_dsi_update_panel_config(struct mdss_dsi_ctrl_pdata *ctrl_pdata,
+				int mode)
+{
+	int ret = 0;
+	struct mdss_panel_info *pinfo = &(ctrl_pdata->panel_data.panel_info);
+
+	if (mode == DSI_CMD_MODE) {
+		pinfo->mipi.mode = DSI_CMD_MODE;
+		pinfo->type = MIPI_CMD_PANEL;
+		pinfo->mipi.vsync_enable = 1;
+		pinfo->mipi.hw_vsync_mode = 1;
+	} else {	/*video mode*/
+		pinfo->mipi.mode = DSI_VIDEO_MODE;
+		pinfo->type = MIPI_VIDEO_PANEL;
+		pinfo->mipi.vsync_enable = 0;
+		pinfo->mipi.hw_vsync_mode = 0;
+	}
+
+	ctrl_pdata->panel_mode = pinfo->mipi.mode;
+	mdss_panel_get_dst_fmt(pinfo->bpp, pinfo->mipi.mode,
+			pinfo->mipi.pixel_packing, &(pinfo->mipi.dst_format));
+	pinfo->cont_splash_enabled = 0;
+
+	return ret;
+}
 static int mdss_dsi_ulps_config(struct mdss_dsi_ctrl_pdata *ctrl,
 	int enable)
 {
@@ -724,11 +755,13 @@
 	mipi  = &pdata->panel_info.mipi;
 
 	if (!(ctrl_pdata->ctrl_state & CTRL_STATE_PANEL_INIT)) {
-		ret = ctrl_pdata->on(pdata);
-		if (ret) {
-			pr_err("%s: unable to initialize the panel\n",
+		if (!pdata->panel_info.dynamic_switch_pending) {
+			ret = ctrl_pdata->on(pdata);
+			if (ret) {
+				pr_err("%s: unable to initialize the panel\n",
 							__func__);
-			return ret;
+				return ret;
+			}
 		}
 		ctrl_pdata->ctrl_state |= CTRL_STATE_PANEL_INIT;
 	}
@@ -781,6 +814,17 @@
 
 	mdss_dsi_op_mode_config(DSI_CMD_MODE, pdata);
 
+	if (pdata->panel_info.dynamic_switch_pending) {
+		pr_info("%s: switching to %s mode\n", __func__,
+			(pdata->panel_info.mipi.mode ? "video" : "command"));
+		if (pdata->panel_info.type == MIPI_CMD_PANEL) {
+			ctrl_pdata->switch_mode(pdata, DSI_VIDEO_MODE);
+		} else if (pdata->panel_info.type == MIPI_VIDEO_PANEL) {
+			ctrl_pdata->switch_mode(pdata, DSI_CMD_MODE);
+			mdss_dsi_set_tear_off(ctrl_pdata);
+		}
+	}
+
 	if (pdata->panel_info.type == MIPI_CMD_PANEL) {
 		if (mipi->vsync_enable && mipi->hw_vsync_mode
 			&& gpio_is_valid(ctrl_pdata->disp_te_gpio)) {
@@ -789,10 +833,12 @@
 	}
 
 	if (ctrl_pdata->ctrl_state & CTRL_STATE_PANEL_INIT) {
-		ret = ctrl_pdata->off(pdata);
-		if (ret) {
-			pr_err("%s: Panel OFF failed\n", __func__);
-			return ret;
+		if (!pdata->panel_info.dynamic_switch_pending) {
+			ret = ctrl_pdata->off(pdata);
+			if (ret) {
+				pr_err("%s: Panel OFF failed\n", __func__);
+				return ret;
+			}
 		}
 		ctrl_pdata->ctrl_state &= ~CTRL_STATE_PANEL_INIT;
 	}
@@ -952,6 +998,15 @@
 	return rc;
 }
 
+int mdss_dsi_register_recovery_handler(struct mdss_dsi_ctrl_pdata *ctrl,
+	struct mdss_panel_recovery *recovery)
+{
+	mutex_lock(&ctrl->mutex);
+	ctrl->recovery = recovery;
+	mutex_unlock(&ctrl->mutex);
+	return 0;
+}
+
 static int mdss_dsi_event_handler(struct mdss_panel_data *pdata,
 				  int event, void *arg)
 {
@@ -1001,7 +1056,6 @@
 		mdss_dsi_clk_req(ctrl_pdata, (int)arg);
 		break;
 	case MDSS_EVENT_DSI_CMDLIST_KOFF:
-		ctrl_pdata->recovery = (struct mdss_panel_recovery *)arg;
 		mdss_dsi_cmdlist_commit(ctrl_pdata, 1);
 		break;
 	case MDSS_EVENT_PANEL_UPDATE_FPS:
@@ -1023,6 +1077,13 @@
 	case MDSS_EVENT_DSI_ULPS_CTRL:
 		rc = mdss_dsi_ulps_config(ctrl_pdata, (int)arg);
 		break;
+	case MDSS_EVENT_REGISTER_RECOVERY_HANDLER:
+		rc = mdss_dsi_register_recovery_handler(ctrl_pdata,
+			(struct mdss_panel_recovery *)arg);
+	case MDSS_EVENT_DSI_DYNAMIC_SWITCH:
+		rc = mdss_dsi_update_panel_config(ctrl_pdata,
+					(int)(unsigned long) arg);
+		break;
 	default:
 		pr_debug("%s: unhandled event=%d\n", __func__, event);
 		break;
diff --git a/drivers/video/msm/mdss/mdss_dsi.h b/drivers/video/msm/mdss/mdss_dsi.h
index f79391a..609b7ce 100644
--- a/drivers/video/msm/mdss/mdss_dsi.h
+++ b/drivers/video/msm/mdss/mdss_dsi.h
@@ -243,6 +243,7 @@
 	int (*partial_update_fnc) (struct mdss_panel_data *pdata);
 	int (*check_status) (struct mdss_dsi_ctrl_pdata *pdata);
 	int (*cmdlist_commit)(struct mdss_dsi_ctrl_pdata *ctrl, int from_mdp);
+	void (*switch_mode) (struct mdss_panel_data *pdata, int mode);
 	struct mdss_panel_data panel_data;
 	unsigned char *ctrl_base;
 	struct dss_io_data ctrl_io;
@@ -286,6 +287,9 @@
 	struct dsi_panel_cmds on_cmds;
 	struct dsi_panel_cmds off_cmds;
 
+	struct dsi_panel_cmds video2cmd;
+	struct dsi_panel_cmds cmd2video;
+
 	struct dcs_cmd_list cmdlist;
 	struct completion dma_comp;
 	struct completion mdp_comp;
@@ -364,6 +368,11 @@
 int mdss_dsi_panel_init(struct device_node *node,
 		struct mdss_dsi_ctrl_pdata *ctrl_pdata,
 		bool cmd_cfg_cont_splash);
+int mdss_panel_get_dst_fmt(u32 bpp, char mipi_mode, u32 pixel_packing,
+				char *dst_format);
+
+int mdss_dsi_register_recovery_handler(struct mdss_dsi_ctrl_pdata *ctrl,
+		struct mdss_panel_recovery *recovery);
 
 static inline bool mdss_dsi_broadcast_mode_enabled(void)
 {
diff --git a/drivers/video/msm/mdss/mdss_dsi_host.c b/drivers/video/msm/mdss/mdss_dsi_host.c
index 74d2739..d8cd22e 100644
--- a/drivers/video/msm/mdss/mdss_dsi_host.c
+++ b/drivers/video/msm/mdss/mdss_dsi_host.c
@@ -882,6 +882,7 @@
 
 	if (rlen <= 2) {
 		short_response = 1;
+		pkt_size = rlen;
 		rx_byte = 4;
 	} else {
 		short_response = 0;
@@ -905,32 +906,30 @@
 	while (!end) {
 		pr_debug("%s:  rlen=%d pkt_size=%d rx_byte=%d\n",
 				__func__, rlen, pkt_size, rx_byte);
-		 if (!short_response) {
-			max_pktsize[0] = pkt_size;
-			mdss_dsi_buf_init(tp);
-			ret = mdss_dsi_cmd_dma_add(tp, &pkt_size_cmd);
-			if (!ret) {
-				pr_err("%s: failed to add max_pkt_size\n",
-					__func__);
-				rp->len = 0;
-				goto end;
-			}
-
-			mdss_dsi_wait4video_eng_busy(ctrl);
-
-			mdss_dsi_enable_irq(ctrl, DSI_CMD_TERM);
-			ret = mdss_dsi_cmd_dma_tx(ctrl, tp);
-			if (IS_ERR_VALUE(ret)) {
-				mdss_dsi_disable_irq(ctrl, DSI_CMD_TERM);
-				pr_err("%s: failed to tx max_pkt_size\n",
-					__func__);
-				rp->len = 0;
-				goto end;
-			}
-			pr_debug("%s: max_pkt_size=%d sent\n",
-						__func__, pkt_size);
+		max_pktsize[0] = pkt_size;
+		mdss_dsi_buf_init(tp);
+		ret = mdss_dsi_cmd_dma_add(tp, &pkt_size_cmd);
+		if (!ret) {
+			pr_err("%s: failed to add max_pkt_size\n",
+				__func__);
+			rp->len = 0;
+			goto end;
 		}
 
+		mdss_dsi_wait4video_eng_busy(ctrl);
+
+		mdss_dsi_enable_irq(ctrl, DSI_CMD_TERM);
+		ret = mdss_dsi_cmd_dma_tx(ctrl, tp);
+		if (IS_ERR_VALUE(ret)) {
+			mdss_dsi_disable_irq(ctrl, DSI_CMD_TERM);
+			pr_err("%s: failed to tx max_pkt_size\n",
+				__func__);
+			rp->len = 0;
+			goto end;
+		}
+		pr_debug("%s: max_pkt_size=%d sent\n",
+					__func__, pkt_size);
+
 		mdss_dsi_buf_init(tp);
 		ret = mdss_dsi_cmd_dma_add(tp, cmds);
 		if (!ret) {
@@ -1032,7 +1031,7 @@
 
 
 	if (is_mdss_iommu_attached()) {
-		int ret = msm_iommu_map_contig_buffer(tp->dmap,
+		ret = msm_iommu_map_contig_buffer(tp->dmap,
 					mdss_get_iommu_domain(domain), 0,
 					size, SZ_4K, 0, &(addr));
 		if (IS_ERR_VALUE(ret)) {
@@ -1241,7 +1240,7 @@
 {
 	struct dcs_cmd_req *req;
 	int ret = -EINVAL;
-
+	int rc = 0;
 	mutex_lock(&ctrl->cmd_mutex);
 	req = mdss_dsi_cmdlist_get(ctrl);
 
@@ -1264,23 +1263,24 @@
 	 * also, axi bus bandwidth need since dsi controller will
 	 * fetch dcs commands from axi bus
 	 */
-	ret = mdss_bus_bandwidth_ctrl(1);
-	if (ret) {
-		pr_err("bus bandwidth request failed ret=%d\n", ret);
-		goto need_lock;
-	}
+	mdss_bus_scale_set_quota(MDSS_HW_DSI0, SZ_1M, SZ_1M);
 
 	pr_debug("%s:  from_mdp=%d pid=%d\n", __func__, from_mdp, current->pid);
 	mdss_dsi_clk_ctrl(ctrl, DSI_ALL_CLKS, 1);
 
+	rc = mdss_iommu_ctrl(1);
+	if (IS_ERR_VALUE(rc)) {
+		pr_err("IOMMU attach failed\n");
+		mutex_unlock(&ctrl->cmd_mutex);
+		return rc;
+	}
 	if (req->flags & CMD_REQ_RX)
 		ret = mdss_dsi_cmdlist_rx(ctrl, req);
 	else
 		ret = mdss_dsi_cmdlist_tx(ctrl, req);
-
+	mdss_iommu_ctrl(0);
 	mdss_dsi_clk_ctrl(ctrl, DSI_ALL_CLKS, 0);
-	mdss_bus_bandwidth_ctrl(0);
-
+	mdss_bus_scale_set_quota(MDSS_HW_DSI0, 0, 0);
 need_lock:
 
 	if (from_mdp) /* from pipe_commit */
@@ -1380,10 +1380,14 @@
 			mdss_dsi_pll_relock(ctrl);
 
 		if (todo & DSI_EV_MDP_FIFO_UNDERFLOW) {
+			mutex_lock(&ctrl->mutex);
 			if (ctrl->recovery) {
+				mdss_dsi_clk_ctrl(ctrl, DSI_ALL_CLKS, 1);
 				mdss_dsi_sw_reset_restore(ctrl);
 				ctrl->recovery->fxn(ctrl->recovery->data);
+				mdss_dsi_clk_ctrl(ctrl, DSI_ALL_CLKS, 0);
 			}
+			mutex_unlock(&ctrl->mutex);
 		}
 
 		if (todo & DSI_EV_DSI_FIFO_EMPTY)
@@ -1397,7 +1401,9 @@
 			spin_unlock_irqrestore(&ctrl->mdp_lock, flag);
 
 			/* enable dsi error interrupt */
+			mdss_dsi_clk_ctrl(ctrl, DSI_ALL_CLKS, 1);
 			mdss_dsi_err_intr_ctrl(ctrl, DSI_INTR_ERROR_MASK, 1);
+			mdss_dsi_clk_ctrl(ctrl, DSI_ALL_CLKS, 0);
 		}
 
 	}
diff --git a/drivers/video/msm/mdss/mdss_dsi_panel.c b/drivers/video/msm/mdss/mdss_dsi_panel.c
index 7575fe3..1ac37dc 100644
--- a/drivers/video/msm/mdss/mdss_dsi_panel.c
+++ b/drivers/video/msm/mdss/mdss_dsi_panel.c
@@ -317,6 +317,36 @@
 	return rc;
 }
 
+static void mdss_dsi_panel_switch_mode(struct mdss_panel_data *pdata,
+							int mode)
+{
+	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
+	struct mipi_panel_info *mipi;
+	struct dsi_panel_cmds *pcmds;
+
+	if (pdata == NULL) {
+		pr_err("%s: Invalid input data\n", __func__);
+		return;
+	}
+
+	mipi  = &pdata->panel_info.mipi;
+
+	if (!mipi->dynamic_switch_enabled)
+		return;
+
+	ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
+				panel_data);
+
+	if (mode == DSI_CMD_MODE)
+		pcmds = &ctrl_pdata->video2cmd;
+	else
+		pcmds = &ctrl_pdata->cmd2video;
+
+	mdss_dsi_panel_cmds_send(ctrl_pdata, pcmds);
+
+	return;
+}
+
 static void mdss_dsi_panel_bl_ctrl(struct mdss_panel_data *pdata,
 							u32 bl_level)
 {
@@ -524,11 +554,16 @@
 		len -= dchdr->dlen;
 	}
 
-	data = of_get_property(np, link_key, NULL);
-	if (data && !strcmp(data, "dsi_hs_mode"))
-		pcmds->link_state = DSI_HS_MODE;
-	else
-		pcmds->link_state = DSI_LP_MODE;
+	/*Set default link state to LP Mode*/
+	pcmds->link_state = DSI_LP_MODE;
+
+	if (link_key) {
+		data = of_get_property(np, link_key, NULL);
+		if (data && !strcmp(data, "dsi_hs_mode"))
+			pcmds->link_state = DSI_HS_MODE;
+		else
+			pcmds->link_state = DSI_LP_MODE;
+	}
 
 	pr_debug("%s: dcs_cmd=%x len=%d, cmd_cnt=%d link_state=%d\n", __func__,
 		pcmds->buf[0], pcmds->blen, pcmds->cmd_cnt, pcmds->link_state);
@@ -541,7 +576,7 @@
 }
 
 
-static int mdss_panel_dt_get_dst_fmt(u32 bpp, char mipi_mode, u32 pixel_packing,
+int mdss_panel_get_dst_fmt(u32 bpp, char mipi_mode, u32 pixel_packing,
 				char *dst_format)
 {
 	int rc = 0;
@@ -728,6 +763,39 @@
 	return 0;
 }
 
+static void mdss_dsi_parse_roi_alignment(struct device_node *np,
+		struct mdss_panel_info *pinfo)
+{
+	int len = 0;
+	u32 value[6];
+	struct property *data;
+	data = of_find_property(np, "qcom,panel-roi-alignment", &len);
+	len /= sizeof(u32);
+	if (!data || (len != 6)) {
+		pr_debug("%s: Panel roi alignment not found", __func__);
+	} else {
+		int rc = of_property_read_u32_array(np,
+				"qcom,panel-roi-alignment", value, len);
+		if (rc)
+			pr_debug("%s: Error reading panel roi alignment values",
+					__func__);
+		else {
+			pinfo->xstart_pix_align = value[0];
+			pinfo->width_pix_align = value[1];
+			pinfo->ystart_pix_align = value[2];
+			pinfo->height_pix_align = value[3];
+			pinfo->min_width = value[4];
+			pinfo->min_height = value[5];
+		}
+
+		pr_debug("%s: ROI alignment: [%d, %d, %d, %d, %d, %d]",
+				__func__, pinfo->xstart_pix_align,
+				pinfo->width_pix_align, pinfo->ystart_pix_align,
+				pinfo->height_pix_align, pinfo->min_width,
+				pinfo->min_height);
+	}
+}
+
 static int mdss_dsi_parse_panel_features(struct device_node *np,
 	struct mdss_dsi_ctrl_pdata *ctrl)
 {
@@ -755,6 +823,25 @@
 	pr_info("%s: ulps feature %s", __func__,
 		(pinfo->ulps_feature_enabled ? "enabled" : "disabled"));
 
+	pinfo->mipi.dynamic_switch_enabled = of_property_read_bool(np,
+		"qcom,dynamic-mode-switch-enabled");
+
+	if (pinfo->mipi.dynamic_switch_enabled) {
+		mdss_dsi_parse_dcs_cmds(np, &ctrl->video2cmd,
+			"qcom,video-to-cmd-mode-switch-commands", NULL);
+
+		mdss_dsi_parse_dcs_cmds(np, &ctrl->cmd2video,
+			"qcom,cmd-to-video-mode-switch-commands", NULL);
+
+		if (!ctrl->video2cmd.cmd_cnt || !ctrl->cmd2video.cmd_cnt) {
+			pr_warn("No commands specified for dynamic switch\n");
+			pinfo->mipi.dynamic_switch_enabled = 0;
+		}
+	}
+
+	pr_info("%s: dynamic switch feature enabled: %d", __func__,
+		pinfo->mipi.dynamic_switch_enabled);
+
 	return 0;
 }
 
@@ -812,9 +899,11 @@
 	tmp = 0;
 	data = of_get_property(np, "qcom,mdss-dsi-pixel-packing", NULL);
 	if (data && !strcmp(data, "loose"))
-		tmp = 1;
-	rc = mdss_panel_dt_get_dst_fmt(pinfo->bpp,
-		pinfo->mipi.mode, tmp,
+		pinfo->mipi.pixel_packing = 1;
+	else
+		pinfo->mipi.pixel_packing = 0;
+	rc = mdss_panel_get_dst_fmt(pinfo->bpp,
+		pinfo->mipi.mode, pinfo->mipi.pixel_packing,
 		&(pinfo->mipi.dst_format));
 	if (rc) {
 		pr_debug("%s: problem determining dst format. Set Default\n",
@@ -1020,6 +1109,7 @@
 	pinfo->mipi.init_delay = (!rc ? tmp : 0);
 
 	mdss_dsi_parse_fbc_params(np, pinfo);
+	mdss_dsi_parse_roi_alignment(np, pinfo);
 
 	mdss_dsi_parse_trigger(np, &(pinfo->mipi.mdp_trigger),
 		"qcom,mdss-dsi-mdp-trigger");
@@ -1085,9 +1175,13 @@
 	pr_info("%s: Continuous splash %s", __func__,
 		pinfo->cont_splash_enabled ? "enabled" : "disabled");
 
+	pinfo->dynamic_switch_pending = false;
+	pinfo->is_lpm_mode = false;
+
 	ctrl_pdata->on = mdss_dsi_panel_on;
 	ctrl_pdata->off = mdss_dsi_panel_off;
 	ctrl_pdata->panel_data.set_backlight = mdss_dsi_panel_bl_ctrl;
+	ctrl_pdata->switch_mode = mdss_dsi_panel_switch_mode;
 
 	return 0;
 }
diff --git a/drivers/video/msm/mdss/mdss_fb.c b/drivers/video/msm/mdss/mdss_fb.c
index c14f936..511fa00 100644
--- a/drivers/video/msm/mdss/mdss_fb.c
+++ b/drivers/video/msm/mdss/mdss_fb.c
@@ -96,6 +96,7 @@
 static int mdss_fb_pan_idle(struct msm_fb_data_type *mfd);
 static int mdss_fb_send_panel_event(struct msm_fb_data_type *mfd,
 					int event, void *arg);
+static void mdss_fb_set_mdp_sync_pt_threshold(struct msm_fb_data_type *mfd);
 void mdss_fb_no_update_notify_timer_cb(unsigned long data)
 {
 	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)data;
@@ -374,12 +375,117 @@
 	return ret;
 }
 
+static ssize_t mdss_fb_get_panel_info(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct fb_info *fbi = dev_get_drvdata(dev);
+	struct msm_fb_data_type *mfd = fbi->par;
+	struct mdss_panel_info *pinfo = mfd->panel_info;
+	int ret;
+
+	ret = scnprintf(buf, PAGE_SIZE,
+			"pu_en=%d\nxstart=%d\nwalign=%d\nystart=%d\nhalign=%d\n"
+			"min_w=%d\nmin_h=%d",
+			pinfo->partial_update_enabled, pinfo->xstart_pix_align,
+			pinfo->width_pix_align, pinfo->ystart_pix_align,
+			pinfo->height_pix_align, pinfo->min_width,
+			pinfo->min_height);
+
+	return ret;
+}
+
+/*
+ * mdss_fb_lpm_enable() - Function to Control LowPowerMode
+ * @mfd:	Framebuffer data structure for display
+ * @mode:	Enabled/Disable LowPowerMode
+ *		1: Enter into LowPowerMode
+ *		0: Exit from LowPowerMode
+ *
+ * This Function dynamically switches to and from LowPowerMode
+ * based on the argument @mode.
+ */
+static int mdss_fb_lpm_enable(struct msm_fb_data_type *mfd, int mode)
+{
+	int ret = 0;
+	u32 bl_lvl = 0;
+	struct mdss_panel_info *pinfo = NULL;
+	struct mdss_panel_data *pdata;
+
+	if (!mfd || !mfd->panel_info)
+		return -EINVAL;
+
+	pinfo = mfd->panel_info;
+
+	if (!pinfo->mipi.dynamic_switch_enabled) {
+		pr_warn("Panel does not support dynamic switch!\n");
+		return 0;
+	}
+
+	if (mode == pinfo->mipi.mode) {
+		pr_debug("Already in requested mode!\n");
+		return 0;
+	}
+
+	pdata = dev_get_platdata(&mfd->pdev->dev);
+
+	pr_debug("Enter mode: %d\n", mode);
+	pdata->panel_info.dynamic_switch_pending = true;
+
+	mutex_lock(&mfd->bl_lock);
+	bl_lvl = mfd->bl_level;
+	mdss_fb_set_backlight(mfd, 0);
+	mutex_unlock(&mfd->bl_lock);
+
+	lock_fb_info(mfd->fbi);
+	ret = mdss_fb_blank_sub(FB_BLANK_POWERDOWN, mfd->fbi,
+						mfd->op_enable);
+	if (ret) {
+		pr_err("can't turn off display!\n");
+		unlock_fb_info(mfd->fbi);
+		return ret;
+	}
+
+	mfd->op_enable = false;
+
+	ret = mfd->mdp.configure_panel(mfd, mode);
+	mdss_fb_set_mdp_sync_pt_threshold(mfd);
+
+	mfd->op_enable = true;
+
+	ret = mdss_fb_blank_sub(FB_BLANK_UNBLANK, mfd->fbi,
+					mfd->op_enable);
+	if (ret) {
+		pr_err("can't turn on display!\n");
+		unlock_fb_info(mfd->fbi);
+		return ret;
+	}
+	unlock_fb_info(mfd->fbi);
+
+	mutex_lock(&mfd->bl_lock);
+	mfd->bl_updated = true;
+	mdss_fb_set_backlight(mfd, bl_lvl);
+	mutex_unlock(&mfd->bl_lock);
+
+	pdata->panel_info.dynamic_switch_pending = false;
+	pdata->panel_info.is_lpm_mode = mode ? 1 : 0;
+
+	if (ret) {
+		pr_err("can't turn on display!\n");
+		return ret;
+	}
+
+	pr_debug("Exit mode: %d\n", mode);
+
+	return 0;
+}
+
 static DEVICE_ATTR(msm_fb_type, S_IRUGO, mdss_fb_get_type, NULL);
 static DEVICE_ATTR(msm_fb_split, S_IRUGO, mdss_fb_get_split, NULL);
 static DEVICE_ATTR(show_blank_event, S_IRUGO, mdss_mdp_show_blank_event, NULL);
 static DEVICE_ATTR(idle_time, S_IRUGO | S_IWUSR | S_IWGRP,
 	mdss_fb_get_idle_time, mdss_fb_set_idle_time);
 static DEVICE_ATTR(idle_notify, S_IRUGO, mdss_fb_get_idle_notify, NULL);
+static DEVICE_ATTR(msm_fb_panel_info, S_IRUGO, mdss_fb_get_panel_info, NULL);
 
 static struct attribute *mdss_fb_attrs[] = {
 	&dev_attr_msm_fb_type.attr,
@@ -387,6 +493,7 @@
 	&dev_attr_show_blank_event.attr,
 	&dev_attr_idle_time.attr,
 	&dev_attr_idle_notify.attr,
+	&dev_attr_msm_fb_panel_info.attr,
 	NULL,
 };
 
@@ -454,6 +561,7 @@
 
 	mfd->ext_ad_ctrl = -1;
 	mfd->bl_level = 0;
+	mfd->bl_level_prev_scaled = 0;
 	mfd->bl_scale = 1024;
 	mfd->bl_min_lvl = 30;
 	mfd->fb_imgType = MDP_RGBA_8888;
@@ -517,6 +625,21 @@
 			__mdss_fb_sync_buf_done_callback;
 	}
 
+	mdss_fb_set_mdp_sync_pt_threshold(mfd);
+
+	if (mfd->mdp.splash_init_fnc)
+		mfd->mdp.splash_init_fnc(mfd);
+
+	INIT_DELAYED_WORK(&mfd->idle_notify_work, __mdss_fb_idle_notify_work);
+
+	return rc;
+}
+
+static void mdss_fb_set_mdp_sync_pt_threshold(struct msm_fb_data_type *mfd)
+{
+	if (!mfd)
+		return;
+
 	switch (mfd->panel.type) {
 	case WRITEBACK_PANEL:
 		mfd->mdp_sync_pt_data.threshold = 1;
@@ -531,15 +654,7 @@
 		mfd->mdp_sync_pt_data.retire_threshold = 0;
 		break;
 	}
-
-	if (mfd->mdp.splash_init_fnc)
-		mfd->mdp.splash_init_fnc(mfd);
-
-	INIT_DELAYED_WORK(&mfd->idle_notify_work, __mdss_fb_idle_notify_work);
-
-	return rc;
 }
-
 static int mdss_fb_remove(struct platform_device *pdev)
 {
 	struct msm_fb_data_type *mfd;
@@ -782,6 +897,7 @@
 	pdata = dev_get_platdata(&mfd->pdev->dev);
 
 	if ((pdata) && (pdata->set_backlight)) {
+		mfd->bl_level_prev_scaled = mfd->bl_level_scaled;
 		if (!IS_CALIB_MODE_BL(mfd))
 			mdss_fb_scale_bl(mfd, &temp);
 		/*
@@ -792,13 +908,13 @@
 		 * as well as setting bl_level to bkl_lvl even though the
 		 * backlight has been set to the scaled value.
 		 */
-		if (mfd->bl_level_old == temp) {
+		if (mfd->bl_level_scaled == temp) {
 			mfd->bl_level = bkl_lvl;
 			return;
 		}
 		pdata->set_backlight(pdata, temp);
 		mfd->bl_level = bkl_lvl;
-		mfd->bl_level_old = temp;
+		mfd->bl_level_scaled = temp;
 
 		if (mfd->mdp.update_ad_input) {
 			update_ad_input = mfd->mdp.update_ad_input;
@@ -821,7 +937,7 @@
 		if ((pdata) && (pdata->set_backlight)) {
 			mfd->bl_level = mfd->unset_bl_level;
 			pdata->set_backlight(pdata, mfd->bl_level);
-			mfd->bl_level_old = mfd->unset_bl_level;
+			mfd->bl_level_scaled = mfd->unset_bl_level;
 			mfd->bl_updated = 1;
 		}
 	}
@@ -858,6 +974,13 @@
 				schedule_delayed_work(&mfd->idle_notify_work,
 					msecs_to_jiffies(mfd->idle_time));
 		}
+
+		mutex_lock(&mfd->bl_lock);
+		if (!mfd->bl_updated) {
+			mfd->bl_updated = 1;
+			mdss_fb_set_backlight(mfd, mfd->bl_level_prev_scaled);
+		}
+		mutex_unlock(&mfd->bl_lock);
 		break;
 
 	case FB_BLANK_VSYNC_SUSPEND:
@@ -879,8 +1002,9 @@
 
 			mfd->op_enable = false;
 			curr_pwr_state = mfd->panel_power_on;
-			mfd->panel_power_on = false;
 			mutex_lock(&mfd->bl_lock);
+			mdss_fb_set_backlight(mfd, 0);
+			mfd->panel_power_on = false;
 			mfd->bl_updated = 0;
 			mutex_unlock(&mfd->bl_lock);
 
@@ -902,6 +1026,7 @@
 
 static int mdss_fb_blank(int blank_mode, struct fb_info *info)
 {
+	struct mdss_panel_data *pdata;
 	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
 
 	mdss_fb_pan_idle(mfd);
@@ -912,6 +1037,18 @@
 			mfd->suspend.panel_power_on = false;
 		return 0;
 	}
+	pr_debug("mode: %d\n", blank_mode);
+
+	pdata = dev_get_platdata(&mfd->pdev->dev);
+
+	if (pdata->panel_info.is_lpm_mode &&
+			blank_mode == FB_BLANK_UNBLANK) {
+		pr_debug("panel is in lpm mode\n");
+		mfd->mdp.configure_panel(mfd, 0);
+		mdss_fb_set_mdp_sync_pt_threshold(mfd);
+		pdata->panel_info.is_lpm_mode = false;
+	}
+
 	return mdss_fb_blank_sub(blank_mode, info, mfd->op_enable);
 }
 
@@ -1687,7 +1824,11 @@
 	u32 wait_for_finish = disp_commit->wait_for_finish;
 	int ret = 0;
 
-	if (!mfd || (!mfd->op_enable) || (!mfd->panel_power_on))
+	if (!mfd || (!mfd->op_enable))
+		return -EPERM;
+
+	if ((!mfd->panel_power_on) && !((mfd->dcm_state == DCM_ENTER) &&
+				(mfd->panel.type == MIPI_CMD_PANEL)))
 		return -EPERM;
 
 	if (var->xoffset > (info->var.xres_virtual - info->var.xres))
@@ -1739,7 +1880,11 @@
 {
 	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
 
-	if ((!mfd->op_enable) || (!mfd->panel_power_on))
+	if (!mfd->op_enable)
+		return -EPERM;
+
+	if ((!mfd->panel_power_on) && !((mfd->dcm_state == DCM_ENTER) &&
+				(mfd->panel.type == MIPI_CMD_PANEL)))
 		return -EPERM;
 
 	if (var->xoffset > (info->var.xres_virtual - info->var.xres))
@@ -2338,6 +2483,7 @@
 	int ret = -ENOSYS;
 	struct mdp_buf_sync buf_sync;
 	struct msm_sync_pt_data *sync_pt_data = NULL;
+	unsigned int dsi_mode = 0;
 
 	if (!info || !info->par)
 		return -EINVAL;
@@ -2404,6 +2550,16 @@
 		ret = mdss_fb_display_commit(info, argp);
 		break;
 
+	case MSMFB_LPM_ENABLE:
+		ret = copy_from_user(&dsi_mode, argp, sizeof(dsi_mode));
+		if (ret) {
+			pr_err("%s: MSMFB_LPM_ENABLE ioctl failed\n", __func__);
+			goto exit;
+		}
+
+		ret = mdss_fb_lpm_enable(mfd, dsi_mode);
+		break;
+
 	default:
 		if (mfd->mdp.ioctl_handler)
 			ret = mfd->mdp.ioctl_handler(mfd, cmd, argp);
diff --git a/drivers/video/msm/mdss/mdss_fb.h b/drivers/video/msm/mdss/mdss_fb.h
index 3416b9e..5ab3d41 100644
--- a/drivers/video/msm/mdss/mdss_fb.h
+++ b/drivers/video/msm/mdss/mdss_fb.h
@@ -129,6 +129,7 @@
 	struct msm_sync_pt_data *(*get_sync_fnc)(struct msm_fb_data_type *mfd,
 				const struct mdp_buf_sync *buf_sync);
 	void (*check_dsi_status)(struct work_struct *work, uint32_t interval);
+	int (*configure_panel)(struct msm_fb_data_type *mfd, int mode);
 	void *private1;
 };
 
@@ -189,7 +190,8 @@
 	u32 bl_min_lvl;
 	u32 unset_bl_level;
 	u32 bl_updated;
-	u32 bl_level_old;
+	u32 bl_level_scaled;
+	u32 bl_level_prev_scaled;
 	struct mutex bl_lock;
 	struct mutex lock;
 
diff --git a/drivers/video/msm/mdss/mdss_mdp.c b/drivers/video/msm/mdss/mdss_mdp.c
index bf151f4..250b163 100644
--- a/drivers/video/msm/mdss/mdss_mdp.c
+++ b/drivers/video/msm/mdss/mdss_mdp.c
@@ -329,7 +329,7 @@
 		pr_debug("register bus_hdl=%x\n", mdata->bus_hdl);
 	}
 
-	return mdss_mdp_bus_scale_set_quota(AB_QUOTA, IB_QUOTA);
+	return mdss_bus_scale_set_quota(MDSS_HW_MDP, AB_QUOTA, IB_QUOTA);
 }
 
 static void mdss_mdp_bus_scale_unregister(struct mdss_data_type *mdata)
@@ -396,6 +396,29 @@
 		new_uc_idx);
 }
 
+int mdss_bus_scale_set_quota(int client, u64 ab_quota, u64 ib_quota)
+{
+	int rc = 0;
+	int i;
+	u64 total_ab = 0;
+	u64 total_ib = 0;
+
+	mutex_lock(&bus_bw_lock);
+
+	mdss_res->ab[client] = ab_quota;
+	mdss_res->ib[client] = ib_quota;
+	for (i = 0; i < MDSS_MAX_HW_BLK; i++) {
+		total_ab += mdss_res->ab[i];
+		total_ib = max(total_ib, mdss_res->ib[i]);
+	}
+
+	rc = mdss_mdp_bus_scale_set_quota(total_ab, total_ib);
+
+	mutex_unlock(&bus_bw_lock);
+
+	return rc;
+}
+
 static inline u32 mdss_mdp_irq_mask(u32 intr_type, u32 intf_num)
 {
 	if (intr_type == MDSS_MDP_IRQ_INTF_UNDER_RUN ||
@@ -620,6 +643,37 @@
 	return clk_rate;
 }
 
+int mdss_iommu_ctrl(int enable)
+{
+	struct mdss_data_type *mdata = mdss_mdp_get_mdata();
+	int rc = 0;
+
+	mutex_lock(&mdp_iommu_lock);
+	pr_debug("%pS: enable %d mdata->iommu_ref_cnt %d\n",
+		__builtin_return_address(0), enable, mdata->iommu_ref_cnt);
+
+	if (enable) {
+
+		if (mdata->iommu_ref_cnt == 0)
+			rc = mdss_iommu_attach(mdata);
+		mdata->iommu_ref_cnt++;
+	} else {
+		if (mdata->iommu_ref_cnt) {
+			mdata->iommu_ref_cnt--;
+			if (mdata->iommu_ref_cnt == 0)
+				rc = mdss_iommu_dettach(mdata);
+		} else {
+			pr_err("unbalanced iommu ref\n");
+		}
+	}
+	mutex_unlock(&mdp_iommu_lock);
+
+	if (IS_ERR_VALUE(rc))
+		return rc;
+	else
+		return mdata->iommu_ref_cnt;
+}
+
 /**
  * mdss_bus_bandwidth_ctrl() -- place bus bandwidth request
  * @enable:	value of enable or disable
@@ -629,27 +683,16 @@
  * Bus bandwidth is required by mdp.For dsi, it only requires to send
  * dcs coammnd. It returns error if bandwidth request fails.
  */
-int mdss_bus_bandwidth_ctrl(int enable)
+void 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) {
@@ -668,7 +711,6 @@
 		if (!enable) {
 			msm_bus_scale_client_update_request(
 				mdata->bus_hdl, 0);
-			mdss_iommu_dettach(mdata);
 			pm_runtime_put(&mdata->pdev->dev);
 		} else {
 			pm_runtime_get_sync(&mdata->pdev->dev);
@@ -677,9 +719,7 @@
 		}
 	}
 
-end:
 	mutex_unlock(&bus_bw_lock);
-	return rc;
 }
 EXPORT_SYMBOL(mdss_bus_bandwidth_ctrl);
 
@@ -687,7 +727,7 @@
 {
 	struct mdss_data_type *mdata = mdss_mdp_get_mdata();
 	static int mdp_clk_cnt;
-	int changed = 0, rc;
+	int changed = 0;
 
 	mutex_lock(&mdp_clk_lock);
 	if (enable) {
@@ -720,9 +760,7 @@
 		if (mdata->vsync_ena)
 			mdss_mdp_clk_update(MDSS_CLK_MDP_VSYNC, enable);
 
-		rc = mdss_bus_bandwidth_ctrl(enable);
-		if (rc)
-			pr_err("bus bandwidth control failed rc=%d", rc);
+		mdss_bus_bandwidth_ctrl(enable);
 
 		if (!enable)
 			pm_runtime_put(&mdata->pdev->dev);
@@ -809,7 +847,6 @@
 	struct mdss_iommu_map_type *iomap;
 	int i, rc = 0;
 
-	mutex_lock(&mdp_iommu_lock);
 	MDSS_XLOG(mdata->iommu_attached);
 
 	if (mdata->iommu_attached) {
@@ -840,8 +877,6 @@
 
 	mdata->iommu_attached = true;
 end:
-	mutex_unlock(&mdp_iommu_lock);
-
 	return rc;
 }
 
@@ -851,12 +886,10 @@
 	struct mdss_iommu_map_type *iomap;
 	int i;
 
-	mutex_lock(&mdp_iommu_lock);
 	MDSS_XLOG(mdata->iommu_attached);
 
 	if (!mdata->iommu_attached) {
 		pr_debug("mdp iommu already dettached\n");
-		mutex_unlock(&mdp_iommu_lock);
 		return 0;
 	}
 
@@ -873,7 +906,6 @@
 	}
 
 	mdata->iommu_attached = false;
-	mutex_unlock(&mdp_iommu_lock);
 
 	return 0;
 }
@@ -2560,7 +2592,6 @@
 		mdata->fs_ena = true;
 	} else {
 		pr_debug("Disable MDP FS\n");
-		mdss_iommu_dettach(mdata);
 		if (mdata->fs_ena) {
 			regulator_disable(mdata->fs);
 			if (!mdata->ulps) {
@@ -2591,20 +2622,20 @@
 	pr_debug("called on=%d\n", on);
 	if (on) {
 		pm_runtime_get_sync(dev);
-		rc = mdss_iommu_attach(mdata);
-		if (rc) {
+		rc = mdss_iommu_ctrl(1);
+		if (IS_ERR_VALUE(rc)) {
 			pr_err("mdss iommu attach failed rc=%d\n", rc);
-			goto end;
+			return rc;
 		}
 		mdss_hw_init(mdata);
 		mdata->ulps = false;
+		mdss_iommu_ctrl(0);
 	} else {
 		mdata->ulps = true;
 		pm_runtime_put_sync(dev);
 	}
 
-end:
-	return rc;
+	return 0;
 }
 
 static inline int mdss_mdp_suspend_sub(struct mdss_data_type *mdata)
diff --git a/drivers/video/msm/mdss/mdss_mdp_ctl.c b/drivers/video/msm/mdss/mdss_mdp_ctl.c
index 4b7f89d..8a0c9b1 100644
--- a/drivers/video/msm/mdss/mdss_mdp_ctl.c
+++ b/drivers/video/msm/mdss/mdss_mdp_ctl.c
@@ -847,7 +847,7 @@
 		&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);
+	mdss_bus_scale_set_quota(MDSS_HW_MDP, bus_ab_quota, bus_ib_quota);
 	pr_debug("ab=%llu ib=%llu\n", bus_ab_quota, bus_ib_quota);
 	ATRACE_END(__func__);
 }
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c b/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
index 991eb06..e619e6b 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
@@ -189,6 +189,7 @@
 {
 	unsigned long flags;
 	struct mdss_data_type *mdata = mdss_mdp_get_mdata();
+	int rc;
 
 	if (!ctx->panel_on)
 		return;
@@ -201,6 +202,10 @@
 		if (cancel_delayed_work_sync(&ctx->ulps_work))
 			pr_debug("deleted pending ulps work\n");
 
+		rc = mdss_iommu_ctrl(1);
+		if (IS_ERR_VALUE(rc))
+			pr_err("IOMMU attach failed\n");
+
 		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
 
 		if (ctx->ulps) {
@@ -243,6 +248,7 @@
 		mdss_mdp_hist_intr_setup(&mdata->hist_intr, MDSS_IRQ_SUSPEND);
 		mdss_mdp_ctl_intf_event
 			(ctx->ctl, MDSS_EVENT_PANEL_CLK_CTRL, (void *)0);
+		mdss_iommu_ctrl(0);
 		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
 		if (ctx->panel_on)
 			schedule_delayed_work(&ctx->ulps_work, ULPS_ENTER_TIME);
@@ -592,6 +598,10 @@
 
 		rc = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_PANEL_ON, NULL);
 		WARN(rc, "intf %d panel on error (%d)\n", ctl->intf_num, rc);
+
+		mdss_mdp_ctl_intf_event(ctl,
+				MDSS_EVENT_REGISTER_RECOVERY_HANDLER,
+				(void *)&ctx->recovery);
 	}
 
 	MDSS_XLOG(ctl->num, ctl->roi.x, ctl->roi.y, ctl->roi.w,
@@ -609,8 +619,7 @@
 	/*
 	 * tx dcs command if had any
 	 */
-	mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_DSI_CMDLIST_KOFF,
-						(void *)&ctx->recovery);
+	mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_DSI_CMDLIST_KOFF, NULL);
 	INIT_COMPLETION(ctx->pp_comp);
 	mdss_mdp_irq_enable(MDSS_MDP_IRQ_PING_PONG_COMP, ctx->pp_num);
 	mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_START, 1);
@@ -679,6 +688,10 @@
 	if (cancel_delayed_work_sync(&ctx->ulps_work))
 		pr_debug("deleted pending ulps work\n");
 
+	mdss_mdp_ctl_intf_event(ctl,
+			MDSS_EVENT_REGISTER_RECOVERY_HANDLER,
+			NULL);
+
 	ctx->panel_on = 0;
 	mdss_mdp_cmd_clk_off(ctx);
 
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_video.c b/drivers/video/msm/mdss/mdss_mdp_intf_video.c
index eff708c..3413894 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_video.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_video.c
@@ -333,6 +333,8 @@
 				frame_rate = 24;
 			msleep((1000/frame_rate) + 1);
 		}
+
+		mdss_iommu_ctrl(0);
 		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
 		ctx->timegen_en = false;
 
@@ -685,6 +687,7 @@
 {
 	struct mdss_mdp_video_ctx *ctx;
 	struct mdss_mdp_ctl *sctl;
+	struct mdss_panel_data *pdata = ctl->panel_data;
 	int rc;
 
 	pr_debug("kickoff ctl=%d\n", ctl->num);
@@ -717,6 +720,18 @@
 
 		pr_debug("enabling timing gen for intf=%d\n", ctl->intf_num);
 
+		if (pdata->panel_info.cont_splash_enabled &&
+			!ctl->mfd->splash_info.splash_logo_enabled) {
+			rc = wait_for_completion_timeout(&ctx->vsync_comp,
+					usecs_to_jiffies(VSYNC_TIMEOUT_US));
+		}
+
+		rc = mdss_iommu_ctrl(1);
+		if (IS_ERR_VALUE(rc)) {
+			pr_err("IOMMU attach failed\n");
+			return rc;
+		}
+
 		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
 
 		mdss_mdp_irq_enable(MDSS_MDP_IRQ_INTF_UNDER_RUN, ctl->intf_num);
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c b/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c
index 02e7b75..7bf03eb 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c
@@ -442,6 +442,7 @@
 		rc = 0;
 	}
 
+	mdss_iommu_ctrl(0);
 	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false); /* clock off */
 
 	ctx->comp_cnt--;
@@ -501,6 +502,11 @@
 	INIT_COMPLETION(ctx->wb_comp);
 	mdss_mdp_irq_enable(ctx->intr_type, ctx->intf_num);
 
+	ret = mdss_iommu_ctrl(1);
+	if (IS_ERR_VALUE(ret)) {
+		pr_err("IOMMU attach failed\n");
+		return ret;
+	}
 	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
 	mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_START, 1);
 	wmb();
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index 52c220f..f371f9c 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -707,9 +707,11 @@
 	if ((num_planes <= 0) || (num_planes > MAX_PLANES))
 		return -EINVAL;
 
-	rc = mdss_bus_bandwidth_ctrl(1);
-	if (rc)
+	rc = mdss_iommu_ctrl(1);
+	if (IS_ERR_VALUE(rc)) {
+		pr_err("Iommu attach failed");
 		goto end;
+	}
 
 	memset(data, 0, sizeof(*data));
 	for (i = 0; i < num_planes; i++) {
@@ -724,31 +726,29 @@
 			break;
 		}
 	}
-	mdss_bus_bandwidth_ctrl(0);
 
+	mdss_iommu_ctrl(0);
 	data->num_planes = i;
-
 end:
 	return rc;
 }
 
 int mdss_mdp_overlay_free_buf(struct mdss_mdp_data *data)
 {
-	int i;
-	int rc;
+	int i, rc;
 
-	rc = mdss_bus_bandwidth_ctrl(1);
-	if (rc)
-		goto end;
+	rc = mdss_iommu_ctrl(1);
+	if (IS_ERR_VALUE(rc)) {
+		pr_err("Iommu attach failed");
+		return rc;
+	}
 
 	for (i = 0; i < data->num_planes && data->p[i].len; i++)
 		mdss_mdp_put_img(&data->p[i]);
-	mdss_bus_bandwidth_ctrl(0);
 
+	mdss_iommu_ctrl(0);
 	data->num_planes = 0;
-
-end:
-	return rc;
+	return 0;
 }
 
 /**
@@ -919,13 +919,6 @@
 
 		if (!mdp5_data->mdata->batfet)
 			mdss_mdp_batfet_ctrl(mdp5_data->mdata, true);
-		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;
 	}
@@ -948,13 +941,14 @@
 	 */
 	if (!is_mdss_iommu_attached()) {
 		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);
+			rc = mdss_iommu_ctrl(1);
+			if (IS_ERR_VALUE(rc)) {
+				pr_err("iommu attach failed rc=%d\n", rc);
 				goto pm_error;
 			}
+			mdss_hw_init(mdss_res);
+			mdss_iommu_ctrl(0);
 		}
-		mdss_hw_init(mdss_res);
 	}
 
 	rc = mdss_mdp_ctl_start(ctl, false);
@@ -1385,14 +1379,6 @@
 	flags = (pipe->flags & MDP_SECURE_OVERLAY_SESSION);
 	flags |= (pipe->flags & MDP_SECURE_DISPLAY_OVERLAY_SESSION);
 
-	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) {
 		pr_warn("dropped buffer pnum=%d play=%d addr=0x%x\n",
@@ -1405,7 +1391,6 @@
 		pr_err("src_data pmem error\n");
 	}
 
-end:
 	mdss_mdp_pipe_unmap(pipe);
 
 	return ret;
@@ -1605,12 +1590,20 @@
 	if (mutex_lock_interruptible(&mdp5_data->ov_lock))
 		return;
 
-	if (!mfd->panel_power_on) {
+	if ((!mfd->panel_power_on) && !((mfd->dcm_state == DCM_ENTER) &&
+				(mfd->panel.type == MIPI_CMD_PANEL))) {
 		mutex_unlock(&mdp5_data->ov_lock);
 		return;
 	}
 
 	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+
+	ret = mdss_iommu_ctrl(1);
+	if (IS_ERR_VALUE(ret)) {
+		pr_err("IOMMU attach failed\n");
+		goto pan_display_error;
+	}
+
 	bpp = fbi->var.bits_per_pixel / 8;
 	offset = fbi->var.xoffset * bpp +
 		 fbi->var.yoffset * fbi->fix.line_length;
@@ -1677,10 +1670,12 @@
 	    (fbi->var.activate & FB_ACTIVATE_FORCE))
 		mfd->mdp.kickoff_fnc(mfd, NULL);
 
+	mdss_iommu_ctrl(0);
 	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
 	return;
 
 pan_display_error:
+	mdss_iommu_ctrl(0);
 	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
 	mutex_unlock(&mdp5_data->ov_lock);
 }
@@ -3054,6 +3049,27 @@
 	return 0;
 }
 
+static int mdss_mdp_update_panel_info(struct msm_fb_data_type *mfd, int mode)
+{
+	int ret = 0;
+	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
+	struct mdss_mdp_ctl *ctl = mdp5_data->ctl;
+
+	ret = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_DSI_DYNAMIC_SWITCH,
+						(void *)(unsigned long)mode);
+	if (ret)
+		pr_err("Dynamic switch to %s mode failed!\n",
+					mode ? "command" : "video");
+	/*
+	 * Destroy current ctrl sturcture as this is
+	 * going to be re-initialized with the requested mode.
+	 */
+	mdss_mdp_ctl_destroy(mdp5_data->ctl);
+	mdp5_data->ctl = NULL;
+
+	return 0;
+}
+
 int mdss_mdp_overlay_init(struct msm_fb_data_type *mfd)
 {
 	struct device *dev = mfd->fbi->dev;
@@ -3072,6 +3088,7 @@
 	mdp5_interface->kickoff_fnc = mdss_mdp_overlay_kickoff;
 	mdp5_interface->get_sync_fnc = mdss_mdp_rotator_sync_pt_get;
 	mdp5_interface->splash_init_fnc = mdss_mdp_splash_init;
+	mdp5_interface->configure_panel = mdss_mdp_update_panel_info;
 
 	mdp5_data = kmalloc(sizeof(struct mdss_overlay_private), GFP_KERNEL);
 	if (!mdp5_data) {
@@ -3122,7 +3139,10 @@
 			pr_err("Error dfps sysfs creation ret=%d\n", rc);
 			goto init_fail;
 		}
-	} else if (mfd->panel_info->type == MIPI_CMD_PANEL) {
+	}
+
+	if (mfd->panel_info->mipi.dynamic_switch_enabled ||
+			mfd->panel_info->type == MIPI_CMD_PANEL) {
 		rc = __vsync_retire_setup(mfd);
 		if (IS_ERR_VALUE(rc)) {
 			pr_err("unable to create vsync timeline\n");
diff --git a/drivers/video/msm/mdss/mdss_mdp_pipe.c b/drivers/video/msm/mdss/mdss_mdp_pipe.c
index 32b8cbf..70544c0 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pipe.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pipe.c
@@ -924,8 +924,17 @@
 	dst = pipe->dst;
 	src = pipe->src;
 
-	if (pipe->mixer->type == MDSS_MDP_MIXER_TYPE_INTF)
+	if (pipe->mixer->type == MDSS_MDP_MIXER_TYPE_INTF) {
 		mdss_mdp_crop_rect(&src, &dst, &sci);
+		if (pipe->flags & MDP_FLIP_LR) {
+			src.x = pipe->src.x + (pipe->src.x + pipe->src.w)
+				- (src.x + src.w);
+		}
+		if (pipe->flags & MDP_FLIP_UD) {
+			src.y = pipe->src.y + (pipe->src.y + pipe->src.h)
+				- (src.y + src.h);
+		}
+	}
 
 	src_size = (src.h << 16) | src.w;
 	src_xy = (src.y << 16) | src.x;
diff --git a/drivers/video/msm/mdss/mdss_mdp_rotator.c b/drivers/video/msm/mdss/mdss_mdp_rotator.c
index 6953469..ff8c6b8 100755
--- a/drivers/video/msm/mdss/mdss_mdp_rotator.c
+++ b/drivers/video/msm/mdss/mdss_mdp_rotator.c
@@ -692,7 +692,6 @@
 			    struct msmfb_overlay_data *req)
 {
 	struct mdss_mdp_rotator_session *rot;
-	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
 	int ret;
 	u32 flgs;
 
@@ -712,9 +711,6 @@
 		goto dst_buf_fail;
 	}
 
-	if (!mfd->panel_info->cont_splash_enabled)
-		mdss_iommu_attach(mdp5_data->mdata);
-
 	mdss_mdp_overlay_free_buf(&rot->src_buf);
 	ret = mdss_mdp_overlay_get_buf(mfd, &rot->src_buf, &req->data, 1, flgs);
 	if (ret) {
diff --git a/drivers/video/msm/mdss/mdss_mdp_splash_logo.c b/drivers/video/msm/mdss/mdss_mdp_splash_logo.c
index 838f58f..829806d 100644
--- a/drivers/video/msm/mdss/mdss_mdp_splash_logo.c
+++ b/drivers/video/msm/mdss/mdss_mdp_splash_logo.c
@@ -109,7 +109,7 @@
 {
 	struct iommu_domain *domain;
 	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
-	int rc;
+	int rc, ret;
 
 	/*
 	 * iommu dynamic attach for following conditions.
@@ -139,9 +139,9 @@
 	if (rc) {
 		pr_debug("iommu memory mapping failed rc=%d\n", rc);
 	} else {
-		rc = mdss_iommu_attach(mdss_res);
-		if (rc) {
-			pr_debug("mdss iommu attach failed\n");
+		ret = mdss_iommu_ctrl(1);
+		if (IS_ERR_VALUE(ret)) {
+			pr_err("mdss iommu attach failed\n");
 			iommu_unmap(domain, mdp5_data->splash_mem_addr,
 						mdp5_data->splash_mem_size);
 		} else {
@@ -167,6 +167,8 @@
 
 		iommu_unmap(domain, mdp5_data->splash_mem_addr,
 						mdp5_data->splash_mem_size);
+		mdss_iommu_ctrl(0);
+
 		mfd->splash_info.iommu_dynamic_attached = false;
 	}
 }
@@ -246,12 +248,6 @@
 	}
 
 	mdss_mdp_footswitch_ctrl_splash(0);
-	if (!is_mdss_iommu_attached()) {
-		rc = mdss_iommu_attach(mdss_res);
-		if (rc)
-			pr_err("iommu attach failed rc=%d\n", rc);
-	}
-
 end:
 	return rc;
 }
diff --git a/drivers/video/msm/mdss/mdss_mdp_wb.c b/drivers/video/msm/mdss/mdss_mdp_wb.c
index 0e59a26..6086e28 100644
--- a/drivers/video/msm/mdss/mdss_mdp_wb.c
+++ b/drivers/video/msm/mdss/mdss_mdp_wb.c
@@ -427,11 +427,20 @@
 	buf = &node->buf_data.p[0];
 	if (wb->is_secure)
 		buf->flags |= MDP_SECURE_OVERLAY_SESSION;
+
+	ret = mdss_iommu_ctrl(1);
+	if (IS_ERR_VALUE(ret)) {
+		pr_err("IOMMU attach failed\n");
+		goto register_fail;
+	}
 	ret = mdss_mdp_get_img(data, buf);
 	if (IS_ERR_VALUE(ret)) {
 		pr_err("error getting buffer info\n");
+		mdss_iommu_ctrl(0);
 		goto register_fail;
 	}
+	mdss_iommu_ctrl(0);
+
 	memcpy(&node->buf_info, data, sizeof(*data));
 
 	ret = mdss_mdp_wb_register_node(wb, node);
@@ -471,7 +480,6 @@
 {
 	struct mdss_mdp_wb *wb = mfd_to_wb(mfd);
 	struct mdss_mdp_wb_data *node = NULL;
-	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
 	int ret = 0;
 
 	if (!wb) {
@@ -481,14 +489,6 @@
 
 	pr_debug("fb%d queue\n", wb->fb_ndx);
 
-	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)
 		node = get_local_node(wb, data);
@@ -741,7 +741,13 @@
 		}
 		break;
 	case MSMFB_WRITEBACK_TERMINATE:
+		ret = mdss_iommu_ctrl(1);
+		if (IS_ERR_VALUE(ret)) {
+			pr_err("IOMMU attach failed\n");
+			return ret;
+		}
 		ret = mdss_mdp_wb_terminate(mfd);
+		mdss_iommu_ctrl(0);
 		break;
 	case MSMFB_WRITEBACK_SET_MIRRORING_HINT:
 		if (!copy_from_user(&hint, arg, sizeof(hint))) {
@@ -854,19 +860,25 @@
 EXPORT_SYMBOL(msm_fb_writeback_set_secure);
 
 /**
- * msm_fb_writeback_iommu_ref() - Power ON/OFF mdp clock
- * @enable - true/false to Power ON/OFF mdp clock
+ * msm_fb_writeback_iommu_ref() - Add/Remove vote on MDSS IOMMU being attached.
+ * @enable - true adds vote on MDSS IOMMU, false removes the vote.
  *
- * Call to enable mdp clock at start of mdp_mmap/mdp_munmap API and
- * to disable mdp clock at end of these API's to ensure iommu is in
- * proper state while driver map/un-map any buffers.
+ * Call to vote on MDSS IOMMU being enabled. To ensure buffers are properly
+ * mapped to IOMMU context bank.
  */
 int msm_fb_writeback_iommu_ref(struct fb_info *info, int enable)
 {
-	if (enable)
-		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
-	else
-		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+	int ret;
+
+	if (enable) {
+		ret = mdss_iommu_ctrl(1);
+		if (IS_ERR_VALUE(ret)) {
+			pr_err("IOMMU attach failed\n");
+			return ret;
+		}
+	} else {
+		mdss_iommu_ctrl(0);
+	}
 
 	return 0;
 }
diff --git a/drivers/video/msm/mdss/mdss_panel.h b/drivers/video/msm/mdss/mdss_panel.h
index 52c3e71..084cba4 100644
--- a/drivers/video/msm/mdss/mdss_panel.h
+++ b/drivers/video/msm/mdss/mdss_panel.h
@@ -132,6 +132,10 @@
  *				event arguments can have one of these values:
  *				- 0: Disable ULPS mode
  *				- 1: Enable ULPS mode
+ * @MDSS_EVENT_DSI_DYNAMIC_SWITCH: Event to update the dsi driver structures
+ *				based on the dsi mode passed as argument.
+ *				- 0: update to video mode
+ *				- 1: update to command mode
  */
 enum mdss_intf_events {
 	MDSS_EVENT_RESET = 1,
@@ -151,6 +155,8 @@
 	MDSS_EVENT_DSI_CMDLIST_KOFF,
 	MDSS_EVENT_ENABLE_PARTIAL_UPDATE,
 	MDSS_EVENT_DSI_ULPS_CTRL,
+	MDSS_EVENT_REGISTER_RECOVERY_HANDLER,
+	MDSS_EVENT_DSI_DYNAMIC_SWITCH,
 };
 
 struct lcd_panel_info {
@@ -221,6 +227,9 @@
 	char stream;	/* 0 or 1 */
 	char mdp_trigger;
 	char dma_trigger;
+	/*Dynamic Switch Support*/
+	bool dynamic_switch_enabled;
+	u32 pixel_packing;
 	u32 dsi_pclk_rate;
 	/* The packet-size should not bet changed */
 	char no_max_pkt_size;
@@ -323,12 +332,22 @@
 	int new_fps;
 	int panel_max_fps;
 	int panel_max_vtotal;
+	u32 xstart_pix_align;
+	u32 width_pix_align;
+	u32 ystart_pix_align;
+	u32 height_pix_align;
+	u32 min_width;
+	u32 min_height;
+
 	u32 cont_splash_enabled;
 	u32 partial_update_enabled;
 	struct ion_handle *splash_ihdl;
 	u32 panel_power_on;
 
 	uint32_t panel_dead;
+	bool dynamic_switch_pending;
+	bool is_lpm_mode;
+
 	struct mdss_mdp_pp_tear_check te;
 
 	struct lcd_panel_info lcdc;
diff --git a/drivers/video/msm/mdss/msm_mdss_io_8974.c b/drivers/video/msm/mdss/msm_mdss_io_8974.c
index 34e383e..584ffe7 100644
--- a/drivers/video/msm/mdss/msm_mdss_io_8974.c
+++ b/drivers/video/msm/mdss/msm_mdss_io_8974.c
@@ -64,7 +64,8 @@
 		goto mdss_dsi_clk_err;
 	}
 
-	if (ctrl_pdata->panel_data.panel_info.type == MIPI_CMD_PANEL) {
+	if ((ctrl_pdata->panel_data.panel_info.type == MIPI_CMD_PANEL) ||
+		ctrl_pdata->panel_data.panel_info.mipi.dynamic_switch_enabled) {
 		ctrl_pdata->mmss_misc_ahb_clk = clk_get(dev, "core_mmss_clk");
 		if (IS_ERR(ctrl_pdata->mmss_misc_ahb_clk)) {
 			rc = PTR_ERR(ctrl_pdata->mmss_misc_ahb_clk);
diff --git a/fs/bio.c b/fs/bio.c
index 84da885..ee796c4 100644
--- a/fs/bio.c
+++ b/fs/bio.c
@@ -458,6 +458,7 @@
 	bio->bi_vcnt = bio_src->bi_vcnt;
 	bio->bi_size = bio_src->bi_size;
 	bio->bi_idx = bio_src->bi_idx;
+	bio->bi_dio_inode = bio_src->bi_dio_inode;
 }
 EXPORT_SYMBOL(__bio_clone);
 
diff --git a/fs/direct-io.c b/fs/direct-io.c
index f4aadd1..be21245 100644
--- a/fs/direct-io.c
+++ b/fs/direct-io.c
@@ -423,6 +423,8 @@
 	if (dio->is_async && dio->rw == READ)
 		bio_set_pages_dirty(bio);
 
+	bio->bi_dio_inode = dio->inode;
+
 	if (sdio->submit_io)
 		sdio->submit_io(dio->rw, bio, dio->inode,
 			       sdio->logical_offset_in_bio);
@@ -434,6 +436,19 @@
 	sdio->logical_offset_in_bio = 0;
 }
 
+struct inode *dio_bio_get_inode(struct bio *bio)
+{
+	struct inode *inode = NULL;
+
+	if (bio == NULL)
+		return NULL;
+
+	inode = bio->bi_dio_inode;
+
+	return inode;
+}
+EXPORT_SYMBOL(dio_bio_get_inode);
+
 /*
  * Release any resources in case of a failure
  */
diff --git a/fs/namei.c b/fs/namei.c
index c427919..a87e323 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -2072,6 +2072,13 @@
 	if (error)
 		return error;
 	error = dir->i_op->create(dir, dentry, mode, nd);
+	if (error)
+		return error;
+
+	error = security_inode_post_create(dir, dentry, mode);
+	if (error)
+		return error;
+
 	if (!error)
 		fsnotify_create(dir, dentry);
 	return error;
@@ -2547,6 +2554,13 @@
 		return error;
 
 	error = dir->i_op->mknod(dir, dentry, mode, dev);
+	if (error)
+		return error;
+
+	error = security_inode_post_create(dir, dentry, mode);
+	if (error)
+		return error;
+
 	if (!error)
 		fsnotify_create(dir, dentry);
 	return error;
diff --git a/fs/open.c b/fs/open.c
index 5720854..56c8810 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -1054,6 +1054,7 @@
 		dnotify_flush(filp, id);
 		locks_remove_posix(filp, id);
 	}
+	security_file_close(filp);
 	fput(filp);
 	return retval;
 }
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/blk_types.h b/include/linux/blk_types.h
index 3f62354..97210b7 100644
--- a/include/linux/blk_types.h
+++ b/include/linux/blk_types.h
@@ -70,6 +70,13 @@
 	struct bio_integrity_payload *bi_integrity;  /* data integrity */
 #endif
 
+	/*
+	 * When using dircet-io (O_DIRECT), we can't get the inode from a bio
+	 * by walking bio->bi_io_vec->bv_page->mapping->host
+	 * since the page is anon.
+	 */
+	struct inode		*bi_dio_inode;
+
 	bio_destructor_t	*bi_destructor;	/* destructor */
 
 	/*
diff --git a/include/linux/diagchar.h b/include/linux/diagchar.h
index f78d418..1e15415 100644
--- a/include/linux/diagchar.h
+++ b/include/linux/diagchar.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2008-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
@@ -13,14 +13,18 @@
 #ifndef DIAGCHAR_SHARED
 #define DIAGCHAR_SHARED
 
-#define MSG_MASKS_TYPE			1
-#define LOG_MASKS_TYPE			2
-#define EVENT_MASKS_TYPE		4
-#define PKT_TYPE			8
-#define DEINIT_TYPE			16
-#define USER_SPACE_DATA_TYPE		32
-#define DCI_DATA_TYPE			64
-#define CALLBACK_DATA_TYPE		128
+#define MSG_MASKS_TYPE		0x00000001
+#define LOG_MASKS_TYPE		0x00000002
+#define EVENT_MASKS_TYPE	0x00000004
+#define PKT_TYPE		0x00000008
+#define DEINIT_TYPE		0x00000010
+#define USER_SPACE_DATA_TYPE	0x00000020
+#define DCI_DATA_TYPE		0x00000040
+#define CALLBACK_DATA_TYPE	0x00000080
+#define DCI_LOG_MASKS_TYPE	0x00000100
+#define DCI_EVENT_MASKS_TYPE	0x00000200
+#define DCI_PKT_TYPE		0x00000400
+
 #define USB_MODE			1
 #define MEMORY_DEVICE_MODE		2
 #define NO_LOGGING_MODE			3
@@ -32,6 +36,8 @@
 #define DATA_TYPE_F3            	1
 #define DATA_TYPE_LOG           	2
 #define DATA_TYPE_RESPONSE      	3
+#define DATA_TYPE_DCI_LOG		0x00000100
+#define DATA_TYPE_DCI_EVENT		0x00000200
 
 /* Different IOCTL values */
 #define DIAG_IOCTL_COMMAND_REG  	0
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 093f0b8..6181c69 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -2436,6 +2436,7 @@
 void dio_end_io(struct bio *bio, int error);
 void inode_dio_wait(struct inode *inode);
 void inode_dio_done(struct inode *inode);
+struct inode *dio_bio_get_inode(struct bio *bio);
 
 ssize_t __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode,
 	struct block_device *bdev, const struct iovec *iov, loff_t offset,
diff --git a/include/linux/msm_mdp.h b/include/linux/msm_mdp.h
index fd2cc6c..b295fcc 100644
--- a/include/linux/msm_mdp.h
+++ b/include/linux/msm_mdp.h
@@ -81,6 +81,7 @@
 #define MSMFB_ASYNC_BLIT              _IOW(MSMFB_IOCTL_MAGIC, 168, unsigned int)
 #define MSMFB_OVERLAY_PREPARE		_IOWR(MSMFB_IOCTL_MAGIC, 169, \
 						struct mdp_overlay_list)
+#define MSMFB_LPM_ENABLE        _IOWR(MSMFB_IOCTL_MAGIC, 170, unsigned int)
 #define FB_TYPE_3D_PANEL 0x10101010
 #define MDP_IMGTYPE2_START 0x10000
 #define MSMFB_DRIVER_VERSION	0xF9E8D701
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..2ec92da
--- /dev/null
+++ b/include/linux/pft.h
@@ -0,0 +1,93 @@
+/* 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>
+#include <linux/bio.h>
+
+#ifdef CONFIG_PFT
+
+/* dm-req-crypt API */
+int pft_get_key_index(struct bio *bio, 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/security.h b/include/linux/security.h
index b62f396..0fe0a70 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -26,6 +26,7 @@
 #include <linux/capability.h>
 #include <linux/slab.h>
 #include <linux/err.h>
+#include <linux/bio.h>
 
 struct linux_binprm;
 struct cred;
@@ -1453,6 +1454,8 @@
 				    void **value, size_t *len);
 	int (*inode_create) (struct inode *dir,
 			     struct dentry *dentry, umode_t mode);
+	int (*inode_post_create) (struct inode *dir,
+				  struct dentry *dentry, umode_t mode);
 	int (*inode_link) (struct dentry *old_dentry,
 			   struct inode *dir, struct dentry *new_dentry);
 	int (*inode_unlink) (struct inode *dir, struct dentry *dentry);
@@ -1503,6 +1506,8 @@
 				    struct fown_struct *fown, int sig);
 	int (*file_receive) (struct file *file);
 	int (*dentry_open) (struct file *file, const struct cred *cred);
+	int (*file_close) (struct file *file);
+	bool (*allow_merge_bio)(struct bio *bio1, struct bio *bio2);
 
 	int (*task_create) (unsigned long clone_flags);
 	void (*task_free) (struct task_struct *task);
@@ -1722,6 +1727,9 @@
 				     const struct qstr *qstr, char **name,
 				     void **value, size_t *len);
 int security_inode_create(struct inode *dir, struct dentry *dentry, umode_t mode);
+int security_inode_post_create(struct inode *dir, struct dentry *dentry,
+			       umode_t mode);
+
 int security_inode_link(struct dentry *old_dentry, struct inode *dir,
 			 struct dentry *new_dentry);
 int security_inode_unlink(struct inode *dir, struct dentry *dentry);
@@ -1766,6 +1774,9 @@
 				 struct fown_struct *fown, int sig);
 int security_file_receive(struct file *file);
 int security_dentry_open(struct file *file, const struct cred *cred);
+int security_file_close(struct file *file);
+bool security_allow_merge_bio(struct bio *bio1, struct bio *bio2);
+
 int security_task_create(unsigned long clone_flags);
 void security_task_free(struct task_struct *task);
 int security_cred_alloc_blank(struct cred *cred, gfp_t gfp);
@@ -2060,6 +2071,13 @@
 	return 0;
 }
 
+static inline int security_inode_post_create(struct inode *dir,
+					     struct dentry *dentry,
+					     umode_t mode)
+{
+	return 0;
+}
+
 static inline int security_inode_link(struct dentry *old_dentry,
 				       struct inode *dir,
 				       struct dentry *new_dentry)
@@ -2262,6 +2280,16 @@
 	return 0;
 }
 
+static inline int security_file_close(struct file *file)
+{
+	return 0;
+}
+
+static inline bool security_allow_merge_bio(struct bio *bio1, struct bio *bio2)
+{
+	return true; /* The default is to allow it for performance */
+}
+
 static inline int security_task_create(unsigned long clone_flags)
 {
 	return 0;
diff --git a/include/linux/spmi.h b/include/linux/spmi.h
index e8e932e..b581de8 100644
--- a/include/linux/spmi.h
+++ b/include/linux/spmi.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-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
@@ -382,6 +382,7 @@
  * -EPERM if the SPMI transaction is denied due to permission issues.
  * -EIO if the SPMI transaction fails (parity errors, etc).
  * -ETIMEDOUT if the SPMI transaction times out.
+ * -EAGAIN if the SPMI transaction is temporarily unavailable
  */
 extern int spmi_command_reset(struct spmi_controller *ctrl, u8 sid);
 
@@ -397,6 +398,7 @@
  * -EPERM if the SPMI transaction is denied due to permission issues.
  * -EIO if the SPMI transaction fails (parity errors, etc).
  * -ETIMEDOUT if the SPMI transaction times out.
+ * -EAGAIN if the SPMI transaction is temporarily unavailable
  */
 extern int spmi_command_sleep(struct spmi_controller *ctrl, u8 sid);
 
@@ -413,6 +415,7 @@
  * -EPERM if the SPMI transaction is denied due to permission issues.
  * -EIO if the SPMI transaction fails (parity errors, etc).
  * -ETIMEDOUT if the SPMI transaction times out.
+ * -EAGAIN if the SPMI transaction is temporarily unavailable
  */
 extern int spmi_command_wakeup(struct spmi_controller *ctrl, u8 sid);
 
@@ -428,6 +431,7 @@
  * -EPERM if the SPMI transaction is denied due to permission issues.
  * -EIO if the SPMI transaction fails (parity errors, etc).
  * -ETIMEDOUT if the SPMI transaction times out.
+ * -EAGAIN if the SPMI transaction is temporarily unavailable
  */
 extern int spmi_command_shutdown(struct spmi_controller *ctrl, u8 sid);
 
diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h
index 44fe134..b93f693 100644
--- a/include/linux/usb/msm_hsusb.h
+++ b/include/linux/usb/msm_hsusb.h
@@ -338,6 +338,10 @@
  * @regs: ioremapped register base address.
  * @inputs: OTG state machine inputs(Id, SessValid etc).
  * @sm_work: OTG state machine work.
+ * @pm_suspended: OTG device is system(PM) suspended.
+ * @pm_notify: Notifier to receive system wide PM transition events.
+		It is used to defer wakeup events processing until
+		system is RESUMED.
  * @in_lpm: indicates low power mode (LPM) state.
  * @async_int: IRQ line on which ASYNC interrupt arrived in LPM.
  * @cur_power: The amount of mA available from downstream port.
@@ -401,6 +405,7 @@
 	struct work_struct sm_work;
 	bool sm_work_pending;
 	atomic_t pm_suspended;
+	struct notifier_block pm_notify;
 	atomic_t in_lpm;
 	int async_int;
 	unsigned cur_power;
diff --git a/include/media/msmb_isp.h b/include/media/msmb_isp.h
index 30e7d06..e627977 100644
--- a/include/media/msmb_isp.h
+++ b/include/media/msmb_isp.h
@@ -154,6 +154,7 @@
 	uint8_t buf_divert; /* if TRUE no vb2 buf done. */
 	/*Return values*/
 	uint32_t axi_stream_handle;
+	uint32_t burst_len;
 };
 
 struct msm_vfe_axi_stream_release_cmd {
@@ -225,6 +226,7 @@
 	uint8_t num_streams;
 	uint32_t stream_handle[MSM_ISP_STATS_MAX];
 	uint8_t enable;
+	uint32_t stats_burst_len;
 };
 
 enum msm_vfe_reg_cfg_type {
@@ -242,6 +244,7 @@
 	GET_MAX_CLK_RATE,
 	VFE_HW_UPDATE_LOCK,
 	VFE_HW_UPDATE_UNLOCK,
+	SET_WM_UB_SIZE,
 };
 
 struct msm_vfe_cfg_cmd2 {
diff --git a/include/net/netlink.h b/include/net/netlink.h
index f394fe5..c0f13ad 100644
--- a/include/net/netlink.h
+++ b/include/net/netlink.h
@@ -98,6 +98,10 @@
  *   nla_put_u16(skb, type, value)	add u16 attribute to skb
  *   nla_put_u32(skb, type, value)	add u32 attribute to skb
  *   nla_put_u64(skb, type, value)	add u64 attribute to skb
+ *   nla_put_s8(skb, type, value)      add s8 attribute to skb
+ *   nla_put_s16(skb, type, value)     add s16 attribute to skb
+ *   nla_put_s32(skb, type, value)     add s32 attribute to skb
+ *   nla_put_s64(skb, type, value)     add s64 attribute to skb
  *   nla_put_string(skb, type, str)	add string attribute to skb
  *   nla_put_flag(skb, type)		add flag attribute to skb
  *   nla_put_msecs(skb, type, jiffies)	add msecs attribute to skb
@@ -135,6 +139,10 @@
  *   nla_get_u16(nla)			get payload for a u16 attribute
  *   nla_get_u32(nla)			get payload for a u32 attribute
  *   nla_get_u64(nla)			get payload for a u64 attribute
+ *   nla_get_s8(nla)                   get payload for a s8 attribute
+ *   nla_get_s16(nla)                  get payload for a s16 attribute
+ *   nla_get_s32(nla)                  get payload for a s32 attribute
+ *   nla_get_s64(nla)                  get payload for a s64 attribute
  *   nla_get_flag(nla)			return 1 if flag is true
  *   nla_get_msecs(nla)			get payload for a msecs attribute
  *
@@ -174,6 +182,10 @@
 	NLA_NESTED_COMPAT,
 	NLA_NUL_STRING,
 	NLA_BINARY,
+	NLA_S8,
+	NLA_S16,
+	NLA_S32,
+	NLA_S64,
 	__NLA_TYPE_MAX,
 };
 
@@ -200,6 +212,8 @@
  *    NLA_MSECS            Leaving the length field zero will verify the
  *                         given type fits, using it verifies minimum length
  *                         just like "All other"
+ *    NLA_S8, NLA_S16,
+ *    NLA_S32, NLA_S64,
  *    All other            Minimum length of attribute payload
  *
  * Example:
@@ -794,6 +808,50 @@
 }
 
 /**
+ * nla_put_s8 - Add a s8 netlink attribute to a socket buffer
+ * @skb: socket buffer to add attribute to
+ * @attrtype: attribute type
+ * @value: numeric value
+ */
+static inline int nla_put_s8(struct sk_buff *skb, int attrtype, s8 value)
+{
+	return nla_put(skb, attrtype, sizeof(s8), &value);
+}
+
+/**
+ * nla_put_s16 - Add a s16 netlink attribute to a socket buffer
+ * @skb: socket buffer to add attribute to
+ * @attrtype: attribute type
+ * @value: numeric value
+ */
+static inline int nla_put_s16(struct sk_buff *skb, int attrtype, s16 value)
+{
+	return nla_put(skb, attrtype, sizeof(s16), &value);
+}
+
+/**
+ * nla_put_s32 - Add a s32 netlink attribute to a socket buffer
+ * @skb: socket buffer to add attribute to
+ * @attrtype: attribute type
+ * @value: numeric value
+ */
+static inline int nla_put_s32(struct sk_buff *skb, int attrtype, s32 value)
+{
+	return nla_put(skb, attrtype, sizeof(s32), &value);
+}
+
+/**
+ * nla_put_s64 - Add a s64 netlink attribute to a socket buffer
+ * @skb: socket buffer to add attribute to
+ * @attrtype: attribute type
+ * @value: numeric value
+ */
+static inline int nla_put_s64(struct sk_buff *skb, int attrtype, s64 value)
+{
+	return nla_put(skb, attrtype, sizeof(s64), &value);
+}
+
+/**
  * nla_put_string - Add a string netlink attribute to a socket buffer
  * @skb: socket buffer to add attribute to
  * @attrtype: attribute type
@@ -963,6 +1021,46 @@
 }
 
 /**
+ * nla_get_s32 - return payload of s32 attribute
+ * @nla: s32 netlink attribute
+ */
+static inline s32 nla_get_s32(const struct nlattr *nla)
+{
+	return *(s32 *) nla_data(nla);
+}
+
+/**
+ * nla_get_s16 - return payload of s16 attribute
+ * @nla: s16 netlink attribute
+ */
+static inline s16 nla_get_s16(const struct nlattr *nla)
+{
+	return *(s16 *) nla_data(nla);
+}
+
+/**
+ * nla_get_s8 - return payload of s8 attribute
+ * @nla: s8 netlink attribute
+ */
+static inline s8 nla_get_s8(const struct nlattr *nla)
+{
+	return *(s8 *) nla_data(nla);
+}
+
+/**
+ * nla_get_s64 - return payload of s64 attribute
+ * @nla: s64 netlink attribute
+ */
+static inline s64 nla_get_s64(const struct nlattr *nla)
+{
+	s64 tmp;
+
+	nla_memcpy(&tmp, nla, sizeof(tmp));
+
+	return tmp;
+}
+
+/**
  * nla_get_flag - return payload of flag attribute
  * @nla: flag netlink attribute
  */
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index cf82dbd..4ff640a 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -1963,8 +1963,8 @@
 
 	hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0,
 			     NL80211_CMD_NEW_KEY);
-	if (IS_ERR(hdr))
-		return PTR_ERR(hdr);
+	if (!hdr)
+		goto nla_put_failure;
 
 	cookie.msg = msg;
 	cookie.idx = key_idx;
@@ -4245,6 +4245,10 @@
 				err = -EINVAL;
 				goto out_free;
 			}
+
+			if (!wiphy->bands[band])
+				continue;
+
 			err = ieee80211_get_ratemask(wiphy->bands[band],
 						     nla_data(attr),
 						     nla_len(attr),
@@ -5409,6 +5413,9 @@
 					   NL80211_CMD_TESTMODE);
 		struct nlattr *tmdata;
 
+		if (!hdr)
+			break;
+
 		if (nla_put_u32(skb, NL80211_ATTR_WIPHY, phy_idx) < 0) {
 			genlmsg_cancel(skb, hdr);
 			break;
@@ -5817,9 +5824,8 @@
 
 	hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0,
 			     NL80211_CMD_REMAIN_ON_CHANNEL);
-
-	if (IS_ERR(hdr)) {
-		err = PTR_ERR(hdr);
+	if (!hdr) {
+		err = -ENOBUFS;
 		goto free_msg;
 	}
 
@@ -6100,9 +6106,8 @@
 
 		hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0,
 				     NL80211_CMD_FRAME);
-
-		if (IS_ERR(hdr)) {
-			err = PTR_ERR(hdr);
+		if (!hdr) {
+			err = -ENOBUFS;
 			goto free_msg;
 		}
 	}
@@ -6662,9 +6667,8 @@
 
 	hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0,
 			     NL80211_CMD_PROBE_CLIENT);
-
-	if (IS_ERR(hdr)) {
-		err = PTR_ERR(hdr);
+	if (!hdr) {
+		err = -ENOBUFS;
 		goto free_msg;
 	}
 
diff --git a/net/wireless/sme.c b/net/wireless/sme.c
index 87547ca..94c06df 100644
--- a/net/wireless/sme.c
+++ b/net/wireless/sme.c
@@ -65,11 +65,45 @@
 	return is_all_idle;
 }
 
+
+static bool cfg80211_is_all_countryie_ignore(void)
+{
+	struct cfg80211_registered_device *rdev;
+	struct wireless_dev *wdev;
+	bool is_all_countryie_ignore = true;
+
+	mutex_lock(&cfg80211_mutex);
+
+	list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
+		cfg80211_lock_rdev(rdev);
+		list_for_each_entry(wdev, &rdev->netdev_list, list) {
+			wdev_lock(wdev);
+			if (!(wdev->wiphy->country_ie_pref &
+				NL80211_COUNTRY_IE_IGNORE_CORE)) {
+				is_all_countryie_ignore = false;
+				wdev_unlock(wdev);
+				cfg80211_unlock_rdev(rdev);
+				goto out;
+			}
+			wdev_unlock(wdev);
+		}
+		cfg80211_unlock_rdev(rdev);
+	}
+out:
+	mutex_unlock(&cfg80211_mutex);
+
+	return is_all_countryie_ignore;
+}
+
+
 static void disconnect_work(struct work_struct *work)
 {
 	if (!cfg80211_is_all_idle())
 		return;
 
+	if (cfg80211_is_all_countryie_ignore())
+		return;
+
 	regulatory_hint_disconnect();
 }
 
diff --git a/scripts/gcc-wrapper.py b/scripts/gcc-wrapper.py
index 548d655..f503aa2 100755
--- a/scripts/gcc-wrapper.py
+++ b/scripts/gcc-wrapper.py
@@ -41,6 +41,7 @@
 
 allowed_warnings = set([
     "return_address.c:62",
+    "hci_conn.c:407",
  ])
 
 # Capture the name of the object file, can find it.
diff --git a/security/security.c b/security/security.c
index cecd55e..cc355c0 100644
--- a/security/security.c
+++ b/security/security.c
@@ -471,6 +471,16 @@
 }
 EXPORT_SYMBOL_GPL(security_inode_create);
 
+int security_inode_post_create(struct inode *dir, struct dentry *dentry,
+			       umode_t mode)
+{
+	if (unlikely(IS_PRIVATE(dir)))
+		return 0;
+	if (security_ops->inode_post_create == NULL)
+		return 0;
+	return security_ops->inode_post_create(dir, dentry, mode);
+}
+
 int security_inode_link(struct dentry *old_dentry, struct inode *dir,
 			 struct dentry *new_dentry)
 {
@@ -732,6 +742,22 @@
 	return fsnotify_perm(file, MAY_OPEN);
 }
 
+int security_file_close(struct file *file)
+{
+	if (security_ops->file_close)
+		return security_ops->file_close(file);
+
+	return 0;
+}
+
+bool security_allow_merge_bio(struct bio *bio1, struct bio *bio2)
+{
+	if (security_ops->allow_merge_bio)
+		return security_ops->allow_merge_bio(bio1, bio2);
+
+	return true;
+}
+
 int security_task_create(unsigned long clone_flags)
 {
 	return security_ops->task_create(clone_flags);
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index c868a74..50b003a 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -82,6 +82,7 @@
 #include <linux/export.h>
 #include <linux/msg.h>
 #include <linux/shm.h>
+#include <linux/pft.h>
 
 #include "avc.h"
 #include "objsec.h"
@@ -1617,9 +1618,15 @@
 	if (rc)
 		return rc;
 
-	return avc_has_perm(newsid, sbsec->sid,
-			    SECCLASS_FILESYSTEM,
-			    FILESYSTEM__ASSOCIATE, &ad);
+	rc = avc_has_perm(newsid, sbsec->sid,
+			  SECCLASS_FILESYSTEM,
+			  FILESYSTEM__ASSOCIATE, &ad);
+	if (rc)
+		return rc;
+
+	rc = pft_inode_mknod(dir, dentry, 0, 0);
+
+	return rc;
 }
 
 /* Check whether a task can create a key. */
@@ -1678,6 +1685,12 @@
 	}
 
 	rc = avc_has_perm(sid, isec->sid, isec->sclass, av, &ad);
+	if (rc)
+		return rc;
+
+	if (kind == MAY_UNLINK)
+		rc = pft_inode_unlink(dir, dentry);
+
 	return rc;
 }
 
@@ -2684,9 +2697,25 @@
 
 static int selinux_inode_create(struct inode *dir, struct dentry *dentry, umode_t mode)
 {
+	int ret;
+
+	ret = pft_inode_create(dir, dentry, mode);
+	if (ret < 0)
+		return ret;
+
 	return may_create(dir, dentry, SECCLASS_FILE);
 }
 
+static int selinux_inode_post_create(struct inode *dir, struct dentry *dentry,
+				     umode_t mode)
+{
+	int ret;
+
+	ret = pft_inode_post_create(dir, dentry, mode);
+
+	return ret;
+}
+
 static int selinux_inode_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry)
 {
 	return may_link(dir, old_dentry, MAY_LINK);
@@ -2720,6 +2749,12 @@
 static int selinux_inode_rename(struct inode *old_inode, struct dentry *old_dentry,
 				struct inode *new_inode, struct dentry *new_dentry)
 {
+	int rc;
+
+	rc = pft_inode_rename(old_inode, old_dentry, new_inode, new_dentry);
+	if (rc)
+		return rc;
+
 	return may_rename(old_inode, old_dentry, new_inode, new_dentry);
 }
 
@@ -2800,6 +2835,10 @@
 {
 	const struct cred *cred = current_cred();
 
+	if (pft_inode_set_xattr(dentry, name) < 0)
+		return -EACCES;
+
+
 	if (!strncmp(name, XATTR_SECURITY_PREFIX,
 		     sizeof XATTR_SECURITY_PREFIX - 1)) {
 		if (!strcmp(name, XATTR_NAME_CAPS)) {
@@ -3023,11 +3062,16 @@
 	struct file_security_struct *fsec = file->f_security;
 	struct inode_security_struct *isec = inode->i_security;
 	u32 sid = current_sid();
+	int ret;
 
 	if (!mask)
 		/* No permission to check.  Existence test. */
 		return 0;
 
+	ret = pft_file_permission(file, mask);
+	if (ret < 0)
+		return ret;
+
 	if (sid == fsec->sid && fsec->isid == isec->sid &&
 	    fsec->pseqno == avc_policy_seqno())
 		/* No change since dentry_open check. */
@@ -3294,6 +3338,11 @@
 	struct file_security_struct *fsec;
 	struct inode *inode;
 	struct inode_security_struct *isec;
+	int ret;
+
+	ret = pft_file_open(file, cred);
+	if (ret < 0)
+		return ret;
 
 	inode = file->f_path.dentry->d_inode;
 	fsec = file->f_security;
@@ -3318,6 +3367,16 @@
 	return inode_has_perm_noadp(cred, inode, open_file_to_av(file), 0);
 }
 
+static int selinux_file_close(struct file *file)
+{
+	return pft_file_close(file);
+}
+
+static bool selinux_allow_merge_bio(struct bio *bio1, struct bio *bio2)
+{
+	return pft_allow_merge_bio(bio1, bio2);
+}
+
 /* task security operations */
 
 static int selinux_task_create(unsigned long clone_flags)
@@ -5629,6 +5688,7 @@
 	.inode_free_security =		selinux_inode_free_security,
 	.inode_init_security =		selinux_inode_init_security,
 	.inode_create =			selinux_inode_create,
+	.inode_post_create =		selinux_inode_post_create,
 	.inode_link =			selinux_inode_link,
 	.inode_unlink =			selinux_inode_unlink,
 	.inode_symlink =		selinux_inode_symlink,
@@ -5664,6 +5724,8 @@
 	.file_receive =			selinux_file_receive,
 
 	.dentry_open =			selinux_dentry_open,
+	.file_close =			selinux_file_close,
+	.allow_merge_bio =		selinux_allow_merge_bio,
 
 	.task_create =			selinux_task_create,
 	.cred_alloc_blank =		selinux_cred_alloc_blank,
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/sound/soc/codecs/wcd9306.c b/sound/soc/codecs/wcd9306.c
index 38d7901..314c4f9 100644
--- a/sound/soc/codecs/wcd9306.c
+++ b/sound/soc/codecs/wcd9306.c
@@ -4139,6 +4139,12 @@
 
 	core = dev_get_drvdata(codec->dev->parent);
 
+	if(core == NULL) {
+		dev_err(codec->dev, "%s: core is null\n",
+				__func__);
+		return -EINVAL;
+	}
+
 	dev_dbg(codec->dev, "%s: event called! codec name %s\n",
 		__func__, w->codec->name);
 	dev_dbg(codec->dev, "%s: num_dai %d stream name %s event %d\n",
diff --git a/sound/soc/codecs/wcd9320.c b/sound/soc/codecs/wcd9320.c
index 4c5d327..e17925f 100644
--- a/sound/soc/codecs/wcd9320.c
+++ b/sound/soc/codecs/wcd9320.c
@@ -35,6 +35,9 @@
 #include <linux/pm_runtime.h>
 #include <linux/kernel.h>
 #include <linux/gpio.h>
+#include <linux/pm_qos.h>
+#include <linux/pm.h>
+#include <mach/cpuidle.h>
 #include "wcd9320.h"
 #include "wcd9xxx-resmgr.h"
 #include "wcd9xxx-common.h"
@@ -449,6 +452,7 @@
 	 * end of impedance measurement
 	 */
 	struct list_head reg_save_restore;
+	struct pm_qos_request pm_qos_req;
 };
 
 static const u32 comp_shift[] = {
@@ -2555,9 +2559,10 @@
 						 WCD9XXX_CLSH_STATE_LO,
 						 WCD9XXX_CLSH_REQ_ENABLE,
 						 WCD9XXX_CLSH_EVENT_POST_PA);
-		pr_debug("%s: sleeping 3 ms after %s PA turn on\n",
+		pr_debug("%s: sleeping 5 ms after %s PA turn on\n",
 				__func__, w->name);
-		usleep_range(3000, 3000);
+		/* Wait for CnP time after PA enable */
+		usleep_range(5000, 5100);
 		break;
 	case SND_SOC_DAPM_POST_PMD:
 		wcd9xxx_clsh_fsm(codec, &taiko->clsh_d,
@@ -2565,6 +2570,10 @@
 						 WCD9XXX_CLSH_REQ_DISABLE,
 						 WCD9XXX_CLSH_EVENT_POST_PA);
 		snd_soc_update_bits(codec, lineout_gain_reg, 0x40, 0x00);
+		pr_debug("%s: sleeping 5 ms after %s PA turn off\n",
+				__func__, w->name);
+		/* Wait for CnP time after PA disable */
+		usleep_range(5000, 5100);
 		break;
 	}
 	return 0;
@@ -2670,8 +2679,15 @@
 	const struct firmware *fw;
 	struct mad_audio_cal *mad_cal;
 	const char *filename = TAIKO_MAD_AUDIO_FIRMWARE_PATH;
+	struct taiko_priv *taiko = snd_soc_codec_get_drvdata(codec);
 
 	pr_debug("%s: enter\n", __func__);
+	/* wakeup for codec calibration access */
+	pm_qos_add_request(&taiko->pm_qos_req,
+			   PM_QOS_CPU_DMA_LATENCY,
+			   PM_QOS_DEFAULT_VALUE);
+	pm_qos_update_request(&taiko->pm_qos_req,
+			      msm_cpuidle_get_deep_idle_latency());
 	ret = request_firmware(&fw, filename, codec->dev);
 	if (ret != 0) {
 		pr_err("Failed to acquire MAD firwmare data %s: %d\n", filename,
@@ -2741,7 +2757,9 @@
 
 	release_firmware(fw);
 	pr_debug("%s: leave ret %d\n", __func__, ret);
-
+	pm_qos_update_request(&taiko->pm_qos_req,
+			      PM_QOS_DEFAULT_VALUE);
+	pm_qos_remove_request(&taiko->pm_qos_req);
 	return ret;
 }
 
diff --git a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c
index fce1940..3bc6abe 100644
--- a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c
@@ -129,6 +129,8 @@
 	uint32_t stream_available;
 	uint32_t next_stream;
 
+	uint64_t marker_timestamp;
+
 	struct msm_compr_gapless_state gapless_state;
 
 	atomic_t start;
@@ -597,6 +599,16 @@
 				prtd->session_id,
 				SNDRV_PCM_STREAM_PLAYBACK);
 
+	/*
+	 * Setting the master volume gain to 0 while
+	 * configuring ASM session. This is to address
+	 * DSP pop noise issue where. This change is
+	 * there from begining may be DSP limitation
+	 */
+	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",
@@ -1064,6 +1076,7 @@
 		prtd->app_pointer  = 0;
 		prtd->bytes_received = 0;
 		prtd->bytes_sent = 0;
+		prtd->marker_timestamp = 0;
 
 		atomic_set(&prtd->xrun, 0);
 		spin_unlock_irqrestore(&prtd->lock, flags);
@@ -1196,6 +1209,8 @@
 			prtd->first_buffer = 1;
 			prtd->last_buffer = 0;
 			prtd->gapless_state.gapless_transition = 1;
+			prtd->marker_timestamp = 0;
+
 			/*
 			Don't reset these as these vars map to
 			total_bytes_transferred and total_bytes_available
@@ -1251,23 +1266,23 @@
 			q6asm_stream_cmd_nowait(ac, CMD_PAUSE, ac->stream_id);
 			prtd->cmd_ack = 0;
 			spin_unlock_irqrestore(&prtd->lock, flags);
-			pr_debug("%s:issue CMD_FLUSH ac->stream_id %d",
-					      __func__, ac->stream_id);
-			q6asm_stream_cmd(ac, CMD_FLUSH, ac->stream_id);
-			wait_event_timeout(prtd->flush_wait,
-					   prtd->cmd_ack, 1 * HZ / 4);
 
+			/*
+			 * Cache this time as last known time
+			 */
+			q6asm_get_session_time(prtd->audio_client,
+					       &prtd->marker_timestamp);
 			spin_lock_irqsave(&prtd->lock, flags);
 			/*
-			Don't reset these as these vars map to
-			total_bytes_transferred and total_bytes_available
-			directly, only total_bytes_transferred will be updated
-			in the next avail() ioctl
-			prtd->copied_total = 0;
-			prtd->bytes_received = 0;
-			do not reset prtd->bytes_sent as well as the same
-			session is used for gapless playback
-			*/
+			 * Don't reset these as these vars map to
+			 * total_bytes_transferred and total_bytes_available.
+			 * Just total_bytes_transferred will be updated
+			 * in the next avail() ioctl.
+			 * prtd->copied_total = 0;
+			 * prtd->bytes_received = 0;
+			 * do not reset prtd->bytes_sent as well as the same
+			 * session is used for gapless playback
+			 */
 			prtd->byte_offset = 0;
 
 			prtd->app_pointer  = 0;
@@ -1275,8 +1290,15 @@
 			prtd->last_buffer = 0;
 			atomic_set(&prtd->drain, 0);
 			atomic_set(&prtd->xrun, 1);
-			q6asm_run_nowait(prtd->audio_client, 0, 0, 0);
 			spin_unlock_irqrestore(&prtd->lock, flags);
+
+			pr_debug("%s:issue CMD_FLUSH ac->stream_id %d",
+					      __func__, ac->stream_id);
+			q6asm_stream_cmd(ac, CMD_FLUSH, ac->stream_id);
+			wait_event_timeout(prtd->flush_wait,
+					   prtd->cmd_ack, 1 * HZ / 4);
+
+			q6asm_run_nowait(prtd->audio_client, 0, 0, 0);
 		}
 		prtd->cmd_interrupt = 0;
 		break;
@@ -1404,6 +1426,8 @@
 				__func__, timestamp);
 			return -EAGAIN;
 		}
+	} else {
+		timestamp = prtd->marker_timestamp;
 	}
 
 	/* DSP returns timestamp in usec */
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
index 4893990..1553d1c 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
@@ -3971,50 +3971,36 @@
 	{"AUDIO_REF_EC_UL1 MUX", "SEC_MI2S_TX" , "SEC_MI2S_TX"},
 	{"AUDIO_REF_EC_UL1 MUX", "TERT_MI2S_TX" , "TERT_MI2S_TX"},
 	{"AUDIO_REF_EC_UL1 MUX", "QUAT_MI2S_TX" , "QUAT_MI2S_TX"},
-	{"AUDIO_REF_EC_UL1 MUX", "I2S_RX" , "PRI_I2S_TX"},
-	{"AUDIO_REF_EC_UL1 MUX", "SLIM_RX" , "SLIMBUS_0_TX"},
 
 	{"AUDIO_REF_EC_UL2 MUX", "PRI_MI2S_TX" , "PRI_MI2S_TX"},
 	{"AUDIO_REF_EC_UL2 MUX", "SEC_MI2S_TX" , "SEC_MI2S_TX"},
 	{"AUDIO_REF_EC_UL2 MUX", "TERT_MI2S_TX" , "TERT_MI2S_TX"},
 	{"AUDIO_REF_EC_UL2 MUX", "QUAT_MI2S_TX" , "QUAT_MI2S_TX"},
-	{"AUDIO_REF_EC_UL2 MUX", "I2S_RX" , "PRI_I2S_TX"},
-	{"AUDIO_REF_EC_UL2 MUX", "SLIM_RX" , "SLIMBUS_0_TX"},
 
 	{"AUDIO_REF_EC_UL4 MUX", "PRI_MI2S_TX" , "PRI_MI2S_TX"},
 	{"AUDIO_REF_EC_UL4 MUX", "SEC_MI2S_TX" , "SEC_MI2S_TX"},
 	{"AUDIO_REF_EC_UL4 MUX", "TERT_MI2S_TX" , "TERT_MI2S_TX"},
 	{"AUDIO_REF_EC_UL4 MUX", "QUAT_MI2S_TX" , "QUAT_MI2S_TX"},
-	{"AUDIO_REF_EC_UL4 MUX", "I2S_RX" , "PRI_I2S_TX"},
-	{"AUDIO_REF_EC_UL4 MUX", "SLIM_RX" , "SLIMBUS_0_TX"},
 
 	{"AUDIO_REF_EC_UL5 MUX", "PRI_MI2S_TX" , "PRI_MI2S_TX"},
 	{"AUDIO_REF_EC_UL5 MUX", "SEC_MI2S_TX" , "SEC_MI2S_TX"},
 	{"AUDIO_REF_EC_UL5 MUX", "TERT_MI2S_TX" , "TERT_MI2S_TX"},
 	{"AUDIO_REF_EC_UL5 MUX", "QUAT_MI2S_TX" , "QUAT_MI2S_TX"},
-	{"AUDIO_REF_EC_UL5 MUX", "I2S_RX" , "PRI_I2S_TX"},
-	{"AUDIO_REF_EC_UL5 MUX", "SLIM_RX" , "SLIMBUS_0_TX"},
 
 	{"AUDIO_REF_EC_UL6 MUX", "PRI_MI2S_TX" , "PRI_MI2S_TX"},
 	{"AUDIO_REF_EC_UL6 MUX", "SEC_MI2S_TX" , "SEC_MI2S_TX"},
 	{"AUDIO_REF_EC_UL6 MUX", "TERT_MI2S_TX" , "TERT_MI2S_TX"},
 	{"AUDIO_REF_EC_UL6 MUX", "QUAT_MI2S_TX" , "QUAT_MI2S_TX"},
-	{"AUDIO_REF_EC_UL6 MUX", "I2S_RX" , "PRI_I2S_TX"},
-	{"AUDIO_REF_EC_UL6 MUX", "SLIM_RX" , "SLIMBUS_0_TX"},
 
 	{"AUDIO_REF_EC_UL8 MUX", "PRI_MI2S_TX" , "PRI_MI2S_TX"},
 	{"AUDIO_REF_EC_UL8 MUX", "SEC_MI2S_TX" , "SEC_MI2S_TX"},
 	{"AUDIO_REF_EC_UL8 MUX", "TERT_MI2S_TX" , "TERT_MI2S_TX"},
 	{"AUDIO_REF_EC_UL8 MUX", "QUAT_MI2S_TX" , "QUAT_MI2S_TX"},
-	{"AUDIO_REF_EC_UL8 MUX", "I2S_RX" , "PRI_I2S_TX"},
-	{"AUDIO_REF_EC_UL8 MUX", "SLIM_RX" , "SLIMBUS_0_TX"},
 
 	{"AUDIO_REF_EC_UL9 MUX", "PRI_MI2S_TX" , "PRI_MI2S_TX"},
 	{"AUDIO_REF_EC_UL9 MUX", "SEC_MI2S_TX" , "SEC_MI2S_TX"},
 	{"AUDIO_REF_EC_UL9 MUX", "TERT_MI2S_TX" , "TERT_MI2S_TX"},
 	{"AUDIO_REF_EC_UL9 MUX", "QUAT_MI2S_TX" , "QUAT_MI2S_TX"},
-	{"AUDIO_REF_EC_UL9 MUX", "I2S_RX" , "PRI_I2S_TX"},
-	{"AUDIO_REF_EC_UL9 MUX", "SLIM_RX" , "SLIMBUS_0_TX"},
 
 	{"MM_UL1", NULL, "AUDIO_REF_EC_UL1 MUX"},
 	{"MM_UL2", NULL, "AUDIO_REF_EC_UL2 MUX"},
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,