Merge "qseecom: Fix error handling path in receive_req()"
diff --git a/Documentation/arm/msm/msm_sharedmem.txt b/Documentation/arm/msm/msm_sharedmem.txt
new file mode 100644
index 0000000..d9c939e
--- /dev/null
+++ b/Documentation/arm/msm/msm_sharedmem.txt
@@ -0,0 +1,115 @@
+Introduction
+============
+
+This is a new platform driver for newly introduced UIO devices
+to facilitate clients in Userspace.
+
+Hardware description
+====================
+This driver does not implement any specific hardware driver.
+
+Software description
+====================
+
+Design
+======
+
+The goal of this driver is to ensure there is no security lapse in the
+Userspace clients' functionality. This new driver uses the existing
+UIO framework to facilitate the clients to be able to memory map their
+respective allotted shared memory address in the client's address space.
+
+				  |
+    Userspace			  |		Kernel space
+ +--------------+	+---------------+	+---------------+
+ |   Client	|	|  Shared	|	|  shrdmem_uio	|
+ |		<------->    Memory	<------->  driver	|
+ +--------------+	+---------------+	+---------------+
+				  |
+				  |
+
+The shared memory (a transport buffer) address is unique for each
+individual client and is made available to the driver via device tree.
+
+For a given client the probe would be called once in the shrdmem_uio driver.
+This driver would parse the device tree and register a new UIO device with kernel
+available under /dev/uioX (where X would start from zero, being serially
+incremented for the next UIO device probed)
+
+The client in Userspace would be able to access the respective UIO device
+under the sysfs entry(/sys/class/uio/uioX) upon verifying the name and version
+of the device under this sysfs node. Once verified it could access the physical
+address under /sys/class/uio/uioX/maps/map0/addr
+
+The client would request for memory mapping which would be taken care of in the
+kernel space by the UIO framework. No explicit mmap() implementation required by
+the shrdmem_uio driver.
+
+Power Management
+================
+Does not implement any power management.
+
+SMP/multi-core
+==============
+
+The platform driver would be loaded/probed once per client.
+DTS files will be looked up for shared memory addresses and sizes for all the clients.
+The UIO char device will be created under /dev/uioX.
+
+This being one time activity for a given client it does not require SMP/multi-core safety.
+
+Security
+========
+
+The devices (/dev/uioX) would have permission checks for restricted access
+
+Performance
+===========
+
+None.
+
+Interface
+=========
+
+This driver does not export any APIs for kernel.
+Android user space can access the shared memory by mmaping it.
+
+Driver parameters
+=================
+
+None.
+
+Config options
+==============
+
+None.
+
+Dependencies
+============
+
+The only dependency is the kernel device tree files for the
+Userspace client details.
+
+User space utilities
+====================
+This driver communicates with the following user space clients/utilities:
+
+Remote File System:
+ - Based on Qualcomm Messaging Interface (QMI)
+ - This service enables the modules on the MSM modem processor to
+   read data from and write data to the embedded multimedia card (eMMC),
+   which is solely controlled by the applications processor.
+
+Remote File System Access (QMI_RFSA):
+ - Based on Qualcomm Messaging Interface (QMI)
+ - This service provides access from the Hexagon processor to a High-Level
+   Operating Sytem (HLOS) file system
+Other
+=====
+
+None.
+
+Known issues
+============
+
+None.
diff --git a/Documentation/cpu-freq/governors.txt b/Documentation/cpu-freq/governors.txt
index b4ae5e6..92bbd16 100644
--- a/Documentation/cpu-freq/governors.txt
+++ b/Documentation/cpu-freq/governors.txt
@@ -234,7 +234,17 @@
 
 above_hispeed_delay: When speed is at or above hispeed_freq, wait for
 this long before raising speed in response to continued high load.
-Default is 20000 uS.
+The format is a single delay value, optionally followed by pairs of
+CPU speeds and the delay to use at or above those speeds.  Colons can
+be used between the speeds and associated delays for readability.  For
+example:
+
+   80000 1300000:200000 1500000:40000
+
+uses delay 80000 uS until CPU speed 1.3 GHz, at which speed delay
+200000 uS is used until speed 1.5 GHz, at which speed (and above)
+delay 40000 uS is used.  If speeds are specified these must appear in
+ascending order.  Default is 20000 uS.
 
 timer_rate: Sample rate for reevaluating CPU load when the CPU is not
 idle.  A deferrable timer is used, such that the CPU will not be woken
diff --git a/Documentation/devicetree/bindings/arm/msm/msm_bus.txt b/Documentation/devicetree/bindings/arm/msm/msm_bus.txt
index fbf1a1f..6283a82 100644
--- a/Documentation/devicetree/bindings/arm/msm/msm_bus.txt
+++ b/Documentation/devicetree/bindings/arm/msm/msm_bus.txt
@@ -101,7 +101,7 @@
 			other parameters used in Limiter and Regular mode
 			for static BKE configuration. It is defined in KBps.
 qcom,bimc,gp:		Grant Period for configuring a master in limiter
-			mode. This is an integer value in micro-seconds.
+			mode. This is an integer value in nano-seconds.
 qcom,bimc,thmp:		Medium threshold percentage for BIMC masters.
 			This percentage is used to calculate medium threshold
 			value for BIMC Masters in Limiter mode for static
diff --git a/Documentation/devicetree/bindings/arm/msm/msm_ion.txt b/Documentation/devicetree/bindings/arm/msm/msm_ion.txt
index 2d83614..f3cf8f3 100644
--- a/Documentation/devicetree/bindings/arm/msm/msm_ion.txt
+++ b/Documentation/devicetree/bindings/arm/msm/msm_ion.txt
@@ -17,6 +17,16 @@
 Required properties for Ion heaps
 
 - reg: The ID of the ION heap.
+- qcom,ion-heap-type: The heap type to use for this heap. Should be one of
+  the following:
+    - "SYSTEM"
+    - "SYSTEM_CONTIG"
+    - "CARVEOUT"
+    - "CHUNK"
+    - "CP"
+    - "DMA"
+    - "SECURE_DMA"
+    - "REMOVED"
 
 Optional properties for Ion heaps
 
@@ -34,16 +44,17 @@
                  #address-cells = <1>;
                  #size-cells = <0>;
 
-                 qcom,ion-heap@30 { /* SYSTEM HEAP */
-                         reg = <30>;
+                 qcom,ion-heap@25 {
+                         reg = <25>;
+                         qcom,ion-heap-type = "SYSTEM";
                  };
 
                  qcom,ion-heap@8 { /* CP_MM HEAP */
                          compatible = "qcom,msm-ion-reserve";
                          reg = <8>;
                          qcom,heap-align = <0x1000>;
-                         qcom,memory-reservation-type = "EBI1"; /* reserve EBI memory */
-                         qcom,memory-reservation-size = <0x7800000>;
+                         linux,contiguous-region = <&secure_mem>;
+                         qcom,ion-heap-type = "SECURE_DMA";
                  };
 
                  qcom,ion-heap@29 { /* FIRMWARE HEAP */
@@ -53,5 +64,6 @@
                          qcom,heap-adjacent = <8>;
                          qcom,memory-reservation-type = "EBI1"; /* reserve EBI memory */
                          qcom,memory-reservation-size = <0xA00000>;
-
+                         qcom,ion-heap-type = "CARVEOUT";
+                 };
 	};
diff --git a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
index 1a44f5a..08d2c2d 100644
--- a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
@@ -250,7 +250,12 @@
 					as below:
 					--> Reset GPIO value
 					--> Sleep value (in ms)
-
+- qcom,mdss-dsi-lp11-init:		Boolean used to enable the DSI clocks and data lanes (low power 11)
+					before issuing hardware reset line.
+- qcom,mdss-dsi-init-delay-us:		Delay in microseconds(us) before performing any DSI activity in lp11
+					mode. This master delay (t_init_delay as per DSI spec) should be sum
+					of DSI internal delay to reach fuctional after power up and minimum
+					delay required by panel to reach functional.
 
 Note, if a given optional qcom,* binding is not present, then the driver will configure
 the default values specified.
@@ -343,5 +348,7 @@
 		qcom,mdss-dsi-panel-mode-gpio-state = "low";
 		qcom,partial-update-enabled;
 		qcom,mdss-dsi-reset-sequence = <1 2>, <0 10>, <1 10>;
+		qcom,mdss-dsi-lp11-init;
+		qcom,mdss-dsi-init-delay-us = <100>;
 	};
 };
diff --git a/Documentation/devicetree/bindings/gpu/adreno.txt b/Documentation/devicetree/bindings/gpu/adreno.txt
index aa0aa8c..656f3a4 100644
--- a/Documentation/devicetree/bindings/gpu/adreno.txt
+++ b/Documentation/devicetree/bindings/gpu/adreno.txt
@@ -64,7 +64,7 @@
 Optional Properties:
 - qcom,initial-powerlevel: This value indicates which qcom,gpu-pwrlevel should be used at start time
 			   and when coming back out of resume
-- qcom,step-pwrlevel:	   How many qcom,gpu-pwrlevel should be decremented at once
+- qcom,bus-control:	   Boolean. Enables an independent bus vote from the gpu frequency
 - qcom,idle-timeout:	   This property represents the time in microseconds for idle timeout.
 - qcom,chipid:		   If it exists this property is used to replace
 			   the chip identification read from the GPU hardware.
diff --git a/Documentation/devicetree/bindings/uio/msm_sharedmem.txt b/Documentation/devicetree/bindings/uio/msm_sharedmem.txt
new file mode 100644
index 0000000..5af50da
--- /dev/null
+++ b/Documentation/devicetree/bindings/uio/msm_sharedmem.txt
@@ -0,0 +1,13 @@
+msm_sharedmem provides the shared memory addresses for various clients in user-space
+
+Required properties:
+- compatible:		Must be "qcom,sharedmem-uio"
+- reg : The address and size of the shared memory. The address/sizes may vary.
+- reg-names : indicates various client-names.
+
+Example:
+	msm_sharedmem {
+		compatible = "qcom,sharedmem-uio";
+		reg = <0x0dc80000 0x00180000>,
+		reg-names = "rmtfs";
+	};
diff --git a/arch/arm/boot/dts/apq8074-v1-ion.dtsi b/arch/arm/boot/dts/apq8074-v1-ion.dtsi
index 49d7ee1..3611132 100644
--- a/arch/arm/boot/dts/apq8074-v1-ion.dtsi
+++ b/arch/arm/boot/dts/apq8074-v1-ion.dtsi
@@ -17,6 +17,7 @@
 			reg = <23>;
 			qcom,heap-align = <0x1000>;
 			qcom,memory-fixed = <0x0dc00000 0x1e00000>;
+			qcom,ion-heap-type = "CARVEOUT";
 		};
 	};
 };
diff --git a/arch/arm/boot/dts/apq8074-v2.0-1-ion.dtsi b/arch/arm/boot/dts/apq8074-v2.0-1-ion.dtsi
index 49d7ee1..3611132 100644
--- a/arch/arm/boot/dts/apq8074-v2.0-1-ion.dtsi
+++ b/arch/arm/boot/dts/apq8074-v2.0-1-ion.dtsi
@@ -17,6 +17,7 @@
 			reg = <23>;
 			qcom,heap-align = <0x1000>;
 			qcom,memory-fixed = <0x0dc00000 0x1e00000>;
+			qcom,ion-heap-type = "CARVEOUT";
 		};
 	};
 };
diff --git a/arch/arm/boot/dts/apq8074-v2.2-ion.dtsi b/arch/arm/boot/dts/apq8074-v2.2-ion.dtsi
index 49d7ee1..3611132 100644
--- a/arch/arm/boot/dts/apq8074-v2.2-ion.dtsi
+++ b/arch/arm/boot/dts/apq8074-v2.2-ion.dtsi
@@ -17,6 +17,7 @@
 			reg = <23>;
 			qcom,heap-align = <0x1000>;
 			qcom,memory-fixed = <0x0dc00000 0x1e00000>;
+			qcom,ion-heap-type = "CARVEOUT";
 		};
 	};
 };
diff --git a/arch/arm/boot/dts/apq8084-ion.dtsi b/arch/arm/boot/dts/apq8084-ion.dtsi
index ea954b8..167b8b7 100644
--- a/arch/arm/boot/dts/apq8084-ion.dtsi
+++ b/arch/arm/boot/dts/apq8084-ion.dtsi
@@ -16,16 +16,14 @@
 		#address-cells = <1>;
 		#size-cells = <0>;
 
-		qcom,ion-heap@30 { /* SYSTEM HEAP */
-			reg = <30>;
-		};
-
-		qcom,ion-heap@21 { /* SYSTEM CONTIG HEAP */
-			reg = <21>;
-		};
-
-		qcom,ion-heap@25 { /* IOMMU HEAP */
+		qcom,ion-heap@25 {
 			reg = <25>;
+			qcom,ion-heap-type = "SYSTEM";
+		};
+
+		qcom,ion-heap@21 {
+			reg = <21>;
+			qcom,ion-heap-type = "SYSTEM_CONTIG";
 		};
 	};
 };
diff --git a/arch/arm/boot/dts/fsm9900.dtsi b/arch/arm/boot/dts/fsm9900.dtsi
index 1c48bf0..705a512 100644
--- a/arch/arm/boot/dts/fsm9900.dtsi
+++ b/arch/arm/boot/dts/fsm9900.dtsi
@@ -85,8 +85,9 @@
 		#address-cells = <1>;
 		#size-cells = <0>;
 
-		qcom,ion-heap@30 { /* SYSTEM HEAP */
-			reg = <30>;
+		qcom,ion-heap@25 {
+			reg = <25>;
+			qcom,ion-heap-type = "SYSTEM";
 		};
 	};
 
diff --git a/arch/arm/boot/dts/mpq8092-ion.dtsi b/arch/arm/boot/dts/mpq8092-ion.dtsi
index f9f5985..903610d 100644
--- a/arch/arm/boot/dts/mpq8092-ion.dtsi
+++ b/arch/arm/boot/dts/mpq8092-ion.dtsi
@@ -16,16 +16,14 @@
 		#address-cells = <1>;
 		#size-cells = <0>;
 
-		qcom,ion-heap@30 { /* SYSTEM HEAP */
-			reg = <30>;
-		};
-
-		qcom,ion-heap@21 { /* SYSTEM CONTIG HEAP */
-			reg = <21>;
-		};
-
-		qcom,ion-heap@25 { /* IOMMU HEAP */
+		qcom,ion-heap@25 {
 			reg = <25>;
+			qcom,ion-heap-type = "SYSTEM";
+		};
+
+		qcom,ion-heap@21 {
+			reg = <21>;
+			qcom,ion-heap-type = "SYSTEM_CONTIG";
 		};
 
 	};
diff --git a/arch/arm/boot/dts/msm8226-ion.dtsi b/arch/arm/boot/dts/msm8226-ion.dtsi
index 30c3209..06e2779 100644
--- a/arch/arm/boot/dts/msm8226-ion.dtsi
+++ b/arch/arm/boot/dts/msm8226-ion.dtsi
@@ -16,12 +16,14 @@
 		#address-cells = <1>;
 		#size-cells = <0>;
 
-		qcom,ion-heap@30 { /* SYSTEM HEAP */
-			reg = <30>;
+		qcom,ion-heap@25 {
+			reg = <25>;
+			qcom,ion-heap-type = "SYSTEM";
 		};
 
-		qcom,ion-heap@21 { /* SYSTEM CONTIG HEAP */
+		qcom,ion-heap@21 {
 			reg = <21>;
+			qcom,ion-heap-type = "SYSTEM_CONTIG";
 		};
 
 		qcom,ion-heap@8 { /* CP_MM HEAP */
@@ -29,10 +31,7 @@
 			reg = <8>;
 			qcom,heap-align = <0x1000>;
 			linux,contiguous-region = <&secure_mem>;
-		};
-
-		qcom,ion-heap@25 { /* IOMMU HEAP */
-			reg = <25>;
+			qcom,ion-heap-type = "SECURE_DMA";
 		};
 
 		qcom,ion-heap@22 { /* adsp heap */
@@ -40,12 +39,14 @@
 			reg = <22>;
 			qcom,heap-align = <0x1000>;
 			linux,contiguous-region = <&adsp_mem>;
+			qcom,ion-heap-type = "DMA";
 		};
 
 		qcom,ion-heap@27 { /* QSECOM HEAP */
 			compatible = "qcom,msm-ion-reserve";
 			reg = <27>;
 			linux,contiguous-region = <&qsecom_mem>;
+			qcom,ion-heap-type = "DMA";
 		};
 
 		qcom,ion-heap@28 { /* AUDIO HEAP */
@@ -54,6 +55,7 @@
 			qcom,heap-align = <0x1000>;
 			qcom,memory-reservation-type = "EBI1"; /* reserve EBI memory */
 			qcom,memory-reservation-size = <0x314000>;
+			qcom,ion-heap-type = "CARVEOUT";
 		};
 
 		qcom,ion-heap@23 { /* OTHER PIL HEAP */
@@ -61,6 +63,7 @@
 			reg = <23>;
 			qcom,heap-align = <0x1000>;
 			qcom,memory-fixed = <0x0dc00000 0x1900000>;
+			qcom,ion-heap-type = "CARVEOUT";
 		};
 
 	};
diff --git a/arch/arm/boot/dts/msm8226.dtsi b/arch/arm/boot/dts/msm8226.dtsi
index 3ef0d6d..c78dacd 100644
--- a/arch/arm/boot/dts/msm8226.dtsi
+++ b/arch/arm/boot/dts/msm8226.dtsi
@@ -726,6 +726,24 @@
 		compatible = "qcom,bcl";
 	};
 
+	rmtfs_sharedmem {
+		compatible = "qcom,sharedmem-uio";
+		reg = <0x0fd80000 0x00180000>;
+		reg-names = "rmtfs";
+	};
+
+	dsp_sharedmem {
+		compatible = "qcom,sharedmem-uio";
+		reg = <0x0fd60000 0x00020000>;
+		reg-names = "rfsa_dsp";
+	};
+
+	mdm_sharedmem {
+		compatible = "qcom,sharedmem-uio";
+		reg = <0x0fd60000 0x00020000>;
+		reg-names = "rfsa_mdm";
+	};
+
 	sdcc1: qcom,sdcc@f9824000 {
 		cell-index = <1>; /* SDC1 eMMC slot */
 		compatible = "qcom,msm-sdcc";
diff --git a/arch/arm/boot/dts/msm8610-bus.dtsi b/arch/arm/boot/dts/msm8610-bus.dtsi
index c6e81d8..54c698c 100644
--- a/arch/arm/boot/dts/msm8610-bus.dtsi
+++ b/arch/arm/boot/dts/msm8610-bus.dtsi
@@ -941,7 +941,7 @@
 			qcom,thresh = <800000>;
 			qcom,dual-conf;
 			qcom,bimc,bw = <300000>;
-			qcom,bimc,gp = <5>;
+			qcom,bimc,gp = <5000>;
 			qcom,bimc,thmp = <50>;
 		};
 
diff --git a/arch/arm/boot/dts/msm8610-ion.dtsi b/arch/arm/boot/dts/msm8610-ion.dtsi
index 77cd582..601f8ed 100644
--- a/arch/arm/boot/dts/msm8610-ion.dtsi
+++ b/arch/arm/boot/dts/msm8610-ion.dtsi
@@ -16,22 +16,21 @@
 		#address-cells = <1>;
 		#size-cells = <0>;
 
-		qcom,ion-heap@30 { /* SYSTEM HEAP */
-			reg = <30>;
-		};
-
-		qcom,ion-heap@21 { /* SYSTEM CONTIG HEAP */
-			reg = <21>;
-		};
-
-		qcom,ion-heap@25 { /* IOMMU HEAP */
+		qcom,ion-heap@25 {
 			reg = <25>;
+			qcom,ion-heap-type = "SYSTEM";
+		};
+
+		qcom,ion-heap@21 {
+			reg = <21>;
+			qcom,ion-heap-type = "SYSTEM_CONTIG";
 		};
 
 		qcom,ion-heap@27 { /* QSECOM HEAP */
 			compatible = "qcom,msm-ion-reserve";
 			reg = <27>;
 			linux,contiguous-region = <&qsecom_mem>;
+			qcom,ion-heap-type = "DMA";
 		};
 
 		qcom,ion-heap@23 { /* OTHER PIL HEAP */
@@ -39,6 +38,7 @@
 			reg = <23>;
 			qcom,heap-align = <0x1000>;
 			qcom,memory-fixed = <0x0c500000 0x1300000>;
+			qcom,ion-heap-type = "CARVEOUT";
 		};
 
 		qcom,ion-heap@26 { /* MODEM HEAP */
@@ -46,6 +46,7 @@
 			reg = <26>;
 			qcom,heap-align = <0x1000>;
 			qcom,memory-fixed = <0x08800000 0x3d00000>;
+			qcom,ion-heap-type = "CARVEOUT";
 		};
 
 	};
diff --git a/arch/arm/boot/dts/msm8610.dtsi b/arch/arm/boot/dts/msm8610.dtsi
index 42b7887..26efa78 100644
--- a/arch/arm/boot/dts/msm8610.dtsi
+++ b/arch/arm/boot/dts/msm8610.dtsi
@@ -257,6 +257,24 @@
 		qcom,streaming-func = "rndis";
 	};
 
+	rmtfs_sharedmem {
+		compatible = "qcom,sharedmem-uio";
+		reg = <0x0dc80000 0x00180000>;
+		reg-names = "rmtfs";
+	};
+
+	dsp_sharedmem {
+		compatible = "qcom,sharedmem-uio";
+		reg = <0x0dc60000 0x00020000>;
+		reg-names = "rfsa_dsp";
+	};
+
+	mdm_sharedmem {
+		compatible = "qcom,sharedmem-uio";
+		reg = <0x0dc60000 0x00020000>;
+		reg-names = "rfsa_mdm";
+	};
+
 	sdcc1: qcom,sdcc@f9824000 {
 		cell-index = <1>; /* SDC1 eMMC slot */
 		compatible = "qcom,msm-sdcc";
diff --git a/arch/arm/boot/dts/msm8974-bus.dtsi b/arch/arm/boot/dts/msm8974-bus.dtsi
index 609a1b3..af51327 100644
--- a/arch/arm/boot/dts/msm8974-bus.dtsi
+++ b/arch/arm/boot/dts/msm8974-bus.dtsi
@@ -1168,18 +1168,12 @@
 			qcom,masterp = <0>;
 			qcom,tier = <2>;
 			qcom,hw-sel = "BIMC";
-			qcom,mode = "Limiter";
+			qcom,mode = "Fixed";
 			qcom,qport = <0>;
 			qcom,ws = <10000>;
 			qcom,mas-hw-id = <0>;
 			qcom,prio-rd = <0>;
 			qcom,prio-wr = <0>;
-			qcom,mode-thresh = "Fixed";
-			qcom,thresh = <2000000>;
-			qcom,dual-conf;
-			qcom,bimc,bw = <300000>;
-			qcom,bimc,gp = <5>;
-			qcom,bimc,thmp = <50>;
 		};
 
 		mas-ampss-m1 {
@@ -1188,18 +1182,12 @@
 			qcom,masterp = <1>;
 			qcom,tier = <2>;
 			qcom,hw-sel = "BIMC";
-			qcom,mode = "Limiter";
+			qcom,mode = "Fixed";
 			qcom,qport = <1>;
 			qcom,ws = <10000>;
 			qcom,mas-hw-id = <0>;
 			qcom,prio-rd = <0>;
 			qcom,prio-wr = <0>;
-			qcom,mode-thresh = "Fixed";
-			qcom,thresh = <2000000>;
-			qcom,dual-conf;
-			qcom,bimc,bw = <300000>;
-			qcom,bimc,gp = <5>;
-			qcom,bimc,thmp = <50>;
 		};
 
 		mas-mss-proc {
diff --git a/arch/arm/boot/dts/msm8974-gpu.dtsi b/arch/arm/boot/dts/msm8974-gpu.dtsi
index 06b9c18..695e452 100644
--- a/arch/arm/boot/dts/msm8974-gpu.dtsi
+++ b/arch/arm/boot/dts/msm8974-gpu.dtsi
@@ -22,8 +22,7 @@
 
 		qcom,chipid = <0x03030000>;
 
-		qcom,initial-pwrlevel = <2>;
-		qcom,step-pwrlevel = <2>;
+		qcom,initial-pwrlevel = <1>;
 
 		qcom,idle-timeout = <8>; //<HZ/12>
 		qcom,strtstp-sleepwake;
@@ -31,14 +30,17 @@
 
 		/* Bus Scale Settings */
 		qcom,msm-bus,name = "grp3d";
-		qcom,msm-bus,num-cases = <6>;
+		qcom,msm-bus,num-cases = <9>;
 		qcom,msm-bus,num-paths = <2>;
 		qcom,msm-bus,vectors-KBps =
 				<26 512 0 0>, <89 604 0 0>,
+				<26 512 0 1600000>, <89 604 0 3000000>,
 				<26 512 0 2200000>, <89 604 0 3000000>,
 				<26 512 0 4000000>, <89 604 0 3000000>,
+				<26 512 0 2200000>, <89 604 0 4500000>,
 				<26 512 0 4000000>, <89 604 0 4500000>,
 				<26 512 0 6400000>, <89 604 0 4500000>,
+				<26 512 0 4000000>, <89 604 0 7600000>,
 				<26 512 0 6400000>, <89 604 0 7600000>;
 
 		/* GDSC oxili regulators */
@@ -67,40 +69,26 @@
 			qcom,gpu-pwrlevel@0 {
 				reg = <0>;
 				qcom,gpu-freq = <450000000>;
-				qcom,bus-freq = <5>;
+				qcom,bus-freq = <8>;
 				qcom,io-fraction = <33>;
 			};
 
 			qcom,gpu-pwrlevel@1 {
 				reg = <1>;
 				qcom,gpu-freq = <320000000>;
-				qcom,bus-freq = <4>;
+				qcom,bus-freq = <5>;
 				qcom,io-fraction = <66>;
 			};
 
 			qcom,gpu-pwrlevel@2 {
 				reg = <2>;
-				qcom,gpu-freq = <320000000>;
-				qcom,bus-freq = <3>;
-				qcom,io-fraction = <66>;
-			};
-
-			qcom,gpu-pwrlevel@3 {
-				reg = <3>;
 				qcom,gpu-freq = <200000000>;
 				qcom,bus-freq = <2>;
 				qcom,io-fraction = <100>;
 			};
 
-			qcom,gpu-pwrlevel@4 {
-				reg = <4>;
-				qcom,gpu-freq = <200000000>;
-				qcom,bus-freq = <1>;
-				qcom,io-fraction = <100>;
-			};
-
-			qcom,gpu-pwrlevel@5 {
-				reg = <5>;
+			qcom,gpu-pwrlevel@3 {
+				reg = <3>;
 				qcom,gpu-freq = <27000000>;
 				qcom,bus-freq = <0>;
 				qcom,io-fraction = <0>;
diff --git a/arch/arm/boot/dts/msm8974-ion.dtsi b/arch/arm/boot/dts/msm8974-ion.dtsi
index 455ed2d..5829f05 100644
--- a/arch/arm/boot/dts/msm8974-ion.dtsi
+++ b/arch/arm/boot/dts/msm8974-ion.dtsi
@@ -16,12 +16,14 @@
 		#address-cells = <1>;
 		#size-cells = <0>;
 
-		qcom,ion-heap@30 { /* SYSTEM HEAP */
-			reg = <30>;
+		qcom,ion-heap@25 {
+			reg = <25>;
+			qcom,ion-heap-type = "SYSTEM";
 		};
 
-		qcom,ion-heap@21 { /* SYSTEM CONTIG HEAP */
+		qcom,ion-heap@21 {
 			reg = <21>;
+			qcom,ion-heap-type = "SYSTEM_CONTIG";
 		};
 
 		qcom,ion-heap@8 { /* CP_MM HEAP */
@@ -29,6 +31,7 @@
 			reg = <8>;
 			qcom,heap-align = <0x1000>;
 			linux,contiguous-region = <&secure_mem>;
+			qcom,ion-heap-type = "SECURE_DMA";
 		};
 
 		qcom,ion-heap@22 { /* adsp heap */
@@ -36,16 +39,14 @@
 			reg = <22>;
 			qcom,heap-align = <0x1000>;
 			linux,contiguous-region = <&adsp_mem>;
-		};
-
-		qcom,ion-heap@25 { /* IOMMU HEAP */
-			reg = <25>;
+			qcom,ion-heap-type = "DMA";
 		};
 
 		qcom,ion-heap@27 { /* QSECOM HEAP */
 			compatible = "qcom,msm-ion-reserve";
 			reg = <27>;
 			linux,contiguous-region = <&qsecom_mem>;
+			qcom,ion-heap-type = "DMA";
 		};
 
 		qcom,ion-heap@28 { /* AUDIO HEAP */
@@ -54,6 +55,7 @@
 			qcom,heap-align = <0x1000>;
 			qcom,memory-reservation-type = "EBI1"; /* reserve EBI memory */
 			qcom,memory-reservation-size = <0x614000>;
+			qcom,ion-heap-type = "CARVEOUT";
 		};
 
 		qcom,ion-heap@23 { /* OTHER PIL HEAP */
@@ -61,6 +63,7 @@
 			reg = <23>;
 			qcom,heap-align = <0x1000>;
 			qcom,memory-fixed = <0x05d00000 0x1e00000>;
+			qcom,ion-heap-type = "CARVEOUT";
 		};
 	};
 };
diff --git a/arch/arm/boot/dts/msm8974-v2.2.dtsi b/arch/arm/boot/dts/msm8974-v2.2.dtsi
index 0ca021b..3ed5720 100644
--- a/arch/arm/boot/dts/msm8974-v2.2.dtsi
+++ b/arch/arm/boot/dts/msm8974-v2.2.dtsi
@@ -23,20 +23,26 @@
 	/* Updated chip ID */
 	qcom,chipid = <0x03030001>;
 
-	qcom,initial-pwrlevel = <4>;
+	qcom,initial-pwrlevel = <2>;
 
 	/* Updated bus bandwidth requirements */
 	qcom,msm-bus,vectors-KBps =
 		/* Off */
 		<26 512 0 0>, <89 604 0 0>,
+		/* Sub-SVS / SVS */
+		<26 512 0 1600000>, <89 604 0 3000000>,
 		/* SVS */
 		<26 512 0 2400000>, <89 604 0 3000000>,
 		/* Nominal / SVS */
 		<26 512 0 4656000>, <89 604 0 3000000>,
+		/* SVS / Nominal */
+		<26 512 0 2400000>, <89 604 0 5120000>,
 		/* Nominal */
 		<26 512 0 4656000>, <89 604 0 5120000>,
 		/* Turbo / Nominal */
 		<26 512 0 7464000>, <89 604 0 5120000>,
+		/* Nominal / Turbo */
+		<26 512 0 4656000>, <89 604 0 6400000>,
 		/* Turbo */
 		<26 512 0 7464000>, <89 604 0 6400000>;
 
@@ -49,54 +55,33 @@
 		qcom,gpu-pwrlevel@0 {
 			reg = <0>;
 			qcom,gpu-freq = <450000000>;
-			qcom,bus-freq = <5>;
+			qcom,bus-freq = <8>;
 			qcom,io-fraction = <33>;
 		};
 
 		qcom,gpu-pwrlevel@1 {
 			reg = <1>;
 			qcom,gpu-freq = <389000000>;
-			qcom,bus-freq = <4>;
+			qcom,bus-freq = <5>;
 			qcom,io-fraction = <33>;
 		};
 
 		qcom,gpu-pwrlevel@2 {
 			reg = <2>;
-			qcom,gpu-freq = <389000000>;
-			qcom,bus-freq = <3>;
+			qcom,gpu-freq = <320000000>;
+			qcom,bus-freq = <5>;
 			qcom,io-fraction = <66>;
 		};
 
 		qcom,gpu-pwrlevel@3 {
 			reg = <3>;
-			qcom,gpu-freq = <320000000>;
-			qcom,bus-freq = <4>;
-			qcom,io-fraction = <66>;
-		};
-
-		qcom,gpu-pwrlevel@4 {
-			reg = <4>;
-			qcom,gpu-freq = <320000000>;
-			qcom,bus-freq = <3>;
-			qcom,io-fraction = <66>;
-		};
-
-		qcom,gpu-pwrlevel@5 {
-			reg = <5>;
 			qcom,gpu-freq = <200000000>;
 			qcom,bus-freq = <2>;
 			qcom,io-fraction = <100>;
 		};
 
-		qcom,gpu-pwrlevel@6 {
-			reg = <6>;
-			qcom,gpu-freq = <200000000>;
-			qcom,bus-freq = <1>;
-			qcom,io-fraction = <100>;
-		};
-
-		qcom,gpu-pwrlevel@7 {
-			reg = <7>;
+		qcom,gpu-pwrlevel@4 {
+			reg = <4>;
 			qcom,gpu-freq = <27000000>;
 			qcom,bus-freq = <0>;
 			qcom,io-fraction = <0>;
diff --git a/arch/arm/boot/dts/msm8974-v2.dtsi b/arch/arm/boot/dts/msm8974-v2.dtsi
index 0da5658..6784068 100644
--- a/arch/arm/boot/dts/msm8974-v2.dtsi
+++ b/arch/arm/boot/dts/msm8974-v2.dtsi
@@ -58,14 +58,20 @@
 	qcom,msm-bus,vectors-KBps =
 		/* Off */
 		<26 512 0 0>, <89 604 0 0>,
+		/* Sub-SVS / SVS */
+		<26 512 0 1600000>, <89 604 0 3000000>,
 		/* SVS */
 		<26 512 0 2400000>, <89 604 0 3000000>,
 		/* Nominal / SVS */
-		<26 512 0 4656000>, <89 604 0 3000000>,
+		<26 512 0 4912000>, <89 604 0 3000000>,
+		/* SVS / Nominal */
+		<26 512 0 2400000>, <89 604 0 5120000>,
 		/* Nominal */
-		<26 512 0 4656000>, <89 604 0 5120000>,
+		<26 512 0 4912000>, <89 604 0 5120000>,
 		/* Turbo / Nominal */
 		<26 512 0 7464000>, <89 604 0 5120000>,
+		/* Nominal / Turbo */
+		<26 512 0 4912000>, <89 604 0 6400000>,
 		/* Turbo */
 		<26 512 0 7464000>, <89 604 0 6400000>;
 };
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index de49851..0412c73 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -283,6 +283,24 @@
 				<87 512 60000 960000>;
 	};
 
+	rmtfs_sharedmem {
+		compatible = "qcom,sharedmem-uio";
+		reg = <0x0fd80000 0x00180000>;
+		reg-names = "rmtfs";
+	};
+
+	dsp_sharedmem {
+		compatible = "qcom,sharedmem-uio";
+		reg = <0x0fd60000 0x00020000>;
+		reg-names = "rfsa_dsp";
+	};
+
+	mdm_sharedmem {
+		compatible = "qcom,sharedmem-uio";
+		reg = <0x0fd60000 0x00020000>;
+		reg-names = "rfsa_mdm";
+	};
+
 	sdcc1: qcom,sdcc@f9824000 {
 		cell-index = <1>; /* SDC1 eMMC slot */
 		compatible = "qcom,msm-sdcc";
diff --git a/arch/arm/boot/dts/msm8974pro-ion.dtsi b/arch/arm/boot/dts/msm8974pro-ion.dtsi
index 4c427bf..3bb885a 100644
--- a/arch/arm/boot/dts/msm8974pro-ion.dtsi
+++ b/arch/arm/boot/dts/msm8974pro-ion.dtsi
@@ -18,6 +18,7 @@
 			reg = <23>;
 			qcom,heap-align = <0x1000>;
 			qcom,memory-fixed = <0x05a00000 0x2100000>;
+			qcom,ion-heap-type = "CARVEOUT";
 		};
 
 		qcom,ion-heap@26 { /* MODEM HEAP */
@@ -25,6 +26,7 @@
 			reg = <26>;
 			qcom,heap-align = <0x1000>;
 			qcom,memory-fixed = <0x08000000 0x5000000>;
+			qcom,ion-heap-type = "CARVEOUT";
 		};
 	};
 };
diff --git a/arch/arm/boot/dts/msm8974pro.dtsi b/arch/arm/boot/dts/msm8974pro.dtsi
index 85c2fe3..ac5ccb9 100644
--- a/arch/arm/boot/dts/msm8974pro.dtsi
+++ b/arch/arm/boot/dts/msm8974pro.dtsi
@@ -1550,21 +1550,21 @@
 
 	qcom,msm-cpufreq@0 {
 		qcom,cpufreq-table =
-			<  300000  300000  600 /*  75 MHz */ >,
-			<  422400  422400 1200 /* 150 MHz */ >,
-			<  652800  499200 1600 /* 200 MHz */ >,
-			<  729600  576000 2456 /* 307 MHz */ >,
-			<  883200  576000 2456 /* 307 MHz */ >,
-			<  960000  960000 3680 /* 460 MHz */ >,
-			< 1036800 1036800 3680 /* 460 MHz */ >,
-			< 1190400 1036800 3680 /* 460 MHz */ >,
-			< 1267200 1267200 4912 /* 614 MHz */ >,
-			< 1497600 1497600 4912 /* 614 MHz */ >,
-			< 1574400 1574400 6400 /* 800 MHz */ >,
-			< 1728000 1651200 6400 /* 800 MHz */ >,
-			< 1958400 1728000 7448 /* 931 MHz */ >,
-			< 2265600 1728000 7448 /* 931 MHz */ >,
-			< 2457600 1728000 7448 /* 931 MHz */ >;
+			<  300000  300000 300 /* 37.5 MHz */ >,
+			<  422400  422400 300 /* 37.5 MHz */ >,
+			<  652800  499200 300 /* 37.5 MHz */ >,
+			<  729600  576000 300 /* 37.5 MHz */ >,
+			<  883200  576000 300 /* 37.5 MHz */ >,
+			<  960000  960000 300 /* 37.5 MHz */ >,
+			< 1036800 1036800 300 /* 37.5 MHz */ >,
+			< 1190400 1036800 300 /* 37.5 MHz */ >,
+			< 1267200 1267200 300 /* 37.5 MHz */ >,
+			< 1497600 1497600 300 /* 37.5 MHz */ >,
+			< 1574400 1574400 300 /* 37.5 MHz */ >,
+			< 1728000 1651200 300 /* 37.5 MHz */ >,
+			< 1958400 1728000 300 /* 37.5 MHz */ >,
+			< 2265600 1728000 300 /* 37.5 MHz */ >,
+			< 2496000 1728000 300 /* 37.5 MHz */ >;
 	};
 };
 
@@ -1572,31 +1572,41 @@
 &msm_gpu {
 	/* Updated chip ID */
 	qcom,chipid = <0x03030002>;
+	qcom,msm-bus,num-cases = <15>;
+	qcom,bus-control;
+	qcom,initial-pwrlevel = <3>;
 
-	qcom,initial-pwrlevel = <6>;
-
-	qcom,msm-bus,num-cases = <10>;
 	/* Updated bus bandwidth requirements */
 	qcom,msm-bus,vectors-KBps =
 		/* Off */
 		<26 512 0 0>, <89 604 0 0>,
+		/* Sub-SVS / SVS */
+		<26 512 0 1600000>, <89 604 0 3200000>,
 		/* SVS */
-		<26 512 0 2400000>, <89 604 0 3200000>,
-		/* Nominal / SVS */
+		<26 512 0 2456000>, <89 604 0 3200000>,
+		/* low Nominal / SVS */
 		<26 512 0 3680000>, <89 604 0 3200000>,
-		/* Nominal / Nominal */
+		/* SVS / low Nominal */
+		<26 512 0 2456000>, <89 604 0 5280000>,
+		/* low Nominal / low Nominal */
 		<26 512 0 3680000>, <89 604 0 5280000>,
-		/* Nominal / Nominal */
+		/* Nominal / low Nominal */
 		<26 512 0 4912000>, <89 604 0 5280000>,
-		/* Nominal / Turbo */
+		/* low Nominal / Nominal */
+		<26 512 0 3680000>, <89 604 0 6224000>,
+		/* Nominal / Nominal */
 		<26 512 0 4912000>, <89 604 0 6224000>,
-		/* Turbo / Turbo */
-		<26 512 0 7464000>, <89 604 0 6224000>,
+		/* low Turbo / Nominal */
+		<26 512 0 6400000>, <89 604 0 6224000>,
+		/* Nominal / low Turbo */
+		<26 512 0 4912000>, <89 604 0 7398000>,
+		/* low Turbo / low Turbo */
+		<26 512 0 6400000>, <89 604 0 7398000>,
+		/* Turbo / low Turbo */
+		<26 512 0 7464000>, <89 604 0 7398000>,
 		/* Nominal / Turbo */
-		<26 512 0 4912000>, <89 604 0 7400000>,
-		/* Turbo */
-		<26 512 0 7464000>, <89 604 0 7400000>,
-		/* Turbo */
+		<26 512 0 4912000>, <89 604 0 9248000>,
+		/* Turbo / Turbo */
 		<26 512 0 7464000>, <89 604 0 9248000>;
 
        qcom,gpu-pwrlevels {
@@ -1608,68 +1618,40 @@
                qcom,gpu-pwrlevel@0 {
                        reg = <0>;
                        qcom,gpu-freq = <578000000>;
-                       qcom,bus-freq = <9>;
+                       qcom,bus-freq = <14>;
                        qcom,io-fraction = <33>;
                };
 
-		qcom,gpu-pwrlevel@1 {
-			reg = <1>;
-			qcom,gpu-freq = <462400000>;
-			qcom,bus-freq = <8>;
-			qcom,io-fraction = <33>;
-		};
-
-		qcom,gpu-pwrlevel@2 {
-			reg = <2>;
-			qcom,gpu-freq = <462400000>;
-			qcom,bus-freq = <7>;
-			qcom,io-fraction = <66>;
-		};
-
-		qcom,gpu-pwrlevel@3 {
-			reg = <3>;
-			qcom,gpu-freq = <389000000>;
-			qcom,bus-freq = <6>;
-			qcom,io-fraction = <66>;
-		};
-
-		qcom,gpu-pwrlevel@4 {
-			reg = <4>;
-			qcom,gpu-freq = <389000000>;
-			qcom,bus-freq = <5>;
-			qcom,io-fraction = <66>;
-		};
-
-               qcom,gpu-pwrlevel@5 {
-                       reg = <5>;
-                       qcom,gpu-freq = <330000000>;
-                       qcom,bus-freq = <4>;
+               qcom,gpu-pwrlevel@1 {
+                       reg = <1>;
+                       qcom,gpu-freq = <462400000>;
+                       qcom,bus-freq = <11>;
                        qcom,io-fraction = <66>;
                };
 
-               qcom,gpu-pwrlevel@6 {
-                       reg = <6>;
-                       qcom,gpu-freq = <330000000>;
-                       qcom,bus-freq = <3>;
+               qcom,gpu-pwrlevel@2 {
+                       reg = <2>;
+                       qcom,gpu-freq = <389000000>;
+                       qcom,bus-freq = <8>;
                        qcom,io-fraction = <66>;
                };
 
-               qcom,gpu-pwrlevel@7 {
-                       reg = <7>;
+               qcom,gpu-pwrlevel@3 {
+                       reg = <3>;
+                       qcom,gpu-freq = <320000000>;
+                       qcom,bus-freq = <5>;
+                       qcom,io-fraction = <100>;
+               };
+
+               qcom,gpu-pwrlevel@4 {
+                       reg = <4>;
                        qcom,gpu-freq = <200000000>;
                        qcom,bus-freq = <2>;
                        qcom,io-fraction = <100>;
                };
 
-               qcom,gpu-pwrlevel@8 {
-                       reg = <8>;
-                       qcom,gpu-freq = <200000000>;
-                       qcom,bus-freq = <1>;
-                       qcom,io-fraction = <100>;
-               };
-
-               qcom,gpu-pwrlevel@9 {
-                       reg = <9>;
+               qcom,gpu-pwrlevel@5 {
+                       reg = <5>;
                        qcom,gpu-freq = <27000000>;
                        qcom,bus-freq = <0>;
                        qcom,io-fraction = <0>;
diff --git a/arch/arm/boot/dts/msm9625-ion.dtsi b/arch/arm/boot/dts/msm9625-ion.dtsi
index 2a3e4b5..3ef0b3f 100644
--- a/arch/arm/boot/dts/msm9625-ion.dtsi
+++ b/arch/arm/boot/dts/msm9625-ion.dtsi
@@ -16,12 +16,9 @@
 		#address-cells = <1>;
 		#size-cells = <0>;
 
-		qcom,ion-heap@30 { /* SYSTEM HEAP */
-			reg = <30>;
-		};
-
-		qcom,ion-heap@25 { /* IOMMU HEAP */
+		qcom,ion-heap@25 {
 			reg = <25>;
+			qcom,ion-heap-type = "SYSTEM";
 		};
 
 		qcom,ion-heap@28 { /* AUDIO HEAP */
@@ -30,6 +27,7 @@
 			qcom,heap-align = <0x1000>;
 			qcom,memory-reservation-type = "EBI1"; /* reserve EBI memory */
 			qcom,memory-reservation-size = <0xAF000>;
+			qcom,ion-heap-type = "CARVEOUT";
 		};
 	};
 };
diff --git a/arch/arm/boot/dts/msmsamarium-ion.dtsi b/arch/arm/boot/dts/msmsamarium-ion.dtsi
index ea954b8..167b8b7 100644
--- a/arch/arm/boot/dts/msmsamarium-ion.dtsi
+++ b/arch/arm/boot/dts/msmsamarium-ion.dtsi
@@ -16,16 +16,14 @@
 		#address-cells = <1>;
 		#size-cells = <0>;
 
-		qcom,ion-heap@30 { /* SYSTEM HEAP */
-			reg = <30>;
-		};
-
-		qcom,ion-heap@21 { /* SYSTEM CONTIG HEAP */
-			reg = <21>;
-		};
-
-		qcom,ion-heap@25 { /* IOMMU HEAP */
+		qcom,ion-heap@25 {
 			reg = <25>;
+			qcom,ion-heap-type = "SYSTEM";
+		};
+
+		qcom,ion-heap@21 {
+			reg = <21>;
+			qcom,ion-heap-type = "SYSTEM_CONTIG";
 		};
 	};
 };
diff --git a/arch/arm/boot/dts/msmsamarium.dtsi b/arch/arm/boot/dts/msmsamarium.dtsi
index a492561..6c55566 100644
--- a/arch/arm/boot/dts/msmsamarium.dtsi
+++ b/arch/arm/boot/dts/msmsamarium.dtsi
@@ -65,6 +65,24 @@
 		reg = <0xfe805000 0x1000>; /* Address and size of IMEM */
 	};
 
+	rmtfs_sharedmem {
+		compatible = "qcom,sharedmem-uio";
+		reg = <0x0fd80000 0x00180000>;
+		reg-names = "rmtfs";
+	};
+
+	dsp_sharedmem {
+		compatible = "qcom,sharedmem-uio";
+		reg = <0x0fd60000 0x00020000>;
+		reg-names = "rfsa_dsp";
+	};
+
+	mdm_sharedmem {
+		compatible = "qcom,sharedmem-uio";
+		reg = <0x0fd60000 0x00020000>;
+		reg-names = "rfsa_mdm";
+	};
+
 	sdcc1: qcom,sdcc@f9824000 {
 		cell-index = <1>; /* SDC1 eMMC slot */
 		compatible = "qcom,msm-sdcc";
diff --git a/arch/arm/configs/msm8226-perf_defconfig b/arch/arm/configs/msm8226-perf_defconfig
index 818e052..dac2286 100644
--- a/arch/arm/configs/msm8226-perf_defconfig
+++ b/arch/arm/configs/msm8226-perf_defconfig
@@ -396,6 +396,8 @@
 CONFIG_RTC_CLASS=y
 # CONFIG_RTC_DRV_MSM is not set
 CONFIG_RTC_DRV_QPNP=y
+CONFIG_UIO=y
+CONFIG_UIO_MSM_SHAREDMEM=y
 CONFIG_STAGING=y
 CONFIG_ANDROID=y
 CONFIG_ANDROID_BINDER_IPC=y
diff --git a/arch/arm/configs/msm8226_defconfig b/arch/arm/configs/msm8226_defconfig
index c1f2ca2..9d4d37b 100644
--- a/arch/arm/configs/msm8226_defconfig
+++ b/arch/arm/configs/msm8226_defconfig
@@ -421,6 +421,8 @@
 CONFIG_RTC_CLASS=y
 # CONFIG_RTC_DRV_MSM is not set
 CONFIG_RTC_DRV_QPNP=y
+CONFIG_UIO=y
+CONFIG_UIO_MSM_SHAREDMEM=y
 CONFIG_STAGING=y
 CONFIG_ANDROID=y
 CONFIG_ANDROID_BINDER_IPC=y
diff --git a/arch/arm/configs/msm8610-perf_defconfig b/arch/arm/configs/msm8610-perf_defconfig
index efdd8de..0d443a6 100644
--- a/arch/arm/configs/msm8610-perf_defconfig
+++ b/arch/arm/configs/msm8610-perf_defconfig
@@ -79,7 +79,6 @@
 CONFIG_ARM_ARCH_TIMER=y
 CONFIG_PREEMPT=y
 CONFIG_AEABI=y
-CONFIG_HIGHMEM=y
 CONFIG_COMPACTION=y
 CONFIG_CC_STACKPROTECTOR=y
 CONFIG_ENABLE_VMALLOC_SAVING=y
@@ -355,7 +354,11 @@
 CONFIG_RTC_CLASS=y
 # CONFIG_RTC_DRV_MSM is not set
 CONFIG_RTC_DRV_QPNP=y
+CONFIG_UIO=y
+CONFIG_UIO_MSM_SHAREDMEM=y
 CONFIG_STAGING=y
+CONFIG_ZRAM=y
+CONFIG_ZSMALLOC=y
 CONFIG_ANDROID=y
 CONFIG_ANDROID_BINDER_IPC=y
 CONFIG_ASHMEM=y
diff --git a/arch/arm/configs/msm8610_defconfig b/arch/arm/configs/msm8610_defconfig
index c140a46..f467b95 100644
--- a/arch/arm/configs/msm8610_defconfig
+++ b/arch/arm/configs/msm8610_defconfig
@@ -80,7 +80,6 @@
 CONFIG_ARM_ARCH_TIMER=y
 CONFIG_PREEMPT=y
 CONFIG_AEABI=y
-CONFIG_HIGHMEM=y
 CONFIG_COMPACTION=y
 CONFIG_CC_STACKPROTECTOR=y
 CONFIG_ENABLE_VMALLOC_SAVING=y
@@ -379,7 +378,11 @@
 CONFIG_RTC_CLASS=y
 # CONFIG_RTC_DRV_MSM is not set
 CONFIG_RTC_DRV_QPNP=y
+CONFIG_UIO=y
+CONFIG_UIO_MSM_SHAREDMEM=y
 CONFIG_STAGING=y
+CONFIG_ZRAM=y
+CONFIG_ZSMALLOC=y
 CONFIG_ANDROID=y
 CONFIG_ANDROID_BINDER_IPC=y
 CONFIG_ASHMEM=y
diff --git a/arch/arm/configs/msm8974-perf_defconfig b/arch/arm/configs/msm8974-perf_defconfig
index fb05a08..731538f 100644
--- a/arch/arm/configs/msm8974-perf_defconfig
+++ b/arch/arm/configs/msm8974-perf_defconfig
@@ -104,6 +104,7 @@
 CONFIG_CPU_FREQ_GOV_ONDEMAND=y
 CONFIG_CPU_FREQ_GOV_INTERACTIVE=y
 CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
+CONFIG_CPU_BOOST=y
 CONFIG_CPU_IDLE=y
 CONFIG_VFP=y
 CONFIG_NEON=y
@@ -435,6 +436,8 @@
 CONFIG_RTC_CLASS=y
 # CONFIG_RTC_DRV_MSM is not set
 CONFIG_RTC_DRV_QPNP=y
+CONFIG_UIO=y
+CONFIG_UIO_MSM_SHAREDMEM=y
 CONFIG_STAGING=y
 CONFIG_ANDROID=y
 CONFIG_ANDROID_BINDER_IPC=y
diff --git a/arch/arm/configs/msm8974_defconfig b/arch/arm/configs/msm8974_defconfig
index 8f6f52f..67ceaed 100644
--- a/arch/arm/configs/msm8974_defconfig
+++ b/arch/arm/configs/msm8974_defconfig
@@ -110,6 +110,7 @@
 CONFIG_CPU_FREQ_GOV_ONDEMAND=y
 CONFIG_CPU_FREQ_GOV_INTERACTIVE=y
 CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
+CONFIG_CPU_BOOST=y
 CONFIG_CPU_IDLE=y
 CONFIG_VFP=y
 CONFIG_NEON=y
@@ -443,6 +444,8 @@
 CONFIG_RTC_CLASS=y
 # CONFIG_RTC_DRV_MSM is not set
 CONFIG_RTC_DRV_QPNP=y
+CONFIG_UIO=y
+CONFIG_UIO_MSM_SHAREDMEM=y
 CONFIG_STAGING=y
 CONFIG_ANDROID=y
 CONFIG_ANDROID_BINDER_IPC=y
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index eacdcdf..3079b64 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -431,3 +431,5 @@
 obj-$(CONFIG_WALL_CLK) += wallclk.o
 obj-$(CONFIG_WALL_CLK_SYSFS) += wallclk_sysfs.o
 obj-$(CONFIG_ARCH_RANDOM) += early_random.o
+obj-$(CONFIG_PERFMAP) += perfmap.o
+obj-$(CONFIG_ARCH_MSM8974) += cpubw-krait.o
diff --git a/arch/arm/mach-msm/acpuclock-krait.c b/arch/arm/mach-msm/acpuclock-krait.c
index cf3fac0..c5b1deb 100644
--- a/arch/arm/mach-msm/acpuclock-krait.c
+++ b/arch/arm/mach-msm/acpuclock-krait.c
@@ -761,15 +761,22 @@
 	}
 
 	/*
-	 * Increment the L2 HFPLL regulator refcount if _this_ CPU's frequency
-	 * requires a corresponding target L2 frequency that needs the L2 to
-	 * run off of an HFPLL.
+	 * Vote for the L2 HFPLL regulators if _this_ CPU's frequency requires
+	 * a corresponding target L2 frequency that needs the L2 an HFPLL.
 	 */
-	if (drv.l2_freq_tbl[acpu_level->l2_level].speed.src == HFPLL)
-		l2_vreg_count++;
+	if (drv.l2_freq_tbl[acpu_level->l2_level].speed.src == HFPLL) {
+		ret = enable_l2_regulators();
+		if (ret) {
+			dev_err(drv.dev, "enable_l2_regulators() failed (%d)\n",
+				ret);
+			goto err_l2_regs;
+		}
+	}
 
 	return 0;
 
+err_l2_regs:
+	regulator_disable(sc->vreg[VREG_CORE].reg);
 err_core_conf:
 	regulator_put(sc->vreg[VREG_CORE].reg);
 err_core_get:
@@ -901,7 +908,7 @@
 			ret = -ENODEV;
 			goto err_table;
 		}
-		dev_dbg(drv.dev, "CPU%d is running at an unknown rate. Defaulting to %lu KHz.\n",
+		dev_warn(drv.dev, "CPU%d is running at an unknown rate. Defaulting to %lu KHz.\n",
 			cpu, acpu_level->speed.khz);
 	} else {
 		dev_dbg(drv.dev, "CPU%d is running at %lu KHz\n", cpu,
@@ -1208,7 +1215,7 @@
 	l2_level = find_cur_l2_level();
 	if (!l2_level) {
 		l2_level = drv.l2_freq_tbl;
-		dev_dbg(drv.dev, "L2 is running at an unknown rate. Defaulting to %lu KHz.\n",
+		dev_warn(drv.dev, "L2 is running at an unknown rate. Defaulting to %lu KHz.\n",
 			l2_level->speed.khz);
 	} else {
 		dev_dbg(drv.dev, "L2 is running at %lu KHz\n",
diff --git a/arch/arm/mach-msm/cpubw-krait.c b/arch/arm/mach-msm/cpubw-krait.c
new file mode 100644
index 0000000..4108754
--- /dev/null
+++ b/arch/arm/mach-msm/cpubw-krait.c
@@ -0,0 +1,472 @@
+/*
+ * Copyright (c) 2013, 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.
+ */
+
+#define pr_fmt(fmt) "cpubw-krait: " fmt
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/ktime.h>
+#include <linux/time.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/mutex.h>
+#include <linux/interrupt.h>
+#include <trace/events/power.h>
+#include <mach/msm_bus.h>
+#include <mach/msm_bus_board.h>
+
+#include <mach/msm-krait-l2-accessors.h>
+
+#define L2PMRESR2		0x412
+#define L2PMCR			0x400
+#define L2PMCNTENCLR		0x402
+#define L2PMCNTENSET		0x403
+#define L2PMINTENCLR		0x404
+#define L2PMINTENSET		0x405
+#define L2PMOVSR		0x406
+#define L2PMOVSSET		0x407
+#define L2PMnEVCNTCR(n)		(0x420 + n * 0x10)
+#define L2PMnEVCNTR(n)		(0x421 + n * 0x10)
+#define L2PMnEVCNTSR(n)		(0x422 + n * 0x10)
+#define L2PMnEVFILTER(n)	(0x423 + n * 0x10)
+#define L2PMnEVTYPER(n)		(0x424 + n * 0x10)
+#define MON_INT			33
+
+#define MBYTE			(1 << 20)
+
+#define BW(_bw) \
+	{ \
+		.vectors = (struct msm_bus_vectors[]){ \
+			{\
+				.src = MSM_BUS_MASTER_AMPSS_M0, \
+				.dst = MSM_BUS_SLAVE_EBI_CH0, \
+			}, \
+			{ \
+				.src = MSM_BUS_MASTER_AMPSS_M1, \
+				.dst = MSM_BUS_SLAVE_EBI_CH0, \
+			}, \
+		}, \
+		.num_paths = 2, \
+	}
+
+/* Has to be a power of 2 to work correctly */
+static unsigned int bytes_per_beat = 8;
+module_param(bytes_per_beat, uint, 0644);
+
+static unsigned int sample_ms = 50;
+module_param(sample_ms, uint, 0644);
+
+static unsigned int tolerance_percent = 10;
+module_param(tolerance_percent, uint, 0644);
+
+static unsigned int guard_band_mbps = 100;
+module_param(guard_band_mbps, uint, 0644);
+
+static unsigned int decay_rate = 90;
+module_param(decay_rate, uint, 0644);
+
+static unsigned int io_percent = 15;
+module_param(io_percent, uint, 0644);
+
+static unsigned int bw_step = 200;
+module_param(bw_step, uint, 0644);
+
+static struct kernel_param_ops enable_ops;
+static bool enable;
+module_param_cb(enable, &enable_ops, &enable, S_IRUGO | S_IWUSR);
+
+static void mon_init(void)
+{
+	/* Set up counters 0/1 to count write/read beats */
+	set_l2_indirect_reg(L2PMRESR2, 0x8B0B0000);
+	set_l2_indirect_reg(L2PMnEVCNTCR(0), 0x0);
+	set_l2_indirect_reg(L2PMnEVCNTCR(1), 0x0);
+	set_l2_indirect_reg(L2PMnEVCNTR(0), 0xFFFFFFFF);
+	set_l2_indirect_reg(L2PMnEVCNTR(1), 0xFFFFFFFF);
+	set_l2_indirect_reg(L2PMnEVFILTER(0), 0xF003F);
+	set_l2_indirect_reg(L2PMnEVFILTER(1), 0xF003F);
+	set_l2_indirect_reg(L2PMnEVTYPER(0), 0xA);
+	set_l2_indirect_reg(L2PMnEVTYPER(1), 0xB);
+}
+
+static void global_mon_enable(bool en)
+{
+	u32 regval;
+
+	/* Global counter enable */
+	regval = get_l2_indirect_reg(L2PMCR);
+	if (en)
+		regval |= BIT(0);
+	else
+		regval &= ~BIT(0);
+	set_l2_indirect_reg(L2PMCR, regval);
+}
+
+static void mon_enable(int n)
+{
+	/* Clear previous overflow state for event counter n */
+	set_l2_indirect_reg(L2PMOVSR, BIT(n));
+
+	/* Enable event counter n */
+	set_l2_indirect_reg(L2PMCNTENSET, BIT(n));
+}
+
+static void mon_disable(int n)
+{
+	/* Disable event counter n */
+	set_l2_indirect_reg(L2PMCNTENCLR, BIT(n));
+}
+
+/* Returns start counter value to be used with mon_get_mbps() */
+static u32 mon_set_limit_mbyte(int n, unsigned int mbytes)
+{
+	u32 regval, beats;
+
+	beats = mult_frac(mbytes, MBYTE, bytes_per_beat);
+	regval = 0xFFFFFFFF - beats;
+	set_l2_indirect_reg(L2PMnEVCNTR(n), regval);
+	pr_debug("EV%d MB: %d, start val: %x\n", n, mbytes, regval);
+
+	return regval;
+}
+
+/* Returns MBps of read/writes for the sampling window. */
+static int mon_get_mbps(int n, u32 start_val, unsigned int us)
+{
+	u32 overflow, count;
+	long long beats;
+
+	count = get_l2_indirect_reg(L2PMnEVCNTR(n));
+	overflow = get_l2_indirect_reg(L2PMOVSR);
+
+	if (overflow & BIT(n))
+		beats = 0xFFFFFFFF - start_val + count;
+	else
+		beats = count - start_val;
+
+	beats *= USEC_PER_SEC;
+	beats *= bytes_per_beat;
+	do_div(beats, us);
+	beats = DIV_ROUND_UP_ULL(beats, MBYTE);
+
+	pr_debug("EV%d ov: %x, cnt: %x\n", n, overflow, count);
+
+	return beats;
+}
+
+static void do_bw_sample(struct work_struct *work);
+static DECLARE_DEFERRED_WORK(bw_sample, do_bw_sample);
+static struct workqueue_struct *bw_sample_wq;
+
+static DEFINE_MUTEX(bw_lock);
+static ktime_t prev_ts;
+static u32 prev_r_start_val;
+static u32 prev_w_start_val;
+
+static struct msm_bus_paths bw_levels[] = {
+	BW(0), BW(200),
+};
+static struct msm_bus_scale_pdata bw_data = {
+	.usecase = bw_levels,
+	.num_usecases = ARRAY_SIZE(bw_levels),
+	.name = "cpubw-krait",
+	.active_only = 1,
+};
+static u32 bus_client;
+static void compute_bw(int mbps);
+static irqreturn_t mon_intr_handler(int irq, void *dev_id);
+
+#define START_LIMIT	100 /* MBps */
+static int start_monitoring(void)
+{
+	int mb_limit;
+	int ret;
+
+	ret = request_threaded_irq(MON_INT, NULL, mon_intr_handler,
+			  IRQF_ONESHOT | IRQF_SHARED | IRQF_TRIGGER_RISING,
+			  "cpubw_krait", mon_intr_handler);
+	if (ret) {
+		pr_err("Unable to register interrupt handler\n");
+		return ret;
+	}
+
+	bw_sample_wq = alloc_workqueue("cpubw-krait", WQ_HIGHPRI, 0);
+	if (!bw_sample_wq) {
+		pr_err("Unable to alloc workqueue\n");
+		ret = -ENOMEM;
+		goto alloc_wq_fail;
+	}
+
+	bus_client = msm_bus_scale_register_client(&bw_data);
+	if (!bus_client) {
+		pr_err("Unable to register bus client\n");
+		ret = -ENODEV;
+		goto bus_reg_fail;
+	}
+
+	compute_bw(START_LIMIT);
+
+	mon_init();
+	mon_disable(0);
+	mon_disable(1);
+
+	mb_limit = mult_frac(START_LIMIT, sample_ms, MSEC_PER_SEC);
+	mb_limit /= 2;
+
+	prev_r_start_val = mon_set_limit_mbyte(0, mb_limit);
+	prev_w_start_val = mon_set_limit_mbyte(1, mb_limit);
+
+	prev_ts = ktime_get();
+
+	set_l2_indirect_reg(L2PMINTENSET, BIT(0));
+	set_l2_indirect_reg(L2PMINTENSET, BIT(1));
+	mon_enable(0);
+	mon_enable(1);
+	global_mon_enable(true);
+
+	queue_delayed_work(bw_sample_wq, &bw_sample,
+				msecs_to_jiffies(sample_ms));
+
+	return 0;
+
+bus_reg_fail:
+	destroy_workqueue(bw_sample_wq);
+alloc_wq_fail:
+	disable_irq(MON_INT);
+	free_irq(MON_INT, mon_intr_handler);
+	return ret;
+}
+
+static void stop_monitoring(void)
+{
+	global_mon_enable(false);
+	mon_disable(0);
+	mon_disable(1);
+	set_l2_indirect_reg(L2PMINTENCLR, BIT(0));
+	set_l2_indirect_reg(L2PMINTENCLR, BIT(1));
+
+	disable_irq(MON_INT);
+	free_irq(MON_INT, mon_intr_handler);
+
+	cancel_delayed_work_sync(&bw_sample);
+	destroy_workqueue(bw_sample_wq);
+
+	bw_levels[0].vectors[0].ib = 0;
+	bw_levels[0].vectors[0].ab = 0;
+	bw_levels[0].vectors[1].ib = 0;
+	bw_levels[0].vectors[1].ab = 0;
+
+	bw_levels[1].vectors[0].ib = 0;
+	bw_levels[1].vectors[0].ab = 0;
+	bw_levels[1].vectors[1].ib = 0;
+	bw_levels[1].vectors[1].ab = 0;
+	msm_bus_scale_unregister_client(bus_client);
+}
+
+static void set_bw(int mbps)
+{
+	static int cur_idx, cur_ab, cur_ib;
+	int new_ab, new_ib;
+	int i, ret;
+
+	if (!io_percent)
+		io_percent = 1;
+	new_ab = roundup(mbps, bw_step);
+	new_ib = mbps * 100 / io_percent;
+	new_ib = roundup(new_ib, bw_step);
+
+	if (cur_ib == new_ib && cur_ab == new_ab)
+		return;
+
+	i = (cur_idx + 1) % ARRAY_SIZE(bw_levels);
+
+	bw_levels[i].vectors[0].ib = new_ib * 1000000ULL;
+	bw_levels[i].vectors[0].ab = new_ab * 1000000ULL;
+	bw_levels[i].vectors[1].ib = new_ib * 1000000ULL;
+	bw_levels[i].vectors[1].ab = new_ab * 1000000ULL;
+
+	pr_debug("BW MBps: Req: %d AB: %d IB: %d\n", mbps, new_ab, new_ib);
+
+	ret = msm_bus_scale_client_update_request(bus_client, i);
+	if (ret)
+		pr_err("bandwidth request failed (%d)\n", ret);
+	else {
+		cur_idx = i;
+		cur_ib = new_ib;
+		cur_ab = new_ab;
+	}
+}
+
+static void compute_bw(int mbps)
+{
+	static int cur_bw;
+	int new_bw;
+
+	mbps += guard_band_mbps;
+
+	if (mbps > cur_bw) {
+		new_bw = mbps;
+	} else {
+		new_bw = mbps * decay_rate + cur_bw * (100 - decay_rate);
+		new_bw /= 100;
+	}
+
+	if (new_bw == cur_bw)
+		return;
+
+	set_bw(new_bw);
+	cur_bw = new_bw;
+}
+
+static int to_limit(int mbps)
+{
+	mbps *= (100 + tolerance_percent) * sample_ms;
+	mbps /= 100;
+	mbps = DIV_ROUND_UP(mbps, MSEC_PER_SEC);
+	return mbps;
+}
+
+static void measure_bw(void)
+{
+	int r_mbps, w_mbps, mbps;
+	ktime_t ts;
+	unsigned int us;
+
+	mutex_lock(&bw_lock);
+
+	/*
+	 * Since we are stopping the counters, we don't want this short work
+	 * to be interrupted by other tasks and cause the measurements to be
+	 * wrong. Not blocking interrupts to avoid affecting interrupt
+	 * latency and since they should be short anyway because they run in
+	 * atomic context.
+	 */
+	preempt_disable();
+
+	ts = ktime_get();
+	us = ktime_to_us(ktime_sub(ts, prev_ts));
+	if (!us)
+		us = 1;
+
+	mon_disable(0);
+	mon_disable(1);
+
+	r_mbps = mon_get_mbps(0, prev_r_start_val, us);
+	w_mbps = mon_get_mbps(1, prev_w_start_val, us);
+
+	prev_r_start_val = mon_set_limit_mbyte(0, to_limit(r_mbps));
+	prev_w_start_val = mon_set_limit_mbyte(1, to_limit(w_mbps));
+
+	mon_enable(0);
+	mon_enable(1);
+
+	preempt_enable();
+
+	mbps = r_mbps + w_mbps;
+	pr_debug("R/W/BW/us = %d/%d/%d/%d\n", r_mbps, w_mbps, mbps, us);
+	compute_bw(mbps);
+
+	prev_ts = ts;
+	mutex_unlock(&bw_lock);
+}
+
+static void do_bw_sample(struct work_struct *work)
+{
+	measure_bw();
+	queue_delayed_work(bw_sample_wq, &bw_sample,
+				msecs_to_jiffies(sample_ms));
+}
+
+static irqreturn_t mon_intr_handler(int irq, void *dev_id)
+{
+	bool pending;
+	u32 regval;
+
+	regval = get_l2_indirect_reg(L2PMOVSR);
+	pr_debug("Got interrupt: %x\n", regval);
+
+	pending = cancel_delayed_work_sync(&bw_sample);
+
+	/*
+	 * Don't recalc bandwidth if the interrupt came just after the end
+	 * of the sample period (!pending). This is done for two reasons:
+	 *
+	 * 1. Sampling the BW during a very short duration can result in a
+	 *    very inaccurate measurement due to very short bursts.
+	 * 2. If the limit was hit very close to the sample period, then the
+	 *    current BW estimate is not very off and can stay as such.
+	 */
+	if (pending)
+		measure_bw();
+
+	queue_delayed_work(bw_sample_wq, &bw_sample,
+				msecs_to_jiffies(sample_ms));
+
+	return IRQ_HANDLED;
+}
+
+static int set_enable(const char *arg, const struct kernel_param *kp)
+{
+	int ret;
+	bool old_val = *((bool *) kp->arg);
+	bool new_val;
+
+	if (!arg)
+		arg = "1";
+	ret = strtobool(arg, &new_val);
+	if (ret)
+		return ret;
+
+	if (!old_val && new_val) {
+		if (start_monitoring()) {
+			pr_err("L2PM counters already in use.\n");
+			return ret;
+		} else {
+			pr_info("Enabling CPU BW monitoring\n");
+		}
+	} else if (old_val && !new_val) {
+		pr_info("Disabling CPU BW monitoring\n");
+		stop_monitoring();
+	}
+
+	*(bool *) kp->arg = new_val;
+	return 0;
+}
+
+static struct kernel_param_ops enable_ops = {
+	.set = set_enable,
+	.get = param_get_bool,
+};
+
+static int cpubw_krait_init(void)
+{
+	bw_sample_wq = alloc_workqueue("cpubw-krait", WQ_HIGHPRI, 0);
+	if (!bw_sample_wq)
+		return -ENOMEM;
+
+	bus_client = msm_bus_scale_register_client(&bw_data);
+	if (!bus_client) {
+		pr_err("Unable to register bus client\n");
+		destroy_workqueue(bw_sample_wq);
+		return -ENODEV;
+	}
+
+	return 0;
+}
+late_initcall(cpubw_krait_init);
+
+MODULE_DESCRIPTION("CPU DDR bandwidth voting driver for Krait CPUs");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/include/mach/kgsl.h b/arch/arm/mach-msm/include/mach/kgsl.h
index 2d7e8df..f398652 100644
--- a/arch/arm/mach-msm/include/mach/kgsl.h
+++ b/arch/arm/mach-msm/include/mach/kgsl.h
@@ -81,9 +81,9 @@
 	int (*set_grp_async)(void);
 	unsigned int idle_timeout;
 	bool strtstp_sleepwake;
+	bool bus_control;
 	unsigned int clk_map;
 	unsigned int idle_needed;
-	unsigned int step_mul;
 	struct msm_bus_scale_pdata *bus_scale_table;
 	struct kgsl_device_iommu_data *iommu_data;
 	int iommu_count;
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_bimc.c b/arch/arm/mach-msm/msm_bus/msm_bus_bimc.c
index 8b64653..c745f92 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_bimc.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_bimc.c
@@ -1578,15 +1578,16 @@
 
 static void set_qos_bw_regs(void __iomem *baddr, uint32_t mas_index,
 	int32_t th, int32_t tm, int32_t tl, uint32_t gp,
-	uint32_t gc, bool bke_en)
+	uint32_t gc)
 {
 	int32_t reg_val, val;
+	int32_t bke_reg_val;
 	int16_t val2;
 
 	/* Disable BKE before writing to registers as per spec */
-	reg_val = readl_relaxed(M_BKE_EN_ADDR(baddr, mas_index)) &
+	bke_reg_val = readl_relaxed(M_BKE_EN_ADDR(baddr, mas_index)) &
 		M_BKE_EN_RMSK;
-	writel_relaxed((reg_val & ~(M_BKE_EN_EN_BMSK)),
+	writel_relaxed((bke_reg_val & ~(M_BKE_EN_EN_BMSK)),
 		M_BKE_EN_ADDR(baddr, mas_index));
 
 	/* Write values of registers calculated */
@@ -1624,8 +1625,7 @@
 	/* Set BKE enable to the value it was */
 	reg_val = readl_relaxed(M_BKE_EN_ADDR(baddr, mas_index)) &
 		M_BKE_EN_RMSK;
-	val =  bke_en << M_BKE_EN_EN_SHFT;
-	writel_relaxed(((reg_val & ~(M_BKE_EN_EN_BMSK)) | (val &
+	writel_relaxed(((reg_val & ~(M_BKE_EN_EN_BMSK)) | (bke_reg_val &
 		M_BKE_EN_EN_BMSK)), M_BKE_EN_ADDR(baddr, mas_index));
 	/* Ensure that all bandwidth register writes have completed
 	 * before returning
@@ -1651,7 +1651,7 @@
 	/* Only calculate if there's a requested bandwidth and window */
 	if (qbw->bw && qbw->ws) {
 		int64_t th, tm, tl;
-		uint32_t gp, gc, data_width;
+		uint32_t gp, gc;
 		int64_t gp_nominal, gp_required, gp_calc, data, temp;
 		int64_t win = qbw->ws * binfo->qos_freq;
 		temp = win;
@@ -1666,16 +1666,7 @@
 		 * Calculate max window size, defined by bw request.
 		 * Units: (KHz, MB/s)
 		 */
-		data_width = (readl_relaxed(M_CONFIG_INFO_2_ADDR(
-			binfo->base, mas_index)) &
-			M_CONFIG_INFO_2_M_DATA_WIDTH_BMSK) >>
-			M_CONFIG_INFO_2_M_DATA_WIDTH_SHFT;
-
-		/* If unspecified, use data-width 8 by default */
-		if (!data_width)
-			data_width = 8;
-
-		gp_calc = MAX_GC * data_width * binfo->qos_freq * 1000;
+		gp_calc = MAX_GC * binfo->qos_freq * 1000;
 		gp_required = gp_calc;
 		bimc_div(&gp_required, qbw->bw);
 
@@ -1684,7 +1675,7 @@
 
 		/* Calculate bandwith in grants and ceil. */
 		temp = qbw->bw * gp;
-		data = data_width * binfo->qos_freq * 1000;
+		data = binfo->qos_freq * 1000;
 		bimc_div(&temp, data);
 		gc = min_t(int64_t, MAX_GC, temp);
 
@@ -1704,12 +1695,10 @@
 			mas_index, th, tm);
 		MSM_BUS_DBG("BIMC: tl: %llu gp:%u gc: %u bke_en: %u\n",
 			tl, gp, gc, bke_en);
-		set_qos_bw_regs(binfo->base, mas_index, th, tm, tl, gp,
-			gc, bke_en);
+		set_qos_bw_regs(binfo->base, mas_index, th, tm, tl, gp, gc);
 	} else
 		/* Clear bandwidth registers */
-		set_qos_bw_regs(binfo->base, mas_index, 0, 0, 0, 0, 0,
-			bke_en);
+		set_qos_bw_regs(binfo->base, mas_index, 0, 0, 0, 0, 0);
 }
 
 static int msm_bus_bimc_allocate_commit_data(struct msm_bus_fabric_registration
@@ -1816,16 +1805,27 @@
 	kfree(cd);
 }
 
-static void bke_switch(void __iomem *baddr, uint32_t mas_index, bool req)
+static void bke_switch(
+	void __iomem *baddr, uint32_t mas_index, bool req, int mode)
 {
 	uint32_t reg_val, val;
 
 	val = req << M_BKE_EN_EN_SHFT;
 	reg_val = readl_relaxed(M_BKE_EN_ADDR(baddr, mas_index)) &
 		M_BKE_EN_RMSK;
+	if (val == reg_val)
+		return;
+
+	if (!req && mode == BIMC_QOS_MODE_FIXED)
+		set_qos_mode(baddr, mas_index, 1, 1, 1);
+
 	writel_relaxed(((reg_val & ~(M_BKE_EN_EN_BMSK)) | (val &
 		M_BKE_EN_EN_BMSK)), M_BKE_EN_ADDR(baddr, mas_index));
+	/* Make sure BKE on/off goes through before changing priorities */
 	wmb();
+
+	if (req)
+		set_qos_mode(baddr, mas_index, 0, 0, 0);
 }
 
 static void msm_bus_bimc_config_master(
@@ -1854,13 +1854,13 @@
 	case BIMC_QOS_MODE_FIXED:
 		for (i = 0; i < ports; i++)
 			bke_switch(binfo->base, info->node_info->qport[i],
-				BKE_OFF);
+				BKE_OFF, mode);
 		break;
 	case BIMC_QOS_MODE_REGULATOR:
 	case BIMC_QOS_MODE_LIMITER:
 		for (i = 0; i < ports; i++)
 			bke_switch(binfo->base, info->node_info->qport[i],
-				BKE_ON);
+				BKE_ON, mode);
 		break;
 	default:
 		break;
@@ -1969,8 +1969,8 @@
 static void bimc_set_static_qos_bw(struct msm_bus_bimc_info *binfo,
 	int mport, struct msm_bus_bimc_qos_bw *qbw)
 {
-	int32_t bw_MBps, thh = 0, thm, thl, gc;
-	int16_t gp;
+	int32_t bw_mbps, thh = 0, thm, thl, gc;
+	int32_t gp;
 	u64 temp;
 
 	if (binfo->qos_freq == 0) {
@@ -1986,17 +1986,17 @@
 	/* Convert bandwidth to MBPS */
 	temp = qbw->bw;
 	bimc_div(&temp, 1000000);
-	bw_MBps = temp;
+	bw_mbps = temp;
 
 	/* Grant period in clock cycles
 	 * Grant period from bandwidth structure
-	 * is in micro seconds, QoS freq is in KHz.
+	 * is in nano seconds, QoS freq is in KHz.
 	 * Divide by 1000 to get clock cycles */
-	gp = (binfo->qos_freq * qbw->gp) / 1000;
+	gp = (binfo->qos_freq * qbw->gp) / (1000 * NSEC_PER_USEC);
 
 	/* Grant count = BW in MBps * Grant period
 	 * in micro seconds */
-	gc = bw_MBps * qbw->gp;
+	gc = bw_mbps * (qbw->gp / NSEC_PER_USEC);
 
 	/* Medium threshold = -((Medium Threshold percentage *
 	 * Grant count) / 100) */
@@ -2007,8 +2007,10 @@
 	thl = -gc;
 	qbw->thl = thl;
 
-	set_qos_bw_regs(binfo->base, mport, thh, thm, thl, gp,
-		gc, 1);
+	MSM_BUS_DBG("%s: BKE parameters: gp %d, gc %d, thm %d thl %d thh %d",
+			__func__, gp, gc, thm, thl, thh);
+
+	set_qos_bw_regs(binfo->base, mport, thh, thm, thl, gp, gc);
 }
 
 static void bimc_init_mas_reg(struct msm_bus_bimc_info *binfo,
diff --git a/arch/arm/mach-msm/qdsp6v2/q6audio_v2_aio.c b/arch/arm/mach-msm/qdsp6v2/q6audio_v2_aio.c
index 4681437..21040b1 100644
--- a/arch/arm/mach-msm/qdsp6v2/q6audio_v2_aio.c
+++ b/arch/arm/mach-msm/qdsp6v2/q6audio_v2_aio.c
@@ -108,9 +108,7 @@
 		break;
 	case RESET_EVENTS:
 		pr_debug("%s: Received opcode:0x%x\n", __func__, opcode);
-		audio->event_abort = 1;
 		audio->stopped = 1;
-		audio->enabled = 0;
 		wake_up(&audio->event_wait);
 		break;
 	default:
diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
index 34ae4e6..ac6ccf3b 100644
--- a/arch/arm/mm/init.c
+++ b/arch/arm/mm/init.c
@@ -885,8 +885,9 @@
 		   MLM(VMALLOC_START, VMALLOC_END),
 		   MLM(PAGE_OFFSET, (unsigned long)high_memory));
 #endif
-#ifdef CONFIG_HIGHMEM
+
 	printk(KERN_NOTICE
+#ifdef CONFIG_HIGHMEM
 		   "    pkmap   : 0x%08lx - 0x%08lx   (%4ld MB)\n"
 #endif
 #ifdef CONFIG_MODULES
diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c
index 4507f80..3aa86463 100644
--- a/drivers/char/adsprpc.c
+++ b/drivers/char/adsprpc.c
@@ -198,7 +198,7 @@
 					me->smmu.domain_id, 0);
 			buf->phys = 0;
 		}
-		if (buf->virt) {
+		if (!IS_ERR_OR_NULL(buf->virt)) {
 			ion_unmap_kernel(me->iclient, buf->handle);
 			buf->virt = 0;
 		}
@@ -211,7 +211,7 @@
 {
 	struct fastrpc_apps *me = &gfa;
 	if (!IS_ERR_OR_NULL(map->handle)) {
-		if (map->virt) {
+		if (!IS_ERR_OR_NULL(map->virt)) {
 			ion_unmap_kernel(me->iclient, map->handle);
 			map->virt = 0;
 		}
@@ -230,13 +230,15 @@
 	unsigned long len;
 	buf->handle = 0;
 	buf->virt = 0;
+	buf->phys = 0;
 	heap = me->smmu.enabled ? ION_HEAP(ION_IOMMU_HEAP_ID) :
 		ION_HEAP(ION_ADSP_HEAP_ID) | ION_HEAP(ION_AUDIO_HEAP_ID);
 	buf->handle = ion_alloc(clnt, buf->size, SZ_4K, heap, ION_FLAG_CACHED);
 	VERIFY(err, 0 == IS_ERR_OR_NULL(buf->handle));
 	if (err)
 		goto bail;
-	VERIFY(err, 0 != (buf->virt = ion_map_kernel(clnt, buf->handle)));
+	buf->virt = ion_map_kernel(clnt, buf->handle);
+	VERIFY(err, 0 == IS_ERR_OR_NULL(buf->virt));
 	if (err)
 		goto bail;
 	if (me->smmu.enabled) {
@@ -355,6 +357,9 @@
 		list[i].num = 0;
 		list[i].pgidx = 0;
 		len = pra[i].buf.len;
+		VERIFY(err, len >= 0);
+		if (err)
+			goto bail;
 		if (!len)
 			continue;
 		buf = pra[i].buf.pv;
@@ -852,7 +857,7 @@
 	context_free(ctx);
 
 	if (me->smmu.enabled) {
-		bufs = REMOTE_SCALARS_LENGTH(sc);
+		bufs = REMOTE_SCALARS_INBUFS(sc) + REMOTE_SCALARS_OUTBUFS(sc);
 		if (fds) {
 			handles = (struct ion_handle **)(fds + bufs);
 			for (i = 0; i < bufs; i++)
@@ -1028,7 +1033,8 @@
 	VERIFY(err, 0 == IS_ERR_OR_NULL(map->handle));
 	if (err)
 		goto bail;
-	VERIFY(err, 0 != (map->virt = ion_map_kernel(clnt, map->handle)));
+	map->virt = ion_map_kernel(clnt, map->handle);
+	VERIFY(err, 0 == IS_ERR_OR_NULL(map->virt));
 	if (err)
 		goto bail;
 	buf = (void *)mmap->vaddrin;
diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile
index 46756c5..83ab92b 100644
--- a/drivers/cpufreq/Makefile
+++ b/drivers/cpufreq/Makefile
@@ -1,5 +1,5 @@
 # CPUfreq core
-obj-$(CONFIG_CPU_FREQ)			+= cpufreq.o
+obj-$(CONFIG_CPU_FREQ)			+= cpufreq.o cpu-boost.o
 # CPUfreq stats
 obj-$(CONFIG_CPU_FREQ_STAT)             += cpufreq_stats.o
 
diff --git a/drivers/cpufreq/cpu-boost.c b/drivers/cpufreq/cpu-boost.c
new file mode 100644
index 0000000..f789425
--- /dev/null
+++ b/drivers/cpufreq/cpu-boost.c
@@ -0,0 +1,192 @@
+/*
+ * Copyright (c) 2013, 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.
+ */
+
+#define pr_fmt(fmt) "cpu-boost: " fmt
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/notifier.h>
+#include <linux/cpufreq.h>
+#include <linux/sched.h>
+#include <linux/jiffies.h>
+#include <linux/kthread.h>
+#include <linux/moduleparam.h>
+
+struct cpu_sync {
+	struct task_struct *thread;
+	wait_queue_head_t sync_wq;
+	struct delayed_work boost_rem;
+	int cpu;
+	spinlock_t lock;
+	bool pending;
+	int src_cpu;
+	unsigned int boost_min;
+};
+
+static DEFINE_PER_CPU(struct cpu_sync, sync_info);
+static struct workqueue_struct *boost_rem_wq;
+
+static unsigned int boost_ms = 50;
+module_param(boost_ms, uint, 0644);
+
+static unsigned int sync_threshold;
+module_param(sync_threshold, uint, 0644);
+/*
+ * The CPUFREQ_ADJUST notifier is used to override the current policy min to
+ * make sure policy min >= boost_min. The cpufreq framework then does the job
+ * of enforcing the new policy.
+ */
+static int boost_adjust_notify(struct notifier_block *nb, unsigned long val, void *data)
+{
+	struct cpufreq_policy *policy = data;
+	unsigned int cpu = policy->cpu;
+	struct cpu_sync *s = &per_cpu(sync_info, cpu);
+	unsigned int min = s->boost_min;
+
+	if (val != CPUFREQ_ADJUST)
+		return NOTIFY_OK;
+
+	if (min == 0)
+		return NOTIFY_OK;
+
+	pr_debug("CPU%u policy min before boost: %u kHz\n",
+		 cpu, policy->min);
+	pr_debug("CPU%u boost min: %u kHz\n", cpu, min);
+
+	cpufreq_verify_within_limits(policy, min, UINT_MAX);
+
+	pr_debug("CPU%u policy min after boost: %u kHz\n",
+		 cpu, policy->min);
+
+	return NOTIFY_OK;
+}
+
+static struct notifier_block boost_adjust_nb = {
+	.notifier_call = boost_adjust_notify,
+};
+
+static void do_boost_rem(struct work_struct *work)
+{
+	struct cpu_sync *s = container_of(work, struct cpu_sync,
+						boost_rem.work);
+
+	pr_debug("Removing boost for CPU%d\n", s->cpu);
+	s->boost_min = 0;
+	/* Force policy re-evaluation to trigger adjust notifier. */
+	cpufreq_update_policy(s->cpu);
+}
+
+static int boost_mig_sync_thread(void *data)
+{
+	int dest_cpu = (int) data;
+	int src_cpu, ret;
+	struct cpu_sync *s = &per_cpu(sync_info, dest_cpu);
+	struct cpufreq_policy dest_policy;
+	struct cpufreq_policy src_policy;
+	unsigned long flags;
+
+	while(1) {
+		wait_event(s->sync_wq, s->pending || kthread_should_stop());
+
+		if (kthread_should_stop())
+			break;
+
+		spin_lock_irqsave(&s->lock, flags);
+		s->pending = false;
+		src_cpu = s->src_cpu;
+		spin_unlock_irqrestore(&s->lock, flags);
+
+		ret = cpufreq_get_policy(&src_policy, src_cpu);
+		if (ret)
+			continue;
+
+		ret = cpufreq_get_policy(&dest_policy, dest_cpu);
+		if (ret)
+			continue;
+
+		if (dest_policy.cur >= src_policy.cur ) {
+			pr_debug("No sync. CPU%d@%dKHz >= CPU%d@%dKHz\n",
+				 dest_cpu, dest_policy.cur, src_cpu, src_policy.cur);
+			continue;
+		}
+
+		if (sync_threshold && (dest_policy.cur >= sync_threshold))
+			continue;
+
+		cancel_delayed_work_sync(&s->boost_rem);
+		if (sync_threshold) {
+			if (src_policy.cur >= sync_threshold)
+				s->boost_min = sync_threshold;
+			else
+				s->boost_min = src_policy.cur;
+		} else {
+			s->boost_min = src_policy.cur;
+		}
+		/* Force policy re-evaluation to trigger adjust notifier. */
+		cpufreq_update_policy(dest_cpu);
+		queue_delayed_work_on(s->cpu, boost_rem_wq,
+			&s->boost_rem, msecs_to_jiffies(boost_ms));
+	}
+
+	return 0;
+}
+
+static int boost_migration_notify(struct notifier_block *nb,
+				unsigned long dest_cpu, void *arg)
+{
+	unsigned long flags;
+	struct cpu_sync *s = &per_cpu(sync_info, dest_cpu);
+
+	if (!boost_ms)
+		return NOTIFY_OK;
+
+	pr_debug("Migration: CPU%d --> CPU%d\n", (int) arg, (int) dest_cpu);
+	spin_lock_irqsave(&s->lock, flags);
+	s->pending = true;
+	s->src_cpu = (int) arg;
+	spin_unlock_irqrestore(&s->lock, flags);
+	wake_up(&s->sync_wq);
+
+	return NOTIFY_OK;
+}
+
+static struct notifier_block boost_migration_nb = {
+	.notifier_call = boost_migration_notify,
+};
+
+static int cpu_boost_init(void)
+{
+	int cpu;
+	struct cpu_sync *s;
+
+	cpufreq_register_notifier(&boost_adjust_nb, CPUFREQ_POLICY_NOTIFIER);
+
+	boost_rem_wq = alloc_workqueue("cpuboost_rem_wq", WQ_HIGHPRI, 0);
+	if (!boost_rem_wq)
+		return -EFAULT;
+
+	for_each_possible_cpu(cpu) {
+		s = &per_cpu(sync_info, cpu);
+		s->cpu = cpu;
+		init_waitqueue_head(&s->sync_wq);
+		spin_lock_init(&s->lock);
+		INIT_DELAYED_WORK(&s->boost_rem, do_boost_rem);
+		s->thread = kthread_run(boost_mig_sync_thread, (void *)cpu,
+					"boost_sync/%d", cpu);
+	}
+	atomic_notifier_chain_register(&migration_notifier_head,
+					&boost_migration_nb);
+
+	return 0;
+}
+late_initcall(cpu_boost_init);
diff --git a/drivers/cpufreq/cpufreq_interactive.c b/drivers/cpufreq/cpufreq_interactive.c
index 7d1952c..6c55285 100644
--- a/drivers/cpufreq/cpufreq_interactive.c
+++ b/drivers/cpufreq/cpufreq_interactive.c
@@ -29,6 +29,7 @@
 #include <linux/workqueue.h>
 #include <linux/kthread.h>
 #include <linux/slab.h>
+#include <linux/kernel_stat.h>
 #include <asm/cputime.h>
 
 #define CREATE_TRACE_POINTS
@@ -69,6 +70,9 @@
 #define DEFAULT_GO_HISPEED_LOAD 99
 static unsigned long go_hispeed_load = DEFAULT_GO_HISPEED_LOAD;
 
+/* Sampling down factor to be applied to min_sample_time at max freq */
+static unsigned int sampling_down_factor;
+
 /* Target load.  Lower values result in higher CPU speeds. */
 #define DEFAULT_TARGET_LOAD 90
 static unsigned int default_target_loads[] = {DEFAULT_TARGET_LOAD};
@@ -93,7 +97,11 @@
  * timer interval.
  */
 #define DEFAULT_ABOVE_HISPEED_DELAY DEFAULT_TIMER_RATE
-static unsigned long above_hispeed_delay_val = DEFAULT_ABOVE_HISPEED_DELAY;
+static unsigned int default_above_hispeed_delay[] = {
+	DEFAULT_ABOVE_HISPEED_DELAY };
+static spinlock_t above_hispeed_delay_lock;
+static unsigned int *above_hispeed_delay = default_above_hispeed_delay;
+static int nabove_hispeed_delay = ARRAY_SIZE(default_above_hispeed_delay);
 
 /* Non-zero means indefinite speed boost active */
 static int boost_val;
@@ -109,6 +117,8 @@
 #define DEFAULT_TIMER_SLACK (4 * DEFAULT_TIMER_RATE)
 static int timer_slack_val = DEFAULT_TIMER_SLACK;
 
+static bool io_is_busy;
+
 static int cpufreq_governor_interactive(struct cpufreq_policy *policy,
 		unsigned int event);
 
@@ -122,27 +132,108 @@
 	.owner = THIS_MODULE,
 };
 
+static inline cputime64_t get_cpu_idle_time_jiffy(unsigned int cpu,
+						  cputime64_t *wall)
+{
+	u64 idle_time;
+	u64 cur_wall_time;
+	u64 busy_time;
+
+	cur_wall_time = jiffies64_to_cputime64(get_jiffies_64());
+
+	busy_time  = kcpustat_cpu(cpu).cpustat[CPUTIME_USER];
+	busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_SYSTEM];
+	busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_IRQ];
+	busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_SOFTIRQ];
+	busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_STEAL];
+	busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_NICE];
+
+	idle_time = cur_wall_time - busy_time;
+	if (wall)
+		*wall = jiffies_to_usecs(cur_wall_time);
+
+	return jiffies_to_usecs(idle_time);
+}
+
+static inline cputime64_t get_cpu_idle_time(unsigned int cpu,
+					    cputime64_t *wall)
+{
+	u64 idle_time = get_cpu_idle_time_us(cpu, wall);
+
+	if (idle_time == -1ULL)
+		idle_time = get_cpu_idle_time_jiffy(cpu, wall);
+	else if (!io_is_busy)
+		idle_time += get_cpu_iowait_time_us(cpu, wall);
+
+	return idle_time;
+}
+
 static void cpufreq_interactive_timer_resched(
 	struct cpufreq_interactive_cpuinfo *pcpu)
 {
-	unsigned long expires = jiffies + usecs_to_jiffies(timer_rate);
+	unsigned long expires;
 	unsigned long flags;
 
+	spin_lock_irqsave(&pcpu->load_lock, flags);
+	pcpu->time_in_idle =
+		get_cpu_idle_time(smp_processor_id(),
+				     &pcpu->time_in_idle_timestamp);
+	pcpu->cputime_speedadj = 0;
+	pcpu->cputime_speedadj_timestamp = pcpu->time_in_idle_timestamp;
+	expires = jiffies + usecs_to_jiffies(timer_rate);
 	mod_timer_pinned(&pcpu->cpu_timer, expires);
+
 	if (timer_slack_val >= 0 && pcpu->target_freq > pcpu->policy->min) {
 		expires += usecs_to_jiffies(timer_slack_val);
 		mod_timer_pinned(&pcpu->cpu_slack_timer, expires);
 	}
 
+	spin_unlock_irqrestore(&pcpu->load_lock, flags);
+}
+
+/* The caller shall take enable_sem write semaphore to avoid any timer race.
+ * The cpu_timer and cpu_slack_timer must be deactivated when calling this
+ * function.
+ */
+static void cpufreq_interactive_timer_start(int cpu)
+{
+	struct cpufreq_interactive_cpuinfo *pcpu = &per_cpu(cpuinfo, cpu);
+	unsigned long expires = jiffies + usecs_to_jiffies(timer_rate);
+	unsigned long flags;
+
+	pcpu->cpu_timer.expires = expires;
+	add_timer_on(&pcpu->cpu_timer, cpu);
+	if (timer_slack_val >= 0 && pcpu->target_freq > pcpu->policy->min) {
+		expires += usecs_to_jiffies(timer_slack_val);
+		pcpu->cpu_slack_timer.expires = expires;
+		add_timer_on(&pcpu->cpu_slack_timer, cpu);
+	}
+
 	spin_lock_irqsave(&pcpu->load_lock, flags);
 	pcpu->time_in_idle =
-		get_cpu_idle_time_us(smp_processor_id(),
-				     &pcpu->time_in_idle_timestamp);
+		get_cpu_idle_time(cpu, &pcpu->time_in_idle_timestamp);
 	pcpu->cputime_speedadj = 0;
 	pcpu->cputime_speedadj_timestamp = pcpu->time_in_idle_timestamp;
 	spin_unlock_irqrestore(&pcpu->load_lock, flags);
 }
 
+static unsigned int freq_to_above_hispeed_delay(unsigned int freq)
+{
+	int i;
+	unsigned int ret;
+	unsigned long flags;
+
+	spin_lock_irqsave(&above_hispeed_delay_lock, flags);
+
+	for (i = 0; i < nabove_hispeed_delay - 1 &&
+			freq >= above_hispeed_delay[i+1]; i += 2)
+		;
+
+	ret = above_hispeed_delay[i];
+	spin_unlock_irqrestore(&above_hispeed_delay_lock, flags);
+	return ret;
+}
+
 static unsigned int freq_to_targetload(unsigned int freq)
 {
 	int i;
@@ -185,9 +276,10 @@
 		 * than or equal to the target load.
 		 */
 
-		cpufreq_frequency_table_target(
-			pcpu->policy, pcpu->freq_table, loadadjfreq / tl,
-			CPUFREQ_RELATION_L, &index);
+		if (cpufreq_frequency_table_target(
+			    pcpu->policy, pcpu->freq_table, loadadjfreq / tl,
+			    CPUFREQ_RELATION_L, &index))
+			break;
 		freq = pcpu->freq_table[index].frequency;
 
 		if (freq > prevfreq) {
@@ -199,10 +291,11 @@
 				 * Find the highest frequency that is less
 				 * than freqmax.
 				 */
-				cpufreq_frequency_table_target(
-					pcpu->policy, pcpu->freq_table,
-					freqmax - 1, CPUFREQ_RELATION_H,
-					&index);
+				if (cpufreq_frequency_table_target(
+					    pcpu->policy, pcpu->freq_table,
+					    freqmax - 1, CPUFREQ_RELATION_H,
+					    &index))
+					break;
 				freq = pcpu->freq_table[index].frequency;
 
 				if (freq == freqmin) {
@@ -225,10 +318,11 @@
 				 * Find the lowest frequency that is higher
 				 * than freqmin.
 				 */
-				cpufreq_frequency_table_target(
-					pcpu->policy, pcpu->freq_table,
-					freqmin + 1, CPUFREQ_RELATION_L,
-					&index);
+				if (cpufreq_frequency_table_target(
+					    pcpu->policy, pcpu->freq_table,
+					    freqmin + 1, CPUFREQ_RELATION_L,
+					    &index))
+					break;
 				freq = pcpu->freq_table[index].frequency;
 
 				/*
@@ -256,10 +350,15 @@
 	unsigned int delta_time;
 	u64 active_time;
 
-	now_idle = get_cpu_idle_time_us(cpu, &now);
+	now_idle = get_cpu_idle_time(cpu, &now);
 	delta_idle = (unsigned int)(now_idle - pcpu->time_in_idle);
 	delta_time = (unsigned int)(now - pcpu->time_in_idle_timestamp);
-	active_time = delta_time - delta_idle;
+
+	if (delta_time <= delta_idle)
+		active_time = 0;
+	else
+		active_time = delta_time - delta_idle;
+
 	pcpu->cputime_speedadj += active_time * pcpu->policy->cur;
 
 	pcpu->time_in_idle = now_idle;
@@ -280,6 +379,7 @@
 	unsigned int index;
 	unsigned long flags;
 	bool boosted;
+	unsigned long mod_min_sample_time;
 
 	if (!down_read_trylock(&pcpu->enable_sem))
 		return;
@@ -315,7 +415,8 @@
 
 	if (pcpu->target_freq >= hispeed_freq &&
 	    new_freq > pcpu->target_freq &&
-	    now - pcpu->hispeed_validate_time < above_hispeed_delay_val) {
+	    now - pcpu->hispeed_validate_time <
+	    freq_to_above_hispeed_delay(pcpu->target_freq)) {
 		trace_cpufreq_interactive_notyet(
 			data, cpu_load, pcpu->target_freq,
 			pcpu->policy->cur, new_freq);
@@ -326,11 +427,8 @@
 
 	if (cpufreq_frequency_table_target(pcpu->policy, pcpu->freq_table,
 					   new_freq, CPUFREQ_RELATION_L,
-					   &index)) {
-		pr_warn_once("timer %d: cpufreq_frequency_table_target error\n",
-			     (int) data);
+					   &index))
 		goto rearm;
-	}
 
 	new_freq = pcpu->freq_table[index].frequency;
 
@@ -338,8 +436,14 @@
 	 * Do not scale below floor_freq unless we have been at or above the
 	 * floor frequency for the minimum sample time since last validated.
 	 */
+	if (pcpu->policy->cur == pcpu->policy->max) {
+		mod_min_sample_time = sampling_down_factor;
+	} else {
+		mod_min_sample_time = min_sample_time;
+	}
+
 	if (new_freq < pcpu->floor_freq) {
-		if (now - pcpu->floor_validate_time < min_sample_time) {
+		if (now - pcpu->floor_validate_time < mod_min_sample_time) {
 			trace_cpufreq_interactive_notyet(
 				data, cpu_load, pcpu->target_freq,
 				pcpu->policy->cur, new_freq);
@@ -565,9 +669,19 @@
 		for_each_cpu(cpu, pcpu->policy->cpus) {
 			struct cpufreq_interactive_cpuinfo *pjcpu =
 				&per_cpu(cpuinfo, cpu);
+			if (cpu != freq->cpu) {
+				if (!down_read_trylock(&pjcpu->enable_sem))
+					continue;
+				if (!pjcpu->governor_enabled) {
+					up_read(&pjcpu->enable_sem);
+					continue;
+				}
+			}
 			spin_lock_irqsave(&pjcpu->load_lock, flags);
 			update_load(cpu);
 			spin_unlock_irqrestore(&pjcpu->load_lock, flags);
+			if (cpu != freq->cpu)
+				up_read(&pjcpu->enable_sem);
 		}
 
 		up_read(&pcpu->enable_sem);
@@ -579,6 +693,51 @@
 	.notifier_call = cpufreq_interactive_notifier,
 };
 
+static unsigned int *get_tokenized_data(const char *buf, int *num_tokens)
+{
+	const char *cp;
+	int i;
+	int ntokens = 1;
+	unsigned int *tokenized_data;
+	int err = -EINVAL;
+
+	cp = buf;
+	while ((cp = strpbrk(cp + 1, " :")))
+		ntokens++;
+
+	if (!(ntokens & 0x1))
+		goto err;
+
+	tokenized_data = kmalloc(ntokens * sizeof(unsigned int), GFP_KERNEL);
+	if (!tokenized_data) {
+		err = -ENOMEM;
+		goto err;
+	}
+
+	cp = buf;
+	i = 0;
+	while (i < ntokens) {
+		if (sscanf(cp, "%u", &tokenized_data[i++]) != 1)
+			goto err_kfree;
+
+		cp = strpbrk(cp, " :");
+		if (!cp)
+			break;
+		cp++;
+	}
+
+	if (i != ntokens)
+		goto err_kfree;
+
+	*num_tokens = ntokens;
+	return tokenized_data;
+
+err_kfree:
+	kfree(tokenized_data);
+err:
+	return ERR_PTR(err);
+}
+
 static ssize_t show_target_loads(
 	struct kobject *kobj, struct attribute *attr, char *buf)
 {
@@ -592,7 +751,7 @@
 		ret += sprintf(buf + ret, "%u%s", target_loads[i],
 			       i & 0x1 ? ":" : " ");
 
-	ret += sprintf(buf + ret, "\n");
+	ret += sprintf(buf + --ret, "\n");
 	spin_unlock_irqrestore(&target_loads_lock, flags);
 	return ret;
 }
@@ -601,40 +760,13 @@
 	struct kobject *kobj, struct attribute *attr, const char *buf,
 	size_t count)
 {
-	int ret;
-	const char *cp;
+	int ntokens;
 	unsigned int *new_target_loads = NULL;
-	int ntokens = 1;
-	int i;
 	unsigned long flags;
 
-	cp = buf;
-	while ((cp = strpbrk(cp + 1, " :")))
-		ntokens++;
-
-	if (!(ntokens & 0x1))
-		goto err_inval;
-
-	new_target_loads = kmalloc(ntokens * sizeof(unsigned int), GFP_KERNEL);
-	if (!new_target_loads) {
-		ret = -ENOMEM;
-		goto err;
-	}
-
-	cp = buf;
-	i = 0;
-	while (i < ntokens) {
-		if (sscanf(cp, "%u", &new_target_loads[i++]) != 1)
-			goto err_inval;
-
-		cp = strpbrk(cp, " :");
-		if (!cp)
-			break;
-		cp++;
-	}
-
-	if (i != ntokens)
-		goto err_inval;
+	new_target_loads = get_tokenized_data(buf, &ntokens);
+	if (IS_ERR(new_target_loads))
+		return PTR_RET(new_target_loads);
 
 	spin_lock_irqsave(&target_loads_lock, flags);
 	if (target_loads != default_target_loads)
@@ -643,18 +775,56 @@
 	ntarget_loads = ntokens;
 	spin_unlock_irqrestore(&target_loads_lock, flags);
 	return count;
-
-err_inval:
-	ret = -EINVAL;
-err:
-	kfree(new_target_loads);
-	return ret;
 }
 
 static struct global_attr target_loads_attr =
 	__ATTR(target_loads, S_IRUGO | S_IWUSR,
 		show_target_loads, store_target_loads);
 
+static ssize_t show_above_hispeed_delay(
+	struct kobject *kobj, struct attribute *attr, char *buf)
+{
+	int i;
+	ssize_t ret = 0;
+	unsigned long flags;
+
+	spin_lock_irqsave(&above_hispeed_delay_lock, flags);
+
+	for (i = 0; i < nabove_hispeed_delay; i++)
+		ret += sprintf(buf + ret, "%u%s", above_hispeed_delay[i],
+			       i & 0x1 ? ":" : " ");
+
+	ret += sprintf(buf + --ret, "\n");
+	spin_unlock_irqrestore(&above_hispeed_delay_lock, flags);
+	return ret;
+}
+
+static ssize_t store_above_hispeed_delay(
+	struct kobject *kobj, struct attribute *attr, const char *buf,
+	size_t count)
+{
+	int ntokens;
+	unsigned int *new_above_hispeed_delay = NULL;
+	unsigned long flags;
+
+	new_above_hispeed_delay = get_tokenized_data(buf, &ntokens);
+	if (IS_ERR(new_above_hispeed_delay))
+		return PTR_RET(new_above_hispeed_delay);
+
+	spin_lock_irqsave(&above_hispeed_delay_lock, flags);
+	if (above_hispeed_delay != default_above_hispeed_delay)
+		kfree(above_hispeed_delay);
+	above_hispeed_delay = new_above_hispeed_delay;
+	nabove_hispeed_delay = ntokens;
+	spin_unlock_irqrestore(&above_hispeed_delay_lock, flags);
+	return count;
+
+}
+
+static struct global_attr above_hispeed_delay_attr =
+	__ATTR(above_hispeed_delay, S_IRUGO | S_IWUSR,
+		show_above_hispeed_delay, store_above_hispeed_delay);
+
 static ssize_t show_hispeed_freq(struct kobject *kobj,
 				 struct attribute *attr, char *buf)
 {
@@ -678,6 +848,29 @@
 static struct global_attr hispeed_freq_attr = __ATTR(hispeed_freq, 0644,
 		show_hispeed_freq, store_hispeed_freq);
 
+static ssize_t show_sampling_down_factor(struct kobject *kobj,
+				struct attribute *attr, char *buf)
+{
+	return sprintf(buf, "%u\n", sampling_down_factor);
+}
+
+static ssize_t store_sampling_down_factor(struct kobject *kobj,
+				struct attribute *attr, const char *buf,
+				size_t count)
+{
+	int ret;
+	long unsigned int val;
+
+	ret = strict_strtoul(buf, 0, &val);
+	if (ret < 0)
+		return ret;
+	sampling_down_factor = val;
+	return count;
+}
+
+static struct global_attr sampling_down_factor_attr =
+				__ATTR(sampling_down_factor, 0644,
+		show_sampling_down_factor, store_sampling_down_factor);
 
 static ssize_t show_go_hispeed_load(struct kobject *kobj,
 				     struct attribute *attr, char *buf)
@@ -723,28 +916,6 @@
 static struct global_attr min_sample_time_attr = __ATTR(min_sample_time, 0644,
 		show_min_sample_time, store_min_sample_time);
 
-static ssize_t show_above_hispeed_delay(struct kobject *kobj,
-					struct attribute *attr, char *buf)
-{
-	return sprintf(buf, "%lu\n", above_hispeed_delay_val);
-}
-
-static ssize_t store_above_hispeed_delay(struct kobject *kobj,
-					 struct attribute *attr,
-					 const char *buf, size_t count)
-{
-	int ret;
-	unsigned long val;
-
-	ret = strict_strtoul(buf, 0, &val);
-	if (ret < 0)
-		return ret;
-	above_hispeed_delay_val = val;
-	return count;
-}
-
-define_one_global_rw(above_hispeed_delay);
-
 static ssize_t show_timer_rate(struct kobject *kobj,
 			struct attribute *attr, char *buf)
 {
@@ -862,17 +1033,41 @@
 
 define_one_global_rw(boostpulse_duration);
 
+static ssize_t show_io_is_busy(struct kobject *kobj,
+			struct attribute *attr, char *buf)
+{
+	return sprintf(buf, "%u\n", io_is_busy);
+}
+
+static ssize_t store_io_is_busy(struct kobject *kobj,
+			struct attribute *attr, const char *buf, size_t count)
+{
+	int ret;
+	unsigned long val;
+
+	ret = kstrtoul(buf, 0, &val);
+	if (ret < 0)
+		return ret;
+	io_is_busy = val;
+	return count;
+}
+
+static struct global_attr io_is_busy_attr = __ATTR(io_is_busy, 0644,
+		show_io_is_busy, store_io_is_busy);
+
 static struct attribute *interactive_attributes[] = {
 	&target_loads_attr.attr,
+	&above_hispeed_delay_attr.attr,
 	&hispeed_freq_attr.attr,
 	&go_hispeed_load_attr.attr,
-	&above_hispeed_delay.attr,
 	&min_sample_time_attr.attr,
 	&timer_rate_attr.attr,
 	&timer_slack.attr,
 	&boost.attr,
 	&boostpulse.attr,
 	&boostpulse_duration.attr,
+	&io_is_busy_attr.attr,
+	&sampling_down_factor_attr.attr,
 	NULL,
 };
 
@@ -922,8 +1117,6 @@
 			hispeed_freq = policy->max;
 
 		for_each_cpu(j, policy->cpus) {
-			unsigned long expires;
-
 			pcpu = &per_cpu(cpuinfo, j);
 			pcpu->policy = policy;
 			pcpu->target_freq = policy->cur;
@@ -934,14 +1127,7 @@
 			pcpu->hispeed_validate_time =
 				pcpu->floor_validate_time;
 			down_write(&pcpu->enable_sem);
-			expires = jiffies + usecs_to_jiffies(timer_rate);
-			pcpu->cpu_timer.expires = expires;
-			add_timer_on(&pcpu->cpu_timer, j);
-			if (timer_slack_val >= 0) {
-				expires += usecs_to_jiffies(timer_slack_val);
-				pcpu->cpu_slack_timer.expires = expires;
-				add_timer_on(&pcpu->cpu_slack_timer, j);
-			}
+			cpufreq_interactive_timer_start(j);
 			pcpu->governor_enabled = 1;
 			up_write(&pcpu->enable_sem);
 		}
@@ -1000,6 +1186,33 @@
 		else if (policy->min > policy->cur)
 			__cpufreq_driver_target(policy,
 					policy->min, CPUFREQ_RELATION_L);
+		for_each_cpu(j, policy->cpus) {
+			pcpu = &per_cpu(cpuinfo, j);
+
+			/* hold write semaphore to avoid race */
+			down_write(&pcpu->enable_sem);
+			if (pcpu->governor_enabled == 0) {
+				up_write(&pcpu->enable_sem);
+				continue;
+			}
+
+			/* update target_freq firstly */
+			if (policy->max < pcpu->target_freq)
+				pcpu->target_freq = policy->max;
+			else if (policy->min > pcpu->target_freq)
+				pcpu->target_freq = policy->min;
+
+			/* Reschedule timer.
+			 * Delete the timers, else the timer callback may
+			 * return without re-arm the timer when failed
+			 * acquire the semaphore. This race may cause timer
+			 * stopped unexpectedly.
+			 */
+			del_timer_sync(&pcpu->cpu_timer);
+			del_timer_sync(&pcpu->cpu_slack_timer);
+			cpufreq_interactive_timer_start(j);
+			up_write(&pcpu->enable_sem);
+		}
 		break;
 	}
 	return 0;
@@ -1029,6 +1242,7 @@
 
 	spin_lock_init(&target_loads_lock);
 	spin_lock_init(&speedchange_cpumask_lock);
+	spin_lock_init(&above_hispeed_delay_lock);
 	mutex_init(&gov_lock);
 	speedchange_task =
 		kthread_create(cpufreq_interactive_speedchange_task, NULL,
diff --git a/drivers/crypto/msm/qce.c b/drivers/crypto/msm/qce.c
index 7778477..8037187 100644
--- a/drivers/crypto/msm/qce.c
+++ b/drivers/crypto/msm/qce.c
@@ -1949,6 +1949,12 @@
 	else
 		q_req->cryptlen = areq->cryptlen - authsize;
 
+	if ((q_req->cryptlen > ULONG_MAX - ivsize) ||
+		(q_req->cryptlen + ivsize > ULONG_MAX - areq->assoclen)) {
+		pr_err("Integer overflow on total aead req length.\n");
+		return -EINVAL;
+	}
+
 	totallen = q_req->cryptlen + ivsize + areq->assoclen;
 	pad_len = ALIGN(totallen, ADM_CE_BLOCK_SIZE) - totallen;
 
diff --git a/drivers/crypto/msm/qce50.c b/drivers/crypto/msm/qce50.c
index 4c05978..a4154c1 100644
--- a/drivers/crypto/msm/qce50.c
+++ b/drivers/crypto/msm/qce50.c
@@ -43,13 +43,17 @@
 #define QCE_MAX_NUM_DSCR    0x500
 #define QCE_SECTOR_SIZE	    0x200
 
-static DEFINE_MUTEX(bam_register_cnt);
+static DEFINE_MUTEX(bam_register_lock);
 struct bam_registration_info {
+	struct list_head qlist;
 	uint32_t handle;
 	uint32_t cnt;
+	uint32_t bam_mem;
+	void __iomem *bam_iobase;
+	bool support_cmd_dscr;
 };
-static struct bam_registration_info bam_registry;
-static bool ce_bam_registered;
+static LIST_HEAD(qce50_bam_list);
+
 /*
  * CE HW device structure.
  * Each engine has an instance of the structure.
@@ -58,11 +62,14 @@
  */
 struct qce_device {
 	struct device *pdev;        /* Handle to platform_device structure */
+	struct bam_registration_info *pbam;
 
 	unsigned char *coh_vmem;    /* Allocated coherent virtual memory */
 	dma_addr_t coh_pmem;	    /* Allocated coherent physical memory */
 	int memsize;				/* Memory allocated */
-	int is_shared;				/* CE HW is shared */
+	uint32_t bam_mem;		/* bam physical address, from DT */
+	uint32_t bam_mem_size;		/* bam io size, from DT */
+	int is_shared;			/* CE HW is shared */
 	bool support_cmd_dscr;
 	bool support_hw_key;
 
@@ -2162,25 +2169,93 @@
 			sps_connect_info->desc.phys_base);
 	sps_free_endpoint(sps_pipe_info);
 }
-/**
- * Initialize SPS HW connected with CE core
- *
- * This function register BAM HW resources with
- * SPS driver and then initialize 2 SPS endpoints
- *
- * This function should only be called once typically
- * during driver probe.
- *
- * @pce_dev - Pointer to qce_device structure
- *
- * @return - 0 if successful else negative value.
- *
- */
-static int qce_sps_init(struct qce_device *pce_dev)
+
+static void qce_sps_release_bam(struct qce_device *pce_dev)
+{
+	struct bam_registration_info *pbam;
+
+	mutex_lock(&bam_register_lock);
+	pbam = pce_dev->pbam;
+	if (pbam == NULL)
+		goto ret;
+
+	pbam->cnt--;
+	if (pbam->cnt > 0)
+		goto ret;
+
+	if (pce_dev->ce_sps.bam_handle) {
+		sps_deregister_bam_device(pce_dev->ce_sps.bam_handle);
+
+		pr_debug("deregister bam handle %x\n",
+					pce_dev->ce_sps.bam_handle);
+		pce_dev->ce_sps.bam_handle = 0;
+	}
+	iounmap(pbam->bam_iobase);
+	pr_debug("delete bam 0x%x\n", pbam->bam_mem);
+	list_del(&pbam->qlist);
+	kfree(pbam);
+
+	pce_dev->pbam = NULL;
+ret:
+	mutex_unlock(&bam_register_lock);
+}
+
+static int qce_sps_get_bam(struct qce_device *pce_dev)
 {
 	int rc = 0;
 	struct sps_bam_props bam = {0};
-	bool register_bam = false;
+	struct bam_registration_info *pbam = NULL;
+	struct bam_registration_info *p;
+	uint32_t bam_cfg = 0 ;
+
+
+	mutex_lock(&bam_register_lock);
+
+	list_for_each_entry(p, &qce50_bam_list, qlist) {
+		if (p->bam_mem == pce_dev->bam_mem) {
+			pbam = p;  /* found */
+			break;
+		}
+	}
+
+	if (pbam) {
+		pr_debug("found bam 0x%x\n", pbam->bam_mem);
+		pbam->cnt++;
+		pce_dev->ce_sps.bam_handle =  pbam->handle;
+		pce_dev->ce_sps.bam_mem = pbam->bam_mem;
+		pce_dev->ce_sps.bam_iobase = pbam->bam_iobase;
+		pce_dev->pbam = pbam;
+		pce_dev->support_cmd_dscr = pbam->support_cmd_dscr;
+		goto ret;
+	}
+
+	pbam = kzalloc(sizeof(struct  bam_registration_info), GFP_KERNEL);
+	if (!pbam) {
+		pr_err("qce50 Memory allocation of bam FAIL, error %ld\n",
+						PTR_ERR(pbam));
+
+		rc = -ENOMEM;
+		goto ret;
+	}
+	pbam->cnt = 1;
+	pbam->bam_mem = pce_dev->bam_mem;
+	pbam->bam_iobase = ioremap_nocache(pce_dev->bam_mem,
+					pce_dev->bam_mem_size);
+	if (!pbam->bam_iobase) {
+		kfree(pbam);
+		rc = -ENOMEM;
+		pr_err("Can not map BAM io memory\n");
+		goto ret;
+	}
+	pce_dev->ce_sps.bam_mem = pbam->bam_mem;
+	pce_dev->ce_sps.bam_iobase = pbam->bam_iobase;
+	pbam->handle = 0;
+	pr_debug("allocate bam 0x%x\n", pbam->bam_mem);
+	bam_cfg = readl_relaxed(pce_dev->ce_sps.bam_iobase +
+					CRYPTO_BAM_CNFG_BITS_REG);
+	pbam->support_cmd_dscr =  (bam_cfg & CRYPTO_BAM_CD_ENABLE_MASK) ?
+					true : false;
+	pce_dev->support_cmd_dscr = pbam->support_cmd_dscr;
 
 	bam.phys_addr = pce_dev->ce_sps.bam_mem;
 	bam.virt_addr = pce_dev->ce_sps.bam_iobase;
@@ -2212,27 +2287,46 @@
 	pr_debug("bam physical base=0x%x\n", (u32)bam.phys_addr);
 	pr_debug("bam virtual base=0x%x\n", (u32)bam.virt_addr);
 
-	mutex_lock(&bam_register_cnt);
-	if (ce_bam_registered == false) {
-		bam_registry.handle = 0;
-		bam_registry.cnt = 0;
+	/* Register CE Peripheral BAM device to SPS driver */
+	rc = sps_register_bam_device(&bam, &pbam->handle);
+	if (rc) {
+		pr_err("sps_register_bam_device() failed! err=%d", rc);
+		rc = -EIO;
+		iounmap(pbam->bam_iobase);
+		kfree(pbam);
+		goto ret;
 	}
-	if ((bam_registry.handle == 0) && (bam_registry.cnt == 0)) {
-		/* Register CE Peripheral BAM device to SPS driver */
-		rc = sps_register_bam_device(&bam, &bam_registry.handle);
-		if (rc) {
-			mutex_unlock(&bam_register_cnt);
-			pr_err("sps_register_bam_device() failed! err=%d", rc);
-			return -EIO;
-		}
-		bam_registry.cnt++;
-		register_bam = true;
-		ce_bam_registered = true;
-	} else {
-		   bam_registry.cnt++;
-	}
-	mutex_unlock(&bam_register_cnt);
-	pce_dev->ce_sps.bam_handle =  bam_registry.handle;
+
+	pce_dev->pbam = pbam;
+	list_add_tail(&pbam->qlist, &qce50_bam_list);
+	pce_dev->ce_sps.bam_handle =  pbam->handle;
+
+ret:
+	mutex_unlock(&bam_register_lock);
+
+	return rc;
+}
+/**
+ * Initialize SPS HW connected with CE core
+ *
+ * This function register BAM HW resources with
+ * SPS driver and then initialize 2 SPS endpoints
+ *
+ * This function should only be called once typically
+ * during driver probe.
+ *
+ * @pce_dev - Pointer to qce_device structure
+ *
+ * @return - 0 if successful else negative value.
+ *
+ */
+static int qce_sps_init(struct qce_device *pce_dev)
+{
+	int rc = 0;
+
+	rc = qce_sps_get_bam(pce_dev);
+	if (rc)
+		return rc;
 	pr_debug("BAM device registered. bam_handle=0x%x",
 		pce_dev->ce_sps.bam_handle);
 
@@ -2253,14 +2347,7 @@
 sps_connect_consumer_err:
 	qce_sps_exit_ep_conn(pce_dev, &pce_dev->ce_sps.producer);
 sps_connect_producer_err:
-	if (register_bam) {
-		mutex_lock(&bam_register_cnt);
-		sps_deregister_bam_device(pce_dev->ce_sps.bam_handle);
-		ce_bam_registered = false;
-		bam_registry.handle = 0;
-		bam_registry.cnt = 0;
-		mutex_unlock(&bam_register_cnt);
-	}
+	qce_sps_release_bam(pce_dev);
 	return rc;
 }
 
@@ -2280,17 +2367,7 @@
 {
 	qce_sps_exit_ep_conn(pce_dev, &pce_dev->ce_sps.consumer);
 	qce_sps_exit_ep_conn(pce_dev, &pce_dev->ce_sps.producer);
-	mutex_lock(&bam_register_cnt);
-	if ((bam_registry.handle != 0) && (bam_registry.cnt == 1)) {
-		sps_deregister_bam_device(pce_dev->ce_sps.bam_handle);
-		bam_registry.cnt = 0;
-		bam_registry.handle = 0;
-	}
-	if ((bam_registry.handle != 0) && (bam_registry.cnt > 1))
-		bam_registry.cnt--;
-	mutex_unlock(&bam_register_cnt);
-
-	iounmap(pce_dev->ce_sps.bam_iobase);
+	qce_sps_release_bam(pce_dev);
 }
 
 static void _aead_sps_producer_callback(struct sps_event_notify *notify)
@@ -4069,22 +4146,15 @@
 	resource = platform_get_resource_byname(pdev, IORESOURCE_MEM,
 							"crypto-bam-base");
 	if (resource) {
-		pce_dev->ce_sps.bam_mem = resource->start;
-		pce_dev->ce_sps.bam_iobase = ioremap_nocache(resource->start,
-					resource_size(resource));
-		if (!pce_dev->ce_sps.bam_iobase) {
-			rc = -ENOMEM;
-			pr_err("Can not map BAM io memory\n");
-			goto err_getting_bam_info;
-		}
+		pce_dev->bam_mem = resource->start;
+		pce_dev->bam_mem_size = resource_size(resource);
 	} else {
 		pr_err("CRYPTO BAM mem unavailable.\n");
 		rc = -ENODEV;
 		goto err_getting_bam_info;
 	}
-	pr_warn("ce_bam_phy_reg_base=0x%x  ", pce_dev->ce_sps.bam_mem);
-	pr_warn("ce_bam_virt_reg_base=0x%x\n",
-				(uint32_t)pce_dev->ce_sps.bam_iobase);
+	pr_warn("ce_bam_phy_reg_base=0x%x  ", pce_dev->bam_mem);
+
 	resource  = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
 	if (resource) {
 		pce_dev->ce_sps.bam_irq = resource->start;
@@ -4250,7 +4320,6 @@
 void *qce_open(struct platform_device *pdev, int *rc)
 {
 	struct qce_device *pce_dev;
-	uint32_t bam_cfg = 0 ;
 
 	pce_dev = kzalloc(sizeof(struct qce_device), GFP_KERNEL);
 	if (!pce_dev) {
@@ -4293,15 +4362,9 @@
 	}
 	*rc = 0;
 
-	bam_cfg = readl_relaxed(pce_dev->ce_sps.bam_iobase +
-					CRYPTO_BAM_CNFG_BITS_REG);
-	pce_dev->support_cmd_dscr = (bam_cfg & CRYPTO_BAM_CD_ENABLE_MASK) ?
-								true : false;
 	qce_init_ce_cfg_val(pce_dev);
-	qce_setup_ce_sps_data(pce_dev);
 	qce_sps_init(pce_dev);
-
-
+	qce_setup_ce_sps_data(pce_dev);
 	qce_disable_clk(pce_dev);
 
 	return pce_dev;
@@ -4313,8 +4376,6 @@
 		dma_free_coherent(pce_dev->pdev, pce_dev->memsize,
 			pce_dev->coh_vmem, pce_dev->coh_pmem);
 err_iobase:
-	if (pce_dev->ce_sps.bam_iobase)
-		iounmap(pce_dev->ce_sps.bam_iobase);
 	if (pce_dev->iobase)
 		iounmap(pce_dev->iobase);
 err_pce_dev:
diff --git a/drivers/crypto/msm/qcedev.c b/drivers/crypto/msm/qcedev.c
index 81a90fe..4845f11 100644
--- a/drivers/crypto/msm/qcedev.c
+++ b/drivers/crypto/msm/qcedev.c
@@ -1339,7 +1339,7 @@
 				areq->cipher_op_req.vbuf.src[0].len))
 		return -EFAULT;
 
-	k_align_src += areq->cipher_op_req.vbuf.src[0].len;
+	k_align_src += byteoffset + areq->cipher_op_req.vbuf.src[0].len;
 
 	for (i = 1; i < areq->cipher_op_req.entries; i++) {
 		user_src =
@@ -1602,11 +1602,6 @@
 static int qcedev_check_cipher_key(struct qcedev_cipher_op_req *req,
 						struct qcedev_control *podev)
 {
-
-	if (req->encklen < 0) {
-		pr_err("%s: Invalid key size: %d\n", __func__, req->encklen);
-		return -EINVAL;
-	}
 	/* if intending to use HW key make sure key fields are set
 	 * correctly and HW key is indeed supported in target
 	 */
@@ -1701,6 +1696,13 @@
 			goto error;
 		}
 	}
+
+	if (req->data_len < req->byteoffset) {
+		pr_err("%s: req data length %u is less than byteoffset %u\n",
+				__func__, req->data_len, req->byteoffset);
+		goto error;
+	}
+
 	/* Ensure zer ivlen for ECB  mode  */
 	if (req->ivlen > 0) {
 		if ((req->mode == QCEDEV_AES_MODE_ECB) ||
@@ -1716,16 +1718,28 @@
 		}
 	}
 	/* Check for sum of all dst length is equal to data_len  */
-	for (i = 0; (i < QCEDEV_MAX_BUFFERS) && (total < req->data_len); i++)
+	for (i = 0; (i < QCEDEV_MAX_BUFFERS) && (total < req->data_len); i++) {
+		if (req->vbuf.dst[i].len > ULONG_MAX - total) {
+			pr_err("%s: Integer overflow on total req dst vbuf length\n",
+				__func__);
+			goto error;
+		}
 		total += req->vbuf.dst[i].len;
+	}
 	if (total != req->data_len) {
 		pr_err("%s: Total (i=%d) dst(%d) buf size != data_len (%d)\n",
 			__func__, i, total, req->data_len);
 		goto error;
 	}
 	/* Check for sum of all src length is equal to data_len  */
-	for (i = 0, total = 0; i < req->entries; i++)
+	for (i = 0, total = 0; i < req->entries; i++) {
+		if (req->vbuf.src[i].len > ULONG_MAX - total) {
+			pr_err("%s: Integer overflow on total req src vbuf length\n",
+				__func__);
+			goto error;
+		}
 		total += req->vbuf.src[i].len;
+	}
 	if (total != req->data_len) {
 		pr_err("%s: Total src(%d) buf size != data_len (%d)\n",
 			__func__, total, req->data_len);
@@ -1781,8 +1795,15 @@
 	}
 
 	/* Check for sum of all src length is equal to data_len  */
-	for (i = 0, total = 0; i < req->entries; i++)
+	for (i = 0, total = 0; i < req->entries; i++) {
+		if (req->data[i].len > ULONG_MAX - total) {
+			pr_err("%s: Integer overflow on total req buf length\n",
+				__func__);
+			goto sha_error;
+		}
 		total += req->data[i].len;
+	}
+
 	if (total != req->data_len) {
 		pr_err("%s: Total src(%d) buf size != data_len (%d)\n",
 			__func__, total, req->data_len);
@@ -2112,21 +2133,21 @@
 	int len = 0;
 
 	pstat = &_qcedev_stat;
-	len = snprintf(_debug_read_buf, DEBUG_MAX_RW_BUF - 1,
+	len = scnprintf(_debug_read_buf, DEBUG_MAX_RW_BUF - 1,
 			"\nQualcomm QCE dev driver %d Statistics:\n",
 				id + 1);
 
-	len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+	len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
 			"   Encryption operation success       : %d\n",
 					pstat->qcedev_enc_success);
-	len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+	len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
 			"   Encryption operation fail   : %d\n",
 					pstat->qcedev_enc_fail);
-	len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+	len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
 			"   Decryption operation success     : %d\n",
 					pstat->qcedev_dec_success);
 
-	len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+	len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
 			"   Encryption operation fail          : %d\n",
 					pstat->qcedev_dec_fail);
 
diff --git a/drivers/crypto/msm/qcrypto.c b/drivers/crypto/msm/qcrypto.c
index ae57d6c..6606706 100644
--- a/drivers/crypto/msm/qcrypto.c
+++ b/drivers/crypto/msm/qcrypto.c
@@ -409,7 +409,7 @@
 {
 	int i;
 
-	for (i = 0; nbytes > 0; i++, sg = scatterwalk_sg_next(sg))
+	for (i = 0; nbytes > 0 && sg != NULL; i++, sg = scatterwalk_sg_next(sg))
 		nbytes -= sg->length;
 
 	return i;
@@ -628,98 +628,98 @@
 	int len = 0;
 
 	pstat = &_qcrypto_stat;
-	len = snprintf(_debug_read_buf, DEBUG_MAX_RW_BUF - 1,
+	len = scnprintf(_debug_read_buf, DEBUG_MAX_RW_BUF - 1,
 			"\nQualcomm crypto accelerator %d Statistics:\n",
 				id + 1);
 
-	len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+	len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
 			"   ABLK AES CIPHER encryption   : %d\n",
 					pstat->ablk_cipher_aes_enc);
-	len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+	len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
 			"   ABLK AES CIPHER decryption   : %d\n",
 					pstat->ablk_cipher_aes_dec);
 
-	len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+	len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
 			"   ABLK DES CIPHER encryption   : %d\n",
 					pstat->ablk_cipher_des_enc);
-	len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+	len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
 			"   ABLK DES CIPHER decryption   : %d\n",
 					pstat->ablk_cipher_des_dec);
 
-	len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+	len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
 			"   ABLK 3DES CIPHER encryption  : %d\n",
 					pstat->ablk_cipher_3des_enc);
 
-	len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+	len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
 			"   ABLK 3DES CIPHER decryption  : %d\n",
 					pstat->ablk_cipher_3des_dec);
 
-	len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+	len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
 			"   ABLK CIPHER operation success: %d\n",
 					pstat->ablk_cipher_op_success);
-	len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+	len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
 			"   ABLK CIPHER operation fail   : %d\n",
 					pstat->ablk_cipher_op_fail);
 
-	len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+	len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
 			"   AEAD SHA1-AES encryption      : %d\n",
 					pstat->aead_sha1_aes_enc);
-	len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+	len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
 			"   AEAD SHA1-AES decryption      : %d\n",
 					pstat->aead_sha1_aes_dec);
 
-	len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+	len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
 			"   AEAD SHA1-DES encryption      : %d\n",
 					pstat->aead_sha1_des_enc);
-	len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+	len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
 			"   AEAD SHA1-DES decryption      : %d\n",
 					pstat->aead_sha1_des_dec);
 
-	len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+	len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
 			"   AEAD SHA1-3DES encryption     : %d\n",
 					pstat->aead_sha1_3des_enc);
-	len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+	len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
 			"   AEAD SHA1-3DES decryption     : %d\n",
 					pstat->aead_sha1_3des_dec);
 
-	len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+	len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
 			"   AEAD CCM-AES encryption     : %d\n",
 					pstat->aead_ccm_aes_enc);
-	len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+	len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
 			"   AEAD CCM-AES decryption     : %d\n",
 					pstat->aead_ccm_aes_dec);
 
-	len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+	len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
 			"   AEAD operation success       : %d\n",
 					pstat->aead_op_success);
-	len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+	len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
 			"   AEAD operation fail          : %d\n",
 					pstat->aead_op_fail);
-	len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+	len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
 			"   AEAD bad message             : %d\n",
 					pstat->aead_bad_msg);
-	len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+	len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
 			"   SHA1 digest			 : %d\n",
 					pstat->sha1_digest);
-	len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+	len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
 			"   SHA256 digest		 : %d\n",
 					pstat->sha256_digest);
-	len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+	len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
 			"   SHA  operation fail          : %d\n",
 					pstat->sha_op_fail);
-	len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+	len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
 			"   SHA  operation success          : %d\n",
 					pstat->sha_op_success);
-	len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+	len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
 			"   SHA1 HMAC digest			 : %d\n",
 					pstat->sha1_hmac_digest);
-	len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+	len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
 			"   SHA256 HMAC digest		 : %d\n",
 					pstat->sha256_hmac_digest);
-	len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+	len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
 			"   SHA HMAC operation fail          : %d\n",
 					pstat->sha_hmac_op_fail);
-	len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+	len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
 			"   SHA HMAC operation success          : %d\n",
 					pstat->sha_hmac_op_success);
 	return len;
@@ -1423,8 +1423,20 @@
 
 			rctx->orig_src = req->src;
 			rctx->orig_dst = req->dst;
+
+			if ((MAX_ALIGN_SIZE*2 > ULONG_MAX - req->assoclen) ||
+				((MAX_ALIGN_SIZE*2 + req->assoclen) >
+						ULONG_MAX - qreq.authsize) ||
+				((MAX_ALIGN_SIZE*2 + req->assoclen +
+						qreq.authsize) >
+						ULONG_MAX - req->cryptlen)) {
+				pr_err("Integer overflow on aead req length.\n");
+				return -EINVAL;
+			}
+
 			rctx->data = kzalloc((req->cryptlen + qreq.assoclen +
-					qreq.authsize + 64*2), GFP_ATOMIC);
+					qreq.authsize + MAX_ALIGN_SIZE*2),
+					GFP_ATOMIC);
 			if (rctx->data == NULL) {
 				pr_err("Mem Alloc fail rctx->data, err %ld\n",
 							PTR_ERR(rctx->data));
@@ -1486,6 +1498,16 @@
 			 * include  assoicated data, ciphering data stream,
 			 * generated MAC, and CCM padding.
 			 */
+			if ((MAX_ALIGN_SIZE * 2 > ULONG_MAX - req->assoclen) ||
+				((MAX_ALIGN_SIZE * 2 + req->assoclen) >
+						ULONG_MAX - qreq.ivsize) ||
+				((MAX_ALIGN_SIZE * 2 + req->assoclen
+					+ qreq.ivsize)
+						> ULONG_MAX - req->cryptlen)) {
+				pr_err("Integer overflow on aead req length.\n");
+				return -EINVAL;
+			}
+
 			rctx->data = kzalloc(
 					(req->cryptlen +
 						req->assoclen +
diff --git a/drivers/devfreq/Kconfig b/drivers/devfreq/Kconfig
index 1c63b70..17bbe19 100644
--- a/drivers/devfreq/Kconfig
+++ b/drivers/devfreq/Kconfig
@@ -63,6 +63,14 @@
 	  Otherwise, the governor does not change the frequnecy
 	  given at the initialization.
 
+config DEVFREQ_GOV_MSM_ADRENO_TZ
+	tristate "MSM Adreno Trustzone"
+	depends on MSM_KGSL && MSM_SCM
+	help
+	  Trustzone based governor for the Adreno GPU.
+	  Sets the frequency using a "on-demand" algorithm.
+	  This governor is unlikely to be useful for other devices.
+
 comment "DEVFREQ Drivers"
 
 config ARM_EXYNOS4_BUS_DEVFREQ
diff --git a/drivers/devfreq/Makefile b/drivers/devfreq/Makefile
index 8c46423..29b48ff 100644
--- a/drivers/devfreq/Makefile
+++ b/drivers/devfreq/Makefile
@@ -3,6 +3,7 @@
 obj-$(CONFIG_DEVFREQ_GOV_PERFORMANCE)	+= governor_performance.o
 obj-$(CONFIG_DEVFREQ_GOV_POWERSAVE)	+= governor_powersave.o
 obj-$(CONFIG_DEVFREQ_GOV_USERSPACE)	+= governor_userspace.o
+obj-$(CONFIG_DEVFREQ_GOV_MSM_ADRENO_TZ)	+= governor_msm_adreno_tz.o
 
 # DEVFREQ Drivers
 obj-$(CONFIG_ARM_EXYNOS4_BUS_DEVFREQ)	+= exynos4_bus.o
diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
index dadf87c..9e49b3e 100644
--- a/drivers/devfreq/devfreq.c
+++ b/drivers/devfreq/devfreq.c
@@ -187,7 +187,7 @@
 		return -EINVAL;
 
 	/* Reevaluate the proper frequency */
-	err = devfreq->governor->get_target_freq(devfreq, &freq);
+	err = devfreq->governor->get_target_freq(devfreq, &freq, &flags);
 	if (err)
 		return err;
 
@@ -459,7 +459,7 @@
 		return NULL;
 
 	for (i = 0; i < profile->num_governor_data; i++) {
-		if (!strncmp(governor_name, profile->governor_data[i].name,
+		if (strncmp(governor_name, profile->governor_data[i].name,
 			     DEVFREQ_NAME_LEN) == 0) {
 			data = profile->governor_data[i].data;
 			break;
diff --git a/drivers/devfreq/governor_msm_adreno_tz.c b/drivers/devfreq/governor_msm_adreno_tz.c
new file mode 100644
index 0000000..8c97fe9
--- /dev/null
+++ b/drivers/devfreq/governor_msm_adreno_tz.c
@@ -0,0 +1,361 @@
+/* Copyright (c) 2010-2013, 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.
+ *
+ */
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/devfreq.h>
+#include <linux/math64.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/ftrace.h>
+#include <linux/msm_adreno_devfreq.h>
+#include <mach/scm.h>
+#include "governor.h"
+
+static DEFINE_SPINLOCK(tz_lock);
+
+/*
+ * FLOOR is 5msec to capture up to 3 re-draws
+ * per frame for 60fps content.
+ */
+#define FLOOR			5000
+#define LONG_FLOOR		50000
+#define HIST			5
+#define TARGET			80
+#define CAP			75
+
+/*
+ * CEILING is 50msec, larger than any standard
+ * frame length, but less than the idle timer.
+ */
+#define CEILING			50000
+#define TZ_RESET_ID		0x3
+#define TZ_UPDATE_ID		0x4
+#define TZ_INIT_ID		0x6
+
+#define TAG "msm_adreno_tz: "
+
+/* Trap into the TrustZone, and call funcs there. */
+static int __secure_tz_entry2(u32 cmd, u32 val1, u32 val2)
+{
+	int ret;
+	spin_lock(&tz_lock);
+	/* sync memory before sending the commands to tz*/
+	__iowmb();
+	ret = scm_call_atomic2(SCM_SVC_IO, cmd, val1, val2);
+	spin_unlock(&tz_lock);
+	return ret;
+}
+
+static int __secure_tz_entry3(u32 cmd, u32 val1, u32 val2, u32 val3)
+{
+	int ret;
+	spin_lock(&tz_lock);
+	/* sync memory before sending the commands to tz*/
+	__iowmb();
+	ret = scm_call_atomic3(SCM_SVC_IO, cmd, val1, val2, val3);
+	spin_unlock(&tz_lock);
+	return ret;
+}
+
+static void _update_cutoff(struct devfreq_msm_adreno_tz_data *priv,
+				unsigned int norm_max)
+{
+	int i;
+
+	priv->bus.max = norm_max;
+	for (i = 0; i < priv->bus.num; i++) {
+		priv->bus.up[i] = priv->bus.p_up[i] * norm_max / 100;
+		priv->bus.down[i] = priv->bus.p_down[i] * norm_max / 100;
+	}
+}
+
+static int tz_get_target_freq(struct devfreq *devfreq, unsigned long *freq,
+				u32 *flag)
+{
+	int result = 0;
+	struct devfreq_msm_adreno_tz_data *priv = devfreq->data;
+	struct devfreq_dev_status stats;
+	struct xstats b;
+	int val, level = 0;
+	int act_level;
+	int norm_cycles;
+	int gpu_percent;
+
+	if (priv->bus.num)
+		stats.private_data = &b;
+	else
+		stats.private_data = NULL;
+	result = devfreq->profile->get_dev_status(devfreq->dev.parent, &stats);
+	if (result) {
+		pr_err(TAG "get_status failed %d\n", result);
+		return result;
+	}
+
+	*freq = stats.current_frequency;
+	*flag = 0;
+	priv->bin.total_time += stats.total_time;
+	priv->bin.busy_time += stats.busy_time;
+	if (priv->bus.num) {
+		priv->bus.total_time += stats.total_time;
+		priv->bus.gpu_time += stats.busy_time;
+		priv->bus.ram_time += b.ram_time;
+		priv->bus.ram_time += b.ram_wait;
+	}
+
+	/*
+	 * Do not waste CPU cycles running this algorithm if
+	 * the GPU just started, or if less than FLOOR time
+	 * has passed since the last run.
+	 */
+	if ((stats.total_time == 0) ||
+		(priv->bin.total_time < FLOOR)) {
+		return 1;
+	}
+
+	level = devfreq_get_freq_level(devfreq, stats.current_frequency);
+
+	if (level < 0) {
+		pr_err(TAG "bad freq %ld\n", stats.current_frequency);
+		return level;
+	}
+
+	/*
+	 * If there is an extended block of busy processing,
+	 * increase frequency.  Otherwise run the normal algorithm.
+	 */
+	if (priv->bin.busy_time > CEILING) {
+		val = -1 * level;
+	} else {
+		val = __secure_tz_entry3(TZ_UPDATE_ID,
+				level,
+				priv->bin.total_time,
+				priv->bin.busy_time);
+	}
+	priv->bin.total_time = 0;
+	priv->bin.busy_time = 0;
+
+	/*
+	 * If the decision is to move to a different level, make sure the GPU
+	 * frequency changes.
+	 */
+	if (val) {
+		level += val;
+		level = max(level, 0);
+		level = min_t(int, level, devfreq->profile->max_state);
+		goto clear;
+	}
+
+	if (priv->bus.total_time < LONG_FLOOR)
+		goto end;
+	norm_cycles = (unsigned int)priv->bus.ram_time /
+			(unsigned int) priv->bus.total_time;
+	gpu_percent = (100 * (unsigned int)priv->bus.gpu_time) /
+			(unsigned int) priv->bus.total_time;
+	/*
+	 * If there's a new high watermark, update the cutoffs and send the
+	 * FAST hint.  Otherwise check the current value against the current
+	 * cutoffs.
+	 */
+	if (norm_cycles > priv->bus.max) {
+		_update_cutoff(priv, norm_cycles);
+		*flag = DEVFREQ_FLAG_FAST_HINT;
+	} else {
+		/*
+		 * Normalize by gpu_time unless it is a small fraction of
+		 * the total time interval.
+		 */
+		norm_cycles = (100 * norm_cycles) / TARGET;
+		act_level = priv->bus.index[level] + b.mod;
+		act_level = (act_level < 0) ? 0 : act_level;
+		act_level = (act_level >= priv->bus.num) ?
+			(priv->bus.num - 1) : act_level;
+		if (norm_cycles > priv->bus.up[act_level] &&
+			gpu_percent > CAP)
+			*flag = DEVFREQ_FLAG_FAST_HINT;
+		else if (norm_cycles < priv->bus.down[act_level] && level)
+			*flag = DEVFREQ_FLAG_SLOW_HINT;
+	}
+
+clear:
+	priv->bus.total_time = 0;
+	priv->bus.gpu_time = 0;
+	priv->bus.ram_time = 0;
+
+end:
+	*freq = devfreq->profile->freq_table[level];
+	return 0;
+}
+
+static int tz_notify(struct notifier_block *nb, unsigned long type, void *devp)
+{
+	int result = 0;
+	struct devfreq *devfreq = devp;
+
+	switch (type) {
+	case ADRENO_DEVFREQ_NOTIFY_IDLE:
+	case ADRENO_DEVFREQ_NOTIFY_RETIRE:
+		mutex_lock(&devfreq->lock);
+		result = update_devfreq(devfreq);
+		mutex_unlock(&devfreq->lock);
+		break;
+	/* ignored by this governor */
+	case ADRENO_DEVFREQ_NOTIFY_SUBMIT:
+	default:
+		break;
+	}
+	return notifier_from_errno(result);
+}
+
+static int tz_start(struct devfreq *devfreq)
+{
+	struct devfreq_msm_adreno_tz_data *priv;
+	unsigned int tz_pwrlevels[MSM_ADRENO_MAX_PWRLEVELS + 1];
+	unsigned int t1, t2 = 2 * HIST;
+	int i, out, ret;
+
+	if (devfreq->data == NULL) {
+		pr_err(TAG "data is required for this governor\n");
+		return -EINVAL;
+	}
+
+	priv = devfreq->data;
+	priv->nb.notifier_call = tz_notify;
+
+	out = 1;
+	if (devfreq->profile->max_state < MSM_ADRENO_MAX_PWRLEVELS) {
+		for (i = 0; i < devfreq->profile->max_state; i++)
+			tz_pwrlevels[out++] = devfreq->profile->freq_table[i];
+		tz_pwrlevels[0] = i;
+	} else {
+		pr_err(TAG "tz_pwrlevels[] is too short\n");
+		return -EINVAL;
+	}
+
+	ret = scm_call(SCM_SVC_DCVS, TZ_INIT_ID, tz_pwrlevels,
+			sizeof(tz_pwrlevels), NULL, 0);
+
+	if (ret != 0)
+		pr_err(TAG "tz_init failed\n");
+
+	/* Set up the cut-over percentages for the bus calculation. */
+	if (priv->bus.num) {
+		for (i = 0; i < priv->bus.num; i++) {
+			t1 = (u32)(100 * priv->bus.ib[i]) /
+					(u32)priv->bus.ib[priv->bus.num - 1];
+			priv->bus.p_up[i] = t1 - HIST;
+			priv->bus.p_down[i] = t2 - 2 * HIST;
+			t2 = t1;
+		}
+		/* Set the upper-most and lower-most bounds correctly. */
+		priv->bus.p_down[0] = 0;
+		priv->bus.p_down[1] = (priv->bus.p_down[1] > (2 * HIST)) ?
+					priv->bus.p_down[1] : (2 * HIST);
+		if (priv->bus.num - 1 >= 0)
+			priv->bus.p_up[priv->bus.num - 1] = 100;
+		_update_cutoff(priv, priv->bus.max);
+	}
+
+	return kgsl_devfreq_add_notifier(devfreq->dev.parent, &priv->nb);
+}
+
+static int tz_stop(struct devfreq *devfreq)
+{
+	struct devfreq_msm_adreno_tz_data *priv = devfreq->data;
+
+	kgsl_devfreq_del_notifier(devfreq->dev.parent, &priv->nb);
+	return 0;
+}
+
+
+static int tz_resume(struct devfreq *devfreq)
+{
+	struct devfreq_dev_profile *profile = devfreq->profile;
+	unsigned long freq;
+
+	freq = profile->initial_freq;
+
+	return profile->target(devfreq->dev.parent, &freq, 0);
+}
+
+static int tz_suspend(struct devfreq *devfreq)
+{
+	struct devfreq_msm_adreno_tz_data *priv = devfreq->data;
+
+	__secure_tz_entry2(TZ_RESET_ID, 0, 0);
+
+	priv->bin.total_time = 0;
+	priv->bin.busy_time = 0;
+	priv->bus.total_time = 0;
+	priv->bus.gpu_time = 0;
+	priv->bus.ram_time = 0;
+	return 0;
+}
+
+static int tz_handler(struct devfreq *devfreq, unsigned int event, void *data)
+{
+	int result;
+	BUG_ON(devfreq == NULL);
+
+	switch (event) {
+	case DEVFREQ_GOV_START:
+		result = tz_start(devfreq);
+		break;
+
+	case DEVFREQ_GOV_STOP:
+		result = tz_stop(devfreq);
+		break;
+
+	case DEVFREQ_GOV_SUSPEND:
+		result = tz_suspend(devfreq);
+		break;
+
+	case DEVFREQ_GOV_RESUME:
+		result = tz_resume(devfreq);
+		break;
+
+	case DEVFREQ_GOV_INTERVAL:
+		/* ignored, this governor doesn't use polling */
+	default:
+		result = 0;
+		break;
+	}
+
+	return result;
+}
+
+static struct devfreq_governor msm_adreno_tz = {
+	.name = "msm-adreno-tz",
+	.get_target_freq = tz_get_target_freq,
+	.event_handler = tz_handler,
+};
+
+static int __init msm_adreno_tz_init(void)
+{
+	return devfreq_add_governor(&msm_adreno_tz);
+}
+subsys_initcall(msm_adreno_tz_init);
+
+static void __exit msm_adreno_tz_exit(void)
+{
+	int ret;
+	ret = devfreq_remove_governor(&msm_adreno_tz);
+	if (ret)
+		pr_err(TAG "failed to remove governor %d\n", ret);
+
+	return;
+}
+
+module_exit(msm_adreno_tz_exit);
+
+MODULE_LICENSE("GPLv2");
diff --git a/drivers/devfreq/governor_performance.c b/drivers/devfreq/governor_performance.c
index bc7da1e..af2edc2 100644
--- a/drivers/devfreq/governor_performance.c
+++ b/drivers/devfreq/governor_performance.c
@@ -14,7 +14,8 @@
 #include "governor.h"
 
 static int devfreq_performance_func(struct devfreq *df,
-				    unsigned long *freq)
+				    unsigned long *freq,
+				u32 *flag)
 {
 	/*
 	 * target callback should be able to get floor value as
diff --git a/drivers/devfreq/governor_powersave.c b/drivers/devfreq/governor_powersave.c
index 6d43685..57f3738 100644
--- a/drivers/devfreq/governor_powersave.c
+++ b/drivers/devfreq/governor_powersave.c
@@ -14,7 +14,8 @@
 #include "governor.h"
 
 static int devfreq_powersave_func(struct devfreq *df,
-				  unsigned long *freq)
+				  unsigned long *freq,
+				u32 *flag)
 {
 	/*
 	 * target callback should be able to get ceiling value as
diff --git a/drivers/devfreq/governor_simpleondemand.c b/drivers/devfreq/governor_simpleondemand.c
index 0720ba8..bb29360 100644
--- a/drivers/devfreq/governor_simpleondemand.c
+++ b/drivers/devfreq/governor_simpleondemand.c
@@ -19,7 +19,8 @@
 #define DFSO_UPTHRESHOLD	(90)
 #define DFSO_DOWNDIFFERENCTIAL	(5)
 static int devfreq_simple_ondemand_func(struct devfreq *df,
-					unsigned long *freq)
+					unsigned long *freq,
+					u32 *flag)
 {
 	struct devfreq_dev_status stat;
 	int err = df->profile->get_dev_status(df->dev.parent, &stat);
diff --git a/drivers/devfreq/governor_userspace.c b/drivers/devfreq/governor_userspace.c
index 35de6e8..4fbde04 100644
--- a/drivers/devfreq/governor_userspace.c
+++ b/drivers/devfreq/governor_userspace.c
@@ -22,7 +22,8 @@
 	bool valid;
 };
 
-static int devfreq_userspace_func(struct devfreq *df, unsigned long *freq)
+static int devfreq_userspace_func(struct devfreq *df, unsigned long *freq,
+					u32 *flag)
 {
 	struct userspace_data *data = df->data;
 
diff --git a/drivers/gpu/ion/Makefile b/drivers/gpu/ion/Makefile
index 0e460c8..108abe6 100644
--- a/drivers/gpu/ion/Makefile
+++ b/drivers/gpu/ion/Makefile
@@ -2,4 +2,4 @@
 			ion_carveout_heap.o ion_chunk_heap.o
 obj-$(CONFIG_CMA) += ion_cma_heap.o ion_cma_secure_heap.o
 obj-$(CONFIG_ION_TEGRA) += tegra/
-obj-$(CONFIG_ION_MSM) += ion_iommu_heap.o ion_cp_heap.o ion_removed_heap.o msm/
+obj-$(CONFIG_ION_MSM) += ion_cp_heap.o ion_removed_heap.o msm/
diff --git a/drivers/gpu/ion/ion.c b/drivers/gpu/ion/ion.c
index 6777dae..c791c49 100644
--- a/drivers/gpu/ion/ion.c
+++ b/drivers/gpu/ion/ion.c
@@ -24,14 +24,13 @@
 #include <linux/ion.h>
 #include <linux/kthread.h>
 #include <linux/list.h>
+#include <linux/list_sort.h>
 #include <linux/memblock.h>
 #include <linux/miscdevice.h>
 #include <linux/export.h>
 #include <linux/mm.h>
 #include <linux/mm_types.h>
 #include <linux/rbtree.h>
-#include <linux/rtmutex.h>
-#include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/seq_file.h>
 #include <linux/uaccess.h>
@@ -62,6 +61,8 @@
 			      unsigned long arg);
 	struct rb_root clients;
 	struct dentry *debug_root;
+	struct dentry *heaps_debug_root;
+	struct dentry *clients_debug_root;
 };
 
 /**
@@ -147,7 +148,6 @@
 
 static int ion_buffer_alloc_dirty(struct ion_buffer *buffer);
 
-static bool ion_heap_drain_freelist(struct ion_heap *heap);
 /* this function should only be called while dev->lock is held */
 static struct ion_buffer *ion_buffer_create(struct ion_heap *heap,
 				     struct ion_device *dev,
@@ -174,7 +174,7 @@
 		if (!(heap->flags & ION_HEAP_FLAG_DEFER_FREE))
 			goto err2;
 
-		ion_heap_drain_freelist(heap);
+		ion_heap_freelist_drain(heap, 0);
 		ret = heap->ops->allocate(heap, buffer, len, align,
 					  flags);
 		if (ret)
@@ -242,7 +242,7 @@
 		buffer->heap->ops->unsecure_buffer(buffer, 1);
 }
 
-static void _ion_buffer_destroy(struct ion_buffer *buffer)
+void ion_buffer_destroy(struct ion_buffer *buffer)
 {
 	if (WARN_ON(buffer->kmap_cnt > 0))
 		buffer->heap->ops->unmap_kernel(buffer->heap, buffer);
@@ -255,7 +255,7 @@
 	kfree(buffer);
 }
 
-static void ion_buffer_destroy(struct kref *kref)
+static void _ion_buffer_destroy(struct kref *kref)
 {
 	struct ion_buffer *buffer = container_of(kref, struct ion_buffer, ref);
 	struct ion_heap *heap = buffer->heap;
@@ -265,14 +265,10 @@
 	rb_erase(&buffer->node, &dev->buffers);
 	mutex_unlock(&dev->buffer_lock);
 
-	if (heap->flags & ION_HEAP_FLAG_DEFER_FREE) {
-		rt_mutex_lock(&heap->lock);
-		list_add(&buffer->list, &heap->free_list);
-		rt_mutex_unlock(&heap->lock);
-		wake_up(&heap->waitqueue);
-		return;
-	}
-	_ion_buffer_destroy(buffer);
+	if (heap->flags & ION_HEAP_FLAG_DEFER_FREE)
+		ion_heap_freelist_add(heap, buffer);
+	else
+		ion_buffer_destroy(buffer);
 }
 
 static void ion_buffer_get(struct ion_buffer *buffer)
@@ -282,7 +278,7 @@
 
 static int ion_buffer_put(struct ion_buffer *buffer)
 {
-	return kref_put(&buffer->ref, ion_buffer_destroy);
+	return kref_put(&buffer->ref, _ion_buffer_destroy);
 }
 
 static void ion_buffer_add_to_handle(struct ion_buffer *buffer)
@@ -708,6 +704,35 @@
 	.release = single_release,
 };
 
+static bool startswith(const char *string, const char *prefix)
+{
+	size_t l1 = strlen(string);
+	size_t l2 = strlen(prefix);
+	return strncmp(string, prefix, min(l1, l2)) == 0;
+}
+
+static int ion_get_client_serial(const struct rb_root *root,
+					const unsigned char *name)
+{
+	int serial = -1;
+	struct rb_node *node;
+	for (node = rb_first(root); node; node = rb_next(node)) {
+		int n;
+		char *serial_string;
+		struct ion_client *client = rb_entry(node, struct ion_client,
+						node);
+		if (!startswith(client->name, name))
+			continue;
+		serial_string = strrchr(client->name, '-');
+		if (!serial_string)
+			continue;
+		serial_string++;
+		sscanf(serial_string, "%d", &n);
+		serial = max(serial, n);
+	}
+	return serial + 1;
+}
+
 struct ion_client *ion_client_create(struct ion_device *dev,
 				     const char *name)
 {
@@ -717,13 +742,16 @@
 	struct rb_node *parent = NULL;
 	struct ion_client *entry;
 	pid_t pid;
-	unsigned int name_len;
+	int name_len;
+	int client_serial;
 
 	if (!name) {
 		pr_err("%s: Name cannot be null\n", __func__);
 		return ERR_PTR(-EINVAL);
 	}
 	name_len = strnlen(name, 64);
+	/* add some space to accommodate the serial number suffix */
+	name_len = min(64, name_len + 11);
 
 	get_task_struct(current->group_leader);
 	task_lock(current->group_leader);
@@ -754,14 +782,14 @@
 		put_task_struct(current->group_leader);
 		kfree(client);
 		return ERR_PTR(-ENOMEM);
-	} else {
-		strlcpy(client->name, name, name_len+1);
 	}
 
 	client->task = task;
 	client->pid = pid;
 
 	down_write(&dev->lock);
+	client_serial = ion_get_client_serial(&dev->clients, name);
+	snprintf(client->name, name_len, "%s-%d", name, client_serial);
 	p = &dev->clients.rb_node;
 	while (*p) {
 		parent = *p;
@@ -776,9 +804,16 @@
 	rb_insert_color(&client->node, &dev->clients);
 
 
-	client->debug_root = debugfs_create_file(name, 0664,
-						 dev->debug_root, client,
-						 &debug_client_fops);
+	client->debug_root = debugfs_create_file(client->name, 0664,
+						dev->clients_debug_root,
+						client, &debug_client_fops);
+	if (!client->debug_root) {
+		char buf[256], *path;
+		path = dentry_path(dev->clients_debug_root, buf, 256);
+		pr_err("Failed to created client debugfs at %s/%s\n",
+			path, client->name);
+	}
+
 	up_write(&dev->lock);
 
 	return client;
@@ -1397,134 +1432,89 @@
 }
 
 /**
- * Searches through a clients handles to find if the buffer is owned
- * by this client. Used for debug output.
- * @param client pointer to candidate owner of buffer
- * @param buf pointer to buffer that we are trying to find the owner of
- * @return 1 if found, 0 otherwise
- */
-static int ion_debug_find_buffer_owner(const struct ion_client *client,
-				       const struct ion_buffer *buf)
-{
-	struct rb_node *n;
-
-	for (n = rb_first(&client->handles); n; n = rb_next(n)) {
-		const struct ion_handle *handle = rb_entry(n,
-						     const struct ion_handle,
-						     node);
-		if (handle->buffer == buf)
-			return 1;
-	}
-	return 0;
-}
-
-/**
- * Adds mem_map_data pointer to the tree of mem_map
- * Used for debug output.
- * @param mem_map The mem_map tree
- * @param data The new data to add to the tree
- */
-static void ion_debug_mem_map_add(struct rb_root *mem_map,
-				  struct mem_map_data *data)
-{
-	struct rb_node **p = &mem_map->rb_node;
-	struct rb_node *parent = NULL;
-	struct mem_map_data *entry;
-
-	while (*p) {
-		parent = *p;
-		entry = rb_entry(parent, struct mem_map_data, node);
-
-		if (data->addr < entry->addr) {
-			p = &(*p)->rb_left;
-		} else if (data->addr > entry->addr) {
-			p = &(*p)->rb_right;
-		} else {
-			pr_err("%s: mem_map_data already found.", __func__);
-			BUG();
-		}
-	}
-	rb_link_node(&data->node, parent, p);
-	rb_insert_color(&data->node, mem_map);
-}
-
-/**
- * Search for an owner of a buffer by iterating over all ION clients.
- * @param dev ion device containing pointers to all the clients.
- * @param buffer pointer to buffer we are trying to find the owner of.
- * @return name of owner.
- */
-const char *ion_debug_locate_owner(const struct ion_device *dev,
-					 const struct ion_buffer *buffer)
-{
-	struct rb_node *j;
-	const char *client_name = NULL;
-
-	for (j = rb_first(&dev->clients); j && !client_name;
-			  j = rb_next(j)) {
-		struct ion_client *client = rb_entry(j, struct ion_client,
-						     node);
-		if (ion_debug_find_buffer_owner(client, buffer))
-			client_name = client->name;
-	}
-	return client_name;
-}
-
-/**
  * Create a mem_map of the heap.
  * @param s seq_file to log error message to.
  * @param heap The heap to create mem_map for.
  * @param mem_map The mem map to be created.
  */
 void ion_debug_mem_map_create(struct seq_file *s, struct ion_heap *heap,
-			      struct rb_root *mem_map)
+			      struct list_head *mem_map)
 {
 	struct ion_device *dev = heap->dev;
-	struct rb_node *n;
+	struct rb_node *cnode;
 	size_t size;
+	struct ion_client *client;
 
 	if (!heap->ops->phys)
 		return;
 
-	for (n = rb_first(&dev->buffers); n; n = rb_next(n)) {
-		struct ion_buffer *buffer =
-				rb_entry(n, struct ion_buffer, node);
-		if (buffer->heap->id == heap->id) {
-			struct mem_map_data *data =
-					kzalloc(sizeof(*data), GFP_KERNEL);
-			if (!data) {
-				seq_printf(s, "ERROR: out of memory. "
-					   "Part of memory map will not be logged\n");
-				break;
-			}
+	down_read(&dev->lock);
+	for (cnode = rb_first(&dev->clients); cnode; cnode = rb_next(cnode)) {
+		struct rb_node *hnode;
+		client = rb_entry(cnode, struct ion_client, node);
 
-			buffer->heap->ops->phys(buffer->heap, buffer,
-						&(data->addr), &size);
-			data->size = (unsigned long) size;
-			data->addr_end = data->addr + data->size - 1;
-			data->client_name = ion_debug_locate_owner(dev, buffer);
-			ion_debug_mem_map_add(mem_map, data);
+		mutex_lock(&client->lock);
+		for (hnode = rb_first(&client->handles);
+		     hnode;
+		     hnode = rb_next(hnode)) {
+			struct ion_handle *handle = rb_entry(
+				hnode, struct ion_handle, node);
+			if (handle->buffer->heap == heap) {
+				struct mem_map_data *data =
+					kzalloc(sizeof(*data), GFP_KERNEL);
+				if (!data)
+					goto inner_error;
+				heap->ops->phys(heap, handle->buffer,
+							&(data->addr), &size);
+				data->size = (unsigned long) size;
+				data->addr_end = data->addr + data->size - 1;
+				data->client_name = kstrdup(client->name,
+							GFP_KERNEL);
+				if (!data->client_name) {
+					kfree(data);
+					goto inner_error;
+				}
+				list_add(&data->node, mem_map);
+			}
 		}
+		mutex_unlock(&client->lock);
 	}
+	up_read(&dev->lock);
+	return;
+
+inner_error:
+	seq_puts(s,
+		"ERROR: out of memory. Part of memory map will not be logged\n");
+	mutex_unlock(&client->lock);
+	up_read(&dev->lock);
 }
 
 /**
  * Free the memory allocated by ion_debug_mem_map_create
  * @param mem_map The mem map to free.
  */
-static void ion_debug_mem_map_destroy(struct rb_root *mem_map)
+static void ion_debug_mem_map_destroy(struct list_head *mem_map)
 {
 	if (mem_map) {
-		struct rb_node *n;
-		while ((n = rb_first(mem_map)) != 0) {
-			struct mem_map_data *data =
-					rb_entry(n, struct mem_map_data, node);
-			rb_erase(&data->node, mem_map);
+		struct mem_map_data *data, *tmp;
+		list_for_each_entry_safe(data, tmp, mem_map, node) {
+			list_del(&data->node);
+			kfree(data->client_name);
 			kfree(data);
 		}
 	}
 }
 
+static int mem_map_cmp(void *priv, struct list_head *a, struct list_head *b)
+{
+	struct mem_map_data *d1, *d2;
+	d1 = list_entry(a, struct mem_map_data, node);
+	d2 = list_entry(b, struct mem_map_data, node);
+	if (d1->addr == d2->addr)
+		return d1->size - d2->size;
+	return d1->addr - d2->addr;
+}
+
 /**
  * Print heap debug information.
  * @param s seq_file to log message to.
@@ -1533,8 +1523,9 @@
 static void ion_heap_print_debug(struct seq_file *s, struct ion_heap *heap)
 {
 	if (heap->ops->print_debug) {
-		struct rb_root mem_map = RB_ROOT;
+		struct list_head mem_map = LIST_HEAD_INIT(mem_map);
 		ion_debug_mem_map_create(s, heap, &mem_map);
+		list_sort(NULL, &mem_map, mem_map_cmp);
 		heap->ops->print_debug(heap, s, &mem_map);
 		ion_debug_mem_map_destroy(&mem_map);
 	}
@@ -1551,6 +1542,7 @@
 	seq_printf(s, "%16.s %16.s %16.s\n", "client", "pid", "size");
 	seq_printf(s, "----------------------------------------------------\n");
 
+	down_read(&dev->lock);
 	for (n = rb_first(&dev->clients); n; n = rb_next(n)) {
 		struct ion_client *client = rb_entry(n, struct ion_client,
 						     node);
@@ -1568,6 +1560,7 @@
 				   client->pid, size);
 		}
 	}
+	up_read(&dev->lock);
 	seq_printf(s, "----------------------------------------------------\n");
 	seq_printf(s, "orphaned allocations (info is from last known client):"
 		   "\n");
@@ -1611,87 +1604,89 @@
 	.release = single_release,
 };
 
-static size_t ion_heap_free_list_is_empty(struct ion_heap *heap)
+#ifdef DEBUG_HEAP_SHRINKER
+static int debug_shrink_set(void *data, u64 val)
 {
-	bool is_empty;
+        struct ion_heap *heap = data;
+        struct shrink_control sc;
+        int objs;
 
-	rt_mutex_lock(&heap->lock);
-	is_empty = list_empty(&heap->free_list);
-	rt_mutex_unlock(&heap->lock);
+        sc.gfp_mask = -1;
+        sc.nr_to_scan = 0;
 
-	return is_empty;
+        if (!val)
+                return 0;
+
+        objs = heap->shrinker.shrink(&heap->shrinker, &sc);
+        sc.nr_to_scan = objs;
+
+        heap->shrinker.shrink(&heap->shrinker, &sc);
+        return 0;
 }
 
-static int ion_heap_deferred_free(void *data)
+static int debug_shrink_get(void *data, u64 *val)
 {
-	struct ion_heap *heap = data;
+        struct ion_heap *heap = data;
+        struct shrink_control sc;
+        int objs;
 
-	while (true) {
-		struct ion_buffer *buffer;
+        sc.gfp_mask = -1;
+        sc.nr_to_scan = 0;
 
-		wait_event_freezable(heap->waitqueue,
-				     !ion_heap_free_list_is_empty(heap));
-
-		rt_mutex_lock(&heap->lock);
-		if (list_empty(&heap->free_list)) {
-			rt_mutex_unlock(&heap->lock);
-			continue;
-		}
-		buffer = list_first_entry(&heap->free_list, struct ion_buffer,
-					  list);
-		list_del(&buffer->list);
-		rt_mutex_unlock(&heap->lock);
-		_ion_buffer_destroy(buffer);
-	}
-
-	return 0;
+        objs = heap->shrinker.shrink(&heap->shrinker, &sc);
+        *val = objs;
+        return 0;
 }
 
-static bool ion_heap_drain_freelist(struct ion_heap *heap)
-{
-	struct ion_buffer *buffer, *tmp;
-
-	if (ion_heap_free_list_is_empty(heap))
-		return false;
-	rt_mutex_lock(&heap->lock);
-	list_for_each_entry_safe(buffer, tmp, &heap->free_list, list) {
-		list_del(&buffer->list);
-		_ion_buffer_destroy(buffer);
-	}
-	BUG_ON(!list_empty(&heap->free_list));
-	rt_mutex_unlock(&heap->lock);
-
-
-	return true;
-}
+DEFINE_SIMPLE_ATTRIBUTE(debug_shrink_fops, debug_shrink_get,
+                        debug_shrink_set, "%llu\n");
+#endif
 
 void ion_device_add_heap(struct ion_device *dev, struct ion_heap *heap)
 {
-	struct sched_param param = { .sched_priority = 0 };
+	struct dentry *debug_file;
 
 	if (!heap->ops->allocate || !heap->ops->free || !heap->ops->map_dma ||
 	    !heap->ops->unmap_dma)
 		pr_err("%s: can not add heap with invalid ops struct.\n",
 		       __func__);
 
-	if (heap->flags & ION_HEAP_FLAG_DEFER_FREE) {
-		INIT_LIST_HEAD(&heap->free_list);
-		rt_mutex_init(&heap->lock);
-		init_waitqueue_head(&heap->waitqueue);
-		heap->task = kthread_run(ion_heap_deferred_free, heap,
-					 "%s", heap->name);
-		sched_setscheduler(heap->task, SCHED_IDLE, &param);
-		if (IS_ERR(heap->task))
-			pr_err("%s: creating thread for deferred free failed\n",
-			       __func__);
-	}
+	if (heap->flags & ION_HEAP_FLAG_DEFER_FREE)
+		ion_heap_init_deferred_free(heap);
 
 	heap->dev = dev;
 	down_write(&dev->lock);
-	plist_node_init(&heap->node, heap->id);
+	/* use negative heap->id to reverse the priority -- when traversing
+	   the list later attempt higher id numbers first */
+	plist_node_init(&heap->node, -heap->id);
 	plist_add(&heap->node, &dev->heaps);
-	debugfs_create_file(heap->name, 0664, dev->debug_root, heap,
-			    &debug_heap_fops);
+	debug_file = debugfs_create_file(heap->name, 0664,
+					dev->heaps_debug_root, heap,
+					&debug_heap_fops);
+
+	if (!debug_file) {
+		char buf[256], *path;
+		path = dentry_path(dev->heaps_debug_root, buf, 256);
+		pr_err("Failed to created heap debugfs at %s/%s\n",
+			path, heap->name);
+	}
+
+#ifdef DEBUG_HEAP_SHRINKER
+	if (heap->shrinker.shrink) {
+		char debug_name[64];
+
+		snprintf(debug_name, 64, "%s_shrink", heap->name);
+		debug_file = debugfs_create_file(
+			debug_name, 0644, dev->heaps_debug_root, heap,
+			&debug_shrink_fops);
+		if (!debug_file) {
+			char buf[256], *path;
+			path = dentry_path(dev->heaps_debug_root, buf, 256);
+			pr_err("Failed to created heap shrinker debugfs at %s/%s\n",
+				path, debug_name);
+		}
+	}
+#endif
 	up_write(&dev->lock);
 }
 
@@ -1839,8 +1834,21 @@
 	}
 
 	idev->debug_root = debugfs_create_dir("ion", NULL);
-	if (IS_ERR_OR_NULL(idev->debug_root))
-		pr_err("ion: failed to create debug files.\n");
+	if (!idev->debug_root) {
+		pr_err("ion: failed to create debugfs root directory.\n");
+		goto debugfs_done;
+	}
+	idev->heaps_debug_root = debugfs_create_dir("heaps", idev->debug_root);
+	if (!idev->heaps_debug_root) {
+		pr_err("ion: failed to create debugfs heaps directory.\n");
+		goto debugfs_done;
+	}
+	idev->clients_debug_root = debugfs_create_dir("clients",
+						idev->debug_root);
+	if (!idev->clients_debug_root)
+		pr_err("ion: failed to create debugfs clients directory.\n");
+
+debugfs_done:
 
 	idev->custom_ioctl = custom_ioctl;
 	idev->buffers = RB_ROOT;
@@ -1854,6 +1862,7 @@
 void ion_device_destroy(struct ion_device *dev)
 {
 	misc_deregister(&dev->dev);
+	debugfs_remove_recursive(dev->debug_root);
 	/* XXX need to free the heaps and clients ? */
 	kfree(dev);
 }
diff --git a/drivers/gpu/ion/ion_carveout_heap.c b/drivers/gpu/ion/ion_carveout_heap.c
index 08921299..d25e928 100644
--- a/drivers/gpu/ion/ion_carveout_heap.c
+++ b/drivers/gpu/ion/ion_carveout_heap.c
@@ -162,7 +162,7 @@
 }
 
 static int ion_carveout_print_debug(struct ion_heap *heap, struct seq_file *s,
-				    const struct rb_root *mem_map)
+				    const struct list_head *mem_map)
 {
 	struct ion_carveout_heap *carveout_heap =
 		container_of(heap, struct ion_carveout_heap, heap);
@@ -176,16 +176,14 @@
 		unsigned long size = carveout_heap->total_size;
 		unsigned long end = base+size;
 		unsigned long last_end = base;
-		struct rb_node *n;
+		struct mem_map_data *data;
 
 		seq_printf(s, "\nMemory Map\n");
 		seq_printf(s, "%16.s %14.s %14.s %14.s\n",
 			   "client", "start address", "end address",
 			   "size (hex)");
 
-		for (n = rb_first(mem_map); n; n = rb_next(n)) {
-			struct mem_map_data *data =
-					rb_entry(n, struct mem_map_data, node);
+		list_for_each_entry(data, mem_map, node) {
 			const char *client_name = "(null)";
 
 			if (last_end < data->addr) {
diff --git a/drivers/gpu/ion/ion_cma_heap.c b/drivers/gpu/ion/ion_cma_heap.c
index b24b2bd..d4bbab7 100644
--- a/drivers/gpu/ion/ion_cma_heap.c
+++ b/drivers/gpu/ion/ion_cma_heap.c
@@ -180,19 +180,17 @@
 }
 
 static int ion_cma_print_debug(struct ion_heap *heap, struct seq_file *s,
-			const struct rb_root *mem_map)
+			const struct list_head *mem_map)
 {
 	if (mem_map) {
-		struct rb_node *n;
+		struct mem_map_data *data;
 
 		seq_printf(s, "\nMemory Map\n");
 		seq_printf(s, "%16.s %14.s %14.s %14.s\n",
 			   "client", "start address", "end address",
 			   "size (hex)");
 
-		for (n = rb_first(mem_map); n; n = rb_next(n)) {
-			struct mem_map_data *data =
-					rb_entry(n, struct mem_map_data, node);
+		list_for_each_entry(data, mem_map, node) {
 			const char *client_name = "(null)";
 
 
diff --git a/drivers/gpu/ion/ion_cma_secure_heap.c b/drivers/gpu/ion/ion_cma_secure_heap.c
index 90451ca..bdf48b3 100644
--- a/drivers/gpu/ion/ion_cma_secure_heap.c
+++ b/drivers/gpu/ion/ion_cma_secure_heap.c
@@ -234,19 +234,17 @@
 }
 
 static int ion_secure_cma_print_debug(struct ion_heap *heap, struct seq_file *s,
-			const struct rb_root *mem_map)
+			const struct list_head *mem_map)
 {
 	if (mem_map) {
-		struct rb_node *n;
+		struct mem_map_data *data;
 
 		seq_printf(s, "\nMemory Map\n");
 		seq_printf(s, "%16.s %14.s %14.s %14.s\n",
 			   "client", "start address", "end address",
 			   "size (hex)");
 
-		for (n = rb_first(mem_map); n; n = rb_next(n)) {
-			struct mem_map_data *data =
-					rb_entry(n, struct mem_map_data, node);
+		list_for_each_entry(data, mem_map, node) {
 			const char *client_name = "(null)";
 
 
diff --git a/drivers/gpu/ion/ion_cp_heap.c b/drivers/gpu/ion/ion_cp_heap.c
index f2f4fad..8cb90e5 100644
--- a/drivers/gpu/ion/ion_cp_heap.c
+++ b/drivers/gpu/ion/ion_cp_heap.c
@@ -622,7 +622,7 @@
 }
 
 static int ion_cp_print_debug(struct ion_heap *heap, struct seq_file *s,
-			      const struct rb_root *mem_map)
+			      const struct list_head *mem_map)
 {
 	unsigned long total_alloc;
 	unsigned long total_size;
@@ -651,16 +651,14 @@
 		unsigned long size = cp_heap->total_size;
 		unsigned long end = base+size;
 		unsigned long last_end = base;
-		struct rb_node *n;
+		struct mem_map_data *data;
 
 		seq_printf(s, "\nMemory Map\n");
 		seq_printf(s, "%16.s %14.s %14.s %14.s\n",
 			   "client", "start address", "end address",
 			   "size (hex)");
 
-		for (n = rb_first(mem_map); n; n = rb_next(n)) {
-			struct mem_map_data *data =
-					rb_entry(n, struct mem_map_data, node);
+		list_for_each_entry(data, mem_map, node) {
 			const char *client_name = "(null)";
 
 			if (last_end < data->addr) {
diff --git a/drivers/gpu/ion/ion_heap.c b/drivers/gpu/ion/ion_heap.c
index 3d37541..9d33bf4 100644
--- a/drivers/gpu/ion/ion_heap.c
+++ b/drivers/gpu/ion/ion_heap.c
@@ -16,10 +16,16 @@
  */
 
 #include <linux/err.h>
+#include <linux/freezer.h>
 #include <linux/ion.h>
+#include <linux/kthread.h>
 #include <linux/mm.h>
+#include <linux/rtmutex.h>
+#include <linux/sched.h>
 #include <linux/scatterlist.h>
 #include <linux/vmalloc.h>
+#include <linux/slab.h>
+#include <linux/highmem.h>
 #include "ion_priv.h"
 
 void *ion_heap_map_kernel(struct ion_heap *heap,
@@ -94,9 +100,155 @@
 	return 0;
 }
 
+#define MAX_VMAP_RETRIES 10
+
+/**
+ * An optimized page-zero'ing function. vmaps arrays of pages in large
+ * chunks to minimize the number of memsets and vmaps/vunmaps.
+ *
+ * Note that the `pages' array should be composed of all 4K pages.
+ */
+int ion_heap_pages_zero(struct page **pages, int num_pages,
+				bool should_invalidate)
+{
+	int i, j, k, npages_to_vmap;
+	void *ptr = NULL;
+	/*
+	 * It's cheaper just to use writecombine memory and skip the
+	 * cache vs. using a cache memory and trying to flush it afterwards
+	 */
+	pgprot_t pgprot = pgprot_writecombine(pgprot_kernel);
+
+	/*
+	 * As an optimization, we manually zero out all of the pages
+	 * in one fell swoop here. To safeguard against insufficient
+	 * vmalloc space, we only vmap `npages_to_vmap' at a time,
+	 * starting with a conservative estimate of 1/8 of the total
+	 * number of vmalloc pages available.
+	 */
+	npages_to_vmap = ((VMALLOC_END - VMALLOC_START)/8)
+			>> PAGE_SHIFT;
+	for (i = 0; i < num_pages; i += npages_to_vmap) {
+		npages_to_vmap = min(npages_to_vmap, num_pages - i);
+		for (j = 0; j < MAX_VMAP_RETRIES && npages_to_vmap;
+			++j) {
+			ptr = vmap(&pages[i], npages_to_vmap,
+					VM_IOREMAP, pgprot);
+			if (ptr)
+				break;
+			else
+				npages_to_vmap >>= 1;
+		}
+		if (!ptr)
+			return -ENOMEM;
+
+		memset(ptr, 0, npages_to_vmap * PAGE_SIZE);
+		if (should_invalidate) {
+			/*
+			 * invalidate the cache to pick up the zeroing
+			 */
+			for (k = 0; k < npages_to_vmap; k++) {
+				void *p = kmap_atomic(pages[i + k]);
+				phys_addr_t phys = page_to_phys(
+							pages[i + k]);
+
+				dmac_inv_range(p, p + PAGE_SIZE);
+				outer_inv_range(phys, phys + PAGE_SIZE);
+				kunmap_atomic(p);
+			}
+		}
+		vunmap(ptr);
+	}
+
+	return 0;
+}
+
+static int ion_heap_alloc_pages_mem(int page_tbl_size,
+				struct pages_mem *pages_mem)
+{
+	struct page **pages;
+	pages_mem->free_fn = kfree;
+	if (page_tbl_size > SZ_8K) {
+		/*
+		 * Do fallback to ensure we have a balance between
+		 * performance and availability.
+		 */
+		pages = kmalloc(page_tbl_size,
+				__GFP_COMP | __GFP_NORETRY |
+				__GFP_NO_KSWAPD | __GFP_NOWARN);
+		if (!pages) {
+			pages = vmalloc(page_tbl_size);
+			pages_mem->free_fn = vfree;
+		}
+	} else {
+		pages = kmalloc(page_tbl_size, GFP_KERNEL);
+	}
+
+	if (!pages)
+		return -ENOMEM;
+
+	pages_mem->pages = pages;
+	return 0;
+}
+
+static void ion_heap_free_pages_mem(struct pages_mem *pages_mem)
+{
+	pages_mem->free_fn(pages_mem->pages);
+}
+
+int ion_heap_high_order_page_zero(struct page *page,
+				int order, bool should_invalidate)
+{
+	int i, ret;
+	struct pages_mem pages_mem;
+	int npages = 1 << order;
+	int page_tbl_size = sizeof(struct page *) * npages;
+
+	if (ion_heap_alloc_pages_mem(page_tbl_size, &pages_mem))
+		return -ENOMEM;
+
+	for (i = 0; i < (1 << order); ++i)
+		pages_mem.pages[i] = page + i;
+
+	ret = ion_heap_pages_zero(pages_mem.pages, npages,
+				should_invalidate);
+	ion_heap_free_pages_mem(&pages_mem);
+	return ret;
+}
+
 int ion_heap_buffer_zero(struct ion_buffer *buffer)
 {
 	struct sg_table *table = buffer->sg_table;
+	struct scatterlist *sg;
+	int i, j, ret = 0, npages = 0, page_tbl_size = 0;
+	struct pages_mem pages_mem;
+
+	for_each_sg(table->sgl, sg, table->nents, i) {
+		unsigned long len = sg_dma_len(sg);
+		int nrpages = len >> PAGE_SHIFT;
+		page_tbl_size += sizeof(struct page *) * nrpages;
+	}
+
+	if (ion_heap_alloc_pages_mem(page_tbl_size, &pages_mem))
+		return -ENOMEM;
+
+	for_each_sg(table->sgl, sg, table->nents, i) {
+		struct page *page = sg_page(sg);
+		unsigned long len = sg_dma_len(sg);
+
+		for (j = 0; j < len / PAGE_SIZE; j++)
+			pages_mem.pages[npages++] = page + j;
+	}
+
+	ret = ion_heap_pages_zero(pages_mem.pages, npages,
+				ion_buffer_cached(buffer));
+	ion_heap_free_pages_mem(&pages_mem);
+	return ret;
+}
+
+int ion_heap_buffer_zero_old(struct ion_buffer *buffer)
+{
+	struct sg_table *table = buffer->sg_table;
 	pgprot_t pgprot;
 	struct scatterlist *sg;
 	struct vm_struct *vm_struct;
@@ -131,6 +283,122 @@
 	return ret;
 }
 
+void ion_heap_free_page(struct ion_buffer *buffer, struct page *page,
+		       unsigned int order)
+{
+	int i;
+
+	if (!ion_buffer_fault_user_mappings(buffer)) {
+		__free_pages(page, order);
+		return;
+	}
+	for (i = 0; i < (1 << order); i++)
+		__free_page(page + i);
+}
+
+void ion_heap_freelist_add(struct ion_heap *heap, struct ion_buffer * buffer)
+{
+	rt_mutex_lock(&heap->lock);
+	list_add(&buffer->list, &heap->free_list);
+	heap->free_list_size += buffer->size;
+	rt_mutex_unlock(&heap->lock);
+	wake_up(&heap->waitqueue);
+}
+
+size_t ion_heap_freelist_size(struct ion_heap *heap)
+{
+	size_t size;
+
+	rt_mutex_lock(&heap->lock);
+	size = heap->free_list_size;
+	rt_mutex_unlock(&heap->lock);
+
+	return size;
+}
+
+static size_t _ion_heap_freelist_drain(struct ion_heap *heap, size_t size,
+				bool skip_pools)
+{
+	struct ion_buffer *buffer, *tmp;
+	size_t total_drained = 0;
+
+	if (ion_heap_freelist_size(heap) == 0)
+		return 0;
+
+	rt_mutex_lock(&heap->lock);
+	if (size == 0)
+		size = heap->free_list_size;
+
+	list_for_each_entry_safe(buffer, tmp, &heap->free_list, list) {
+		if (total_drained >= size)
+			break;
+		list_del(&buffer->list);
+		ion_buffer_destroy(buffer);
+		heap->free_list_size -= buffer->size;
+		if (skip_pools)
+			buffer->flags |= ION_FLAG_FREED_FROM_SHRINKER;
+		total_drained += buffer->size;
+	}
+	rt_mutex_unlock(&heap->lock);
+
+	return total_drained;
+}
+
+size_t ion_heap_freelist_drain(struct ion_heap *heap, size_t size)
+{
+	return _ion_heap_freelist_drain(heap, size, false);
+}
+
+size_t ion_heap_freelist_drain_from_shrinker(struct ion_heap *heap, size_t size)
+{
+	return _ion_heap_freelist_drain(heap, size, true);
+}
+
+int ion_heap_deferred_free(void *data)
+{
+	struct ion_heap *heap = data;
+
+	while (true) {
+		struct ion_buffer *buffer;
+
+		wait_event_freezable(heap->waitqueue,
+				     ion_heap_freelist_size(heap) > 0);
+
+		rt_mutex_lock(&heap->lock);
+		if (list_empty(&heap->free_list)) {
+			rt_mutex_unlock(&heap->lock);
+			continue;
+		}
+		buffer = list_first_entry(&heap->free_list, struct ion_buffer,
+					  list);
+		list_del(&buffer->list);
+		heap->free_list_size -= buffer->size;
+		rt_mutex_unlock(&heap->lock);
+		ion_buffer_destroy(buffer);
+	}
+
+	return 0;
+}
+
+int ion_heap_init_deferred_free(struct ion_heap *heap)
+{
+	struct sched_param param = { .sched_priority = 0 };
+
+	INIT_LIST_HEAD(&heap->free_list);
+	heap->free_list_size = 0;
+	rt_mutex_init(&heap->lock);
+	init_waitqueue_head(&heap->waitqueue);
+	heap->task = kthread_run(ion_heap_deferred_free, heap,
+				 "%s", heap->name);
+	sched_setscheduler(heap->task, SCHED_IDLE, &param);
+	if (IS_ERR(heap->task)) {
+		pr_err("%s: creating thread for deferred free failed\n",
+		       __func__);
+		return PTR_RET(heap->task);
+	}
+	return 0;
+}
+
 struct ion_heap *ion_heap_create(struct ion_platform_heap *heap_data)
 {
 	struct ion_heap *heap = NULL;
diff --git a/drivers/gpu/ion/ion_iommu_heap.c b/drivers/gpu/ion/ion_iommu_heap.c
deleted file mode 100644
index d9e9e09..0000000
--- a/drivers/gpu/ion/ion_iommu_heap.c
+++ /dev/null
@@ -1,588 +0,0 @@
-/*
- * Copyright (c) 2011-2013, 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.
- */
-#include <linux/err.h>
-#include <linux/io.h>
-#include <linux/msm_ion.h>
-#include <linux/mm.h>
-#include <linux/highmem.h>
-#include <linux/scatterlist.h>
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-#include <linux/iommu.h>
-#include <linux/pfn.h>
-#include <linux/dma-mapping.h>
-#include "ion_priv.h"
-
-#include <asm/mach/map.h>
-#include <asm/page.h>
-#include <asm/cacheflush.h>
-#include <mach/iommu_domains.h>
-#include <trace/events/kmem.h>
-
-struct ion_iommu_heap {
-	struct ion_heap heap;
-	struct ion_page_pool **cached_pools;
-	struct ion_page_pool **uncached_pools;
-};
-
-/*
- * We will attempt to allocate high-order pages and store those in an
- * sg_list. However, some APIs expect an array of struct page * where
- * each page is of size PAGE_SIZE. We use this extra structure to
- * carry around an array of such pages (derived from the high-order
- * pages with nth_page).
- */
-struct ion_iommu_priv_data {
-	struct page **pages;
-	unsigned int pages_uses_vmalloc;
-	int nrpages;
-	unsigned long size;
-};
-
-#define MAX_VMAP_RETRIES 10
-#define BAD_ORDER	-1
-
-static const unsigned int orders[] = {9, 8, 4, 0};
-static const int num_orders = ARRAY_SIZE(orders);
-static unsigned int low_gfp_flags = __GFP_HIGHMEM | GFP_KERNEL | __GFP_ZERO;
-static unsigned int high_gfp_flags = (__GFP_HIGHMEM | __GFP_NORETRY
-				| __GFP_NO_KSWAPD | __GFP_NOWARN |
-				 __GFP_IO | __GFP_FS | __GFP_ZERO);
-
-struct page_info {
-	struct page *page;
-	unsigned int order;
-	struct list_head list;
-};
-
-static int order_to_index(unsigned int order)
-{
-	int i;
-	for (i = 0; i < num_orders; i++)
-		if (order == orders[i])
-			return i;
-	BUG();
-	return BAD_ORDER;
-}
-
-static unsigned int order_to_size(int order)
-{
-	return PAGE_SIZE << order;
-}
-
-static struct page_info *alloc_largest_available(struct ion_iommu_heap *heap,
-						unsigned long size,
-						unsigned int max_order,
-						unsigned long flags)
-{
-	struct page *page;
-	struct page_info *info;
-	int i;
-
-	for (i = 0; i < num_orders; i++) {
-		gfp_t gfp;
-		int idx = order_to_index(orders[i]);
-		struct ion_page_pool *pool;
-
-		if (idx == BAD_ORDER)
-			continue;
-
-		if (ION_IS_CACHED(flags)) {
-			pool = heap->cached_pools[idx];
-			BUG_ON(!pool);
-		} else {
-			pool = heap->uncached_pools[idx];
-			BUG_ON(!pool);
-		}
-
-		if (size < order_to_size(orders[i]))
-			continue;
-		if (max_order < orders[i])
-			continue;
-
-		if (orders[i]) {
-			gfp = high_gfp_flags;
-		} else {
-			gfp = low_gfp_flags;
-		}
-		trace_alloc_pages_iommu_start(gfp, orders[i]);
-		if (flags & ION_FLAG_POOL_FORCE_ALLOC)
-			page = alloc_pages(gfp, orders[i]);
-		else
-			page = ion_page_pool_alloc(pool);
-		trace_alloc_pages_iommu_end(gfp, orders[i]);
-		if (!page) {
-			trace_alloc_pages_iommu_fail(gfp, orders[i]);
-			continue;
-		}
-
-		info = kmalloc(sizeof(struct page_info), GFP_KERNEL);
-		if (info) {
-			info->page = page;
-			info->order = orders[i];
-		}
-		return info;
-	}
-	return NULL;
-}
-
-static int ion_iommu_buffer_zero(struct ion_iommu_priv_data *data,
-				bool is_cached)
-{
-	int i, j, k;
-	unsigned int npages_to_vmap;
-	unsigned int total_pages;
-	void *ptr = NULL;
-	/*
-	 * It's cheaper just to use writecombine memory and skip the
-	 * cache vs. using a cache memory and trying to flush it afterwards
-	 */
-	pgprot_t pgprot = pgprot_writecombine(pgprot_kernel);
-
-	/*
-	 * As an optimization, we manually zero out all of the
-	 * pages in one fell swoop here. To safeguard against
-	 * insufficient vmalloc space, we only vmap
-	 * `npages_to_vmap' at a time, starting with a
-	 * conservative estimate of 1/8 of the total number of
-	 * vmalloc pages available. Note that the `pages'
-	 * array is composed of all 4K pages, irrespective of
-	 * the size of the pages on the sg list.
-	 */
-	npages_to_vmap = ((VMALLOC_END - VMALLOC_START)/8)
-			>> PAGE_SHIFT;
-	total_pages = data->nrpages;
-	for (i = 0; i < total_pages; i += npages_to_vmap) {
-		npages_to_vmap = min(npages_to_vmap, total_pages - i);
-		for (j = 0; j < MAX_VMAP_RETRIES && npages_to_vmap;
-			++j) {
-			ptr = vmap(&data->pages[i], npages_to_vmap,
-					VM_IOREMAP, pgprot);
-			if (ptr)
-				break;
-			else
-				npages_to_vmap >>= 1;
-		}
-		if (!ptr)
-			return -ENOMEM;
-
-		memset(ptr, 0, npages_to_vmap * PAGE_SIZE);
-		if (is_cached) {
-			/*
-			 * invalidate the cache to pick up the zeroing
-			 */
-			for (k = 0; k < npages_to_vmap; k++) {
-				void *p = kmap_atomic(data->pages[i + k]);
-				phys_addr_t phys = page_to_phys(
-							data->pages[i + k]);
-
-				dmac_inv_range(p, p + PAGE_SIZE);
-				outer_inv_range(phys, phys + PAGE_SIZE);
-				kunmap_atomic(p);
-			}
-		}
-		vunmap(ptr);
-	}
-
-	return 0;
-}
-
-static int ion_iommu_heap_allocate(struct ion_heap *heap,
-				      struct ion_buffer *buffer,
-				      unsigned long size, unsigned long align,
-				      unsigned long flags)
-{
-	int ret, i;
-	struct list_head pages_list;
-	struct page_info *info, *tmp_info;
-	struct ion_iommu_priv_data *data = NULL;
-	struct ion_iommu_heap *iommu_heap =
-		container_of(heap, struct ion_iommu_heap, heap);
-
-	if (msm_use_iommu()) {
-		struct scatterlist *sg;
-		struct sg_table *table;
-		int j;
-		unsigned int num_large_pages = 0;
-		unsigned long size_remaining = PAGE_ALIGN(size);
-		unsigned int max_order = ION_IS_CACHED(flags) ? 0 : orders[0];
-		unsigned int page_tbl_size;
-
-		data = kmalloc(sizeof(*data), GFP_KERNEL);
-		if (!data)
-			return -ENOMEM;
-
-		INIT_LIST_HEAD(&pages_list);
-		while (size_remaining > 0) {
-			info = alloc_largest_available(iommu_heap,
-						size_remaining,
-						max_order,
-						flags);
-			if (!info) {
-				ret = -ENOMEM;
-				goto err_free_data;
-			}
-			list_add_tail(&info->list, &pages_list);
-			size_remaining -= order_to_size(info->order);
-			max_order = info->order;
-			num_large_pages++;
-		}
-
-		data->size = PFN_ALIGN(size);
-		data->nrpages = data->size >> PAGE_SHIFT;
-		data->pages_uses_vmalloc = 0;
-		page_tbl_size = sizeof(struct page *) * data->nrpages;
-
-		if (page_tbl_size > SZ_8K) {
-			/*
-			 * Do fallback to ensure we have a balance between
-			 * performance and availability.
-			 */
-			data->pages = kmalloc(page_tbl_size,
-					      __GFP_COMP | __GFP_NORETRY |
-					      __GFP_NO_KSWAPD | __GFP_NOWARN);
-			if (!data->pages) {
-				data->pages = vmalloc(page_tbl_size);
-				data->pages_uses_vmalloc = 1;
-			}
-		} else {
-			data->pages = kmalloc(page_tbl_size, GFP_KERNEL);
-		}
-		if (!data->pages) {
-			ret = -ENOMEM;
-			goto err_free_data;
-		}
-
-		table = buffer->sg_table =
-				kzalloc(sizeof(struct sg_table), GFP_KERNEL);
-
-		if (!table) {
-			ret = -ENOMEM;
-			goto err1;
-		}
-		ret = sg_alloc_table(table, num_large_pages, GFP_KERNEL);
-		if (ret)
-			goto err2;
-
-		i = 0;
-		sg = table->sgl;
-		list_for_each_entry_safe(info, tmp_info, &pages_list, list) {
-			struct page *page = info->page;
-			sg_set_page(sg, page, order_to_size(info->order), 0);
-			sg_dma_address(sg) = sg_phys(sg);
-			sg = sg_next(sg);
-			for (j = 0; j < (1 << info->order); ++j)
-				data->pages[i++] = nth_page(page, j);
-			list_del(&info->list);
-			kfree(info);
-		}
-
-
-		if (flags & ION_FLAG_POOL_FORCE_ALLOC) {
-			ret = ion_iommu_buffer_zero(data, ION_IS_CACHED(flags));
-			if (ret) {
-				pr_err("Couldn't vmap the pages for zeroing\n");
-				goto err3;
-			}
-
-
-			if (!ION_IS_CACHED(flags))
-				dma_sync_sg_for_device(NULL, table->sgl,
-						table->nents,
-						DMA_BIDIRECTIONAL);
-
-		}
-		buffer->priv_virt = data;
-		return 0;
-
-	} else {
-		return -ENOMEM;
-	}
-
-
-err3:
-	sg_free_table(buffer->sg_table);
-err2:
-	kfree(buffer->sg_table);
-	buffer->sg_table = 0;
-err1:
-	if (data->pages_uses_vmalloc)
-		vfree(data->pages);
-	else
-		kfree(data->pages);
-err_free_data:
-	kfree(data);
-
-	list_for_each_entry_safe(info, tmp_info, &pages_list, list) {
-		if (info->page)
-			__free_pages(info->page, info->order);
-		list_del(&info->list);
-		kfree(info);
-	}
-	return ret;
-}
-
-static void ion_iommu_heap_free(struct ion_buffer *buffer)
-{
-	int i;
-	struct scatterlist *sg;
-	struct sg_table *table = buffer->sg_table;
-	struct ion_iommu_priv_data *data = buffer->priv_virt;
-	bool cached = ion_buffer_cached(buffer);
-	struct ion_iommu_heap *iommu_heap =
-	     container_of(buffer->heap, struct	ion_iommu_heap, heap);
-
-	if (!table)
-		return;
-	if (!data)
-		return;
-
-	if (!(buffer->flags & ION_FLAG_POOL_FORCE_ALLOC))
-		ion_iommu_buffer_zero(data, ION_IS_CACHED(buffer->flags));
-
-	for_each_sg(table->sgl, sg, table->nents, i) {
-		int order = get_order(sg_dma_len(sg));
-		int idx = order_to_index(order);
-		struct ion_page_pool *pool;
-
-		if (idx == BAD_ORDER) {
-			WARN_ON(1);
-			continue;
-		}
-
-		if (cached)
-			pool = iommu_heap->cached_pools[idx];
-		else
-			pool = iommu_heap->uncached_pools[idx];
-
-		if (buffer->flags & ION_FLAG_POOL_FORCE_ALLOC)
-			__free_pages(sg_page(sg), order);
-		else
-			ion_page_pool_free(pool, sg_page(sg));
-	}
-
-	sg_free_table(table);
-	kfree(table);
-	table = 0;
-	if (data->pages_uses_vmalloc)
-		vfree(data->pages);
-	else
-		kfree(data->pages);
-	kfree(data);
-}
-
-void *ion_iommu_heap_map_kernel(struct ion_heap *heap,
-				struct ion_buffer *buffer)
-{
-	struct ion_iommu_priv_data *data = buffer->priv_virt;
-	pgprot_t page_prot = PAGE_KERNEL;
-
-	if (!data)
-		return NULL;
-
-	if (!ION_IS_CACHED(buffer->flags))
-		page_prot = pgprot_writecombine(page_prot);
-
-	buffer->vaddr = vmap(data->pages, data->nrpages, VM_IOREMAP, page_prot);
-
-	return buffer->vaddr;
-}
-
-void ion_iommu_heap_unmap_kernel(struct ion_heap *heap,
-				    struct ion_buffer *buffer)
-{
-	if (!buffer->vaddr)
-		return;
-
-	vunmap(buffer->vaddr);
-	buffer->vaddr = NULL;
-}
-
-int ion_iommu_heap_map_user(struct ion_heap *heap, struct ion_buffer *buffer,
-			       struct vm_area_struct *vma)
-{
-	struct sg_table *table = buffer->sg_table;
-	unsigned long addr = vma->vm_start;
-	unsigned long offset = vma->vm_pgoff * PAGE_SIZE;
-	struct scatterlist *sg;
-	int i;
-
-	if (!ION_IS_CACHED(buffer->flags))
-		vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
-
-	for_each_sg(table->sgl, sg, table->nents, i) {
-		struct page *page = sg_page(sg);
-		unsigned long remainder = vma->vm_end - addr;
-		unsigned long len = sg_dma_len(sg);
-
-		if (offset >= sg_dma_len(sg)) {
-			offset -= sg_dma_len(sg);
-			continue;
-		} else if (offset) {
-			page += offset / PAGE_SIZE;
-			len = sg_dma_len(sg) - offset;
-			offset = 0;
-		}
-		len = min(len, remainder);
-		remap_pfn_range(vma, addr, page_to_pfn(page), len,
-				vma->vm_page_prot);
-		addr += len;
-		if (addr >= vma->vm_end)
-			return 0;
-	}
-	return 0;
-}
-
-static struct sg_table *ion_iommu_heap_map_dma(struct ion_heap *heap,
-					      struct ion_buffer *buffer)
-{
-	return buffer->sg_table;
-}
-
-static void ion_iommu_heap_unmap_dma(struct ion_heap *heap,
-				 struct ion_buffer *buffer)
-{
-}
-
-static int ion_iommu_heap_debug_show(struct ion_heap *heap, struct seq_file *s,
-					void *unused)
-{
-
-	struct ion_iommu_heap *iommu_heap = container_of(heap,
-							struct ion_iommu_heap,
-							heap);
-	int i;
-	unsigned long total = 0;
-
-	seq_printf(s, "Cached Pools:\n");
-	for (i = 0; i < num_orders; i++) {
-		struct ion_page_pool *pool = iommu_heap->cached_pools[i];
-		seq_printf(s, "%d order %u highmem pages in pool = %lx total\n",
-			   pool->high_count, pool->order,
-			   (1 << pool->order) * PAGE_SIZE * pool->high_count);
-		seq_printf(s, "%d order %u lowmem pages in pool = %lx total\n",
-			   pool->low_count, pool->order,
-			   (1 << pool->order) * PAGE_SIZE * pool->low_count);
-
-		total += (1 << pool->order) * PAGE_SIZE *
-			  (pool->low_count + pool->high_count);
-	}
-
-	seq_printf(s, "Uncached Pools:\n");
-	for (i = 0; i < num_orders; i++) {
-		struct ion_page_pool *pool = iommu_heap->uncached_pools[i];
-		seq_printf(s, "%d order %u highmem pages in pool = %lx total\n",
-			   pool->high_count, pool->order,
-			   (1 << pool->order) * PAGE_SIZE * pool->high_count);
-		seq_printf(s, "%d order %u lowmem pages in pool = %lx total\n",
-			   pool->low_count, pool->order,
-			   (1 << pool->order) * PAGE_SIZE * pool->low_count);
-
-		total += (1 << pool->order) * PAGE_SIZE *
-			  (pool->low_count + pool->high_count);
-	}
-	seq_printf(s, "Total bytes in pool: %lx\n", total);
-	return 0;
-}
-
-static struct ion_heap_ops iommu_heap_ops = {
-	.allocate = ion_iommu_heap_allocate,
-	.free = ion_iommu_heap_free,
-	.map_user = ion_iommu_heap_map_user,
-	.map_kernel = ion_iommu_heap_map_kernel,
-	.unmap_kernel = ion_iommu_heap_unmap_kernel,
-	.map_dma = ion_iommu_heap_map_dma,
-	.unmap_dma = ion_iommu_heap_unmap_dma,
-};
-
-struct ion_heap *ion_iommu_heap_create(struct ion_platform_heap *heap_data)
-{
-	struct ion_iommu_heap *iommu_heap;
-	int i;
-
-	iommu_heap = kzalloc(sizeof(struct ion_iommu_heap), GFP_KERNEL);
-	if (!iommu_heap)
-		return ERR_PTR(-ENOMEM);
-
-	iommu_heap->heap.ops = &iommu_heap_ops;
-	iommu_heap->heap.type = ION_HEAP_TYPE_IOMMU;
-	iommu_heap->uncached_pools = kzalloc(
-			      sizeof(struct ion_page_pool *) * num_orders,
-			      GFP_KERNEL);
-	if (!iommu_heap->uncached_pools)
-		goto err_alloc_uncached_pools;
-
-	iommu_heap->cached_pools = kzalloc(
-			      sizeof(struct ion_page_pool *) * num_orders,
-			      GFP_KERNEL);
-
-	if (!iommu_heap->cached_pools)
-		goto err_alloc_cached_pools;
-
-	for (i = 0; i < num_orders; i++) {
-		struct ion_page_pool *pool;
-		gfp_t gfp_flags;
-
-		if (orders[i])
-			gfp_flags = high_gfp_flags | __GFP_ZERO;
-		else
-			gfp_flags = low_gfp_flags | __GFP_ZERO;
-		pool = ion_page_pool_create(gfp_flags, orders[i]);
-		if (!pool)
-			goto err_create_cached_pool;
-		iommu_heap->cached_pools[i] = pool;
-	}
-
-	for (i = 0; i < num_orders; i++) {
-		struct ion_page_pool *pool;
-		gfp_t gfp_flags;
-
-		if (orders[i])
-			gfp_flags = high_gfp_flags | __GFP_ZERO;
-		else
-			gfp_flags = low_gfp_flags | __GFP_ZERO;
-		pool = ion_page_pool_create(gfp_flags, orders[i]);
-		if (!pool)
-			goto err_create_uncached_pool;
-		iommu_heap->uncached_pools[i] = pool;
-	}
-	iommu_heap->heap.debug_show = ion_iommu_heap_debug_show;
-	return &iommu_heap->heap;
-
-err_create_uncached_pool:
-	for (i = 0; i < num_orders; i++)
-		if (iommu_heap->cached_pools[i])
-			ion_page_pool_destroy(iommu_heap->uncached_pools[i]);
-
-
-err_create_cached_pool:
-	for (i = 0; i < num_orders; i++)
-		if (iommu_heap->uncached_pools[i])
-			ion_page_pool_destroy(iommu_heap->cached_pools[i]);
-
-	kfree(iommu_heap->cached_pools);
-err_alloc_cached_pools:
-	kfree(iommu_heap->uncached_pools);
-err_alloc_uncached_pools:
-	kfree(iommu_heap);
-	return ERR_PTR(-ENOMEM);
-}
-
-void ion_iommu_heap_destroy(struct ion_heap *heap)
-{
-	struct ion_iommu_heap *iommu_heap =
-	     container_of(heap, struct  ion_iommu_heap, heap);
-
-	kfree(iommu_heap);
-	iommu_heap = NULL;
-}
diff --git a/drivers/gpu/ion/ion_page_pool.c b/drivers/gpu/ion/ion_page_pool.c
index 495dd24..94f9445 100644
--- a/drivers/gpu/ion/ion_page_pool.c
+++ b/drivers/gpu/ion/ion_page_pool.c
@@ -21,14 +21,9 @@
 #include <linux/list.h>
 #include <linux/module.h>
 #include <linux/slab.h>
-#include <linux/shrinker.h>
+#include <linux/vmalloc.h>
 #include "ion_priv.h"
 
-/* #define DEBUG_PAGE_POOL_SHRINKER */
-
-static struct plist_head pools = PLIST_HEAD_INIT(pools);
-static struct shrinker shrinker;
-
 struct ion_page_pool_item {
 	struct page *page;
 	struct list_head list;
@@ -36,18 +31,28 @@
 
 static void *ion_page_pool_alloc_pages(struct ion_page_pool *pool)
 {
-	struct page *page = alloc_pages(pool->gfp_mask, pool->order);
+	struct page *page;
 	struct scatterlist sg;
 
+	page = alloc_pages(pool->gfp_mask & ~__GFP_ZERO, pool->order);
+
 	if (!page)
 		return NULL;
 
+	if (pool->gfp_mask & __GFP_ZERO)
+		if (ion_heap_high_order_page_zero(
+				page, pool->order, pool->should_invalidate))
+			goto error_free_pages;
+
 	sg_init_table(&sg, 1);
 	sg_set_page(&sg, page, PAGE_SIZE << pool->order, 0);
 	sg_dma_address(&sg) = sg_phys(&sg);
 	dma_sync_sg_for_device(NULL, &sg, 1, DMA_BIDIRECTIONAL);
 
 	return page;
+error_free_pages:
+	__free_pages(page, pool->order);
+	return NULL;
 }
 
 static void ion_page_pool_free_pages(struct ion_page_pool *pool,
@@ -128,113 +133,50 @@
 		ion_page_pool_free_pages(pool, page);
 }
 
-#ifdef DEBUG_PAGE_POOL_SHRINKER
-static int debug_drop_pools_set(void *data, u64 val)
+static int ion_page_pool_total(struct ion_page_pool *pool, bool high)
 {
-	struct shrink_control sc;
-	int objs;
-
-	sc.gfp_mask = -1;
-	sc.nr_to_scan = 0;
-
-	if (!val)
-		return 0;
-
-	objs = shrinker.shrink(&shrinker, &sc);
-	sc.nr_to_scan = objs;
-
-	shrinker.shrink(&shrinker, &sc);
-	return 0;
-}
-
-static int debug_drop_pools_get(void *data, u64 *val)
-{
-	struct shrink_control sc;
-	int objs;
-
-	sc.gfp_mask = -1;
-	sc.nr_to_scan = 0;
-
-	objs = shrinker.shrink(&shrinker, &sc);
-	*val = objs;
-	return 0;
-}
-
-DEFINE_SIMPLE_ATTRIBUTE(debug_drop_pools_fops, debug_drop_pools_get,
-                        debug_drop_pools_set, "%llu\n");
-
-static int debug_grow_pools_set(void *data, u64 val)
-{
-	struct ion_page_pool *pool;
-	struct page *page;
-
-	plist_for_each_entry(pool, &pools, list) {
-		if (val != pool->list.prio)
-			continue;
-		page = ion_page_pool_alloc_pages(pool);
-		if (page)
-			ion_page_pool_add(pool, page);
-	}
-
-	return 0;
-}
-
-DEFINE_SIMPLE_ATTRIBUTE(debug_grow_pools_fops, debug_drop_pools_get,
-			debug_grow_pools_set, "%llu\n");
-#endif
-
-static int ion_page_pool_total(bool high)
-{
-	struct ion_page_pool *pool;
 	int total = 0;
 
-	plist_for_each_entry(pool, &pools, list) {
-		total += high ? (pool->high_count + pool->low_count) *
-			(1 << pool->order) :
+	total += high ? (pool->high_count + pool->low_count) *
+		(1 << pool->order) :
 			pool->low_count * (1 << pool->order);
-	}
 	return total;
 }
 
-static int ion_page_pool_shrink(struct shrinker *shrinker,
-				 struct shrink_control *sc)
+int ion_page_pool_shrink(struct ion_page_pool *pool, gfp_t gfp_mask,
+				int nr_to_scan)
 {
-	struct ion_page_pool *pool;
 	int nr_freed = 0;
 	int i;
 	bool high;
-	int nr_to_scan = sc->nr_to_scan;
 
-	if (sc->gfp_mask & __GFP_HIGHMEM)
-		high = true;
+	high = gfp_mask & __GFP_HIGHMEM;
 
 	if (nr_to_scan == 0)
-		return ion_page_pool_total(high);
+		return ion_page_pool_total(pool, high);
 
-	plist_for_each_entry(pool, &pools, list) {
-		for (i = 0; i < nr_to_scan; i++) {
-			struct page *page;
+	for (i = 0; i < nr_to_scan; i++) {
+		struct page *page;
 
-			mutex_lock(&pool->mutex);
-			if (high && pool->high_count) {
-				page = ion_page_pool_remove(pool, true);
-			} else if (pool->low_count) {
-				page = ion_page_pool_remove(pool, false);
-			} else {
-				mutex_unlock(&pool->mutex);
-				break;
-			}
+		mutex_lock(&pool->mutex);
+		if (high && pool->high_count) {
+			page = ion_page_pool_remove(pool, true);
+		} else if (pool->low_count) {
+			page = ion_page_pool_remove(pool, false);
+		} else {
 			mutex_unlock(&pool->mutex);
-			ion_page_pool_free_pages(pool, page);
-			nr_freed += (1 << pool->order);
+			break;
 		}
-		nr_to_scan -= i;
+		mutex_unlock(&pool->mutex);
+		ion_page_pool_free_pages(pool, page);
+		nr_freed += (1 << pool->order);
 	}
 
-	return ion_page_pool_total(high);
+	return nr_freed;
 }
 
-struct ion_page_pool *ion_page_pool_create(gfp_t gfp_mask, unsigned int order)
+struct ion_page_pool *ion_page_pool_create(gfp_t gfp_mask, unsigned int order,
+	bool should_invalidate)
 {
 	struct ion_page_pool *pool = kmalloc(sizeof(struct ion_page_pool),
 					     GFP_KERNEL);
@@ -246,37 +188,25 @@
 	INIT_LIST_HEAD(&pool->high_items);
 	pool->gfp_mask = gfp_mask;
 	pool->order = order;
+	pool->should_invalidate = should_invalidate;
 	mutex_init(&pool->mutex);
 	plist_node_init(&pool->list, order);
-	plist_add(&pool->list, &pools);
 
 	return pool;
 }
 
 void ion_page_pool_destroy(struct ion_page_pool *pool)
 {
-	plist_del(&pool->list, &pools);
 	kfree(pool);
 }
 
 static int __init ion_page_pool_init(void)
 {
-	shrinker.shrink = ion_page_pool_shrink;
-	shrinker.seeks = DEFAULT_SEEKS;
-	shrinker.batch = 0;
-	register_shrinker(&shrinker);
-#ifdef DEBUG_PAGE_POOL_SHRINKER
-	debugfs_create_file("ion_pools_shrink", 0644, NULL, NULL,
-			    &debug_drop_pools_fops);
-	debugfs_create_file("ion_pools_grow", 0644, NULL, NULL,
-			    &debug_grow_pools_fops);
-#endif
 	return 0;
 }
 
 static void __exit ion_page_pool_exit(void)
 {
-	unregister_shrinker(&shrinker);
 }
 
 module_init(ion_page_pool_init);
diff --git a/drivers/gpu/ion/ion_priv.h b/drivers/gpu/ion/ion_priv.h
index e3fbbda..2b00ee6 100644
--- a/drivers/gpu/ion/ion_priv.h
+++ b/drivers/gpu/ion/ion_priv.h
@@ -85,11 +85,16 @@
 	char task_comm[TASK_COMM_LEN];
 	pid_t pid;
 };
+void ion_buffer_destroy(struct ion_buffer *buffer);
 
 /**
  * struct ion_heap_ops - ops to operate on a given heap
  * @allocate:		allocate memory
- * @free:		free memory
+ * @free:		free memory. Will be called with
+ *			ION_FLAG_FREED_FROM_SHRINKER set in buffer flags when
+ *			called from a shrinker. In that case, the pages being
+ *			free'd must be truly free'd back to the system, not put
+ *			in a page pool or otherwise cached.
  * @phys		get physical address of a buffer (only define on
  *			physically contiguous heaps)
  * @map_dma		map the memory for dma to a scatterlist
@@ -115,7 +120,7 @@
 			 struct vm_area_struct *vma);
 	void (*unmap_user) (struct ion_heap *mapper, struct ion_buffer *buffer);
 	int (*print_debug)(struct ion_heap *heap, struct seq_file *s,
-			   const struct rb_root *mem_map);
+			   const struct list_head *mem_map);
 	int (*secure_heap)(struct ion_heap *heap, int version, void *data);
 	int (*unsecure_heap)(struct ion_heap *heap, int version, void *data);
 	int (*secure_buffer)(struct ion_buffer *buffer, int version,
@@ -139,8 +144,13 @@
  *			allocating.  These are specified by platform data and
  *			MUST be unique
  * @name:		used for debugging
+ * @shrinker:		a shrinker for the heap, if the heap caches system
+ *			memory, it must define a shrinker to return it on low
+ *			memory conditions, this includes system memory cached
+ *			in the deferred free lists for heaps that support it
  * @priv:		private heap data
  * @free_list:		free list head if deferred free is used
+ * @free_list_size	size of the deferred free list in bytes
  * @lock:		protects the free list
  * @waitqueue:		queue to wait on from deferred free thread
  * @task:		task struct of deferred free thread
@@ -160,8 +170,10 @@
 	unsigned long flags;
 	unsigned int id;
 	const char *name;
+	struct shrinker shrinker;
 	void *priv;
 	struct list_head free_list;
+	size_t free_list_size;
 	struct rt_mutex lock;
 	wait_queue_head_t waitqueue;
 	struct task_struct *task;
@@ -209,6 +221,11 @@
  */
 void ion_device_add_heap(struct ion_device *dev, struct ion_heap *heap);
 
+struct pages_mem {
+	struct page **pages;
+	void (*free_fn) (const void *);
+};
+
 /**
  * some helpers for common operations on buffers using the sg_table
  * and vaddr fields
@@ -217,7 +234,71 @@
 void ion_heap_unmap_kernel(struct ion_heap *, struct ion_buffer *);
 int ion_heap_map_user(struct ion_heap *, struct ion_buffer *,
 			struct vm_area_struct *);
+int ion_heap_pages_zero(struct page **pages, int num_pages,
+			bool should_invalidate);
 int ion_heap_buffer_zero(struct ion_buffer *buffer);
+int ion_heap_high_order_page_zero(struct page *page,
+				int order, bool should_invalidate);
+
+/**
+ * ion_heap_init_deferred_free -- initialize deferred free functionality
+ * @heap:		the heap
+ *
+ * If a heap sets the ION_HEAP_FLAG_DEFER_FREE flag this function will
+ * be called to setup deferred frees. Calls to free the buffer will
+ * return immediately and the actual free will occur some time later
+ */
+int ion_heap_init_deferred_free(struct ion_heap *heap);
+
+/**
+ * ion_heap_freelist_add - add a buffer to the deferred free list
+ * @heap:		the heap
+ * @buffer: 		the buffer
+ *
+ * Adds an item to the deferred freelist.
+ */
+void ion_heap_freelist_add(struct ion_heap *heap, struct ion_buffer *buffer);
+
+/**
+ * ion_heap_freelist_drain - drain the deferred free list
+ * @heap:		the heap
+ * @size:		ammount of memory to drain in bytes
+ *
+ * Drains the indicated amount of memory from the deferred freelist immediately.
+ * Returns the total amount freed.  The total freed may be higher depending
+ * on the size of the items in the list, or lower if there is insufficient
+ * total memory on the freelist.
+ */
+size_t ion_heap_freelist_drain(struct ion_heap *heap, size_t size);
+
+/**
+ * ion_heap_freelist_drain_from_shrinker - drain the deferred free
+ *				list, skipping any heap-specific
+ *				pooling or caching mechanisms
+ *
+ * @heap:		the heap
+ * @size:		amount of memory to drain in bytes
+ *
+ * Drains the indicated amount of memory from the deferred freelist immediately.
+ * Returns the total amount freed.  The total freed may be higher depending
+ * on the size of the items in the list, or lower if there is insufficient
+ * total memory on the freelist.
+ *
+ * Unlike with @ion_heap_freelist_drain, don't put any pages back into
+ * page pools or otherwise cache the pages. Everything must be
+ * genuinely free'd back to the system. If you're free'ing from a
+ * shrinker you probably want to use this. Note that this relies on
+ * the heap.ops.free callback honoring the
+ * ION_FLAG_FREED_FROM_SHRINKER flag.
+ */
+size_t ion_heap_freelist_drain_from_shrinker(struct ion_heap *heap,
+					size_t size);
+
+/**
+ * ion_heap_freelist_size - returns the size of the freelist in bytes
+ * @heap:		the heap
+ */
+size_t ion_heap_freelist_size(struct ion_heap *heap);
 
 
 /**
@@ -276,6 +357,8 @@
  * @gfp_mask:		gfp_mask to use from alloc
  * @order:		order of pages in the pool
  * @list:		plist node for list of pools
+ * @should_invalidate:	whether or not the cache needs to be invalidated at
+ *			page allocation time.
  *
  * Allows you to keep a pool of pre allocated pages to use from your heap.
  * Keeping a pool of pages that is ready for dma, ie any cached mapping have
@@ -288,16 +371,26 @@
 	struct list_head high_items;
 	struct list_head low_items;
 	struct mutex mutex;
-	void *(*alloc)(struct ion_page_pool *pool);
-	void (*free)(struct ion_page_pool *pool, struct page *page);
 	gfp_t gfp_mask;
 	unsigned int order;
 	struct plist_node list;
+	bool should_invalidate;
 };
 
-struct ion_page_pool *ion_page_pool_create(gfp_t gfp_mask, unsigned int order);
+struct ion_page_pool *ion_page_pool_create(gfp_t gfp_mask, unsigned int order,
+	bool should_invalidate);
 void ion_page_pool_destroy(struct ion_page_pool *);
 void *ion_page_pool_alloc(struct ion_page_pool *);
 void ion_page_pool_free(struct ion_page_pool *, struct page *);
 
+/** ion_page_pool_shrink - shrinks the size of the memory cached in the pool
+ * @pool:		the pool
+ * @gfp_mask:		the memory type to reclaim
+ * @nr_to_scan:		number of items to shrink in pages
+ *
+ * returns the number of items freed in pages
+ */
+int ion_page_pool_shrink(struct ion_page_pool *pool, gfp_t gfp_mask,
+			  int nr_to_scan);
+
 #endif /* _ION_PRIV_H */
diff --git a/drivers/gpu/ion/ion_removed_heap.c b/drivers/gpu/ion/ion_removed_heap.c
index 84d8d37..94d4a25 100644
--- a/drivers/gpu/ion/ion_removed_heap.c
+++ b/drivers/gpu/ion/ion_removed_heap.c
@@ -233,7 +233,7 @@
 }
 
 static int ion_removed_print_debug(struct ion_heap *heap, struct seq_file *s,
-				    const struct rb_root *mem_map)
+				    const struct list_head *mem_map)
 {
 	struct ion_removed_heap *removed_heap =
 		container_of(heap, struct ion_removed_heap, heap);
@@ -247,16 +247,14 @@
 		unsigned long size = removed_heap->total_size;
 		unsigned long end = base+size;
 		unsigned long last_end = base;
-		struct rb_node *n;
+		struct mem_map_data *data;
 
 		seq_printf(s, "\nMemory Map\n");
 		seq_printf(s, "%16.s %14.s %14.s %14.s\n",
 			   "client", "start address", "end address",
 			   "size (hex)");
 
-		for (n = rb_first(mem_map); n; n = rb_next(n)) {
-			struct mem_map_data *data =
-					rb_entry(n, struct mem_map_data, node);
+		list_for_each_entry(data, mem_map, node) {
 			const char *client_name = "(null)";
 
 			if (last_end < data->addr) {
diff --git a/drivers/gpu/ion/ion_system_heap.c b/drivers/gpu/ion/ion_system_heap.c
index 44bb86f..8e885b2 100644
--- a/drivers/gpu/ion/ion_system_heap.c
+++ b/drivers/gpu/ion/ion_system_heap.c
@@ -53,7 +53,8 @@
 
 struct ion_system_heap {
 	struct ion_heap heap;
-	struct ion_page_pool **pools;
+	struct ion_page_pool **uncached_pools;
+	struct ion_page_pool **cached_pools;
 };
 
 struct page_info {
@@ -68,29 +69,14 @@
 {
 	bool cached = ion_buffer_cached(buffer);
 	bool split_pages = ion_buffer_fault_user_mappings(buffer);
-	struct ion_page_pool *pool = heap->pools[order_to_index(order)];
 	struct page *page;
+	struct ion_page_pool *pool;
 
-	if (!cached) {
-		page = ion_page_pool_alloc(pool);
-	} else {
-		struct scatterlist sg;
-		gfp_t gfp_flags = low_order_gfp_flags;
-
-		if (order > 4)
-			gfp_flags = high_order_gfp_flags;
-		trace_alloc_pages_sys_start(gfp_flags, order);
-		page = alloc_pages(gfp_flags, order);
-		trace_alloc_pages_sys_end(gfp_flags, order);
-		if (!page) {
-			trace_alloc_pages_sys_fail(gfp_flags, order);
-			return 0;
-		}
-		sg_init_table(&sg, 1);
-		sg_set_page(&sg, page, PAGE_SIZE << order, 0);
-		sg_dma_address(&sg) = sg_phys(&sg);
-		dma_sync_sg_for_device(NULL, &sg, 1, DMA_BIDIRECTIONAL);
-	}
+	if (!cached)
+		pool = heap->uncached_pools[order_to_index(order)];
+	else
+		pool = heap->cached_pools[order_to_index(order)];
+	page = ion_page_pool_alloc(pool);
 	if (!page)
 		return 0;
 
@@ -107,14 +93,20 @@
 	bool split_pages = ion_buffer_fault_user_mappings(buffer);
 	int i;
 
-	if (!cached) {
-		struct ion_page_pool *pool = heap->pools[order_to_index(order)];
+	if ((buffer->flags & ION_FLAG_FREED_FROM_SHRINKER)) {
+		if (split_pages) {
+			for (i = 0; i < (1 << order); i++)
+				__free_page(page + i);
+		} else {
+			__free_pages(page, order);
+		}
+	} else  {
+		struct ion_page_pool *pool;
+		if (cached)
+			pool = heap->cached_pools[order_to_index(order)];
+		else
+			pool = heap->uncached_pools[order_to_index(order)];
 		ion_page_pool_free(pool, page);
-	} else if (split_pages) {
-		for (i = 0; i < (1 << order); i++)
-			__free_page(page + i);
-	} else {
-		__free_pages(page, order);
 	}
 }
 
@@ -212,7 +204,7 @@
 err1:
 	kfree(table);
 err:
-	list_for_each_entry(info, &pages, list) {
+	list_for_each_entry_safe(info, tmp_info, &pages, list) {
 		free_buffer_page(sys_heap, buffer, info->page, info->order);
 		kfree(info);
 	}
@@ -226,14 +218,11 @@
 							struct ion_system_heap,
 							heap);
 	struct sg_table *table = buffer->sg_table;
-	bool cached = ion_buffer_cached(buffer);
 	struct scatterlist *sg;
 	LIST_HEAD(pages);
 	int i;
 
-	/* uncached pages come from the page pools, zero them before returning
-	   for security purposes (other allocations are zerod at alloc time */
-	if (!cached)
+	if (!(buffer->flags & ION_FLAG_FREED_FROM_SHRINKER))
 		ion_heap_buffer_zero(buffer);
 
 	for_each_sg(table->sgl, sg, table->nents, i)
@@ -265,6 +254,56 @@
 	.map_user = ion_heap_map_user,
 };
 
+static int ion_system_heap_shrink(struct shrinker *shrinker,
+				  struct shrink_control *sc) {
+
+	struct ion_heap *heap = container_of(shrinker, struct ion_heap,
+					     shrinker);
+	struct ion_system_heap *sys_heap = container_of(heap,
+							struct ion_system_heap,
+							heap);
+	int nr_total = 0;
+	int nr_freed = 0;
+	int i;
+
+	if (sc->nr_to_scan == 0)
+		goto end;
+
+	/* shrink the free list first, no point in zeroing the memory if
+	   we're just going to reclaim it. Also, skip any possible
+	   page pooling */
+	nr_freed += ion_heap_freelist_drain_from_shrinker(
+		heap, sc->nr_to_scan * PAGE_SIZE) / PAGE_SIZE;
+
+	if (nr_freed >= sc->nr_to_scan)
+		goto end;
+
+	for (i = 0; i < num_orders; i++) {
+		nr_freed += ion_page_pool_shrink(sys_heap->uncached_pools[i],
+						sc->gfp_mask, sc->nr_to_scan);
+		if (nr_freed >= sc->nr_to_scan)
+			goto end;
+
+		nr_freed += ion_page_pool_shrink(sys_heap->cached_pools[i],
+						sc->gfp_mask, sc->nr_to_scan);
+		if (nr_freed >= sc->nr_to_scan)
+			goto end;
+	}
+
+end:
+	/* total number of items is whatever the page pools are holding
+	   plus whatever's in the freelist */
+	for (i = 0; i < num_orders; i++) {
+		nr_total += ion_page_pool_shrink(
+			sys_heap->uncached_pools[i], sc->gfp_mask, 0);
+		nr_total += ion_page_pool_shrink(
+			sys_heap->cached_pools[i], sc->gfp_mask, 0);
+	}
+	nr_total += ion_heap_freelist_size(heap) / PAGE_SIZE;
+	return nr_total;
+
+}
+
 static int ion_system_heap_debug_show(struct ion_heap *heap, struct seq_file *s,
 				      void *unused)
 {
@@ -274,21 +313,74 @@
 							heap);
 	int i;
 	for (i = 0; i < num_orders; i++) {
-		struct ion_page_pool *pool = sys_heap->pools[i];
-		seq_printf(s, "%d order %u highmem pages in pool = %lu total\n",
-			   pool->high_count, pool->order,
-			   (1 << pool->order) * PAGE_SIZE * pool->high_count);
-		seq_printf(s, "%d order %u lowmem pages in pool = %lu total\n",
-			   pool->low_count, pool->order,
-			   (1 << pool->order) * PAGE_SIZE * pool->low_count);
+		struct ion_page_pool *pool = sys_heap->uncached_pools[i];
+		seq_printf(s,
+			"%d order %u highmem pages in uncached pool = %lu total\n",
+			pool->high_count, pool->order,
+			(1 << pool->order) * PAGE_SIZE * pool->high_count);
+		seq_printf(s,
+			"%d order %u lowmem pages in uncached pool = %lu total\n",
+			pool->low_count, pool->order,
+			(1 << pool->order) * PAGE_SIZE * pool->low_count);
+	}
+
+	for (i = 0; i < num_orders; i++) {
+		struct ion_page_pool *pool = sys_heap->cached_pools[i];
+		seq_printf(s,
+			"%d order %u highmem pages in cached pool = %lu total\n",
+			pool->high_count, pool->order,
+			(1 << pool->order) * PAGE_SIZE * pool->high_count);
+		seq_printf(s,
+			"%d order %u lowmem pages in cached pool = %lu total\n",
+			pool->low_count, pool->order,
+			(1 << pool->order) * PAGE_SIZE * pool->low_count);
+	}
+
+	return 0;
+}
+
+
+static void ion_system_heap_destroy_pools(struct ion_page_pool **pools)
+{
+	int i;
+	for (i = 0; i < num_orders; i++)
+		if (pools[i])
+			ion_page_pool_destroy(pools[i]);
+}
+
+/**
+ * ion_system_heap_create_pools - Creates pools for all orders
+ *
+ * If this fails you don't need to destroy any pools. It's all or
+ * nothing. If it succeeds you'll eventually need to use
+ * ion_system_heap_destroy_pools to destroy the pools.
+ */
+static int ion_system_heap_create_pools(struct ion_page_pool **pools,
+					bool should_invalidate)
+{
+	int i;
+	for (i = 0; i < num_orders; i++) {
+		struct ion_page_pool *pool;
+		gfp_t gfp_flags = low_order_gfp_flags;
+
+		if (orders[i] > 4)
+			gfp_flags = high_order_gfp_flags;
+		pool = ion_page_pool_create(gfp_flags, orders[i],
+					should_invalidate);
+		if (!pool)
+			goto err_create_pool;
+		pools[i] = pool;
 	}
 	return 0;
+err_create_pool:
+	ion_system_heap_destroy_pools(pools);
+	return 1;
 }
 
 struct ion_heap *ion_system_heap_create(struct ion_platform_heap *unused)
 {
 	struct ion_system_heap *heap;
-	int i;
+	int pools_size = sizeof(struct ion_page_pool *) * num_orders;
 
 	heap = kzalloc(sizeof(struct ion_system_heap), GFP_KERNEL);
 	if (!heap)
@@ -296,29 +388,35 @@
 	heap->heap.ops = &system_heap_ops;
 	heap->heap.type = ION_HEAP_TYPE_SYSTEM;
 	heap->heap.flags = ION_HEAP_FLAG_DEFER_FREE;
-	heap->pools = kzalloc(sizeof(struct ion_page_pool *) * num_orders,
-			      GFP_KERNEL);
-	if (!heap->pools)
-		goto err_alloc_pools;
-	for (i = 0; i < num_orders; i++) {
-		struct ion_page_pool *pool;
-		gfp_t gfp_flags = low_order_gfp_flags;
 
-		if (orders[i] > 4)
-			gfp_flags = high_order_gfp_flags;
-		pool = ion_page_pool_create(gfp_flags, orders[i]);
-		if (!pool)
-			goto err_create_pool;
-		heap->pools[i] = pool;
-	}
+	heap->uncached_pools = kzalloc(pools_size, GFP_KERNEL);
+	if (!heap->uncached_pools)
+		goto err_alloc_uncached_pools;
+
+	heap->cached_pools = kzalloc(pools_size, GFP_KERNEL);
+	if (!heap->cached_pools)
+		goto err_alloc_cached_pools;
+
+	if (ion_system_heap_create_pools(heap->uncached_pools, false))
+		goto err_create_uncached_pools;
+
+	if (ion_system_heap_create_pools(heap->cached_pools, true))
+		goto err_create_cached_pools;
+
+	heap->heap.shrinker.shrink = ion_system_heap_shrink;
+	heap->heap.shrinker.seeks = DEFAULT_SEEKS;
+	heap->heap.shrinker.batch = 0;
+	register_shrinker(&heap->heap.shrinker);
 	heap->heap.debug_show = ion_system_heap_debug_show;
 	return &heap->heap;
-err_create_pool:
-	for (i = 0; i < num_orders; i++)
-		if (heap->pools[i])
-			ion_page_pool_destroy(heap->pools[i]);
-	kfree(heap->pools);
-err_alloc_pools:
+
+err_create_cached_pools:
+	ion_system_heap_destroy_pools(heap->uncached_pools);
+err_create_uncached_pools:
+	kfree(heap->cached_pools);
+err_alloc_cached_pools:
+	kfree(heap->uncached_pools);
+err_alloc_uncached_pools:
 	kfree(heap);
 	return ERR_PTR(-ENOMEM);
 }
@@ -328,36 +426,82 @@
 	struct ion_system_heap *sys_heap = container_of(heap,
 							struct ion_system_heap,
 							heap);
-	int i;
 
-	for (i = 0; i < num_orders; i++)
-		ion_page_pool_destroy(sys_heap->pools[i]);
-	kfree(sys_heap->pools);
+	ion_system_heap_destroy_pools(sys_heap->uncached_pools);
+	ion_system_heap_destroy_pools(sys_heap->cached_pools);
+	kfree(sys_heap->uncached_pools);
+	kfree(sys_heap->cached_pools);
 	kfree(sys_heap);
 }
 
+struct kmalloc_buffer_info {
+	struct sg_table *table;
+	void *vaddr;
+};
+
 static int ion_system_contig_heap_allocate(struct ion_heap *heap,
 					   struct ion_buffer *buffer,
 					   unsigned long len,
 					   unsigned long align,
 					   unsigned long flags)
 {
-	buffer->priv_virt = kzalloc(len, GFP_KERNEL);
-	if (!buffer->priv_virt)
-		return -ENOMEM;
+	int ret;
+	struct kmalloc_buffer_info *info;
+
+	info = kmalloc(sizeof(struct kmalloc_buffer_info), GFP_KERNEL);
+	if (!info) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	info->table = kzalloc(sizeof(struct sg_table), GFP_KERNEL);
+	if (!info->table) {
+		ret = -ENOMEM;
+		goto kfree_info;
+	}
+
+	ret = sg_alloc_table(info->table, 1, GFP_KERNEL);
+	if (ret)
+		goto kfree_table;
+
+	info->vaddr = kzalloc(len, GFP_KERNEL);
+	if (!info->vaddr) {
+		ret = -ENOMEM;
+		goto sg_free_table;
+	}
+
+	sg_set_page(info->table->sgl, virt_to_page(info->vaddr), len,
+		    0);
+	sg_dma_address(info->table->sgl) = virt_to_phys(info->vaddr);
+	dma_sync_sg_for_device(NULL, info->table->sgl, 1, DMA_BIDIRECTIONAL);
+
+	buffer->priv_virt = info;
 	return 0;
+
+sg_free_table:
+	sg_free_table(info->table);
+kfree_table:
+	kfree(info->table);
+kfree_info:
+	kfree(info);
+out:
+	return ret;
 }
 
 void ion_system_contig_heap_free(struct ion_buffer *buffer)
 {
-	kfree(buffer->priv_virt);
+	struct kmalloc_buffer_info *info = buffer->priv_virt;
+	sg_free_table(info->table);
+	kfree(info->table);
+	kfree(info->vaddr);
 }
 
 static int ion_system_contig_heap_phys(struct ion_heap *heap,
 				       struct ion_buffer *buffer,
 				       ion_phys_addr_t *addr, size_t *len)
 {
-	*addr = virt_to_phys(buffer->priv_virt);
+	struct kmalloc_buffer_info *info = buffer->priv_virt;
+	*addr = virt_to_phys(info->vaddr);
 	*len = buffer->size;
 	return 0;
 }
@@ -365,27 +509,13 @@
 struct sg_table *ion_system_contig_heap_map_dma(struct ion_heap *heap,
 						struct ion_buffer *buffer)
 {
-	struct sg_table *table;
-	int ret;
-
-	table = kzalloc(sizeof(struct sg_table), GFP_KERNEL);
-	if (!table)
-		return ERR_PTR(-ENOMEM);
-	ret = sg_alloc_table(table, 1, GFP_KERNEL);
-	if (ret) {
-		kfree(table);
-		return ERR_PTR(ret);
-	}
-	sg_set_page(table->sgl, virt_to_page(buffer->priv_virt), buffer->size,
-		    0);
-	return table;
+	struct kmalloc_buffer_info *info = buffer->priv_virt;
+	return info->table;
 }
 
 void ion_system_contig_heap_unmap_dma(struct ion_heap *heap,
 				      struct ion_buffer *buffer)
 {
-	sg_free_table(buffer->sg_table);
-	kfree(buffer->sg_table);
 }
 
 static struct ion_heap_ops kmalloc_ops = {
diff --git a/drivers/gpu/ion/msm/msm_ion.c b/drivers/gpu/ion/msm/msm_ion.c
index 118c39a..c77bac7 100644
--- a/drivers/gpu/ion/msm/msm_ion.c
+++ b/drivers/gpu/ion/msm/msm_ion.c
@@ -51,74 +51,56 @@
 static struct ion_heap_desc ion_heap_meta[] = {
 	{
 		.id	= ION_SYSTEM_HEAP_ID,
-		.type	= ION_HEAP_TYPE_SYSTEM,
-		.name	= ION_VMALLOC_HEAP_NAME,
+		.name	= ION_SYSTEM_HEAP_NAME,
 	},
 	{
 		.id	= ION_SYSTEM_CONTIG_HEAP_ID,
-		.type	= ION_HEAP_TYPE_SYSTEM_CONTIG,
 		.name	= ION_KMALLOC_HEAP_NAME,
 	},
 	{
 		.id	= ION_CP_MM_HEAP_ID,
-		.type	= ION_HEAP_TYPE_SECURE_DMA,
 		.name	= ION_MM_HEAP_NAME,
 		.permission_type = IPT_TYPE_MM_CARVEOUT,
 	},
 	{
 		.id	= ION_MM_FIRMWARE_HEAP_ID,
-		.type	= ION_HEAP_TYPE_CARVEOUT,
 		.name	= ION_MM_FIRMWARE_HEAP_NAME,
 	},
 	{
 		.id	= ION_CP_MFC_HEAP_ID,
-		.type	= ION_HEAP_TYPE_CP,
 		.name	= ION_MFC_HEAP_NAME,
 		.permission_type = IPT_TYPE_MFC_SHAREDMEM,
 	},
 	{
 		.id	= ION_SF_HEAP_ID,
-		.type	= ION_HEAP_TYPE_CARVEOUT,
 		.name	= ION_SF_HEAP_NAME,
 	},
 	{
-		.id	= ION_IOMMU_HEAP_ID,
-		.type	= ION_HEAP_TYPE_IOMMU,
-		.name	= ION_IOMMU_HEAP_NAME,
-	},
-	{
 		.id	= ION_QSECOM_HEAP_ID,
-		.type	= ION_HEAP_TYPE_DMA,
 		.name	= ION_QSECOM_HEAP_NAME,
 	},
 	{
 		.id	= ION_AUDIO_HEAP_ID,
-		.type	= ION_HEAP_TYPE_CARVEOUT,
 		.name	= ION_AUDIO_HEAP_NAME,
 	},
 	{
 		.id	= ION_PIL1_HEAP_ID,
-		.type	= ION_HEAP_TYPE_CARVEOUT,
 		.name	= ION_PIL1_HEAP_NAME,
 	},
 	{
 		.id	= ION_PIL2_HEAP_ID,
-		.type	= ION_HEAP_TYPE_CARVEOUT,
 		.name	= ION_PIL2_HEAP_NAME,
 	},
 	{
 		.id	= ION_CP_WB_HEAP_ID,
-		.type	= ION_HEAP_TYPE_CP,
 		.name	= ION_WB_HEAP_NAME,
 	},
 	{
 		.id	= ION_CAMERA_HEAP_ID,
-		.type	= ION_HEAP_TYPE_CARVEOUT,
 		.name	= ION_CAMERA_HEAP_NAME,
 	},
 	{
 		.id	= ION_ADSP_HEAP_ID,
-		.type	= ION_HEAP_TYPE_DMA,
 		.name	= ION_ADSP_HEAP_NAME,
 	}
 };
@@ -127,6 +109,16 @@
 struct ion_client *msm_ion_client_create(unsigned int heap_mask,
 					const char *name)
 {
+	/*
+	 * The assumption is that if there is a NULL device, the ion
+	 * driver has not yet probed.
+	 */
+	if (idev == NULL)
+		return ERR_PTR(-EPROBE_DEFER);
+
+	if (IS_ERR(idev))
+		return (struct ion_client *)idev;
+
 	return ion_client_create(idev, name);
 }
 EXPORT_SYMBOL(msm_ion_client_create);
@@ -593,15 +585,58 @@
 	return ret;
 }
 
-static int msm_ion_populate_heap(struct ion_platform_heap *heap)
+#define MAKE_HEAP_TYPE_MAPPING(h) { .name = #h, \
+			.heap_type = ION_HEAP_TYPE_##h, }
+
+static struct heap_types_info {
+	const char *name;
+	int heap_type;
+} heap_types_info[] = {
+	MAKE_HEAP_TYPE_MAPPING(SYSTEM),
+	MAKE_HEAP_TYPE_MAPPING(SYSTEM_CONTIG),
+	MAKE_HEAP_TYPE_MAPPING(CARVEOUT),
+	MAKE_HEAP_TYPE_MAPPING(CHUNK),
+	MAKE_HEAP_TYPE_MAPPING(DMA),
+	MAKE_HEAP_TYPE_MAPPING(CP),
+	MAKE_HEAP_TYPE_MAPPING(SECURE_DMA),
+	MAKE_HEAP_TYPE_MAPPING(REMOVED),
+};
+
+static int msm_ion_get_heap_type_from_dt_node(struct device_node *node,
+					int *heap_type)
+{
+	const char *name;
+	int i, ret = -EINVAL;
+	ret = of_property_read_string(node, "qcom,ion-heap-type", &name);
+	if (ret)
+		goto out;
+	for (i = 0; i < ARRAY_SIZE(heap_types_info); ++i) {
+		if (!strcmp(heap_types_info[i].name, name)) {
+			*heap_type = heap_types_info[i].heap_type;
+			ret = 0;
+			goto out;
+		}
+	}
+	WARN(1, "Unknown heap type: %s. You might need to update heap_types_info in %s",
+		name, __FILE__);
+out:
+	return ret;
+}
+
+static int msm_ion_populate_heap(struct device_node *node,
+				struct ion_platform_heap *heap)
 {
 	unsigned int i;
-	int ret = -EINVAL;
+	int ret = -EINVAL, heap_type = -1;
 	unsigned int len = ARRAY_SIZE(ion_heap_meta);
 	for (i = 0; i < len; ++i) {
 		if (ion_heap_meta[i].id == heap->id) {
 			heap->name = ion_heap_meta[i].name;
-			heap->type = ion_heap_meta[i].type;
+			ret = msm_ion_get_heap_type_from_dt_node(node,
+								&heap_type);
+			if (ret)
+				break;
+			heap->type = heap_type;
 			ret = msm_init_extra_data(heap, &ion_heap_meta[i]);
 			break;
 		}
@@ -793,7 +828,7 @@
 		}
 		pdata->heaps[idx].id = val;
 
-		ret = msm_ion_populate_heap(&pdata->heaps[idx]);
+		ret = msm_ion_populate_heap(node, &pdata->heaps[idx]);
 		if (ret)
 			goto free_heaps;
 
@@ -933,9 +968,6 @@
 	struct ion_heap *heap = NULL;
 
 	switch ((int)heap_data->type) {
-	case ION_HEAP_TYPE_IOMMU:
-		heap = ion_iommu_heap_create(heap_data);
-		break;
 	case ION_HEAP_TYPE_CP:
 		heap = ion_cp_heap_create(heap_data);
 		break;
@@ -975,9 +1007,6 @@
 		return;
 
 	switch ((int)heap->type) {
-	case ION_HEAP_TYPE_IOMMU:
-		ion_iommu_heap_destroy(heap);
-		break;
 	case ION_HEAP_TYPE_CP:
 		ion_cp_heap_destroy(heap);
 		break;
@@ -999,6 +1028,7 @@
 
 static int msm_ion_probe(struct platform_device *pdev)
 {
+	static struct ion_device *new_dev;
 	struct ion_platform_data *pdata;
 	unsigned int pdata_needs_to_be_freed;
 	int err = -1;
@@ -1024,9 +1054,14 @@
 		goto out;
 	}
 
-	idev = ion_device_create(msm_ion_custom_ioctl);
-	if (IS_ERR_OR_NULL(idev)) {
-		err = PTR_ERR(idev);
+	new_dev = ion_device_create(msm_ion_custom_ioctl);
+	if (IS_ERR_OR_NULL(new_dev)) {
+		/*
+		 * set this to the ERR to indicate to the clients
+		 * that Ion failed to probe.
+		 */
+		idev = new_dev;
+		err = PTR_ERR(new_dev);
 		goto freeheaps;
 	}
 
@@ -1053,13 +1088,18 @@
 							  heap_data->name);
 		}
 
-		ion_device_add_heap(idev, heaps[i]);
+		ion_device_add_heap(new_dev, heaps[i]);
 	}
 	check_for_heap_overlap(pdata->heaps, num_heaps);
 	if (pdata_needs_to_be_freed)
 		free_pdata(pdata);
 
-	platform_set_drvdata(pdev, idev);
+	platform_set_drvdata(pdev, new_dev);
+	/*
+	 * intentionally set this at the very end to allow probes to be deferred
+	 * completely until Ion is setup
+	 */
+	idev = new_dev;
 	return 0;
 
 freeheaps:
diff --git a/drivers/gpu/ion/msm_ion_priv.h b/drivers/gpu/ion/msm_ion_priv.h
index 2de4e8a..412ead2 100644
--- a/drivers/gpu/ion/msm_ion_priv.h
+++ b/drivers/gpu/ion/msm_ion_priv.h
@@ -21,14 +21,14 @@
 #include <linux/kref.h>
 #include <linux/mm_types.h>
 #include <linux/mutex.h>
-#include <linux/rbtree.h>
+#include <linux/types.h>
 #include <linux/ion.h>
 #include <linux/iommu.h>
 #include <linux/seq_file.h>
 
 /**
  * struct mem_map_data - represents information about the memory map for a heap
- * @node:		rb node used to store in the tree of mem_map_data
+ * @node:		list node used to store in the list of mem_map_data
  * @addr:		start address of memory region.
  * @addr:		end address of memory region.
  * @size:		size of memory region
@@ -36,7 +36,7 @@
  *
  */
 struct mem_map_data {
-	struct rb_node node;
+	struct list_head node;
 	ion_phys_addr_t addr;
 	ion_phys_addr_t addr_end;
 	unsigned long size;
diff --git a/drivers/gpu/msm/Kconfig b/drivers/gpu/msm/Kconfig
index ba63fbc..2576386 100644
--- a/drivers/gpu/msm/Kconfig
+++ b/drivers/gpu/msm/Kconfig
@@ -4,6 +4,10 @@
 	depends on ARCH_MSM && !ARCH_MSM7X00A && !ARCH_MSM7X25
 	select GENERIC_ALLOCATOR
 	select FW_LOADER
+	select PM_DEVFREQ
+	select DEVFREQ_GOV_SIMPLE_ONDEMAND
+	select DEVFREQ_GOV_PERFORMANCE
+	select DEVFREQ_GOV_MSM_ADRENO_TZ
 	---help---
 	  3D graphics driver. Required to use hardware accelerated
 	  OpenGL ES 2.0 and 1.1.
@@ -60,6 +64,17 @@
 	default y
 	depends on MSM_KGSL && !ARCH_MSM7X27 && !ARCH_MSM7X27A && !(ARCH_QSD8X50 && !MSM_SOC_REV_A)
 
+config MSM_ADRENO_DEFAULT_GOVERNOR
+	string "devfreq governor for the adreno core"
+	default "msm-adreno-tz" if DEVFREQ_GOV_MSM_ADRENO_TZ
+	default "simple_ondemand"
+	depends on MSM_KGSL
+
+config MSM_Z180_DEFAULT_GOVERNOR
+	string "devfreq governor for the z180 core(s)"
+	default "performance"
+	depends on MSM_KGSL_2D
+
 config MSM_KGSL_DRM
 	bool "Build a DRM interface for the MSM_KGSL driver"
 	depends on MSM_KGSL && DRM
diff --git a/drivers/gpu/msm/Makefile b/drivers/gpu/msm/Makefile
index aac183b..14e07e5 100644
--- a/drivers/gpu/msm/Makefile
+++ b/drivers/gpu/msm/Makefile
@@ -15,8 +15,6 @@
 msm_kgsl_core-$(CONFIG_DEBUG_FS) += kgsl_debugfs.o
 msm_kgsl_core-$(CONFIG_MSM_KGSL_CFF_DUMP) += kgsl_cffdump.o
 msm_kgsl_core-$(CONFIG_MSM_KGSL_DRM) += kgsl_drm.o
-msm_kgsl_core-$(CONFIG_MSM_SCM) += kgsl_pwrscale_trustzone.o
-msm_kgsl_core-$(CONFIG_MSM_SLEEP_STATS_DEVICE) += kgsl_pwrscale_idlestats.o
 msm_kgsl_core-$(CONFIG_SYNC) += kgsl_sync.o
 
 msm_adreno-y += \
diff --git a/drivers/gpu/msm/a3xx_reg.h b/drivers/gpu/msm/a3xx_reg.h
index 676f46d..758d5c5 100644
--- a/drivers/gpu/msm/a3xx_reg.h
+++ b/drivers/gpu/msm/a3xx_reg.h
@@ -775,6 +775,9 @@
 #define SP0_ICL1_MISSES                0x1A
 #define SP_FS_CFLOW_INSTRUCTIONS       0x0C
 
+/* COUNTABLE FOR TSE PERFCOUNTER */
+#define TSE_INPUT_PRIM_NUM             0x0
+
 /* VBIF PERFCOUNTER ENA/CLR values */
 #define VBIF_PERF_CNT_0 BIT(0)
 #define VBIF_PERF_CNT_1 BIT(1)
@@ -789,6 +792,7 @@
 #define VBIF_PERF_CNT_1_SEL_MASK 0x7f00
 
 /* VBIF countables */
+#define VBIF_AXI_TOTAL_BEATS 85
 #define VBIF_DDR_TOTAL_CYCLES 110
 
 #endif
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index a271388..675fcf3 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -19,6 +19,7 @@
 #include <linux/of_device.h>
 #include <linux/delay.h>
 #include <linux/of_coresight.h>
+#include <linux/input.h>
 
 #include <mach/socinfo.h>
 #include <mach/msm_bus_board.h>
@@ -77,11 +78,38 @@
 
 #define KGSL_LOG_LEVEL_DEFAULT 3
 
+static void adreno_start_work(struct work_struct *work);
+static void adreno_input_work(struct work_struct *work);
+
+/*
+ * The default values for the simpleondemand governor are 90 and 5,
+ * we use different values here.
+ * They have to be tuned and compare with the tz governor anyway.
+ */
+static struct devfreq_simple_ondemand_data adreno_ondemand_data = {
+	.upthreshold = 80,
+	.downdifferential = 20,
+};
+
+static struct devfreq_msm_adreno_tz_data adreno_tz_data = {
+	.bus = {
+		.max = 450,
+	},
+	.device_id = KGSL_DEVICE_3D0,
+};
+
+static const struct devfreq_governor_data adreno_governors[] = {
+	{ .name = "simple_ondemand", .data = &adreno_ondemand_data },
+	{ .name = "msm-adreno-tz", .data = &adreno_tz_data },
+};
+
 static const struct kgsl_functable adreno_functable;
 
 static struct adreno_device device_3d0 = {
 	.dev = {
 		KGSL_DEVICE_COMMON_INIT(device_3d0.dev),
+		.pwrscale = KGSL_PWRSCALE_INIT(adreno_governors,
+					ARRAY_SIZE(adreno_governors)),
 		.name = DEVICE_3D0_NAME,
 		.id = KGSL_DEVICE_3D0,
 		.mh = {
@@ -123,10 +151,16 @@
 	.ft_pf_policy = KGSL_FT_PAGEFAULT_DEFAULT_POLICY,
 	.fast_hang_detect = 1,
 	.long_ib_detect = 1,
+	.start_work = __WORK_INITIALIZER(device_3d0.start_work,
+		adreno_start_work),
+	.input_work = __WORK_INITIALIZER(device_3d0.input_work,
+		adreno_input_work),
 };
 
 unsigned int ft_detect_regs[FT_DETECT_REGS_COUNT];
 
+static struct workqueue_struct *adreno_wq;
+
 /*
  * This is the master list of all GPU cores that are supported by this
  * driver.
@@ -220,6 +254,122 @@
 		512, 0, 2, SZ_128K, 0x3FF037, 0x3FF016 },
 };
 
+/* Nice level for the higher priority GPU start thread */
+static unsigned int _wake_nice = -7;
+
+/* Number of milliseconds to stay active active after a wake on touch */
+static unsigned int _wake_timeout = 100;
+
+/*
+ * A workqueue callback responsible for actually turning on the GPU after a
+ * touch event. kgsl_pwrctrl_wake() is used without any active_count protection
+ * to avoid the need to maintain state.  Either somebody will start using the
+ * GPU or the idle timer will fire and put the GPU back into slumber
+ */
+static void adreno_input_work(struct work_struct *work)
+{
+	struct adreno_device *adreno_dev = container_of(work,
+			struct adreno_device, input_work);
+	struct kgsl_device *device = &adreno_dev->dev;
+
+	mutex_lock(&device->mutex);
+
+	device->flags |= KGSL_FLAG_WAKE_ON_TOUCH;
+
+	/*
+	 * Don't schedule adreno_start in a high priority workqueue, we are
+	 * already in a workqueue which should be sufficient
+	 */
+	kgsl_pwrctrl_wake(device, 0);
+
+	/*
+	 * When waking up from a touch event we want to stay active long enough
+	 * for the user to send a draw command.  The default idle timer timeout
+	 * is shorter than we want so go ahead and push the idle timer out
+	 * further for this special case
+	 */
+	mod_timer(&device->idle_timer,
+		jiffies + msecs_to_jiffies(_wake_timeout));
+	mutex_unlock(&device->mutex);
+}
+
+/*
+ * Process input events and schedule work if needed.  At this point we are only
+ * interested in groking EV_ABS touchscreen events
+ */
+static void adreno_input_event(struct input_handle *handle, unsigned int type,
+		unsigned int code, int value)
+{
+	struct kgsl_device *device = handle->handler->private;
+	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+
+	/*
+	 * Only queue the work under certain circumstances: we have to be in
+	 * slumber, the event has to be EV_EBS and we had to have processed an
+	 * IB since the last time we called wake on touch.
+	 */
+	if ((type == EV_ABS) &&
+		!(device->flags & KGSL_FLAG_WAKE_ON_TOUCH) &&
+		(device->state == KGSL_STATE_SLUMBER))
+		schedule_work(&adreno_dev->input_work);
+}
+
+static int adreno_input_connect(struct input_handler *handler,
+		struct input_dev *dev, const struct input_device_id *id)
+{
+	struct input_handle *handle;
+	int ret;
+
+	handle = kzalloc(sizeof(*handle), GFP_KERNEL);
+	if (handle == NULL)
+		return -ENOMEM;
+
+	handle->dev = dev;
+	handle->handler = handler;
+	handle->name = handler->name;
+
+	ret = input_register_handle(handle);
+	if (ret) {
+		kfree(handle);
+		return ret;
+	}
+
+	ret = input_open_device(handle);
+	if (ret) {
+		input_unregister_handle(handle);
+		kfree(handle);
+	}
+
+	return ret;
+}
+
+static void adreno_input_disconnect(struct input_handle *handle)
+{
+	input_close_device(handle);
+	input_unregister_handle(handle);
+	kfree(handle);
+}
+
+/*
+ * We are only interested in EV_ABS events so only register handlers for those
+ * input devices that have EV_ABS events
+ */
+static const struct input_device_id adreno_input_ids[] = {
+	{
+		.flags = INPUT_DEVICE_ID_MATCH_EVBIT,
+		.evbit = { BIT_MASK(EV_ABS) },
+	},
+	{ },
+};
+
+static struct input_handler adreno_input_handler = {
+	.event = adreno_input_event,
+	.connect = adreno_input_connect,
+	.disconnect = adreno_input_disconnect,
+	.name = "kgsl",
+	.id_table = adreno_input_ids,
+};
+
 /**
  * adreno_perfcounter_init: Reserve kernel performance counters
  * @device: device to configure
@@ -616,6 +766,33 @@
 	return -EINVAL;
 }
 
+/**
+ * adreno_perfcounter_restore() - Restore performance counters
+ * @adreno_dev: adreno device to configure
+ *
+ * Load the physical performance counters with 64 bit value which are
+ * saved on GPU power collapse.
+ */
+static inline void adreno_perfcounter_restore(struct adreno_device *adreno_dev)
+{
+	if (adreno_dev->gpudev->perfcounter_restore)
+		adreno_dev->gpudev->perfcounter_restore(adreno_dev);
+}
+
+/**
+ * adreno_perfcounter_save() - Save performance counters
+ * @adreno_dev: adreno device to configure
+ *
+ * Save the performance counter values before GPU power collapse.
+ * The saved values are restored on restart.
+ * This ensures physical counters are coherent across power-collapse.
+ */
+static inline void adreno_perfcounter_save(struct adreno_device *adreno_dev)
+{
+	if (adreno_dev->gpudev->perfcounter_save)
+		adreno_dev->gpudev->perfcounter_save(adreno_dev);
+}
+
 static irqreturn_t adreno_irq_handler(struct kgsl_device *device)
 {
 	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
@@ -631,8 +808,6 @@
 
 	kgsl_mmu_unmap(pagetable, &rb->buffer_desc);
 
-	kgsl_mmu_unmap(pagetable, &rb->memptrs_desc);
-
 	kgsl_mmu_unmap(pagetable, &device->memstore);
 
 	kgsl_mmu_unmap(pagetable, &adreno_dev->pwron_fixup);
@@ -653,14 +828,11 @@
 
 	/*
 	 * ALERT: Order of these mapping is important to
-	 * Keep the most used entries like memptrs, memstore
+	 * Keep the most used entries like memstore
 	 * and mmu setstate memory by TLB prefetcher.
 	 */
 
 	if (!result)
-		result = kgsl_mmu_map_global(pagetable, &rb->memptrs_desc);
-
-	if (!result)
 		result = kgsl_mmu_map_global(pagetable, &device->memstore);
 
 	if (!result)
@@ -1364,15 +1536,6 @@
 		&pdata->init_level))
 		pdata->init_level = 1;
 
-	/*
-	 * qcom,step-pwrlevel isn't required so don't spam the kernel log
-	 * if it isn't found
-	 */
-
-	if (of_property_read_u32(parent, "qcom,step-pwrlevel",
-		&pdata->step_mul))
-		pdata->step_mul = 1;
-
 	if (pdata->init_level < 0 || pdata->init_level > pdata->num_levels) {
 		KGSL_CORE_ERR("Initial power level out of range\n");
 		pdata->init_level = 1;
@@ -1506,6 +1669,9 @@
 	pdata->strtstp_sleepwake = of_property_read_bool(pdev->dev.of_node,
 						"qcom,strtstp-sleepwake");
 
+	pdata->bus_control = of_property_read_bool(pdev->dev.of_node,
+					"qcom,bus-control");
+
 	if (adreno_of_read_property(pdev->dev.of_node, "qcom,clk-map",
 		&pdata->clk_map))
 		goto err;
@@ -1635,14 +1801,23 @@
 
 	adreno_ft_init_sysfs(device);
 
-	kgsl_pwrscale_init(device);
-	kgsl_pwrscale_attach_policy(device, ADRENO_DEFAULT_PWRSCALE_POLICY);
+	kgsl_pwrscale_init(&pdev->dev, CONFIG_MSM_ADRENO_DEFAULT_GOVERNOR);
+
 
 	device->flags &= ~KGSL_FLAGS_SOFT_RESET;
 	pdata = kgsl_device_get_drvdata(device);
 
 	adreno_coresight_init(pdev);
 
+	adreno_input_handler.private = device;
+
+	/*
+	 * It isn't fatal if we cannot register the input handler.  Sad,
+	 * perhaps, but not fatal
+	 */
+	if (input_register_handler(&adreno_input_handler))
+		KGSL_DRV_ERR(device, "Unable to register the input handler\n");
+
 	return 0;
 
 error_close_device:
@@ -1663,10 +1838,11 @@
 	device = (struct kgsl_device *)pdev->id_entry->driver_data;
 	adreno_dev = ADRENO_DEVICE(device);
 
+	input_unregister_handler(&adreno_input_handler);
+
 	adreno_coresight_remove(pdev);
 	adreno_profile_close(device);
 
-	kgsl_pwrscale_detach_policy(device);
 	kgsl_pwrscale_close(device);
 
 	adreno_dispatcher_close(adreno_dev);
@@ -1685,6 +1861,9 @@
 	int i;
 	int ret;
 
+	/* Make a high priority workqueue for starting the GPU */
+	adreno_wq = alloc_workqueue("adreno", WQ_HIGHPRI | WQ_UNBOUND, 1);
+
 	kgsl_pwrctrl_set_state(device, KGSL_STATE_INIT);
 	/*
 	 * initialization only needs to be done once initially until
@@ -1761,10 +1940,17 @@
 	return ret;
 }
 
-static int adreno_start(struct kgsl_device *device)
+/**
+ * _adreno_start - Power up the GPU and prepare to accept commands
+ * @adreno_dev: Pointer to an adreno_device structure
+ *
+ * The core function that powers up and initalizes the GPU.  This function is
+ * called at init and after coming out of SLUMBER
+ */
+static int _adreno_start(struct adreno_device *adreno_dev)
 {
+	struct kgsl_device *device = &adreno_dev->dev;
 	int status = -EINVAL;
-	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
 	unsigned int state = device->state;
 	unsigned int regulator_left_on = 0;
 
@@ -1817,6 +2003,9 @@
 		adreno_dev->gpudev->soft_reset(adreno_dev);
 	}
 
+	/* Restore performance counter registers with saved values */
+	adreno_perfcounter_restore(adreno_dev);
+
 	/* Start the GPU */
 	adreno_dev->gpudev->start(adreno_dev);
 
@@ -1854,6 +2043,58 @@
 	return status;
 }
 
+static int _status;
+
+/**
+ * _adreno_start_work() - Work handler for the low latency adreno_start
+ * @work: Pointer to the work_struct for
+ *
+ * The work callbak for the low lantecy GPU start - this executes the core
+ * _adreno_start function in the workqueue.
+ */
+static void adreno_start_work(struct work_struct *work)
+{
+	struct adreno_device *adreno_dev = container_of(work,
+		struct adreno_device, start_work);
+	struct kgsl_device *device = &adreno_dev->dev;
+
+	/* Nice ourselves to be higher priority but not too high priority */
+	set_user_nice(current, _wake_nice);
+
+	mutex_lock(&device->mutex);
+	_status = _adreno_start(adreno_dev);
+	mutex_unlock(&device->mutex);
+}
+
+/**
+ * adreno_start() - Power up and initialize the GPU
+ * @device: Pointer to the KGSL device to power up
+ * @priority:  Boolean flag to specify of the start should be scheduled in a low
+ * latency work queue
+ *
+ * Power up the GPU and initialize it.  If priority is specified then queue the
+ * start function in a high priority queue for lower latency.
+ */
+static int adreno_start(struct kgsl_device *device, int priority)
+{
+	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+
+	/* No priority (normal latency) call the core start function directly */
+	if (!priority)
+		return _adreno_start(adreno_dev);
+
+	/*
+	 * If priority is specified (low latency) then queue the work in a
+	 * higher priority work queue and wait for it to finish
+	 */
+	queue_work(adreno_wq, &adreno_dev->start_work);
+	mutex_unlock(&device->mutex);
+	flush_work(&adreno_dev->start_work);
+	mutex_lock(&device->mutex);
+
+	return _status;
+}
+
 static int adreno_stop(struct kgsl_device *device)
 {
 	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
@@ -1874,6 +2115,9 @@
 
 	adreno_ocmem_gmem_free(adreno_dev);
 
+	/* Save physical performance counter values before GPU power down*/
+	adreno_perfcounter_save(adreno_dev);
+
 	/* Power down the device */
 	kgsl_pwrctrl_disable(device);
 
@@ -1908,7 +2152,7 @@
 
 		/* Keep trying to start the device until it works */
 		for (i = 0; i < NUM_TIMES_RESET_RETRY; i++) {
-			ret = adreno_start(device);
+			ret = adreno_start(device, 0);
 			if (!ret)
 				break;
 
@@ -2090,12 +2334,29 @@
 				     const char *buf, size_t count)
 {
 	struct adreno_device *adreno_dev = _get_adreno_dev(dev);
-	int ret;
+	int ret, tmp;
+
 	if (adreno_dev == NULL)
 		return 0;
 
 	mutex_lock(&adreno_dev->dev.mutex);
+
+	tmp = adreno_dev->fast_hang_detect;
+
 	ret = _ft_sysfs_store(buf, count, &adreno_dev->fast_hang_detect);
+
+	if (tmp != adreno_dev->fast_hang_detect) {
+		if (adreno_dev->fast_hang_detect) {
+			if (adreno_dev->gpudev->fault_detect_start)
+				adreno_dev->gpudev->fault_detect_start(
+					adreno_dev);
+		} else {
+			if (adreno_dev->gpudev->fault_detect_stop)
+				adreno_dev->gpudev->fault_detect_stop(
+					adreno_dev);
+		}
+	}
+
 	mutex_unlock(&adreno_dev->dev.mutex);
 
 	return ret;
@@ -2166,6 +2427,36 @@
 				(adreno_dev->long_ib_detect ? 1 : 0));
 }
 
+/**
+ * _wake_timeout_store() - Store the amount of time to extend idle check after
+ * wake on touch
+ * @dev: device ptr
+ * @attr: Device attribute
+ * @buf: value to write
+ * @count: size of the value to write
+ *
+ */
+static ssize_t _wake_timeout_store(struct device *dev,
+				     struct device_attribute *attr,
+				     const char *buf, size_t count)
+{
+	return _ft_sysfs_store(buf, count, &_wake_timeout);
+}
+
+/**
+ * _wake_timeout_show() -  Show the amount of time idle check gets extended
+ * after wake on touch
+ * detect policy
+ * @dev: device ptr
+ * @attr: Device attribute
+ * @buf: value read
+ */
+static ssize_t _wake_timeout_show(struct device *dev,
+					struct device_attribute *attr,
+					char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%d\n", _wake_timeout);
+}
 
 #define FT_DEVICE_ATTR(name) \
 	DEVICE_ATTR(name, 0644,	_ ## name ## _show, _ ## name ## _store);
@@ -2175,12 +2466,16 @@
 FT_DEVICE_ATTR(ft_fast_hang_detect);
 FT_DEVICE_ATTR(ft_long_ib_detect);
 
+static DEVICE_INT_ATTR(wake_nice, 0644, _wake_nice);
+static FT_DEVICE_ATTR(wake_timeout);
 
 const struct device_attribute *ft_attr_list[] = {
 	&dev_attr_ft_policy,
 	&dev_attr_ft_pagefault_policy,
 	&dev_attr_ft_fast_hang_detect,
 	&dev_attr_ft_long_ib_detect,
+	&dev_attr_wake_nice.attr,
+	&dev_attr_wake_timeout,
 	NULL,
 };
 
@@ -2316,11 +2611,19 @@
 			if (enable) {
 				device->pwrctrl.ctrl_flags = 0;
 				adreno_dev->fast_hang_detect = 1;
+
+				if (adreno_dev->gpudev->fault_detect_start)
+					adreno_dev->gpudev->fault_detect_start(
+						adreno_dev);
+
 				kgsl_pwrscale_enable(device);
 			} else {
-				kgsl_pwrctrl_wake(device);
+				kgsl_pwrctrl_wake(device, 0);
 				device->pwrctrl.ctrl_flags = KGSL_PWR_ON;
 				adreno_dev->fast_hang_detect = 0;
+				if (adreno_dev->gpudev->fault_detect_stop)
+					adreno_dev->gpudev->fault_detect_stop(
+						adreno_dev);
 				kgsl_pwrscale_disable(device);
 			}
 
@@ -2403,9 +2706,15 @@
 	/* Make sure we are totally awake */
 	kgsl_pwrctrl_enable(device);
 
+	/* save physical performance counter values before GPU soft reset */
+	adreno_perfcounter_save(adreno_dev);
+
 	/* Reset the GPU */
 	adreno_dev->gpudev->soft_reset(adreno_dev);
 
+	/* Restore physical performance counter values after soft reset */
+	adreno_perfcounter_restore(adreno_dev);
+
 	/* Reinitialize the GPU */
 	adreno_dev->gpudev->start(adreno_dev);
 
@@ -2580,9 +2889,6 @@
 	if (kgsl_gpuaddr_in_memdesc(&ringbuffer->buffer_desc, gpuaddr, size))
 		return &ringbuffer->buffer_desc;
 
-	if (kgsl_gpuaddr_in_memdesc(&ringbuffer->memptrs_desc, gpuaddr, size))
-		return &ringbuffer->memptrs_desc;
-
 	if (kgsl_gpuaddr_in_memdesc(&device->memstore, gpuaddr, size))
 		return &device->memstore;
 
@@ -2842,10 +3148,10 @@
 
 }
 
-static inline s64 adreno_ticks_to_us(u32 ticks, u32 gpu_freq)
+static inline s64 adreno_ticks_to_us(u32 ticks, u32 freq)
 {
-	gpu_freq /= 1000000;
-	return ticks / gpu_freq;
+	freq /= 1000000;
+	return ticks / freq;
 }
 
 static void adreno_power_stats(struct kgsl_device *device,
@@ -2853,32 +3159,21 @@
 {
 	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
 	struct kgsl_pwrctrl *pwr = &device->pwrctrl;
-	unsigned int cycles = 0;
+	struct adreno_busy_data busy_data;
 
+	memset(stats, 0, sizeof(*stats));
 	/*
 	 * Get the busy cycles counted since the counter was last reset.
 	 * If we're not currently active, there shouldn't have been
 	 * any cycles since the last time this function was called.
 	 */
 	if (device->state == KGSL_STATE_ACTIVE)
-		cycles = adreno_dev->gpudev->busy_cycles(adreno_dev);
+		adreno_dev->gpudev->busy_cycles(adreno_dev, &busy_data);
 
-	/*
-	 * In order to calculate idle you have to have run the algorithm
-	 * at least once to get a start time.
-	 */
-	if (pwr->time != 0) {
-		s64 tmp = ktime_to_us(ktime_get());
-		stats->total_time = tmp - pwr->time;
-		pwr->time = tmp;
-		stats->busy_time = adreno_ticks_to_us(cycles, device->pwrctrl.
-				pwrlevels[device->pwrctrl.active_pwrlevel].
-				gpu_freq);
-	} else {
-		stats->total_time = 0;
-		stats->busy_time = 0;
-		pwr->time = ktime_to_us(ktime_get());
-	}
+	stats->busy_time = adreno_ticks_to_us(busy_data.gpu_busy,
+					      kgsl_pwrctrl_active_freq(pwr));
+	stats->ram_time = busy_data.vbif_ram_cycles;
+	stats->ram_wait = busy_data.vbif_starved_ram;
 }
 
 void adreno_irqctrl(struct kgsl_device *device, int state)
diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h
index 418d230..b5938b0 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -62,6 +62,7 @@
 #define ADRENO_DEFAULT_PWRSCALE_POLICY  NULL
 #endif
 
+void adreno_debugfs_init(struct kgsl_device *device);
 
 #define ADRENO_ISTORE_START 0x5000 /* Istore offset */
 
@@ -148,6 +149,12 @@
 
 struct adreno_gpudev;
 
+struct adreno_busy_data {
+	unsigned int gpu_busy;
+	unsigned int vbif_ram_cycles;
+	unsigned int vbif_starved_ram;
+};
+
 struct adreno_device {
 	struct kgsl_device dev;    /* Must be first field in this struct */
 	unsigned long priv;
@@ -188,11 +195,14 @@
 	unsigned int gpulist_index;
 	struct ocmem_buf *ocmem_hdl;
 	unsigned int ocmem_base;
-	unsigned int gpu_cycles;
 	struct adreno_profile profile;
 	struct kgsl_memdesc pwron_fixup;
 	unsigned int pwron_fixup_dwords;
 	struct adreno_dispatcher dispatcher;
+	struct adreno_busy_data busy_data;
+
+	struct work_struct start_work;
+	struct work_struct input_work;
 };
 
 /**
@@ -220,6 +230,7 @@
  * @offset: register hardware offset
  * @load_bit: The bit number in LOAD register which corresponds to this counter
  * @select: The countable register offset
+ * @value: The 64 bit countable register value
  */
 struct adreno_perfcount_register {
 	unsigned int countable;
@@ -228,6 +239,7 @@
 	unsigned int offset;
 	int load_bit;
 	unsigned int select;
+	uint64_t value;
 };
 
 /**
@@ -350,12 +362,18 @@
 	int (*rb_init)(struct adreno_device *, struct adreno_ringbuffer *);
 	int (*perfcounter_init)(struct adreno_device *);
 	void (*perfcounter_close)(struct adreno_device *);
+	void (*perfcounter_save)(struct adreno_device *);
+	void (*perfcounter_restore)(struct adreno_device *);
+	void (*fault_detect_start)(struct adreno_device *);
+	void (*fault_detect_stop)(struct adreno_device *);
 	void (*start)(struct adreno_device *);
-	unsigned int (*busy_cycles)(struct adreno_device *);
 	int (*perfcounter_enable)(struct adreno_device *, unsigned int group,
 		unsigned int counter, unsigned int countable);
+	void (*busy_cycles)(struct adreno_device *, struct adreno_busy_data *);
 	uint64_t (*perfcounter_read)(struct adreno_device *adreno_dev,
 		unsigned int group, unsigned int counter);
+	void (*perfcounter_write)(struct adreno_device *adreno_dev,
+		unsigned int group, unsigned int counter);
 	int (*coresight_enable) (struct kgsl_device *device);
 	void (*coresight_disable) (struct kgsl_device *device);
 	void (*coresight_config_debug_reg) (struct kgsl_device *device,
@@ -364,7 +382,7 @@
 	void (*postmortem_dump)(struct adreno_device *adreno_dev);
 };
 
-#define FT_DETECT_REGS_COUNT 12
+#define FT_DETECT_REGS_COUNT 14
 
 struct log_field {
 	bool show;
@@ -845,4 +863,19 @@
 		return 0;
 }
 
+/**
+ * adreno_get_rptr() - Get the current ringbuffer read pointer
+ * @rb: Pointer the ringbuffer to query
+ *
+ * Get the current read pointer from the GPU register.
+ */
+static inline unsigned int
+adreno_get_rptr(struct adreno_ringbuffer *rb)
+{
+	struct adreno_device *adreno_dev = ADRENO_DEVICE(rb->device);
+	unsigned int result;
+	adreno_readreg(adreno_dev, ADRENO_REG_CP_RB_RPTR, &result);
+	return result;
+}
+
 #endif /*__ADRENO_H */
diff --git a/drivers/gpu/msm/adreno_a2xx.c b/drivers/gpu/msm/adreno_a2xx.c
index 24a0933..622350d3 100644
--- a/drivers/gpu/msm/adreno_a2xx.c
+++ b/drivers/gpu/msm/adreno_a2xx.c
@@ -1971,17 +1971,19 @@
 	return 0;
 }
 
-static unsigned int a2xx_busy_cycles(struct adreno_device *adreno_dev)
+static void a2xx_busy_cycles(struct adreno_device *adreno_dev,
+				struct adreno_busy_data *data)
 {
 	struct kgsl_device *device = &adreno_dev->dev;
-	unsigned int reg, val;
+	unsigned int reg;
 
+	memset(data, 0, sizeof(*data));
 	/* Freeze the counter */
 	kgsl_regwrite(device, REG_CP_PERFMON_CNTL,
 		REG_PERF_MODE_CNT | REG_PERF_STATE_FREEZE);
 
 	/* Get the value */
-	kgsl_regread(device, REG_RBBM_PERFCOUNTER1_LO, &val);
+	kgsl_regread(device, REG_RBBM_PERFCOUNTER1_LO, &data->gpu_busy);
 
 	/* Reset the counter */
 	kgsl_regwrite(device, REG_CP_PERFMON_CNTL,
@@ -1994,7 +1996,6 @@
 	kgsl_regwrite(device, REG_CP_PERFMON_CNTL,
 		REG_PERF_MODE_CNT | REG_PERF_STATE_ENABLE);
 
-	return val;
 }
 
 static void a2xx_gmeminit(struct adreno_device *adreno_dev)
diff --git a/drivers/gpu/msm/adreno_a3xx.c b/drivers/gpu/msm/adreno_a3xx.c
index df1794f..ced7fe6 100644
--- a/drivers/gpu/msm/adreno_a3xx.c
+++ b/drivers/gpu/msm/adreno_a3xx.c
@@ -95,6 +95,11 @@
 
 #define _SET(_shift, _val) ((_val) << (_shift))
 
+/* EN/CLR mask for the VBIF counters we care about */
+#define VBIF_PERF_MASK (VBIF_PERF_CNT_0 | VBIF_PERF_PWR_CNT_0)
+#define RBBM_PERF_ENABLE_MASK (RBBM_RBBM_CTL_ENABLE_PWR_CTR1)
+#define RBBM_PERF_RESET_MASK (RBBM_RBBM_CTL_RESET_PWR_CTR1)
+
 /*
  ****************************************************************************
  *
@@ -3376,6 +3381,136 @@
 	return (((uint64_t) hi) << 32) | lo;
 }
 
+/*
+ * values cannot be loaded into physical performance
+ * counters belonging to these groups.
+ */
+static inline int loadable_perfcounter_group(unsigned int groupid)
+{
+	return ((groupid == KGSL_PERFCOUNTER_GROUP_VBIF_PWR) ||
+		(groupid == KGSL_PERFCOUNTER_GROUP_VBIF) ||
+		(groupid == KGSL_PERFCOUNTER_GROUP_PWR)) ? 0 : 1;
+}
+
+/*
+ * Return true if the countable is used and not broken
+ */
+static inline int active_countable(unsigned int countable)
+{
+	return ((countable != KGSL_PERFCOUNTER_NOT_USED) &&
+		(countable != KGSL_PERFCOUNTER_BROKEN));
+}
+
+/**
+ * a3xx_perfcounter_save() - Save the physical performance counter values
+ * @adreno_dev -  Adreno device whose registers need to be saved
+ *
+ * Read all the physical performance counter's values and save them
+ * before GPU power collapse.
+ */
+static void a3xx_perfcounter_save(struct adreno_device *adreno_dev)
+{
+	struct adreno_perfcounters *counters = adreno_dev->gpudev->perfcounters;
+	struct adreno_perfcount_group *group;
+	unsigned int regid, groupid;
+
+	for (groupid = 0; groupid < counters->group_count; groupid++) {
+		if (!loadable_perfcounter_group(groupid))
+			continue;
+
+		group = &(counters->groups[groupid]);
+
+		/* group/counter iterator */
+		for (regid = 0; regid < group->reg_count; regid++) {
+			if (!active_countable(group->regs[regid].countable))
+				continue;
+
+			group->regs[regid].value =
+				adreno_dev->gpudev->perfcounter_read(
+				adreno_dev, groupid, regid);
+		}
+	}
+}
+
+/**
+ * a3xx_perfcounter_write() - Write the physical performance counter values.
+ * @adreno_dev -  Adreno device whose registers are to be written to.
+ * @group - group to which the physical counter belongs to.
+ * @counter - register id of the physical counter to which the value is
+ *		written to.
+ *
+ * This function loads the 64 bit saved value into the particular physical
+ * counter by enabling the corresponding bit in A3XX_RBBM_PERFCTR_LOAD_CMD*
+ * register.
+ */
+static void a3xx_perfcounter_write(struct adreno_device *adreno_dev,
+				unsigned int group, unsigned int counter)
+{
+	struct kgsl_device *device = &(adreno_dev->dev);
+	struct adreno_perfcount_register *reg;
+	unsigned int val;
+
+	reg = &(adreno_dev->gpudev->perfcounters->groups[group].regs[counter]);
+
+	/* Clear the load cmd registers */
+	kgsl_regwrite(device, A3XX_RBBM_PERFCTR_LOAD_CMD0, 0);
+	kgsl_regwrite(device, A3XX_RBBM_PERFCTR_LOAD_CMD1, 0);
+
+	/* Write the saved value to PERFCTR_LOAD_VALUE* registers. */
+	kgsl_regwrite(device, A3XX_RBBM_PERFCTR_LOAD_VALUE_LO,
+			(uint32_t)reg->value);
+	kgsl_regwrite(device, A3XX_RBBM_PERFCTR_LOAD_VALUE_HI,
+			(uint32_t)(reg->value >> 32));
+
+	/*
+	 * Set the load bit in PERFCTR_LOAD_CMD for the physical counter
+	 * we want to restore. The value in PERFCTR_LOAD_VALUE* is loaded
+	 * into the corresponding physical counter.
+	 */
+	if (reg->load_bit < 32)	{
+		val = 1 << reg->load_bit;
+		kgsl_regwrite(device, A3XX_RBBM_PERFCTR_LOAD_CMD0, val);
+	} else {
+		val  = 1 << (reg->load_bit - 32);
+		kgsl_regwrite(device, A3XX_RBBM_PERFCTR_LOAD_CMD1, val);
+	}
+}
+
+/**
+ * a3xx_perfcounter_restore() - Restore the physical performance counter values.
+ * @adreno_dev -  Adreno device whose registers are to be restored.
+ *
+ * This function together with a3xx_perfcounter_save make sure that performance
+ * counters are coherent across GPU power collapse.
+ */
+static void a3xx_perfcounter_restore(struct adreno_device *adreno_dev)
+{
+	struct kgsl_device *device = &adreno_dev->dev;
+	struct adreno_perfcounters *counters = adreno_dev->gpudev->perfcounters;
+	struct adreno_perfcount_group *group;
+	unsigned int regid, groupid;
+
+	for (groupid = 0; groupid < counters->group_count; groupid++) {
+		if (!loadable_perfcounter_group(groupid))
+			continue;
+
+		group = &(counters->groups[groupid]);
+
+		/* group/counter iterator */
+		for (regid = 0; regid < group->reg_count; regid++) {
+			if (!active_countable(group->regs[regid].countable))
+				continue;
+
+			a3xx_perfcounter_write(adreno_dev, groupid, regid);
+		}
+	}
+
+	/* Clear the load cmd registers */
+	kgsl_regwrite(device, A3XX_RBBM_PERFCTR_LOAD_CMD0, 0);
+	kgsl_regwrite(device, A3XX_RBBM_PERFCTR_LOAD_CMD1, 0);
+
+}
+
 #define A3XX_IRQ_CALLBACK(_c) { .func = _c }
 
 #define A3XX_INT_MASK \
@@ -3474,32 +3609,63 @@
 	return (status & A3XX_INT_MASK) ? 1 : 0;
 }
 
-static unsigned int a3xx_busy_cycles(struct adreno_device *adreno_dev)
+static unsigned int counter_delta(struct adreno_device *adreno_dev,
+			unsigned int reg, unsigned int *counter)
 {
 	struct kgsl_device *device = &adreno_dev->dev;
 	unsigned int val;
 	unsigned int ret = 0;
 
 	/* Read the value */
-	kgsl_regread(device, A3XX_RBBM_PERFCTR_PWR_1_LO, &val);
+	if (reg == ADRENO_REG_RBBM_PERFCTR_PWR_1_LO)
+		adreno_readreg(adreno_dev, reg, &val);
+	else
+		kgsl_regread(device, reg, &val);
 
 	/* Return 0 for the first read */
-	if (adreno_dev->gpu_cycles != 0) {
-		if (val < adreno_dev->gpu_cycles)
-			ret = (0xFFFFFFFF - adreno_dev->gpu_cycles) + val;
+	if (*counter != 0) {
+		if (val < *counter)
+			ret = (0xFFFFFFFF - *counter) + val;
 		else
-			ret = val - adreno_dev->gpu_cycles;
+			ret = val - *counter;
 	}
 
-	adreno_dev->gpu_cycles = val;
+	*counter = val;
 	return ret;
 }
 
+/*
+ * a3xx_busy_cycles() - Returns number of gpu cycles
+ * @adreno_dev: Pointer to device ehose cycles are checked
+ *
+ * Returns number of busy cycles since the last time this function is called
+ * Function is common between a3xx and a4xx devices
+ */
+void a3xx_busy_cycles(struct adreno_device *adreno_dev,
+				struct adreno_busy_data *data)
+{
+	struct adreno_busy_data *busy = &adreno_dev->busy_data;
+	struct kgsl_device *device = &adreno_dev->dev;
+
+	memset(data, 0, sizeof(*data));
+
+	data->gpu_busy = counter_delta(adreno_dev,
+					ADRENO_REG_RBBM_PERFCTR_PWR_1_LO,
+					&busy->gpu_busy);
+	if (device->pwrctrl.bus_control) {
+		data->vbif_ram_cycles = counter_delta(adreno_dev,
+					A3XX_VBIF_PERF_CNT0_LO,
+					&busy->vbif_ram_cycles);
+		data->vbif_starved_ram = counter_delta(adreno_dev,
+					A3XX_VBIF_PERF_PWR_CNT0_LO,
+					&busy->vbif_starved_ram);
+	}
+}
+
 struct a3xx_vbif_data {
 	unsigned int reg;
 	unsigned int val;
 };
-
 /* VBIF registers start after 0x3000 so use 0x0 as end of list marker */
 static struct a3xx_vbif_data a305_vbif[] = {
 	/* Set up 16 deep read/write request queues */
@@ -3789,27 +3955,123 @@
 	ARRAY_SIZE(a3xx_perfcounter_groups),
 };
 
-/*
- * a3xx_perfcounter_close() - Return counters that were initialized in
+static inline int _get_counter(struct adreno_device *adreno_dev,
+		int group, int countable, unsigned int *lo,
+		unsigned int *hi)
+{
+	int ret = 0;
+
+	if (*lo == 0) {
+		*hi = 0;
+
+		ret = adreno_perfcounter_get(adreno_dev, group, countable,
+			lo, PERFCOUNTER_FLAG_KERNEL);
+
+		if (ret == 0)
+			*hi = *lo + 1;
+		else {
+			struct kgsl_device *device = &adreno_dev->dev;
+
+			KGSL_DRV_ERR(device,
+				"Unable to allocate fault detect performance counter %d/%d\n",
+				group, countable);
+			KGSL_DRV_ERR(device,
+				"GPU fault detect will be less reliable\n");
+		}
+	}
+
+	return ret;
+}
+
+static inline void _put_counter(struct adreno_device *adreno_dev,
+		int group, int countable, unsigned int *lo,
+		unsigned int *hi)
+{
+	if (*lo != 0) {
+		adreno_perfcounter_put(adreno_dev, group, countable,
+			PERFCOUNTER_FLAG_KERNEL);
+	}
+
+	*lo = 0;
+	*hi = 0;
+}
+
+/**
+ * a3xx_fault_detect_start() - Allocate performance counters used for fast fault
+ * detection
+ * @adreno_dev: Pointer to an adreno_device structure
+ *
+ * Allocate the series of performance counters that should be periodically
+ * checked to verify that the GPU is still moving
+ */
+void a3xx_fault_detect_start(struct adreno_device *adreno_dev)
+{
+	_get_counter(adreno_dev, KGSL_PERFCOUNTER_GROUP_SP,
+		SP_ALU_ACTIVE_CYCLES,
+		&ft_detect_regs[6], &ft_detect_regs[7]);
+
+	_get_counter(adreno_dev, KGSL_PERFCOUNTER_GROUP_SP,
+		SP0_ICL1_MISSES,
+		&ft_detect_regs[8], &ft_detect_regs[9]);
+
+	_get_counter(adreno_dev, KGSL_PERFCOUNTER_GROUP_SP,
+		SP_FS_CFLOW_INSTRUCTIONS,
+		&ft_detect_regs[10], &ft_detect_regs[11]);
+
+	_get_counter(adreno_dev, KGSL_PERFCOUNTER_GROUP_TSE,
+		TSE_INPUT_PRIM_NUM,
+		&ft_detect_regs[12], &ft_detect_regs[13]);
+}
+/**
+ * a3xx_fault_detect_stop() - Release performance counters used for fast fault
+ * detection
+ * @adreno_dev: Pointer to an adreno_device structure
+ *
+ * Release the counters allocated in a3xx_fault_detect_start
+ */
+void a3xx_fault_detect_stop(struct adreno_device *adreno_dev)
+{
+	_put_counter(adreno_dev, KGSL_PERFCOUNTER_GROUP_SP,
+		SP_ALU_ACTIVE_CYCLES,
+		&ft_detect_regs[6], &ft_detect_regs[7]);
+
+	_put_counter(adreno_dev, KGSL_PERFCOUNTER_GROUP_SP,
+		SP0_ICL1_MISSES,
+		&ft_detect_regs[8], &ft_detect_regs[9]);
+
+	_put_counter(adreno_dev, KGSL_PERFCOUNTER_GROUP_SP,
+		SP_FS_CFLOW_INSTRUCTIONS,
+		&ft_detect_regs[10], &ft_detect_regs[11]);
+
+	_put_counter(adreno_dev, KGSL_PERFCOUNTER_GROUP_TSE,
+		TSE_INPUT_PRIM_NUM,
+		&ft_detect_regs[12], &ft_detect_regs[13]);
+}
+
+/**
+ * a3xx_perfcounter_close() - Put counters that were initialized in
  * a3xx_perfcounter_init
- * @adreno_dev: The device for which counters were initialized
+ * @adreno_dev: Pointer to an adreno_device structure
  */
 static void a3xx_perfcounter_close(struct adreno_device *adreno_dev)
 {
-	adreno_perfcounter_put(adreno_dev, KGSL_PERFCOUNTER_GROUP_SP,
-		SP_FS_FULL_ALU_INSTRUCTIONS,
+	adreno_perfcounter_put(adreno_dev, KGSL_PERFCOUNTER_GROUP_PWR, 1,
 		PERFCOUNTER_FLAG_KERNEL);
-	adreno_perfcounter_put(adreno_dev, KGSL_PERFCOUNTER_GROUP_SP,
-		SP_FS_CFLOW_INSTRUCTIONS,
+
+	adreno_perfcounter_put(adreno_dev, KGSL_PERFCOUNTER_GROUP_VBIF_PWR, 0,
 		PERFCOUNTER_FLAG_KERNEL);
-	adreno_perfcounter_put(adreno_dev, KGSL_PERFCOUNTER_GROUP_SP,
-		SP0_ICL1_MISSES,
-		PERFCOUNTER_FLAG_KERNEL);
-	adreno_perfcounter_put(adreno_dev, KGSL_PERFCOUNTER_GROUP_SP,
-		SP_ALU_ACTIVE_CYCLES,
-		PERFCOUNTER_FLAG_KERNEL);
+
+	adreno_perfcounter_put(adreno_dev, KGSL_PERFCOUNTER_GROUP_VBIF,
+		VBIF_AXI_TOTAL_BEATS, PERFCOUNTER_FLAG_KERNEL);
+
+	if (adreno_dev->fast_hang_detect)
+		a3xx_fault_detect_stop(adreno_dev);
 }
 
+/**
+ * a3xx_perfcounter_init() - Allocate performance counters for use in the kernel
+ * @adreno_dev: Pointer to an adreno_device structure
+ */
 static int a3xx_perfcounter_init(struct adreno_device *adreno_dev)
 {
 	int ret;
@@ -3817,57 +4079,25 @@
 	if (adreno_is_a330(adreno_dev))
 		a3xx_perfcounters_sp[3].countable = KGSL_PERFCOUNTER_BROKEN;
 
-	/*
-	 * Set SP to count SP_ALU_ACTIVE_CYCLES, it includes
-	 * all ALU instruction execution regardless precision or shader ID.
-	 * Set SP to count SP0_ICL1_MISSES, It counts
-	 * USP L1 instruction miss request.
-	 * Set SP to count SP_FS_FULL_ALU_INSTRUCTIONS, it
-	 * counts USP flow control instruction execution.
-	 * we will use this to augment our hang detection
-	 */
-	if (adreno_dev->fast_hang_detect) {
-		ret = adreno_perfcounter_get(adreno_dev,
-			KGSL_PERFCOUNTER_GROUP_SP,
-			SP_ALU_ACTIVE_CYCLES, &ft_detect_regs[6],
-			PERFCOUNTER_FLAG_KERNEL);
-		if (ret)
-			goto err;
-		ft_detect_regs[7] = ft_detect_regs[6] + 1;
-		ret = adreno_perfcounter_get(adreno_dev,
-			KGSL_PERFCOUNTER_GROUP_SP,
-			SP0_ICL1_MISSES, &ft_detect_regs[8],
-			PERFCOUNTER_FLAG_KERNEL);
-		if (ret)
-			goto err;
-		ft_detect_regs[9] = ft_detect_regs[8] + 1;
-		ret = adreno_perfcounter_get(adreno_dev,
-			KGSL_PERFCOUNTER_GROUP_SP,
-			SP_FS_CFLOW_INSTRUCTIONS, &ft_detect_regs[10],
-			PERFCOUNTER_FLAG_KERNEL);
-		if (ret)
-			goto err;
-		ft_detect_regs[11] = ft_detect_regs[10] + 1;
-	}
-
-	ret = adreno_perfcounter_get(adreno_dev, KGSL_PERFCOUNTER_GROUP_SP,
-		SP_FS_FULL_ALU_INSTRUCTIONS, NULL, PERFCOUNTER_FLAG_KERNEL);
-	if (ret)
-		goto err;
+	if (adreno_dev->fast_hang_detect)
+		a3xx_fault_detect_start(adreno_dev);
 
 	/* Reserve and start countable 1 in the PWR perfcounter group */
 	ret = adreno_perfcounter_get(adreno_dev, KGSL_PERFCOUNTER_GROUP_PWR, 1,
 			NULL, PERFCOUNTER_FLAG_KERNEL);
-	if (ret)
-		goto err;
+
+	/* VBIF waiting for RAM */
+	ret |= adreno_perfcounter_get(adreno_dev,
+				KGSL_PERFCOUNTER_GROUP_VBIF_PWR, 0,
+				NULL, PERFCOUNTER_FLAG_KERNEL);
+	/* VBIF DDR cycles */
+	ret |= adreno_perfcounter_get(adreno_dev, KGSL_PERFCOUNTER_GROUP_VBIF,
+				VBIF_AXI_TOTAL_BEATS, NULL,
+				PERFCOUNTER_FLAG_KERNEL);
 
 	/* Default performance counter profiling to false */
 	adreno_dev->profile.enabled = false;
 	return ret;
-
-err:
-	a3xx_perfcounter_close(adreno_dev);
-	return ret;
 }
 
 /**
@@ -3971,14 +4201,14 @@
 	a3xx_protect_init(device);
 
 	/* Turn on performance counters */
-	kgsl_regwrite(device, A3XX_RBBM_PERFCTR_CTL, 0x01);
-
-	/* Turn on the GPU busy counter and let it run free */
-
-	adreno_dev->gpu_cycles = 0;
+	kgsl_regwrite(device, A3XX_RBBM_PERFCTR_CTL, RBBM_PERF_ENABLE_MASK);
+	kgsl_regwrite(device, A3XX_VBIF_PERF_CNT_SEL,
+			_SET(VBIF_PERF_CNT_0_SEL, VBIF_AXI_TOTAL_BEATS));
+	kgsl_regwrite(device, A3XX_VBIF_PERF_CNT_EN, VBIF_PERF_MASK);
 
 	/* the CP_DEBUG register offset and value are same as A2XX */
 	kgsl_regwrite(device, REG_CP_DEBUG, A2XX_CP_DEBUG_DEFAULT);
+	memset(&adreno_dev->busy_data, 0, sizeof(adreno_dev->busy_data));
 }
 
 /**
@@ -4345,6 +4575,8 @@
 	.rb_init = a3xx_rb_init,
 	.perfcounter_init = a3xx_perfcounter_init,
 	.perfcounter_close = a3xx_perfcounter_close,
+	.perfcounter_save = a3xx_perfcounter_save,
+	.perfcounter_restore = a3xx_perfcounter_restore,
 	.irq_control = a3xx_irq_control,
 	.irq_handler = a3xx_irq_handler,
 	.irq_pending = a3xx_irq_pending,
@@ -4353,9 +4585,12 @@
 	.snapshot = a3xx_snapshot,
 	.perfcounter_enable = a3xx_perfcounter_enable,
 	.perfcounter_read = a3xx_perfcounter_read,
+	.perfcounter_write = a3xx_perfcounter_write,
 	.coresight_enable = a3xx_coresight_enable,
 	.coresight_disable = a3xx_coresight_disable,
 	.coresight_config_debug_reg = a3xx_coresight_config_debug_reg,
+	.fault_detect_start = a3xx_fault_detect_start,
+	.fault_detect_stop = a3xx_fault_detect_stop,
 	.soft_reset = a3xx_soft_reset,
 	.postmortem_dump = a3xx_postmortem_dump,
 };
diff --git a/drivers/gpu/msm/adreno_profile.c b/drivers/gpu/msm/adreno_profile.c
index 8d3efd6..28fd6d6 100644
--- a/drivers/gpu/msm/adreno_profile.c
+++ b/drivers/gpu/msm/adreno_profile.c
@@ -441,6 +441,11 @@
 					profile, *(ptr + buf_off++));
 			if (assigns_list == NULL) {
 				*log_ptr = (unsigned int) -1;
+
+				shared_buf_inc(profile->shared_size,
+					&profile->shared_tail,
+					SIZE_SHARED_ENTRY(cnt));
+
 				goto err;
 			} else {
 				*log_ptr = assigns_list->groupid << 16 |
diff --git a/drivers/gpu/msm/adreno_ringbuffer.c b/drivers/gpu/msm/adreno_ringbuffer.c
index a43bd54..1383a20 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.c
+++ b/drivers/gpu/msm/adreno_ringbuffer.c
@@ -368,61 +368,26 @@
  */
 void _ringbuffer_setup_common(struct adreno_ringbuffer *rb)
 {
-	union reg_cp_rb_cntl cp_rb_cntl;
-	unsigned int rb_cntl;
 	struct kgsl_device *device = rb->device;
 	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
 
-	kgsl_sharedmem_set(rb->device, &rb->memptrs_desc, 0, 0,
-			   sizeof(struct kgsl_rbmemptrs));
-
 	kgsl_sharedmem_set(rb->device, &rb->buffer_desc, 0, 0xAA,
 			   (rb->sizedwords << 2));
 
-	if (adreno_is_a2xx(adreno_dev)) {
-		kgsl_regwrite(device, REG_CP_RB_WPTR_BASE,
-			(rb->memptrs_desc.gpuaddr
-			+ GSL_RB_MEMPTRS_WPTRPOLL_OFFSET));
-
-		/* setup WPTR delay */
-		kgsl_regwrite(device, REG_CP_RB_WPTR_DELAY,
-			0 /*0x70000010 */);
-	}
-
-	/*setup REG_CP_RB_CNTL */
-	adreno_readreg(adreno_dev, ADRENO_REG_CP_RB_CNTL, &rb_cntl);
-	cp_rb_cntl.val = rb_cntl;
-
 	/*
 	 * The size of the ringbuffer in the hardware is the log2
-	 * representation of the size in quadwords (sizedwords / 2)
+	 * representation of the size in quadwords (sizedwords / 2).
+	 * Also disable the host RPTR shadow register as it might be unreliable
+	 * in certain circumstances.
 	 */
-	cp_rb_cntl.f.rb_bufsz = ilog2(rb->sizedwords >> 1);
 
-	/*
-	 * Specify the quadwords to read before updating mem RPTR.
-	 * Like above, pass the log2 representation of the blocksize
-	 * in quadwords.
-	*/
-	cp_rb_cntl.f.rb_blksz = ilog2(KGSL_RB_BLKSIZE >> 3);
-
-	if (adreno_is_a2xx(adreno_dev)) {
-		/* WPTR polling */
-		cp_rb_cntl.f.rb_poll_en = GSL_RB_CNTL_POLL_EN;
-	}
-
-	/* mem RPTR writebacks */
-	cp_rb_cntl.f.rb_no_update =  GSL_RB_CNTL_NO_UPDATE;
-
-	adreno_writereg(adreno_dev, ADRENO_REG_CP_RB_CNTL, cp_rb_cntl.val);
+	adreno_writereg(adreno_dev, ADRENO_REG_CP_RB_CNTL,
+		(ilog2(rb->sizedwords >> 1) & 0x3F) |
+		(1 << 27));
 
 	adreno_writereg(adreno_dev, ADRENO_REG_CP_RB_BASE,
 					rb->buffer_desc.gpuaddr);
 
-	adreno_writereg(adreno_dev, ADRENO_REG_CP_RB_RPTR_ADDR,
-				rb->memptrs_desc.gpuaddr +
-				GSL_RB_MEMPTRS_RPTR_OFFSET);
-
 	if (adreno_is_a2xx(adreno_dev)) {
 		/* explicitly clear all cp interrupts */
 		kgsl_regwrite(device, REG_CP_INT_ACK, 0xFFFFFFFF);
@@ -621,20 +586,6 @@
 		return status;
 	}
 
-	/* allocate memory for polling and timestamps */
-	/* This really can be at 4 byte alignment boundry but for using MMU
-	 * we need to make it at page boundary */
-	status = kgsl_allocate_contiguous(&rb->memptrs_desc,
-		sizeof(struct kgsl_rbmemptrs));
-
-	if (status != 0) {
-		adreno_ringbuffer_close(rb);
-		return status;
-	}
-
-	/* overlay structure on memptrs memory */
-	rb->memptrs = (struct kgsl_rbmemptrs *) rb->memptrs_desc.hostptr;
-
 	rb->global_ts = 0;
 
 	return 0;
@@ -645,7 +596,6 @@
 	struct adreno_device *adreno_dev = ADRENO_DEVICE(rb->device);
 
 	kgsl_sharedmem_free(&rb->buffer_desc);
-	kgsl_sharedmem_free(&rb->memptrs_desc);
 
 	kfree(adreno_dev->pfp_fw);
 	kfree(adreno_dev->pm4_fw);
@@ -1156,6 +1106,13 @@
 	/* wait for the suspend gate */
 	wait_for_completion(&device->cmdbatch_gate);
 
+	/*
+	 * Clear the wake on touch bit to indicate an IB has been submitted
+	 * since the last time we set it
+	 */
+
+	device->flags &= ~KGSL_FLAG_WAKE_ON_TOUCH;
+
 	/* Queue the command in the ringbuffer */
 	ret = adreno_dispatcher_queue_cmd(adreno_dev, drawctxt, cmdbatch,
 		timestamp);
diff --git a/drivers/gpu/msm/adreno_ringbuffer.h b/drivers/gpu/msm/adreno_ringbuffer.h
index eee4127..697e113 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.h
+++ b/drivers/gpu/msm/adreno_ringbuffer.h
@@ -19,7 +19,6 @@
  */
 
 #define KGSL_RB_SIZE (32 * 1024)
-#define KGSL_RB_BLKSIZE 16
 
 /* CP timestamp register */
 #define	REG_CP_TIMESTAMP		 REG_SCRATCH_REG0
@@ -28,27 +27,12 @@
 struct kgsl_device;
 struct kgsl_device_private;
 
-#define GSL_RB_MEMPTRS_SCRATCH_COUNT	 8
-struct kgsl_rbmemptrs {
-	int  rptr;
-	int  wptr_poll;
-};
-
-#define GSL_RB_MEMPTRS_RPTR_OFFSET \
-	(offsetof(struct kgsl_rbmemptrs, rptr))
-
-#define GSL_RB_MEMPTRS_WPTRPOLL_OFFSET \
-	(offsetof(struct kgsl_rbmemptrs, wptr_poll))
-
 struct adreno_ringbuffer {
 	struct kgsl_device *device;
 	uint32_t flags;
 
 	struct kgsl_memdesc buffer_desc;
 
-	struct kgsl_memdesc memptrs_desc;
-	struct kgsl_rbmemptrs *memptrs;
-
 	/*ringbuffer size */
 	unsigned int sizedwords;
 
@@ -70,25 +54,6 @@
 /* enable timestamp (...scratch0) memory shadowing */
 #define GSL_RB_MEMPTRS_SCRATCH_MASK 0x1
 
-/* mem rptr */
-#define GSL_RB_CNTL_NO_UPDATE 0x0 /* enable */
-
-/**
- * adreno_get_rptr - Get the current ringbuffer read pointer
- * @rb -  the ringbuffer
- *
- * Get the current read pointer, which is written by the GPU.
- */
-static inline unsigned int
-adreno_get_rptr(struct adreno_ringbuffer *rb)
-{
-	unsigned int result = rb->memptrs->rptr;
-	rmb();
-	return result;
-}
-
-#define GSL_RB_CNTL_POLL_EN 0x0 /* disable */
-
 /*
  * protected mode error checking below register address 0x800
  * note: if CP_INTERRUPT packet is used then checking needs
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index fe6b34c..fe99a4b 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -60,6 +60,9 @@
 	struct sg_table *table;
 };
 
+static void kgsl_put_process_private(struct kgsl_device *device,
+			 struct kgsl_process_private *private);
+
 static void kgsl_mem_entry_detach_process(struct kgsl_mem_entry *entry);
 
 static void
@@ -341,14 +344,19 @@
  */
 static int
 kgsl_mem_entry_attach_process(struct kgsl_mem_entry *entry,
-				   struct kgsl_process_private *process)
+				   struct kgsl_device_private *dev_priv)
 {
 	int ret;
+	struct kgsl_process_private *process = dev_priv->process_priv;
+	
+	ret = kref_get_unless_zero(&process->refcount);
+	if (!ret)
+		return -EBADF;
 
 	while (1) {
 		if (idr_pre_get(&process->mem_idr, GFP_KERNEL) == 0) {
 			ret = -ENOMEM;
-			goto err;
+			goto err_put_proc_priv;
 		}
 
 		spin_lock(&process->mem_lock);
@@ -359,9 +367,10 @@
 		if (ret == 0)
 			break;
 		else if (ret != -EAGAIN)
-			goto err;
+			goto err_put_proc_priv;
 	}
 	entry->priv = process;
+	entry->dev_priv = dev_priv;
 
 	spin_lock(&process->mem_lock);
 	ret = kgsl_mem_entry_track_gpuaddr(process, entry);
@@ -369,14 +378,17 @@
 		idr_remove(&process->mem_idr, entry->id);
 	spin_unlock(&process->mem_lock);
 	if (ret)
-		goto err;
+		goto err_put_proc_priv;
 	/* map the memory after unlocking if gpuaddr has been assigned */
 	if (entry->memdesc.gpuaddr) {
 		ret = kgsl_mmu_map(process->pagetable, &entry->memdesc);
 		if (ret)
 			kgsl_mem_entry_detach_process(entry);
 	}
-err:
+	return ret;
+
+err_put_proc_priv:
+	kgsl_put_process_private(dev_priv->device, process);
 	return ret;
 }
 
@@ -399,6 +411,7 @@
 
 	entry->priv->stats[entry->memtype].cur -= entry->memdesc.size;
 	spin_unlock(&entry->priv->mem_lock);
+	kgsl_put_process_private(entry->dev_priv->device, entry->priv);
 
 	entry->priv = NULL;
 }
@@ -605,7 +618,6 @@
 static int kgsl_suspend_device(struct kgsl_device *device, pm_message_t state)
 {
 	int status = -EINVAL;
-	struct kgsl_pwrscale_policy *policy_saved;
 
 	if (!device)
 		return -EINVAL;
@@ -613,8 +625,6 @@
 	KGSL_PWR_WARN(device, "suspend start\n");
 
 	mutex_lock(&device->mutex);
-	policy_saved = device->pwrscale.policy;
-	device->pwrscale.policy = NULL;
 	kgsl_pwrctrl_request_state(device, KGSL_STATE_SUSPEND);
 
 	/* Tell the device to drain the submission queue */
@@ -659,7 +669,7 @@
 			goto end;
 	}
 	kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE);
-	device->pwrscale.policy = policy_saved;
+	kgsl_pwrscale_sleep(device);
 	status = 0;
 
 end:
@@ -767,11 +777,6 @@
  */
 static void kgsl_destroy_process_private(struct kref *kref)
 {
-
-	struct kgsl_mem_entry *entry = NULL;
-	int next = 0;
-
-
 	struct kgsl_process_private *private = container_of(kref,
 			struct kgsl_process_private, refcount);
 
@@ -795,20 +800,6 @@
 	if (private->debug_root)
 		debugfs_remove_recursive(private->debug_root);
 
-	while (1) {
-		spin_lock(&private->mem_lock);
-		entry = idr_get_next(&private->mem_idr, &next);
-		spin_unlock(&private->mem_lock);
-		if (entry == NULL)
-			break;
-		kgsl_mem_entry_put(entry);
-		/*
-		 * Always start back at the beginning, to
-		 * ensure all entries are removed,
-		 * like list_for_each_entry_safe.
-		 */
-		next = 0;
-	}
 	idr_destroy(&private->mem_idr);
 	kgsl_mmu_putpagetable(private->pagetable);
 
@@ -953,6 +944,7 @@
 	struct kgsl_process_private *private = dev_priv->process_priv;
 	struct kgsl_device *device = dev_priv->device;
 	struct kgsl_context *context;
+	struct kgsl_mem_entry *entry;
 	int next = 0;
 
 	filep->private_data = NULL;
@@ -981,6 +973,25 @@
 
 		next = next + 1;
 	}
+	next = 0;
+	while (1) {
+		spin_lock(&private->mem_lock);
+		entry = idr_get_next(&private->mem_idr, &next);
+		spin_unlock(&private->mem_lock);
+		if (entry == NULL)
+			break;
+		/*
+		 * If the free pending flag is not set it means that user space
+		 * did not free it's reference to this entry, in that case
+		 * free a reference to this entry, other references are from
+		 * within kgsl so they will be freed eventually by kgsl
+		 */
+		if (entry->dev_priv == dev_priv && !entry->pending_free) {
+			entry->pending_free = 1;
+			kgsl_mem_entry_put(entry);
+		}
+		next = next + 1;
+	}
 	/*
 	 * Clean up any to-be-freed entries that belong to this
 	 * process and this device. This is done after the context
@@ -1017,7 +1028,7 @@
 		if (result)
 			goto err;
 
-		result = device->ftbl->start(device);
+		result = device->ftbl->start(device, 0);
 		if (result)
 			goto err;
 		/*
@@ -2743,7 +2754,7 @@
 	/* echo back flags */
 	param->flags = entry->memdesc.flags;
 
-	result = kgsl_mem_entry_attach_process(entry, private);
+	result = kgsl_mem_entry_attach_process(entry, dev_priv);
 	if (result)
 		goto error_attach;
 
@@ -3031,7 +3042,7 @@
 	if (result)
 		return result;
 
-	result = kgsl_mem_entry_attach_process(entry, private);
+	result = kgsl_mem_entry_attach_process(entry, dev_priv);
 	if (result != 0)
 		goto err;
 
@@ -3064,7 +3075,7 @@
 	if (result != 0)
 		goto err;
 
-	result = kgsl_mem_entry_attach_process(entry, private);
+	result = kgsl_mem_entry_attach_process(entry, dev_priv);
 	if (result != 0)
 		goto err;
 
@@ -4054,7 +4065,7 @@
 	del_timer_sync(&device->idle_timer);
 
 	/* Force on the clocks */
-	kgsl_pwrctrl_wake(device);
+	kgsl_pwrctrl_wake(device, 0);
 
 	/* Disable the irq */
 	kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_OFF);
diff --git a/drivers/gpu/msm/kgsl.h b/drivers/gpu/msm/kgsl.h
index ee7a485..6da4a86 100644
--- a/drivers/gpu/msm/kgsl.h
+++ b/drivers/gpu/msm/kgsl.h
@@ -200,6 +200,7 @@
 	struct kgsl_process_private *priv;
 	/* Initialized to 0, set to 1 when entry is marked for freeing */
 	int pending_free;
+	struct kgsl_device_private *dev_priv;
 };
 
 #ifdef CONFIG_MSM_KGSL_MMU_PAGE_FAULT
diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h
index f87c64c..7fc6fae 100644
--- a/drivers/gpu/msm/kgsl_device.h
+++ b/drivers/gpu/msm/kgsl_device.h
@@ -62,6 +62,8 @@
 #define KGSL_EVENT_TIMESTAMP_RETIRED 0
 #define KGSL_EVENT_CANCELLED 1
 
+#define KGSL_FLAG_WAKE_ON_TOUCH BIT(0)
+
 /*
  * "list" of event types for ftrace symbolic magic
  */
@@ -91,7 +93,7 @@
 	bool (*isidle) (struct kgsl_device *device);
 	int (*suspend_context) (struct kgsl_device *device);
 	int (*init) (struct kgsl_device *device);
-	int (*start) (struct kgsl_device *device);
+	int (*start) (struct kgsl_device *device, int priority);
 	int (*stop) (struct kgsl_device *device);
 	int (*getproperty) (struct kgsl_device *device,
 		enum kgsl_property_type type, void *value,
@@ -292,7 +294,6 @@
 	struct list_head events;
 	struct list_head events_pending_list;
 	unsigned int events_last_timestamp;
-	s64 on_time;
 
 	/* Postmortem Control switches */
 	int pm_regs_enabled;
@@ -418,11 +419,6 @@
 	struct kgsl_process_private *process_priv;
 };
 
-struct kgsl_power_stats {
-	s64 total_time;
-	s64 busy_time;
-};
-
 struct kgsl_device *kgsl_get_device(int dev_idx);
 
 int kgsl_add_event(struct kgsl_device *device, u32 id, u32 ts,
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c
index 8ed29fb..3e15580 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.c
+++ b/drivers/gpu/msm/kgsl_pwrctrl.c
@@ -17,6 +17,7 @@
 #include <linux/pm_runtime.h>
 #include <mach/msm_iomap.h>
 #include <mach/msm_bus.h>
+#include <mach/msm_bus_board.h>
 #include <linux/ktime.h>
 #include <linux/delay.h>
 
@@ -123,13 +124,34 @@
 	return level;
 }
 
+void kgsl_pwrctrl_buslevel_update(struct kgsl_device *device,
+			bool on)
+{
+	struct kgsl_pwrctrl *pwr = &device->pwrctrl;
+	int cur = pwr->pwrlevels[pwr->active_pwrlevel].bus_freq;
+	int buslevel = 0;
+	if (!pwr->pcl)
+		return;
+	/*
+	 * If the bus should remain on calculate our request and submit it,
+	 * otherwise request bus level 0, off.
+	 */
+	if (on) {
+		buslevel = min_t(int, pwr->pwrlevels[0].bus_freq,
+				cur + pwr->bus_mod);
+		buslevel = max_t(int, buslevel, 1);
+	}
+	msm_bus_scale_client_update_request(pwr->pcl, buslevel);
+	trace_kgsl_pwrlevel(device, pwr->active_pwrlevel, buslevel);
+}
+EXPORT_SYMBOL(kgsl_pwrctrl_buslevel_update);
+
 void kgsl_pwrctrl_pwrlevel_change(struct kgsl_device *device,
 				unsigned int new_level)
 {
 	struct kgsl_pwrctrl *pwr = &device->pwrctrl;
 	struct kgsl_pwrlevel *pwrlevel;
-	int delta;
-	int level;
+	int delta, level;
 
 	/* Adjust the power level to the current constraints */
 	new_level = _adjust_pwrlevel(pwr, new_level);
@@ -150,14 +172,12 @@
 	 */
 
 	pwr->active_pwrlevel = new_level;
+	pwr->bus_mod = 0;
 	pwrlevel = &pwr->pwrlevels[pwr->active_pwrlevel];
 
 	if (test_bit(KGSL_PWRFLAGS_AXI_ON, &pwr->power_flags)) {
-
-		if (pwr->pcl)
-			msm_bus_scale_client_update_request(pwr->pcl,
-				pwrlevel->bus_freq);
-		else if (pwr->ebi1_clk)
+		kgsl_pwrctrl_buslevel_update(device, true);
+		if (pwr->ebi1_clk)
 			clk_set_rate(pwr->ebi1_clk, pwrlevel->bus_freq);
 	}
 
@@ -226,11 +246,8 @@
 	 * a policy only change the active clock if it is higher then the new
 	 * thermal level
 	 */
-
-	if (device->pwrscale.policy == NULL ||
-		pwr->thermal_pwrlevel > pwr->active_pwrlevel)
+	if (pwr->thermal_pwrlevel > pwr->active_pwrlevel)
 		kgsl_pwrctrl_pwrlevel_change(device, pwr->thermal_pwrlevel);
-
 	mutex_unlock(&device->mutex);
 
 	return count;
@@ -285,11 +302,8 @@
 	 * If there is no policy then move to max by default.  Otherwise only
 	 * move max if the current level happens to be higher then the new max
 	 */
-
-	if (device->pwrscale.policy == NULL ||
-		(max_level > pwr->active_pwrlevel))
+	if (max_level > pwr->active_pwrlevel)
 		kgsl_pwrctrl_pwrlevel_change(device, max_level);
-
 	mutex_unlock(&device->mutex);
 
 	return count;
@@ -479,8 +493,7 @@
 	if (device == NULL)
 		return 0;
 	pwr = &device->pwrctrl;
-	return snprintf(buf, PAGE_SIZE, "%d\n",
-			pwr->pwrlevels[pwr->active_pwrlevel].gpu_freq);
+	return snprintf(buf, PAGE_SIZE, "%ld\n", kgsl_pwrctrl_active_freq(pwr));
 }
 
 static int kgsl_pwrctrl_idle_timer_store(struct device *dev,
@@ -742,6 +755,42 @@
 	return __force_on_store(dev, attr, buf, count, KGSL_PWRFLAGS_POWER_ON);
 }
 
+static ssize_t kgsl_pwrctrl_bus_split_show(struct device *dev,
+					struct device_attribute *attr,
+					char *buf)
+{
+	struct kgsl_device *device = kgsl_device_from_dev(dev);
+	if (device == NULL)
+		return 0;
+	return snprintf(buf, PAGE_SIZE, "%d\n",
+		device->pwrctrl.bus_control);
+}
+
+static ssize_t kgsl_pwrctrl_bus_split_store(struct device *dev,
+					struct device_attribute *attr,
+					const char *buf, size_t count)
+{
+	char temp[20];
+	unsigned long val;
+	struct kgsl_device *device = kgsl_device_from_dev(dev);
+	int rc;
+
+	if (device == NULL)
+		return 0;
+
+	snprintf(temp, sizeof(temp), "%.*s",
+			(int)min(count, sizeof(temp) - 1), buf);
+	rc = kstrtoul(temp, 0, &val);
+	if (rc)
+		return rc;
+
+	mutex_lock(&device->mutex);
+	device->pwrctrl.bus_control = val ? true : false;
+	mutex_unlock(&device->mutex);
+
+	return count;
+}
+
 DEVICE_ATTR(gpuclk, 0644, kgsl_pwrctrl_gpuclk_show, kgsl_pwrctrl_gpuclk_store);
 DEVICE_ATTR(max_gpuclk, 0644, kgsl_pwrctrl_max_gpuclk_show,
 	kgsl_pwrctrl_max_gpuclk_store);
@@ -781,6 +830,9 @@
 DEVICE_ATTR(force_rail_on, 0644,
 	kgsl_pwrctrl_force_rail_on_show,
 	kgsl_pwrctrl_force_rail_on_store);
+DEVICE_ATTR(bus_split, 0644,
+	kgsl_pwrctrl_bus_split_show,
+	kgsl_pwrctrl_bus_split_store);
 
 static const struct device_attribute *pwrctrl_attr_list[] = {
 	&dev_attr_gpuclk,
@@ -798,6 +850,7 @@
 	&dev_attr_force_clk_on,
 	&dev_attr_force_bus_on,
 	&dev_attr_force_rail_on,
+	&dev_attr_bus_split,
 	NULL
 };
 
@@ -924,9 +977,7 @@
 				clk_set_rate(pwr->ebi1_clk, 0);
 				clk_disable_unprepare(pwr->ebi1_clk);
 			}
-			if (pwr->pcl)
-				msm_bus_scale_client_update_request(pwr->pcl,
-								    0);
+			kgsl_pwrctrl_buslevel_update(device, false);
 		}
 	} else if (state == KGSL_PWRFLAGS_ON) {
 		if (!test_and_set_bit(KGSL_PWRFLAGS_AXI_ON,
@@ -938,10 +989,7 @@
 					pwr->pwrlevels[pwr->active_pwrlevel].
 					bus_freq);
 			}
-			if (pwr->pcl)
-				msm_bus_scale_client_update_request(pwr->pcl,
-					pwr->pwrlevels[pwr->active_pwrlevel].
-						bus_freq);
+			kgsl_pwrctrl_buslevel_update(device, true);
 		}
 	}
 }
@@ -1011,7 +1059,7 @@
 
 int kgsl_pwrctrl_init(struct kgsl_device *device)
 {
-	int i, result = 0;
+	int i, k, m, n = 0, result = 0;
 	struct clk *clk;
 	struct platform_device *pdev =
 		container_of(device->parentdev, struct platform_device, dev);
@@ -1092,26 +1140,61 @@
 		clk_set_rate(pwr->ebi1_clk,
 					 pwr->pwrlevels[pwr->active_pwrlevel].
 						bus_freq);
-	if (pdata->bus_scale_table != NULL) {
-		pwr->pcl = msm_bus_scale_register_client(pdata->
-							bus_scale_table);
-		if (!pwr->pcl) {
-			KGSL_PWR_ERR(device,
-					"msm_bus_scale_register_client failed: "
-					"id %d table %p", device->id,
-					pdata->bus_scale_table);
-			result = -EINVAL;
-			goto done;
-		}
-	}
-
-	/* Set the power level step multiplier with 1 as the default */
-	pwr->step_mul = pdata->step_mul ? pdata->step_mul : 1;
 
 	/* Set the CPU latency to 501usec to allow low latency PC modes */
 	pwr->pm_qos_latency = 501;
 
 	pm_runtime_enable(device->parentdev);
+
+	if (pdata->bus_scale_table == NULL)
+		return result;
+
+	pwr->pcl = msm_bus_scale_register_client(pdata->
+						bus_scale_table);
+	if (!pwr->pcl) {
+		KGSL_PWR_ERR(device,
+				"msm_bus_scale_register_client failed: "
+				"id %d table %p", device->id,
+				pdata->bus_scale_table);
+		result = -EINVAL;
+		goto done;
+	}
+
+	/* Set if independent bus BW voting is supported */
+	pwr->bus_control = pdata->bus_control;
+	/*
+	 * Pull the BW vote out of the bus table.  They will be used to
+	 * calculate the ratio between the votes.
+	 */
+	for (i = 0; i < pdata->bus_scale_table->num_usecases; i++) {
+		struct msm_bus_paths *usecase =
+				&pdata->bus_scale_table->usecase[i];
+		struct msm_bus_vectors *vector = &usecase->vectors[0];
+		if (vector->dst == MSM_BUS_SLAVE_EBI_CH0 &&
+				vector->ib != 0) {
+			for (k = 0; k < n; k++)
+				if (vector->ib == pwr->bus_ib[k])
+					break;
+			/* if this is a new ib value, save it */
+			if (k == n) {
+				pwr->bus_ib[k] = vector->ib;
+				n++;
+				/* find which pwrlevels use this ib */
+				for (m = 0; m < pwr->num_pwrlevels - 1; m++) {
+					if (pdata->bus_scale_table->
+						usecase[pwr->pwrlevels[m].
+						bus_freq].vectors[0].ib
+						== vector->ib)
+						pwr->bus_index[m] = k;
+				}
+				printk("kgsl bus ib [%d] = %llu\n", k, vector->ib);
+			}
+		}
+	}
+
+	for (m = 0; m < pwr->num_pwrlevels - 1; m++)
+		printk("kgsl bus index is %d for pwrlevel %d\n", pwr->bus_index[m], m);
+
 	return result;
 
 clk_err:
@@ -1179,7 +1262,7 @@
 
 	mutex_lock(&device->mutex);
 
-	kgsl_pwrscale_idle(device);
+	kgsl_pwrscale_update(device);
 
 	if (device->state == KGSL_STATE_ACTIVE
 		   || device->state ==  KGSL_STATE_NAP) {
@@ -1275,12 +1358,25 @@
 static int
 _nap(struct kgsl_device *device)
 {
+	struct kgsl_power_stats stats;
+
 	switch (device->state) {
 	case KGSL_STATE_ACTIVE:
 		if (!device->ftbl->isidle(device)) {
 			kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE);
 			return -EBUSY;
 		}
+
+		/*
+		 * Read HW busy counters before going to NAP state.
+		 * The data might be used by power scale governors
+		 * independently of the HW activity. For example
+		 * the simple-on-demand governor will get the latest
+		 * busy_time data even if the gpu isn't active.
+		*/
+		device->ftbl->power_stats(device, &stats);
+		device->pwrscale.accum_stats.busy_time += stats.busy_time;
+
 		kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_OFF);
 		kgsl_pwrctrl_clk(device, KGSL_PWRFLAGS_OFF, KGSL_STATE_NAP);
 		kgsl_pwrctrl_set_state(device, KGSL_STATE_NAP);
@@ -1300,7 +1396,7 @@
 {
 	kgsl_pwrctrl_busy_time(device, false);
 	device->pwrctrl.clk_stats.start = ktime_set(0, 0);
-	device->pwrctrl.time = 0;
+
 	kgsl_pwrscale_sleep(device);
 }
 
@@ -1398,9 +1494,16 @@
 }
 EXPORT_SYMBOL(kgsl_pwrctrl_sleep);
 
-/******************************************************************/
-/* Caller must hold the device mutex. */
-int kgsl_pwrctrl_wake(struct kgsl_device *device)
+/**
+ * kgsl_pwrctrl_wake() - Power up the GPU from a slumber/sleep state
+ * @device - Pointer to the kgsl_device struct
+ * @priority - Boolean flag to indicate that the GPU start should be run in the
+ * higher priority thread
+ *
+ * Resume the GPU from a lower power state to ACTIVE.  The caller to this
+ * fucntion must host the kgsl_device mutex.
+ */
+int kgsl_pwrctrl_wake(struct kgsl_device *device, int priority)
 {
 	int status = 0;
 	unsigned int context_id;
@@ -1411,7 +1514,8 @@
 	kgsl_pwrctrl_request_state(device, KGSL_STATE_ACTIVE);
 	switch (device->state) {
 	case KGSL_STATE_SLUMBER:
-		status = device->ftbl->start(device);
+		status = device->ftbl->start(device, priority);
+
 		if (status) {
 			kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE);
 			KGSL_DRV_ERR(device, "start failed %d\n", status);
@@ -1465,7 +1569,7 @@
 	struct kgsl_pwrctrl *pwr = &device->pwrctrl;
 	/* Order pwrrail/clk sequence based upon platform */
 	kgsl_pwrctrl_pwrrail(device, KGSL_PWRFLAGS_ON);
-	kgsl_pwrctrl_pwrlevel_change(device, pwr->default_pwrlevel);
+	kgsl_pwrctrl_pwrlevel_change(device, pwr->active_pwrlevel);
 	kgsl_pwrctrl_clk(device, KGSL_PWRFLAGS_ON, KGSL_STATE_ACTIVE);
 	kgsl_pwrctrl_axi(device, KGSL_PWRFLAGS_ON);
 }
@@ -1544,7 +1648,7 @@
 		wait_for_completion(&device->hwaccess_gate);
 		mutex_lock(&device->mutex);
 
-		ret = kgsl_pwrctrl_wake(device);
+		ret = kgsl_pwrctrl_wake(device, 1);
 	}
 	if (ret == 0)
 		atomic_inc(&device->active_cnt);
@@ -1591,8 +1695,6 @@
 	BUG_ON(!mutex_is_locked(&device->mutex));
 	BUG_ON(atomic_read(&device->active_cnt) == 0);
 
-	kgsl_pwrscale_idle(device);
-
 	if (atomic_dec_and_test(&device->active_cnt)) {
 		if (device->state == KGSL_STATE_ACTIVE &&
 			device->requested_state == KGSL_STATE_NONE) {
@@ -1602,6 +1704,8 @@
 
 		mod_timer(&device->idle_timer,
 			jiffies + device->pwrctrl.interval_timeout);
+	} else {
+		kgsl_pwrscale_update(device);
 	}
 
 	trace_kgsl_active_count(device,
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.h b/drivers/gpu/msm/kgsl_pwrctrl.h
index 9f18160..6ec809d 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.h
+++ b/drivers/gpu/msm/kgsl_pwrctrl.h
@@ -64,7 +64,9 @@
  * @clk_stats - structure of clock statistics
  * @pm_qos_req_dma - the power management quality of service structure
  * @pm_qos_latency - allowed CPU latency in microseconds
- * @step_mul - multiplier for moving between power levels
+ * @bus_control - true if the bus calculation is independent
+ * @bus_index - default bus index into the bus_ib table
+ * @bus_ib - the set of unique ib requests needed for the bus calculation
  */
 
 struct kgsl_pwrctrl {
@@ -88,12 +90,14 @@
 	uint32_t pcl;
 	unsigned int idle_needed;
 	const char *irq_name;
-	s64 time;
+	bool irq_last;
 	struct kgsl_clk_stats clk_stats;
 	struct pm_qos_request pm_qos_req_dma;
 	unsigned int pm_qos_latency;
-	unsigned int step_mul;
-	unsigned int irq_last;
+	bool bus_control;
+	int bus_mod;
+	unsigned int bus_index[KGSL_MAX_PWRLEVELS];
+	uint64_t bus_ib[KGSL_MAX_PWRLEVELS];
 };
 
 void kgsl_pwrctrl_irq(struct kgsl_device *device, int state);
@@ -103,9 +107,11 @@
 void kgsl_idle_check(struct work_struct *work);
 void kgsl_pre_hwaccess(struct kgsl_device *device);
 int kgsl_pwrctrl_sleep(struct kgsl_device *device);
-int kgsl_pwrctrl_wake(struct kgsl_device *device);
+int kgsl_pwrctrl_wake(struct kgsl_device *device, int priority);
 void kgsl_pwrctrl_pwrlevel_change(struct kgsl_device *device,
 	unsigned int level);
+void kgsl_pwrctrl_buslevel_update(struct kgsl_device *device,
+	bool on);
 int kgsl_pwrctrl_init_sysfs(struct kgsl_device *device);
 void kgsl_pwrctrl_uninit_sysfs(struct kgsl_device *device);
 void kgsl_pwrctrl_enable(struct kgsl_device *device);
@@ -117,6 +123,18 @@
 	return (clk != NULL) ? clk_get_rate(clk) : 0;
 }
 
+/*
+ * kgsl_pwrctrl_active_freq - get currently configured frequency
+ * @pwr: kgsl_pwrctrl structure for the device
+ *
+ * Returns the currently configured frequency for the device.
+ */
+static inline unsigned long
+kgsl_pwrctrl_active_freq(struct kgsl_pwrctrl *pwr)
+{
+	return pwr->pwrlevels[pwr->active_pwrlevel].gpu_freq;
+}
+
 void kgsl_pwrctrl_set_state(struct kgsl_device *device, unsigned int state);
 void kgsl_pwrctrl_request_state(struct kgsl_device *device, unsigned int state);
 
diff --git a/drivers/gpu/msm/kgsl_pwrscale.c b/drivers/gpu/msm/kgsl_pwrscale.c
index 47554c4..52732cf 100644
--- a/drivers/gpu/msm/kgsl_pwrscale.c
+++ b/drivers/gpu/msm/kgsl_pwrscale.c
@@ -14,364 +14,497 @@
 #include <linux/export.h>
 #include <linux/kernel.h>
 
-#include <asm/page.h>
-
 #include "kgsl.h"
 #include "kgsl_pwrscale.h"
 #include "kgsl_device.h"
+#include "kgsl_trace.h"
 
-struct kgsl_pwrscale_attribute {
-	struct attribute attr;
-	ssize_t (*show)(struct kgsl_device *device, char *buf);
-	ssize_t (*store)(struct kgsl_device *device, const char *buf,
-			 size_t count);
-};
+#define FAST_BUS 1
+#define SLOW_BUS -1
 
-#define to_pwrscale(k) container_of(k, struct kgsl_pwrscale, kobj)
-#define pwrscale_to_device(p) container_of(p, struct kgsl_device, pwrscale)
-#define to_device(k) container_of(k, struct kgsl_device, pwrscale_kobj)
-#define to_pwrscale_attr(a) \
-container_of(a, struct kgsl_pwrscale_attribute, attr)
-#define to_policy_attr(a) \
-container_of(a, struct kgsl_pwrscale_policy_attribute, attr)
+static void do_devfreq_suspend(struct work_struct *work);
+static void do_devfreq_resume(struct work_struct *work);
+static void do_devfreq_notify(struct work_struct *work);
 
-#define PWRSCALE_ATTR(_name, _mode, _show, _store) \
-struct kgsl_pwrscale_attribute pwrscale_attr_##_name = \
-__ATTR(_name, _mode, _show, _store)
-
-/* Master list of available policies */
-
-static struct kgsl_pwrscale_policy *kgsl_pwrscale_policies[] = {
-#ifdef CONFIG_MSM_SCM
-	&kgsl_pwrscale_policy_tz,
-#endif
-#ifdef CONFIG_MSM_SLEEP_STATS_DEVICE
-	&kgsl_pwrscale_policy_idlestats,
-#endif
-	NULL
-};
-
-static ssize_t pwrscale_policy_store(struct kgsl_device *device,
-				     const char *buf, size_t count)
-{
-	int i;
-	struct kgsl_pwrscale_policy *policy = NULL;
-
-	/* The special keyword none allows the user to detach all
-	   policies */
-	if (!strncmp("none", buf, 4)) {
-		kgsl_pwrscale_detach_policy(device);
-		return count;
-	}
-
-	for (i = 0; kgsl_pwrscale_policies[i]; i++) {
-		if (!strncmp(kgsl_pwrscale_policies[i]->name, buf,
-			     strnlen(kgsl_pwrscale_policies[i]->name,
-				PAGE_SIZE))) {
-			policy = kgsl_pwrscale_policies[i];
-			break;
-		}
-	}
-
-	if (policy)
-		if (kgsl_pwrscale_attach_policy(device, policy))
-			return -EIO;
-
-	return count;
-}
-
-static ssize_t pwrscale_policy_show(struct kgsl_device *device, char *buf)
-{
-	int ret;
-
-	if (device->pwrscale.policy) {
-		ret = snprintf(buf, PAGE_SIZE, "%s",
-			       device->pwrscale.policy->name);
-		if (device->pwrscale.enabled == 0)
-			ret += snprintf(buf + ret, PAGE_SIZE - ret,
-				" (disabled)");
-		ret += snprintf(buf + ret, PAGE_SIZE - ret, "\n");
-	} else
-		ret = snprintf(buf, PAGE_SIZE, "none\n");
-
-	return ret;
-}
-
-PWRSCALE_ATTR(policy, 0664, pwrscale_policy_show, pwrscale_policy_store);
-
-static ssize_t pwrscale_avail_policies_show(struct kgsl_device *device,
-					    char *buf)
-{
-	int i, ret = 0;
-
-	for (i = 0; kgsl_pwrscale_policies[i]; i++) {
-		ret += snprintf(buf + ret, PAGE_SIZE - ret, "%s ",
-				kgsl_pwrscale_policies[i]->name);
-	}
-
-	ret += snprintf(buf + ret, PAGE_SIZE - ret, "none\n");
-	return ret;
-}
-PWRSCALE_ATTR(avail_policies, 0444, pwrscale_avail_policies_show, NULL);
-
-static struct attribute *pwrscale_attrs[] = {
-	&pwrscale_attr_policy.attr,
-	&pwrscale_attr_avail_policies.attr,
-	NULL
-};
-
-static ssize_t policy_sysfs_show(struct kobject *kobj,
-				   struct attribute *attr, char *buf)
-{
-	struct kgsl_pwrscale *pwrscale = to_pwrscale(kobj);
-	struct kgsl_device *device = pwrscale_to_device(pwrscale);
-	struct kgsl_pwrscale_policy_attribute *pattr = to_policy_attr(attr);
-	ssize_t ret;
-
-	if (pattr->show)
-		ret = pattr->show(device, pwrscale, buf);
-	else
-		ret = -EIO;
-
-	return ret;
-}
-
-static ssize_t policy_sysfs_store(struct kobject *kobj,
-				    struct attribute *attr,
-				    const char *buf, size_t count)
-{
-	struct kgsl_pwrscale *pwrscale = to_pwrscale(kobj);
-	struct kgsl_device *device = pwrscale_to_device(pwrscale);
-	struct kgsl_pwrscale_policy_attribute *pattr = to_policy_attr(attr);
-	ssize_t ret;
-
-	if (pattr->store)
-		ret = pattr->store(device, pwrscale, buf, count);
-	else
-		ret = -EIO;
-
-	return ret;
-}
-
-static void policy_sysfs_release(struct kobject *kobj)
-{
-}
-
-static ssize_t pwrscale_sysfs_show(struct kobject *kobj,
-				   struct attribute *attr, char *buf)
-{
-	struct kgsl_device *device = to_device(kobj);
-	struct kgsl_pwrscale_attribute *pattr = to_pwrscale_attr(attr);
-	ssize_t ret;
-
-	if (pattr->show)
-		ret = pattr->show(device, buf);
-	else
-		ret = -EIO;
-
-	return ret;
-}
-
-static ssize_t pwrscale_sysfs_store(struct kobject *kobj,
-				    struct attribute *attr,
-				    const char *buf, size_t count)
-{
-	struct kgsl_device *device = to_device(kobj);
-	struct kgsl_pwrscale_attribute *pattr = to_pwrscale_attr(attr);
-	ssize_t ret;
-
-	if (pattr->store)
-		ret = pattr->store(device, buf, count);
-	else
-		ret = -EIO;
-
-	return ret;
-}
-
-static void pwrscale_sysfs_release(struct kobject *kobj)
-{
-}
-
-static const struct sysfs_ops policy_sysfs_ops = {
-	.show = policy_sysfs_show,
-	.store = policy_sysfs_store
-};
-
-static const struct sysfs_ops pwrscale_sysfs_ops = {
-	.show = pwrscale_sysfs_show,
-	.store = pwrscale_sysfs_store
-};
-
-static struct kobj_type ktype_pwrscale_policy = {
-	.sysfs_ops = &policy_sysfs_ops,
-	.default_attrs = NULL,
-	.release = policy_sysfs_release
-};
-
-static struct kobj_type ktype_pwrscale = {
-	.sysfs_ops = &pwrscale_sysfs_ops,
-	.default_attrs = pwrscale_attrs,
-	.release = pwrscale_sysfs_release
-};
-
-#define PWRSCALE_ACTIVE(_d) \
-	((_d)->pwrscale.policy && (_d)->pwrscale.enabled)
-
+/*
+ * kgsl_pwrscale_sleep - notify governor that device is going off
+ * @device: The device
+ *
+ * Called shortly after all pending work is completed.
+ */
 void kgsl_pwrscale_sleep(struct kgsl_device *device)
 {
-	if (PWRSCALE_ACTIVE(device) && device->pwrscale.policy->sleep)
-		device->pwrscale.policy->sleep(device, &device->pwrscale);
+	BUG_ON(!mutex_is_locked(&device->mutex));
+	if (!device->pwrscale.enabled)
+		return;
+	device->pwrscale.time = device->pwrscale.on_time = 0;
+
+	/* to call devfreq_suspend_device() from a kernel thread */
+	queue_work(device->pwrscale.devfreq_wq,
+		&device->pwrscale.devfreq_suspend_ws);
 }
 EXPORT_SYMBOL(kgsl_pwrscale_sleep);
 
+/*
+ * kgsl_pwrscale_wake - notify governor that device is going on
+ * @device: The device
+ *
+ * Called when the device is returning to an active state.
+ */
 void kgsl_pwrscale_wake(struct kgsl_device *device)
 {
-	if (PWRSCALE_ACTIVE(device) && device->pwrscale.policy->wake)
-		device->pwrscale.policy->wake(device, &device->pwrscale);
+	struct kgsl_power_stats stats;
+	BUG_ON(!mutex_is_locked(&device->mutex));
+
+	if (!device->pwrscale.enabled)
+		return;
+	/* clear old stats before waking */
+	memset(&device->pwrscale.accum_stats, 0,
+		sizeof(device->pwrscale.accum_stats));
+
+	/* and any hw activity from waking up*/
+	device->ftbl->power_stats(device, &stats);
+
+	device->pwrscale.time = ktime_to_us(ktime_get());
+
+	device->pwrscale.next_governor_call = 0;
+
+	/* to call devfreq_resume_device() from a kernel thread */
+	queue_work(device->pwrscale.devfreq_wq,
+		&device->pwrscale.devfreq_resume_ws);
 }
 EXPORT_SYMBOL(kgsl_pwrscale_wake);
 
+/*
+ * kgsl_pwrscale_busy - update pwrscale state for new work
+ * @device: The device
+ *
+ * Called when new work is submitted to the device.
+ * This function must be called with the device mutex locked.
+ */
 void kgsl_pwrscale_busy(struct kgsl_device *device)
 {
-	if (PWRSCALE_ACTIVE(device) && device->pwrscale.policy->busy)
-		device->pwrscale.policy->busy(device,
-				&device->pwrscale);
+	BUG_ON(!mutex_is_locked(&device->mutex));
+	if (!device->pwrscale.enabled)
+		return;
+	if (device->pwrscale.on_time == 0)
+		device->pwrscale.on_time = ktime_to_us(ktime_get());
 }
 EXPORT_SYMBOL(kgsl_pwrscale_busy);
 
-void kgsl_pwrscale_idle(struct kgsl_device *device)
+/*
+ * kgsl_pwrscale_update - update device busy statistics
+ * @device: The device
+ *
+ * Read hardware busy counters when the device is likely to be
+ * on and accumulate the results between devfreq get_dev_status
+ * calls. This is limits the need to turn on clocks to read these
+ * values for governors that run independently of hardware
+ * activity (for example, by time based polling).
+ */
+void kgsl_pwrscale_update(struct kgsl_device *device)
 {
-	if (PWRSCALE_ACTIVE(device) && device->pwrscale.policy->idle)
-		if (device->state == KGSL_STATE_ACTIVE)
-			device->pwrscale.policy->idle(device,
-					&device->pwrscale);
-}
-EXPORT_SYMBOL(kgsl_pwrscale_idle);
+	struct kgsl_power_stats stats;
+	BUG_ON(!mutex_is_locked(&device->mutex));
 
+	if (!device->pwrscale.enabled)
+		return;
+
+	if (device->pwrscale.next_governor_call == 0)
+		device->pwrscale.next_governor_call = jiffies;
+
+	if (time_before(jiffies, device->pwrscale.next_governor_call))
+		return;
+
+	device->pwrscale.next_governor_call = jiffies
+			+ msecs_to_jiffies(KGSL_GOVERNOR_CALL_INTERVAL);
+
+	if (device->state == KGSL_STATE_ACTIVE) {
+		device->ftbl->power_stats(device, &stats);
+		device->pwrscale.accum_stats.busy_time += stats.busy_time;
+		device->pwrscale.accum_stats.ram_time += stats.ram_time;
+		device->pwrscale.accum_stats.ram_wait += stats.ram_wait;
+	}
+
+	/* to call srcu_notifier_call_chain() from a kernel thread */
+	if (device->requested_state != KGSL_STATE_SLUMBER)
+		queue_work(device->pwrscale.devfreq_wq,
+			&device->pwrscale.devfreq_notify_ws);
+}
+EXPORT_SYMBOL(kgsl_pwrscale_update);
+
+/*
+ * kgsl_pwrscale_disable - temporarily disable the governor
+ * @device: The device
+ *
+ * Temporarily disable the governor, to prevent interference
+ * with profiling tools that expect a fixed clock frequency.
+ * This function must be called with the device mutex locked.
+ */
 void kgsl_pwrscale_disable(struct kgsl_device *device)
 {
-	device->pwrscale.enabled = 0;
+	BUG_ON(!mutex_is_locked(&device->mutex));
+
+	if (device->pwrscale.enabled) {
+		queue_work(device->pwrscale.devfreq_wq,
+			&device->pwrscale.devfreq_suspend_ws);
+		device->pwrscale.enabled = false;
+		kgsl_pwrctrl_pwrlevel_change(device, KGSL_PWRLEVEL_TURBO);
+	}
 }
 EXPORT_SYMBOL(kgsl_pwrscale_disable);
 
+/*
+ * kgsl_pwrscale_enable - re-enable the governor
+ * @device: The device
+ *
+ * Reenable the governor after a kgsl_pwrscale_disable() call.
+ * This function must be called with the device mutex locked.
+ */
 void kgsl_pwrscale_enable(struct kgsl_device *device)
 {
-	device->pwrscale.enabled = 1;
+	BUG_ON(!mutex_is_locked(&device->mutex));
+
+	if (!device->pwrscale.enabled) {
+		device->pwrscale.enabled = true;
+		queue_work(device->pwrscale.devfreq_wq,
+			&device->pwrscale.devfreq_resume_ws);
+	}
 }
 EXPORT_SYMBOL(kgsl_pwrscale_enable);
 
-int kgsl_pwrscale_policy_add_files(struct kgsl_device *device,
-				   struct kgsl_pwrscale *pwrscale,
-				   struct attribute_group *attr_group)
+/*
+ * kgsl_devfreq_target - devfreq_dev_profile.target callback
+ * @dev: see devfreq.h
+ * @freq: see devfreq.h
+ * @flags: see devfreq.h
+ *
+ * This function expects the device mutex to be unlocked.
+ */
+int kgsl_devfreq_target(struct device *dev, unsigned long *freq, u32 flags)
 {
-	int ret;
+	struct kgsl_device *device = dev_get_drvdata(dev);
+	struct kgsl_pwrctrl *pwr;
+	int level, i, b;
+	unsigned long cur_freq;
 
-	ret = kobject_add(&pwrscale->kobj, &device->pwrscale_kobj,
-		"%s", pwrscale->policy->name);
+	if (device == NULL)
+		return -ENODEV;
+	if (freq == NULL)
+		return -EINVAL;
+	if (!device->pwrscale.enabled)
+		return 0;
 
-	if (ret)
-		return ret;
+	pwr = &device->pwrctrl;
 
-	ret = sysfs_create_group(&pwrscale->kobj, attr_group);
+	mutex_lock(&device->mutex);
+	cur_freq = kgsl_pwrctrl_active_freq(pwr);
+	level = pwr->active_pwrlevel;
 
-	if (ret) {
-		kobject_del(&pwrscale->kobj);
-		kobject_put(&pwrscale->kobj);
-	}
-
-	return ret;
-}
-
-void kgsl_pwrscale_policy_remove_files(struct kgsl_device *device,
-				       struct kgsl_pwrscale *pwrscale,
-				       struct attribute_group *attr_group)
-{
-	sysfs_remove_group(&pwrscale->kobj, attr_group);
-	kobject_del(&pwrscale->kobj);
-	kobject_put(&pwrscale->kobj);
-}
-
-static void _kgsl_pwrscale_detach_policy(struct kgsl_device *device)
-{
-	if (device->pwrscale.policy != NULL) {
-		device->pwrscale.policy->close(device, &device->pwrscale);
-
+	if (*freq != cur_freq) {
+		level = pwr->max_pwrlevel;
+		for (i = pwr->min_pwrlevel; i >= pwr->max_pwrlevel; i--)
+			if (*freq <= pwr->pwrlevels[i].gpu_freq) {
+				level = i;
+				break;
+			}
+	} else if (flags && pwr->bus_control) {
 		/*
-		 * Try to set max pwrlevel which will be limited to thermal by
-		 * kgsl_pwrctrl_pwrlevel_change if thermal is indeed lower
+		 * Signal for faster or slower bus.  If KGSL isn't already
+		 * running at the desired speed for the given level, modify
+		 * its vote.
 		 */
-
-		kgsl_pwrctrl_pwrlevel_change(device,
-				device->pwrctrl.max_pwrlevel);
-		device->pwrctrl.default_pwrlevel =
-				device->pwrctrl.max_pwrlevel;
+		b = pwr->bus_mod;
+		if ((flags & DEVFREQ_FLAG_FAST_HINT) &&
+			(pwr->bus_mod != FAST_BUS))
+			pwr->bus_mod = (pwr->bus_mod == SLOW_BUS) ?
+					0 : FAST_BUS;
+		else if ((flags & DEVFREQ_FLAG_SLOW_HINT) &&
+			(pwr->bus_mod != SLOW_BUS))
+			pwr->bus_mod = (pwr->bus_mod == FAST_BUS) ?
+					0 : SLOW_BUS;
+		if (pwr->bus_mod != b)
+			kgsl_pwrctrl_buslevel_update(device, true);
 	}
-	device->pwrscale.policy = NULL;
-}
 
-void kgsl_pwrscale_detach_policy(struct kgsl_device *device)
-{
-	mutex_lock(&device->mutex);
-	_kgsl_pwrscale_detach_policy(device);
+	kgsl_pwrctrl_pwrlevel_change(device, level);
+	*freq = kgsl_pwrctrl_active_freq(pwr);
+
 	mutex_unlock(&device->mutex);
+	return 0;
 }
-EXPORT_SYMBOL(kgsl_pwrscale_detach_policy);
+EXPORT_SYMBOL(kgsl_devfreq_target);
 
-int kgsl_pwrscale_attach_policy(struct kgsl_device *device,
-				struct kgsl_pwrscale_policy *policy)
+/*
+ * kgsl_devfreq_get_dev_status - devfreq_dev_profile.get_dev_status callback
+ * @dev: see devfreq.h
+ * @freq: see devfreq.h
+ * @flags: see devfreq.h
+ *
+ * This function expects the device mutex to be unlocked.
+ */
+int kgsl_devfreq_get_dev_status(struct device *dev,
+				struct devfreq_dev_status *stat)
 {
-	int ret = 0;
+	struct kgsl_device *device = dev_get_drvdata(dev);
+	struct kgsl_pwrscale *pwrscale;
+	s64 tmp;
+
+	if (device == NULL)
+		return -ENODEV;
+	if (stat == NULL)
+		return -EINVAL;
+
+	pwrscale = &device->pwrscale;
 
 	mutex_lock(&device->mutex);
-
-	if (device->pwrscale.policy == policy)
-		goto done;
-
-	if (device->pwrctrl.num_pwrlevels < 3) {
-		ret = -EINVAL;
-		goto done;
+	/* make sure we don't turn on clocks just to read stats */
+	if (device->state == KGSL_STATE_ACTIVE) {
+		struct kgsl_power_stats extra;
+		device->ftbl->power_stats(device, &extra);
+		device->pwrscale.accum_stats.busy_time += extra.busy_time;
+		device->pwrscale.accum_stats.ram_time += extra.ram_time;
+		device->pwrscale.accum_stats.ram_wait += extra.ram_wait;
 	}
 
-	if (device->pwrscale.policy != NULL)
-		_kgsl_pwrscale_detach_policy(device);
+	tmp = ktime_to_us(ktime_get());
+	stat->total_time = tmp - pwrscale->time;
+	pwrscale->time = tmp;
 
-	device->pwrscale.policy = policy;
+	stat->busy_time = pwrscale->accum_stats.busy_time;
 
-	device->pwrctrl.default_pwrlevel =
-			device->pwrctrl.init_pwrlevel;
-	/* Pwrscale is enabled by default at attach time */
-	kgsl_pwrscale_enable(device);
+	stat->current_frequency = kgsl_pwrctrl_active_freq(&device->pwrctrl);
 
-	if (policy) {
-		ret = device->pwrscale.policy->init(device, &device->pwrscale);
-		if (ret)
-			device->pwrscale.policy = NULL;
+	if (stat->private_data) {
+		struct xstats *b = (struct xstats *)stat->private_data;
+		b->ram_time = device->pwrscale.accum_stats.ram_time;
+		b->ram_wait = device->pwrscale.accum_stats.ram_wait;
+		b->mod = device->pwrctrl.bus_mod;
 	}
 
-done:
+	trace_kgsl_pwrstats(device, stat->total_time, &pwrscale->accum_stats);
+	memset(&pwrscale->accum_stats, 0, sizeof(pwrscale->accum_stats));
+
 	mutex_unlock(&device->mutex);
 
-	return ret;
+	return 0;
 }
-EXPORT_SYMBOL(kgsl_pwrscale_attach_policy);
+EXPORT_SYMBOL(kgsl_devfreq_get_dev_status);
 
-int kgsl_pwrscale_init(struct kgsl_device *device)
+/*
+ * kgsl_devfreq_get_cur_freq - devfreq_dev_profile.get_cur_freq callback
+ * @dev: see devfreq.h
+ * @freq: see devfreq.h
+ * @flags: see devfreq.h
+ *
+ * This function expects the device mutex to be unlocked.
+ */
+int kgsl_devfreq_get_cur_freq(struct device *dev, unsigned long *freq)
 {
+	struct kgsl_device *device = dev_get_drvdata(dev);
+
+	if (device == NULL)
+		return -ENODEV;
+	if (freq == NULL)
+		return -EINVAL;
+
+	mutex_lock(&device->mutex);
+	*freq = kgsl_pwrctrl_active_freq(&device->pwrctrl);
+	mutex_unlock(&device->mutex);
+
+	return 0;
+}
+EXPORT_SYMBOL(kgsl_devfreq_get_cur_freq);
+
+/*
+ * kgsl_devfreq_add_notifier - add a fine grained notifier.
+ * @dev: The device
+ * @nb: Notifier block that will recieve updates.
+ *
+ * Add a notifier to recieve ADRENO_DEVFREQ_NOTIFY_* events
+ * from the device.
+ */
+int kgsl_devfreq_add_notifier(struct device *dev, struct notifier_block *nb)
+{
+	struct kgsl_device *device = dev_get_drvdata(dev);
+
+	if (device == NULL)
+		return -ENODEV;
+
+	if (nb == NULL)
+		return -EINVAL;
+
+	return srcu_notifier_chain_register(&device->pwrscale.nh, nb);
+}
+
+void kgsl_pwrscale_idle(struct kgsl_device *device)
+{
+	BUG_ON(!mutex_is_locked(&device->mutex));
+	queue_work(device->pwrscale.devfreq_wq,
+		&device->pwrscale.devfreq_notify_ws);
+}
+EXPORT_SYMBOL(kgsl_pwrscale_idle);
+
+/*
+ * kgsl_devfreq_del_notifier - remove a fine grained notifier.
+ * @dev: The device
+ * @nb: The notifier block.
+ *
+ * Remove a notifier registered with kgsl_devfreq_add_notifier().
+ */
+int kgsl_devfreq_del_notifier(struct device *dev, struct notifier_block *nb)
+{
+	struct kgsl_device *device = dev_get_drvdata(dev);
+
+	if (device == NULL)
+		return -ENODEV;
+
+	if (nb == NULL)
+		return -EINVAL;
+
+	return srcu_notifier_chain_unregister(&device->pwrscale.nh, nb);
+}
+EXPORT_SYMBOL(kgsl_devfreq_del_notifier);
+
+/*
+ * kgsl_pwrscale_init - Initialize pwrscale.
+ * @dev: The device
+ * @governor: The initial governor to use.
+ *
+ * Initialize devfreq and any non-constant profile data.
+ */
+int kgsl_pwrscale_init(struct device *dev, const char *governor)
+{
+	struct kgsl_device *device;
+	struct kgsl_pwrscale *pwrscale;
+	struct kgsl_pwrctrl *pwr;
+	struct devfreq *devfreq;
+	struct devfreq_dev_profile *profile;
+	struct devfreq_msm_adreno_tz_data *data;
+	int i, out = 0;
 	int ret;
 
-	ret = kobject_init_and_add(&device->pwrscale_kobj, &ktype_pwrscale,
-		&device->dev->kobj, "pwrscale");
+	device = dev_get_drvdata(dev);
+	if (device == NULL)
+		return -ENODEV;
 
-	if (ret)
-		return ret;
+	pwrscale = &device->pwrscale;
+	pwr = &device->pwrctrl;
+	profile = &pwrscale->profile;
 
-	kobject_init(&device->pwrscale.kobj, &ktype_pwrscale_policy);
-	return ret;
+	srcu_init_notifier_head(&pwrscale->nh);
+
+	profile->initial_freq =
+		pwr->pwrlevels[pwr->default_pwrlevel].gpu_freq;
+	/* Let's start with 10 ms and tune in later */
+	profile->polling_ms = 10;
+
+	/* do not include the 'off' level or duplicate freq. levels */
+	for (i = 0; i < (pwr->num_pwrlevels - 1); i++)
+		pwrscale->freq_table[out++] = pwr->pwrlevels[i].gpu_freq;
+
+	profile->max_state = out;
+	/* link storage array to the devfreq profile pointer */
+	profile->freq_table = pwrscale->freq_table;
+
+	/* if there is only 1 freq, no point in running a governor */
+	if (profile->max_state == 1)
+		governor = "performance";
+
+	/* initialize any governor specific data here */
+	for (i = 0; i < profile->num_governor_data; i++) {
+		if (strncmp("msm-adreno-tz",
+				profile->governor_data[i].name,
+				DEVFREQ_NAME_LEN) == 0) {
+			data = (struct devfreq_msm_adreno_tz_data *)
+				profile->governor_data[i].data;
+			/*
+			 * If there is a separate GX power rail, allow
+			 * independent modification to its voltage through
+			 * the bus bandwidth vote.
+			 */
+			if (pwr->bus_control) {
+				out = 0;
+				while (pwr->bus_ib[out]) {
+					pwr->bus_ib[out] =
+						pwr->bus_ib[out] >> 20;
+					out++;
+				}
+				data->bus.num = out;
+				data->bus.ib = &pwr->bus_ib[0];
+				data->bus.index = &pwr->bus_index[0];
+				printk("kgsl: num bus is %d\n", out);
+			} else {
+				data->bus.num = 0;
+			}
+		}
+	}
+
+	devfreq = devfreq_add_device(dev, &pwrscale->profile, governor, NULL);
+	if (IS_ERR(devfreq))
+		return PTR_ERR(devfreq);
+
+	pwrscale->devfreq = devfreq;
+
+	ret = sysfs_create_link(&device->dev->kobj,
+			&devfreq->dev.kobj, "devfreq");
+
+	pwrscale->devfreq_wq = create_freezable_workqueue("kgsl_devfreq_wq");
+	INIT_WORK(&pwrscale->devfreq_suspend_ws, do_devfreq_suspend);
+	INIT_WORK(&pwrscale->devfreq_resume_ws, do_devfreq_resume);
+	INIT_WORK(&pwrscale->devfreq_notify_ws, do_devfreq_notify);
+
+	pwrscale->next_governor_call = 0;
+
+	return 0;
 }
 EXPORT_SYMBOL(kgsl_pwrscale_init);
 
+/*
+ * kgsl_pwrscale_close - clean up pwrscale
+ * @device: the device
+ *
+ * This function should be called with the device mutex locked.
+ */
 void kgsl_pwrscale_close(struct kgsl_device *device)
 {
-	kobject_put(&device->pwrscale_kobj);
+	struct kgsl_pwrscale *pwrscale;
+
+	BUG_ON(!mutex_is_locked(&device->mutex));
+
+	pwrscale = &device->pwrscale;
+	flush_workqueue(pwrscale->devfreq_wq);
+	destroy_workqueue(pwrscale->devfreq_wq);
+	devfreq_remove_device(device->pwrscale.devfreq);
+	device->pwrscale.devfreq = NULL;
+	srcu_cleanup_notifier_head(&device->pwrscale.nh);
 }
 EXPORT_SYMBOL(kgsl_pwrscale_close);
+
+static void do_devfreq_suspend(struct work_struct *work)
+{
+	struct kgsl_pwrscale *pwrscale = container_of(work,
+			struct kgsl_pwrscale, devfreq_suspend_ws);
+	struct devfreq *devfreq = pwrscale->devfreq;
+
+	devfreq_suspend_device(devfreq);
+}
+
+static void do_devfreq_resume(struct work_struct *work)
+{
+	struct kgsl_pwrscale *pwrscale = container_of(work,
+			struct kgsl_pwrscale, devfreq_resume_ws);
+	struct devfreq *devfreq = pwrscale->devfreq;
+
+	devfreq_resume_device(devfreq);
+}
+
+static void do_devfreq_notify(struct work_struct *work)
+{
+	struct kgsl_pwrscale *pwrscale = container_of(work,
+			struct kgsl_pwrscale, devfreq_notify_ws);
+	struct devfreq *devfreq = pwrscale->devfreq;
+	srcu_notifier_call_chain(&pwrscale->nh,
+				 ADRENO_DEVFREQ_NOTIFY_RETIRE,
+				 devfreq);
+}
diff --git a/drivers/gpu/msm/kgsl_pwrscale.h b/drivers/gpu/msm/kgsl_pwrscale.h
index f17b394..866964c 100644
--- a/drivers/gpu/msm/kgsl_pwrscale.h
+++ b/drivers/gpu/msm/kgsl_pwrscale.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-2013, 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
@@ -14,68 +14,58 @@
 #ifndef __KGSL_PWRSCALE_H
 #define __KGSL_PWRSCALE_H
 
-struct kgsl_pwrscale;
+#include <linux/devfreq.h>
+#include <linux/msm_adreno_devfreq.h>
 
-struct kgsl_pwrscale_policy  {
-	const char *name;
-	int (*init)(struct kgsl_device *device,
-		struct kgsl_pwrscale *pwrscale);
-	void (*close)(struct kgsl_device *device,
-		struct kgsl_pwrscale *pwrscale);
-	void (*idle)(struct kgsl_device *device,
-		struct kgsl_pwrscale *pwrscale);
-	void (*busy)(struct kgsl_device *device,
-		struct kgsl_pwrscale *pwrscale);
-	void (*sleep)(struct kgsl_device *device,
-		struct kgsl_pwrscale *pwrscale);
-	void (*wake)(struct kgsl_device *device,
-		struct kgsl_pwrscale *pwrscale);
+/* devfreq governor call window in msec */
+#define KGSL_GOVERNOR_CALL_INTERVAL 5
+
+struct kgsl_power_stats {
+	u64 busy_time;
+	u64 ram_time;
+	u64 ram_wait;
 };
 
 struct kgsl_pwrscale {
-	struct kgsl_pwrscale_policy *policy;
-	struct kobject kobj;
-	void *priv;
-	int enabled;
+	struct devfreq *devfreq;
+	struct devfreq_dev_profile profile;
+	unsigned int freq_table[KGSL_MAX_PWRLEVELS];
+	char last_governor[DEVFREQ_NAME_LEN];
+	struct kgsl_power_stats accum_stats;
+	bool enabled;
+	s64 time;
+	s64 on_time;
+	struct srcu_notifier_head nh;
+	struct workqueue_struct *devfreq_wq;
+	struct work_struct devfreq_suspend_ws;
+	struct work_struct devfreq_resume_ws;
+	struct work_struct devfreq_notify_ws;
+	unsigned long next_governor_call;
 };
 
-struct kgsl_pwrscale_policy_attribute {
-	struct attribute attr;
-	ssize_t (*show)(struct kgsl_device *device,
-			struct kgsl_pwrscale *pwrscale, char *buf);
-	ssize_t (*store)(struct kgsl_device *device,
-			 struct kgsl_pwrscale *pwrscale, const char *buf,
-			 size_t count);
-};
-
-#define PWRSCALE_POLICY_ATTR(_name, _mode, _show, _store)          \
-	struct kgsl_pwrscale_policy_attribute policy_attr_##_name = \
-		__ATTR(_name, _mode, _show, _store)
-
-extern struct kgsl_pwrscale_policy kgsl_pwrscale_policy_tz;
-extern struct kgsl_pwrscale_policy kgsl_pwrscale_policy_idlestats;
-extern struct kgsl_pwrscale_policy kgsl_pwrscale_policy_msm;
-
-int kgsl_pwrscale_init(struct kgsl_device *device);
+int kgsl_pwrscale_init(struct device *dev, const char *governor);
 void kgsl_pwrscale_close(struct kgsl_device *device);
 
-int kgsl_pwrscale_attach_policy(struct kgsl_device *device,
-	struct kgsl_pwrscale_policy *policy);
-void kgsl_pwrscale_detach_policy(struct kgsl_device *device);
-
-void kgsl_pwrscale_idle(struct kgsl_device *device);
+void kgsl_pwrscale_update(struct kgsl_device *device);
 void kgsl_pwrscale_busy(struct kgsl_device *device);
+void kgsl_pwrscale_idle(struct kgsl_device *device);
 void kgsl_pwrscale_sleep(struct kgsl_device *device);
 void kgsl_pwrscale_wake(struct kgsl_device *device);
 
 void kgsl_pwrscale_enable(struct kgsl_device *device);
 void kgsl_pwrscale_disable(struct kgsl_device *device);
 
-int kgsl_pwrscale_policy_add_files(struct kgsl_device *device,
-				   struct kgsl_pwrscale *pwrscale,
-				   struct attribute_group *attr_group);
+int kgsl_devfreq_target(struct device *dev, unsigned long *freq, u32 flags);
+int kgsl_devfreq_get_dev_status(struct device *, struct devfreq_dev_status *);
+int kgsl_devfreq_get_cur_freq(struct device *dev, unsigned long *freq);
 
-void kgsl_pwrscale_policy_remove_files(struct kgsl_device *device,
-				       struct kgsl_pwrscale *pwrscale,
-				       struct attribute_group *attr_group);
+#define KGSL_PWRSCALE_INIT(_gov_list, _num_gov) { \
+	.enabled = true, \
+	.profile = { \
+		.target = kgsl_devfreq_target, \
+		.get_dev_status = kgsl_devfreq_get_dev_status, \
+		.get_cur_freq = kgsl_devfreq_get_cur_freq, \
+		.governor_data = (_gov_list), \
+		.num_governor_data = (_num_gov), \
+	} }
 #endif
diff --git a/drivers/gpu/msm/kgsl_pwrscale_idlestats.c b/drivers/gpu/msm/kgsl_pwrscale_idlestats.c
deleted file mode 100644
index c3188a5..0000000
--- a/drivers/gpu/msm/kgsl_pwrscale_idlestats.c
+++ /dev/null
@@ -1,232 +0,0 @@
-/* Copyright (c) 2011-2012, 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.
- *
- */
-
-#include <linux/slab.h>
-#include <linux/timer.h>
-#include <linux/idle_stats_device.h>
-#include <linux/cpufreq.h>
-#include <linux/notifier.h>
-#include <linux/cpumask.h>
-#include <linux/tick.h>
-
-#include "kgsl.h"
-#include "kgsl_pwrscale.h"
-#include "kgsl_device.h"
-
-#define MAX_CORES 4
-struct _cpu_info {
-	spinlock_t lock;
-	struct notifier_block cpu_nb;
-	u64 start[MAX_CORES];
-	u64 end[MAX_CORES];
-	int curr_freq[MAX_CORES];
-	int max_freq[MAX_CORES];
-};
-
-struct idlestats_priv {
-	char name[32];
-	struct msm_idle_stats_device idledev;
-	struct kgsl_device *device;
-	struct msm_idle_pulse pulse;
-	struct _cpu_info cpu_info;
-};
-
-static int idlestats_cpufreq_notifier(
-				struct notifier_block *nb,
-				unsigned long val, void *data)
-{
-	struct _cpu_info *cpu = container_of(nb,
-						struct _cpu_info, cpu_nb);
-	struct cpufreq_freqs *freq = data;
-
-	if (val != CPUFREQ_POSTCHANGE)
-		return 0;
-
-	spin_lock(&cpu->lock);
-	if (freq->cpu < num_possible_cpus())
-		cpu->curr_freq[freq->cpu] = freq->new / 1000;
-	spin_unlock(&cpu->lock);
-
-	return 0;
-}
-
-static void idlestats_get_sample(struct msm_idle_stats_device *idledev,
-	struct msm_idle_pulse *pulse)
-{
-	struct kgsl_power_stats stats;
-	struct idlestats_priv *priv = container_of(idledev,
-		struct idlestats_priv, idledev);
-	struct kgsl_device *device = priv->device;
-	struct kgsl_pwrctrl *pwr = &device->pwrctrl;
-
-	mutex_lock(&device->mutex);
-	/* If the GPU is asleep, don't wake it up - assume that we
-	   are idle */
-
-	if (device->state == KGSL_STATE_ACTIVE) {
-		device->ftbl->power_stats(device, &stats);
-		pulse->busy_start_time = pwr->time - stats.busy_time;
-		pulse->busy_interval = stats.busy_time;
-	} else {
-		pulse->busy_start_time = pwr->time;
-		pulse->busy_interval = 0;
-	}
-	pulse->wait_interval = 0;
-	mutex_unlock(&device->mutex);
-}
-
-static void idlestats_busy(struct kgsl_device *device,
-			struct kgsl_pwrscale *pwrscale)
-{
-	struct idlestats_priv *priv = pwrscale->priv;
-	struct kgsl_power_stats stats;
-	int i, busy, nr_cpu = 1;
-
-	if (priv->pulse.busy_start_time != 0) {
-		priv->pulse.wait_interval = 0;
-		/* Calculate the total CPU busy time for this GPU pulse */
-		for (i = 0; i < num_possible_cpus(); i++) {
-			spin_lock(&priv->cpu_info.lock);
-			if (cpu_online(i)) {
-				priv->cpu_info.end[i] =
-						(u64)ktime_to_us(ktime_get()) -
-						get_cpu_idle_time_us(i, NULL);
-				busy = priv->cpu_info.end[i] -
-						priv->cpu_info.start[i];
-				/* Normalize the busy time by frequency */
-				busy = priv->cpu_info.curr_freq[i] *
-					(busy / priv->cpu_info.max_freq[i]);
-				priv->pulse.wait_interval += busy;
-				nr_cpu++;
-			}
-			spin_unlock(&priv->cpu_info.lock);
-		}
-		priv->pulse.wait_interval /= nr_cpu;
-
-		/* This is called from within a mutex protected function, so
-		   no additional locking required */
-		device->ftbl->power_stats(device, &stats);
-
-		/* If total_time is zero, then we don't have
-		   any interesting statistics to store */
-		if (stats.total_time == 0) {
-			priv->pulse.busy_start_time = 0;
-			return;
-		}
-
-		priv->pulse.busy_interval = stats.busy_time;
-		msm_idle_stats_idle_end(&priv->idledev, &priv->pulse);
-	}
-	priv->pulse.busy_start_time = ktime_to_us(ktime_get());
-}
-
-static void idlestats_idle(struct kgsl_device *device,
-		struct kgsl_pwrscale *pwrscale)
-{
-	int i, nr_cpu;
-	struct idlestats_priv *priv = pwrscale->priv;
-
-	nr_cpu = num_possible_cpus();
-	for (i = 0; i < nr_cpu; i++)
-		if (cpu_online(i))
-			priv->cpu_info.start[i] =
-					(u64)ktime_to_us(ktime_get()) -
-					get_cpu_idle_time_us(i, NULL);
-
-	msm_idle_stats_idle_start(&priv->idledev);
-}
-
-static void idlestats_sleep(struct kgsl_device *device,
-			struct kgsl_pwrscale *pwrscale)
-{
-	struct idlestats_priv *priv = pwrscale->priv;
-	msm_idle_stats_update_event(&priv->idledev,
-		MSM_IDLE_STATS_EVENT_IDLE_TIMER_EXPIRED);
-}
-
-static void idlestats_wake(struct kgsl_device *device,
-			struct kgsl_pwrscale *pwrscale)
-{
-	/* Use highest perf level on wake-up from
-	   sleep for better performance */
-	kgsl_pwrctrl_pwrlevel_change(device, KGSL_PWRLEVEL_TURBO);
-}
-
-static int idlestats_init(struct kgsl_device *device,
-		     struct kgsl_pwrscale *pwrscale)
-{
-	struct idlestats_priv *priv;
-	struct cpufreq_policy cpu_policy;
-	int ret, i;
-
-	priv = pwrscale->priv = kzalloc(sizeof(struct idlestats_priv),
-		GFP_KERNEL);
-	if (pwrscale->priv == NULL)
-		return -ENOMEM;
-
-	snprintf(priv->name, sizeof(priv->name), "idle_stats_%s",
-		 device->name);
-
-	priv->device = device;
-
-	priv->idledev.name = (const char *) priv->name;
-	priv->idledev.get_sample = idlestats_get_sample;
-
-	spin_lock_init(&priv->cpu_info.lock);
-	priv->cpu_info.cpu_nb.notifier_call =
-			idlestats_cpufreq_notifier;
-	ret = cpufreq_register_notifier(&priv->cpu_info.cpu_nb,
-				CPUFREQ_TRANSITION_NOTIFIER);
-	if (ret)
-		goto err;
-	for (i = 0; i < num_possible_cpus(); i++) {
-		cpufreq_frequency_table_cpuinfo(&cpu_policy,
-					cpufreq_frequency_get_table(i));
-		priv->cpu_info.max_freq[i] = cpu_policy.max / 1000;
-		priv->cpu_info.curr_freq[i] = cpu_policy.max / 1000;
-	}
-	ret = msm_idle_stats_register_device(&priv->idledev);
-err:
-	if (ret) {
-		kfree(pwrscale->priv);
-		pwrscale->priv = NULL;
-	}
-
-	return ret;
-}
-
-static void idlestats_close(struct kgsl_device *device,
-		      struct kgsl_pwrscale *pwrscale)
-{
-	struct idlestats_priv *priv = pwrscale->priv;
-
-	if (pwrscale->priv == NULL)
-		return;
-
-	cpufreq_unregister_notifier(&priv->cpu_info.cpu_nb,
-						CPUFREQ_TRANSITION_NOTIFIER);
-	msm_idle_stats_deregister_device(&priv->idledev);
-
-	kfree(pwrscale->priv);
-	pwrscale->priv = NULL;
-}
-
-struct kgsl_pwrscale_policy kgsl_pwrscale_policy_idlestats = {
-	.name = "idlestats",
-	.init = idlestats_init,
-	.idle = idlestats_idle,
-	.busy = idlestats_busy,
-	.sleep = idlestats_sleep,
-	.wake = idlestats_wake,
-	.close = idlestats_close
-};
diff --git a/drivers/gpu/msm/kgsl_pwrscale_trustzone.c b/drivers/gpu/msm/kgsl_pwrscale_trustzone.c
deleted file mode 100644
index 7f8a6b1..0000000
--- a/drivers/gpu/msm/kgsl_pwrscale_trustzone.c
+++ /dev/null
@@ -1,269 +0,0 @@
-/* Copyright (c) 2010-2013, 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.
- *
- */
-
-#include <linux/export.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/io.h>
-#include <linux/spinlock.h>
-#include <mach/socinfo.h>
-#include <mach/scm.h>
-
-#include "kgsl.h"
-#include "kgsl_pwrscale.h"
-#include "kgsl_device.h"
-
-#define TZ_GOVERNOR_PERFORMANCE 0
-#define TZ_GOVERNOR_ONDEMAND    1
-
-struct tz_priv {
-	int governor;
-	struct kgsl_power_stats bin;
-	unsigned int idle_dcvs;
-};
-spinlock_t tz_lock;
-
-/* FLOOR is 5msec to capture up to 3 re-draws
- * per frame for 60fps content.
- */
-#define FLOOR			5000
-/* CEILING is 50msec, larger than any standard
- * frame length, but less than the idle timer.
- */
-#define CEILING			50000
-#define TZ_RESET_ID		0x3
-#define TZ_UPDATE_ID		0x4
-#define TZ_INIT_ID		0x6
-
-/* Trap into the TrustZone, and call funcs there. */
-static int __secure_tz_entry2(u32 cmd, u32 val1, u32 val2)
-{
-	int ret;
-	spin_lock(&tz_lock);
-	/* sync memory before sending the commands to tz*/
-	__iowmb();
-	ret = scm_call_atomic2(SCM_SVC_IO, cmd, val1, val2);
-	spin_unlock(&tz_lock);
-	return ret;
-}
-
-static int __secure_tz_entry3(u32 cmd, u32 val1, u32 val2,
-				u32 val3)
-{
-	int ret;
-	spin_lock(&tz_lock);
-	/* sync memory before sending the commands to tz*/
-	__iowmb();
-	ret = scm_call_atomic3(SCM_SVC_IO, cmd, val1, val2,
-				val3);
-	spin_unlock(&tz_lock);
-	return ret;
-}
-
-static ssize_t tz_governor_show(struct kgsl_device *device,
-				struct kgsl_pwrscale *pwrscale,
-				char *buf)
-{
-	struct tz_priv *priv = pwrscale->priv;
-	int ret;
-
-	if (priv->governor == TZ_GOVERNOR_ONDEMAND)
-		ret = snprintf(buf, 10, "ondemand\n");
-	else
-		ret = snprintf(buf, 13, "performance\n");
-
-	return ret;
-}
-
-static ssize_t tz_governor_store(struct kgsl_device *device,
-				struct kgsl_pwrscale *pwrscale,
-				 const char *buf, size_t count)
-{
-	char str[20];
-	struct tz_priv *priv = pwrscale->priv;
-	struct kgsl_pwrctrl *pwr = &device->pwrctrl;
-	int ret;
-
-	ret = sscanf(buf, "%20s", str);
-	if (ret != 1)
-		return -EINVAL;
-
-	mutex_lock(&device->mutex);
-
-	if (!strncmp(str, "ondemand", 8))
-		priv->governor = TZ_GOVERNOR_ONDEMAND;
-	else if (!strncmp(str, "performance", 11))
-		priv->governor = TZ_GOVERNOR_PERFORMANCE;
-
-	if (priv->governor == TZ_GOVERNOR_PERFORMANCE) {
-		kgsl_pwrctrl_pwrlevel_change(device, pwr->max_pwrlevel);
-		pwr->default_pwrlevel = pwr->max_pwrlevel;
-	} else {
-		pwr->default_pwrlevel = pwr->init_pwrlevel;
-	}
-
-	mutex_unlock(&device->mutex);
-	return count;
-}
-
-PWRSCALE_POLICY_ATTR(governor, 0644, tz_governor_show, tz_governor_store);
-
-static struct attribute *tz_attrs[] = {
-	&policy_attr_governor.attr,
-	NULL
-};
-
-static struct attribute_group tz_attr_group = {
-	.attrs = tz_attrs,
-};
-
-static void tz_wake(struct kgsl_device *device, struct kgsl_pwrscale *pwrscale)
-{
-	struct tz_priv *priv = pwrscale->priv;
-	if (device->state != KGSL_STATE_NAP &&
-		priv->governor == TZ_GOVERNOR_ONDEMAND)
-		kgsl_pwrctrl_pwrlevel_change(device,
-					device->pwrctrl.default_pwrlevel);
-}
-
-static void tz_idle(struct kgsl_device *device, struct kgsl_pwrscale *pwrscale)
-{
-	struct kgsl_pwrctrl *pwr = &device->pwrctrl;
-	struct tz_priv *priv = pwrscale->priv;
-	struct kgsl_power_stats stats;
-	int val, idle;
-
-	/* In "performance" mode the clock speed always stays
-	   the same */
-	if (priv->governor == TZ_GOVERNOR_PERFORMANCE)
-		return;
-
-	device->ftbl->power_stats(device, &stats);
-	priv->bin.total_time += stats.total_time;
-	priv->bin.busy_time += stats.busy_time;
-	/* Do not waste CPU cycles running this algorithm if
-	 * the GPU just started, or if less than FLOOR time
-	 * has passed since the last run.
-	 */
-	if ((stats.total_time == 0) ||
-		(priv->bin.total_time < FLOOR))
-		return;
-
-	/* If there is an extended block of busy processing, set
-	 * frequency to turbo.  Otherwise run the normal algorithm.
-	 */
-	if (priv->bin.busy_time > CEILING) {
-		val = 0;
-		kgsl_pwrctrl_pwrlevel_change(device,
-				KGSL_PWRLEVEL_TURBO);
-	} else if (priv->idle_dcvs) {
-		idle = priv->bin.total_time - priv->bin.busy_time;
-		idle = (idle > 0) ? idle : 0;
-		val = __secure_tz_entry2(TZ_UPDATE_ID, idle, device->id);
-	} else {
-		if (pwr->step_mul > 1)
-			val = __secure_tz_entry3(TZ_UPDATE_ID,
-				(pwr->active_pwrlevel + 1)/2,
-				priv->bin.total_time, priv->bin.busy_time);
-		else
-			val = __secure_tz_entry3(TZ_UPDATE_ID,
-				pwr->active_pwrlevel,
-				priv->bin.total_time, priv->bin.busy_time);
-	}
-
-	priv->bin.total_time = 0;
-	priv->bin.busy_time = 0;
-
-	/* If the decision is to move to a lower level, make sure the GPU
-	 * frequency drops.
-	 */
-	if (val > 0)
-		val *= pwr->step_mul;
-	if (val)
-		kgsl_pwrctrl_pwrlevel_change(device,
-					     pwr->active_pwrlevel + val);
-}
-
-static void tz_busy(struct kgsl_device *device,
-	struct kgsl_pwrscale *pwrscale)
-{
-	device->on_time = ktime_to_us(ktime_get());
-}
-
-static void tz_sleep(struct kgsl_device *device,
-	struct kgsl_pwrscale *pwrscale)
-{
-	struct tz_priv *priv = pwrscale->priv;
-
-	__secure_tz_entry2(TZ_RESET_ID, 0, 0);
-	priv->bin.total_time = 0;
-	priv->bin.busy_time = 0;
-}
-
-#ifdef CONFIG_MSM_SCM
-static int tz_init(struct kgsl_device *device, struct kgsl_pwrscale *pwrscale)
-{
-	int i = 0, j = 1, ret = 0;
-	struct tz_priv *priv;
-	struct kgsl_pwrctrl *pwr = &device->pwrctrl;
-	unsigned int tz_pwrlevels[KGSL_MAX_PWRLEVELS + 1];
-
-	priv = pwrscale->priv = kzalloc(sizeof(struct tz_priv), GFP_KERNEL);
-	if (pwrscale->priv == NULL)
-		return -ENOMEM;
-	priv->idle_dcvs = 0;
-	priv->governor = TZ_GOVERNOR_ONDEMAND;
-	spin_lock_init(&tz_lock);
-	kgsl_pwrscale_policy_add_files(device, pwrscale, &tz_attr_group);
-	for (i = 0; i < pwr->num_pwrlevels - 1; i++) {
-		if (i == 0)
-			tz_pwrlevels[j] = pwr->pwrlevels[i].gpu_freq;
-		else if (pwr->pwrlevels[i].gpu_freq !=
-				pwr->pwrlevels[i - 1].gpu_freq) {
-			j++;
-			tz_pwrlevels[j] = pwr->pwrlevels[i].gpu_freq;
-		}
-	}
-	tz_pwrlevels[0] = j;
-	ret = scm_call(SCM_SVC_DCVS, TZ_INIT_ID, tz_pwrlevels,
-				sizeof(tz_pwrlevels), NULL, 0);
-	if (ret) {
-		KGSL_DRV_ERR(device, "Fall back to idle based GPU DCVS algo");
-		priv->idle_dcvs = 1;
-	}
-	return 0;
-}
-#else
-static int tz_init(struct kgsl_device *device, struct kgsl_pwrscale *pwrscale)
-{
-	return -EINVAL;
-}
-#endif /* CONFIG_MSM_SCM */
-
-static void tz_close(struct kgsl_device *device, struct kgsl_pwrscale *pwrscale)
-{
-	kgsl_pwrscale_policy_remove_files(device, pwrscale, &tz_attr_group);
-	kfree(pwrscale->priv);
-	pwrscale->priv = NULL;
-}
-
-struct kgsl_pwrscale_policy kgsl_pwrscale_policy_tz = {
-	.name = "trustzone",
-	.init = tz_init,
-	.busy = tz_busy,
-	.idle = tz_idle,
-	.sleep = tz_sleep,
-	.wake = tz_wake,
-	.close = tz_close
-};
-EXPORT_SYMBOL(kgsl_pwrscale_policy_tz);
diff --git a/drivers/gpu/msm/kgsl_sharedmem.h b/drivers/gpu/msm/kgsl_sharedmem.h
index 3986c61..505be69 100644
--- a/drivers/gpu/msm/kgsl_sharedmem.h
+++ b/drivers/gpu/msm/kgsl_sharedmem.h
@@ -141,6 +141,9 @@
 
 static inline void *kgsl_sg_alloc(unsigned int sglen)
 {
+	if (sglen >= ULONG_MAX / sizeof(struct scatterlist))
+		return NULL;
+
 	if ((sglen * sizeof(struct scatterlist)) <  PAGE_SIZE)
 		return kzalloc(sglen * sizeof(struct scatterlist), GFP_KERNEL);
 	else
diff --git a/drivers/gpu/msm/kgsl_trace.h b/drivers/gpu/msm/kgsl_trace.h
index 5f39b8b..c737cc8 100644
--- a/drivers/gpu/msm/kgsl_trace.h
+++ b/drivers/gpu/msm/kgsl_trace.h
@@ -796,6 +796,37 @@
 	)
 );
 
+
+TRACE_EVENT(kgsl_pwrstats,
+	TP_PROTO(struct kgsl_device *device, s64 time,
+		struct kgsl_power_stats *pstats),
+
+	TP_ARGS(device, time, pstats),
+
+	TP_STRUCT__entry(
+		__string(device_name, device->name)
+		__field(s64, total_time)
+		__field(u64, busy_time)
+		__field(u64, ram_time)
+		__field(u64, ram_wait)
+	),
+
+	TP_fast_assign(
+		__assign_str(device_name, device->name);
+		__entry->total_time = time;
+		__entry->busy_time = pstats->busy_time;
+		__entry->ram_time = pstats->ram_time;
+		__entry->ram_wait = pstats->ram_wait;
+	),
+
+	TP_printk(
+		"d_name=%s total=%lld busy=%lld ram_time=%lld ram_wait=%lld",
+		__get_str(device_name), __entry->total_time, __entry->busy_time,
+		__entry->ram_time, __entry->ram_wait
+	)
+);
+
+
 #endif /* _KGSL_TRACE_H */
 
 /* This part must be outside protection */
diff --git a/drivers/gpu/msm/z180.c b/drivers/gpu/msm/z180.c
index ae7aee0..270a7a6 100644
--- a/drivers/gpu/msm/z180.c
+++ b/drivers/gpu/msm/z180.c
@@ -94,7 +94,7 @@
 #define Z180_CMDWINDOW_ADDR_SHIFT		8
 
 static int z180_init(struct kgsl_device *device);
-static int z180_start(struct kgsl_device *device);
+static int z180_start(struct kgsl_device *device, int priority);
 static int z180_stop(struct kgsl_device *device);
 static int z180_wait(struct kgsl_device *device,
 				struct kgsl_context *context,
@@ -559,8 +559,7 @@
 	if (status)
 		goto error_close_ringbuffer;
 
-	kgsl_pwrscale_init(device);
-	kgsl_pwrscale_attach_policy(device, Z180_DEFAULT_PWRSCALE_POLICY);
+	kgsl_pwrscale_init(&pdev->dev, CONFIG_MSM_Z180_DEFAULT_GOVERNOR);
 
 	return status;
 
@@ -595,7 +594,7 @@
 	return 0;
 }
 
-static int z180_start(struct kgsl_device *device)
+static int z180_start(struct kgsl_device *device, int priority)
 {
 	int status = 0;
 
@@ -955,18 +954,16 @@
 static void z180_power_stats(struct kgsl_device *device,
 			    struct kgsl_power_stats *stats)
 {
-	struct kgsl_pwrctrl *pwr = &device->pwrctrl;
+	struct kgsl_pwrscale *pwrscale = &device->pwrscale;
 	s64 tmp = ktime_to_us(ktime_get());
 
-	if (pwr->time == 0) {
-		pwr->time = tmp;
-		stats->total_time = 0;
+	memset(stats, 0, sizeof(stats));
+	if (pwrscale->on_time == 0) {
+		pwrscale->on_time = tmp;
 		stats->busy_time = 0;
 	} else {
-		stats->total_time = tmp - pwr->time;
-		pwr->time = tmp;
-		stats->busy_time = tmp - device->on_time;
-		device->on_time = tmp;
+		stats->busy_time = tmp - pwrscale->on_time;
+		pwrscale->on_time = tmp;
 	}
 }
 
diff --git a/drivers/gpu/msm/z180.h b/drivers/gpu/msm/z180.h
index a36e92d..5b54445 100644
--- a/drivers/gpu/msm/z180.h
+++ b/drivers/gpu/msm/z180.h
@@ -26,8 +26,6 @@
 #define Z180_DEVICE(device) \
 		KGSL_CONTAINER_OF(device, struct z180_device, dev)
 
-#define Z180_DEFAULT_PWRSCALE_POLICY  NULL
-
 /* Wait a maximum of 10 seconds when trying to idle the core */
 #define Z180_IDLE_TIMEOUT (20 * 1000)
 
diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c
index a1cac54..937fb8c 100644
--- a/drivers/media/dvb/dvb-core/dmxdev.c
+++ b/drivers/media/dvb/dvb-core/dmxdev.c
@@ -899,7 +899,9 @@
 	} else {
 		int i;
 
+		spin_lock(&dmxdev->dvr_in_lock);
 		dmxdev->dvr_in_exit = 1;
+		spin_unlock(&dmxdev->dvr_in_lock);
 
 		wake_up_all(&dmxdev->dvr_cmd_buffer.queue);
 
diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
index 2124b13..63973b4 100644
--- a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
+++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
@@ -1285,8 +1285,8 @@
 
 	in_phyaddr = msm_cpp_fetch_buffer_info(cpp_dev,
 		&new_frame->input_buffer_info,
-		((new_frame->identity >> 16) & 0xFFFF),
-		(new_frame->identity & 0xFFFF), &in_fd);
+		((new_frame->input_buffer_info.identity >> 16) & 0xFFFF),
+		(new_frame->input_buffer_info.identity & 0xFFFF), &in_fd);
 	if (!in_phyaddr) {
 		pr_err("error gettting input physical address\n");
 		rc = -EINVAL;
diff --git a/drivers/media/platform/msm/vidc/hfi_packetization.c b/drivers/media/platform/msm/vidc/hfi_packetization.c
index ae94287..2fb3c35 100644
--- a/drivers/media/platform/msm/vidc/hfi_packetization.c
+++ b/drivers/media/platform/msm/vidc/hfi_packetization.c
@@ -553,6 +553,7 @@
 	pkt->alloc_len = output_frame->alloc_len;
 	pkt->filled_len = output_frame->filled_len;
 	pkt->offset = output_frame->offset;
+	pkt->rgData[0] = output_frame->extradata_size;
 	dprintk(VIDC_DBG, "### Q OUTPUT BUFFER ###: %d, %d, %d\n",
 			pkt->alloc_len, pkt->filled_len, pkt->offset);
 
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index 42460fa..c63af6c 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -2448,9 +2448,12 @@
 			extra_idx =
 			EXTRADATA_IDX(inst->fmts[CAPTURE_PORT]->num_planes);
 			if (extra_idx && (extra_idx < VIDEO_MAX_PLANES) &&
-				vb->v4l2_planes[extra_idx].m.userptr)
+				vb->v4l2_planes[extra_idx].m.userptr) {
 				frame_data.extradata_addr =
 					vb->v4l2_planes[extra_idx].m.userptr;
+				frame_data.extradata_size =
+					vb->v4l2_planes[extra_idx].length;
+			}
 			dprintk(VIDC_DBG,
 				"Sending ftb to hal: Alloc: %d :filled: %d",
 				frame_data.alloc_len, frame_data.filled_len);
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_api.h b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
index cc07806..ee83eee 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_api.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
@@ -862,6 +862,7 @@
 	u32 mark_target;
 	u32 mark_data;
 	u32 clnt_data;
+	u32 extradata_size;
 };
 
 struct vidc_seq_hdr {
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index 2fe5618..ce69e6d 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -91,7 +91,6 @@
 
 static struct class *driver_class;
 static dev_t qseecom_device_no;
-static struct cdev qseecom_cdev;
 
 static DEFINE_MUTEX(qsee_bw_mutex);
 static DEFINE_MUTEX(app_access_lock);
@@ -162,6 +161,7 @@
 	uint32_t qsee_perf_client;
 	struct qseecom_clk qsee;
 	struct qseecom_clk ce_drv;
+	struct cdev cdev;
 };
 
 struct qseecom_client_handle {
@@ -3341,7 +3341,7 @@
 	if (IS_ERR(driver_class)) {
 		rc = -ENOMEM;
 		pr_err("class_create failed %d\n", rc);
-		goto unregister_chrdev_region;
+		goto exit_unreg_chrdev_region;
 	}
 
 	class_dev = device_create(driver_class, NULL, qseecom_device_no, NULL,
@@ -3349,16 +3349,16 @@
 	if (!class_dev) {
 		pr_err("class_device_create failed %d\n", rc);
 		rc = -ENOMEM;
-		goto class_destroy;
+		goto exit_destroy_class;
 	}
 
-	cdev_init(&qseecom_cdev, &qseecom_fops);
-	qseecom_cdev.owner = THIS_MODULE;
+	cdev_init(&qseecom.cdev, &qseecom_fops);
+	qseecom.cdev.owner = THIS_MODULE;
 
-	rc = cdev_add(&qseecom_cdev, MKDEV(MAJOR(qseecom_device_no), 0), 1);
+	rc = cdev_add(&qseecom.cdev, MKDEV(MAJOR(qseecom_device_no), 0), 1);
 	if (rc < 0) {
 		pr_err("cdev_add failed %d\n", rc);
-		goto err;
+		goto exit_destroy_device;
 	}
 
 	INIT_LIST_HEAD(&qseecom.registered_listener_list_head);
@@ -3374,7 +3374,7 @@
 				&qsee_not_legacy, sizeof(qsee_not_legacy));
 	if (rc) {
 		pr_err("Failed to retrieve QSEOS version information %d\n", rc);
-		goto err;
+		goto exit_del_cdev;
 	}
 	if (qsee_not_legacy) {
 		uint32_t feature = 10;
@@ -3384,14 +3384,14 @@
 			&qseecom.qsee_version, sizeof(qseecom.qsee_version));
 		if (rc) {
 			pr_err("Failed to get QSEE version info %d\n", rc);
-			goto err;
+			goto exit_del_cdev;
 		}
 		qseecom.qseos_version = QSEOS_VERSION_14;
 	} else {
 		pr_err("QSEE legacy version is not supported:");
 		pr_err("Support for TZ1.3 and earlier is deprecated\n");
 		rc = -EINVAL;
-		goto err;
+		goto exit_del_cdev;
 	}
 	qseecom.commonlib_loaded = false;
 	qseecom.pdev = class_dev;
@@ -3400,7 +3400,7 @@
 	if (qseecom.ion_clnt == NULL) {
 		pr_err("Ion client cannot be created\n");
 		rc = -ENOMEM;
-		goto err;
+		goto exit_del_cdev;
 	}
 
 	/* register client for bus scaling */
@@ -3412,7 +3412,7 @@
 			pr_err("Fail to get disk-encrypt pipe pair information.\n");
 			qseecom.ce_info.disk_encrypt_pipe = 0xff;
 			rc = -EINVAL;
-			goto err;
+			goto exit_destroy_ion_client;
 		} else {
 			pr_warn("bam_pipe_pair=0x%x",
 			qseecom.ce_info.disk_encrypt_pipe);
@@ -3424,7 +3424,7 @@
 			pr_err("Fail to get qsee ce hw instance information.\n");
 			qseecom.ce_info.qsee_ce_hw_instance = 0xff;
 			rc = -EINVAL;
-			goto err;
+			goto exit_destroy_ion_client;
 		} else {
 			pr_warn("qsee-ce-hw-instance=0x%x",
 			qseecom.ce_info.qsee_ce_hw_instance);
@@ -3436,7 +3436,7 @@
 			pr_err("Fail to get hlos ce hw instance information.\n");
 			qseecom.ce_info.hlos_ce_hw_instance = 0xff;
 			rc = -EINVAL;
-			goto err;
+			goto exit_destroy_ion_client;
 		} else {
 			pr_warn("hlos-ce-hw-instance=0x%x",
 			qseecom.ce_info.hlos_ce_hw_instance);
@@ -3447,13 +3447,13 @@
 
 		ret = __qseecom_init_clk(CLK_QSEE);
 		if (ret)
-			goto err;
+			goto exit_destroy_ion_client;
 
 		if (qseecom.qsee.instance != qseecom.ce_drv.instance) {
 			ret = __qseecom_init_clk(CLK_CE_DRV);
 			if (ret) {
 				__qseecom_deinit_clk(CLK_QSEE);
-				goto err;
+				goto exit_destroy_ion_client;
 			}
 		} else {
 			struct qseecom_clk *qclk;
@@ -3483,7 +3483,7 @@
 			} else {
 				pr_err("Fail to get secure app region info\n");
 				rc = -EINVAL;
-				goto err;
+				goto exit_destroy_ion_client;
 			}
 			rc = scm_call(SCM_SVC_TZSCHEDULER, 1, &req, sizeof(req),
 							&resp, sizeof(resp));
@@ -3491,7 +3491,7 @@
 				pr_err("send secapp reg fail %d resp.res %d\n",
 							rc, resp.result);
 				rc = -EINVAL;
-				goto err;
+				goto exit_destroy_ion_client;
 			}
 		}
 	} else {
@@ -3505,11 +3505,16 @@
 	if (!qseecom.qsee_perf_client)
 		pr_err("Unable to register bus client\n");
 	return 0;
-err:
+
+exit_destroy_ion_client:
+	ion_client_destroy(qseecom.ion_clnt);
+exit_del_cdev:
+	cdev_del(&qseecom.cdev);
+exit_destroy_device:
 	device_destroy(driver_class, qseecom_device_no);
-class_destroy:
+exit_destroy_class:
 	class_destroy(driver_class);
-unregister_chrdev_region:
+exit_unreg_chrdev_region:
 	unregister_chrdev_region(qseecom_device_no, 1);
 	return rc;
 }
@@ -3520,69 +3525,64 @@
 	unsigned long flags = 0;
 	int ret = 0;
 
-	if (pdev->dev.platform_data != NULL)
-		msm_bus_scale_unregister_client(qseecom.qsee_perf_client);
-
 	spin_lock_irqsave(&qseecom.registered_kclient_list_lock, flags);
-	kclient = list_entry((&qseecom.registered_kclient_list_head)->next,
-		struct qseecom_registered_kclient_list, list);
-	if (list_empty(&kclient->list)) {
-		spin_unlock_irqrestore(&qseecom.registered_kclient_list_lock,
-			flags);
-		return 0;
-	}
+
 	list_for_each_entry(kclient, &qseecom.registered_kclient_list_head,
-				list) {
-			if (kclient)
-				list_del(&kclient->list);
-			break;
-	}
-	spin_unlock_irqrestore(&qseecom.registered_kclient_list_lock, flags);
+								list) {
+		if (!kclient)
+			goto exit_irqrestore;
 
+		/* Break the loop if client handle is NULL */
+		if (!kclient->handle)
+			goto exit_free_kclient;
 
-	while (kclient->handle != NULL) {
+		if (list_empty(&kclient->list))
+			goto exit_free_kc_handle;
+
+		list_del(&kclient->list);
 		ret = qseecom_unload_app(kclient->handle->dev);
-		if (ret == 0) {
+		if (!ret) {
 			kzfree(kclient->handle->dev);
 			kzfree(kclient->handle);
 			kzfree(kclient);
 		}
-		spin_lock_irqsave(&qseecom.registered_kclient_list_lock, flags);
-		kclient = list_entry(
-				(&qseecom.registered_kclient_list_head)->next,
-				struct qseecom_registered_kclient_list, list);
-		if (list_empty(&kclient->list)) {
-			spin_unlock_irqrestore(
-				&qseecom.registered_kclient_list_lock, flags);
-			return 0;
-		}
-		list_for_each_entry(kclient,
-				&qseecom.registered_kclient_list_head, list) {
-			if (kclient)
-				list_del(&kclient->list);
-			break;
-		}
-		spin_unlock_irqrestore(&qseecom.registered_kclient_list_lock,
-				flags);
-		if (!kclient) {
-			ret = 0;
-			break;
-		}
 	}
-	if (qseecom.qseos_version  > QSEEE_VERSION_00)
+
+exit_free_kc_handle:
+	kzfree(kclient->handle);
+exit_free_kclient:
+	kzfree(kclient);
+exit_irqrestore:
+	spin_unlock_irqrestore(&qseecom.registered_kclient_list_lock, flags);
+
+	if (qseecom.qseos_version > QSEEE_VERSION_00)
 		qseecom_unload_commonlib_image();
 
 	if (qseecom.qsee_perf_client)
 		msm_bus_scale_client_update_request(qseecom.qsee_perf_client,
 									0);
+	if (pdev->dev.platform_data != NULL)
+		msm_bus_scale_unregister_client(qseecom.qsee_perf_client);
+
 	/* register client for bus scaling */
 	if (pdev->dev.of_node) {
 		__qseecom_deinit_clk(CLK_QSEE);
 		if (qseecom.qsee.instance != qseecom.ce_drv.instance)
 			__qseecom_deinit_clk(CLK_CE_DRV);
 	}
+
+	ion_client_destroy(qseecom.ion_clnt);
+
+	cdev_del(&qseecom.cdev);
+
+	device_destroy(driver_class, qseecom_device_no);
+
+	class_destroy(driver_class);
+
+	unregister_chrdev_region(qseecom_device_no, 1);
+
 	return ret;
-};
+}
 
 static struct of_device_id qseecom_match[] = {
 	{
@@ -3608,10 +3608,7 @@
 
 static void __devexit qseecom_exit(void)
 {
-	device_destroy(driver_class, qseecom_device_no);
-	class_destroy(driver_class);
-	unregister_chrdev_region(qseecom_device_no, 1);
-	ion_client_destroy(qseecom.ion_clnt);
+	platform_driver_unregister(&qseecom_plat_driver);
 }
 
 MODULE_LICENSE("GPL v2");
diff --git a/drivers/misc/tspp.c b/drivers/misc/tspp.c
index 36bdf45..3d69473 100644
--- a/drivers/misc/tspp.c
+++ b/drivers/misc/tspp.c
@@ -1821,7 +1821,7 @@
 	}
 
 	if (filter->priority >= TSPP_NUM_PRIORITIES) {
-		pr_err("tspp invalid source");
+		pr_err("tspp invalid filter priority");
 		return -ENOSR;
 	}
 
@@ -1950,6 +1950,10 @@
 		pr_err("tspp_remove: can't find device %i", dev);
 		return -ENODEV;
 	}
+	if (filter->priority >= TSPP_NUM_PRIORITIES) {
+		pr_err("tspp invalid filter priority");
+		return -ENOSR;
+	}
 	channel = &pdev->channels[channel_id];
 
 	src = channel->src;
diff --git a/drivers/net/wireless/ath/regd.c b/drivers/net/wireless/ath/regd.c
index 10dea37..bd4ecf3 100644
--- a/drivers/net/wireless/ath/regd.c
+++ b/drivers/net/wireless/ath/regd.c
@@ -520,6 +520,7 @@
 		 */
 		regd = ath_world_regdomain(reg);
 		wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
+		wiphy->country_ie_pref = NL80211_COUNTRY_IE_FOLLOW_POWER;
 	} else {
 		/*
 		 * This gets applied in the case of the absence of CRDA,
diff --git a/drivers/power/qpnp-bms.c b/drivers/power/qpnp-bms.c
index 9727787..aa4e016 100644
--- a/drivers/power/qpnp-bms.c
+++ b/drivers/power/qpnp-bms.c
@@ -1876,7 +1876,7 @@
 		if (batt_terminal_uv >= chip->max_voltage_uv - VDD_MAX_ERR) {
 			chip->soc_at_cv = soc;
 			chip->prev_chg_soc = soc;
-			chip->ibat_at_cv_ua = ibat_ua;
+			chip->ibat_at_cv_ua = params->iavg_ua;
 			pr_debug("CC_TO_CV ibat_ua = %d CHG SOC %d\n",
 					ibat_ua, soc);
 		} else {
@@ -1927,7 +1927,7 @@
 	soc_ibat = bound_soc(linear_interpolate(chip->soc_at_cv,
 					chip->ibat_at_cv_ua,
 					100, -1 * chip->chg_term_ua,
-					ibat_ua));
+					params->iavg_ua));
 	weight_ibat = bound_soc(linear_interpolate(1, chip->soc_at_cv,
 					100, 100, chip->prev_chg_soc));
 	weight_cc = 100 - weight_ibat;
diff --git a/drivers/staging/zram/zram_drv.c b/drivers/staging/zram/zram_drv.c
index 91d94b5..83fa657 100644
--- a/drivers/staging/zram/zram_drv.c
+++ b/drivers/staging/zram/zram_drv.c
@@ -32,6 +32,7 @@
 #include <linux/lzo.h>
 #include <linux/string.h>
 #include <linux/vmalloc.h>
+#include <linux/ratelimit.h>
 
 #include "zram_drv.h"
 
@@ -39,6 +40,12 @@
 static int zram_major;
 static struct zram *zram_devices;
 
+/*
+ * We don't need to see memory allocation errors more than once every 1
+ * second to know that a problem is occurring.
+ */
+#define ALLOC_ERROR_LOG_RATE_MS 1000
+
 /* Module params (documentation at end) */
 static unsigned int num_devices = 1;
 
@@ -221,7 +228,8 @@
 		goto free_buffer;
 	}
 
-	meta->mem_pool = zs_create_pool(GFP_NOIO | __GFP_HIGHMEM);
+	meta->mem_pool = zs_create_pool(GFP_NOIO | __GFP_HIGHMEM |
+					__GFP_NOWARN);
 	if (!meta->mem_pool) {
 		pr_err("Error creating memory pool\n");
 		goto free_table;
@@ -399,6 +407,7 @@
 	struct page *page;
 	unsigned char *user_mem, *cmem, *src, *uncmem = NULL;
 	struct zram_meta *meta = zram->meta;
+	static unsigned long zram_rs_time;
 
 	page = bvec->bv_page;
 	src = meta->compress_buffer;
@@ -472,8 +481,10 @@
 
 	handle = zs_malloc(meta->mem_pool, clen);
 	if (!handle) {
-		pr_info("Error allocating memory for compressed page: %u, size=%zu\n",
-			index, clen);
+		if (printk_timed_ratelimit(&zram_rs_time,
+					   ALLOC_ERROR_LOG_RATE_MS))
+			pr_info("Error allocating memory for compressed page: %u, size=%zu\n",
+				index, clen);
 		ret = -ENOMEM;
 		goto out;
 	}
diff --git a/drivers/staging/zram/zram_drv.h b/drivers/staging/zram/zram_drv.h
index 97a3acf..508a19f 100644
--- a/drivers/staging/zram/zram_drv.h
+++ b/drivers/staging/zram/zram_drv.h
@@ -32,7 +32,7 @@
  * Pages that compress to size greater than this are stored
  * uncompressed in memory.
  */
-static const size_t max_zpage_size = PAGE_SIZE / 4 * 3;
+static const size_t max_zpage_size = PAGE_SIZE / 10 * 9;
 
 /*
  * NOTE: max_zpage_size must be less than or equal to:
diff --git a/drivers/staging/zsmalloc/zsmalloc-main.c b/drivers/staging/zsmalloc/zsmalloc-main.c
index 1a67537..523b937 100644
--- a/drivers/staging/zsmalloc/zsmalloc-main.c
+++ b/drivers/staging/zsmalloc/zsmalloc-main.c
@@ -472,7 +472,7 @@
 	set_page_private(page, 0);
 	page->mapping = NULL;
 	page->freelist = NULL;
-	page_mapcount_reset(page);
+	reset_page_mapcount(page);
 }
 
 static void free_zspage(struct page *first_page)
diff --git a/drivers/uio/Kconfig b/drivers/uio/Kconfig
index 6f3ea9b..ad66113 100644
--- a/drivers/uio/Kconfig
+++ b/drivers/uio/Kconfig
@@ -111,4 +111,11 @@
 	  To compile this driver as a module, choose M here: the module
 	  will be called uio_pruss.
 
+config UIO_MSM_SHAREDMEM
+	bool "MSM shared memory driver"
+	default n
+	help
+	  Provides the clients with their respective alloted shared memory
+	  addresses which are used as transport buffer.
+
 endif
diff --git a/drivers/uio/Makefile b/drivers/uio/Makefile
index d4dd9a5..c4d177a 100644
--- a/drivers/uio/Makefile
+++ b/drivers/uio/Makefile
@@ -7,3 +7,4 @@
 obj-$(CONFIG_UIO_PCI_GENERIC)	+= uio_pci_generic.o
 obj-$(CONFIG_UIO_NETX)	+= uio_netx.o
 obj-$(CONFIG_UIO_PRUSS)         += uio_pruss.o
+obj-$(CONFIG_UIO_MSM_SHAREDMEM) += msm_sharedmem.o
diff --git a/drivers/uio/msm_sharedmem.c b/drivers/uio/msm_sharedmem.c
new file mode 100644
index 0000000..438f002
--- /dev/null
+++ b/drivers/uio/msm_sharedmem.c
@@ -0,0 +1,87 @@
+/* Copyright (c) 2013, 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.
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/uio_driver.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+
+#define DRIVER_NAME "msm_sharedmem"
+
+static int msm_sharedmem_probe(struct platform_device *pdev)
+{
+	int ret = 0;
+	struct uio_info *info = NULL;
+	struct resource *clnt_res = NULL;
+
+	/* Get the addresses from platform-data */
+	if (!pdev->dev.of_node) {
+		pr_err("Node not found\n");
+		ret = -ENODEV;
+		goto out;
+	}
+	clnt_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!clnt_res) {
+		pr_err("resource not found\n");
+		return -ENODEV;
+	}
+
+	info = devm_kzalloc(&pdev->dev, sizeof(struct uio_info), GFP_KERNEL);
+	if (!info)
+		return -ENOMEM;
+
+	info->name = clnt_res->name;
+	info->version = "1.0";
+	info->mem[0].addr = clnt_res->start;
+	info->mem[0].size = resource_size(clnt_res);
+	info->mem[0].memtype = UIO_MEM_PHYS;
+
+	/* Setup device */
+	ret = uio_register_device(&pdev->dev, info);
+	if (ret)
+		goto out;
+
+	dev_set_drvdata(&pdev->dev, info);
+	pr_debug("Device created for client '%s'\n", clnt_res->name);
+out:
+	return ret;
+}
+
+static int msm_sharedmem_remove(struct platform_device *pdev)
+{
+	struct uio_info *info = dev_get_drvdata(&pdev->dev);
+
+	uio_unregister_device(info);
+
+	return 0;
+}
+
+static struct of_device_id msm_sharedmem_of_match[] = {
+	{.compatible = "qcom,sharedmem-uio",},
+	{},
+};
+MODULE_DEVICE_TABLE(of, msm_sharedmem_of_match);
+
+static struct platform_driver msm_sharedmem_driver = {
+	.probe          = msm_sharedmem_probe,
+	.remove         = msm_sharedmem_remove,
+	.driver         = {
+		.name   = DRIVER_NAME,
+		.owner	= THIS_MODULE,
+		.of_match_table = msm_sharedmem_of_match,
+	},
+};
+
+module_platform_driver(msm_sharedmem_driver);
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/video/msm/mdss/mdp3.c b/drivers/video/msm/mdss/mdp3.c
index d642093..c4986ef 100644
--- a/drivers/video/msm/mdss/mdp3.c
+++ b/drivers/video/msm/mdss/mdp3.c
@@ -184,11 +184,11 @@
 	u32 mdp_interrupt = 0;
 
 	spin_lock(&mdata->irq_lock);
-	if (!mdata->irq_mask) {
+	if (!mdata->irq_mask)
 		pr_err("spurious interrupt\n");
-		spin_unlock(&mdata->irq_lock);
-		return IRQ_HANDLED;
-	}
+
+	clk_enable(mdp3_res->clocks[MDP3_CLK_AHB]);
+	clk_enable(mdp3_res->clocks[MDP3_CLK_CORE]);
 
 	mdp_interrupt = MDP3_REG_READ(MDP3_REG_INTR_STATUS);
 	MDP3_REG_WRITE(MDP3_REG_INTR_CLEAR, mdp_interrupt);
@@ -202,6 +202,10 @@
 		mdp_interrupt = mdp_interrupt >> 1;
 		i++;
 	}
+
+	clk_disable(mdp3_res->clocks[MDP3_CLK_AHB]);
+	clk_disable(mdp3_res->clocks[MDP3_CLK_CORE]);
+
 	spin_unlock(&mdata->irq_lock);
 
 	return IRQ_HANDLED;
@@ -281,8 +285,6 @@
 	spin_lock_irqsave(&mdp3_res->irq_lock, flag);
 	memset(mdp3_res->irq_ref_count, 0, sizeof(u32) * MDP3_MAX_INTR);
 	mdp3_res->irq_mask = 0;
-	MDP3_REG_WRITE(MDP3_REG_INTR_ENABLE, 0);
-	MDP3_REG_WRITE(MDP3_REG_INTR_CLEAR, 0xfffffff);
 	disable_irq_nosync(mdp3_res->irq);
 	spin_unlock_irqrestore(&mdp3_res->irq_lock, flag);
 }
@@ -415,10 +417,10 @@
 	count = mdp3_res->clock_ref_count[clk_idx];
 	if (count == 1 && enable) {
 		pr_debug("clk=%d en=%d\n", clk_idx, enable);
-		ret = clk_prepare_enable(clk);
+		ret = clk_enable(clk);
 	} else if (count == 0) {
 		pr_debug("clk=%d disable\n", clk_idx);
-		clk_disable_unprepare(clk);
+		clk_disable(clk);
 		ret = 0;
 	} else if (count < 0) {
 		pr_err("clk=%d count=%d\n", clk_idx, count);
@@ -554,7 +556,7 @@
 		clk_put(mdp3_res->clocks[MDP3_CLK_DSI]);
 }
 
-int mdp3_clk_enable(int enable)
+int mdp3_clk_enable(int enable, int dsi_clk)
 {
 	int rc;
 
@@ -564,7 +566,79 @@
 	rc = mdp3_clk_update(MDP3_CLK_AHB, enable);
 	rc |= mdp3_clk_update(MDP3_CLK_CORE, enable);
 	rc |= mdp3_clk_update(MDP3_CLK_VSYNC, enable);
-	rc |= mdp3_clk_update(MDP3_CLK_DSI, enable);
+	if (dsi_clk)
+		rc |= mdp3_clk_update(MDP3_CLK_DSI, enable);
+	mutex_unlock(&mdp3_res->res_mutex);
+	return rc;
+}
+
+int mdp3_clk_prepare(void)
+{
+	int rc = 0;
+
+	mutex_lock(&mdp3_res->res_mutex);
+	mdp3_res->clk_prepare_count++;
+	if (mdp3_res->clk_prepare_count == 1) {
+		rc = clk_prepare(mdp3_res->clocks[MDP3_CLK_AHB]);
+		if (rc < 0)
+			goto error0;
+		rc = clk_prepare(mdp3_res->clocks[MDP3_CLK_CORE]);
+		if (rc < 0)
+			goto error1;
+		rc = clk_prepare(mdp3_res->clocks[MDP3_CLK_VSYNC]);
+		if (rc < 0)
+			goto error2;
+		rc = clk_prepare(mdp3_res->clocks[MDP3_CLK_DSI]);
+		if (rc < 0)
+			goto error3;
+	}
+	mutex_unlock(&mdp3_res->res_mutex);
+	return rc;
+
+error3:
+	clk_unprepare(mdp3_res->clocks[MDP3_CLK_VSYNC]);
+error2:
+	clk_unprepare(mdp3_res->clocks[MDP3_CLK_CORE]);
+error1:
+	clk_unprepare(mdp3_res->clocks[MDP3_CLK_AHB]);
+error0:
+	mdp3_res->clk_prepare_count--;
+	mutex_unlock(&mdp3_res->res_mutex);
+	return rc;
+}
+
+void mdp3_clk_unprepare(void)
+{
+	mutex_lock(&mdp3_res->res_mutex);
+	mdp3_res->clk_prepare_count--;
+	if (mdp3_res->clk_prepare_count == 0) {
+		clk_unprepare(mdp3_res->clocks[MDP3_CLK_AHB]);
+		clk_unprepare(mdp3_res->clocks[MDP3_CLK_CORE]);
+		clk_unprepare(mdp3_res->clocks[MDP3_CLK_VSYNC]);
+		clk_unprepare(mdp3_res->clocks[MDP3_CLK_DSI]);
+	} else if (mdp3_res->clk_prepare_count < 0) {
+		pr_err("mdp3 clk unprepare mismatch\n");
+	}
+	mutex_unlock(&mdp3_res->res_mutex);
+}
+
+int mdp3_get_mdp_dsi_clk(void)
+{
+	int rc;
+
+	mutex_lock(&mdp3_res->res_mutex);
+	clk_prepare(mdp3_res->clocks[MDP3_CLK_DSI]);
+	rc = mdp3_clk_update(MDP3_CLK_DSI, 1);
+	mutex_unlock(&mdp3_res->res_mutex);
+	return rc;
+}
+
+int mdp3_put_mdp_dsi_clk(void)
+{
+	int rc;
+	mutex_lock(&mdp3_res->res_mutex);
+	rc = mdp3_clk_update(MDP3_CLK_DSI, 0);
+	clk_unprepare(mdp3_res->clocks[MDP3_CLK_DSI]);
 	mutex_unlock(&mdp3_res->res_mutex);
 	return rc;
 }
@@ -1512,8 +1586,17 @@
 static int mdp3_init(struct msm_fb_data_type *mfd)
 {
 	int rc;
+
 	rc = mdp3_ctrl_init(mfd);
-	rc |= mdp3_ppp_res_init(mfd);
+	if (rc) {
+		pr_err("mdp3 ctl init fail\n");
+		return rc;
+	}
+
+	rc = mdp3_ppp_res_init(mfd);
+	if (rc)
+		pr_err("mdp3 ppp res init fail\n");
+
 	return rc;
 }
 
@@ -1740,9 +1823,16 @@
 
 	pr_debug("mdp3__continuous_splash_on\n");
 
-	rc = mdp3_clk_enable(1);
+	rc = mdp3_clk_prepare();
+	if (rc) {
+		pr_err("fail to prepare clk\n");
+		return rc;
+	}
+
+	rc = mdp3_clk_enable(1, 1);
 	if (rc) {
 		pr_err("fail to enable clk\n");
+		mdp3_clk_unprepare();
 		return rc;
 	}
 
@@ -1779,8 +1869,10 @@
 	return 0;
 
 splash_on_err:
-	if (mdp3_clk_enable(0))
+	if (mdp3_clk_enable(0, 1))
 		pr_err("%s: Unable to disable mdp3 clocks\n", __func__);
+
+	mdp3_clk_unprepare();
 	return rc;
 }
 
@@ -1813,10 +1905,13 @@
 
 static void mdp3_debug_enable_clock(int on)
 {
-	if (on)
-		mdp3_clk_enable(1);
-	else
-		mdp3_clk_enable(0);
+	if (on) {
+		mdp3_clk_prepare();
+		mdp3_clk_enable(1, 0);
+	} else {
+		mdp3_clk_enable(0, 0);
+		mdp3_clk_unprepare();
+	}
 }
 
 static int mdp3_debug_init(struct platform_device *pdev)
diff --git a/drivers/video/msm/mdss/mdp3.h b/drivers/video/msm/mdss/mdp3.h
index e66b5ac..e0dd021 100644
--- a/drivers/video/msm/mdss/mdp3.h
+++ b/drivers/video/msm/mdss/mdp3.h
@@ -152,6 +152,8 @@
 	struct mdss_panel_cfg pan_cfg;
 	u32 splash_mem_addr;
 	u32 splash_mem_size;
+
+	int clk_prepare_count;
 };
 
 struct mdp3_img_data {
@@ -175,7 +177,9 @@
 void mdp3_irq_register(void);
 void mdp3_irq_deregister(void);
 int mdp3_clk_set_rate(int clk_type, unsigned long clk_rate, int client);
-int mdp3_clk_enable(int enable);
+int mdp3_clk_enable(int enable, int dsi_clk);
+int mdp3_clk_prepare(void);
+void mdp3_clk_unprepare(void);
 int mdp3_bus_scale_set_quota(int client, u64 ab_quota, u64 ib_quota);
 int mdp3_put_img(struct mdp3_img_data *data, int client);
 int mdp3_get_img(struct msmfb_data *img, struct mdp3_img_data *data,
@@ -187,6 +191,8 @@
 int mdp3_parse_dt_splash(struct msm_fb_data_type *mfd);
 void mdp3_release_splash_memory(void);
 int mdp3_create_sysfs_link(struct device *dev);
+int mdp3_get_mdp_dsi_clk(void);
+int mdp3_put_mdp_dsi_clk(void);
 
 #define MDP3_REG_WRITE(addr, val) writel_relaxed(val, mdp3_res->mdp_base + addr)
 #define MDP3_REG_READ(addr) readl_relaxed(mdp3_res->mdp_base + addr)
diff --git a/drivers/video/msm/mdss/mdp3_ctrl.c b/drivers/video/msm/mdss/mdp3_ctrl.c
index b123ccb..de4e9a1 100644
--- a/drivers/video/msm/mdss/mdp3_ctrl.c
+++ b/drivers/video/msm/mdss/mdp3_ctrl.c
@@ -118,7 +118,9 @@
 	}
 
 	mutex_lock(&mdp3_session->lock);
+	mdp3_clk_enable(1, 0);
 	mdp3_session->dma->vsync_enable(mdp3_session->dma, arg);
+	mdp3_clk_enable(0, 0);
 	if (enable && mdp3_session->status == 1 && !mdp3_session->intf->active)
 		mod_timer(&mdp3_session->vsync_timer,
 			jiffies + msecs_to_jiffies(mdp3_session->vsync_period));
@@ -236,12 +238,24 @@
 		mdp3_clk_set_rate(MDP3_CLK_VSYNC, MDP_VSYNC_CLK_RATE,
 				MDP3_CLIENT_DMA_P);
 
-		rc = mdp3_clk_enable(true);
-		if (rc)
+		rc = mdp3_clk_prepare();
+		if (rc) {
+			pr_err("mdp3 clk prepare fail\n");
 			return rc;
+		}
 
+		rc = mdp3_clk_enable(1, 1);
+		if (rc) {
+			pr_err("mdp3 clk enable fail\n");
+			mdp3_clk_unprepare();
+			return rc;
+		}
 	} else {
-		rc = mdp3_clk_enable(false);
+		rc = mdp3_clk_enable(0, 1);
+		if (rc)
+			pr_err("mdp3 clk disable fail\n");
+		else
+			mdp3_clk_unprepare();
 	}
 	return rc;
 }
@@ -517,19 +531,21 @@
 		goto off_error;
 	}
 
+	mdp3_clk_enable(1, 0);
+
 	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");
 
+	mdp3_clk_enable(0, 0);
+
 	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");
 
-
-
 	mdp3_irq_deregister();
 
 	pr_debug("mdp3_ctrl_off stop clock\n");
@@ -650,7 +666,7 @@
 	if (rc)
 		pr_err("fail to turn off panel\n");
 
-	rc = mdp3_ctrl_res_req_clk(mfd, 0);
+	rc = mdp3_put_mdp_dsi_clk();
 	if (rc) {
 		pr_err("fail to release mdp clocks\n");
 		goto reset_error;
@@ -680,7 +696,7 @@
 		goto reset_error;
 	}
 
-	rc = mdp3_ctrl_res_req_clk(mfd, 1);
+	rc = mdp3_get_mdp_dsi_clk();
 	if (rc) {
 		pr_err("fail to turn on mdp clks\n");
 		goto reset_error;
@@ -845,9 +861,11 @@
 
 	data = mdp3_bufq_pop(&mdp3_session->bufq_in);
 	if (data) {
+		mdp3_clk_enable(1, 0);
 		mdp3_session->dma->update(mdp3_session->dma,
 			(void *)data->addr,
 			mdp3_session->intf);
+		mdp3_clk_enable(0, 0);
 		mdp3_bufq_push(&mdp3_session->bufq_out, data);
 	}
 
@@ -912,6 +930,7 @@
 		goto pan_error;
 	}
 
+	mdp3_clk_enable(1, 0);
 	if (mfd->fbi->screen_base) {
 		mdp3_session->dma->update(mdp3_session->dma,
 				(void *)mfd->iova + offset,
@@ -920,6 +939,7 @@
 		pr_debug("mdp3_ctrl_pan_display no memory, stop interface");
 		mdp3_session->dma->stop(mdp3_session->dma, mdp3_session->intf);
 	}
+	mdp3_clk_enable(0, 0);
 
 	if (mdp3_session->first_commit) {
 		/*wait for one frame time to ensure frame is sent to panel*/
@@ -1034,10 +1054,11 @@
 
 	if (session->histo_status) {
 		pr_err("mdp3_histogram_start already started\n");
-		ret = -EBUSY;
-		goto histogram_start_err;
+		mutex_unlock(&session->histo_lock);
+		return -EBUSY;
 	}
 
+	mdp3_clk_enable(1, 0);
 	ret = session->dma->histo_op(session->dma, MDP3_DMA_HISTO_OP_RESET);
 	if (ret) {
 		pr_err("mdp3_histogram_start reset error\n");
@@ -1063,6 +1084,8 @@
 	session->histo_status = 1;
 
 histogram_start_err:
+	if (ret)
+		mdp3_clk_enable(0, 0);
 	mutex_unlock(&session->histo_lock);
 	return ret;
 }
@@ -1086,6 +1109,7 @@
 	}
 
 	ret = session->dma->histo_op(session->dma, MDP3_DMA_HISTO_OP_CANCEL);
+	mdp3_clk_enable(0, 0);
 	if (ret)
 		pr_err("mdp3_histogram_stop error\n");
 
@@ -1199,7 +1223,9 @@
 	ccs.post_lv = data->csc_data.csc_post_lv;
 
 	mutex_lock(&session->lock);
+	mdp3_clk_enable(1, 0);
 	ret = session->dma->config_ccs(session->dma, &config, &ccs);
+	mdp3_clk_enable(0, 0);
 	mutex_unlock(&session->lock);
 	return ret;
 }
@@ -1341,8 +1367,10 @@
 		return -EPERM;
 	}
 
+	mdp3_clk_enable(1, 0);
 	rc = mdp3_session->dma->config_lut(mdp3_session->dma, &lut_config,
 					&lut);
+	mdp3_clk_enable(0, 0);
 	if (rc)
 		pr_err("mdp3_ctrl_lut_update failed\n");
 
diff --git a/drivers/video/msm/mdss/mdp3_dma.c b/drivers/video/msm/mdss/mdp3_dma.c
index 89f3e27..3a2c94b 100644
--- a/drivers/video/msm/mdss/mdp3_dma.c
+++ b/drivers/video/msm/mdss/mdp3_dma.c
@@ -828,6 +828,9 @@
 					MDP3_DMA_CALLBACK_TYPE_DMA_DONE);
 	mdp3_irq_disable(MDP3_INTR_LCDC_UNDERFLOW);
 
+	MDP3_REG_WRITE(MDP3_REG_INTR_ENABLE, 0);
+	MDP3_REG_WRITE(MDP3_REG_INTR_CLEAR, 0xfffffff);
+
 	init_completion(&dma->dma_comp);
 	dma->vsync_client.handler = NULL;
 	return ret;
diff --git a/drivers/video/msm/mdss/mdp3_ppp.c b/drivers/video/msm/mdss/mdp3_ppp.c
index 83787c3..6187db4 100644
--- a/drivers/video/msm/mdss/mdp3_ppp.c
+++ b/drivers/video/msm/mdss/mdp3_ppp.c
@@ -372,14 +372,14 @@
 		ib = (ab * 3) / 2;
 	}
 	mdp3_clk_set_rate(MDP3_CLK_CORE, rate, MDP3_CLIENT_PPP);
-	rc = mdp3_clk_enable(on_off);
+	rc = mdp3_clk_enable(on_off, 0);
 	if (rc < 0) {
 		pr_err("%s: mdp3_clk_enable failed\n", __func__);
 		return rc;
 	}
 	rc = mdp3_bus_scale_set_quota(MDP3_CLIENT_PPP, ab, ib);
 	if (rc < 0) {
-		mdp3_clk_enable(!on_off);
+		mdp3_clk_enable(!on_off, 0);
 		pr_err("%s: scale_set_quota failed\n", __func__);
 		return rc;
 	}
diff --git a/drivers/video/msm/mdss/mdss_dsi.c b/drivers/video/msm/mdss/mdss_dsi.c
index bb1f8ae..d33aefa 100644
--- a/drivers/video/msm/mdss/mdss_dsi.c
+++ b/drivers/video/msm/mdss/mdss_dsi.c
@@ -377,19 +377,24 @@
 
 	pinfo = &pdata->panel_info;
 
-	ret = mdss_dsi_panel_power_on(pdata, 1);
+	ret = msm_dss_enable_vreg(ctrl_pdata->power_data.vreg_config,
+				ctrl_pdata->power_data.num_vreg, 1);
 	if (ret) {
-		pr_err("%s: Panel power on failed\n", __func__);
+		pr_err("%s:Failed to enable vregs. rc=%d\n", __func__, ret);
 		return ret;
 	}
 
 	pdata->panel_info.panel_power_on = 1;
 
+	if (!pdata->panel_info.mipi.lp11_init)
+		mdss_dsi_panel_reset(pdata, 1);
+
 	ret = mdss_dsi_enable_bus_clocks(ctrl_pdata);
 	if (ret) {
 		pr_err("%s: failed to enable bus clocks. rc=%d\n", __func__,
 			ret);
 		mdss_dsi_panel_power_on(pdata, 0);
+		pdata->panel_info.panel_power_on = 0;
 		return ret;
 	}
 
@@ -470,6 +475,16 @@
 	mdss_dsi_sw_reset(pdata);
 	mdss_dsi_host_init(mipi, pdata);
 
+	/*
+	 * Issue hardware reset line after enabling the DSI clocks and data
+	 * data lanes for LP11 init
+	 */
+	if (pdata->panel_info.mipi.lp11_init)
+		mdss_dsi_panel_reset(pdata, 1);
+
+	if (pdata->panel_info.mipi.init_delay)
+		usleep(pdata->panel_info.mipi.init_delay);
+
 	if (mipi->force_clk_lane_hs) {
 		u32 tmp;
 
diff --git a/drivers/video/msm/mdss/mdss_dsi_panel.c b/drivers/video/msm/mdss/mdss_dsi_panel.c
index 890066e..8c04940 100644
--- a/drivers/video/msm/mdss/mdss_dsi_panel.c
+++ b/drivers/video/msm/mdss/mdss_dsi_panel.c
@@ -847,6 +847,11 @@
 	for (i = 0; i < len; i++)
 		pinfo->mipi.dsi_phy_db.timing[i] = data[i];
 
+	pinfo->mipi.lp11_init = of_property_read_bool(np,
+					"qcom,mdss-dsi-lp11-init");
+	rc = of_property_read_u32(np, "qcom,mdss-dsi-init-delay-us", &tmp);
+	pinfo->mipi.init_delay = (!rc ? tmp : 0);
+
 	mdss_dsi_parse_fbc_params(np, pinfo);
 
 	mdss_dsi_parse_reset_seq(np, pinfo->rst_seq, &(pinfo->rst_seq_len),
diff --git a/drivers/video/msm/mdss/mdss_panel.h b/drivers/video/msm/mdss/mdss_panel.h
index b859598..65275db 100644
--- a/drivers/video/msm/mdss/mdss_panel.h
+++ b/drivers/video/msm/mdss/mdss_panel.h
@@ -222,6 +222,9 @@
 
 	char vsync_enable;
 	char hw_vsync_mode;
+
+	char lp11_init;
+	u32  init_delay;
 };
 
 enum dynamic_fps_update {
diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c
index 4bbd07a..8da837b 100644
--- a/fs/ext4/balloc.c
+++ b/fs/ext4/balloc.c
@@ -90,8 +90,8 @@
 	 * unusual file system layouts.
 	 */
 	if (ext4_block_in_group(sb, ext4_block_bitmap(sb, gdp), block_group)) {
-		block_cluster = EXT4_B2C(sbi, (start -
-					       ext4_block_bitmap(sb, gdp)));
+		block_cluster = EXT4_B2C(sbi,
+					 ext4_block_bitmap(sb, gdp) - start);
 		if (block_cluster < num_clusters)
 			block_cluster = -1;
 		else if (block_cluster == num_clusters) {
@@ -102,7 +102,7 @@
 
 	if (ext4_block_in_group(sb, ext4_inode_bitmap(sb, gdp), block_group)) {
 		inode_cluster = EXT4_B2C(sbi,
-					 start - ext4_inode_bitmap(sb, gdp));
+					 ext4_inode_bitmap(sb, gdp) - start);
 		if (inode_cluster < num_clusters)
 			inode_cluster = -1;
 		else if (inode_cluster == num_clusters) {
@@ -114,7 +114,7 @@
 	itbl_blk = ext4_inode_table(sb, gdp);
 	for (i = 0; i < sbi->s_itb_per_group; i++) {
 		if (ext4_block_in_group(sb, itbl_blk + i, block_group)) {
-			c = EXT4_B2C(sbi, start - itbl_blk + i);
+			c = EXT4_B2C(sbi, itbl_blk + i - start);
 			if ((c < num_clusters) || (c == inode_cluster) ||
 			    (c == block_cluster) || (c == itbl_cluster))
 				continue;
diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h
index 9c74fbb..d00847a 100644
--- a/include/linux/devfreq.h
+++ b/include/linux/devfreq.h
@@ -52,6 +52,9 @@
  */
 #define DEVFREQ_FLAG_LEAST_UPPER_BOUND		0x1
 
+#define DEVFREQ_FLAG_FAST_HINT	0x2
+#define DEVFREQ_FLAG_SLOW_HINT	0x4
+
 /**
  * struct devfreq_governor_data - mapping to per device governor data
  * @name:		The name of the governor.
@@ -132,7 +135,8 @@
 	struct list_head node;
 
 	const char name[DEVFREQ_NAME_LEN];
-	int (*get_target_freq)(struct devfreq *this, unsigned long *freq);
+	int (*get_target_freq)(struct devfreq *this, unsigned long *freq,
+				u32 *flag);
 	int (*event_handler)(struct devfreq *devfreq,
 				unsigned int event, void *data);
 };
diff --git a/include/linux/ion.h b/include/linux/ion.h
index 4983316..f36298b 100644
--- a/include/linux/ion.h
+++ b/include/linux/ion.h
@@ -58,6 +58,14 @@
 #define ION_FLAG_CACHED_NEEDS_SYNC 2	/* mappings of this buffer will created
 					   at mmap time, if this is set
 					   caches must be managed manually */
+#define ION_FLAG_FREED_FROM_SHRINKER 4	/* Skip any possible
+					   heap-specific caching
+					   mechanism (e.g. page
+					   pools). Guarantees that any
+					   buffer storage that came
+					   from the system allocator
+					   will be returned to the
+					   system allocator. */
 
 #ifdef __KERNEL__
 #include <linux/err.h>
diff --git a/include/linux/msm_adreno_devfreq.h b/include/linux/msm_adreno_devfreq.h
new file mode 100644
index 0000000..53d7085
--- /dev/null
+++ b/include/linux/msm_adreno_devfreq.h
@@ -0,0 +1,47 @@
+#ifndef MSM_ADRENO_DEVFREQ_H
+#define MSM_ADRENO_DEVFREQ_H
+
+#include <linux/notifier.h>
+
+#define ADRENO_DEVFREQ_NOTIFY_SUBMIT	1
+#define ADRENO_DEVFREQ_NOTIFY_RETIRE	2
+#define ADRENO_DEVFREQ_NOTIFY_IDLE	3
+
+struct device;
+
+int kgsl_devfreq_add_notifier(struct device *, struct notifier_block *);
+
+int kgsl_devfreq_del_notifier(struct device *, struct notifier_block *);
+
+/* same as KGSL_MAX_PWRLEVELS */
+#define MSM_ADRENO_MAX_PWRLEVELS 10
+
+struct xstats {
+	u64 ram_time;
+	u64 ram_wait;
+	int mod;
+};
+
+struct devfreq_msm_adreno_tz_data {
+	struct notifier_block nb;
+	struct {
+		s64 total_time;
+		s64 busy_time;
+	} bin;
+	struct {
+		u64 total_time;
+		u64 ram_time;
+		u64 gpu_time;
+		u32 num;
+		u32 max;
+		u32 up[MSM_ADRENO_MAX_PWRLEVELS];
+		u32 down[MSM_ADRENO_MAX_PWRLEVELS];
+		u32 p_up[MSM_ADRENO_MAX_PWRLEVELS];
+		u32 p_down[MSM_ADRENO_MAX_PWRLEVELS];
+		unsigned int *index;
+		uint64_t *ib;
+	} bus;
+	unsigned int device_id;
+};
+
+#endif
diff --git a/include/linux/msm_ion.h b/include/linux/msm_ion.h
index 16a1000..3976699 100644
--- a/include/linux/msm_ion.h
+++ b/include/linux/msm_ion.h
@@ -5,11 +5,14 @@
 
 enum msm_ion_heap_types {
 	ION_HEAP_TYPE_MSM_START = ION_HEAP_TYPE_CUSTOM + 1,
-	ION_HEAP_TYPE_IOMMU = ION_HEAP_TYPE_MSM_START,
-	ION_HEAP_TYPE_DMA,
+	ION_HEAP_TYPE_DMA = ION_HEAP_TYPE_MSM_START,
 	ION_HEAP_TYPE_CP,
 	ION_HEAP_TYPE_SECURE_DMA,
 	ION_HEAP_TYPE_REMOVED,
+	/*
+	 * if you add a heap type here you should also add it to
+	 * heap_types_info[] in msm_ion.c
+	 */
 };
 
 /**
@@ -31,17 +34,23 @@
 	ION_ADSP_HEAP_ID = 22,
 	ION_PIL1_HEAP_ID = 23, /* Currently used for other PIL images */
 	ION_SF_HEAP_ID = 24,
-	ION_IOMMU_HEAP_ID = 25,
+	ION_SYSTEM_HEAP_ID = 25,
 	ION_PIL2_HEAP_ID = 26, /* Currently used for modem firmware images */
 	ION_QSECOM_HEAP_ID = 27,
 	ION_AUDIO_HEAP_ID = 28,
 
 	ION_MM_FIRMWARE_HEAP_ID = 29,
-	ION_SYSTEM_HEAP_ID = 30,
 
 	ION_HEAP_ID_RESERVED = 31 /** Bit reserved for ION_FLAG_SECURE flag */
 };
 
+/*
+ * The IOMMU heap is deprecated! Here are some aliases for backwards
+ * compatibility:
+ */
+#define ION_IOMMU_HEAP_ID ION_SYSTEM_HEAP_ID
+#define ION_HEAP_TYPE_IOMMU ION_HEAP_TYPE_SYSTEM
+
 enum ion_fixed_position {
 	NOT_FIXED,
 	FIXED_LOW,
@@ -90,7 +99,8 @@
 #define ION_HEAP(bit) (1 << (bit))
 
 #define ION_ADSP_HEAP_NAME	"adsp"
-#define ION_VMALLOC_HEAP_NAME	"vmalloc"
+#define ION_SYSTEM_HEAP_NAME	"system"
+#define ION_VMALLOC_HEAP_NAME	ION_SYSTEM_HEAP_NAME
 #define ION_KMALLOC_HEAP_NAME	"kmalloc"
 #define ION_AUDIO_HEAP_NAME	"audio"
 #define ION_SF_HEAP_NAME	"sf"
diff --git a/include/linux/tspp.h b/include/linux/tspp.h
index c790c28..ddddbfb 100644
--- a/include/linux/tspp.h
+++ b/include/linux/tspp.h
@@ -34,7 +34,7 @@
 	int pid;
 	int mask;
 	enum tspp_mode mode;
-	int priority;	/* 0 - 15 */
+	unsigned int priority;	/* 0 - 15 */
 	int decrypt;
 	enum tspp_source source;
 };
diff --git a/include/media/msmb_pproc.h b/include/media/msmb_pproc.h
index de42c38..ed4ffa2 100644
--- a/include/media/msmb_pproc.h
+++ b/include/media/msmb_pproc.h
@@ -90,6 +90,7 @@
 	uint32_t offset;
 	uint8_t native_buff;
 	uint8_t processed_divert;
+	uint32_t identity;
 };
 
 struct msm_cpp_stream_buff_info_t {
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 4ecadd8..7932ba1 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -1801,22 +1801,28 @@
  * enum wiphy_flags - wiphy capability flags
  *
  * @WIPHY_FLAG_CUSTOM_REGULATORY:  tells us the driver for this device
- * 	has its own custom regulatory domain and cannot identify the
- * 	ISO / IEC 3166 alpha2 it belongs to. When this is enabled
- * 	we will disregard the first regulatory hint (when the
- * 	initiator is %REGDOM_SET_BY_CORE).
- * @WIPHY_FLAG_STRICT_REGULATORY: tells us the driver for this device will
- *	ignore regulatory domain settings until it gets its own regulatory
- *	domain via its regulatory_hint() unless the regulatory hint is
- *	from a country IE. After its gets its own regulatory domain it will
- *	only allow further regulatory domain settings to further enhance
- *	compliance. For example if channel 13 and 14 are disabled by this
- *	regulatory domain no user regulatory domain can enable these channels
- *	at a later time. This can be used for devices which do not have
- *	calibration information guaranteed for frequencies or settings
- *	outside of its regulatory domain. If used in combination with
- *	WIPHY_FLAG_CUSTOM_REGULATORY the inspected country IE power settings
- *	will be followed.
+ *	has its own custom regulatory domain and cannot identify the
+ *	ISO / IEC 3166 alpha2 it belongs to. When this is enabled
+ *	we will disregard the first regulatory hint (when the
+ *	initiator is %REGDOM_SET_BY_CORE). wiphys can set the custom
+ *	regulatory domain using wiphy_apply_custom_regulatory()
+ *	prior to wiphy registration.
+ * @WIPHY_FLAG_STRICT_REGULATORY: tells us that the wiphy for this device
+ *	has regulatory domain that it wishes to be considered as the
+ *	superset for regulatory rules. After this device gets its regulatory
+ *	domain programmed further regulatory hints shall only be considered
+ *	for this device to enhance regulatory compliance, forcing the
+ *	device to only possibly use subsets of the original regulatory
+ *	rules. For example if channel 13 and 14 are disabled by this
+ *	device's regulatory domain no user specified regulatory hint which
+ *	has these channels enabled would enable them for this wiphy,
+ *	the device's original regulatory domain will be trusted as the
+ *	base. You can program the superset of regulatory rules for this
+ *	wiphy with regulatory_hint() for cards programmed with an
+ *	ISO3166-alpha2 country code. wiphys that use regulatory_hint()
+ *	will have their wiphy->regd programmed once the regulatory
+ *	domain is set, and all other regulatory hints will be ignored
+ *	until their own regulatory domain gets programmed.
  * @WIPHY_FLAG_DISABLE_BEACON_HINTS: enable this if your driver needs to ensure
  *	that passive scan flags and beaconing flags may not be lifted by
  *	cfg80211 due to regulatory beacon hints. For more information on beacon
@@ -1884,6 +1890,34 @@
 };
 
 /**
+ * enum nl80211_country_ie_pref - country IE processing preferences
+ *
+ * enumerates the different preferences a 802.11 card can advertize
+ * for parsing the country IEs. As per the current implementation
+ * country IEs are only used derive the apha2, the information
+ * for power settings that comes with the country IE is ignored
+ * and we use the power settings from regdb.
+ *
+ * @NL80211_COUNTRY_IE_FOLLOW_CORE - This is the default behaviour.
+ *	It allows the core to update channel flags according to the
+ *	ISO3166-alpha2 in the country IE. The applied power is -
+ *	MIN(power specified by custom domain, power obtained from regdb)
+ * @NL80211_COUNTRY_IE_FOLLOW_POWER - for devices that have a
+ *	preference that even though they may have programmed their own
+ *	custom power setting prior to wiphy registration, they want
+ *	to ensure their channel power settings are updated for this
+ *	connection with the power settings derived from alpha2 of the
+ *	country IE.
+ * @NL80211_COUNTRY_IE_IGNORE_CORE - for devices that have a preference to
+ *	to ignore all country IE information processed by the core.
+ */
+enum nl80211_country_ie_pref {
+	NL80211_COUNTRY_IE_FOLLOW_CORE,
+	NL80211_COUNTRY_IE_FOLLOW_POWER,
+	NL80211_COUNTRY_IE_IGNORE_CORE,
+};
+
+/**
  * struct ieee80211_iface_limit - limit on certain interface types
  * @max: maximum number of interfaces of these types
  * @types: interface types (bits)
@@ -2100,6 +2134,8 @@
  *
  * @max_acl_mac_addrs: Maximum number of MAC addresses that the device
  *	supports for ACL.
+ * @country_ie_pref: country IE processing preferences specified
+ *	by enum nl80211_country_ie_pref
  */
 struct wiphy {
 	/* assign these fields before you register the wiphy */
@@ -2164,6 +2200,8 @@
 	 */
 	u32 probe_resp_offload;
 
+	u8 country_ie_pref;
+
 	/* If multiple wiphys are registered and you're handed e.g.
 	 * a regular netdev with assigned ieee80211_ptr, you won't
 	 * know whether it points to a wiphy your driver has registered
@@ -2691,6 +2729,30 @@
 extern int regulatory_hint(struct wiphy *wiphy, const char *alpha2);
 
 /**
+ * regulatory_hint_user - hint to the wireless core a regulatory domain
+ * which the driver has received from an application
+ * @alpha2: the ISO/IEC 3166 alpha2 the driver claims its regulatory domain
+ * 	should be in. If @rd is set this should be NULL. Note that if you
+ * 	set this to NULL you should still set rd->alpha2 to some accepted
+ * 	alpha2.
+ *
+ * Wireless drivers can use this function to hint to the wireless core
+ * the current regulatory domain as specified by trusted applications,
+ * it is the driver's responsibilty to estbalish which applications it
+ * trusts.
+ *
+ * The wiphy should be registered to cfg80211 prior to this call.
+ * For cfg80211 drivers this means you must first use wiphy_register(),
+ * for mac80211 drivers you must first use ieee80211_register_hw().
+ *
+ * Drivers should check the return value, its possible you can get
+ * an -ENOMEM or an -EINVAL.
+ *
+ * Return: 0 on success. -ENOMEM, -EINVAL.
+ */
+extern int regulatory_hint_user(const char *alpha2);
+
+/**
  * wiphy_apply_custom_regulatory - apply a custom driver regulatory domain
  * @wiphy: the wireless device we want to process the regulatory domain on
  * @regd: the custom regulatory domain to use for this wiphy
diff --git a/include/trace/events/sched.h b/include/trace/events/sched.h
index 41f8607..c549831 100644
--- a/include/trace/events/sched.h
+++ b/include/trace/events/sched.h
@@ -242,6 +242,56 @@
 		__entry->status ? "online" : "offline", __entry->error)
 );
 
+/*
+ * Tracepoint for load balancing:
+ */
+#if NR_CPUS > 32
+#error "Unsupported NR_CPUS for lb tracepoint."
+#endif
+TRACE_EVENT(sched_load_balance,
+
+	TP_PROTO(int cpu, enum cpu_idle_type idle, int balance,
+		 unsigned long group_mask, int busiest_nr_running,
+		 unsigned long imbalance, unsigned int env_flags, int ld_moved,
+		 unsigned int balance_interval),
+
+	TP_ARGS(cpu, idle, balance, group_mask, busiest_nr_running,
+		imbalance, env_flags, ld_moved, balance_interval),
+
+	TP_STRUCT__entry(
+		__field(	int,			cpu)
+		__field(	enum cpu_idle_type,	idle)
+		__field(	int,			balance)
+		__field(	unsigned long,		group_mask)
+		__field(	int,			busiest_nr_running)
+		__field(	unsigned long,		imbalance)
+		__field(	unsigned int,		env_flags)
+		__field(	int,			ld_moved)
+		__field(	unsigned int,		balance_interval)
+	),
+
+	TP_fast_assign(
+		__entry->cpu			= cpu;
+		__entry->idle			= idle;
+		__entry->balance		= balance;
+		__entry->group_mask		= group_mask;
+		__entry->busiest_nr_running	= busiest_nr_running;
+		__entry->imbalance		= imbalance;
+		__entry->env_flags		= env_flags;
+		__entry->ld_moved		= ld_moved;
+		__entry->balance_interval	= balance_interval;
+	),
+
+	TP_printk("cpu=%d state=%s balance=%d group=%#lx busy_nr=%d imbalance=%ld flags=%#x ld_moved=%d bal_int=%d",
+		  __entry->cpu,
+		  __entry->idle == CPU_IDLE ? "idle" :
+		  (__entry->idle == CPU_NEWLY_IDLE ? "newly_idle" : "busy"),
+		  __entry->balance,
+		  __entry->group_mask, __entry->busiest_nr_running,
+		  __entry->imbalance, __entry->env_flags, __entry->ld_moved,
+		  __entry->balance_interval)
+);
+
 DECLARE_EVENT_CLASS(sched_process_template,
 
 	TP_PROTO(struct task_struct *p),
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index 627dab1..89a5395 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -621,7 +621,19 @@
 static inline bool got_nohz_idle_kick(void)
 {
 	int cpu = smp_processor_id();
-	return idle_cpu(cpu) && test_bit(NOHZ_BALANCE_KICK, nohz_flags(cpu));
+
+	if (!test_bit(NOHZ_BALANCE_KICK, nohz_flags(cpu)))
+		return false;
+
+	if (idle_cpu(cpu) && !need_resched())
+		return true;
+
+	/*
+	 * We can't run Idle Load Balance on this CPU for this time so we
+	 * cancel it and clear NOHZ_BALANCE_KICK
+	 */
+	clear_bit(NOHZ_BALANCE_KICK, nohz_flags(cpu));
+	return false;
 }
 
 #else /* CONFIG_NO_HZ */
@@ -1519,7 +1531,7 @@
 	/*
 	 * Check if someone kicked us for doing the nohz idle load balance.
 	 */
-	if (unlikely(got_nohz_idle_kick() && !need_resched())) {
+	if (unlikely(got_nohz_idle_kick())) {
 		this_rq()->idle_balance = 1;
 		raise_softirq_irqoff(SCHED_SOFTIRQ);
 	}
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index 2e98983..08497b0 100644
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -4422,7 +4422,7 @@
 	int ld_moved, active_balance = 0;
 	struct sched_group *group;
 	unsigned long imbalance;
-	struct rq *busiest;
+	struct rq *busiest = NULL;
 	unsigned long flags;
 	struct cpumask *cpus = __get_cpu_var(load_balance_tmpmask);
 
@@ -4591,6 +4591,10 @@
 
 	ld_moved = 0;
 out:
+	trace_sched_load_balance(this_cpu, idle, *balance,
+				 group ? group->cpumask[0] : 0,
+				 busiest ? busiest->nr_running : 0, imbalance,
+				 env.flags, ld_moved, sd->balance_interval);
 	return ld_moved;
 }
 
diff --git a/mm/page_io.c b/mm/page_io.c
index e60e43f..1499e1c 100644
--- a/mm/page_io.c
+++ b/mm/page_io.c
@@ -20,8 +20,15 @@
 #include <linux/swapops.h>
 #include <linux/writeback.h>
 #include <linux/blkdev.h>
+#include <linux/ratelimit.h>
 #include <asm/pgtable.h>
 
+/*
+ * We don't need to see swap errors more than once every 1 second to know
+ * that a problem is occurring.
+ */
+#define SWAP_ERROR_LOG_RATE_MS 1000
+
 static struct bio *get_swap_bio(gfp_t gfp_flags,
 				struct page *page, bio_end_io_t end_io)
 {
@@ -46,6 +53,7 @@
 {
 	const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
 	struct page *page = bio->bi_io_vec[0].bv_page;
+	static unsigned long swap_error_rs_time;
 
 	if (!uptodate) {
 		SetPageError(page);
@@ -58,7 +66,9 @@
 		 * Also clear PG_reclaim to avoid rotate_reclaimable_page()
 		 */
 		set_page_dirty(page);
-		printk(KERN_ALERT "Write-error on swap-device (%u:%u:%Lu)\n",
+		if (printk_timed_ratelimit(&swap_error_rs_time,
+					   SWAP_ERROR_LOG_RATE_MS))
+			printk(KERN_ALERT "Write-error on swap-device (%u:%u:%Lu)\n",
 				imajor(bio->bi_bdev->bd_inode),
 				iminor(bio->bi_bdev->bd_inode),
 				(unsigned long long)bio->bi_sector);
diff --git a/mm/vmscan.c b/mm/vmscan.c
index 9e95109..d0e40e5 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -474,6 +474,8 @@
 		if (!PageWriteback(page)) {
 			/* synchronous write or broken a_ops? */
 			ClearPageReclaim(page);
+			if (PageError(page))
+				return PAGE_ACTIVATE;
 		}
 		trace_mm_vmscan_writepage(page, trace_reclaim_flags(page));
 		inc_zone_page_state(page, NR_VMSCAN_WRITE);
diff --git a/net/wireless/db.txt b/net/wireless/db.txt
index c5861b8..b1efe57 100644
--- a/net/wireless/db.txt
+++ b/net/wireless/db.txt
@@ -6,24 +6,34 @@
 	# Channel 14. Only JP enables this and for 802.11b only
 	(2474 - 2494 @ 20), (3, 20), PASSIVE-SCAN, NO-IBSS, NO-OFDM
 	# Channel 36 - 48
-	(5170 - 5250 @ 40), (3, 20), PASSIVE-SCAN, NO-IBSS
+	(5170 - 5250 @ 80), (3, 20), PASSIVE-SCAN, NO-IBSS
 	# NB: 5260 MHz - 5700 MHz requies DFS
 	# Channel 149 - 165
-	(5735 - 5835 @ 40), (3, 20), PASSIVE-SCAN, NO-IBSS
+	(5735 - 5835 @ 80), (3, 20), PASSIVE-SCAN, NO-IBSS
+	# IEEE 802.11ad (60GHz), channels 1..3
+	(57240 - 63720 @ 2160), (N/A, 0)
 
 
 country AD:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 80), (N/A, 20)
+	(5250 - 5330 @ 80), (N/A, 20), DFS
+	(5490 - 5710 @ 80), (N/A, 27), DFS
 	# 60 gHz band channels 1-4, ref: Etsi En 302 567
 	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
 
 country AE:
 	(2402 - 2482 @ 40), (N/A, 20)
-	(5170 - 5250 @ 40), (N/A, 20)
-	(5250 - 5330 @ 40), (N/A, 20), DFS
-	(5490 - 5710 @ 40), (N/A, 27), DFS
+	(5170 - 5250 @ 80), (3, 17)
+	(5250 - 5330 @ 80), (3, 24), DFS
+	(5490 - 5710 @ 80), (3, 24), DFS
+	(5735 - 5835 @ 80), (3, 30)
 
 country AL:
-	(2402 - 2482 @ 20), (N/A, 20)
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5150 - 5250 @ 80), (N/A, 20)
+	(5250 - 5350 @ 80), (N/A, 20), DFS
+	(5470 - 5725 @ 80), (N/A, 27), DFS
 
 country AM:
 	(2402 - 2482 @ 40), (N/A, 20)
@@ -32,30 +42,38 @@
 
 country AN:
 	(2402 - 2482 @ 40), (N/A, 20)
-	(5170 - 5250 @ 40), (N/A, 20)
-	(5250 - 5330 @ 40), (N/A, 20), DFS
-	(5490 - 5710 @ 40), (N/A, 27), DFS
+	(5170 - 5250 @ 80), (N/A, 20)
+	(5250 - 5330 @ 80), (N/A, 20), DFS
+	(5490 - 5710 @ 80), (N/A, 27), DFS
 
 country AR:
 	(2402 - 2482 @ 40), (N/A, 20)
-	(5170 - 5250 @ 40), (3, 17)
-	(5250 - 5330 @ 40), (3, 20), DFS
-	(5490 - 5710 @ 40), (3, 20), DFS
-	(5735 - 5835 @ 40), (3, 30)
+	(5170 - 5250 @ 80), (3, 17)
+	(5250 - 5330 @ 80), (3, 24), DFS
+	(5490 - 5710 @ 80), (3, 24), DFS
+	(5735 - 5835 @ 80), (3, 30)
+
+country AS:
+	(2402 - 2472 @ 40), (N/A, 30)
+	(5150 - 5250 @ 80), (6, 17)
+	(5250 - 5350 @ 80), (6, 24), DFS
+	(5470 - 5725 @ 80), (6, 24), DFS
+	(5725 - 5850 @ 80), (6, 30)
 
 country AT: DFS-ETSI
 	(2402 - 2482 @ 40), (N/A, 20)
-	(5170 - 5250 @ 40), (N/A, 20)
-	(5250 - 5330 @ 40), (N/A, 20), DFS
-	(5490 - 5710 @ 40), (N/A, 27), DFS
+	(5170 - 5250 @ 80), (N/A, 20)
+	(5250 - 5330 @ 80), (N/A, 20), DFS
+	(5490 - 5710 @ 80), (N/A, 27), DFS
 	# 60 gHz band channels 1-4, ref: Etsi En 302 567
 	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
 
 country AU:
 	(2402 - 2482 @ 40), (N/A, 20)
-	(5170 - 5250 @ 40), (3, 23)
-	(5250 - 5330 @ 40), (3, 23), DFS
-	(5735 - 5835 @ 40), (3, 30)
+	(5170 - 5250 @ 80), (3, 17)
+	(5250 - 5330 @ 80), (3, 24), DFS
+	(5490 - 5710 @ 80), (3, 24), DFS
+	(5735 - 5835 @ 80), (3, 30)
 
 country AW:
 	(2402 - 2482 @ 40), (N/A, 20)
@@ -65,39 +83,40 @@
 
 country AZ:
 	(2402 - 2482 @ 40), (N/A, 20)
-	(5170 - 5250 @ 40), (N/A, 18)
-	(5250 - 5330 @ 40), (N/A, 18), DFS
+	(5170 - 5250 @ 80), (N/A, 18)
+	(5250 - 5330 @ 80), (N/A, 18), DFS
 
 country BA: DFS-ETSI
 	(2402 - 2482 @ 40), (N/A, 20)
-	(5170 - 5250 @ 40), (N/A, 20)
-	(5250 - 5330 @ 40), (N/A, 20), DFS
-	(5490 - 5710 @ 40), (N/A, 27), DFS
+	(5170 - 5250 @ 80), (N/A, 20)
+	(5250 - 5330 @ 80), (N/A, 20), DFS
+	(5490 - 5710 @ 80), (N/A, 27), DFS
 	# 60 gHz band channels 1-4, ref: Etsi En 302 567
 	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
 
 country BB:
 	(2402 - 2482 @ 40), (N/A, 20)
-	(5170 - 5250 @ 40), (3, 23)
-	(5250 - 5330 @ 40), (3, 23), DFS
-	(5735 - 5835 @ 40), (3, 30)
+	(5170 - 5250 @ 80), (3, 23)
+	(5250 - 5330 @ 80), (3, 23), DFS
+	(5735 - 5835 @ 80), (3, 30)
 
 country BD:
 	(2402 - 2482 @ 40), (N/A, 20)
+	(5725 - 5850 @ 80), (N/A, 30)
 
 country BE: DFS-ETSI
 	(2402 - 2482 @ 40), (N/A, 20)
-	(5170 - 5250 @ 40), (N/A, 20)
-	(5250 - 5330 @ 40), (N/A, 20), DFS
-	(5490 - 5710 @ 40), (N/A, 27), DFS
+	(5170 - 5250 @ 80), (N/A, 20)
+	(5250 - 5330 @ 80), (N/A, 20), DFS
+	(5490 - 5710 @ 80), (N/A, 27), DFS
 	# 60 gHz band channels 1-4, ref: Etsi En 302 567
 	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
 
 country BG: DFS-ETSI
 	(2402 - 2482 @ 40), (N/A, 20)
-	(5170 - 5250 @ 40), (N/A, 23)
-	(5250 - 5290 @ 40), (N/A, 23), DFS
-	(5490 - 5710 @ 40), (N/A, 30), DFS
+	(5170 - 5250 @ 80), (N/A, 23)
+	(5250 - 5290 @ 80), (N/A, 23), DFS
+	(5490 - 5710 @ 80), (N/A, 30), DFS
 	# 60 gHz band channels 1-4, ref: Etsi En 302 567
 	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
 
@@ -112,57 +131,74 @@
 	(5170 - 5250 @ 40), (N/A, 18)
 	(5250 - 5330 @ 40), (N/A, 18), DFS
 
+country BM:
+	(2402 - 2472 @ 40), (N/A, 30)
+	(5150 - 5250 @ 80), (6, 17)
+	(5250 - 5350 @ 80), (6, 24), DFS
+	(5470 - 5725 @ 80), (6, 24), DFS
+	(5725 - 5850 @ 80), (6, 30)
+
 country BN:
 	(2402 - 2482 @ 40), (N/A, 20)
-	(5170 - 5250 @ 40), (N/A, 20)
-	(5250 - 5330 @ 40), (N/A, 20), DFS
-	(5735 - 5835 @ 40), (N/A, 30)
+	(5170 - 5250 @ 80), (N/A, 20)
+	(5250 - 5330 @ 80), (N/A, 20), DFS
+	(5735 - 5835 @ 80), (N/A, 30)
 
 country BO:
 	(2402 - 2482 @ 40), (N/A, 30)
-	(5735 - 5835 @ 40), (N/A, 30)
+	(5735 - 5835 @ 80), (N/A, 30)
 
 country BR:
 	(2402 - 2482 @ 40), (N/A, 20)
-	(5170 - 5250 @ 40), (3, 17)
-	(5250 - 5330 @ 40), (3, 20), DFS
-	(5490 - 5710 @ 40), (3, 20), DFS
-	(5735 - 5835 @ 40), (3, 30)
+	(5170 - 5250 @ 80), (3, 17)
+	(5250 - 5330 @ 80), (3, 24), DFS
+	(5490 - 5710 @ 80), (3, 24), DFS
+	(5735 - 5835 @ 80), (3, 30)
+
+country BS:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5150 - 5250 @ 80), (6, 17)
+	(5250 - 5350 @ 80), (6, 24), DFS
+	(5470 - 5725 @ 80), (6, 24), DFS
+	(5725 - 5850 @ 80), (6, 30)
 
 country BY:
 	(2402 - 2482 @ 40), (N/A, 20)
-	(5170 - 5250 @ 40), (N/A, 20)
-	(5250 - 5330 @ 40), (N/A, 20), DFS
-	(5490 - 5710 @ 40), (N/A, 27), DFS
+	(5170 - 5250 @ 80), (N/A, 20)
+	(5250 - 5330 @ 80), (N/A, 20), DFS
+	(5490 - 5710 @ 80), (N/A, 27), DFS
 
 country BZ:
 	(2402 - 2482 @ 40), (N/A, 30)
-	(5735 - 5835 @ 40), (N/A, 30)
+	(5735 - 5835 @ 80), (N/A, 30)
 
 country CA:
-	(2402 - 2472 @ 40), (3, 27)
-	(5170 - 5250 @ 40), (3, 17)
-	(5250 - 5330 @ 40), (3, 20), DFS
-	(5490 - 5710 @ 40), (3, 20), DFS
-	(5735 - 5835 @ 40), (3, 30)
+	(2402 - 2472 @ 40), (N/A, 27)
+	(5170 - 5250 @ 80), (3, 17)
+	(5250 - 5330 @ 80), (3, 24), DFS
+	(5490 - 5710 @ 80), (3, 24), DFS
+	(5735 - 5835 @ 80), (3, 30)
 
 country CH: DFS-ETSI
 	(2402 - 2482 @ 40), (N/A, 20)
-	(5170 - 5250 @ 40), (N/A, 20)
-	(5250 - 5330 @ 40), (N/A, 20), DFS
-	(5490 - 5710 @ 40), (N/A, 27), DFS
+	(5170 - 5250 @ 80), (N/A, 20)
+	(5250 - 5330 @ 80), (N/A, 20), DFS
+	(5490 - 5710 @ 80), (N/A, 27), DFS
 	# 60 gHz band channels 1-4, ref: Etsi En 302 567
 	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
 
 country CL:
 	(2402 - 2482 @ 40), (N/A, 20)
-	(5170 - 5250 @ 40), (N/A, 20)
-	(5250 - 5330 @ 40), (N/A, 20), DFS
-	(5735 - 5835 @ 40), (N/A, 20)
+	(5170 - 5250 @ 80), (N/A, 20)
+	(5250 - 5330 @ 80), (N/A, 20), DFS
+	(5735 - 5835 @ 80), (N/A, 20)
 
 country CN:
 	(2402 - 2482 @ 40), (N/A, 20)
-	(5735 - 5835 @ 40), (N/A, 30)
+	(5150 - 5250 @ 80), (6,	23)
+	(5250 - 5350 @ 80), (6,	23), DFS
+	(5725 - 5850 @ 80), (6,	30)
+	(5735 - 5835 @ 80), (N/A, 30)
 	# 60 gHz band channels 1,4: 28dBm, channels 2,3: 44dBm
 	# ref: http://www.miit.gov.cn/n11293472/n11505629/n11506593/n11960250/n11960606/n11960700/n12330791.files/n12330790.pdf
 	(57240 - 59400 @ 2160), (N/A, 28)
@@ -170,28 +206,24 @@
 	(63720 - 65880 @ 2160), (N/A, 28)
 
 country CO:
-	(2402 - 2472 @ 40), (3, 27)
-	(5170 - 5250 @ 40), (3, 17)
-	(5250 - 5330 @ 40), (3, 23), DFS
-	(5735 - 5835 @ 40), (3, 30)
+	(2402 - 2472 @ 40), (N/A, 27)
+	(5170 - 5250 @ 80), (3, 17)
+	(5250 - 5330 @ 80), (3, 24), DFS
+	(5490 - 5710 @ 80), (3, 24), DFS
+	(5735 - 5835 @ 80), (3, 30)
 
 country CR:
 	(2402 - 2482 @ 40), (N/A, 20)
 	(5170 - 5250 @ 20), (3, 17)
-	(5250 - 5330 @ 20), (3, 23), DFS
+	(5250 - 5330 @ 20), (3, 24), DFS
+	(5490 - 5710 @ 20), (3, 24), DFS
 	(5735 - 5835 @ 20), (3, 30)
 
-country CS:
-	(2402 - 2482 @ 40), (N/A, 20)
-	(5170 - 5250 @ 40), (N/A, 20)
-	(5250 - 5330 @ 40), (N/A, 20), DFS
-	(5490 - 5710 @ 40), (N/A, 27), DFS
-
 country CY: DFS-ETSI
 	(2402 - 2482 @ 40), (N/A, 20)
-	(5170 - 5250 @ 40), (N/A, 20)
-	(5250 - 5330 @ 40), (N/A, 20), DFS
-	(5490 - 5710 @ 40), (N/A, 27), DFS
+	(5170 - 5250 @ 80), (N/A, 20)
+	(5250 - 5330 @ 80), (N/A, 20), DFS
+	(5490 - 5710 @ 80), (N/A, 27), DFS
 	# 60 gHz band channels 1-4, ref: Etsi En 302 567
 	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
 
@@ -201,9 +233,9 @@
 # implemented.
 country CZ: DFS-ETSI
 	(2400 - 2483.5 @ 40), (N/A, 100 mW)
-	(5150 - 5250 @ 40), (N/A, 200 mW), NO-OUTDOOR
-	(5250 - 5350 @ 40), (N/A, 100 mW), NO-OUTDOOR, DFS
-	(5470 - 5725 @ 40), (N/A, 500 mW), DFS
+	(5150 - 5250 @ 80), (N/A, 200 mW), NO-OUTDOOR
+	(5250 - 5350 @ 80), (N/A, 100 mW), NO-OUTDOOR, DFS
+	(5470 - 5725 @ 80), (N/A, 500 mW), DFS
 	# 60 gHz band channels 1-4, ref: Etsi En 302 567
 	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
 
@@ -223,27 +255,27 @@
 	# entries 279004 and 280006
 	(2400 - 2483.5 @ 40), (N/A, 100 mW)
 	# entry 303005
-	(5150 - 5250 @ 40), (N/A, 100 mW), NO-OUTDOOR
+	(5150 - 5250 @ 80), (N/A, 100 mW), NO-OUTDOOR
 	# entries 304002 and 305002
-	(5250 - 5350 @ 40), (N/A, 100 mW), NO-OUTDOOR, DFS
+	(5250 - 5350 @ 80), (N/A, 100 mW), NO-OUTDOOR, DFS
 	# entries 308002, 309001 and 310003
-	(5470 - 5725 @ 40), (N/A, 500 mW), DFS
+	(5470 - 5725 @ 80), (N/A, 500 mW), DFS
 	# 60 gHz band channels 1-4, ref: Etsi En 302 567
 	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
 
 country DK: DFS-ETSI
 	(2402 - 2482 @ 40), (N/A, 20)
-	(5170 - 5250 @ 40), (N/A, 20)
-	(5250 - 5330 @ 40), (N/A, 20), DFS
-	(5490 - 5710 @ 40), (N/A, 27), DFS
+	(5170 - 5250 @ 80), (N/A, 20)
+	(5250 - 5330 @ 80), (N/A, 20), DFS
+	(5490 - 5710 @ 80), (N/A, 27), DFS
 	# 60 gHz band channels 1-4, ref: Etsi En 302 567
 	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
 
 country DO:
-	(2402 - 2472 @ 40), (3, 27)
-	(5170 - 5250 @ 40), (3, 17)
-	(5250 - 5330 @ 40), (3, 23), DFS
-	(5735 - 5835 @ 40), (3, 30)
+	(2402 - 2472 @ 40), (N/A, 27)
+	(5170 - 5250 @ 80), (3, 17)
+	(5250 - 5330 @ 80), (3, 23), DFS
+	(5735 - 5835 @ 80), (3, 30)
 
 country DZ:
 	(2402 - 2482 @ 40), (N/A, 20)
@@ -251,14 +283,15 @@
 country EC:
 	(2402 - 2482 @ 40), (N/A, 20)
 	(5170 - 5250 @ 20), (3, 17)
-	(5250 - 5330 @ 20), (3, 23), DFS
+	(5250 - 5330 @ 20), (3, 24), DFS
+	(5490 - 5710 @ 20), (3, 24), DFS
 	(5735 - 5835 @ 20), (3, 30)
 
 country EE: DFS-ETSI
 	(2402 - 2482 @ 40), (N/A, 20)
-	(5170 - 5250 @ 40), (N/A, 20)
-	(5250 - 5330 @ 40), (N/A, 20), DFS
-	(5490 - 5710 @ 40), (N/A, 27), DFS
+	(5170 - 5250 @ 80), (N/A, 20)
+	(5250 - 5330 @ 80), (N/A, 20), DFS
+	(5490 - 5710 @ 80), (N/A, 27), DFS
 	# 60 gHz band channels 1-4, ref: Etsi En 302 567
 	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
 
@@ -269,55 +302,67 @@
 
 country ES: DFS-ETSI
 	(2400 - 2483.5 @ 40), (N/A, 100 mW)
-	(5150 - 5250 @ 40), (N/A, 100 mW), NO-OUTDOOR
-	(5250 - 5350 @ 40), (N/A, 100 mW), NO-OUTDOOR, DFS
-	(5470 - 5725 @ 40), (N/A, 500 mW), DFS
+	(5150 - 5250 @ 80), (N/A, 100 mW), NO-OUTDOOR
+	(5250 - 5350 @ 80), (N/A, 100 mW), NO-OUTDOOR, DFS
+	(5470 - 5725 @ 80), (N/A, 500 mW), DFS
 	# 60 gHz band channels 1-4, ref: Etsi En 302 567
 	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
 
 country FI: DFS-ETSI
 	(2402 - 2482 @ 40), (N/A, 20)
-	(5170 - 5250 @ 40), (N/A, 20)
-	(5250 - 5330 @ 40), (N/A, 20), DFS
-	(5490 - 5710 @ 40), (N/A, 27), DFS
+	(5170 - 5250 @ 80), (N/A, 20)
+	(5250 - 5330 @ 80), (N/A, 20), DFS
+	(5490 - 5710 @ 80), (N/A, 27), DFS
 	# 60 gHz band channels 1-4, ref: Etsi En 302 567
 	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
 
 country FR: DFS-ETSI
 	(2402 - 2482 @ 40), (N/A, 20)
-	(5170 - 5250 @ 40), (N/A, 20)
-	(5250 - 5330 @ 40), (N/A, 20), DFS
-	(5490 - 5710 @ 40), (N/A, 27), DFS
+	(5170 - 5250 @ 80), (N/A, 20)
+	(5250 - 5330 @ 80), (N/A, 20), DFS
+	(5490 - 5710 @ 80), (N/A, 27), DFS
 	# 60 gHz band channels 1-4, ref: Etsi En 302 567
 	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
 
+country GF:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5150 - 5250 @ 80), (N/A, 20)
+	(5250 - 5350 @ 80), (N/A, 20), DFS
+        (5470 - 5725 @ 80), (N/A, 20), DFS
+
 country GE:
 	(2402 - 2482 @ 40), (N/A, 20)
-	(5170 - 5250 @ 40), (N/A, 18)
-	(5250 - 5330 @ 40), (N/A, 18), DFS
+	(5170 - 5250 @ 80), (N/A, 18)
+	(5250 - 5330 @ 80), (N/A, 18), DFS
 	# 60 gHz band channels 1-4, ref: Etsi En 302 567
 	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
 
 country GB: DFS-ETSI
 	(2402 - 2482 @ 40), (N/A, 20)
-	(5170 - 5250 @ 40), (N/A, 20)
-	(5250 - 5330 @ 40), (N/A, 20), DFS
-	(5490 - 5710 @ 40), (N/A, 27), DFS
+	(5170 - 5250 @ 80), (N/A, 20)
+	(5250 - 5330 @ 80), (N/A, 20), DFS
+	(5490 - 5710 @ 80), (N/A, 27), DFS
 	# 60 gHz band channels 1-4, ref: Etsi En 302 567
 	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
 
 country GD:
-	(2402 - 2472 @ 40), (3, 27)
-	(5170 - 5250 @ 40), (3, 17)
-	(5250 - 5330 @ 40), (3, 20), DFS
-	(5490 - 5710 @ 40), (3, 20), DFS
-	(5735 - 5835 @ 40), (3, 30)
+	(2402 - 2472 @ 40), (3, 30)
+	(5170 - 5250 @ 80), (6, 17)
+	(5250 - 5330 @ 80), (6, 24), DFS
+	(5490 - 5710 @ 80), (6, 24), DFS
+	(5735 - 5835 @ 80), (6, 30)
+
+country GP:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5150 - 5250 @ 80), (N/A, 20)
+	(5250 - 5350 @ 80), (N/A, 20), DFS
+        (5470 - 5725 @ 80), (N/A, 27), DFS
 
 country GR: DFS-ETSI
 	(2402 - 2482 @ 40), (N/A, 20)
-	(5170 - 5250 @ 40), (N/A, 20)
-	(5250 - 5330 @ 40), (N/A, 20), DFS
-	(5490 - 5710 @ 40), (N/A, 27), DFS
+	(5170 - 5250 @ 80), (N/A, 20)
+	(5250 - 5330 @ 80), (N/A, 20), DFS
+	(5490 - 5710 @ 80), (N/A, 27), DFS
 	# 60 gHz band channels 1-4, ref: Etsi En 302 567
 	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
 
@@ -328,156 +373,165 @@
 	(5490 - 5710 @ 20), (N/A, 27), DFS
 
 country GT:
-	(2402 - 2472 @ 40), (3, 27)
-	(5170 - 5250 @ 40), (3, 17)
-	(5250 - 5330 @ 40), (3, 23), DFS
-	(5735 - 5835 @ 40), (3, 30)
+	(2402 - 2472 @ 40), (3, 30)
+	(5170 - 5250 @ 80), (6, 17)
+	(5250 - 5330 @ 80), (6, 23), DFS
+	(5735 - 5835 @ 80), (6, 30)
 
 country GU:
-	(2402 - 2472 @ 40), (3, 27)
-	(5170 - 5250 @ 20), (3, 17)
-	(5250 - 5330 @ 20), (3, 23), DFS
-	(5735 - 5835 @ 20), (3, 30)
+	(2402 - 2472 @ 40), (3, 30)
+	(5170 - 5250 @ 20), (6, 17)
+	(5250 - 5330 @ 20), (6, 24), DFS
+	(5490 - 5710 @ 20), (6, 24), DFS
+	(5735 - 5835 @ 20), (6, 30)
 
 country HN:
 	(2402 - 2482 @ 40), (N/A, 20)
-	(5170 - 5250 @ 40), (3, 17)
-	(5250 - 5330 @ 40), (3, 20), DFS
-	(5490 - 5710 @ 40), (3, 20), DFS
-	(5735 - 5835 @ 40), (3, 30)
+	(5170 - 5250 @ 80), (6, 17)
+	(5250 - 5330 @ 80), (6, 24), DFS
+	(5490 - 5710 @ 80), (6, 24), DFS
+	(5735 - 5835 @ 80), (6, 30)
 
 country HK:
 	(2402 - 2482 @ 40), (N/A, 20)
-	(5170 - 5250 @ 40), (3, 17)
-	(5250 - 5330 @ 40), (3, 20), DFS
-	(5490 - 5710 @ 40), (3, 20), DFS
-	(5735 - 5835 @ 40), (3, 30)
+	(5170 - 5250 @ 80), (6, 17)
+	(5250 - 5330 @ 80), (6, 24), DFS
+	(5490 - 5710 @ 80), (6, 24), DFS
+	(5735 - 5835 @ 80), (6, 30)
 
 country HR: DFS-ETSI
 	(2402 - 2482 @ 40), (N/A, 20)
-	(5170 - 5250 @ 40), (N/A, 20)
-	(5250 - 5330 @ 40), (N/A, 20), DFS
-	(5490 - 5710 @ 40), (N/A, 27), DFS
+	(5170 - 5250 @ 80), (N/A, 20)
+	(5250 - 5330 @ 80), (N/A, 20), DFS
+	(5490 - 5710 @ 80), (N/A, 27), DFS
 	# 60 gHz band channels 1-4, ref: Etsi En 302 567
 	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
 
 country HT:
 	(2402 - 2482 @ 40), (N/A, 20)
-	(5170 - 5250 @ 40), (N/A, 20)
-	(5250 - 5330 @ 40), (N/A, 20), DFS
-	(5490 - 5710 @ 40), (N/A, 27), DFS
+	(5170 - 5250 @ 80), (N/A, 20)
+	(5250 - 5330 @ 80), (N/A, 20), DFS
+	(5490 - 5710 @ 80), (N/A, 27), DFS
 
 country HU: DFS-ETSI
 	(2402 - 2482 @ 40), (N/A, 20)
-	(5170 - 5250 @ 40), (N/A, 20)
-	(5250 - 5330 @ 40), (N/A, 20), DFS
-	(5490 - 5710 @ 40), (N/A, 27), DFS
+	(5170 - 5250 @ 80), (N/A, 20)
+	(5250 - 5330 @ 80), (N/A, 20), DFS
+	(5490 - 5710 @ 80), (N/A, 27), DFS
 	# 60 gHz band channels 1-4, ref: Etsi En 302 567
 	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
 
 country ID:
+	# ref: http://www.postel.go.id/content/ID/regulasi/standardisasi/kepdir/bwa%205,8%20ghz.pdf
 	(2402 - 2482 @ 40), (N/A, 20)
+	(5735 - 5815 @ 20), (N/A, 23)
 
 country IE: DFS-ETSI
 	(2402 - 2482 @ 40), (N/A, 20)
-	(5170 - 5250 @ 40), (N/A, 20)
-	(5250 - 5330 @ 40), (N/A, 20), DFS
-	(5490 - 5710 @ 40), (N/A, 27), DFS
+	(5170 - 5250 @ 80), (N/A, 20)
+	(5250 - 5330 @ 80), (N/A, 20), DFS
+	(5490 - 5710 @ 80), (N/A, 27), DFS
 	# 60 gHz band channels 1-4, ref: Etsi En 302 567
 	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
 
 country IL:
 	(2402 - 2482 @ 40), (N/A, 20)
-	(5150 - 5250 @ 40), (N/A, 200 mW), NO-OUTDOOR
-	(5250 - 5350 @ 40), (N/A, 200 mW), NO-OUTDOOR, DFS
+	(5150 - 5250 @ 80), (N/A, 200 mW), NO-OUTDOOR
+	(5250 - 5350 @ 80), (N/A, 200 mW), NO-OUTDOOR, DFS
 
 country IN:
 	(2402 - 2482 @ 40), (N/A, 20)
-	(5170 - 5250 @ 40), (N/A, 20)
-	(5250 - 5330 @ 40), (N/A, 20), DFS
-	(5735 - 5835 @ 40), (N/A, 20)
+	(5170 - 5250 @ 80), (N/A, 20)
+	(5250 - 5330 @ 80), (N/A, 20), DFS
+	(5735 - 5835 @ 80), (N/A, 20)
 
 country IS: DFS-ETSI
 	(2402 - 2482 @ 40), (N/A, 20)
-	(5170 - 5250 @ 40), (N/A, 20)
-	(5250 - 5330 @ 40), (N/A, 20), DFS
-	(5490 - 5710 @ 40), (N/A, 27), DFS
+	(5170 - 5250 @ 80), (N/A, 20)
+	(5250 - 5330 @ 80), (N/A, 20), DFS
+	(5490 - 5710 @ 80), (N/A, 27), DFS
 	# 60 gHz band channels 1-4, ref: Etsi En 302 567
 	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
 
 country IR:
 	(2402 - 2482 @ 40), (N/A, 20)
-	(5735 - 5835 @ 40), (N/A, 30)
+	(5735 - 5835 @ 80), (N/A, 30)
 
 country IT: DFS-ETSI
 	(2402 - 2482 @ 40), (N/A, 20)
-	(5170 - 5250 @ 40), (N/A, 20)
-	(5250 - 5330 @ 40), (N/A, 20), DFS
-	(5490 - 5710 @ 40), (N/A, 27), DFS
+	(5170 - 5250 @ 80), (N/A, 20)
+	(5250 - 5330 @ 80), (N/A, 20), DFS
+	(5490 - 5710 @ 80), (N/A, 27), DFS
 	# 60 gHz band channels 1-4, ref: Etsi En 302 567
 	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
 
 country JM:
 	(2402 - 2482 @ 40), (N/A, 20)
-	(5170 - 5250 @ 40), (3, 17)
-	(5250 - 5330 @ 40), (3, 20), DFS
-	(5490 - 5710 @ 40), (3, 20), DFS
-	(5735 - 5835 @ 40), (3, 30)
+	(5170 - 5250 @ 80), (6, 17)
+	(5250 - 5330 @ 80), (6, 24), DFS
+	(5490 - 5710 @ 80), (6, 24), DFS
+	(5735 - 5835 @ 80), (6, 30)
 
 country JP:
 	(2402 - 2482 @ 40), (N/A, 20)
 	(2474 - 2494 @ 20), (N/A, 20), NO-OFDM
 	(4910 - 4990 @ 40), (N/A, 23)
 	(5030 - 5090 @ 40), (N/A, 23)
-	(5170 - 5250 @ 40), (N/A, 20)
-	(5250 - 5330 @ 40), (N/A, 20), DFS
-	(5490 - 5710 @ 40), (N/A, 23), DFS
+	(5170 - 5250 @ 80), (N/A, 20)
+	(5250 - 5330 @ 80), (N/A, 20), DFS
+	(5490 - 5710 @ 160), (N/A, 23), DFS
 
 country JO:
 	(2402 - 2482 @ 40), (N/A, 20)
-	(5170 - 5250 @ 40), (N/A, 18)
+	(5150 - 5250 @ 80), (N/A, 23)
+	(5725 - 5850 @ 80), (N/A, 23)
 
 country KE:
 	(2402 - 2482 @ 40), (N/A, 20)
-	(5735 - 5835 @ 40), (N/A, 30)
+	(5150 - 5250 @ 80), (N/A, 23)
+        (5470 - 5570 @ 80), (N/A, 30), DFS
+        (5725 - 5775 @ 80), (N/A, 23)
 
 country KH:
 	(2402 - 2482 @ 40), (N/A, 20)
-	(5170 - 5250 @ 40), (N/A, 20)
-	(5250 - 5330 @ 40), (N/A, 20), DFS
-	(5490 - 5710 @ 40), (N/A, 27), DFS
+	(5170 - 5250 @ 80), (N/A, 20)
+	(5250 - 5330 @ 80), (N/A, 20), DFS
+	(5490 - 5710 @ 80), (N/A, 27), DFS
 
 country KP:
-	(2402 - 2482 @ 40), (N/A, 20)
-	(5170 - 5330 @ 40), (3, 20)
-	(5160 - 5250 @ 40), (3, 20), DFS
-	(5490 - 5630 @ 40), (3, 30), DFS
-	(5735 - 5815 @ 40), (3, 30)
+	(2402 - 2482 @ 20), (N/A, 20)
+	(5170 - 5330 @ 20), (6, 20)
+	(5160 - 5250 @ 20), (6, 20), DFS
+	(5490 - 5630 @ 20), (6, 30), DFS
+	(5735 - 5815 @ 20), (6, 30)
 
 country KR:
 	(2402 - 2482 @ 20), (N/A, 20)
-	(5170 - 5250 @ 20), (3, 20)
-	(5250 - 5330 @ 20), (3, 20), DFS
-	(5490 - 5630 @ 20), (3, 30), DFS
-	(5735 - 5815 @ 20), (3, 30)
+	(5150 - 5250 @ 80), (6, 20)
+	(5250 - 5350 @ 80), (6, 20), DFS
+	(5470 - 5725 @ 80), (6, 30), DFS
+	(5725 - 5825 @ 80), (6, 30)
 
 country KW:
 	(2402 - 2482 @ 40), (N/A, 20)
-	(5170 - 5250 @ 40), (N/A, 20)
-	(5250 - 5330 @ 40), (N/A, 20), DFS
+	(5170 - 5250 @ 80), (N/A, 20)
+	(5250 - 5330 @ 80), (N/A, 20), DFS
 
 country KZ:
 	(2402 - 2482 @ 40), (N/A, 20)
 
 country LB:
 	(2402 - 2482 @ 40), (N/A, 20)
-	(5735 - 5835 @ 40), (N/A, 30)
+	(5150 - 5250 @ 80), (6, 17)
+	(5250 - 5350 @ 80), (6, 24), DFS
+	(5470 - 5725 @ 80), (6, 24), DFS
+	(5725 - 5850 @ 80), (6, 30)
 
 country LI: DFS-ETSI
 	(2402 - 2482 @ 40), (N/A, 20)
-	(5170 - 5250 @ 40), (N/A, 20)
-	(5250 - 5330 @ 40), (N/A, 20), DFS
-	(5490 - 5710 @ 40), (N/A, 27), DFS
+	(5170 - 5250 @ 80), (N/A, 20)
+	(5250 - 5330 @ 80), (N/A, 20), DFS
+	(5490 - 5710 @ 80), (N/A, 27), DFS
 
 country LK:
 	(2402 - 2482 @ 40), (N/A, 20)
@@ -488,35 +542,38 @@
 
 country LT: DFS-ETSI
 	(2402 - 2482 @ 40), (N/A, 20)
-	(5170 - 5250 @ 40), (N/A, 20)
-	(5250 - 5330 @ 40), (N/A, 20), DFS
-	(5490 - 5710 @ 40), (N/A, 27), DFS
+	(5170 - 5250 @ 80), (N/A, 20)
+	(5250 - 5330 @ 80), (N/A, 20), DFS
+	(5490 - 5710 @ 80), (N/A, 27), DFS
 	# 60 gHz band channels 1-4, ref: Etsi En 302 567
 	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
 
 country LU: DFS-ETSI
 	(2402 - 2482 @ 40), (N/A, 20)
-	(5170 - 5250 @ 40), (N/A, 20)
-	(5250 - 5330 @ 40), (N/A, 20), DFS
-	(5490 - 5710 @ 40), (N/A, 27), DFS
+	(5170 - 5250 @ 80), (N/A, 20)
+	(5250 - 5330 @ 80), (N/A, 20), DFS
+	(5490 - 5710 @ 80), (N/A, 27), DFS
 	# 60 gHz band channels 1-4, ref: Etsi En 302 567
 	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
 
 country LV: DFS-ETSI
 	(2402 - 2482 @ 40), (N/A, 20)
-	(5170 - 5250 @ 40), (N/A, 20)
-	(5250 - 5330 @ 40), (N/A, 20), DFS
-	(5490 - 5710 @ 40), (N/A, 27), DFS
+	(5170 - 5250 @ 80), (N/A, 20)
+	(5250 - 5330 @ 80), (N/A, 20), DFS
+	(5490 - 5710 @ 80), (N/A, 27), DFS
 	# 60 gHz band channels 1-4, ref: Etsi En 302 567
 	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
 
 country MC: DFS-ETSI
 	(2402 - 2482 @ 40), (N/A, 20)
-	(5170 - 5250 @ 40), (N/A, 18)
-	(5250 - 5330 @ 40), (N/A, 18), DFS
+        (5150 - 5250 @ 80), (N/A, 20)
+        (5250 - 5350 @ 80), (N/A, 20), DFS
+        (5470 - 5725 @ 80), (N/A, 27), DFS
 
 country MA:
 	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 80), (N/A, 20)
+	(5735 - 5835 @ 80), (N/A, 20), DFS
 
 country MO:
 	(2402 - 2482 @ 40), (N/A, 20)
@@ -524,6 +581,13 @@
 	(5250 - 5330 @ 40), (3, 23), DFS
 	(5735 - 5835 @ 40), (3, 30)
 
+country MP:
+	(2402 - 2472 @ 40), (N/A, 30)
+        (5150 - 5250 @ 80), (6, 17)
+        (5250 - 5350 @ 80), (6, 24), DFS
+        (5470 - 5725 @ 80), (6,	24), DFS
+        (5725 - 5850 @ 80), (6, 30)
+
 country MK: DFS-ETSI
 	(2402 - 2482 @ 40), (N/A, 20)
 	(5170 - 5250 @ 40), (N/A, 20)
@@ -532,6 +596,13 @@
 	# 60 gHz band channels 1-4, ref: Etsi En 302 567
 	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
 
+country MN:
+	(2402 - 2482 @ 40), (N/A, 20)
+        (5150 - 5250 @ 80), (6, 17)
+        (5250 - 5350 @ 80), (6, 24), DFS
+        (5470 - 5725 @ 80), (6, 24), DFS
+        (5725 - 5850 @ 80), (6,	30)
+
 country MT: DFS-ETSI
 	(2402 - 2482 @ 40), (N/A, 20)
 	(5170 - 5250 @ 40), (N/A, 20)
@@ -540,105 +611,167 @@
 	# 60 gHz band channels 1-4, ref: Etsi En 302 567
 	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
 
+country MQ: DFS-ETSI
+        (2402 - 2482 @ 40), (N/A, 20)
+        (5150 - 5250 @ 80), (N/A, 20)
+	(5250 - 5350 @ 80), (N/A, 20), DFS
+	(5470 - 5725 @ 80), (N/A, 27), DFS
+
+country MU:
+        (2402 - 2482 @ 40), (N/A, 20)
+        (5150 - 5250 @ 80), (6, 17)
+        (5250 - 5350 @ 80), (6, 24), DFS
+        (5470 - 5725 @ 80), (6, 24), DFS
+        (5725 - 5850 @ 80), (6, 30)
+
 country MY:
 	(2402 - 2482 @ 40), (N/A, 20)
-	(5250 - 5330 @ 40), (N/A, 30), DFS
-	(5735 - 5835 @ 40), (N/A, 30)
+	(5170 - 5250 @ 80), (N/A, 17)
+	(5250 - 5330 @ 80), (N/A, 23), DFS
+	(5735 - 5835 @ 80), (N/A, 30)
 
 country MX:
 	(2402 - 2472 @ 40), (3, 27)
-	(5170 - 5250 @ 40), (3, 17)
-	(5250 - 5330 @ 40), (3, 23), DFS
-	(5735 - 5835 @ 40), (3, 30)
+	(5170 - 5250 @ 80), (3, 17)
+	(5250 - 5330 @ 80), (3, 24), DFS
+	(5490 - 5710 @ 80), (3, 24), DFS
+	(5735 - 5835 @ 80), (3, 30)
+
+country MW:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5150 - 5250 @ 80), (N/A, 20)
+	(5250 - 5350 @ 80), (N/A, 20), DFS
+	(5470 - 5725 @ 80), (N/A, 27), DFS
+
+country NG:
+	(2402 - 2482 @ 40), (N/A, 20)
+        (5250 - 5350 @ 80), (N/A, 30), DFS
+        (5725 - 5850 @ 80), (N/A, 30)
+
+country NI:
+	(2402 - 2472 @ 40), (N/A, 30)
+        (5150 - 5250 @ 80), (6, 17)
+        (5250 - 5350 @ 80), (6, 24), DFS
+        (5470 - 5725 @ 80), (6,	24), DFS
+        (5725 - 5850 @ 80), (6, 30)
 
 country NL: DFS-ETSI
 	(2402 - 2482 @ 40), (N/A, 20)
-	(5170 - 5250 @ 40), (N/A, 20), NO-OUTDOOR
-	(5250 - 5330 @ 40), (N/A, 20), NO-OUTDOOR, DFS
-	(5490 - 5710 @ 40), (N/A, 27), DFS
+	(5170 - 5250 @ 80), (N/A, 20), NO-OUTDOOR
+	(5250 - 5330 @ 80), (N/A, 20), NO-OUTDOOR, DFS
+	(5490 - 5710 @ 80), (N/A, 27), DFS
 	# 60 gHz band channels 1-4, ref: Etsi En 302 567
 	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
 
 country NO: DFS-ETSI
 	(2402 - 2482 @ 40), (N/A, 20)
-	(5170 - 5250 @ 40), (N/A, 20)
-	(5250 - 5330 @ 40), (N/A, 20), DFS
-	(5490 - 5710 @ 40), (N/A, 27), DFS
+	(5170 - 5250 @ 80), (N/A, 20)
+	(5250 - 5330 @ 80), (N/A, 20), DFS
+	(5490 - 5710 @ 80), (N/A, 27), DFS
 	# 60 gHz band channels 1-4, ref: Etsi En 302 567
 	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
 
 country NP:
 	(2402 - 2482 @ 40), (N/A, 20)
-	(5735 - 5835 @ 40), (N/A, 30)
+        (5150 - 5250 @ 80), (N/A, 20)
+        (5250 - 5350 @ 80), (N/A, 20), DFS
+        (5725 - 5850 @ 80), (N/A, 20)
 
 country NZ:
 	(2402 - 2482 @ 40), (N/A, 30)
-	(5170 - 5250 @ 20), (3, 23)
-	(5250 - 5330 @ 20), (3, 23), DFS
-	(5735 - 5835 @ 20), (3, 30)
+	(5170 - 5250 @ 80), (6, 17)
+	(5250 - 5330 @ 80), (6, 24), DFS
+	(5490 - 5710 @ 80), (6, 24), DFS
+	(5735 - 5835 @ 80), (6, 30)
 
 country OM:
 	(2402 - 2482 @ 40), (N/A, 20)
-	(5170 - 5250 @ 40), (3, 17)
-	(5250 - 5330 @ 40), (3, 20), DFS
-	(5490 - 5710 @ 40), (3, 20), DFS
-	(5735 - 5835 @ 40), (3, 30)
+	(5150 - 5250 @ 80), (N/A, 20)
+	(5250 - 5350 @ 80), (N/A, 20), DFS
+	(5470 - 5725 @ 80), (N/A, 27), DFS
 
 country PA:
-	(2402 - 2472 @ 40), (3, 27)
-	(5170 - 5250 @ 40), (3, 17)
-	(5250 - 5330 @ 40), (3, 23), DFS
-	(5735 - 5835 @ 40), (3, 30)
+	(2402 - 2472 @ 40), (N/A, 30)
+	(5170 - 5250 @ 80), (6, 17)
+	(5250 - 5330 @ 80), (6, 23), DFS
+	(5735 - 5835 @ 80), (6, 30)
 
 country PE:
 	(2402 - 2482 @ 40), (N/A, 20)
-	(5735 - 5835 @ 40), (N/A, 30)
+	(5170 - 5250 @ 80), (6, 20)
+	(5250 - 5330 @ 80), (6, 20), DFS
+	(5490 - 5710 @ 80), (6, 27), DFS
+	(5735 - 5835 @ 80), (6, 30)
+
+country PF:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5150 - 5250 @ 80), (N/A, 20)
+	(5250 - 5350 @ 80), (N/A, 20), DFS
+        (5470 - 5725 @ 80), (N/A, 27), DFS
 
 country PG:
 	(2402 - 2482 @ 40), (N/A, 20)
-	(5170 - 5250 @ 40), (3, 17)
-	(5250 - 5330 @ 40), (3, 23), DFS
-	(5735 - 5835 @ 40), (3, 30)
+	(5150 - 5250 @ 80), (6, 17)
+	(5250 - 5350 @ 80), (6, 24), DFS
+	(5470 - 5725 @ 80), (6, 24), DFS
+	(5725 - 5850 @ 80), (6, 30)
 
 country PH:
 	(2402 - 2482 @ 40), (N/A, 20)
-	(5735 - 5835 @ 40), (N/A, 30)
+	(5170 - 5250 @ 80), (6, 17)
+	(5250 - 5330 @ 80), (6, 24), DFS
+	(5490 - 5710 @ 80), (6, 24), DFS
+	(5735 - 5835 @ 80), (6, 30)
 
 country PK:
 	(2402 - 2482 @ 40), (N/A, 20)
-	(5735 - 5835 @ 40), (N/A, 30)
+	(5735 - 5835 @ 80), (N/A, 30)
 
 country PL: DFS-ETSI
 	(2402 - 2482 @ 40), (N/A, 20)
-	(5170 - 5250 @ 40), (N/A, 20)
-	(5250 - 5330 @ 40), (N/A, 20), DFS
-	(5490 - 5710 @ 40), (N/A, 27), DFS
+	(5170 - 5250 @ 80), (N/A, 20)
+	(5250 - 5330 @ 80), (N/A, 20), DFS
+	(5490 - 5710 @ 80), (N/A, 27), DFS
 	# 60 gHz band channels 1-4, ref: Etsi En 302 567
 	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
 
 country PT: DFS-ETSI
 	(2402 - 2482 @ 40), (N/A, 20)
-	(5170 - 5250 @ 40), (N/A, 20)
-	(5250 - 5330 @ 40), (N/A, 20), DFS
-	(5490 - 5710 @ 40), (N/A, 27), DFS
+	(5170 - 5250 @ 80), (N/A, 20)
+	(5250 - 5330 @ 80), (N/A, 20), DFS
+	(5490 - 5710 @ 80), (N/A, 27), DFS
 	# 60 gHz band channels 1-4, ref: Etsi En 302 567
 	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
 
 country PR:
-	(2402 - 2472 @ 40), (3, 27)
-	(5170 - 5250 @ 40), (3, 17)
-	(5250 - 5330 @ 40), (3, 23), DFS
-	(5735 - 5835 @ 40), (3, 30)
+	(2402 - 2472 @ 40), (3, 30)
+	(5170 - 5250 @ 80), (6, 17)
+	(5250 - 5330 @ 80), (6, 24), DFS
+	(5490 - 5710 @ 80), (6, 24), DFS
+	(5735 - 5835 @ 80), (6, 30)
+
+country PY:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5150 - 5250 @ 80), (6, 17)
+	(5250 - 5350 @ 80), (6, 24), DFS
+	(5470 - 5725 @ 80), (6, 24), DFS
+	(5725 - 5850 @ 80), (6, 30)
 
 country QA:
 	(2402 - 2482 @ 40), (N/A, 20)
-	(5735 - 5835 @ 40), (N/A, 30)
+	(5735 - 5835 @ 80), (N/A, 30)
+
+country RE:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5150 - 5250 @ 80), (N/A, 20)
+	(5250 - 5350 @ 80), (N/A, 20), DFS
+	(5470 - 5725 @ 80), (N/A, 27), DFS
 
 country RO: DFS-ETSI
 	(2402 - 2482 @ 40), (N/A, 20)
-	(5170 - 5250 @ 40), (N/A, 20)
-	(5250 - 5330 @ 40), (N/A, 20), DFS
-	(5490 - 5710 @ 40), (N/A, 27), DFS
+	(5170 - 5250 @ 80), (N/A, 20)
+	(5250 - 5330 @ 80), (N/A, 20), DFS
+	(5490 - 5710 @ 80), (N/A, 27), DFS
 	# 60 gHz band channels 1-4, ref: Etsi En 302 567
 	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
 
@@ -647,52 +780,61 @@
 # http://www.ratel.rs/upload/documents/Plan_namene/Plan_namene-sl_glasnik.pdf
 country RS:
 	(2400 - 2483.5 @ 40), (N/A, 100 mW)
-	(5150 - 5350 @ 40), (N/A, 200 mW), NO-OUTDOOR
-	(5470 - 5725 @ 20), (3, 1000 mW), DFS
+	(5150 - 5250 @ 80), (N/A, 200 mW), NO-OUTDOOR
+        (5250 - 5350 @ 80), (N/A, 200 mW), DFS
+	(5470 - 5725 @ 80), (3, 1000 mW), DFS
 	# 60 gHz band channels 1-4, ref: Etsi En 302 567
 	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
 
 country RU:
 	(2402 - 2482 @ 40), (N/A, 20)
-	(5735 - 5835 @ 20), (N/A, 30)
+	(5150 - 5250 @ 40), (N/A, 20)
+	(5250 - 5350 @ 40), (N/A, 20), DFS
+	(5650 - 5725 @ 40), (N/A, 30), DFS
+	(5725 - 5825 @ 40), (N/A, 30)
 
 country RW:
 	(2402 - 2482 @ 40), (N/A, 20)
-	(5735 - 5835 @ 40), (N/A, 30)
+	(5150 - 5250 @ 80), (6, 17)
+	(5250 - 5330 @ 80), (6, 24), DFS
+	(5470 - 5725 @ 80), (6, 24), DFS
+	(5725 - 5835 @ 80), (6, 30)
 
 country SA:
 	(2402 - 2482 @ 40), (N/A, 20)
-	(5170 - 5250 @ 20), (3, 23)
-	(5250 - 5330 @ 20), (3, 23), DFS
-	(5735 - 5835 @ 20), (3, 30)
+	(5170 - 5250 @ 80), (3, 17)
+	(5250 - 5330 @ 80), (3, 24), DFS
+	(5490 - 5710 @ 80), (3, 24), DFS
+	(5735 - 5835 @ 80), (3, 30)
 
 country SE: DFS-ETSI
 	(2402 - 2482 @ 40), (N/A, 20)
-	(5170 - 5250 @ 40), (N/A, 20)
-	(5250 - 5330 @ 40), (N/A, 20), DFS
-	(5490 - 5710 @ 40), (N/A, 27), DFS
+	(5170 - 5250 @ 80), (N/A, 20)
+	(5250 - 5330 @ 80), (N/A, 20), DFS
+	(5490 - 5710 @ 80), (N/A, 27), DFS
 	# 60 gHz band channels 1-4, ref: Etsi En 302 567
 	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
 
 country SG:
 	(2402 - 2482 @ 40), (N/A, 20)
-	(5170 - 5250 @ 40), (N/A, 20)
-	(5250 - 5330 @ 40), (N/A, 20), DFS
-	(5735 - 5835 @ 40), (N/A, 20)
+	(5170 - 5250 @ 80), (6, 17)
+	(5250 - 5330 @ 80), (6, 24), DFS
+	(5490 - 5710 @ 80), (6, 24), DFS
+	(5735 - 5835 @ 80), (6, 30)
 
 country SI: DFS-ETSI
 	(2402 - 2482 @ 40), (N/A, 20)
-	(5170 - 5250 @ 40), (N/A, 20)
-	(5250 - 5330 @ 40), (N/A, 20), DFS
-	(5490 - 5710 @ 40), (N/A, 27), DFS
+	(5170 - 5250 @ 80), (N/A, 20)
+	(5250 - 5330 @ 80), (N/A, 20), DFS
+	(5490 - 5710 @ 80), (N/A, 27), DFS
 	# 60 gHz band channels 1-4, ref: Etsi En 302 567
 	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
 
 country SK: DFS-ETSI
 	(2402 - 2482 @ 40), (N/A, 20)
-	(5170 - 5250 @ 40), (N/A, 20)
-	(5250 - 5330 @ 40), (N/A, 20), DFS
-	(5490 - 5710 @ 40), (N/A, 27), DFS
+	(5170 - 5250 @ 80), (N/A, 20)
+	(5250 - 5330 @ 80), (N/A, 20), DFS
+	(5490 - 5710 @ 80), (N/A, 27), DFS
 	# 60 gHz band channels 1-4, ref: Etsi En 302 567
 	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
 
@@ -707,15 +849,16 @@
 
 country TW:
 	(2402 - 2472 @ 40), (3, 27)
-	(5270 - 5330 @ 40), (3, 17), DFS
-	(5735 - 5815 @ 40), (3, 30)
+	(5270 - 5330 @ 80), (6, 17), DFS
+	(5490 - 5710 @ 80), (6, 30), DFS
+	(5735 - 5815 @ 80), (6, 30)
 
 country TH:
 	(2402 - 2482 @ 40), (N/A, 20)
-	(5170 - 5250 @ 40), (3, 17)
-	(5250 - 5330 @ 40), (3, 20), DFS
-	(5490 - 5710 @ 40), (3, 20), DFS
-	(5735 - 5835 @ 40), (3, 30)
+	(5170 - 5250 @ 80), (3, 17)
+	(5250 - 5330 @ 80), (3, 24), DFS
+	(5490 - 5710 @ 80), (3, 24), DFS
+	(5735 - 5835 @ 80), (3, 30)
 
 country TT:
 	(2402 - 2482 @ 40), (N/A, 20)
@@ -731,8 +874,9 @@
 
 country TR: DFS-ETSI
 	(2402 - 2482 @ 40), (N/A, 20)
-	(5170 - 5250 @ 20), (N/A, 20)
-	(5250 - 5330 @ 20), (N/A, 20), DFS
+	(5170 - 5250 @ 80), (N/A, 20)
+	(5250 - 5330 @ 80), (N/A, 20), DFS
+	(5490 - 5710 @ 80), (N/A, 27), DFS
 	# 60 gHz band channels 1-4, ref: Etsi En 302 567
 	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
  
@@ -745,22 +889,42 @@
 # disputable definitions there.
 country UA:
 	(2400 - 2483.5 @ 40), (N/A, 20), NO-OUTDOOR
-	(5150 - 5350 @ 40), (N/A, 20), NO-OUTDOOR
+	(5150 - 5250 @ 40), (N/A, 20), NO-OUTDOOR
+	(5250 - 5350 @ 40), (N/A, 20), NO-OUTDOOR, DFS
+	(5470 - 5670 @ 40), (N/A, 20), DFS
+	(5725 - 5850 @ 40), (N/A, 20)
 	# 60 gHz band channels 1-4, ref: Etsi En 302 567
 	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
 
+country UG:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5150 - 5250 @ 80), (6, 20)
+	(5250 - 5350 @ 80), (6, 20), DFS
+        (5470 - 5725 @ 80), (6, 20), DFS
+        (5725 - 5825 @ 80), (6, 20)
+
 country US: DFS-FCC
 	(2402 - 2472 @ 40), (3, 27)
-	(5170 - 5250 @ 40), (3, 17)
-	(5250 - 5330 @ 40), (3, 20), DFS
-	(5490 - 5600 @ 40), (3, 20), DFS
-	(5650 - 5710 @ 40), (3, 20), DFS
-	(5735 - 5835 @ 40), (3, 30)
+	(5170 - 5250 @ 80), (3, 17)
+	(5250 - 5330 @ 80), (3, 24), DFS
+	(5490 - 5600 @ 80), (3, 24), DFS
+	(5650 - 5710 @ 40), (3, 24), DFS
+	(5735 - 5835 @ 80), (3, 30)
 	# 60g band
 	# reference: http://cfr.regstoday.com/47cfr15.aspx#47_CFR_15p255
 	# channels 1,2,3, EIRP=40dBm(43dBm peak)
 	(57240 - 63720 @ 2160), (N/A, 40)
 
+# Public Safety FCCA, FCC4
+#  27dBm [4.9GHz 1/4 rate], 30dBm [1/2 rate], 33dBm [full rate], and 5GHz same as FCC1
+#  db.txt cannot express the limitation on 5G so disable all 5G channels for FCC4
+country PS:
+	(2402 - 2472 @ 40), (N/A, 30)
+	#(4940 - 4990 @ 40), (6, 27)
+	#(5150 - 5250 @ 80), (6, 30)
+	#(5250 - 5350 @ 80), (6, 30), DFS
+	#(5725 - 5850 @ 80), (6, 33)
+
 country UY:
 	(2402 - 2482 @ 40), (N/A, 20)
 	(5170 - 5250 @ 40), (3, 17)
@@ -777,23 +941,44 @@
 
 country VE:
 	(2402 - 2482 @ 40), (N/A, 20)
-	(5735 - 5815 @ 40), (N/A, 23)
+      (5150 - 5250 @ 80), (6, 17)
+      (5250 - 5350 @ 80), (6, 23), DFS
+      (5725 - 5850 @ 80), (6, 30)
+
 
 country VN:
 	(2402 - 2482 @ 40), (N/A, 20)
-	(5170 - 5250 @ 40), (N/A, 20)
-	(5250 - 5330 @ 40), (N/A, 20), DFS
+	(5170 - 5250 @ 80), (3, 17)
+	(5250 - 5330 @ 80), (3, 24), DFS
+	(5490 - 5710 @ 80), (3, 24), DFS
+	(5735 - 5835 @ 80), (3, 30)
+
+country VI:
+	(2402 - 2472 @ 40), (N/A, 30)
+	(5150 - 5250 @ 80), (6, 17)
+	(5250 - 5350 @ 80), (6, 24), DFS
+	(5470 - 5725 @ 80), (6, 24), DFS
+	(5725 - 5850 @ 80), (6, 30)
 
 country YE:
 	(2402 - 2482 @ 40), (N/A, 20)
 
+country YT: DFS-ETSI
+	(2402 - 2482 @ 40), (N/A, 20)
+        (5150 - 5250 @ 80), (N/A, 20)
+        (5250 - 5350 @ 80), (N/A, 20), DFS
+        (5470 - 5725 @ 80), (N/A, 27), DFS
+
 country ZA:
 	(2402 - 2482 @ 40), (N/A, 20)
-	(5170 - 5250 @ 40), (3, 17)
-	(5250 - 5330 @ 40), (3, 20), DFS
-	(5490 - 5710 @ 40), (3, 20), DFS
-	(5735 - 5835 @ 40), (3, 30)
+	(5170 - 5250 @ 80), (3, 17)
+	(5250 - 5330 @ 80), (3, 24), DFS
+	(5490 - 5710 @ 80), (3, 24), DFS
+	(5735 - 5835 @ 80), (3, 30)
 
 country ZW:
 	(2402 - 2482 @ 40), (N/A, 20)
+	(5150 - 5250 @ 80), (N/A, 20)
+	(5250 - 5350 @ 80), (N/A, 20), DFS
+	(5470 - 5725 @ 80), (N/A, 27), DFS
 
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index b96094c..bddb720 100755
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -848,8 +848,18 @@
 		    r == -ERANGE)
 			return;
 
-		REG_DBG_PRINT("Disabling freq %d MHz\n", chan->center_freq);
-		chan->flags = IEEE80211_CHAN_DISABLED;
+		if (last_request->initiator == NL80211_REGDOM_SET_BY_DRIVER &&
+		    request_wiphy && request_wiphy == wiphy &&
+		    request_wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY) {
+			REG_DBG_PRINT("Disabling freq %d MHz for good\n",
+			chan->center_freq);
+			chan->orig_flags |= IEEE80211_CHAN_DISABLED;
+			chan->flags = chan->orig_flags;
+		} else {
+			REG_DBG_PRINT("Disabling freq %d MHz\n",
+			chan->center_freq);
+			chan->flags |= IEEE80211_CHAN_DISABLED;
+		}
 		return;
 	}
 
@@ -883,7 +893,19 @@
 	chan->max_antenna_gain = min(chan->orig_mag,
 		(int) MBI_TO_DBI(power_rule->max_antenna_gain));
 	chan->max_reg_power = (int) MBM_TO_DBM(power_rule->max_eirp);
-	chan->max_power = min(chan->max_power, chan->max_reg_power);
+	if (chan->orig_mpwr) {
+		/*
+		 * Devices that use NL80211_COUNTRY_IE_FOLLOW_POWER will always
+		 * follow the passed country IE power settings.
+		 */
+		if (initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE &&
+		    wiphy->country_ie_pref & NL80211_COUNTRY_IE_FOLLOW_POWER)
+			chan->max_power = chan->max_reg_power;
+		else
+			chan->max_power = min(chan->orig_mpwr,
+					      chan->max_reg_power);
+	} else
+		chan->max_power = chan->max_reg_power;
 }
 
 static void handle_band(struct wiphy *wiphy,
@@ -1218,7 +1240,8 @@
 			      "wide channel\n",
 			      chan->center_freq,
 			      KHZ_TO_MHZ(desired_bw_khz));
-		chan->flags = IEEE80211_CHAN_DISABLED;
+		chan->orig_flags |= IEEE80211_CHAN_DISABLED;
+		chan->flags = chan->orig_flags;
 		return;
 	}
 
@@ -1295,6 +1318,8 @@
 	case NL80211_REGDOM_SET_BY_CORE:
 		return 0;
 	case NL80211_REGDOM_SET_BY_COUNTRY_IE:
+		if (wiphy->country_ie_pref & NL80211_COUNTRY_IE_IGNORE_CORE)
+			return -EALREADY;
 
 		last_wiphy = wiphy_idx_to_wiphy(last_request->wiphy_idx);
 
@@ -1648,6 +1673,7 @@
 
 	return 0;
 }
+EXPORT_SYMBOL(regulatory_hint_user);
 
 /* Driver hints */
 int regulatory_hint(struct wiphy *wiphy, const char *alpha2)
@@ -2117,7 +2143,7 @@
 		 * checking if the alpha2 changes if CRDA was already called
 		 */
 		if (!regdom_changes(rd->alpha2))
-			return -EINVAL;
+			return -EALREADY;
 	}
 
 	/*
@@ -2242,6 +2268,9 @@
 	/* Note that this doesn't update the wiphys, this is done below */
 	r = __set_regdom(rd);
 	if (r) {
+		if (r == -EALREADY)
+			reg_set_request_processed();
+
 		kfree(rd);
 		mutex_unlock(&reg_mutex);
 		return r;
diff --git a/net/wireless/reg.h b/net/wireless/reg.h
index e2aaaf5..017880c 100644
--- a/net/wireless/reg.h
+++ b/net/wireless/reg.h
@@ -22,8 +22,6 @@
 bool reg_is_valid_request(const char *alpha2);
 bool reg_supported_dfs_region(u8 dfs_region);
 
-int regulatory_hint_user(const char *alpha2);
-
 int reg_device_uevent(struct device *dev, struct kobj_uevent_env *env);
 void reg_device_remove(struct wiphy *wiphy);
 
diff --git a/sound/soc/msm/msm-dai-fe.c b/sound/soc/msm/msm-dai-fe.c
index d235a69..39cb470 100644
--- a/sound/soc/msm/msm-dai-fe.c
+++ b/sound/soc/msm/msm-dai-fe.c
@@ -281,6 +281,17 @@
 			.rate_min =	8000,
 			.rate_max = 192000,
 		},
+		.capture = {
+			.stream_name = "MultiMedia8 Capture",
+			.aif_name = "MM_UL8",
+			.rates = (SNDRV_PCM_RATE_8000_48000|
+					SNDRV_PCM_RATE_KNOT),
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+			.channels_min = 1,
+			.channels_max = 8,
+			.rate_min =     8000,
+			.rate_max =	48000,
+		},
 		.ops = &msm_fe_Multimedia_dai_ops,
 		.name = "MultiMedia8",
 	},
diff --git a/sound/soc/msm/msm8974.c b/sound/soc/msm/msm8974.c
index 99f196c..b34750a 100644
--- a/sound/soc/msm/msm8974.c
+++ b/sound/soc/msm/msm8974.c
@@ -2158,7 +2158,7 @@
 		.name = "MSM8974 Compr4",
 		.stream_name = "COMPR4",
 		.cpu_dai_name	= "MultiMedia8",
-		.platform_name  = "msm-compress-dsp",
+		.platform_name  = "msm-compr-dsp",
 		.dynamic = 1,
 		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
 			 SND_SOC_DPCM_TRIGGER_POST},
diff --git a/sound/soc/msm/qdsp6v2/Makefile b/sound/soc/msm/qdsp6v2/Makefile
index 15128c9..5aa84a0 100644
--- a/sound/soc/msm/qdsp6v2/Makefile
+++ b/sound/soc/msm/qdsp6v2/Makefile
@@ -1,6 +1,7 @@
 snd-soc-qdsp6v2-objs += msm-dai-q6-v2.o msm-pcm-q6-v2.o msm-pcm-routing-v2.o \
-			msm-compress-q6-v2.o msm-multi-ch-pcm-q6-v2.o \
-			msm-pcm-lpa-v2.o msm-pcm-afe-v2.o msm-pcm-voip-v2.o \
+			msm-compress-q6-v2.o msm-compr-q6-v2.o \
+			msm-multi-ch-pcm-q6-v2.o msm-pcm-lpa-v2.o \
+			msm-pcm-afe-v2.o msm-pcm-voip-v2.o \
 			msm-pcm-voice-v2.o msm-dai-q6-hdmi-v2.o \
 			msm-lsm-client.o
 obj-$(CONFIG_SND_SOC_QDSP6V2) += snd-soc-qdsp6v2.o msm-pcm-dtmf-v2.o \
diff --git a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
index b626fa4..bb325d8 100755
--- a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
@@ -52,6 +52,9 @@
 #define COMPRESSED_LR_VOL_MAX_STEPS	0x20002000
 
 #define MAX_AC3_PARAM_SIZE		(18*2*sizeof(int))
+#define AMR_WB_BAND_MODE 8
+#define AMR_WB_DTX_MODE 0
+
 
 const DECLARE_TLV_DB_LINEAR(compr_rx_vol_gain, 0,
 			    COMPRESSED_LR_VOL_MAX_STEPS);
@@ -108,12 +111,30 @@
 	8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000
 };
 
+/* Add supported codecs for compress capture path */
+static uint32_t supported_compr_capture_codecs[] = {
+	SND_AUDIOCODEC_AMRWB
+};
+
 static struct snd_pcm_hw_constraint_list constraints_sample_rates = {
 	.count = ARRAY_SIZE(supported_sample_rates),
 	.list = supported_sample_rates,
 	.mask = 0,
 };
 
+static bool msm_compr_capture_codecs(uint32_t req_codec)
+{
+	int i;
+	pr_debug("%s req_codec:%d\n", __func__, req_codec);
+	if (req_codec == 0)
+		return false;
+	for (i = 0; i < ARRAY_SIZE(supported_compr_capture_codecs); i++) {
+		if (req_codec == supported_compr_capture_codecs[i])
+			return true;
+	}
+	return false;
+}
+
 static void compr_event_handler(uint32_t opcode,
 		uint32_t token, uint32_t *payload, void *priv)
 {
@@ -428,6 +449,11 @@
 	prtd->pcm_count = snd_pcm_lib_period_bytes(substream);
 	prtd->pcm_irq_pos = 0;
 
+	if (!msm_compr_capture_codecs(codec->id)) {
+		/*request codec invalid or not supported,
+		use default compress format*/
+		codec->id = SND_AUDIOCODEC_AMRWB;
+	}
 	/* rate and channels are sent to audio driver */
 	prtd->samp_rate = runtime->rate;
 	prtd->channel_mode = runtime->channels;
@@ -441,8 +467,12 @@
 		pr_debug("SND_AUDIOCODEC_AMRWB\n");
 		ret = q6asm_enc_cfg_blk_amrwb(prtd->audio_client,
 			MAX_NUM_FRAMES_PER_BUFFER,
-			codec->options.generic.reserved[0] /*bitrate 0-8*/,
-			codec->options.generic.reserved[1] /*dtx mode 0/1*/);
+			/* use fixed band mode and dtx mode
+			 *  band mode - 23.85 kbps
+                         */
+			AMR_WB_BAND_MODE,
+			/* dtx mode - disable */
+			AMR_WB_DTX_MODE);
 		if (ret < 0)
 			pr_err("%s: CMD Format block" \
 				"failed: %d\n", __func__, ret);
@@ -500,6 +530,13 @@
 		prtd->pcm_irq_pos = 0;
 
 		if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+			if (!msm_compr_capture_codecs(
+				compr->info.codec_param.codec.id)) {
+				/*request codec invalid or not supported,
+				use default compress format*/
+				compr->info.codec_param.codec.id =
+				SND_AUDIOCODEC_AMRWB;
+			}
 			switch (compr->info.codec_param.codec.id) {
 			case SND_AUDIOCODEC_AMRWB:
 				break;
@@ -834,6 +871,13 @@
 			pr_err("%s: Send SoftVolume Param failed ret=%d\n",
 				__func__, ret);
 	} else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+		if (!msm_compr_capture_codecs(
+			compr->info.codec_param.codec.id)) {
+			/*request codec invalid or not supported,
+			use default compress format*/
+			compr->info.codec_param.codec.id =
+				SND_AUDIOCODEC_AMRWB;
+		}
 		switch (compr->info.codec_param.codec.id) {
 		case SND_AUDIOCODEC_AMRWB:
 			pr_debug("q6asm_open_read(FORMAT_AMRWB)\n");
diff --git a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c
index 79f0a97..55d50ed 100644
--- a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c
@@ -372,9 +372,11 @@
 			COMPR_PLAYBACK_MIN_NUM_FRAGMENTS;
 	prtd->compr_cap.max_fragments =
 			COMPR_PLAYBACK_MAX_NUM_FRAGMENTS;
-	prtd->compr_cap.num_codecs = 2;
+	prtd->compr_cap.num_codecs = 4;
 	prtd->compr_cap.codecs[0] = SND_AUDIOCODEC_MP3;
 	prtd->compr_cap.codecs[1] = SND_AUDIOCODEC_AAC;
+	prtd->compr_cap.codecs[2] = SND_AUDIOCODEC_AC3;
+	prtd->compr_cap.codecs[3] = SND_AUDIOCODEC_EAC3;
 }
 
 static int msm_compr_send_media_format_block(struct snd_compr_stream *cstream,
@@ -400,6 +402,10 @@
 		if (ret < 0)
 			pr_err("%s: CMD Format block failed\n", __func__);
 		break;
+	case FORMAT_AC3:
+		break;
+	case FORMAT_EAC3:
+		break;
 	default:
 		pr_debug("%s, unsupported format, skip", __func__);
 		break;
@@ -685,6 +691,16 @@
 		break;
 	}
 
+	case SND_AUDIOCODEC_AC3: {
+		prtd->codec = FORMAT_AC3;
+		break;
+	}
+
+	case SND_AUDIOCODEC_EAC3: {
+		prtd->codec = FORMAT_EAC3;
+		break;
+	}
+
 	default:
 		pr_err("codec not supported, id =%d\n", params->codec.id);
 		return -EINVAL;
@@ -1226,6 +1242,10 @@
 			(SND_AUDIOSTREAMFORMAT_MP4ADTS |
 				SND_AUDIOSTREAMFORMAT_RAW);
 		break;
+	case SND_AUDIOCODEC_AC3:
+		break;
+	case SND_AUDIOCODEC_EAC3:
+		break;
 	default:
 		pr_err("%s: Unsupported audio codec %d\n",
 			__func__, codec->codec);
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-afe-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-afe-v2.c
index 0612805..d80ca19 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-afe-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-afe-v2.c
@@ -40,8 +40,8 @@
 
 #define MIN_CAPTURE_PERIOD_SIZE (128 * 2 * 4)
 #define MAX_CAPTURE_PERIOD_SIZE (128 * 2 * 2 * 6 * 4)
-#define MIN_CAPTURE_NUM_PERIODS (32 * 4)
-#define MAX_CAPTURE_NUM_PERIODS (384 * 4)
+#define MIN_CAPTURE_NUM_PERIODS (32)
+#define MAX_CAPTURE_NUM_PERIODS (384)
 
 static struct snd_pcm_hardware msm_afe_hardware_playback = {
 	.info =                 (SNDRV_PCM_INFO_MMAP |
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
index 1b4fae9..121c2ea 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
@@ -1933,6 +1933,31 @@
 	msm_routing_put_audio_mixer),
 };
 
+static const struct snd_kcontrol_new mmul8_mixer_controls[] = {
+	SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX,
+	MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_PRI_MI2S_TX,
+	MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_INT_FM_TX,
+	MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_INT_BT_SCO_TX,
+	MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("AFE_PCM_TX", MSM_BACKEND_DAI_AFE_PCM_TX,
+	MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("VOC_REC_DL", MSM_BACKEND_DAI_INCALL_RECORD_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("VOC_REC_UL", MSM_BACKEND_DAI_INCALL_RECORD_TX,
+	MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+};
+
+
 static const struct snd_kcontrol_new pri_rx_voice_mixer_controls[] = {
 	SOC_SINGLE_EXT("CSVoice", MSM_BACKEND_DAI_PRI_I2S_RX,
 	MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
@@ -2938,6 +2963,7 @@
 	SND_SOC_DAPM_AIF_OUT("MM_UL2", "MultiMedia2 Capture", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_OUT("MM_UL4", "MultiMedia4 Capture", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_OUT("MM_UL5", "MultiMedia5 Capture", 0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("MM_UL8", "MultiMedia8 Capture", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_OUT("MM_UL9", "MultiMedia9 Capture", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_IN("CS-VOICE_DL1", "CS-VOICE Playback", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_OUT("CS-VOICE_UL1", "CS-VOICE Capture", 0, 0, 0, 0),
@@ -3114,6 +3140,8 @@
 	mmul4_mixer_controls, ARRAY_SIZE(mmul4_mixer_controls)),
 	SND_SOC_DAPM_MIXER("MultiMedia5 Mixer", SND_SOC_NOPM, 0, 0,
 	mmul5_mixer_controls, ARRAY_SIZE(mmul5_mixer_controls)),
+	SND_SOC_DAPM_MIXER("MultiMedia8 Mixer", SND_SOC_NOPM, 0, 0,
+	mmul8_mixer_controls, ARRAY_SIZE(mmul8_mixer_controls)),
 	SND_SOC_DAPM_MIXER("AUX_PCM_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
 	auxpcm_rx_mixer_controls, ARRAY_SIZE(auxpcm_rx_mixer_controls)),
 	SND_SOC_DAPM_MIXER("SEC_AUX_PCM_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
@@ -3300,11 +3328,15 @@
 
 	{"MultiMedia1 Mixer", "VOC_REC_UL", "INCALL_RECORD_TX"},
 	{"MultiMedia4 Mixer", "VOC_REC_UL", "INCALL_RECORD_TX"},
+	{"MultiMedia8 Mixer", "VOC_REC_UL", "INCALL_RECORD_TX"},
 	{"MultiMedia1 Mixer", "VOC_REC_DL", "INCALL_RECORD_RX"},
 	{"MultiMedia4 Mixer", "VOC_REC_DL", "INCALL_RECORD_RX"},
+	{"MultiMedia8 Mixer", "VOC_REC_DL", "INCALL_RECORD_RX"},
 	{"MultiMedia1 Mixer", "SLIM_4_TX", "SLIMBUS_4_TX"},
 	{"MultiMedia4 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
+	{"MultiMedia8 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
 	{"MultiMedia4 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
+	{"MultiMedia8 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
 	{"MultiMedia5 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
 	{"MI2S_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
 	{"MI2S_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
@@ -3398,18 +3430,22 @@
 	{"MultiMedia1 Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
 	{"MultiMedia4 Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
 	{"MultiMedia5 Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
+	{"MultiMedia8 Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
 	{"MultiMedia1 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
 	{"MultiMedia4 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
 	{"MultiMedia5 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
+	{"MultiMedia8 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
 
 	{"MultiMedia1 Mixer", "AFE_PCM_TX", "PCM_TX"},
 	{"MultiMedia4 Mixer", "AFE_PCM_TX", "PCM_TX"},
 	{"MultiMedia5 Mixer", "AFE_PCM_TX", "PCM_TX"},
+	{"MultiMedia8 Mixer", "AFE_PCM_TX", "PCM_TX"},
 	{"MM_UL1", NULL, "MultiMedia1 Mixer"},
 	{"MultiMedia2 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
 	{"MM_UL2", NULL, "MultiMedia2 Mixer"},
 	{"MM_UL4", NULL, "MultiMedia4 Mixer"},
 	{"MM_UL5", NULL, "MultiMedia5 Mixer"},
+	{"MM_UL8", NULL, "MultiMedia8 Mixer"},
 
 	{"AUX_PCM_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
 	{"AUX_PCM_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
diff --git a/sound/soc/msm/qdsp6v2/q6afe.c b/sound/soc/msm/qdsp6v2/q6afe.c
index 09ecd75..acb8e70 100644
--- a/sound/soc/msm/qdsp6v2/q6afe.c
+++ b/sound/soc/msm/qdsp6v2/q6afe.c
@@ -2879,7 +2879,14 @@
 	uint16_t port_index;
 
 	if (this_afe.apr == NULL) {
-		pr_err("AFE is already closed\n");
+		pr_err("%s: AFE is already closed\n", __func__);
+		if ((port_id == RT_PROXY_DAI_001_RX) ||
+		    (port_id == RT_PROXY_DAI_002_TX))
+			pcm_afe_instance[port_id & 0x1] = 0;
+		if ((port_id == RT_PROXY_DAI_002_RX) ||
+		    (port_id == RT_PROXY_DAI_001_TX))
+			proxy_afe_instance[port_id & 0x1] = 0;
+		afe_close_done[port_id & 0x1] = true;
 		ret = -EINVAL;
 		goto fail_cmd;
 	}
diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c
index 3ae5221..2804c6a 100644
--- a/sound/soc/msm/qdsp6v2/q6asm.c
+++ b/sound/soc/msm/qdsp6v2/q6asm.c
@@ -1831,7 +1831,7 @@
 	struct asm_stream_cmd_open_readwrite_v2 open;
 
 	if ((ac == NULL) || (ac->apr == NULL)) {
-		pr_err("APR handle NULL\n");
+		pr_err("%s: APR handle NULL\n", __func__);
 		return -EINVAL;
 	}
 	pr_debug("%s: session[%d]", __func__, ac->session);
@@ -1943,7 +1943,7 @@
 	struct asm_session_cmd_run_v2 run;
 	int rc;
 	if (!ac || ac->apr == NULL) {
-		pr_err("APR handle NULL\n");
+		pr_err("%s: APR handle NULL\n", __func__);
 		return -EINVAL;
 	}
 	pr_debug("%s session[%d]", __func__, ac->session);
@@ -2871,7 +2871,7 @@
 	int	cmd_size = 0;
 
 	if (!ac || ac->mmap_apr == NULL) {
-		pr_err("APR handle NULL\n");
+		pr_err("%s: APR handle NULL\n", __func__);
 		return -EINVAL;
 	}
 	pr_debug("%s: Session[%d]\n", __func__, ac->session);
@@ -2948,7 +2948,7 @@
 	int rc = 0;
 
 	if (!ac || this_mmap.apr == NULL) {
-		pr_err("APR handle NULL\n");
+		pr_err("%s: APR handle NULL\n", __func__);
 		return -EINVAL;
 	}
 	pr_debug("%s: Session[%d]\n", __func__, ac->session);
@@ -3018,7 +3018,7 @@
 	uint32_t bufsz_t;
 
 	if (!ac || ac->mmap_apr == NULL) {
-		pr_err("APR handle NULL\n");
+		pr_err("%s: APR handle NULL\n", __func__);
 		return -EINVAL;
 	}
 	pr_debug("%s: Session[%d]\n", __func__, ac->session);
@@ -3127,7 +3127,7 @@
 	int	cmd_size = 0;
 
 	if (!ac || ac->mmap_apr == NULL) {
-		pr_err("APR handle NULL\n");
+		pr_err("%s: APR handle NULL\n", __func__);
 		return -EINVAL;
 	}
 	pr_debug("%s: Session[%d]\n", __func__, ac->session);
@@ -3513,7 +3513,7 @@
 	struct audio_port_data     *port;
 	int rc;
 	if (!ac || ac->apr == NULL) {
-		pr_err("APR handle NULL\n");
+		pr_err("%s: APR handle NULL\n", __func__);
 		return -EINVAL;
 	}
 	if (ac->io_mode & SYNC_IO_MODE) {
@@ -3576,7 +3576,7 @@
 	struct audio_port_data     *port;
 	int rc;
 	if (!ac || ac->apr == NULL) {
-		pr_err("APR handle NULL\n");
+		pr_err("%s: APR handle NULL\n", __func__);
 		return -EINVAL;
 	}
 	if (ac->io_mode & SYNC_IO_MODE) {
@@ -3773,7 +3773,7 @@
 	int dsp_buf = 0;
 
 	if (!ac || ac->apr == NULL) {
-		pr_err("APR handle NULL\n");
+		pr_err("%s: APR handle NULL\n", __func__);
 		return -EINVAL;
 	}
 	pr_debug("%s: session[%d] len=%d", __func__, ac->session, len);
@@ -3841,7 +3841,7 @@
 	int dsp_buf = 0;
 
 	if (!ac || ac->apr == NULL) {
-		pr_err("APR handle NULL\n");
+		pr_err("%s: APR handle NULL\n", __func__);
 		return -EINVAL;
 	}
 	pr_debug("%s: session[%d] len=%d", __func__, ac->session, len);
@@ -3900,7 +3900,7 @@
 	int rc;
 
 	if (!ac || ac->apr == NULL || tstamp == NULL) {
-		pr_err("APR handle NULL or tstamp NULL\n");
+		pr_err("%s: APR handle NULL or tstamp NULL\n", __func__);
 		return -EINVAL;
 	}
 	q6asm_add_hdr(ac, &hdr, sizeof(hdr), TRUE);
@@ -3938,7 +3938,7 @@
 	int cnt = 0;
 
 	if (!ac || ac->apr == NULL) {
-		pr_err("APR handle NULL\n");
+		pr_err("%s: APR handle NULL\n", __func__);
 		return -EINVAL;
 	}
 	q6asm_stream_add_hdr(ac, &hdr, sizeof(hdr), TRUE, stream_id);
@@ -4151,7 +4151,7 @@
 	int rc;
 
 	if (!ac || ac->apr == NULL) {
-		pr_err("APR handle NULL\n");
+		pr_err("%s: APR handle NULL\n", __func__);
 		return -EINVAL;
 	}
 	pr_debug("%s:session[%d]enable[%d]\n", __func__,