Merge "USB: msm72k_udc: Add proprietary charger detection support" into msm-3.4
diff --git a/Documentation/devicetree/bindings/crypto/msm/qcedev.txt b/Documentation/devicetree/bindings/crypto/msm/qcedev.txt
new file mode 100644
index 0000000..c50a6c3
--- /dev/null
+++ b/Documentation/devicetree/bindings/crypto/msm/qcedev.txt
@@ -0,0 +1,18 @@
+* QCEDEV (Qualcomm Crypto Engine Device)
+
+Required properties:
+  - compatible : should be "qcom,qcedev"
+  - reg : should contain crypto, BAM register map.
+  - interrupts : should contain crypto BAM interrupt.
+  - qcom,bam-pipe-pair : should contain crypto BAM pipe pair index.
+
+Example:
+
+        qcom,qcedev@fd440000 {
+		compatible = "qcom,qcedev";
+		reg = <0xfd440000 0x20000>,
+		      <0xfd444000 0x8000>;
+		reg-names = "crypto-base","crypto-bam-base";
+		interrupts = <0 235 0>;
+		qcom,bam-pipe-pair = <0>;
+	};
diff --git a/Documentation/devicetree/bindings/crypto/msm/qcrypto.txt b/Documentation/devicetree/bindings/crypto/msm/qcrypto.txt
new file mode 100644
index 0000000..1b0f703
--- /dev/null
+++ b/Documentation/devicetree/bindings/crypto/msm/qcrypto.txt
@@ -0,0 +1,18 @@
+* QCRYPTO (Qualcomm Crypto)
+
+Required properties:
+  - compatible : should be "qcom,qcrypto"
+  - reg : should contain crypto, BAM register map.
+  - interrupts : should contain crypto BAM interrupt.
+  - qcom,bam-pipe-pair : should contain crypto BAM pipe pair.
+
+Example:
+
+        qcom,qcrypto@fd444000 {
+		compatible = "qcom,qcrypto";
+		reg = <0xfd440000 0x20000>,
+		      <0xfd444000 0x8000>;
+		reg-names = "crypto-base","crypto-bam-base";
+		interrupts = <0 235 0>;
+		qcom,bam-pipe-pair = <1>;
+	};
diff --git a/Documentation/devicetree/bindings/iommu/msm_iommu.txt b/Documentation/devicetree/bindings/iommu/msm_iommu.txt
index 67933e7..c198fe9 100644
--- a/Documentation/devicetree/bindings/iommu/msm_iommu.txt
+++ b/Documentation/devicetree/bindings/iommu/msm_iommu.txt
@@ -13,12 +13,15 @@
   - qcom,iommu-ctx-sids : List of stream identifiers associated with this
     translation context.
   - qcom,iommu-ctx-name : Name of the context bank
+  - qcom,iommu-smt-size : Number of SMR entries in the SMT of this HW block
+  - vdd-supply : vdd-supply: phandle to GDSC regulator controlling this IOMMU.
 
 Example:
 
         qcom,iommu@fda64000 {
                 compatible = "qcom,msm-smmu-v2";
                 reg = <0xfda64000 0x10000>;
+		vdd-supply = <&gdsc_iommu>;
 
                 qcom,iommu-ctx@fda6c000 {
                         reg = <0xfda6c000 0x1000>;
diff --git a/Documentation/devicetree/bindings/rtc/qpnp-rtc.txt b/Documentation/devicetree/bindings/rtc/qpnp-rtc.txt
new file mode 100644
index 0000000..156141f
--- /dev/null
+++ b/Documentation/devicetree/bindings/rtc/qpnp-rtc.txt
@@ -0,0 +1,64 @@
+* msm-qpnp-rtc
+
+msm-qpnp-rtc is a RTC driver that supports 32 bit RTC housed inside PMIC.
+Driver utilizes MSM SPMI interface to communicate with the RTC module.
+RTC device is divided into two sub-peripherals one which controls basic RTC
+and other for controlling alarm.
+
+[PMIC RTC Device Declarations]
+
+-Root Node-
+
+Required properties :
+ - compatible:		Must be "qcom,qpnp-rtc"
+ - #address-cells:	The number of cells dedicated to represent an address
+			This must be set to '1'.
+ - #size-cells:		The number of cells dedicated to represent address
+			space range of a peripheral. This must be set to '1'.
+ - spmi-dev-container:	This specifies that all the device nodes specified
+			within this node should have their resources
+			coalesced into a single spmi_device.
+
+Optional properties:
+ - qcom,qpnp-rtc-write:		This property enables/disables rtc write
+				operation. If not mentioned rtc driver keeps
+				rtc writes disabled.
+				0 = Disable rtc writes.
+				1 = Enable rtc writes.
+ - qcom,qpnp-rtc-alarm-pwrup:	This property enables/disables feature of
+				powering up phone (from power down state)
+				through alarm interrupt.
+				If not mentioned rtc driver will disable
+				feature of powring-up phone through alarm.
+				0 = Disable powering up of phone through
+				alarm interrupt.
+				1 = Enable powering up of phone through
+				alarm interrupt.
+
+-Child Nodes-
+
+Required properties :
+ - reg :		Specify the spmi offset and size for device.
+ - interrupts:		Specifies alarm interrupt, only for rtc_alarm
+			sub-peripheral.
+
+Example:
+	qcom,pm8941_rtc {
+		spmi-dev-container;
+		compatible = "qcom,qpnp-rtc";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		qcom,qpnp-rtc-write = <0>;
+		qcom,qpnp-rtc-alarm-pwrup = <0>;
+
+		qcom,pm8941_rtc_rw@6000 {
+			reg = <0x6000 0x100>;
+		};
+
+		qcom,pm8941_rtc_alarm@6100 {
+			reg = <0x6100 0x100>;
+			interrupts = <0x0 0x61 0x1>;
+		};
+	};
+
+
diff --git a/Documentation/devicetree/bindings/thermal/tsens.txt b/Documentation/devicetree/bindings/thermal/tsens.txt
new file mode 100644
index 0000000..c683f58
--- /dev/null
+++ b/Documentation/devicetree/bindings/thermal/tsens.txt
@@ -0,0 +1,42 @@
+Qualcomm's TSENS driver
+
+The TSENS driver supports reading temperature from sensors across
+the MSM. The driver defaults to support a 10 bit ADC.
+
+The driver uses the Thermal sysfs framework to provide thermal
+clients the ability to enable/disable the sensors, read trip zones,
+read cool/warm temperature thresholds, set temperature thresholds
+for cool/warm notification and receive notification on temperature
+threshold events.
+
+TSENS node
+
+Required properties:
+- compatible : should be "qcom,msm-tsens" for MSM8974 TSENS driver.
+- reg : offset and length of the TSENS registers.
+- reg : offset and length of the QFPROM registers used for storing
+	the calibration data for the individual sensors.
+- reg-names : resource names used for the physical address of the TSENS
+	      registers and the QFPROM efuse calibration address.
+	      Should be "tsens_physical" for physical address of the TSENS
+	      and "tsens_eeprom_physical" for physical address where calibration
+	      data is stored.
+- interrupts : TSENS interrupt for cool/warm temperature threshold.
+- qcom,sensors : Total number of available Temperature sensors for TSENS.
+- qcom,slope : One point calibration characterized slope data for each
+	       sensor used to compute the offset. Slope is represented
+	       as ADC code/DegC and the value is multipled by a factor
+	       of 1000.
+
+Example:
+
+tsens@fc4a8000 {
+	compatible = "qcom,msm-tsens";
+	reg = <0xfc4a8000 0x2000>,
+	      <0xfc4b80d0 0x5>;
+	reg-names = "tsens_physical", "tsens_eeprom_physical";
+	interrupts = <0 184 0>;
+	qcom,sensors = <11>;
+	qcom,slope = <1134 1122 1142 1123 1176 1176 1176 1186 1176
+			1176>;
+};
diff --git a/arch/arm/boot/dts/msm8974-iommu.dtsi b/arch/arm/boot/dts/msm8974-iommu.dtsi
index e1a0a9b..a115fd8 100755
--- a/arch/arm/boot/dts/msm8974-iommu.dtsi
+++ b/arch/arm/boot/dts/msm8974-iommu.dtsi
@@ -18,6 +18,7 @@
 		ranges;
 		reg = <0xfda64000 0x10000>;
 		vdd-supply = <&gdsc_jpeg>;
+		qcom,iommu-smt-size = <16>;
 
 		qcom,iommu-ctx@fda6c000 {
 			reg = <0xfda6c000 0x1000>;
@@ -46,6 +47,7 @@
 		ranges;
 		reg = <0xfd928000 0x10000>;
 		vdd-supply = <&gdsc_mdss>;
+		qcom,iommu-smt-size = <16>;
 
 		qcom,iommu-ctx@fd930000 {
 			reg = <0xfd930000 0x1000>;
@@ -68,6 +70,7 @@
 		ranges;
 		reg = <0xfdc84000 0x10000>;
 		vdd-supply = <&gdsc_venus>;
+		qcom,iommu-smt-size = <16>;
 
 		qcom,iommu-ctx@fdc8c000 {
 			reg = <0xfdc8c000 0x1000>;
diff --git a/arch/arm/boot/dts/msm8974-rumi.dts b/arch/arm/boot/dts/msm8974-rumi.dts
index b179d94..2cf68b8 100644
--- a/arch/arm/boot/dts/msm8974-rumi.dts
+++ b/arch/arm/boot/dts/msm8974-rumi.dts
@@ -103,4 +103,8 @@
 	qcom,pronto@fb21b000 {
 		status = "disable";
 	};
+
+	qcom,mss@fc880000 {
+		status = "disable";
+	};
 };
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index 54f6863..1531a95 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -477,6 +477,17 @@
 		qcom,firmware-min-paddr = <0xF500000>;
 		qcom,firmware-max-paddr = <0xFA00000>;
 	};
+
+	tsens@fc4a8000 {
+		compatible = "qcom,msm-tsens";
+		reg = <0xfc4a8000 0x2000>,
+		      <0xfc4b80d0 0x5>;
+		reg-names = "tsens_physical", "tsens_eeprom_physical";
+		interrupts = <0 184 0>;
+		qcom,sensors = <11>;
+		qcom,slope = <1134 1122 1142 1123 1176 1176 1176 1186 1176
+				1176 1176>;
+	};
 };
 
 /include/ "msm-pm8x41-rpm-regulator.dtsi"
diff --git a/arch/arm/configs/msm7627a-perf_defconfig b/arch/arm/configs/msm7627a-perf_defconfig
index 913e084..c40d4d0 100644
--- a/arch/arm/configs/msm7627a-perf_defconfig
+++ b/arch/arm/configs/msm7627a-perf_defconfig
@@ -17,7 +17,6 @@
 CONFIG_KALLSYMS_ALL=y
 CONFIG_ASHMEM=y
 CONFIG_EMBEDDED=y
-CONFIG_SLAB=y
 CONFIG_PROFILING=y
 CONFIG_OPROFILE=y
 CONFIG_KPROBES=y
diff --git a/arch/arm/configs/msm7627a_defconfig b/arch/arm/configs/msm7627a_defconfig
index 8cd091c..838933c 100644
--- a/arch/arm/configs/msm7627a_defconfig
+++ b/arch/arm/configs/msm7627a_defconfig
@@ -17,7 +17,6 @@
 CONFIG_KALLSYMS_ALL=y
 CONFIG_ASHMEM=y
 CONFIG_EMBEDDED=y
-CONFIG_SLAB=y
 CONFIG_PROFILING=y
 CONFIG_OPROFILE=y
 CONFIG_KPROBES=y
@@ -340,8 +339,6 @@
 CONFIG_LOCKUP_DETECTOR=y
 # CONFIG_SCHED_DEBUG is not set
 CONFIG_TIMER_STATS=y
-CONFIG_DEBUG_SLAB=y
-CONFIG_DEBUG_SLAB_LEAK=y
 CONFIG_DEBUG_SPINLOCK=y
 CONFIG_DEBUG_MUTEXES=y
 CONFIG_DEBUG_ATOMIC_SLEEP=y
diff --git a/arch/arm/configs/msm8960_defconfig b/arch/arm/configs/msm8960_defconfig
index 9eea6f6..3da628f 100644
--- a/arch/arm/configs/msm8960_defconfig
+++ b/arch/arm/configs/msm8960_defconfig
@@ -341,6 +341,7 @@
 # CONFIG_MEDIA_TUNER_CUSTOMISE is not set
 CONFIG_VIDEOBUF2_MSM_MEM=y
 CONFIG_VIDEO_HELPER_CHIPS_AUTO=y
+CONFIG_USB_VIDEO_CLASS=y
 CONFIG_V4L_PLATFORM_DRIVERS=y
 CONFIG_MSM_CAMERA_V4L2=y
 CONFIG_IMX074=y
diff --git a/arch/arm/configs/msm8974_defconfig b/arch/arm/configs/msm8974_defconfig
index 9bd967b..bdfb50b 100644
--- a/arch/arm/configs/msm8974_defconfig
+++ b/arch/arm/configs/msm8974_defconfig
@@ -168,7 +168,6 @@
 # CONFIG_LCD_CLASS_DEVICE is not set
 CONFIG_BACKLIGHT_CLASS_DEVICE=y
 # CONFIG_BACKLIGHT_GENERIC is not set
-# CONFIG_HID_SUPPORT is not set
 CONFIG_USB=y
 CONFIG_USB_XHCI_HCD=y
 CONFIG_USB_STORAGE=y
@@ -251,3 +250,7 @@
 CONFIG_SND=y
 CONFIG_SND_SOC=y
 CONFIG_SND_SOC_MSM8974=y
+CONFIG_CRYPTO_DEV_QCRYPTO=m
+CONFIG_CRYPTO_DEV_QCE=m
+CONFIG_CRYPTO_DEV_QCEDEV=m
+
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index 702667b..7ccdd0f 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -27,6 +27,7 @@
 obj-$(CONFIG_ARCH_MSM_SCORPION) += pmu.o
 obj-$(CONFIG_ARCH_MSM_SCORPIONMP) += perf_event_msm_l2.o
 obj-$(CONFIG_ARCH_MSM_KRAIT) += msm-krait-l2-accessors.o pmu.o perf_event_msm_krait_l2.o
+obj-$(CONFIG_ARCH_MSM_KRAIT) += krait-scm.o
 obj-$(CONFIG_ARCH_MSM7X27A) += pmu.o
 
 ifndef CONFIG_MSM_SMP
diff --git a/arch/arm/mach-msm/acpuclock-8974.c b/arch/arm/mach-msm/acpuclock-8974.c
index c67109e..8cf9c2b 100644
--- a/arch/arm/mach-msm/acpuclock-8974.c
+++ b/arch/arm/mach-msm/acpuclock-8974.c
@@ -123,8 +123,8 @@
 
 #define L2(x) (&l2_freq_tbl[(x)])
 static struct l2_level l2_freq_tbl[] = {
-	[0]  = { {STBY_KHZ, QSB,   0, 0,   0 }, LVL_NOM, 1050000, 0 },
-	[1]  = { {  300000, PLL_0, 0, 2,   0 }, LVL_NOM, 1050000, 2 },
+	[0]  = { {STBY_KHZ, QSB,   0, 0,   0 }, LVL_LOW, 1050000, 0 },
+	[1]  = { {  300000, PLL_0, 0, 2,   0 }, LVL_LOW, 1050000, 2 },
 	[2]  = { {  384000, HFPLL, 2, 0,  40 }, LVL_NOM, 1050000, 2 },
 	[3]  = { {  460800, HFPLL, 2, 0,  48 }, LVL_NOM, 1050000, 2 },
 	[4]  = { {  537600, HFPLL, 1, 0,  28 }, LVL_NOM, 1050000, 2 },
diff --git a/arch/arm/mach-msm/board-8064-gpu.c b/arch/arm/mach-msm/board-8064-gpu.c
index 0f9c939..eb36a81e 100644
--- a/arch/arm/mach-msm/board-8064-gpu.c
+++ b/arch/arm/mach-msm/board-8064-gpu.c
@@ -13,10 +13,11 @@
 
 #include <linux/init.h>
 #include <linux/platform_device.h>
-#include <linux/msm_kgsl.h>
+#include <mach/kgsl.h>
 #include <mach/msm_bus_board.h>
 #include <mach/board.h>
 #include <mach/msm_dcvs.h>
+#include <mach/socinfo.h>
 
 #include "devices.h"
 #include "board-8064.h"
@@ -247,5 +248,13 @@
 
 void __init apq8064_init_gpu(void)
 {
+	unsigned int version = socinfo_get_version();
+
+	if ((SOCINFO_VERSION_MAJOR(version) == 1) &&
+		(SOCINFO_VERSION_MINOR(version) == 1))
+		kgsl_3d0_pdata.chipid = ADRENO_CHIPID(3, 2, 0, 1);
+	else
+		kgsl_3d0_pdata.chipid = ADRENO_CHIPID(3, 2, 0, 0);
+
 	platform_device_register(&device_kgsl_3d0);
 }
diff --git a/arch/arm/mach-msm/board-8930-gpu.c b/arch/arm/mach-msm/board-8930-gpu.c
index 066c134..105a5aa 100644
--- a/arch/arm/mach-msm/board-8930-gpu.c
+++ b/arch/arm/mach-msm/board-8930-gpu.c
@@ -13,7 +13,7 @@
 
 #include <linux/init.h>
 #include <linux/platform_device.h>
-#include <linux/msm_kgsl.h>
+#include <mach/kgsl.h>
 #include <mach/msm_bus_board.h>
 #include <mach/board.h>
 #include <mach/socinfo.h>
@@ -160,8 +160,16 @@
 
 void __init msm8930_init_gpu(void)
 {
+	unsigned int version = socinfo_get_version();
+
 	if (cpu_is_msm8627())
 		kgsl_3d0_pdata.pwrlevel[0].gpu_freq = 400000000;
 
+	if ((SOCINFO_VERSION_MAJOR(version) == 1) &&
+		(SOCINFO_VERSION_MINOR(version) == 2))
+		kgsl_3d0_pdata.chipid = ADRENO_CHIPID(3, 0, 5, 2);
+	else
+		kgsl_3d0_pdata.chipid = ADRENO_CHIPID(3, 0, 5, 0);
+
 	platform_device_register(&device_kgsl_3d0);
 }
diff --git a/arch/arm/mach-msm/board-8930.c b/arch/arm/mach-msm/board-8930.c
index e695241..ec218ac 100644
--- a/arch/arm/mach-msm/board-8930.c
+++ b/arch/arm/mach-msm/board-8930.c
@@ -26,7 +26,6 @@
 #include <linux/spi/spi.h>
 #include <linux/slimbus/slimbus.h>
 #include <linux/bootmem.h>
-#include <linux/msm_kgsl.h>
 #ifdef CONFIG_ANDROID_PMEM
 #include <linux/android_pmem.h>
 #endif
@@ -80,6 +79,7 @@
 #include <linux/fmem.h>
 #include <mach/msm_cache_dump.h>
 
+#include <mach/kgsl.h>
 #ifdef CONFIG_INPUT_MPU3050
 #include <linux/input/mpu3050.h>
 #endif
diff --git a/arch/arm/mach-msm/board-8960.c b/arch/arm/mach-msm/board-8960.c
index 755965c..bb20d04 100644
--- a/arch/arm/mach-msm/board-8960.c
+++ b/arch/arm/mach-msm/board-8960.c
@@ -26,7 +26,6 @@
 #include <linux/spi/spi.h>
 #include <linux/slimbus/slimbus.h>
 #include <linux/bootmem.h>
-#include <linux/msm_kgsl.h>
 #ifdef CONFIG_ANDROID_PMEM
 #include <linux/android_pmem.h>
 #endif
@@ -87,6 +86,7 @@
 #include <mach/scm.h>
 #include <mach/iommu_domains.h>
 
+#include <mach/kgsl.h>
 #include <linux/fmem.h>
 
 #include "timer.h"
@@ -2467,7 +2467,6 @@
 	&msm8960_device_dmov,
 	&msm_device_smd,
 	&msm_device_uart_dm6,
-	&msm_device_uart_dm9,
 	&msm_device_saw_core0,
 	&msm_device_saw_core1,
 	&msm8960_device_ext_5v_vreg,
@@ -2687,13 +2686,26 @@
 
 static void __init msm8960_gfx_init(void)
 {
+	struct kgsl_device_platform_data *kgsl_3d0_pdata =
+		msm_kgsl_3d0.dev.platform_data;
 	uint32_t soc_platform_version = socinfo_get_version();
+
 	if (SOCINFO_VERSION_MAJOR(soc_platform_version) == 1) {
-		struct kgsl_device_platform_data *kgsl_3d0_pdata =
-				msm_kgsl_3d0.dev.platform_data;
 		kgsl_3d0_pdata->pwrlevel[0].gpu_freq = 320000000;
 		kgsl_3d0_pdata->pwrlevel[1].gpu_freq = 266667000;
 	}
+	if (cpu_is_msm8960ab()) {
+		kgsl_3d0_pdata->chipid = ADRENO_CHIPID(3, 2, 1, 0);
+	} else {
+
+		/* 8960v3 GPU registers returns 5 for patch release
+		 * but it should be 6, so dummy up the chipid here
+		 * based the platform type
+		 */
+
+		if (SOCINFO_VERSION_MAJOR(soc_platform_version) >= 3)
+			kgsl_3d0_pdata->chipid = ADRENO_CHIPID(2, 2, 0, 6);
+	}
 }
 
 static struct msm_rpmrs_level msm_rpmrs_levels[] = {
@@ -3124,6 +3136,7 @@
 	if (socinfo_get_platform_subtype() == PLATFORM_SUBTYPE_SGLTE) {
 		msm_uart_dm9_pdata.wakeup_irq = gpio_to_irq(94); /* GSBI9(2) */
 		msm_device_uart_dm9.dev.platform_data = &msm_uart_dm9_pdata;
+		platform_device_register(&msm_device_uart_dm9);
 	}
 
 	platform_add_devices(common_devices, ARRAY_SIZE(common_devices));
diff --git a/arch/arm/mach-msm/board-8974.c b/arch/arm/mach-msm/board-8974.c
index 557331a..8cbde5f 100644
--- a/arch/arm/mach-msm/board-8974.c
+++ b/arch/arm/mach-msm/board-8974.c
@@ -640,6 +640,8 @@
 	OF_DEV_AUXDATA("qcom,qseecom", 0xFE806000, \
 			"qseecom", NULL),
 	OF_DEV_AUXDATA("qcom,mdss_mdp", 0xFD900000, "mdp.0", NULL),
+	OF_DEV_AUXDATA("qcom,msm-tsens", 0xFC4A8000, \
+			"msm-tsens", NULL),
 	{}
 };
 
diff --git a/arch/arm/mach-msm/board-qrd7627a.c b/arch/arm/mach-msm/board-qrd7627a.c
index 5b9ea36..8182fc4 100644
--- a/arch/arm/mach-msm/board-qrd7627a.c
+++ b/arch/arm/mach-msm/board-qrd7627a.c
@@ -144,6 +144,7 @@
 
 static struct android_usb_platform_data android_usb_pdata = {
 	.update_pid_and_serial_num = usb_diag_update_pid_and_serial_num,
+	.cdrom = 1,
 };
 
 static struct platform_device android_usb_device = {
diff --git a/arch/arm/mach-msm/board-swordfish.c b/arch/arm/mach-msm/board-swordfish.c
index 45d5bb0..7262277 100644
--- a/arch/arm/mach-msm/board-swordfish.c
+++ b/arch/arm/mach-msm/board-swordfish.c
@@ -21,7 +21,7 @@
 #include <linux/delay.h>
 #include <linux/fs.h>
 #include <linux/android_pmem.h>
-#include <linux/msm_kgsl.h>
+#include <mach/kgsl.h>
 
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
diff --git a/arch/arm/mach-msm/clock-8960.c b/arch/arm/mach-msm/clock-8960.c
index f99e5de8..2a4566e 100644
--- a/arch/arm/mach-msm/clock-8960.c
+++ b/arch/arm/mach-msm/clock-8960.c
@@ -5109,7 +5109,10 @@
 	CLK_LOOKUP("core_clk",		sdc2_clk.c,		"msm_sdcc.2"),
 	CLK_LOOKUP("core_clk",		sdc3_clk.c,		"msm_sdcc.3"),
 	CLK_LOOKUP("core_clk",		sdc4_clk.c,		"msm_sdcc.4"),
-	CLK_LOOKUP("ref_clk",		tsif_ref_clk.c,		""),
+	CLK_LOOKUP("ref_clk",		tsif_ref_clk.c,		"msm_tsif.0"),
+	CLK_LOOKUP("iface_clk",		tsif_p_clk.c,		"msm_tsif.0"),
+	CLK_LOOKUP("ref_clk",		tsif_ref_clk.c,		"msm_tsif.1"),
+	CLK_LOOKUP("iface_clk",		tsif_p_clk.c,		"msm_tsif.1"),
 	CLK_LOOKUP("core_clk",		tssc_clk.c,		""),
 	CLK_LOOKUP("alt_core_clk",	usb_hs1_xcvr_clk.c,	"msm_otg"),
 	CLK_LOOKUP("alt_core_clk",      usb_hs3_xcvr_clk.c,  "msm_ehci_host.0"),
diff --git a/arch/arm/mach-msm/clock-8974.c b/arch/arm/mach-msm/clock-8974.c
index 6c9a566..930de81 100644
--- a/arch/arm/mach-msm/clock-8974.c
+++ b/arch/arm/mach-msm/clock-8974.c
@@ -593,10 +593,12 @@
 #define RPM_MEM_CLK_TYPE  0x326b6c63
 
 #define CXO_ID		0x0
+#define QDSS_ID		0x1
 
 #define PNOC_ID		0x0
 #define SNOC_ID		0x1
 #define CNOC_ID		0x2
+#define MMSSNOC_AHB_ID  0x4
 
 #define BIMC_ID		0x0
 #define OCMEM_ID	0x1
@@ -604,6 +606,8 @@
 DEFINE_CLK_RPM_SMD(pnoc_clk, pnoc_a_clk, RPM_BUS_CLK_TYPE, PNOC_ID, NULL);
 DEFINE_CLK_RPM_SMD(snoc_clk, snoc_a_clk, RPM_BUS_CLK_TYPE, SNOC_ID, NULL);
 DEFINE_CLK_RPM_SMD(cnoc_clk, cnoc_a_clk, RPM_BUS_CLK_TYPE, CNOC_ID, NULL);
+DEFINE_CLK_RPM_SMD(mmssnoc_ahb_clk, mmssnoc_ahb_a_clk, RPM_BUS_CLK_TYPE,
+			MMSSNOC_AHB_ID, NULL);
 
 DEFINE_CLK_RPM_SMD(bimc_clk, bimc_a_clk, RPM_MEM_CLK_TYPE, BIMC_ID, NULL);
 DEFINE_CLK_RPM_SMD(ocmemgx_clk, ocmemgx_a_clk, RPM_MEM_CLK_TYPE, OCMEM_ID,
@@ -611,6 +615,7 @@
 
 DEFINE_CLK_RPM_SMD_BRANCH(cxo_clk_src, cxo_a_clk_src,
 				RPM_MISC_CLK_TYPE, CXO_ID, 19200000);
+DEFINE_CLK_RPM_SMD_QDSS(qdss_clk, qdss_a_clk, RPM_MISC_CLK_TYPE, QDSS_ID);
 
 static struct pll_vote_clk gpll0_clk_src = {
 	.en_reg = (void __iomem *)APCS_GPLL_ENA_VOTE_REG,
@@ -4830,6 +4835,36 @@
 	CLK_LOOKUP("bus_a_clk",	ocmemnoc_clk.c,		"msm_ocmem_noc"),
 	CLK_LOOKUP("bus_clk",	mmss_mmssnoc_axi_clk.c,	"msm_mmss_noc"),
 	CLK_LOOKUP("bus_a_clk",	mmss_mmssnoc_axi_clk.c,	"msm_mmss_noc"),
+
+	CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-tmc-etr"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-tpiu"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-replicator"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-tmc-etf"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-funnel-merg"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-funnel-in0"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-funnel-in1"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-funnel-kpss"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-funnel-mmss"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-stm"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-etm0"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-etm1"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-etm2"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-etm3"),
+
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-tmc-etr"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-tpiu"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-replicator"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-tmc-etf"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-funnel-merg"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-funnel-in0"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-funnel-in1"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-funnel-kpss"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-funnel-mmss"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-stm"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-etm0"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-etm1"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-etm2"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-etm3"),
 };
 
 static struct pll_config_regs gpll0_regs __initdata = {
@@ -5028,6 +5063,13 @@
 	clk_set_rate(&ocmemnoc_clk_src.c, 333330000);
 
 	/*
+	 * Hold an active set vote at a rate of 40MHz for the MMSS NOC AHB
+	 * source. Sleep set vote is 0.
+	 */
+	clk_set_rate(&mmssnoc_ahb_a_clk.c, 40000000);
+	clk_prepare_enable(&mmssnoc_ahb_a_clk.c);
+
+	/*
 	 * Hold an active set vote for CXO; this is because CXO is expected
 	 * to remain on whenever CPUs aren't power collapsed.
 	 */
diff --git a/arch/arm/mach-msm/clock-8x60.c b/arch/arm/mach-msm/clock-8x60.c
index 4493ddc..1769f07 100644
--- a/arch/arm/mach-msm/clock-8x60.c
+++ b/arch/arm/mach-msm/clock-8x60.c
@@ -3522,6 +3522,7 @@
 	CLK_LOOKUP("mem_a_clk",		ebi1_msmbus_a_clk.c, "msm_bus"),
 	CLK_LOOKUP("smi_clk",		smi_clk.c,	"msm_bus"),
 	CLK_LOOKUP("smi_a_clk",		smi_a_clk.c,	"msm_bus"),
+	CLK_LOOKUP("mmfpb_a_clk",	mmfpb_a_clk.c,	"clock-8x60"),
 
 	CLK_LOOKUP("core_clk",		gp0_clk.c,		""),
 	CLK_LOOKUP("core_clk",		gp1_clk.c,		""),
@@ -3873,7 +3874,7 @@
 	int rc;
 
 	/* Vote for MMFPB to be at least 64MHz when an Apps CPU is active. */
-	struct clk *mmfpb_a_clk = clk_get(NULL, "mmfpb_a_clk");
+	struct clk *mmfpb_a_clk = clk_get_sys("clock-8x60", "mmfpb_a_clk");
 	if (WARN(IS_ERR(mmfpb_a_clk), "mmfpb_a_clk not found (%ld)\n",
 			PTR_ERR(mmfpb_a_clk)))
 		return PTR_ERR(mmfpb_a_clk);
diff --git a/arch/arm/mach-msm/clock-rpm.c b/arch/arm/mach-msm/clock-rpm.c
index 8096c10..207dbef 100644
--- a/arch/arm/mach-msm/clock-rpm.c
+++ b/arch/arm/mach-msm/clock-rpm.c
@@ -54,15 +54,11 @@
 	return (rc < 0) ? rc : iv.value * r->factor;
 }
 
-#define RPM_SMD_KEY_RATE	0x007A484B
-#define RPM_SMD_KEY_ENABLE	0x62616E45
-
 static int clk_rpmrs_set_rate_smd(struct rpm_clk *r, uint32_t value,
 				uint32_t context, int noirq)
 {
-	u32 rpm_key = r->branch ? RPM_SMD_KEY_ENABLE : RPM_SMD_KEY_RATE;
 	struct msm_rpm_kvp kvp = {
-		.key = rpm_key,
+		.key = r->rpm_key,
 		.data = (void *)&value,
 		.length = sizeof(value),
 	};
diff --git a/arch/arm/mach-msm/clock-rpm.h b/arch/arm/mach-msm/clock-rpm.h
index ce878ce..22691c5 100644
--- a/arch/arm/mach-msm/clock-rpm.h
+++ b/arch/arm/mach-msm/clock-rpm.h
@@ -17,6 +17,10 @@
 #include <mach/rpm.h>
 #include <mach/rpm-smd.h>
 
+#define RPM_SMD_KEY_RATE	0x007A484B
+#define RPM_SMD_KEY_ENABLE	0x62616E45
+#define RPM_SMD_KEY_STATE	0x54415453
+
 struct clk_ops;
 struct clk_rpmrs_data;
 extern struct clk_ops clk_ops_rpm;
@@ -24,6 +28,7 @@
 
 struct rpm_clk {
 	const int rpm_res_type;
+	const int rpm_key;
 	const int rpm_clk_id;
 	const int rpm_status_id;
 	const bool active_only;
@@ -47,12 +52,14 @@
 extern struct clk_rpmrs_data clk_rpmrs_data;
 extern struct clk_rpmrs_data clk_rpmrs_data_smd;
 
-#define __DEFINE_CLK_RPM(name, active, type, r_id, stat_id, dep, rpmrsdata) \
+#define __DEFINE_CLK_RPM(name, active, type, r_id, stat_id, dep, key, \
+				rpmrsdata) \
 	static struct rpm_clk active; \
 	static struct rpm_clk name = { \
 		.rpm_res_type = (type), \
 		.rpm_clk_id = (r_id), \
 		.rpm_status_id = (stat_id), \
+		.rpm_key = (key), \
 		.peer = &active, \
 		.factor = 1000, \
 		.rpmrs_data = (rpmrsdata),\
@@ -67,6 +74,7 @@
 		.rpm_res_type = (type), \
 		.rpm_clk_id = (r_id), \
 		.rpm_status_id = (stat_id), \
+		.rpm_key = (key), \
 		.peer = &name, \
 		.active_only = true, \
 		.factor = 1000, \
@@ -80,12 +88,13 @@
 	};
 
 #define __DEFINE_CLK_RPM_BRANCH(name, active, type, r_id, stat_id, r, \
-					rpmrsdata) \
+					key, rpmrsdata) \
 	static struct rpm_clk active; \
 	static struct rpm_clk name = { \
 		.rpm_res_type = (type), \
 		.rpm_clk_id = (r_id), \
 		.rpm_status_id = (stat_id), \
+		.rpm_key = (key), \
 		.peer = &active, \
 		.last_set_khz = ((r) / 1000), \
 		.last_set_sleep_khz = ((r) / 1000), \
@@ -104,6 +113,7 @@
 		.rpm_res_type = (type), \
 		.rpm_clk_id = (r_id), \
 		.rpm_status_id = (stat_id), \
+		.rpm_key = (key), \
 		.peer = &name, \
 		.last_set_khz = ((r) / 1000), \
 		.active_only = true, \
@@ -119,12 +129,14 @@
 		}, \
 	};
 
-#define __DEFINE_CLK_RPM_QDSS(name, active, type, r_id, stat_id, rpmrsdata) \
+#define __DEFINE_CLK_RPM_QDSS(name, active, type, r_id, stat_id, \
+				key, rpmrsdata) \
 	static struct rpm_clk active; \
 	static struct rpm_clk name = { \
 		.rpm_res_type = (type), \
 		.rpm_clk_id = (r_id), \
 		.rpm_status_id = (stat_id), \
+		.rpm_key = (key), \
 		.peer = &active, \
 		.factor = 1, \
 		.rpmrs_data = (rpmrsdata),\
@@ -139,6 +151,7 @@
 		.rpm_res_type = (type), \
 		.rpm_clk_id = (r_id), \
 		.rpm_status_id = (stat_id), \
+		.rpm_key = (key), \
 		.peer = &name, \
 		.active_only = true, \
 		.factor = 1, \
@@ -153,21 +166,26 @@
 
 #define DEFINE_CLK_RPM(name, active, r_id, dep) \
 	__DEFINE_CLK_RPM(name, active, 0, MSM_RPM_ID_##r_id##_CLK, \
-		MSM_RPM_STATUS_ID_##r_id##_CLK, dep, &clk_rpmrs_data)
+		MSM_RPM_STATUS_ID_##r_id##_CLK, dep, 0, &clk_rpmrs_data)
 
 #define DEFINE_CLK_RPM_QDSS(name, active) \
 	__DEFINE_CLK_RPM_QDSS(name, active, 0, MSM_RPM_ID_QDSS_CLK, \
-		MSM_RPM_STATUS_ID_QDSS_CLK, &clk_rpmrs_data)
+		MSM_RPM_STATUS_ID_QDSS_CLK, 0, &clk_rpmrs_data)
 
 #define DEFINE_CLK_RPM_BRANCH(name, active, r_id, r) \
 	__DEFINE_CLK_RPM_BRANCH(name, active, 0, MSM_RPM_ID_##r_id##_CLK, \
-			MSM_RPM_STATUS_ID_##r_id##_CLK, r, &clk_rpmrs_data)
+			MSM_RPM_STATUS_ID_##r_id##_CLK, r, 0, &clk_rpmrs_data)
 
 #define DEFINE_CLK_RPM_SMD(name, active, type, r_id, dep) \
-	__DEFINE_CLK_RPM(name, active, type, r_id, 0, dep, &clk_rpmrs_data_smd)
+	__DEFINE_CLK_RPM(name, active, type, r_id, 0, dep, \
+				RPM_SMD_KEY_RATE, &clk_rpmrs_data_smd)
 
-#define DEFINE_CLK_RPM_SMD_BRANCH(name, active, type, r_id, dep) \
-	__DEFINE_CLK_RPM_BRANCH(name, active, type, r_id, 0, dep, \
-					&clk_rpmrs_data_smd)
+#define DEFINE_CLK_RPM_SMD_BRANCH(name, active, type, r_id, r) \
+	__DEFINE_CLK_RPM_BRANCH(name, active, type, r_id, 0, r, \
+				RPM_SMD_KEY_ENABLE, &clk_rpmrs_data_smd)
+
+#define DEFINE_CLK_RPM_SMD_QDSS(name, active, type, r_id) \
+	__DEFINE_CLK_RPM_QDSS(name, active, type, r_id, \
+		0, RPM_SMD_KEY_STATE, &clk_rpmrs_data_smd)
 
 #endif
diff --git a/arch/arm/mach-msm/devices-8960.c b/arch/arm/mach-msm/devices-8960.c
index 7d93fe7..79f8c88 100644
--- a/arch/arm/mach-msm/devices-8960.c
+++ b/arch/arm/mach-msm/devices-8960.c
@@ -19,7 +19,7 @@
 #include <linux/gpio.h>
 #include <linux/coresight.h>
 #include <asm/clkdev.h>
-#include <linux/msm_kgsl.h>
+#include <mach/kgsl.h>
 #include <linux/android_pmem.h>
 #include <mach/irqs-8960.h>
 #include <mach/dma.h>
diff --git a/arch/arm/mach-msm/devices-msm7x27.c b/arch/arm/mach-msm/devices-msm7x27.c
index 4619cca..69d7430 100644
--- a/arch/arm/mach-msm/devices-msm7x27.c
+++ b/arch/arm/mach-msm/devices-msm7x27.c
@@ -15,7 +15,7 @@
 
 #include <linux/kernel.h>
 #include <linux/platform_device.h>
-#include <linux/msm_kgsl.h>
+#include <mach/kgsl.h>
 #include <linux/regulator/machine.h>
 #include <linux/dma-mapping.h>
 #include <linux/init.h>
diff --git a/arch/arm/mach-msm/devices-msm7x27a.c b/arch/arm/mach-msm/devices-msm7x27a.c
index c159926..8912e96 100644
--- a/arch/arm/mach-msm/devices-msm7x27a.c
+++ b/arch/arm/mach-msm/devices-msm7x27a.c
@@ -13,7 +13,7 @@
 #include <linux/kernel.h>
 #include <linux/platform_device.h>
 #include <linux/dma-mapping.h>
-#include <linux/msm_kgsl.h>
+#include <mach/kgsl.h>
 #include <linux/regulator/machine.h>
 #include <linux/init.h>
 #include <linux/irq.h>
diff --git a/arch/arm/mach-msm/devices-msm7x30.c b/arch/arm/mach-msm/devices-msm7x30.c
index 4b02f7a..f04ef9d 100644
--- a/arch/arm/mach-msm/devices-msm7x30.c
+++ b/arch/arm/mach-msm/devices-msm7x30.c
@@ -17,7 +17,7 @@
 #include <linux/platform_device.h>
 #include <linux/msm_rotator.h>
 #include <linux/dma-mapping.h>
-#include <linux/msm_kgsl.h>
+#include <mach/kgsl.h>
 #include <linux/android_pmem.h>
 #include <linux/regulator/machine.h>
 #include <linux/init.h>
diff --git a/arch/arm/mach-msm/devices-msm8x60.c b/arch/arm/mach-msm/devices-msm8x60.c
index 2ced412..3920abe 100644
--- a/arch/arm/mach-msm/devices-msm8x60.c
+++ b/arch/arm/mach-msm/devices-msm8x60.c
@@ -20,7 +20,7 @@
 #include <mach/dma.h>
 #include <asm/mach/mmc.h>
 #include <asm/clkdev.h>
-#include <linux/msm_kgsl.h>
+#include <mach/kgsl.h>
 #include <linux/msm_rotator.h>
 #include <mach/msm_hsusb.h>
 #include "footswitch.h"
diff --git a/arch/arm/mach-msm/devices-qsd8x50.c b/arch/arm/mach-msm/devices-qsd8x50.c
index 2ecc852..ec4a14f 100644
--- a/arch/arm/mach-msm/devices-qsd8x50.c
+++ b/arch/arm/mach-msm/devices-qsd8x50.c
@@ -15,7 +15,7 @@
 
 #include <linux/kernel.h>
 #include <linux/platform_device.h>
-#include <linux/msm_kgsl.h>
+#include <mach/kgsl.h>
 
 #include <linux/dma-mapping.h>
 #include <asm/clkdev.h>
diff --git a/arch/arm/mach-msm/dma.c b/arch/arm/mach-msm/dma.c
index e5dca00..12f5aa9 100644
--- a/arch/arm/mach-msm/dma.c
+++ b/arch/arm/mach-msm/dma.c
@@ -356,7 +356,7 @@
 	}
 	if (!dmov_conf[adm].channel_active) {
 		dmov_conf[adm].clk_ctl = CLK_TO_BE_DIS;
-		schedule_delayed_work(&dmov_conf[adm].work, HZ);
+		schedule_delayed_work(&dmov_conf[adm].work, (HZ/10));
 	}
 	spin_unlock_irqrestore(&dmov_conf[adm].list_lock, flags);
 error:
@@ -573,7 +573,7 @@
 	if (!dmov_conf[adm].channel_active && valid) {
 		disable_irq_nosync(dmov_conf[adm].irq);
 		dmov_conf[adm].clk_ctl = CLK_TO_BE_DIS;
-		schedule_delayed_work(&dmov_conf[adm].work, HZ);
+		schedule_delayed_work(&dmov_conf[adm].work, (HZ/10));
 	}
 
 	mutex_unlock(&dmov_conf[adm].lock);
diff --git a/arch/arm/mach-msm/gss-8064.c b/arch/arm/mach-msm/gss-8064.c
index b9b877a..e528650 100644
--- a/arch/arm/mach-msm/gss-8064.c
+++ b/arch/arm/mach-msm/gss-8064.c
@@ -43,6 +43,8 @@
 
 static int crash_shutdown;
 
+static struct subsys_device *gss_8064_dev;
+
 #define MAX_SSR_REASON_LEN 81U
 
 static void log_gss_sfr(void)
@@ -72,7 +74,7 @@
 static void restart_gss(void)
 {
 	log_gss_sfr();
-	subsystem_restart("gss");
+	subsystem_restart_dev(gss_8064_dev);
 }
 
 static void smsm_state_cb(void *data, uint32_t old_state, uint32_t new_state)
@@ -91,7 +93,7 @@
 
 #define Q6_FW_WDOG_ENABLE		0x08882024
 #define Q6_SW_WDOG_ENABLE		0x08982024
-static int gss_shutdown(const struct subsys_data *subsys)
+static int gss_shutdown(const struct subsys_desc *desc)
 {
 	pil_force_shutdown("gss");
 	disable_irq_nosync(GSS_A5_WDOG_EXPIRED);
@@ -99,14 +101,14 @@
 	return 0;
 }
 
-static int gss_powerup(const struct subsys_data *subsys)
+static int gss_powerup(const struct subsys_desc *desc)
 {
 	pil_force_boot("gss");
 	enable_irq(GSS_A5_WDOG_EXPIRED);
 	return 0;
 }
 
-void gss_crash_shutdown(const struct subsys_data *subsys)
+void gss_crash_shutdown(const struct subsys_desc *desc)
 {
 	crash_shutdown = 1;
 	smsm_reset_modem(SMSM_RESET);
@@ -122,7 +124,7 @@
 };
 
 static int gss_ramdump(int enable,
-				const struct subsys_data *crashed_subsys)
+				const struct subsys_desc *crashed_subsys)
 {
 	int ret = 0;
 
@@ -157,7 +159,7 @@
 	return IRQ_HANDLED;
 }
 
-static struct subsys_data gss_8064 = {
+static struct subsys_desc gss_8064 = {
 	.name = "gss",
 	.shutdown = gss_shutdown,
 	.powerup = gss_powerup,
@@ -167,7 +169,10 @@
 
 static int gss_subsystem_restart_init(void)
 {
-	return ssr_register_subsystem(&gss_8064);
+	gss_8064_dev = subsys_register(&gss_8064);
+	if (IS_ERR(gss_8064_dev))
+		return PTR_ERR(gss_8064_dev);
+	return 0;
 }
 
 static int gss_open(struct inode *inode, struct file *filep)
diff --git a/arch/arm/mach-msm/include/mach/dma.h b/arch/arm/mach-msm/include/mach/dma.h
index ba621e6..381ea12 100644
--- a/arch/arm/mach-msm/include/mach/dma.h
+++ b/arch/arm/mach-msm/include/mach/dma.h
@@ -263,6 +263,9 @@
 #define DMOV8064_CE_OUT_CHAN       1
 #define DMOV8064_CE_OUT_CRCI       15
 
+#define DMOV8064_TSIF_CHAN         2
+#define DMOV8064_TSIF_CRCI         1
+
 
 /* no client rate control ifc (eg, ram) */
 #define DMOV_NONE_CRCI        0
diff --git a/arch/arm/mach-msm/include/mach/iommu.h b/arch/arm/mach-msm/include/mach/iommu.h
index 4bfbe61..28c53db 100644
--- a/arch/arm/mach-msm/include/mach/iommu.h
+++ b/arch/arm/mach-msm/include/mach/iommu.h
@@ -35,6 +35,9 @@
  */
 #define MAX_NUM_MIDS	32
 
+/* Maximum number of SMT entries allowed by the system */
+#define MAX_NUM_SMR	128
+
 /**
  * struct msm_iommu_dev - a single IOMMU hardware instance
  * name		Human-readable name given to this IOMMU HW instance
@@ -69,6 +72,9 @@
  * @irq:	Interrupt number
  * @clk:	The bus clock for this IOMMU hardware instance
  * @pclk:	The clock for the IOMMU bus interconnect
+ * @name:	Human-readable name of this IOMMU device
+ * @gdsc:	Regulator needed to power this HW block (v2 only)
+ * @nsmr:	Size of the SMT on this HW block (v2 only)
  *
  * A msm_iommu_drvdata holds the global driver data about a single piece
  * of an IOMMU hardware instance.
@@ -81,6 +87,7 @@
 	struct clk *pclk;
 	const char *name;
 	struct regulator *gdsc;
+	unsigned int nsmr;
 };
 
 /**
@@ -89,6 +96,10 @@
  * @pdev:		Platform device associated wit this HW instance
  * @attached_elm:	List element for domains to track which devices are
  *			attached to them
+ * @attached_domain	Domain currently attached to this context (if any)
+ * @name		Human-readable name of this context device
+ * @sids		List of Stream IDs mapped to this context (v2 only)
+ * @nsid		Number of Stream IDs mapped to this context (v2 only)
  *
  * A msm_iommu_ctx_drvdata holds the driver data for a single context bank
  * within each IOMMU hardware instance
@@ -99,6 +110,8 @@
 	struct list_head attached_elm;
 	struct iommu_domain *attached_domain;
 	const char *name;
+	u32 sids[MAX_NUM_SMR];
+	unsigned int nsid;
 };
 
 /*
diff --git a/arch/arm/mach-msm/include/mach/iommu_hw-v2.h b/arch/arm/mach-msm/include/mach/iommu_hw-v2.h
index fac13b3..b01dbd8 100644
--- a/arch/arm/mach-msm/include/mach/iommu_hw-v2.h
+++ b/arch/arm/mach-msm/include/mach/iommu_hw-v2.h
@@ -16,8 +16,6 @@
 #define CTX_SHIFT  12
 #define CTX_OFFSET 0x8000
 
-#define MAX_NUM_SMR 128
-
 #define GET_GLOBAL_REG(reg, base) (readl_relaxed((base) + (reg)))
 #define GET_CTX_REG(reg, base, ctx) \
 	(readl_relaxed((base) + CTX_OFFSET + (reg) + ((ctx) << CTX_SHIFT)))
diff --git a/arch/arm/mach-msm/include/mach/kgsl.h b/arch/arm/mach-msm/include/mach/kgsl.h
new file mode 100644
index 0000000..a51cc46
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/kgsl.h
@@ -0,0 +1,82 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _ARCH_ARM_MACH_KGSL_H
+#define _ARCH_ARM_MACH_KGSL_H
+
+/* Clock flags to show which clocks should be controled by a given platform */
+#define KGSL_CLK_SRC	0x00000001
+#define KGSL_CLK_CORE	0x00000002
+#define KGSL_CLK_IFACE	0x00000004
+#define KGSL_CLK_MEM	0x00000008
+#define KGSL_CLK_MEM_IFACE 0x00000010
+#define KGSL_CLK_AXI	0x00000020
+
+#define KGSL_MAX_PWRLEVELS 5
+
+#define KGSL_CONVERT_TO_MBPS(val) \
+	(val*1000*1000U)
+
+#define KGSL_3D0_REG_MEMORY	"kgsl_3d0_reg_memory"
+#define KGSL_3D0_IRQ		"kgsl_3d0_irq"
+#define KGSL_2D0_REG_MEMORY	"kgsl_2d0_reg_memory"
+#define KGSL_2D0_IRQ		"kgsl_2d0_irq"
+#define KGSL_2D1_REG_MEMORY	"kgsl_2d1_reg_memory"
+#define KGSL_2D1_IRQ		"kgsl_2d1_irq"
+
+#define ADRENO_CHIPID(_co, _ma, _mi, _pa) \
+	((((_co) & 0xFF) << 24) | \
+	 (((_ma) & 0xFF) << 16) | \
+	 (((_mi) & 0xFF) << 8) | \
+	 ((_pa) & 0xFF))
+
+enum kgsl_iommu_context_id {
+	KGSL_IOMMU_CONTEXT_USER = 0,
+	KGSL_IOMMU_CONTEXT_PRIV = 1,
+};
+
+struct kgsl_iommu_ctx {
+	const char *iommu_ctx_name;
+	enum kgsl_iommu_context_id ctx_id;
+};
+
+struct kgsl_device_iommu_data {
+	const struct kgsl_iommu_ctx *iommu_ctxs;
+	int iommu_ctx_count;
+	unsigned int physstart;
+	unsigned int physend;
+};
+
+struct kgsl_pwrlevel {
+	unsigned int gpu_freq;
+	unsigned int bus_freq;
+	unsigned int io_fraction;
+};
+
+struct kgsl_device_platform_data {
+	struct kgsl_pwrlevel pwrlevel[KGSL_MAX_PWRLEVELS];
+	int init_level;
+	int num_levels;
+	int (*set_grp_async)(void);
+	unsigned int idle_timeout;
+	bool strtstp_sleepwake;
+	unsigned int nap_allowed;
+	unsigned int clk_map;
+	unsigned int idle_needed;
+	struct msm_bus_scale_pdata *bus_scale_table;
+	struct kgsl_device_iommu_data *iommu_data;
+	int iommu_count;
+	struct msm_dcvs_core_info *core_info;
+	unsigned int chipid;
+};
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/rpm-regulator-smd.h b/arch/arm/mach-msm/include/mach/rpm-regulator-smd.h
index 319c2d8..12bf2b7 100644
--- a/arch/arm/mach-msm/include/mach/rpm-regulator-smd.h
+++ b/arch/arm/mach-msm/include/mach/rpm-regulator-smd.h
@@ -30,6 +30,7 @@
  */
 enum rpm_regulator_voltage_corner {
 	RPM_REGULATOR_CORNER_RETENTION = 1,
+	RPM_REGULATOR_CORNER_NONE = RPM_REGULATOR_CORNER_RETENTION,
 	RPM_REGULATOR_CORNER_SVS_KRAIT,
 	RPM_REGULATOR_CORNER_SVS_SOC,
 	RPM_REGULATOR_CORNER_NORMAL,
diff --git a/arch/arm/mach-msm/include/mach/subsystem_restart.h b/arch/arm/mach-msm/include/mach/subsystem_restart.h
index 51ace96..6d15f47 100644
--- a/arch/arm/mach-msm/include/mach/subsystem_restart.h
+++ b/arch/arm/mach-msm/include/mach/subsystem_restart.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -18,6 +18,8 @@
 
 #define SUBSYS_NAME_MAX_LENGTH 40
 
+struct subsys_device;
+
 enum {
 	RESET_SOC = 1,
 	RESET_SUBSYS_COUPLED,
@@ -25,29 +27,23 @@
 	RESET_LEVEL_MAX
 };
 
-struct subsys_data {
+struct subsys_desc {
 	const char *name;
-	int (*shutdown) (const struct subsys_data *);
-	int (*powerup) (const struct subsys_data *);
-	void (*crash_shutdown) (const struct subsys_data *);
-	int (*ramdump) (int, const struct subsys_data *);
 
-	/* Internal use only */
-	struct list_head list;
-	void *notif_handle;
-
-	struct mutex shutdown_lock;
-	struct mutex powerup_lock;
-
-	void *restart_order;
-	struct subsys_data *single_restart_list[1];
+	int (*shutdown)(const struct subsys_desc *desc);
+	int (*powerup)(const struct subsys_desc *desc);
+	void (*crash_shutdown)(const struct subsys_desc *desc);
+	int (*ramdump)(int, const struct subsys_desc *desc);
 };
 
 #if defined(CONFIG_MSM_SUBSYSTEM_RESTART)
 
-int get_restart_level(void);
-int subsystem_restart(const char *subsys_name);
-int ssr_register_subsystem(struct subsys_data *subsys);
+extern int get_restart_level(void);
+extern int subsystem_restart_dev(struct subsys_device *dev);
+extern int subsystem_restart(const char *name);
+
+extern struct subsys_device *subsys_register(struct subsys_desc *desc);
+extern void subsys_unregister(struct subsys_device *dev);
 
 #else
 
@@ -56,16 +52,24 @@
 	return 0;
 }
 
-static inline int subsystem_restart(const char *subsystem_name)
+static inline int subsystem_restart_dev(struct subsys_device *dev)
 {
 	return 0;
 }
 
-static inline int ssr_register_subsystem(struct subsys_data *subsys)
+static inline int subsystem_restart(const char *name)
 {
 	return 0;
 }
 
+static inline
+struct subsys_device *subsys_register(struct subsys_desc *desc)
+{
+	return NULL;
+}
+
+static inline void subsys_unregister(struct subsys_device *dev) { }
+
 #endif /* CONFIG_MSM_SUBSYSTEM_RESTART */
 
 #endif
diff --git a/arch/arm/mach-msm/krait-scm.c b/arch/arm/mach-msm/krait-scm.c
new file mode 100644
index 0000000..eb48d35
--- /dev/null
+++ b/arch/arm/mach-msm/krait-scm.c
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2012, Code Aurora Forum. 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/kernel.h>
+#include <linux/workqueue.h>
+#include <linux/percpu.h>
+#include <linux/cpu.h>
+#include <linux/smp.h>
+#include <linux/sysfs.h>
+#include <linux/sysdev.h>
+
+#include <mach/scm.h>
+
+#define CPU_CONFIG_CMD 5
+#define CPU_CONFIG_QUERY_CMD 6
+
+static int query_cpu_config(void)
+{
+	struct cpu_config_query_req_resp {
+		u32	id;
+		u32	arg0;
+		u32	arg1;
+		u32	arg2;
+	} request;
+	struct cpu_config_query_resp {
+		u32	ret0;
+		u32	ret1;
+		u32	ret2;
+		u32	ret3;
+	} response = {0};
+	int ret;
+
+	request.id = 1;
+	ret = scm_call(SCM_SVC_BOOT, CPU_CONFIG_QUERY_CMD, &request,
+			sizeof(request), &response, sizeof(response));
+	return ret ? : response.ret0;
+}
+
+static void set_cpu_config(int enable)
+{
+	struct cpu_config_req {
+		u32	id;
+		u32	arg0;
+		u32	arg1;
+		u32	arg2;
+	} request;
+
+	request.id = 1;
+	request.arg0 = enable;
+	scm_call(SCM_SVC_BOOT, CPU_CONFIG_CMD, &request, sizeof(request),
+			NULL, 0);
+}
+
+void enable_cpu_config(struct work_struct *work)
+{
+	set_cpu_config(1);
+}
+
+void disable_cpu_config(struct work_struct *work)
+{
+	set_cpu_config(0);
+}
+
+int cpu_config_on_each_cpu(bool enable)
+{
+	work_func_t func = enable ? enable_cpu_config : disable_cpu_config;
+	return schedule_on_each_cpu(func);
+}
+
+static ssize_t show_cpuctl(struct sysdev_class *class,
+		struct sysdev_class_attribute *attr, char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%d\n", query_cpu_config());
+}
+
+static ssize_t store_cpuctl(struct sysdev_class *class,
+		struct sysdev_class_attribute *attr, const char *buf,
+		size_t count)
+{
+	unsigned val;
+	int ret;
+
+	ret = kstrtouint(buf, 10, &val);
+	if (ret < 0)
+		return ret;
+	ret = cpu_config_on_each_cpu(val);
+	if (ret < 0)
+		return ret;
+
+	return count;
+}
+
+static SYSDEV_CLASS_ATTR(cpuctl, 0600, show_cpuctl, store_cpuctl);
+
+static int __init init_scm_cpu(void)
+{
+	return sysfs_create_file(&cpu_subsys.dev_root->kobj,
+			&attr_cpuctl.attr);
+}
+module_init(init_scm_cpu);
diff --git a/arch/arm/mach-msm/lpass-8660.c b/arch/arm/mach-msm/lpass-8660.c
index 1018360..be18b68 100644
--- a/arch/arm/mach-msm/lpass-8660.c
+++ b/arch/arm/mach-msm/lpass-8660.c
@@ -19,6 +19,7 @@
 #include <linux/stringify.h>
 #include <linux/delay.h>
 #include <linux/module.h>
+#include <linux/err.h>
 
 #include <mach/irqs.h>
 #include <mach/scm.h>
@@ -35,6 +36,8 @@
 #define MODULE_NAME			"lpass_8x60"
 #define SCM_Q6_NMI_CMD			0x1
 
+static struct subsys_device *subsys_8x60_q6_dev;
+
 /* Subsystem restart: QDSP6 data, functions */
 static void *q6_ramdump_dev;
 static void q6_fatal_fn(struct work_struct *);
@@ -44,7 +47,7 @@
 static void q6_fatal_fn(struct work_struct *work)
 {
 	pr_err("%s: Watchdog bite received from Q6!\n", MODULE_NAME);
-	subsystem_restart("lpass");
+	subsystem_restart_dev(subsys_8x60_q6_dev);
 	enable_irq(LPASS_Q6SS_WDOG_EXPIRED);
 }
 
@@ -65,7 +68,7 @@
 	pr_info("subsystem-fatal-8x60: Q6 NMI was sent.\n");
 }
 
-int subsys_q6_shutdown(const struct subsys_data *crashed_subsys)
+int subsys_q6_shutdown(const struct subsys_desc *crashed_subsys)
 {
 	void __iomem *q6_wdog_addr =
 		ioremap_nocache(Q6SS_WDOG_ENABLE, 8);
@@ -82,7 +85,7 @@
 	return 0;
 }
 
-int subsys_q6_powerup(const struct subsys_data *crashed_subsys)
+int subsys_q6_powerup(const struct subsys_desc *crashed_subsys)
 {
 	int ret = pil_force_boot("q6");
 	enable_irq(LPASS_Q6SS_WDOG_EXPIRED);
@@ -93,7 +96,7 @@
 static struct ramdump_segment q6_segments[] = { {0x46700000, 0x47F00000 -
 					0x46700000}, {0x28400000, 0x12800} };
 static int subsys_q6_ramdump(int enable,
-				const struct subsys_data *crashed_subsys)
+				const struct subsys_desc *crashed_subsys)
 {
 	if (enable)
 		return do_ramdump(q6_ramdump_dev, q6_segments,
@@ -102,7 +105,7 @@
 		return 0;
 }
 
-void subsys_q6_crash_shutdown(const struct subsys_data *crashed_subsys)
+void subsys_q6_crash_shutdown(const struct subsys_desc *crashed_subsys)
 {
 	send_q6_nmi();
 }
@@ -117,7 +120,7 @@
 	return IRQ_HANDLED;
 }
 
-static struct subsys_data subsys_8x60_q6 = {
+static struct subsys_desc subsys_8x60_q6 = {
 	.name = "lpass",
 	.shutdown = subsys_q6_shutdown,
 	.powerup = subsys_q6_powerup,
@@ -127,6 +130,7 @@
 
 static void __exit lpass_fatal_exit(void)
 {
+	subsys_unregister(subsys_8x60_q6_dev);
 	iounmap(q6_wakeup_intr);
 	free_irq(LPASS_Q6SS_WDOG_EXPIRED, NULL);
 }
@@ -156,7 +160,9 @@
 	if (!q6_wakeup_intr)
 		pr_warn("lpass-8660: Unable to ioremap q6 wakeup address.");
 
-	ret = ssr_register_subsystem(&subsys_8x60_q6);
+	subsys_8x60_q6_dev = subsys_register(&subsys_8x60_q6);
+	if (IS_ERR(subsys_8x60_q6_dev))
+		ret = PTR_ERR(subsys_8x60_q6_dev);
 out:
 	return ret;
 }
diff --git a/arch/arm/mach-msm/lpass-8960.c b/arch/arm/mach-msm/lpass-8960.c
index c58b0e1..b714a7f 100644
--- a/arch/arm/mach-msm/lpass-8960.c
+++ b/arch/arm/mach-msm/lpass-8960.c
@@ -152,7 +152,7 @@
 	pr_debug("%s: Q6 NMI was sent.\n", __func__);
 }
 
-static int lpass_shutdown(const struct subsys_data *subsys)
+static int lpass_shutdown(const struct subsys_desc *subsys)
 {
 	send_q6_nmi();
 	pil_force_shutdown("q6");
@@ -161,7 +161,7 @@
 	return 0;
 }
 
-static int lpass_powerup(const struct subsys_data *subsys)
+static int lpass_powerup(const struct subsys_desc *subsys)
 {
 	int ret = pil_force_boot("q6");
 	enable_irq(LPASS_Q6SS_WDOG_EXPIRED);
@@ -170,7 +170,7 @@
 /* RAM segments - address and size for 8960 */
 static struct ramdump_segment q6_segments[] = { {0x8da00000, 0x8f200000 -
 					0x8da00000}, {0x28400000, 0x20000} };
-static int lpass_ramdump(int enable, const struct subsys_data *subsys)
+static int lpass_ramdump(int enable, const struct subsys_desc *subsys)
 {
 	pr_debug("%s: enable[%d]\n", __func__, enable);
 	if (enable)
@@ -181,7 +181,7 @@
 		return 0;
 }
 
-static void lpass_crash_shutdown(const struct subsys_data *subsys)
+static void lpass_crash_shutdown(const struct subsys_desc *subsys)
 {
 	q6_crash_shutdown = 1;
 	send_q6_nmi();
@@ -198,7 +198,9 @@
 	return IRQ_HANDLED;
 }
 
-static struct subsys_data lpass_8960 = {
+static struct subsys_device *lpass_8960_dev;
+
+static struct subsys_desc lpass_8960 = {
 	.name = "lpass",
 	.shutdown = lpass_shutdown,
 	.powerup = lpass_powerup,
@@ -208,7 +210,10 @@
 
 static int __init lpass_restart_init(void)
 {
-	return ssr_register_subsystem(&lpass_8960);
+	lpass_8960_dev = subsys_register(&lpass_8960);
+	if (IS_ERR(lpass_8960_dev))
+		return PTR_ERR(lpass_8960_dev);
+	return 0;
 }
 
 static int __init lpass_fatal_init(void)
@@ -275,6 +280,7 @@
 {
 	subsys_notif_unregister_notifier(ssr_notif_hdle, &rnb);
 	subsys_notif_unregister_notifier(ssr_modem_notif_hdle, &mnb);
+	subsys_unregister(lpass_8960_dev);
 	free_irq(LPASS_Q6SS_WDOG_EXPIRED, NULL);
 }
 
diff --git a/arch/arm/mach-msm/mdm.c b/arch/arm/mach-msm/mdm.c
index cbdc92a..4280fb4 100644
--- a/arch/arm/mach-msm/mdm.c
+++ b/arch/arm/mach-msm/mdm.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012, Code Aurora Forum. 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
@@ -73,14 +73,14 @@
 
 }
 
-static int charm_subsys_shutdown(const struct subsys_data *crashed_subsys)
+static int charm_subsys_shutdown(const struct subsys_desc *crashed_subsys)
 {
 	charm_ready = 0;
 	power_down_charm();
 	return 0;
 }
 
-static int charm_subsys_powerup(const struct subsys_data *crashed_subsys)
+static int charm_subsys_powerup(const struct subsys_desc *crashed_subsys)
 {
 	power_on_charm();
 	boot_type = CHARM_NORMAL_BOOT;
@@ -92,7 +92,7 @@
 }
 
 static int charm_subsys_ramdumps(int want_dumps,
-				const struct subsys_data *crashed_subsys)
+				const struct subsys_desc *crashed_subsys)
 {
 	charm_ram_dump_status = 0;
 	if (want_dumps) {
@@ -105,7 +105,9 @@
 	return charm_ram_dump_status;
 }
 
-static struct subsys_data charm_subsystem = {
+static struct subsys_device *charm_subsys;
+
+static struct subsys_desc charm_subsystem = {
 	.shutdown = charm_subsys_shutdown,
 	.ramdump = charm_subsys_ramdumps,
 	.powerup = charm_subsys_powerup,
@@ -229,7 +231,7 @@
 static void charm_status_fn(struct work_struct *work)
 {
 	pr_info("Reseting the charm because status changed\n");
-	subsystem_restart("external_modem");
+	subsystem_restart_dev(charm_subsys);
 }
 
 static DECLARE_WORK(charm_status_work, charm_status_fn);
@@ -239,7 +241,7 @@
 	pr_info("Reseting the charm due to an errfatal\n");
 	if (get_restart_level() == RESET_SOC)
 		pm8xxx_stay_on();
-	subsystem_restart("external_modem");
+	subsystem_restart_dev(charm_subsys);
 }
 
 static DECLARE_WORK(charm_fatal_work, charm_fatal_fn);
@@ -349,7 +351,11 @@
 	atomic_notifier_chain_register(&panic_notifier_list, &charm_panic_blk);
 	charm_debugfs_init();
 
-	ssr_register_subsystem(&charm_subsystem);
+	charm_subsys = subsys_register(&charm_subsystem);
+	if (IS_ERR(charm_subsys)) {
+		ret = PTR_ERR(charm_subsys);
+		goto fatal_err;
+	}
 
 	irq = platform_get_irq(pdev, 0);
 	if (irq < 0) {
diff --git a/arch/arm/mach-msm/mdm_common.c b/arch/arm/mach-msm/mdm_common.c
index 5b181e1..ac9da2e 100644
--- a/arch/arm/mach-msm/mdm_common.c
+++ b/arch/arm/mach-msm/mdm_common.c
@@ -56,6 +56,7 @@
 #define EXTERNAL_MODEM "external_modem"
 
 static struct mdm_modem_drv *mdm_drv;
+static struct subsys_device *mdm_subsys_dev;
 
 DECLARE_COMPLETION(mdm_needs_reload);
 DECLARE_COMPLETION(mdm_boot);
@@ -154,7 +155,7 @@
 		pr_err("%s: MDM2AP_STATUS gpio did not go high\n",
 			   __func__);
 		mdm_drv->mdm_ready = 0;
-		subsystem_restart(EXTERNAL_MODEM);
+		subsystem_restart_dev(mdm_subsys_dev);
 	}
 }
 
@@ -271,7 +272,7 @@
 		(gpio_get_value(mdm_drv->mdm2ap_status_gpio) == 1)) {
 		pr_info("%s: Reseting the mdm due to an errfatal\n", __func__);
 		mdm_drv->mdm_ready = 0;
-		subsystem_restart(EXTERNAL_MODEM);
+		subsystem_restart_dev(mdm_subsys_dev);
 	}
 	return IRQ_HANDLED;
 }
@@ -332,7 +333,7 @@
 		pr_info("%s: unexpected reset external modem\n", __func__);
 		mdm_drv->mdm_unexpected_reset_occurred = 1;
 		mdm_drv->mdm_ready = 0;
-		subsystem_restart(EXTERNAL_MODEM);
+		subsystem_restart_dev(mdm_subsys_dev);
 	} else if (value == 1) {
 		cancel_delayed_work(&mdm2ap_status_check_work);
 		pr_info("%s: status = 1: mdm is now ready\n", __func__);
@@ -349,7 +350,7 @@
 	return IRQ_HANDLED;
 }
 
-static int mdm_subsys_shutdown(const struct subsys_data *crashed_subsys)
+static int mdm_subsys_shutdown(const struct subsys_desc *crashed_subsys)
 {
 	mdm_drv->mdm_ready = 0;
 	gpio_direction_output(mdm_drv->ap2mdm_errfatal_gpio, 1);
@@ -367,7 +368,7 @@
 	return 0;
 }
 
-static int mdm_subsys_powerup(const struct subsys_data *crashed_subsys)
+static int mdm_subsys_powerup(const struct subsys_desc *crashed_subsys)
 {
 	gpio_direction_output(mdm_drv->ap2mdm_errfatal_gpio, 0);
 	gpio_direction_output(mdm_drv->ap2mdm_status_gpio, 1);
@@ -390,7 +391,7 @@
 }
 
 static int mdm_subsys_ramdumps(int want_dumps,
-				const struct subsys_data *crashed_subsys)
+				const struct subsys_desc *crashed_subsys)
 {
 	mdm_drv->mdm_ram_dump_status = 0;
 	if (want_dumps) {
@@ -411,7 +412,7 @@
 	return mdm_drv->mdm_ram_dump_status;
 }
 
-static struct subsys_data mdm_subsystem = {
+static struct subsys_desc mdm_subsystem = {
 	.shutdown = mdm_subsys_shutdown,
 	.ramdump = mdm_subsys_ramdumps,
 	.powerup = mdm_subsys_powerup,
@@ -588,7 +589,11 @@
 	mdm_debugfs_init();
 
 	/* Register subsystem handlers */
-	ssr_register_subsystem(&mdm_subsystem);
+	mdm_subsys_dev = subsys_register(&mdm_subsystem);
+	if (IS_ERR(mdm_subsys_dev)) {
+		ret = PTR_ERR(mdm_subsys_dev);
+		goto fatal_err;
+	}
 
 	/* ERR_FATAL irq. */
 	irq = MSM_GPIO_TO_INT(mdm_drv->mdm2ap_errfatal_gpio);
diff --git a/arch/arm/mach-msm/modem-8660.c b/arch/arm/mach-msm/modem-8660.c
index 9c558e4..096ed9c 100644
--- a/arch/arm/mach-msm/modem-8660.c
+++ b/arch/arm/mach-msm/modem-8660.c
@@ -19,6 +19,7 @@
 #include <linux/stringify.h>
 #include <linux/delay.h>
 #include <linux/module.h>
+#include <linux/err.h>
 
 #include <mach/irqs.h>
 #include <mach/scm.h>
@@ -48,6 +49,8 @@
 module_param(reset_modem, int, 0644);
 #endif
 
+static struct subsys_device *modem_8660_dev;
+
 /* Subsystem restart: Modem data, functions */
 static void *modem_ramdump_dev;
 static void modem_fatal_fn(struct work_struct *);
@@ -75,7 +78,7 @@
 	mb();
 	iounmap(hwio_modem_reset_addr);
 
-	subsystem_restart("modem");
+	subsystem_restart_dev(modem_8660_dev);
 	enable_irq(MARM_WDOG_EXPIRED);
 }
 
@@ -93,7 +96,7 @@
 
 	if (modem_state == 0 || modem_state & panic_smsm_states) {
 
-		subsystem_restart("modem");
+		subsystem_restart_dev(modem_8660_dev);
 		enable_irq(MARM_WDOG_EXPIRED);
 
 	} else if (modem_state & reset_smsm_states) {
@@ -135,13 +138,13 @@
 			goto out;
 		}
 		pr_err("%s: Modem error fatal'ed.", MODULE_NAME);
-		subsystem_restart("modem");
+		subsystem_restart_dev(modem_8660_dev);
 	}
 out:
 	return NOTIFY_DONE;
 }
 
-static int modem_shutdown(const struct subsys_data *crashed_subsys)
+static int modem_shutdown(const struct subsys_desc *crashed_subsys)
 {
 	void __iomem *modem_wdog_addr;
 
@@ -178,7 +181,7 @@
 	return 0;
 }
 
-static int modem_powerup(const struct subsys_data *crashed_subsys)
+static int modem_powerup(const struct subsys_desc *crashed_subsys)
 {
 	int ret;
 
@@ -192,8 +195,7 @@
 static struct ramdump_segment modem_segments[] = {
 	{0x42F00000, 0x46000000 - 0x42F00000} };
 
-static int modem_ramdump(int enable,
-				const struct subsys_data *crashed_subsys)
+static int modem_ramdump(int enable, const struct subsys_desc *crashed_subsys)
 {
 	if (enable)
 		return do_ramdump(modem_ramdump_dev, modem_segments,
@@ -202,8 +204,7 @@
 		return 0;
 }
 
-static void modem_crash_shutdown(
-				const struct subsys_data *crashed_subsys)
+static void modem_crash_shutdown(const struct subsys_desc *crashed_subsys)
 {
 	/* If modem hasn't already crashed, send SMSM_RESET. */
 	if (!(smsm_get_state(SMSM_MODEM_STATE) & SMSM_RESET)) {
@@ -225,7 +226,7 @@
 	return IRQ_HANDLED;
 }
 
-static struct subsys_data subsys_8660_modem = {
+static struct subsys_desc subsys_8660_modem = {
 	.name = "modem",
 	.shutdown = modem_shutdown,
 	.powerup = modem_powerup,
@@ -260,13 +261,16 @@
 		goto out;
 	}
 
-	ret = ssr_register_subsystem(&subsys_8660_modem);
+	modem_8660_dev = subsys_register(&subsys_8660_modem);
+	if (IS_ERR(modem_8660_dev))
+		ret = PTR_ERR(modem_8660_dev);
 out:
 	return ret;
 }
 
 static void __exit modem_8660_exit(void)
 {
+	subsys_unregister(modem_8660_dev);
 	free_irq(MARM_WDOG_EXPIRED, NULL);
 }
 
diff --git a/arch/arm/mach-msm/modem-8960.c b/arch/arm/mach-msm/modem-8960.c
index fd7b7b5..73b9b1f 100644
--- a/arch/arm/mach-msm/modem-8960.c
+++ b/arch/arm/mach-msm/modem-8960.c
@@ -35,6 +35,8 @@
 
 static int crash_shutdown;
 
+static struct subsys_device *modem_8960_dev;
+
 #define MAX_SSR_REASON_LEN 81U
 #define Q6_FW_WDOG_ENABLE		0x08882024
 #define Q6_SW_WDOG_ENABLE		0x08982024
@@ -66,7 +68,7 @@
 static void restart_modem(void)
 {
 	log_modem_sfr();
-	subsystem_restart("modem");
+	subsystem_restart_dev(modem_8960_dev);
 }
 
 static void modem_wdog_check(struct work_struct *work)
@@ -101,7 +103,7 @@
 	}
 }
 
-static int modem_shutdown(const struct subsys_data *subsys)
+static int modem_shutdown(const struct subsys_desc *subsys)
 {
 	void __iomem *q6_fw_wdog_addr;
 	void __iomem *q6_sw_wdog_addr;
@@ -142,7 +144,7 @@
 
 #define MODEM_WDOG_CHECK_TIMEOUT_MS 10000
 
-static int modem_powerup(const struct subsys_data *subsys)
+static int modem_powerup(const struct subsys_desc *subsys)
 {
 	pil_force_boot("modem_fw");
 	pil_force_boot("modem");
@@ -153,7 +155,7 @@
 	return 0;
 }
 
-void modem_crash_shutdown(const struct subsys_data *subsys)
+void modem_crash_shutdown(const struct subsys_desc *subsys)
 {
 	crash_shutdown = 1;
 	smsm_reset_modem(SMSM_RESET);
@@ -176,8 +178,7 @@
 static void *modemsw_ramdump_dev;
 static void *smem_ramdump_dev;
 
-static int modem_ramdump(int enable,
-				const struct subsys_data *crashed_subsys)
+static int modem_ramdump(int enable, const struct subsys_desc *crashed_subsys)
 {
 	int ret = 0;
 
@@ -234,7 +235,7 @@
 	return IRQ_HANDLED;
 }
 
-static struct subsys_data modem_8960 = {
+static struct subsys_desc modem_8960 = {
 	.name = "modem",
 	.shutdown = modem_shutdown,
 	.powerup = modem_powerup,
@@ -244,13 +245,16 @@
 
 static int modem_subsystem_restart_init(void)
 {
-	return ssr_register_subsystem(&modem_8960);
+	modem_8960_dev = subsys_register(&modem_8960);
+	if (IS_ERR(modem_8960_dev))
+		return PTR_ERR(modem_8960_dev);
+	return 0;
 }
 
 static int modem_debug_set(void *data, u64 val)
 {
 	if (val == 1)
-		subsystem_restart("modem");
+		subsystem_restart_dev(modem_8960_dev);
 
 	return 0;
 }
diff --git a/arch/arm/mach-msm/msm_dsps.c b/arch/arm/mach-msm/msm_dsps.c
index 200d717..6dde576 100644
--- a/arch/arm/mach-msm/msm_dsps.c
+++ b/arch/arm/mach-msm/msm_dsps.c
@@ -722,6 +722,8 @@
 	.unlocked_ioctl = dsps_ioctl,
 };
 
+static struct subsys_device *dsps_dev;
+
 /**
  *  Fatal error handler
  *  Resets DSPS.
@@ -735,7 +737,7 @@
 		pr_err("%s: DSPS already resetting. Count %d\n", __func__,
 		       atomic_read(&drv->crash_in_progress));
 	} else {
-		subsystem_restart("dsps");
+		subsystem_restart_dev(dsps_dev);
 	}
 }
 
@@ -765,7 +767,7 @@
  * called by the restart notifier
  *
  */
-static int dsps_shutdown(const struct subsys_data *subsys)
+static int dsps_shutdown(const struct subsys_desc *subsys)
 {
 	pr_debug("%s\n", __func__);
 	disable_irq_nosync(drv->wdog_irq);
@@ -779,7 +781,7 @@
  * called by the restart notifier
  *
  */
-static int dsps_powerup(const struct subsys_data *subsys)
+static int dsps_powerup(const struct subsys_desc *subsys)
 {
 	pr_debug("%s\n", __func__);
 	dsps_power_on_handler();
@@ -794,7 +796,7 @@
  * called by the restart notifier
  *
  */
-static void dsps_crash_shutdown(const struct subsys_data *subsys)
+static void dsps_crash_shutdown(const struct subsys_desc *subsys)
 {
 	pr_debug("%s\n", __func__);
 	dsps_crash_shutdown_g = 1;
@@ -806,7 +808,7 @@
  * called by the restart notifier
  *
  */
-static int dsps_ramdump(int enable, const struct subsys_data *subsys)
+static int dsps_ramdump(int enable, const struct subsys_desc *subsys)
 {
 	int ret = 0;
 	pr_debug("%s\n", __func__);
@@ -838,7 +840,7 @@
 	return ret;
 }
 
-static struct subsys_data dsps_ssrops = {
+static struct subsys_desc dsps_ssrops = {
 	.name = "dsps",
 	.shutdown = dsps_shutdown,
 	.powerup = dsps_powerup,
@@ -919,9 +921,10 @@
 		goto smsm_register_err;
 	}
 
-	ret = ssr_register_subsystem(&dsps_ssrops);
-	if (ret) {
-		pr_err("%s: ssr_register_subsystem fail %d\n", __func__,
+	dsps_dev = subsys_register(&dsps_ssrops);
+	if (IS_ERR(dsps_dev)) {
+		ret = PTR_ERR(dsps_dev);
+		pr_err("%s: subsys_register fail %d\n", __func__,
 		       ret);
 		goto ssr_register_err;
 	}
@@ -953,6 +956,7 @@
 {
 	pr_debug("%s.\n", __func__);
 
+	subsys_unregister(dsps_dev);
 	dsps_power_off_handler();
 	dsps_free_resources();
 
diff --git a/arch/arm/mach-msm/peripheral-loader.c b/arch/arm/mach-msm/peripheral-loader.c
index 3f6eb95..540ffbb 100644
--- a/arch/arm/mach-msm/peripheral-loader.c
+++ b/arch/arm/mach-msm/peripheral-loader.c
@@ -565,18 +565,6 @@
 static void msm_pil_debugfs_remove(struct pil_device *pil) { }
 #endif
 
-static int __msm_pil_shutdown(struct device *dev, void *data)
-{
-	pil_shutdown(to_pil_device(dev));
-	return 0;
-}
-
-static int msm_pil_shutdown_at_boot(void)
-{
-	return bus_for_each_dev(&pil_bus_type, NULL, NULL, __msm_pil_shutdown);
-}
-late_initcall(msm_pil_shutdown_at_boot);
-
 static void pil_device_release(struct device *dev)
 {
 	struct pil_device *pil = to_pil_device(dev);
diff --git a/arch/arm/mach-msm/pm-8x60.c b/arch/arm/mach-msm/pm-8x60.c
index 6e86baa..42616c6 100644
--- a/arch/arm/mach-msm/pm-8x60.c
+++ b/arch/arm/mach-msm/pm-8x60.c
@@ -591,7 +591,7 @@
 
 static int64_t msm_pm_timer_enter_suspend(int64_t *period)
 {
-	int time = 0;
+	int64_t time = 0;
 
 	if (msm_pm_use_qtimer)
 		return sched_clock();
diff --git a/arch/arm/mach-msm/pm2.c b/arch/arm/mach-msm/pm2.c
index ae7a3cd..7a8e4c3 100644
--- a/arch/arm/mach-msm/pm2.c
+++ b/arch/arm/mach-msm/pm2.c
@@ -1280,7 +1280,7 @@
 
 static int64_t msm_pm_timer_enter_suspend(int64_t *period)
 {
-	int time = 0;
+	int64_t time = 0;
 
 	time = msm_timer_get_sclk_time(period);
 	if (!time)
diff --git a/arch/arm/mach-msm/ramdump.c b/arch/arm/mach-msm/ramdump.c
index a18acd6..21e81dd 100644
--- a/arch/arm/mach-msm/ramdump.c
+++ b/arch/arm/mach-msm/ramdump.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. 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
@@ -222,6 +222,17 @@
 	return (void *)rd_dev;
 }
 
+void destroy_ramdump_device(void *dev)
+{
+	struct ramdump_device *rd_dev = dev;
+
+	if (IS_ERR_OR_NULL(rd_dev))
+		return;
+
+	misc_deregister(&rd_dev->device);
+	kfree(rd_dev);
+}
+
 int do_ramdump(void *handle, struct ramdump_segment *segments,
 		int nsegments)
 {
diff --git a/arch/arm/mach-msm/ramdump.h b/arch/arm/mach-msm/ramdump.h
index 0b60a44..9006010 100644
--- a/arch/arm/mach-msm/ramdump.h
+++ b/arch/arm/mach-msm/ramdump.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. 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
@@ -19,6 +19,7 @@
 };
 
 void *create_ramdump_device(const char *dev_name);
+void destroy_ramdump_device(void *dev);
 int do_ramdump(void *handle, struct ramdump_segment *segments,
 		int nsegments);
 
diff --git a/arch/arm/mach-msm/rpm-smd.c b/arch/arm/mach-msm/rpm-smd.c
index b8bb27b..697d504 100644
--- a/arch/arm/mach-msm/rpm-smd.c
+++ b/arch/arm/mach-msm/rpm-smd.c
@@ -24,6 +24,7 @@
 #include <linux/list.h>
 #include <linux/mutex.h>
 #include <linux/spinlock.h>
+#include <linux/string.h>
 #include <linux/device.h>
 #include <linux/notifier.h>
 #include <linux/slab.h>
@@ -36,6 +37,19 @@
 #include <mach/rpm-smd.h>
 #include "rpm-notifier.h"
 
+/* Debug Definitions */
+
+enum {
+	MSM_RPM_LOG_REQUEST_PRETTY	= BIT(0),
+	MSM_RPM_LOG_REQUEST_RAW		= BIT(1),
+	MSM_RPM_LOG_REQUEST_SHOW_MSG_ID	= BIT(2),
+};
+
+static int msm_rpm_debug_mask;
+module_param_named(
+	debug_mask, msm_rpm_debug_mask, int, S_IRUGO | S_IWUSR
+);
+
 struct msm_rpm_driver_data {
 	const char *ch_name;
 	uint32_t ch_type;
@@ -492,6 +506,140 @@
 	}
 }
 
+#define DEBUG_PRINT_BUFFER_SIZE 512
+
+static void msm_rpm_log_request(struct msm_rpm_request *cdata)
+{
+	char buf[DEBUG_PRINT_BUFFER_SIZE];
+	size_t buflen = DEBUG_PRINT_BUFFER_SIZE;
+	char name[5];
+	u32 value;
+	int i, j, prev_valid;
+	int valid_count = 0;
+	int pos = 0;
+
+	name[4] = 0;
+
+	for (i = 0; i < cdata->write_idx; i++)
+		if (cdata->kvp[i].valid)
+			valid_count++;
+
+	pos += scnprintf(buf + pos, buflen - pos, "%sRPM req: ", KERN_INFO);
+	if (msm_rpm_debug_mask & MSM_RPM_LOG_REQUEST_SHOW_MSG_ID)
+		pos += scnprintf(buf + pos, buflen - pos, "msg_id=%u, ",
+				cdata->msg_hdr.msg_id);
+	pos += scnprintf(buf + pos, buflen - pos, "s=%s",
+		(cdata->msg_hdr.set == MSM_RPM_CTX_ACTIVE_SET ? "act" : "slp"));
+
+	if ((msm_rpm_debug_mask & MSM_RPM_LOG_REQUEST_PRETTY)
+	    && (msm_rpm_debug_mask & MSM_RPM_LOG_REQUEST_RAW)) {
+		/* Both pretty and raw formatting */
+		memcpy(name, &cdata->msg_hdr.resource_type, sizeof(uint32_t));
+		pos += scnprintf(buf + pos, buflen - pos,
+			", rsc_type=0x%08X (%s), rsc_id=%u; ",
+			cdata->msg_hdr.resource_type, name,
+			cdata->msg_hdr.resource_id);
+
+		for (i = 0, prev_valid = 0; i < cdata->write_idx; i++) {
+			if (!cdata->kvp[i].valid)
+				continue;
+
+			memcpy(name, &cdata->kvp[i].key, sizeof(uint32_t));
+			pos += scnprintf(buf + pos, buflen - pos,
+					"[key=0x%08X (%s), value=%s",
+					cdata->kvp[i].key, name,
+					(cdata->kvp[i].nbytes ? "0x" : "null"));
+
+			for (j = 0; j < cdata->kvp[i].nbytes; j++)
+				pos += scnprintf(buf + pos, buflen - pos,
+						"%02X ",
+						cdata->kvp[i].value[j]);
+
+			if (cdata->kvp[i].nbytes)
+				pos += scnprintf(buf + pos, buflen - pos, "(");
+
+			for (j = 0; j < cdata->kvp[i].nbytes; j += 4) {
+				value = 0;
+				memcpy(&value, &cdata->kvp[i].value[j],
+					min(sizeof(uint32_t),
+						cdata->kvp[i].nbytes - j));
+				pos += scnprintf(buf + pos, buflen - pos, "%u",
+						value);
+				if (j + 4 < cdata->kvp[i].nbytes)
+					pos += scnprintf(buf + pos,
+						buflen - pos, " ");
+			}
+			if (cdata->kvp[i].nbytes)
+				pos += scnprintf(buf + pos, buflen - pos, ")");
+			pos += scnprintf(buf + pos, buflen - pos, "]");
+			if (prev_valid + 1 < valid_count)
+				pos += scnprintf(buf + pos, buflen - pos, ", ");
+			prev_valid++;
+		}
+	} else if (msm_rpm_debug_mask & MSM_RPM_LOG_REQUEST_PRETTY) {
+		/* Pretty formatting only */
+		memcpy(name, &cdata->msg_hdr.resource_type, sizeof(uint32_t));
+		pos += scnprintf(buf + pos, buflen - pos, " %s %u; ", name,
+				cdata->msg_hdr.resource_id);
+
+		for (i = 0, prev_valid = 0; i < cdata->write_idx; i++) {
+			if (!cdata->kvp[i].valid)
+				continue;
+
+			memcpy(name, &cdata->kvp[i].key, sizeof(uint32_t));
+			pos += scnprintf(buf + pos, buflen - pos, "%s=%s",
+				name, (cdata->kvp[i].nbytes ? "" : "null"));
+
+			for (j = 0; j < cdata->kvp[i].nbytes; j += 4) {
+				value = 0;
+				memcpy(&value, &cdata->kvp[i].value[j],
+					min(sizeof(uint32_t),
+						cdata->kvp[i].nbytes - j));
+				pos += scnprintf(buf + pos, buflen - pos, "%u",
+						value);
+
+				if (j + 4 < cdata->kvp[i].nbytes)
+					pos += scnprintf(buf + pos,
+						buflen - pos, " ");
+			}
+			if (prev_valid + 1 < valid_count)
+				pos += scnprintf(buf + pos, buflen - pos, ", ");
+			prev_valid++;
+		}
+	} else {
+		/* Raw formatting only */
+		pos += scnprintf(buf + pos, buflen - pos,
+			", rsc_type=0x%08X, rsc_id=%u; ",
+			cdata->msg_hdr.resource_type,
+			cdata->msg_hdr.resource_id);
+
+		for (i = 0, prev_valid = 0; i < cdata->write_idx; i++) {
+			if (!cdata->kvp[i].valid)
+				continue;
+
+			pos += scnprintf(buf + pos, buflen - pos,
+					"[key=0x%08X, value=%s",
+					cdata->kvp[i].key,
+					(cdata->kvp[i].nbytes ? "0x" : "null"));
+			for (j = 0; j < cdata->kvp[i].nbytes; j++) {
+				pos += scnprintf(buf + pos, buflen - pos,
+						"%02X",
+						cdata->kvp[i].value[j]);
+				if (j + 1 < cdata->kvp[i].nbytes)
+					pos += scnprintf(buf + pos,
+							buflen - pos, " ");
+			}
+			pos += scnprintf(buf + pos, buflen - pos, "]");
+			if (prev_valid + 1 < valid_count)
+				pos += scnprintf(buf + pos, buflen - pos, ", ");
+			prev_valid++;
+		}
+	}
+
+	pos += scnprintf(buf + pos, buflen - pos, "\n");
+	printk(buf);
+}
+
 static int msm_rpm_send_data(struct msm_rpm_request *cdata,
 		int msg_type, bool noirq)
 {
@@ -546,6 +694,10 @@
 		tmpbuff += cdata->kvp[i].nbytes;
 	}
 
+	if (msm_rpm_debug_mask
+	    & (MSM_RPM_LOG_REQUEST_PRETTY | MSM_RPM_LOG_REQUEST_RAW))
+		msm_rpm_log_request(cdata);
+
 	if (standalone) {
 		for (i = 0; (i < cdata->write_idx); i++)
 			cdata->kvp[i].valid = false;
diff --git a/arch/arm/mach-msm/subsystem_restart.c b/arch/arm/mach-msm/subsystem_restart.c
index 0b6f225..65da903 100644
--- a/arch/arm/mach-msm/subsystem_restart.c
+++ b/arch/arm/mach-msm/subsystem_restart.c
@@ -17,7 +17,6 @@
 #include <linux/uaccess.h>
 #include <linux/module.h>
 #include <linux/fs.h>
-#include <linux/proc_fs.h>
 #include <linux/delay.h>
 #include <linux/list.h>
 #include <linux/io.h>
@@ -25,11 +24,13 @@
 #include <linux/time.h>
 #include <linux/wakelock.h>
 #include <linux/suspend.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
 
 #include <asm/current.h>
 
 #include <mach/peripheral-loader.h>
-#include <mach/scm.h>
 #include <mach/socinfo.h>
 #include <mach/subsystem_notif.h>
 #include <mach/subsystem_restart.h>
@@ -42,30 +43,40 @@
 
 	struct mutex shutdown_lock;
 	struct mutex powerup_lock;
-	struct subsys_data *subsys_ptrs[];
-};
-
-struct restart_wq_data {
-	struct subsys_data *subsys;
-	struct wake_lock ssr_wake_lock;
-	char wlname[64];
-	int use_restart_order;
-	struct work_struct work;
+	struct subsys_device *subsys_ptrs[];
 };
 
 struct restart_log {
 	struct timeval time;
-	struct subsys_data *subsys;
+	struct subsys_device *dev;
 	struct list_head list;
 };
 
-static int restart_level;
+struct subsys_device {
+	struct subsys_desc *desc;
+	struct list_head list;
+	struct wake_lock wake_lock;
+	char wlname[64];
+	struct work_struct work;
+	spinlock_t restart_lock;
+	bool restarting;
+
+	void *notify;
+
+	struct mutex shutdown_lock;
+	struct mutex powerup_lock;
+
+	void *restart_order;
+};
+
 static int enable_ramdumps;
+module_param(enable_ramdumps, int, S_IRUGO | S_IWUSR);
+
 struct workqueue_struct *ssr_wq;
 
 static LIST_HEAD(restart_log_list);
 static LIST_HEAD(subsystem_list);
-static DEFINE_SPINLOCK(subsystem_list_lock);
+static DEFINE_MUTEX(subsystem_list_lock);
 static DEFINE_MUTEX(soc_order_reg_lock);
 static DEFINE_MUTEX(restart_log_mutex);
 
@@ -122,10 +133,7 @@
 static struct subsys_soc_restart_order **restart_orders;
 static int n_restart_orders;
 
-module_param(enable_ramdumps, int, S_IRUGO | S_IWUSR);
-
-static struct subsys_soc_restart_order *_update_restart_order(
-		struct subsys_data *subsys);
+static int restart_level = RESET_SOC;
 
 int get_restart_level()
 {
@@ -148,18 +156,14 @@
 		return ret;
 
 	switch (restart_level) {
-
 	case RESET_SOC:
 	case RESET_SUBSYS_COUPLED:
 	case RESET_SUBSYS_INDEPENDENT:
 		pr_info("Phase %d behavior activated.\n", restart_level);
-	break;
-
+		break;
 	default:
 		restart_level = old_val;
 		return -EINVAL;
-	break;
-
 	}
 	return 0;
 }
@@ -167,62 +171,29 @@
 module_param_call(restart_level, restart_level_set, param_get_int,
 			&restart_level, 0644);
 
-static struct subsys_data *_find_subsystem(const char *subsys_name)
-{
-	struct subsys_data *subsys;
-	unsigned long flags;
-
-	spin_lock_irqsave(&subsystem_list_lock, flags);
-	list_for_each_entry(subsys, &subsystem_list, list)
-		if (!strncmp(subsys->name, subsys_name,
-				SUBSYS_NAME_MAX_LENGTH)) {
-			spin_unlock_irqrestore(&subsystem_list_lock, flags);
-			return subsys;
-		}
-	spin_unlock_irqrestore(&subsystem_list_lock, flags);
-
-	return NULL;
-}
-
-static struct subsys_soc_restart_order *_update_restart_order(
-		struct subsys_data *subsys)
+static struct subsys_soc_restart_order *
+update_restart_order(struct subsys_device *dev)
 {
 	int i, j;
-
-	if (!subsys)
-		return NULL;
-
-	if (!subsys->name)
-		return NULL;
+	struct subsys_soc_restart_order *order;
+	const char *name = dev->desc->name;
+	int len = SUBSYS_NAME_MAX_LENGTH;
 
 	mutex_lock(&soc_order_reg_lock);
 	for (j = 0; j < n_restart_orders; j++) {
-		for (i = 0; i < restart_orders[j]->count; i++)
-			if (!strncmp(restart_orders[j]->subsystem_list[i],
-				subsys->name, SUBSYS_NAME_MAX_LENGTH)) {
-
-					restart_orders[j]->subsys_ptrs[i] =
-						subsys;
-					mutex_unlock(&soc_order_reg_lock);
-					return restart_orders[j];
+		order = restart_orders[j];
+		for (i = 0; i < order->count; i++) {
+			if (!strncmp(order->subsystem_list[i], name, len)) {
+				order->subsys_ptrs[i] = dev;
+				goto found;
 			}
+		}
 	}
-
+	order = NULL;
+found:
 	mutex_unlock(&soc_order_reg_lock);
 
-	return NULL;
-}
-
-static void _send_notification_to_order(struct subsys_data
-			**restart_list, int count,
-			enum subsys_notif_type notif_type)
-{
-	int i;
-
-	for (i = 0; i < count; i++)
-		if (restart_list[i])
-			subsys_notif_queue_notification(
-				restart_list[i]->notif_handle, notif_type);
+	return order;
 }
 
 static int max_restarts;
@@ -231,7 +202,7 @@
 static long max_history_time = 3600;
 module_param(max_history_time, long, 0644);
 
-static void do_epoch_check(struct subsys_data *subsys)
+static void do_epoch_check(struct subsys_device *dev)
 {
 	int n = 0;
 	struct timeval *time_first = NULL, *curr_time;
@@ -251,7 +222,7 @@
 	r_log = kmalloc(sizeof(struct restart_log), GFP_KERNEL);
 	if (!r_log)
 		goto out;
-	r_log->subsys = subsys;
+	r_log->dev = dev;
 	do_gettimeofday(&r_log->time);
 	curr_time = &r_log->time;
 	INIT_LIST_HEAD(&r_log->list);
@@ -289,42 +260,94 @@
 	mutex_unlock(&restart_log_mutex);
 }
 
+static void for_each_subsys_device(struct subsys_device **list, unsigned count,
+		void *data, void (*fn)(struct subsys_device *, void *))
+{
+	while (count--) {
+		struct subsys_device *dev = *list++;
+		if (!dev)
+			continue;
+		fn(dev, data);
+	}
+}
+
+static void __send_notification_to_order(struct subsys_device *dev, void *data)
+{
+	enum subsys_notif_type type = (enum subsys_notif_type)data;
+
+	subsys_notif_queue_notification(dev->notify, type);
+}
+
+static void send_notification_to_order(struct subsys_device **l, unsigned n,
+		enum subsys_notif_type t)
+{
+	for_each_subsys_device(l, n, (void *)t, __send_notification_to_order);
+}
+
+static void subsystem_shutdown(struct subsys_device *dev, void *data)
+{
+	const char *name = dev->desc->name;
+
+	pr_info("[%p]: Shutting down %s\n", current, name);
+	if (dev->desc->shutdown(dev->desc) < 0)
+		panic("subsys-restart: [%p]: Failed to shutdown %s!",
+			current, name);
+}
+
+static void subsystem_ramdump(struct subsys_device *dev, void *data)
+{
+	const char *name = dev->desc->name;
+
+	if (dev->desc->ramdump)
+		if (dev->desc->ramdump(enable_ramdumps, dev->desc) < 0)
+			pr_warn("%s[%p]: Ramdump failed.\n", name, current);
+}
+
+static void subsystem_powerup(struct subsys_device *dev, void *data)
+{
+	const char *name = dev->desc->name;
+
+	pr_info("[%p]: Powering up %s\n", current, name);
+	if (dev->desc->powerup(dev->desc) < 0)
+		panic("[%p]: Failed to powerup %s!", current, name);
+}
+
 static void subsystem_restart_wq_func(struct work_struct *work)
 {
-	struct restart_wq_data *r_work = container_of(work,
-						struct restart_wq_data, work);
-	struct subsys_data **restart_list;
-	struct subsys_data *subsys = r_work->subsys;
+	struct subsys_device *dev = container_of(work,
+						struct subsys_device, work);
+	struct subsys_device **list;
+	struct subsys_desc *desc = dev->desc;
 	struct subsys_soc_restart_order *soc_restart_order = NULL;
-
 	struct mutex *powerup_lock;
 	struct mutex *shutdown_lock;
+	unsigned count;
+	unsigned long flags;
 
-	int i;
-	int restart_list_count = 0;
+	if (restart_level != RESET_SUBSYS_INDEPENDENT)
+		soc_restart_order = dev->restart_order;
 
-	if (r_work->use_restart_order)
-		soc_restart_order = subsys->restart_order;
-
-	/* It's OK to not take the registration lock at this point.
+	/*
+	 * It's OK to not take the registration lock at this point.
 	 * This is because the subsystem list inside the relevant
 	 * restart order is not being traversed.
 	 */
 	if (!soc_restart_order) {
-		restart_list = subsys->single_restart_list;
-		restart_list_count = 1;
-		powerup_lock = &subsys->powerup_lock;
-		shutdown_lock = &subsys->shutdown_lock;
+		list = &dev;
+		count = 1;
+		powerup_lock = &dev->powerup_lock;
+		shutdown_lock = &dev->shutdown_lock;
 	} else {
-		restart_list = soc_restart_order->subsys_ptrs;
-		restart_list_count = soc_restart_order->count;
+		list = soc_restart_order->subsys_ptrs;
+		count = soc_restart_order->count;
 		powerup_lock = &soc_restart_order->powerup_lock;
 		shutdown_lock = &soc_restart_order->shutdown_lock;
 	}
 
 	pr_debug("[%p]: Attempting to get shutdown lock!\n", current);
 
-	/* Try to acquire shutdown_lock. If this fails, these subsystems are
+	/*
+	 * Try to acquire shutdown_lock. If this fails, these subsystems are
 	 * already being restarted - return.
 	 */
 	if (!mutex_trylock(shutdown_lock))
@@ -332,7 +355,8 @@
 
 	pr_debug("[%p]: Attempting to get powerup lock!\n", current);
 
-	/* Now that we've acquired the shutdown lock, either we're the first to
+	/*
+	 * Now that we've acquired the shutdown lock, either we're the first to
 	 * restart these subsystems or some other thread is doing the powerup
 	 * sequence for these subsystems. In the latter case, panic and bail
 	 * out, since a subsystem died in its powerup sequence.
@@ -341,38 +365,23 @@
 		panic("%s[%p]: Subsystem died during powerup!",
 						__func__, current);
 
-	do_epoch_check(subsys);
+	do_epoch_check(dev);
 
-	/* Now it is necessary to take the registration lock. This is because
-	 * the subsystem list in the SoC restart order will be traversed
-	 * and it shouldn't be changed until _this_ restart sequence completes.
+	/*
+	 * It's necessary to take the registration lock because the subsystem
+	 * list in the SoC restart order will be traversed and it shouldn't be
+	 * changed until _this_ restart sequence completes.
 	 */
 	mutex_lock(&soc_order_reg_lock);
 
 	pr_debug("[%p]: Starting restart sequence for %s\n", current,
-			r_work->subsys->name);
+			desc->name);
+	send_notification_to_order(list, count, SUBSYS_BEFORE_SHUTDOWN);
+	for_each_subsys_device(list, count, NULL, subsystem_shutdown);
+	send_notification_to_order(list, count, SUBSYS_AFTER_SHUTDOWN);
 
-	_send_notification_to_order(restart_list,
-				restart_list_count,
-				SUBSYS_BEFORE_SHUTDOWN);
-
-	for (i = 0; i < restart_list_count; i++) {
-
-		if (!restart_list[i])
-			continue;
-
-		pr_info("[%p]: Shutting down %s\n", current,
-			restart_list[i]->name);
-
-		if (restart_list[i]->shutdown(subsys) < 0)
-			panic("subsys-restart: %s[%p]: Failed to shutdown %s!",
-				__func__, current, restart_list[i]->name);
-	}
-
-	_send_notification_to_order(restart_list, restart_list_count,
-				SUBSYS_AFTER_SHUTDOWN);
-
-	/* Now that we've finished shutting down these subsystems, release the
+	/*
+	 * Now that we've finished shutting down these subsystems, release the
 	 * shutdown lock. If a subsystem restart request comes in for a
 	 * subsystem in _this_ restart order after the unlock below, and
 	 * before the powerup lock is released, panic and bail out.
@@ -380,40 +389,14 @@
 	mutex_unlock(shutdown_lock);
 
 	/* Collect ram dumps for all subsystems in order here */
-	for (i = 0; i < restart_list_count; i++) {
-		if (!restart_list[i])
-			continue;
+	for_each_subsys_device(list, count, NULL, subsystem_ramdump);
 
-		if (restart_list[i]->ramdump)
-			if (restart_list[i]->ramdump(enable_ramdumps,
-							subsys) < 0)
-				pr_warn("%s[%p]: Ramdump failed.\n",
-						restart_list[i]->name, current);
-	}
-
-	_send_notification_to_order(restart_list,
-			restart_list_count,
-			SUBSYS_BEFORE_POWERUP);
-
-	for (i = restart_list_count - 1; i >= 0; i--) {
-
-		if (!restart_list[i])
-			continue;
-
-		pr_info("[%p]: Powering up %s\n", current,
-					restart_list[i]->name);
-
-		if (restart_list[i]->powerup(subsys) < 0)
-			panic("%s[%p]: Failed to powerup %s!", __func__,
-				current, restart_list[i]->name);
-	}
-
-	_send_notification_to_order(restart_list,
-				restart_list_count,
-				SUBSYS_AFTER_POWERUP);
+	send_notification_to_order(list, count, SUBSYS_BEFORE_POWERUP);
+	for_each_subsys_device(list, count, NULL, subsystem_powerup);
+	send_notification_to_order(list, count, SUBSYS_AFTER_POWERUP);
 
 	pr_info("[%p]: Restart sequence for %s completed.\n",
-			current, r_work->subsys->name);
+			current, desc->name);
 
 	mutex_unlock(powerup_lock);
 
@@ -422,123 +405,119 @@
 	pr_debug("[%p]: Released powerup lock!\n", current);
 
 out:
-	wake_unlock(&r_work->ssr_wake_lock);
-	wake_lock_destroy(&r_work->ssr_wake_lock);
-	kfree(r_work);
+	spin_lock_irqsave(&dev->restart_lock, flags);
+	wake_unlock(&dev->wake_lock);
+	dev->restarting = false;
+	spin_unlock_irqrestore(&dev->restart_lock, flags);
 }
 
-static void __subsystem_restart(struct subsys_data *subsys)
+static void __subsystem_restart_dev(struct subsys_device *dev)
 {
-	struct restart_wq_data *data = NULL;
-	int rc;
+	struct subsys_desc *desc = dev->desc;
+	unsigned long flags;
 
-	pr_debug("Restarting %s [level=%d]!\n", subsys->name,
+	spin_lock_irqsave(&dev->restart_lock, flags);
+	if (!dev->restarting) {
+		pr_debug("Restarting %s [level=%d]!\n", desc->name,
 				restart_level);
 
-	data = kzalloc(sizeof(struct restart_wq_data), GFP_ATOMIC);
-	if (!data)
-		panic("%s: Unable to allocate memory to restart %s.",
-		      __func__, subsys->name);
-
-	data->subsys = subsys;
-
-	if (restart_level != RESET_SUBSYS_INDEPENDENT)
-		data->use_restart_order = 1;
-
-	snprintf(data->wlname, sizeof(data->wlname), "ssr(%s)", subsys->name);
-	wake_lock_init(&data->ssr_wake_lock, WAKE_LOCK_SUSPEND, data->wlname);
-	wake_lock(&data->ssr_wake_lock);
-
-	INIT_WORK(&data->work, subsystem_restart_wq_func);
-	rc = queue_work(ssr_wq, &data->work);
-	if (rc < 0)
-		panic("%s: Unable to schedule work to restart %s (%d).",
-		     __func__, subsys->name, rc);
+		dev->restarting = true;
+		wake_lock(&dev->wake_lock);
+		queue_work(ssr_wq, &dev->work);
+	}
+	spin_unlock_irqrestore(&dev->restart_lock, flags);
 }
 
-int subsystem_restart(const char *subsys_name)
+int subsystem_restart_dev(struct subsys_device *dev)
 {
-	struct subsys_data *subsys;
-
-	if (!subsys_name) {
-		pr_err("Invalid subsystem name.\n");
-		return -EINVAL;
-	}
+	const char *name = dev->desc->name;
 
 	pr_info("Restart sequence requested for %s, restart_level = %d.\n",
-		subsys_name, restart_level);
-
-	/* List of subsystems is protected by a lock. New subsystems can
-	 * still come in.
-	 */
-	subsys = _find_subsystem(subsys_name);
-
-	if (!subsys) {
-		pr_warn("Unregistered subsystem %s!\n", subsys_name);
-		return -EINVAL;
-	}
+		name, restart_level);
 
 	switch (restart_level) {
 
 	case RESET_SUBSYS_COUPLED:
 	case RESET_SUBSYS_INDEPENDENT:
-		__subsystem_restart(subsys);
+		__subsystem_restart_dev(dev);
 		break;
-
 	case RESET_SOC:
-		panic("subsys-restart: Resetting the SoC - %s crashed.",
-			subsys->name);
+		panic("subsys-restart: Resetting the SoC - %s crashed.", name);
 		break;
-
 	default:
 		panic("subsys-restart: Unknown restart level!\n");
-	break;
-
+		break;
 	}
 
 	return 0;
 }
+EXPORT_SYMBOL(subsystem_restart_dev);
+
+int subsystem_restart(const char *name)
+{
+	struct subsys_device *dev;
+
+	mutex_lock(&subsystem_list_lock);
+	list_for_each_entry(dev, &subsystem_list, list)
+		if (!strncmp(dev->desc->name, name, SUBSYS_NAME_MAX_LENGTH))
+			goto found;
+	dev = NULL;
+found:
+	mutex_unlock(&subsystem_list_lock);
+	if (dev)
+		return subsystem_restart_dev(dev);
+	return -ENODEV;
+}
 EXPORT_SYMBOL(subsystem_restart);
 
-int ssr_register_subsystem(struct subsys_data *subsys)
+struct subsys_device *subsys_register(struct subsys_desc *desc)
 {
-	unsigned long flags;
+	struct subsys_device *dev;
 
-	if (!subsys)
-		goto err;
+	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+	if (!dev)
+		return ERR_PTR(-ENOMEM);
 
-	if (!subsys->name)
-		goto err;
+	dev->desc = desc;
+	dev->notify = subsys_notif_add_subsys(desc->name);
+	dev->restart_order = update_restart_order(dev);
 
-	if (!subsys->powerup || !subsys->shutdown)
-		goto err;
+	snprintf(dev->wlname, sizeof(dev->wlname), "ssr(%s)", desc->name);
+	wake_lock_init(&dev->wake_lock, WAKE_LOCK_SUSPEND, dev->wlname);
+	INIT_WORK(&dev->work, subsystem_restart_wq_func);
+	spin_lock_init(&dev->restart_lock);
 
-	subsys->notif_handle = subsys_notif_add_subsys(subsys->name);
-	subsys->restart_order = _update_restart_order(subsys);
-	subsys->single_restart_list[0] = subsys;
+	mutex_init(&dev->shutdown_lock);
+	mutex_init(&dev->powerup_lock);
 
-	mutex_init(&subsys->shutdown_lock);
-	mutex_init(&subsys->powerup_lock);
+	mutex_lock(&subsystem_list_lock);
+	list_add(&dev->list, &subsystem_list);
+	mutex_unlock(&subsystem_list_lock);
 
-	spin_lock_irqsave(&subsystem_list_lock, flags);
-	list_add(&subsys->list, &subsystem_list);
-	spin_unlock_irqrestore(&subsystem_list_lock, flags);
-
-	return 0;
-
-err:
-	return -EINVAL;
+	return dev;
 }
-EXPORT_SYMBOL(ssr_register_subsystem);
+EXPORT_SYMBOL(subsys_register);
+
+void subsys_unregister(struct subsys_device *dev)
+{
+	if (IS_ERR_OR_NULL(dev))
+		return;
+	mutex_lock(&subsystem_list_lock);
+	list_del(&dev->list);
+	mutex_unlock(&subsystem_list_lock);
+	wake_lock_destroy(&dev->wake_lock);
+	kfree(dev);
+}
+EXPORT_SYMBOL(subsys_unregister);
 
 static int ssr_panic_handler(struct notifier_block *this,
 				unsigned long event, void *ptr)
 {
-	struct subsys_data *subsys;
+	struct subsys_device *dev;
 
-	list_for_each_entry(subsys, &subsystem_list, list)
-		if (subsys->crash_shutdown)
-			subsys->crash_shutdown(subsys);
+	list_for_each_entry(dev, &subsystem_list, list)
+		if (dev->desc->crash_shutdown)
+			dev->desc->crash_shutdown(dev->desc);
 	return NOTIFY_DONE;
 }
 
@@ -595,20 +574,12 @@
 
 static int __init subsys_restart_init(void)
 {
-	int ret = 0;
-
-	restart_level = RESET_SOC;
-
 	ssr_wq = alloc_workqueue("ssr_wq", 0, 0);
-
 	if (!ssr_wq)
 		panic("Couldn't allocate workqueue for subsystem restart.\n");
 
-	ret = ssr_init_soc_restart_orders();
-
-	return ret;
+	return ssr_init_soc_restart_orders();
 }
-
 arch_initcall(subsys_restart_init);
 
 MODULE_DESCRIPTION("Subsystem Restart Driver");
diff --git a/arch/arm/mach-msm/wcnss-ssr-8960.c b/arch/arm/mach-msm/wcnss-ssr-8960.c
index 6e8d57c..4295d9b 100644
--- a/arch/arm/mach-msm/wcnss-ssr-8960.c
+++ b/arch/arm/mach-msm/wcnss-ssr-8960.c
@@ -19,6 +19,7 @@
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/wcnss_wlan.h>
+#include <linux/err.h>
 #include <mach/irqs.h>
 #include <mach/scm.h>
 #include <mach/subsystem_restart.h>
@@ -37,6 +38,7 @@
 static int riva_crash;
 static int ss_restart_inprogress;
 static int enable_riva_ssr;
+static struct subsys_device *riva_8960_dev;
 
 static void smsm_state_cb_hdlr(void *data, uint32_t old_state,
 					uint32_t new_state)
@@ -83,7 +85,7 @@
 	}
 
 	ss_restart_inprogress = true;
-	subsystem_restart("riva");
+	subsystem_restart_dev(riva_8960_dev);
 }
 
 static irqreturn_t riva_wdog_bite_irq_hdlr(int irq, void *dev_id)
@@ -100,7 +102,7 @@
 		panic(MODULE_NAME ": Watchdog bite received from Riva");
 
 	ss_restart_inprogress = true;
-	subsystem_restart("riva");
+	subsystem_restart_dev(riva_8960_dev);
 
 	return IRQ_HANDLED;
 }
@@ -126,7 +128,7 @@
 }
 
 /* Subsystem handlers */
-static int riva_shutdown(const struct subsys_data *subsys)
+static int riva_shutdown(const struct subsys_desc *subsys)
 {
 	pil_force_shutdown("wcnss");
 	flush_delayed_work(&cancel_vote_work);
@@ -135,7 +137,7 @@
 	return 0;
 }
 
-static int riva_powerup(const struct subsys_data *subsys)
+static int riva_powerup(const struct subsys_desc *subsys)
 {
 	struct platform_device *pdev = wcnss_get_platform_device();
 	struct wcnss_wlan_config *pwlanconfig = wcnss_get_wlan_config();
@@ -162,7 +164,7 @@
 static struct ramdump_segment riva_segments[] = {{0x8f200000,
 						0x8f700000 - 0x8f200000} };
 
-static int riva_ramdump(int enable, const struct subsys_data *subsys)
+static int riva_ramdump(int enable, const struct subsys_desc *subsys)
 {
 	pr_debug("%s: enable[%d]\n", MODULE_NAME, enable);
 	if (enable)
@@ -174,14 +176,14 @@
 }
 
 /* Riva crash handler */
-static void riva_crash_shutdown(const struct subsys_data *subsys)
+static void riva_crash_shutdown(const struct subsys_desc *subsys)
 {
 	pr_err("%s: crash shutdown : %d\n", MODULE_NAME, riva_crash);
 	if (riva_crash != true)
 		smsm_riva_reset();
 }
 
-static struct subsys_data riva_8960 = {
+static struct subsys_desc riva_8960 = {
 	.name = "riva",
 	.shutdown = riva_shutdown,
 	.powerup = riva_powerup,
@@ -208,7 +210,10 @@
 
 static int __init riva_restart_init(void)
 {
-	return ssr_register_subsystem(&riva_8960);
+	riva_8960_dev = subsys_register(&riva_8960);
+	if (IS_ERR(riva_8960_dev))
+		return PTR_ERR(riva_8960_dev);
+	return 0;
 }
 
 static int __init riva_ssr_module_init(void)
@@ -253,6 +258,7 @@
 
 static void __exit riva_ssr_module_exit(void)
 {
+	subsys_unregister(riva_8960_dev);
 	free_irq(RIVA_APSS_WDOG_BITE_RESET_RDY_IRQ, NULL);
 }
 
diff --git a/block/test-iosched.c b/block/test-iosched.c
index 3c38734..ce9527f 100644
--- a/block/test-iosched.c
+++ b/block/test-iosched.c
@@ -127,7 +127,7 @@
 	test_pr_info("%s: request %d completed, err=%d",
 	       __func__, test_rq->req_id, err);
 
-	test_rq->req_completed = 1;
+	test_rq->req_completed = true;
 	test_rq->req_result = err;
 
 	check_test_completion();
@@ -204,8 +204,8 @@
 		blk_put_request(rq);
 		return -ENODEV;
 	}
-	test_rq->req_completed = 0;
-	test_rq->req_result = -1;
+	test_rq->req_completed = false;
+	test_rq->req_result = -EINVAL;
 	test_rq->rq = rq;
 	test_rq->is_err_expected = is_err_expcted;
 	rq->elv.priv[0] = (void *)test_rq;
@@ -347,8 +347,8 @@
 	ptd->num_of_write_bios += num_bios;
 	test_rq->req_id = ptd->wr_rd_next_req_id++;
 
-	test_rq->req_completed = 0;
-	test_rq->req_result = -1;
+	test_rq->req_completed = false;
+	test_rq->req_result = -EINVAL;
 	test_rq->rq = rq;
 	test_rq->is_err_expected = is_err_expcted;
 	rq->elv.priv[0] = (void *)test_rq;
@@ -519,10 +519,26 @@
 static void free_test_requests(struct test_data *td)
 {
 	struct test_request *test_rq;
+	struct bio *bio;
+
 	while (!list_empty(&td->test_queue)) {
 		test_rq = list_entry(td->test_queue.next, struct test_request,
 				     queuelist);
 		list_del_init(&test_rq->queuelist);
+		/*
+		 * If the request was not completed we need to free its BIOs
+		 * and remove it from the packed list
+		 */
+		if (!test_rq->req_completed) {
+			test_pr_info(
+				"%s: Freeing memory of an uncompleted request",
+				__func__);
+			list_del_init(&test_rq->rq->queuelist);
+			while ((bio = test_rq->rq->bio) != NULL) {
+				test_rq->rq->bio = bio->bi_next;
+				bio_put(bio);
+			}
+		}
 		blk_put_request(test_rq->rq);
 		kfree(test_rq->bios_buffer);
 		kfree(test_rq);
@@ -606,7 +622,8 @@
 			test_pr_info(
 				"%s: Another test is running, try again later",
 				__func__);
-			return -EINVAL;
+			spin_unlock(&ptd->lock);
+			return -EBUSY;
 		}
 
 		if (ptd->start_sector == 0) {
@@ -698,9 +715,8 @@
 		return -EINVAL;
 
 error:
-	ptd->test_result = TEST_FAILED;
-	ptd->test_info.testcase = 0;
 	post_test(ptd);
+	ptd->test_result = TEST_FAILED;
 	return ret;
 }
 EXPORT_SYMBOL(test_iosched_start_test);
diff --git a/drivers/crypto/msm/qcedev.c b/drivers/crypto/msm/qcedev.c
index 2a191d5..cc6d744 100644
--- a/drivers/crypto/msm/qcedev.c
+++ b/drivers/crypto/msm/qcedev.c
@@ -2098,12 +2098,19 @@
 	return 0;
 };
 
+static struct of_device_id qcedev_match[] = {
+	{	.compatible = "qcom,qcedev",
+	},
+	{}
+};
+
 static struct platform_driver qcedev_plat_driver = {
 	.probe = qcedev_probe,
 	.remove = qcedev_remove,
 	.driver = {
 		.name = "qce",
 		.owner = THIS_MODULE,
+		.of_match_table = qcedev_match,
 	},
 };
 
@@ -2222,7 +2229,7 @@
 MODULE_LICENSE("GPL v2");
 MODULE_AUTHOR("Mona Hossain <mhossain@codeaurora.org>");
 MODULE_DESCRIPTION("Qualcomm DEV Crypto driver");
-MODULE_VERSION("1.26");
+MODULE_VERSION("1.27");
 
 module_init(qcedev_init);
 module_exit(qcedev_exit);
diff --git a/drivers/crypto/msm/qcrypto.c b/drivers/crypto/msm/qcrypto.c
index a41a64b..c11c36e 100644
--- a/drivers/crypto/msm/qcrypto.c
+++ b/drivers/crypto/msm/qcrypto.c
@@ -3260,12 +3260,20 @@
 	return rc;
 };
 
+
+static struct of_device_id qcrypto_match[] = {
+	{	.compatible = "qcom,qcrypto",
+	},
+	{}
+};
+
 static struct platform_driver _qualcomm_crypto = {
 	.probe          = _qcrypto_probe,
 	.remove         = _qcrypto_remove,
 	.driver         = {
 		.owner  = THIS_MODULE,
 		.name   = "qcrypto",
+		.of_match_table = qcrypto_match,
 	},
 };
 
@@ -3364,4 +3372,4 @@
 MODULE_LICENSE("GPL v2");
 MODULE_AUTHOR("Mona Hossain <mhossain@codeaurora.org>");
 MODULE_DESCRIPTION("Qualcomm Crypto driver");
-MODULE_VERSION("1.21");
+MODULE_VERSION("1.22");
diff --git a/drivers/gpu/msm/a3xx_reg.h b/drivers/gpu/msm/a3xx_reg.h
index 2e8964d..8ec9431 100644
--- a/drivers/gpu/msm/a3xx_reg.h
+++ b/drivers/gpu/msm/a3xx_reg.h
@@ -290,6 +290,8 @@
 #define RB_CLEAR_MODE_RESOLVE 1
 #define RB_TILINGMODE_LINEAR 0
 #define RB_REF_NEVER 0
+#define RB_FRAG_LESS 1
+#define RB_REF_ALWAYS 7
 #define RB_STENCIL_KEEP 0
 #define RB_RENDERING_PASS 0
 #define RB_TILINGMODE_32X32 2
@@ -327,6 +329,7 @@
 #define GRAS_SC_SCREEN_SCISSOR_BR_BR_Y 16
 #define GRAS_SC_WINDOW_SCISSOR_BR_BR_X 0
 #define GRAS_SC_WINDOW_SCISSOR_BR_BR_Y 16
+#define GRAS_SU_CTRLMODE_LINEHALFWIDTH 03
 #define HLSQ_CONSTFSPRESERVEDRANGEREG_ENDENTRY 16
 #define HLSQ_CONSTFSPRESERVEDRANGEREG_STARTENTRY 0
 #define HLSQ_CTRL0REG_CHUNKDISABLE 26
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index 6e80907..7720df0 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -544,53 +544,16 @@
 static unsigned int
 a3xx_getchipid(struct kgsl_device *device)
 {
-	unsigned int majorid = 0, minorid = 0, patchid = 0;
+	struct kgsl_device_platform_data *pdata =
+		kgsl_device_get_drvdata(device);
 
 	/*
-	 * We could detect the chipID from the hardware but it takes multiple
-	 * registers to find the right combination. Since we traffic exclusively
-	 * in system on chips, we can be (mostly) confident that a SOC version
-	 * will match a GPU (at this juncture at least).  So do the lazy/quick
-	 * thing and set the chip_id based on the SoC
+	 * All current A3XX chipids are detected at the SOC level. Leave this
+	 * function here to support any future GPUs that have working
+	 * chip ID registers
 	 */
 
-	unsigned int version = socinfo_get_version();
-
-	if (cpu_is_apq8064()) {
-
-		/* A320 */
-		majorid = 2;
-		minorid = 0;
-
-		/*
-		 * V1.1 has some GPU work arounds that we need to communicate
-		 * up to user space via the patchid
-		 */
-
-		if ((SOCINFO_VERSION_MAJOR(version) == 1) &&
-			(SOCINFO_VERSION_MINOR(version) == 1))
-			patchid = 1;
-		else
-			patchid = 0;
-	} else if (cpu_is_msm8930() || cpu_is_msm8930aa() || cpu_is_msm8627()) {
-
-		/* A305 */
-		majorid = 0;
-		minorid = 5;
-
-		/*
-		 * V1.2 has some GPU work arounds that we need to communicate
-		 * up to user space via the patchid
-		 */
-
-		if ((SOCINFO_VERSION_MAJOR(version) == 1) &&
-			(SOCINFO_VERSION_MINOR(version) == 2))
-			patchid = 2;
-		else
-			patchid = 0;
-	}
-
-	return (0x03 << 24) | (majorid << 16) | (minorid << 8) | patchid;
+	return pdata->chipid;
 }
 
 static unsigned int
@@ -598,7 +561,13 @@
 {
 	unsigned int chipid = 0;
 	unsigned int coreid, majorid, minorid, patchid, revid;
-	uint32_t soc_platform_version = socinfo_get_version();
+	struct kgsl_device_platform_data *pdata =
+		kgsl_device_get_drvdata(device);
+
+	/* If the chip id is set at the platform level, then just use that */
+
+	if (pdata->chipid != 0)
+		return pdata->chipid;
 
 	adreno_regread(device, REG_RBBM_PERIPHID1, &coreid);
 	adreno_regread(device, REG_RBBM_PERIPHID2, &majorid);
@@ -608,7 +577,7 @@
 	* adreno 22x gpus are indicated by coreid 2,
 	* but REG_RBBM_PERIPHID1 always contains 0 for this field
 	*/
-	if (cpu_is_msm8960() || cpu_is_msm8x60())
+	if (cpu_is_msm8x60())
 		chipid = 2 << 24;
 	else
 		chipid = (coreid & 0xF) << 24;
@@ -620,13 +589,9 @@
 	patchid = ((revid >> 16) & 0xFF);
 
 	/* 8x50 returns 0 for patch release, but it should be 1 */
-	/* 8960v3 returns 5 for patch release, but it should be 6 */
 	/* 8x25 returns 0 for minor id, but it should be 1 */
 	if (cpu_is_qsd8x50())
 		patchid = 1;
-	else if (cpu_is_msm8960() &&
-			SOCINFO_VERSION_MAJOR(soc_platform_version) == 3)
-		patchid = 6;
 	else if (cpu_is_msm8625() && minorid == 0)
 		minorid = 1;
 
@@ -638,11 +603,18 @@
 static unsigned int
 adreno_getchipid(struct kgsl_device *device)
 {
-	if (cpu_is_apq8064() || cpu_is_msm8930() || cpu_is_msm8930aa() ||
-	    cpu_is_msm8627())
-		return a3xx_getchipid(device);
-	else
+	struct kgsl_device_platform_data *pdata =
+		kgsl_device_get_drvdata(device);
+
+	/*
+	 * All A3XX chipsets will have pdata set, so assume !pdata->chipid is
+	 * an A2XX processor
+	 */
+
+	if (pdata->chipid == 0 || ADRENO_CHIPID_MAJOR(pdata->chipid) == 2)
 		return a2xx_getchipid(device);
+	else
+		return a3xx_getchipid(device);
 }
 
 static inline bool _rev_match(unsigned int id, unsigned int entry)
@@ -657,10 +629,10 @@
 
 	adreno_dev->chip_id = adreno_getchipid(&adreno_dev->dev);
 
-	core = (adreno_dev->chip_id >> 24) & 0xff;
-	major = (adreno_dev->chip_id >> 16) & 0xff;
-	minor = (adreno_dev->chip_id >> 8) & 0xff;
-	patchid = (adreno_dev->chip_id & 0xff);
+	core = ADRENO_CHIPID_CORE(adreno_dev->chip_id);
+	major = ADRENO_CHIPID_MAJOR(adreno_dev->chip_id);
+	minor = ADRENO_CHIPID_MINOR(adreno_dev->chip_id);
+	patchid = ADRENO_CHIPID_PATCH(adreno_dev->chip_id);
 
 	for (i = 0; i < ARRAY_SIZE(adreno_gpulist); i++) {
 		if (core == adreno_gpulist[i].core &&
diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h
index e1d1eb9..04dc3d6 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -24,6 +24,11 @@
 #define ADRENO_DEVICE(device) \
 		KGSL_CONTAINER_OF(device, struct adreno_device, dev)
 
+#define ADRENO_CHIPID_CORE(_id) (((_id) >> 24) & 0xFF)
+#define ADRENO_CHIPID_MAJOR(_id) (((_id) >> 16) & 0xFF)
+#define ADRENO_CHIPID_MINOR(_id) (((_id) >> 8) & 0xFF)
+#define ADRENO_CHIPID_PATCH(_id) ((_id) & 0xFF)
+
 /* Flags to control command packet settings */
 #define KGSL_CMD_FLAGS_NONE             0x00000000
 #define KGSL_CMD_FLAGS_PMODE		0x00000001
diff --git a/drivers/gpu/msm/adreno_a3xx.c b/drivers/gpu/msm/adreno_a3xx.c
index 152fc76..bb89067 100644
--- a/drivers/gpu/msm/adreno_a3xx.c
+++ b/drivers/gpu/msm/adreno_a3xx.c
@@ -1236,12 +1236,13 @@
 	*cmds++ = CP_REG(A3XX_HLSQ_CONTROL_0_REG);
 	/* HLSQ_CONTROL_0_REG */
 	*cmds++ = _SET(HLSQ_CTRL0REG_FSTHREADSIZE, HLSQ_FOUR_PIX_QUADS) |
+		_SET(HLSQ_CTRL0REG_FSSUPERTHREADENABLE, 1) |
 		_SET(HLSQ_CTRL0REG_SPSHADERRESTART, 1) |
 		_SET(HLSQ_CTRL0REG_CHUNKDISABLE, 1) |
-		_SET(HLSQ_CTRL0REG_SPCONSTFULLUPDATE, 1) |
-		_SET(HLSQ_CTRL0REG_TPFULLUPDATE, 1);
+		_SET(HLSQ_CTRL0REG_SPCONSTFULLUPDATE, 1);
 	/* HLSQ_CONTROL_1_REG */
-	*cmds++ = _SET(HLSQ_CTRL1REG_VSTHREADSIZE, HLSQ_TWO_VTX_QUADS);
+	*cmds++ = _SET(HLSQ_CTRL1REG_VSTHREADSIZE, HLSQ_TWO_VTX_QUADS) |
+		_SET(HLSQ_CTRL1REG_VSSUPERTHREADENABLE, 1);
 	/* HLSQ_CONTROL_2_REG */
 	*cmds++ = _SET(HLSQ_CTRL2REG_PRIMALLOCTHRESHOLD, 31);
 	/* HLSQ_CONTROL3_REG */
@@ -1268,6 +1269,9 @@
 	*cmds++ = 0x00000240;
 	*cmds++ = 0x00000000;
 
+	*cmds++ = cp_type0_packet(A3XX_VFD_PERFCOUNTER0_SELECT, 1);
+	*cmds++ = 0x00000000;
+
 	/* Texture memobjs */
 	*cmds++ = cp_type3_packet(CP_LOAD_STATE, 6);
 	*cmds++ = (16 << CP_LOADSTATE_DSTOFFSET_SHIFT)
@@ -1281,6 +1285,9 @@
 	*cmds++ = (shadow->pitch*4*8) << 9;
 	*cmds++ = 0x00000000;
 
+	*cmds++ = cp_type0_packet(A3XX_VFD_PERFCOUNTER0_SELECT, 1);
+	*cmds++ = 0x00000000;
+
 	/* Mipmap bases */
 	*cmds++ = cp_type3_packet(CP_LOAD_STATE, 16);
 	*cmds++ = (224 << CP_LOADSTATE_DSTOFFSET_SHIFT)
@@ -1304,6 +1311,9 @@
 	*cmds++ = 0x00000000;
 	*cmds++ = 0x00000000;
 
+	*cmds++ = cp_type0_packet(A3XX_VFD_PERFCOUNTER0_SELECT, 1);
+	*cmds++ = 0x00000000;
+
 	*cmds++ = cp_type3_packet(CP_SET_CONSTANT, 5);
 	*cmds++ = CP_REG(A3XX_HLSQ_VS_CONTROL_REG);
 	/* HLSQ_VS_CONTROL_REG */
@@ -1377,9 +1387,11 @@
 	*cmds++ = _SET(SP_FSCTRLREG0_FSTHREADMODE, SP_MULTI) |
 		_SET(SP_FSCTRLREG0_FSINSTRBUFFERMODE, SP_BUFFER_MODE) |
 		_SET(SP_FSCTRLREG0_FSICACHEINVALID, 1) |
-		_SET(SP_FSCTRLREG0_FSFULLREGFOOTPRINT, 2) |
+		_SET(SP_FSCTRLREG0_FSHALFREGFOOTPRINT, 1) |
+		_SET(SP_FSCTRLREG0_FSFULLREGFOOTPRINT, 1) |
 		_SET(SP_FSCTRLREG0_FSINOUTREGOVERLAP, 1) |
 		_SET(SP_FSCTRLREG0_FSTHREADSIZE, SP_FOUR_PIX_QUADS) |
+		_SET(SP_FSCTRLREG0_FSSUPERTHREADMODE, 1) |
 		_SET(SP_FSCTRLREG0_PIXLODENABLE, 1) |
 		_SET(SP_FSCTRLREG0_FSLENGTH, 2);
 	/* SP_FS_CTRL_REG1 */
@@ -1388,7 +1400,7 @@
 		_SET(SP_FSCTRLREG1_HALFPRECVAROFFSET, 63);
 	/* SP_FS_OBJ_OFFSET_REG */
 	*cmds++ = _SET(SP_OBJOFFSETREG_CONSTOBJECTSTARTOFFSET, 128) |
-		_SET(SP_OBJOFFSETREG_SHADEROBJOFFSETINIC, 1);
+		_SET(SP_OBJOFFSETREG_SHADEROBJOFFSETINIC, 126);
 	/* SP_FS_OBJ_START_REG */
 	*cmds++ = 0x00000000;
 
@@ -1407,7 +1419,7 @@
 	*cmds++ = cp_type3_packet(CP_SET_CONSTANT, 5);
 	*cmds++ = CP_REG(A3XX_SP_FS_MRT_REG_0);
 	/* SP_FS_MRT_REG0 */
-	*cmds++ = _SET(SP_FSMRTREG_REGID, 4);
+	*cmds++ = _SET(SP_FSMRTREG_PRECISION, 1);
 	/* SP_FS_MRT_REG1 */
 	*cmds++ = 0;
 	/* SP_FS_MRT_REG2 */
@@ -1504,7 +1516,8 @@
 	*cmds++ = cp_type3_packet(CP_SET_CONSTANT, 2);
 	*cmds++ = CP_REG(A3XX_SP_SP_CTRL_REG);
 	/* SP_SP_CTRL_REG */
-	*cmds++ = _SET(SP_SPCTRLREG_SLEEPMODE, 1);
+	*cmds++ = _SET(SP_SPCTRLREG_SLEEPMODE, 1) |
+		_SET(SP_SPCTRLREG_LOMODE, 1);
 
 	/* Load vertex shader */
 	*cmds++ = cp_type3_packet(CP_LOAD_STATE, 10);
@@ -1515,7 +1528,7 @@
 	*cmds++ = (HLSQ_SP_VS_INSTR << CP_LOADSTATE_STATETYPE_SHIFT)
 		| (0 << CP_LOADSTATE_EXTSRCADDR_SHIFT);
 	/* (sy)end; */
-	*cmds++ = 0x00000000; *cmds++ = 0x13000000;
+	*cmds++ = 0x00000000; *cmds++ = 0x13001000;
 	/* nop; */
 	*cmds++ = 0x00000000; *cmds++ = 0x00000000;
 	/* nop; */
@@ -1523,6 +1536,13 @@
 	/* nop; */
 	*cmds++ = 0x00000000; *cmds++ = 0x00000000;
 
+	*cmds++ = cp_type0_packet(A3XX_VFD_PERFCOUNTER0_SELECT, 1);
+	*cmds++ = 0x00000000;
+
+	*cmds++ = cp_type3_packet(CP_WAIT_FOR_IDLE, 1);
+	*cmds++ = 0x00000000;
+
+
 	/* Load fragment shader */
 	*cmds++ = cp_type3_packet(CP_LOAD_STATE, 18);
 	*cmds++ = (0 << CP_LOADSTATE_DSTOFFSET_SHIFT)
@@ -1532,21 +1552,27 @@
 	*cmds++ = (HLSQ_SP_FS_INSTR << CP_LOADSTATE_STATETYPE_SHIFT)
 		| (0 << CP_LOADSTATE_EXTSRCADDR_SHIFT);
 	/* (sy)(rpt1)bary.f (ei)r0.z, (r)0, r0.x; */
-	*cmds++ = 0x00002000; *cmds++ = 0x57368902;
+	*cmds++ = 0x00002000; *cmds++ = 0x57309902;
 	/* (rpt5)nop; */
 	*cmds++ = 0x00000000; *cmds++ = 0x00000500;
 	/* sam (f32)r0.xyzw, r0.z, s#0, t#0; */
 	*cmds++ = 0x00000005; *cmds++ = 0xa0c01f00;
 	/* (sy)mov.f32f32 r1.x, r0.x; */
-	*cmds++ = 0x00000000; *cmds++ = 0x30044004;
+	*cmds++ = 0x00000000; *cmds++ = 0x30040b00;
 	/* mov.f32f32 r1.y, r0.y; */
-	*cmds++ = 0x00000001; *cmds++ = 0x20044005;
-	/* mov.f32f32 r1.z, r0.z; */
-	*cmds++ = 0x00000002; *cmds++ = 0x20044006;
-	/* mov.f32f32 r1.w, r0.w; */
-	*cmds++ = 0x00000003; *cmds++ = 0x20044007;
-	/* end; */
 	*cmds++ = 0x00000000; *cmds++ = 0x03000000;
+	/* mov.f32f32 r1.z, r0.z; */
+	*cmds++ = 0x00000000; *cmds++ = 0x00000000;
+	/* mov.f32f32 r1.w, r0.w; */
+	*cmds++ = 0x00000000; *cmds++ = 0x00000000;
+	/* end; */
+	*cmds++ = 0x00000000; *cmds++ = 0x00000000;
+
+	*cmds++ = cp_type0_packet(A3XX_VFD_PERFCOUNTER0_SELECT, 1);
+	*cmds++ = 0x00000000;
+
+	*cmds++ = cp_type3_packet(CP_WAIT_FOR_IDLE, 1);
+	*cmds++ = 0x00000000;
 
 	*cmds++ = cp_type3_packet(CP_SET_CONSTANT, 3);
 	*cmds++ = CP_REG(A3XX_VFD_CONTROL_0);
@@ -1599,16 +1625,16 @@
 	*cmds++ = cp_type3_packet(CP_SET_CONSTANT, 2);
 	*cmds++ = CP_REG(A3XX_RB_DEPTH_CONTROL);
 	/* RB_DEPTH_CONTROL */
-	*cmds++ = _SET(RB_DEPTHCONTROL_Z_TEST_FUNC, RB_FRAG_NEVER);
+	*cmds++ = _SET(RB_DEPTHCONTROL_Z_TEST_FUNC, RB_FRAG_LESS);
 
 	*cmds++ = cp_type3_packet(CP_SET_CONSTANT, 2);
 	*cmds++ = CP_REG(A3XX_RB_STENCIL_CONTROL);
 	/* RB_STENCIL_CONTROL */
-	*cmds++ = _SET(RB_STENCILCONTROL_STENCIL_FUNC, RB_REF_NEVER) |
+	*cmds++ = _SET(RB_STENCILCONTROL_STENCIL_FUNC, RB_REF_ALWAYS) |
 		_SET(RB_STENCILCONTROL_STENCIL_FAIL, RB_STENCIL_KEEP) |
 		_SET(RB_STENCILCONTROL_STENCIL_ZPASS, RB_STENCIL_KEEP) |
 		_SET(RB_STENCILCONTROL_STENCIL_ZFAIL, RB_STENCIL_KEEP) |
-		_SET(RB_STENCILCONTROL_STENCIL_FUNC_BF, RB_REF_NEVER) |
+		_SET(RB_STENCILCONTROL_STENCIL_FUNC_BF, RB_REF_ALWAYS) |
 		_SET(RB_STENCILCONTROL_STENCIL_FAIL_BF, RB_STENCIL_KEEP) |
 		_SET(RB_STENCILCONTROL_STENCIL_ZPASS_BF, RB_STENCIL_KEEP) |
 		_SET(RB_STENCILCONTROL_STENCIL_ZFAIL_BF, RB_STENCIL_KEEP);
@@ -1634,9 +1660,8 @@
 	*cmds++ = cp_type3_packet(CP_SET_CONSTANT, 2);
 	*cmds++ = CP_REG(A3XX_RB_MRT_CONTROL0);
 	/* RB_MRT_CONTROL0 */
-	*cmds++ = _SET(RB_MRTCONTROL_READ_DEST_ENABLE, 1) |
-		_SET(RB_MRTCONTROL_ROP_CODE, 12) |
-		_SET(RB_MRTCONTROL_DITHER_MODE, RB_DITHER_ALWAYS) |
+	*cmds++ = _SET(RB_MRTCONTROL_ROP_CODE, 12) |
+		_SET(RB_MRTCONTROL_DITHER_MODE, RB_DITHER_DISABLE) |
 		_SET(RB_MRTCONTROL_COMPONENT_ENABLE, 0xF);
 
 	*cmds++ = cp_type3_packet(CP_SET_CONSTANT, 3);
@@ -1651,7 +1676,8 @@
 		_SET(RB_MRTBLENDCONTROL_CLAMP_ENABLE, 1);
 	/* RB_MRT_CONTROL1 */
 	*cmds++ = _SET(RB_MRTCONTROL_READ_DEST_ENABLE, 1) |
-		_SET(RB_MRTCONTROL_DITHER_MODE, RB_DITHER_DISABLE) |
+		_SET(RB_MRTCONTROL_ROP_CODE, 12) |
+		_SET(RB_MRTCONTROL_DITHER_MODE, RB_DITHER_ALWAYS) |
 		_SET(RB_MRTCONTROL_COMPONENT_ENABLE, 0xF);
 
 	*cmds++ = cp_type3_packet(CP_SET_CONSTANT, 3);
@@ -1666,7 +1692,8 @@
 		_SET(RB_MRTBLENDCONTROL_CLAMP_ENABLE, 1);
 	/* RB_MRT_CONTROL2 */
 	*cmds++ = _SET(RB_MRTCONTROL_READ_DEST_ENABLE, 1) |
-		_SET(RB_MRTCONTROL_DITHER_MODE, RB_DITHER_DISABLE) |
+		_SET(RB_MRTCONTROL_ROP_CODE, 12) |
+		_SET(RB_MRTCONTROL_DITHER_MODE, RB_DITHER_ALWAYS) |
 		_SET(RB_MRTCONTROL_COMPONENT_ENABLE, 0xF);
 
 	*cmds++ = cp_type3_packet(CP_SET_CONSTANT, 3);
@@ -1681,7 +1708,8 @@
 		_SET(RB_MRTBLENDCONTROL_CLAMP_ENABLE, 1);
 	/* RB_MRT_CONTROL3 */
 	*cmds++ = _SET(RB_MRTCONTROL_READ_DEST_ENABLE, 1) |
-		_SET(RB_MRTCONTROL_DITHER_MODE, RB_DITHER_DISABLE) |
+		_SET(RB_MRTCONTROL_ROP_CODE, 12) |
+		_SET(RB_MRTCONTROL_DITHER_MODE, RB_DITHER_ALWAYS) |
 		_SET(RB_MRTCONTROL_COMPONENT_ENABLE, 0xF);
 
 	*cmds++ = cp_type3_packet(CP_SET_CONSTANT, 2);
@@ -1700,7 +1728,7 @@
 	/* VFD_INDEX_MIN */
 	*cmds++ = 0x00000000;
 	/* VFD_INDEX_MAX */
-	*cmds++ = 0xFFFFFFFF;
+	*cmds++ = 340;
 	/* VFD_INDEX_OFFSET */
 	*cmds++ = 0x00000000;
 	/* TPL1_TP_VS_TEX_OFFSET */
@@ -1709,7 +1737,7 @@
 	*cmds++ = cp_type3_packet(CP_SET_CONSTANT, 2);
 	*cmds++ = CP_REG(A3XX_VFD_VS_THREADING_THRESHOLD);
 	/* VFD_VS_THREADING_THRESHOLD */
-	*cmds++ = _SET(VFD_THREADINGTHRESHOLD_RESERVED6, 12) |
+	*cmds++ = _SET(VFD_THREADINGTHRESHOLD_REGID_THRESHOLD, 15) |
 		_SET(VFD_THREADINGTHRESHOLD_REGID_VTXCNT, 252);
 
 	*cmds++ = cp_type3_packet(CP_SET_CONSTANT, 2);
@@ -1734,7 +1762,7 @@
 	*cmds++ = cp_type3_packet(CP_SET_CONSTANT, 2);
 	*cmds++ = CP_REG(A3XX_GRAS_SU_MODE_CONTROL);
 	/* GRAS_SU_MODE_CONTROL */
-	*cmds++ = 0x00000000;
+	*cmds++ = _SET(GRAS_SU_CTRLMODE_LINEHALFWIDTH, 2);
 
 	*cmds++ = cp_type3_packet(CP_SET_CONSTANT, 3);
 	*cmds++ = CP_REG(A3XX_GRAS_SC_WINDOW_SCISSOR_TL);
@@ -1790,6 +1818,46 @@
 		PC_DRAW_TRIANGLES) |
 		_SET(PC_PRIM_VTX_CONTROL_PROVOKING_VTX_LAST, 1);
 
+
+	/* oxili_generate_context_roll_packets */
+	*cmds++ = cp_type0_packet(A3XX_SP_VS_CTRL_REG0, 1);
+	*cmds++ = 0x00000400;
+
+	*cmds++ = cp_type0_packet(A3XX_SP_FS_CTRL_REG0, 1);
+	*cmds++ = 0x00000400;
+
+	*cmds++ = cp_type0_packet(A3XX_SP_VS_PVT_MEM_SIZE_REG, 1);
+	*cmds++ = 0x00008000; /* SP_VS_MEM_SIZE_REG */
+
+	*cmds++ = cp_type0_packet(A3XX_SP_FS_PVT_MEM_SIZE_REG, 1);
+	*cmds++ = 0x00008000; /* SP_FS_MEM_SIZE_REG */
+
+	/* Clear cache invalidate bit when re-loading the shader control regs */
+	*cmds++ = cp_type0_packet(A3XX_SP_VS_CTRL_REG0, 1);
+	*cmds++ = _SET(SP_VSCTRLREG0_VSTHREADMODE, SP_MULTI) |
+		_SET(SP_VSCTRLREG0_VSINSTRBUFFERMODE, SP_BUFFER_MODE) |
+		_SET(SP_VSCTRLREG0_VSFULLREGFOOTPRINT, 2) |
+		_SET(SP_VSCTRLREG0_VSTHREADSIZE, SP_TWO_VTX_QUADS) |
+		_SET(SP_VSCTRLREG0_VSLENGTH, 1);
+
+	*cmds++ = cp_type0_packet(A3XX_SP_FS_CTRL_REG0, 1);
+	*cmds++ = _SET(SP_FSCTRLREG0_FSTHREADMODE, SP_MULTI) |
+		_SET(SP_FSCTRLREG0_FSINSTRBUFFERMODE, SP_BUFFER_MODE) |
+		_SET(SP_FSCTRLREG0_FSHALFREGFOOTPRINT, 1) |
+		_SET(SP_FSCTRLREG0_FSFULLREGFOOTPRINT, 1) |
+		_SET(SP_FSCTRLREG0_FSINOUTREGOVERLAP, 1) |
+		_SET(SP_FSCTRLREG0_FSTHREADSIZE, SP_FOUR_PIX_QUADS) |
+		_SET(SP_FSCTRLREG0_FSSUPERTHREADMODE, 1) |
+		_SET(SP_FSCTRLREG0_FSLENGTH, 2);
+
+	*cmds++ = cp_type0_packet(A3XX_SP_VS_PVT_MEM_SIZE_REG, 1);
+	*cmds++ = 0x00000000;		 /* SP_VS_MEM_SIZE_REG */
+
+	*cmds++ = cp_type0_packet(A3XX_SP_FS_PVT_MEM_SIZE_REG, 1);
+	*cmds++ = 0x00000000;		 /* SP_FS_MEM_SIZE_REG */
+
+	/* end oxili_generate_context_roll_packets */
+
 	*cmds++ = cp_type3_packet(CP_DRAW_INDX, 3);
 	*cmds++ = 0x00000000; /* Viz query info */
 	*cmds++ = BUILD_PC_DRAW_INITIATOR(PC_DI_PT_RECTLIST,
@@ -1804,6 +1872,7 @@
 	return cmds;
 }
 
+
 static void build_regrestore_cmds(struct adreno_device *adreno_dev,
 				  struct adreno_context *drawctxt)
 {
diff --git a/drivers/gpu/msm/kgsl.h b/drivers/gpu/msm/kgsl.h
index 7ffa83b..8a3345b 100644
--- a/drivers/gpu/msm/kgsl.h
+++ b/drivers/gpu/msm/kgsl.h
@@ -23,6 +23,8 @@
 #include <linux/regulator/consumer.h>
 #include <linux/mm.h>
 
+#include <mach/kgsl.h>
+
 #define KGSL_NAME "kgsl"
 
 /* The number of memstore arrays limits the number of contexts allowed.
diff --git a/drivers/iommu/msm_iommu-v2.c b/drivers/iommu/msm_iommu-v2.c
index 6e62e60..26e967d 100644
--- a/drivers/iommu/msm_iommu-v2.c
+++ b/drivers/iommu/msm_iommu-v2.c
@@ -128,7 +128,7 @@
 	return ret;
 }
 
-static void __reset_iommu(void __iomem *base)
+static void __reset_iommu(void __iomem *base, int smt_size)
 {
 	int i;
 
@@ -143,15 +143,15 @@
 	SET_SCR1(base, 0);
 	SET_SSDR_N(base, 0, 0);
 
-	for (i = 0; i < MAX_NUM_SMR; i++)
+	for (i = 0; i < smt_size; i++)
 		SET_SMR_VALID(base, i, 0);
 
 	mb();
 }
 
-static void __program_iommu(void __iomem *base)
+static void __program_iommu(void __iomem *base, int smt_size)
 {
-	__reset_iommu(base);
+	__reset_iommu(base, smt_size);
 
 	SET_CR0_SMCFCFG(base, 1);
 	SET_CR0_USFCFG(base, 1);
@@ -182,7 +182,7 @@
 
 static void __program_context(void __iomem *base, int ctx, int ncb,
 				phys_addr_t pgtable, int redirect,
-				u32 *sids, int len)
+				u32 *sids, int len, int smt_size)
 {
 	unsigned int prrr, nmrr;
 	unsigned int pn;
@@ -227,10 +227,10 @@
 
 	/* Program the M2V tables for this context */
 	for (i = 0; i < len / sizeof(*sids); i++) {
-		for (; num < MAX_NUM_SMR; num++)
+		for (; num < smt_size; num++)
 			if (GET_SMR_VALID(base, num) == 0)
 				break;
-		BUG_ON(num >= MAX_NUM_SMR);
+		BUG_ON(num >= smt_size);
 
 		SET_SMR_VALID(base, num, 1);
 		SET_SMR_MASK(base, num, 0);
@@ -346,8 +346,7 @@
 	struct msm_iommu_drvdata *iommu_drvdata;
 	struct msm_iommu_ctx_drvdata *ctx_drvdata;
 	struct msm_iommu_ctx_drvdata *tmp_drvdata;
-	u32 sids[MAX_NUM_SMR];
-	int len = 0, ret;
+	int ret;
 
 	mutex_lock(&msm_iommu_lock);
 
@@ -375,14 +374,6 @@
 			goto fail;
 		}
 
-	of_get_property(dev->of_node, "qcom,iommu-ctx-sids", &len);
-	BUG_ON(len >= sizeof(sids));
-	if (of_property_read_u32_array(dev->of_node, "qcom,iommu-ctx-sids",
-					sids, len / sizeof(*sids))) {
-		ret = -EINVAL;
-		goto fail;
-	}
-
 	ret = regulator_enable(iommu_drvdata->gdsc);
 	if (ret)
 		goto fail;
@@ -394,11 +385,12 @@
 	}
 
 	if (!msm_iommu_ctx_attached(dev->parent))
-		__program_iommu(iommu_drvdata->base);
+		__program_iommu(iommu_drvdata->base, iommu_drvdata->nsmr);
 
 	__program_context(iommu_drvdata->base, ctx_drvdata->num,
 		iommu_drvdata->ncb, __pa(priv->pt.fl_table),
-		priv->pt.redirect, sids, len);
+		priv->pt.redirect, ctx_drvdata->sids, ctx_drvdata->nsid,
+		iommu_drvdata->nsmr);
 	__disable_clocks(iommu_drvdata);
 
 	list_add(&(ctx_drvdata->attached_elm), &priv->list_attached);
diff --git a/drivers/iommu/msm_iommu_dev-v2.c b/drivers/iommu/msm_iommu_dev-v2.c
index 87e1a46..d3a088a 100644
--- a/drivers/iommu/msm_iommu_dev-v2.c
+++ b/drivers/iommu/msm_iommu_dev-v2.c
@@ -33,12 +33,25 @@
 				struct msm_iommu_drvdata *drvdata)
 {
 	struct device_node *child;
-	int ret;
+	int ret = 0;
+	u32 nsmr;
 
 	ret = device_move(&pdev->dev, &msm_iommu_root_dev->dev, DPM_ORDER_NONE);
 	if (ret)
-		return ret;
+		goto fail;
 
+	ret = of_property_read_u32(pdev->dev.of_node, "qcom,iommu-smt-size",
+				   &nsmr);
+	if (ret)
+		goto fail;
+
+	if (nsmr > MAX_NUM_SMR) {
+		pr_err("Invalid SMT size: %d\n", nsmr);
+		ret = -EINVAL;
+		goto fail;
+	}
+
+	drvdata->nsmr = nsmr;
 	for_each_child_of_node(pdev->dev.of_node, child) {
 		drvdata->ncb++;
 		if (!of_platform_device_create(child, NULL, &pdev->dev))
@@ -46,7 +59,8 @@
 	}
 
 	drvdata->name = dev_name(&pdev->dev);
-	return 0;
+fail:
+	return ret;
 }
 
 static atomic_t msm_iommu_next_id = ATOMIC_INIT(-1);
@@ -149,6 +163,7 @@
 {
 	struct resource *r, rp;
 	int irq, ret;
+	u32 nsid;
 
 	irq = platform_get_irq(pdev, 0);
 	if (irq > 0) {
@@ -181,6 +196,19 @@
 					&ctx_drvdata->name))
 		ctx_drvdata->name = dev_name(&pdev->dev);
 
+	if (!of_get_property(pdev->dev.of_node, "qcom,iommu-ctx-sids", &nsid))
+		return -EINVAL;
+
+	if (nsid >= sizeof(ctx_drvdata->sids))
+		return -EINVAL;
+
+	if (of_property_read_u32_array(pdev->dev.of_node, "qcom,iommu-ctx-sids",
+				       ctx_drvdata->sids,
+				       nsid / sizeof(*ctx_drvdata->sids))) {
+		return -EINVAL;
+	}
+	ctx_drvdata->nsid = nsid;
+
 	return 0;
 }
 
diff --git a/drivers/media/video/msm/Makefile b/drivers/media/video/msm/Makefile
index 5703d88..eb45271 100644
--- a/drivers/media/video/msm/Makefile
+++ b/drivers/media/video/msm/Makefile
@@ -12,10 +12,11 @@
   EXTRA_CFLAGS += -Idrivers/media/video/msm/actuators
   EXTRA_CFLAGS += -Idrivers/media/video/msm/server
   obj-$(CONFIG_MSM_CAMERA) += msm_isp.o msm.o msm_mem.o msm_mctl.o msm_mctl_buf.o msm_mctl_pp.o msm_vfe_stats_buf.o
-  obj-$(CONFIG_MSM_CAMERA) += server/ eeprom/ sensors/ actuators/ csi/
+  obj-$(CONFIG_MSM_CAMERA) += server/
+  obj-$(CONFIG_MSM_CAM_IRQ_ROUTER) += msm_camirq_router.o
+  obj-$(CONFIG_MSM_CAMERA) += eeprom/ sensors/ actuators/ csi/
   obj-$(CONFIG_MSM_CPP) += cpp/
   obj-$(CONFIG_MSM_CAMERA) += msm_gesture.o
-  obj-$(CONFIG_MSM_CAM_IRQ_ROUTER) += msm_camirq_router.o
 else
   obj-$(CONFIG_MSM_CAMERA) += msm_camera.o
 endif
diff --git a/drivers/media/video/msm/io/msm_camera_i2c.h b/drivers/media/video/msm/io/msm_camera_i2c.h
index a0cdd77..188a176 100644
--- a/drivers/media/video/msm/io/msm_camera_i2c.h
+++ b/drivers/media/video/msm/io/msm_camera_i2c.h
@@ -53,9 +53,9 @@
 struct msm_camera_i2c_reg_conf {
 	uint16_t reg_addr;
 	uint16_t reg_data;
-	int16_t mask;
 	enum msm_camera_i2c_data_type dt;
 	enum msm_camera_i2c_cmd_type cmd_type;
+	int16_t mask;
 };
 
 struct msm_camera_i2c_reg_tbl {
diff --git a/drivers/media/video/msm/msm_camirq_router.c b/drivers/media/video/msm/msm_camirq_router.c
index 52dd175..25a561f 100644
--- a/drivers/media/video/msm/msm_camirq_router.c
+++ b/drivers/media/video/msm/msm_camirq_router.c
@@ -13,6 +13,7 @@
 
 #include <linux/module.h>
 #include <linux/interrupt.h>
+#include <linux/of.h>
 #include <mach/irqs.h>
 #include <media/msm_isp.h>
 #include <media/v4l2-device.h>
@@ -207,6 +208,10 @@
 	v4l2_set_subdevdata(&irqrouter_ctrl->subdev, irqrouter_ctrl);
 	irqrouter_ctrl->pdev = pdev;
 
+	if (pdev->dev.of_node)
+		of_property_read_u32((&pdev->dev)->of_node,
+			"cell-index", &pdev->id);
+
 	msm_irqrouter_send_default_irqmap(irqrouter_ctrl);
 
 	media_entity_init(&irqrouter_ctrl->subdev.entity, 0, NULL, 0);
@@ -237,16 +242,27 @@
 
 static int __exit irqrouter_exit(struct platform_device *pdev)
 {
+	struct v4l2_subdev *subdev = dev_get_drvdata(&pdev->dev);
+	struct irqrouter_ctrl_type *irqrouter_ctrl =
+		v4l2_get_subdevdata(subdev);
 	kfree(irqrouter_ctrl);
 	return 0;
 }
 
+static const struct of_device_id msm_irqrouter_dt_match[] = {
+	{.compatible = "qcom,irqrouter"},
+	{}
+};
+
+MODULE_DEVICE_TABLE(of, msm_irqrouter_dt_match);
+
 static struct platform_driver msm_irqrouter_driver = {
 	.probe = irqrouter_probe,
 	.remove = irqrouter_exit,
 	.driver = {
 		.name = MSM_IRQ_ROUTER_DRV_NAME,
 		.owner = THIS_MODULE,
+		.of_match_table = msm_irqrouter_dt_match,
 	},
 };
 
diff --git a/drivers/media/video/msm/msm_vfe32.c b/drivers/media/video/msm/msm_vfe32.c
index c6dd143..38954f8 100644
--- a/drivers/media/video/msm/msm_vfe32.c
+++ b/drivers/media/video/msm/msm_vfe32.c
@@ -5297,6 +5297,13 @@
 		axi_ctrl->fs_vfe = NULL;
 	}
 
+	/* Register subdev node before requesting irq since
+	 * irq_num is needed by msm_cam_server */
+	sd_info.sdev_type = VFE_DEV;
+	sd_info.sd_index = 0;
+	sd_info.irq_num = axi_ctrl->vfeirq->start;
+	msm_cam_register_subdev_node(&vfe32_ctrl->subdev, &sd_info);
+
 	/* Request for this device irq from the camera server. If the
 	 * IRQ Router is present on this target, the interrupt will be
 	 * handled by the camera server and the interrupt service
@@ -5336,10 +5343,6 @@
 		axi32_do_tasklet, (unsigned long)axi_ctrl);
 
 	vfe32_ctrl->pdev = pdev;
-	sd_info.sdev_type = VFE_DEV;
-	sd_info.sd_index = 0;
-	sd_info.irq_num = axi_ctrl->vfeirq->start;
-	msm_cam_register_subdev_node(&vfe32_ctrl->subdev, &sd_info);
 	return 0;
 
 vfe32_no_resource:
diff --git a/drivers/media/video/msm/sensors/ov7692_v4l2.c b/drivers/media/video/msm/sensors/ov7692_v4l2.c
index 6fc1da1..71d436e 100644
--- a/drivers/media/video/msm/sensors/ov7692_v4l2.c
+++ b/drivers/media/video/msm/sensors/ov7692_v4l2.c
@@ -173,24 +173,33 @@
 };
 
 static struct msm_camera_i2c_reg_conf ov7692_saturation[][4] = {
-	{{0x81, 0x33, 0xCC}, {0xd8, 0x00, 0x00}, {0xd9, 0x00, 0x00},
-		{0xd2, 0x02, 0x00},},	/* SATURATION LEVEL0*/
-	{{0x81, 0x33, 0xCC}, {0xd8, 0x10, 0x00}, {0xd9, 0x10, 0x00},
-		{0xd2, 0x02, 0x00},},	/* SATURATION LEVEL1*/
-	{{0x81, 0x33, 0xCC}, {0xd8, 0x20, 0x00}, {0xd9, 0x20, 0x00},
-		{0xd2, 0x02, 0x00},},	/* SATURATION LEVEL2*/
-	{{0x81, 0x33, 0xCC}, {0xd8, 0x30, 0x00}, {0xd9, 0x30, 0x00},
-		{0xd2, 0x02, 0x00},},	/* SATURATION LEVEL3*/
-	{{0x81, 0x33, 0xCC}, {0xd8, 0x40, 0x00}, {0xd9, 0x40, 0x00},
-		{0xd2, 0x02, 0x00},},	/* SATURATION LEVEL4*/
-	{{0x81, 0x33, 0xCC}, {0xd8, 0x50, 0x00}, {0xd9, 0x50, 0x00},
-		{0xd2, 0x02, 0x00},},	/* SATURATION LEVEL5*/
-	{{0x81, 0x33, 0xCC}, {0xd8, 0x60, 0x00}, {0xd9, 0x60, 0x00},
-		{0xd2, 0x02, 0x00},},	/* SATURATION LEVEL6*/
-	{{0x81, 0x33, 0xCC}, {0xd8, 0x70, 0x00}, {0xd9, 0x70, 0x00},
-		{0xd2, 0x02, 0x00},},	/* SATURATION LEVEL7*/
-	{{0x81, 0x33, 0xCC}, {0xd8, 0x80, 0x00}, {0xd9, 0x80, 0x00},
-		{0xd2, 0x02, 0x00},},	/* SATURATION LEVEL8*/
+	{{0x81, 0x33, 0x00, 0x00, 0xCC}, {0xd8, 0x00, 0x00, 0x00, 0x00},
+		{0xd9, 0x00, 0x00, 0x00, 0x00},
+		{0xd2, 0x02, 0x00, 0x00, 0x00},},/* SATURATION LEVEL0*/
+	{{0x81, 0x33, 0x00, 0x00, 0xCC}, {0xd8, 0x10, 0x00, 0x00, 0x00},
+		{0xd9, 0x10, 0x00, 0x00, 0x00},
+		{0xd2, 0x02, 0x00, 0x00, 0x00},},	/* SATURATION LEVEL1*/
+	{{0x81, 0x33, 0x00, 0x00, 0xCC}, {0xd8, 0x20, 0x00, 0x00, 0x00},
+		{0xd9, 0x20, 0x00, 0x00, 0x00},
+		{0xd2, 0x02, 0x00, 0x00, 0x00},},	/* SATURATION LEVEL2*/
+	{{0x81, 0x33, 0x00, 0x00, 0xCC}, {0xd8, 0x30, 0x00, 0x00, 0x00},
+		{0xd9, 0x30, 0x00, 0x00, 0x00},
+		{0xd2, 0x02, 0x00, 0x00, 0x00},},	/* SATURATION LEVEL3*/
+	{{0x81, 0x33, 0x00, 0x00, 0xCC}, {0xd8, 0x40, 0x00, 0x00, 0x00},
+		{0xd9, 0x40, 0x00, 0x00, 0x00},
+		{0xd2, 0x02, 0x00, 0x00, 0x00},},	/* SATURATION LEVEL4*/
+	{{0x81, 0x33, 0x00, 0x00, 0xCC}, {0xd8, 0x50, 0x00, 0x00, 0x00},
+		{0xd9, 0x50, 0x00, 0x00, 0x00},
+		{0xd2, 0x02, 0x00, 0x00, 0x00},},	/* SATURATION LEVEL5*/
+	{{0x81, 0x33, 0x00, 0x00, 0xCC}, {0xd8, 0x60, 0x00, 0x00, 0x00},
+		{0xd9, 0x60, 0x00, 0x00, 0x00},
+		{0xd2, 0x02, 0x00, 0x00, 0x00},},	/* SATURATION LEVEL6*/
+	{{0x81, 0x33, 0x00, 0x00, 0xCC}, {0xd8, 0x70, 0x00, 0x00, 0x00},
+		{0xd9, 0x70, 0x00, 0x00, 0x00},
+		{0xd2, 0x02, 0x00, 0x00, 0x00},},	/* SATURATION LEVEL7*/
+	{{0x81, 0x33, 0x00, 0x00, 0xCC}, {0xd8, 0x80, 0x00, 0x00, 0x00},
+		{0xd9, 0x80, 0x00, 0x00, 0x00},
+		{0xd2, 0x02, 0x00, 0x00, 0x00},},	/* SATURATION LEVEL8*/
 };
 static struct msm_camera_i2c_conf_array ov7692_saturation_confs[][1] = {
 	{{ov7692_saturation[0], ARRAY_SIZE(ov7692_saturation[0]), 0,
@@ -327,12 +336,18 @@
 	.data_type = MSM_CAMERA_I2C_BYTE_DATA,
 };
 static struct msm_camera_i2c_reg_conf ov7692_sharpness[][2] = {
-	{{0xb4, 0x20, 0xDF}, {0xb6, 0x00, 0xE0},},    /* SHARPNESS LEVEL 0*/
-	{{0xb4, 0x20, 0xDF}, {0xb6, 0x01, 0xE0},},    /* SHARPNESS LEVEL 1*/
-	{{0xb4, 0x00, 0xDF}, {0xb6, 0x00, 0xE0},},    /* SHARPNESS LEVEL 2*/
-	{{0xb4, 0x20, 0xDF}, {0xb6, 0x66, 0xE0},},    /* SHARPNESS LEVEL 3*/
-	{{0xb4, 0x20, 0xDF}, {0xb6, 0x99, 0xE0},},    /* SHARPNESS LEVEL 4*/
-	{{0xb4, 0x20, 0xDF}, {0xb6, 0xcc, 0xE0},},    /* SHARPNESS LEVEL 5*/
+	{{0xb4, 0x20, 0x00, 0x00, 0xDF},
+		{0xb6, 0x00, 0x00, 0x00, 0xE0},},    /* SHARPNESS LEVEL 0*/
+	{{0xb4, 0x20, 0x00, 0x00, 0xDF},
+		{0xb6, 0x01, 0x00, 0x00, 0xE0},},    /* SHARPNESS LEVEL 1*/
+	{{0xb4, 0x00, 0x00, 0x00, 0xDF},
+		{0xb6, 0x00, 0x00, 0x00, 0xE0},},    /* SHARPNESS LEVEL 2*/
+	{{0xb4, 0x20, 0x00, 0x00, 0xDF},
+		{0xb6, 0x66, 0x00, 0x00, 0xE0},},    /* SHARPNESS LEVEL 3*/
+	{{0xb4, 0x20, 0x00, 0x00, 0xDF},
+		{0xb6, 0x99, 0x00, 0x00, 0xE0},},    /* SHARPNESS LEVEL 4*/
+	{{0xb4, 0x20, 0x00, 0x00, 0xDF},
+		{0xb6, 0xcc, 0x00, 0x00, 0xE0},},    /* SHARPNESS LEVEL 5*/
 };
 
 static struct msm_camera_i2c_conf_array ov7692_sharpness_confs[][1] = {
@@ -407,13 +422,13 @@
 };
 
 static struct msm_camera_i2c_reg_conf ov7692_iso[][1] = {
-	{{0x14, 0x20, 0x8F},},   /*ISO_AUTO*/
-	{{0x14, 0x20, 0x8F},},   /*ISO_DEBLUR*/
-	{{0x14, 0x00, 0x8F},},   /*ISO_100*/
-	{{0x14, 0x10, 0x8F},},   /*ISO_200*/
-	{{0x14, 0x20, 0x8F},},   /*ISO_400*/
-	{{0x14, 0x30, 0x8F},},   /*ISO_800*/
-	{{0x14, 0x40, 0x8F},},   /*ISO_1600*/
+	{{0x14, 0x20, 0x00, 0x00, 0x8F},},   /*ISO_AUTO*/
+	{{0x14, 0x20, 0x00, 0x00, 0x8F},},   /*ISO_DEBLUR*/
+	{{0x14, 0x00, 0x00, 0x00, 0x8F},},   /*ISO_100*/
+	{{0x14, 0x10, 0x00, 0x00, 0x8F},},   /*ISO_200*/
+	{{0x14, 0x20, 0x00, 0x00, 0x8F},},   /*ISO_400*/
+	{{0x14, 0x30, 0x00, 0x00, 0x8F},},   /*ISO_800*/
+	{{0x14, 0x40, 0x00, 0x00, 0x8F},},   /*ISO_1600*/
 };
 
 
@@ -453,7 +468,7 @@
 };
 
 static struct msm_camera_i2c_reg_conf ov7692_no_effect[] = {
-	{0x81, 0x00, 0xDF},
+	{0x81, 0x00, 0x00, 0x00, 0xDF},
 	{0x28, 0x00,},
 	{0xd2, 0x00,},
 	{0xda, 0x80,},
@@ -467,32 +482,41 @@
 };
 
 static struct msm_camera_i2c_reg_conf ov7692_special_effect[][5] = {
-	{{0x81, 0x20, 0xDF}, {0x28, 0x00,}, {0xd2, 0x18,}, {0xda, 0x80,},
-		{0xdb, 0x80,},},	/*for special effect OFF*/
-	{{0x81, 0x20, 0xDF}, {0x28, 0x00,}, {0xd2, 0x18,}, {0xda, 0x80,},
-		{0xdb, 0x80,},},	/*for special effect MONO*/
-	{{0x81, 0x20, 0xDF}, {0x28, 0x80,}, {0xd2, 0x40,}, {0xda, 0x80,},
-		{0xdb, 0x80,},},	/*for special efefct Negative*/
-	{{-1, -1, -1}, {-1, -1, -1}, {-1, -1, -1}, {-1, -1, -1},
-		{-1, -1, -1},},		/*Solarize is not supported by sensor*/
-	{{0x81, 0x20, 0xDF}, {0x28, 0x00,}, {0xd2, 0x18,}, {0xda, 0x40,},
-		{0xdb, 0xa0,},},	/*for sepia*/
-	{{-1, -1, -1}, {-1, -1, -1}, {-1, -1, -1}, {-1, -1, -1},
-		{-1, -1, -1},},		/* Posteraize not supported */
-	{{-1, -1, -1}, {-1, -1, -1}, {-1, -1, -1}, {-1, -1, -1},
-		{-1, -1, -1},},		/* White board not supported*/
-	{{-1, -1, -1}, {-1, -1, -1}, {-1, -1, -1}, {-1, -1, -1},
-		{-1, -1, -1},},		/*Blackboard not supported*/
-	{{-1, -1, -1}, {-1, -1, -1}, {-1, -1, -1}, {-1, -1, -1},
-		{-1, -1, -1},},		/*Aqua not supported*/
-	{{-1, -1, -1}, {-1, -1, -1}, {-1, -1, -1}, {-1, -1, -1},
-		{-1, -1, -1},},		/*Emboss not supported */
-	{{-1, -1, -1}, {-1, -1, -1}, {-1, -1, -1}, {-1, -1, -1},
-		{-1, -1, -1},},		/*sketch not supported*/
-	{{-1, -1, -1}, {-1, -1, -1}, {-1, -1, -1}, {-1, -1, -1},
-		{-1, -1, -1},},		/*Neon not supported*/
-	{{-1, -1, -1}, {-1, -1, -1}, {-1, -1, -1}, {-1, -1, -1},
-		{-1, -1, -1},},		/*MAX value*/
+	{{0x81, 0x20, 0x00, 0x00, 0xDF}, {0x28, 0x00,}, {0xd2, 0x18,},
+		{0xda, 0x80,}, {0xdb, 0x80,},},	/*for special effect OFF*/
+	{{0x81, 0x20, 0x00, 0x00, 0xDF}, {0x28, 0x00,}, {0xd2, 0x18,},
+		{0xda, 0x80,}, {0xdb, 0x80,},},	/*for special effect MONO*/
+	{{0x81, 0x20, 0x00, 0x00, 0xDF}, {0x28, 0x80,}, {0xd2, 0x40,},
+		{0xda, 0x80,}, {0xdb, 0x80,},},	/*for special efefct Negative*/
+	{{-1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1},
+		{-1, -1, -1, -1, -1},
+		{-1, -1, -1, -1, -1},},/*Solarize is not supported by sensor*/
+	{{0x81, 0x20, 0x00, 0x00, 0xDF}, {0x28, 0x00,}, {0xd2, 0x18,},
+		{0xda, 0x40,}, {0xdb, 0xa0,},},	/*for sepia*/
+	{{-1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1},
+		{-1, -1, -1, -1, -1},
+		{-1, -1, -1, -1, -1},},		/* Posteraize not supported */
+	{{-1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1},
+		{-1, -1, -1, -1, -1},
+		{-1, -1, -1, -1, -1},},		/* White board not supported*/
+	{{-1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1},
+		{-1, -1, -1, -1, -1},
+		{-1, -1, -1, -1, -1},},		/*Blackboard not supported*/
+	{{-1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1},
+		{-1, -1, -1, -1, -1},
+		{-1, -1, -1, -1, -1},},		/*Aqua not supported*/
+	{{-1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1},
+		{-1, -1, -1, -1, -1},
+		{-1, -1, -1, -1, -1},},		/*Emboss not supported */
+	{{-1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1},
+		{-1, -1, -1, -1, -1},
+		{-1, -1, -1, -1, -1},},		/*sketch not supported*/
+	{{-1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1},
+		{-1, -1, -1, -1, -1},
+		{-1, -1, -1, -1, -1},},		/*Neon not supported*/
+	{{-1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1},
+		{-1, -1, -1, -1, -1},
+		{-1, -1, -1, -1, -1},},		/*MAX value*/
 };
 
 static struct msm_camera_i2c_conf_array ov7692_special_effect_confs[][1] = {
@@ -551,9 +575,12 @@
 };
 
 static struct msm_camera_i2c_reg_conf ov7692_antibanding[][2] = {
-	{{0x13, 0x20, 0xDF}, {0x14, 0x16, 0xE8},},   /*ANTIBANDING 60HZ*/
-	{{0x13, 0x20, 0xDF}, {0x14, 0x17, 0xE8},},   /*ANTIBANDING 50HZ*/
-	{{0x13, 0x20, 0xDF}, {0x14, 0x14, 0xE8},},   /* ANTIBANDING AUTO*/
+	{{0x13, 0x20, 0x00, 0x00, 0xDF},
+		{0x14, 0x16, 0x00, 0x00, 0xE8},},   /*ANTIBANDING 60HZ*/
+	{{0x13, 0x20, 0x00, 0x00, 0xDF},
+		{0x14, 0x17, 0x00, 0x00, 0xE8},},   /*ANTIBANDING 50HZ*/
+	{{0x13, 0x20, 0x00, 0x00, 0xDF},
+		{0x14, 0x14, 0x00, 0x00, 0xE8},},   /* ANTIBANDING AUTO*/
 };
 
 
@@ -583,16 +610,16 @@
 };
 
 static struct msm_camera_i2c_reg_conf ov7692_wb_oem[][4] = {
-	{{-1, -1, -1}, {-1, -1, -1}, {-1, -1, -1},
-		{-1, -1, -1},},/*WHITEBALNACE OFF*/
-	{{0x13, 0xf7}, {0x15, 0x00}, {-1, -1, -1},
-		{-1, -1, -1},}, /*WHITEBALNACE AUTO*/
+	{{-1, -1, -1, -1 , -1}, {-1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1},
+		{-1, -1, -1, -1, -1},},/*WHITEBALNACE OFF*/
+	{{0x13, 0xf7}, {0x15, 0x00}, {-1, -1, -1, -1, -1},
+		{-1, -1, -1, -1, -1},}, /*WHITEBALNACE AUTO*/
 	{{0x13, 0xf5}, {0x01, 0x56}, {0x02, 0x50},
 		{0x15, 0x00},},	/*WHITEBALNACE CUSTOM*/
 	{{0x13, 0xf5}, {0x01, 0x66}, {0x02, 0x40},
 		{0x15, 0x00},},	/*INCANDISCENT*/
-	{{-1, -1, -1}, {-1, -1, -1}, {-1, -1, -1},
-		{-1, -1, -1},},	/*FLOURESECT NOT SUPPORTED */
+	{{-1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1},
+		{-1, -1, -1, -1, -1},},	/*FLOURESECT NOT SUPPORTED */
 	{{0x13, 0xf5}, {0x01, 0x43}, {0x02, 0x5d},
 		{0x15, 0x00},},	/*DAYLIGHT*/
 	{{0x13, 0xf5}, {0x01, 0x48}, {0x02, 0x63},
diff --git a/drivers/media/video/msm/server/msm_cam_server.c b/drivers/media/video/msm/server/msm_cam_server.c
index 05f3c4a..2d3022f 100644
--- a/drivers/media/video/msm/server/msm_cam_server.c
+++ b/drivers/media/video/msm/server/msm_cam_server.c
@@ -1703,10 +1703,10 @@
 					sizeof(struct intr_table_entry));
 			D("%s Saving Entry %d %d %d %p",
 			__func__,
-			ind_irq_tbl[irq_req->cam_hw_idx].irq_num,
-			ind_irq_tbl[irq_req->cam_hw_idx].cam_hw_idx,
-			ind_irq_tbl[irq_req->cam_hw_idx].is_composite,
-			ind_irq_tbl[irq_req->cam_hw_idx].subdev_list[0]);
+			ind_irq_tbl[irq_req->irq_idx].irq_num,
+			ind_irq_tbl[irq_req->irq_idx].cam_hw_idx,
+			ind_irq_tbl[irq_req->irq_idx].is_composite,
+			ind_irq_tbl[irq_req->irq_idx].subdev_list[0]);
 
 			spin_unlock_irqrestore(&g_server_dev.intr_table_lock,
 				flags);
@@ -1859,10 +1859,16 @@
 		break;
 
 	case ISPIF_DEV:
+		if (index >= MAX_NUM_ISPIF_DEV) {
+			pr_err("%s Invalid ISPIF idx %d", __func__, index);
+			err = -EINVAL;
+			break;
+		}
+		cam_hw_idx = MSM_CAM_HW_ISPIF + index;
 		g_server_dev.ispif_device = sd;
 		if (g_server_dev.irqr_device) {
 			g_server_dev.subdev_table[cam_hw_idx] = sd;
-			err = msm_cam_server_fill_sdev_irqnum(MSM_CAM_HW_ISPIF,
+			err = msm_cam_server_fill_sdev_irqnum(cam_hw_idx,
 				sd_info->irq_num);
 		}
 		break;
diff --git a/drivers/media/video/msm_vidc/msm_vdec.c b/drivers/media/video/msm_vidc/msm_vdec.c
index 09c7215..dca9f1d 100644
--- a/drivers/media/video/msm_vidc/msm_vdec.c
+++ b/drivers/media/video/msm_vidc/msm_vdec.c
@@ -154,7 +154,11 @@
 static u32 get_frame_size_nv12(int plane,
 					u32 height, u32 width)
 {
-	return (ALIGN(height, 32) * ALIGN(width, 32) * 3) / 2;
+	int luma_stride = ALIGN(width, 32);
+	int luma_slice = ALIGN(height, 32);
+	int chroma_stride = ALIGN(roundup(width, 2)/2, 32);
+	int chroma_slice = ALIGN(roundup(height, 2)/2, 32);
+	return (luma_stride * luma_slice) + (chroma_stride * chroma_slice) * 2;
 }
 static u32 get_frame_size_nv21(int plane,
 					u32 height, u32 width)
@@ -165,7 +169,7 @@
 static u32 get_frame_size_compressed(int plane,
 					u32 height, u32 width)
 {
-	return 0x500000;
+	return height * width * 3/2;
 }
 
 static const struct msm_vidc_format vdec_formats[] = {
diff --git a/drivers/media/video/msm_vidc/msm_vidc.c b/drivers/media/video/msm_vidc/msm_vidc.c
index 11fbcf4..28fe2b8 100644
--- a/drivers/media/video/msm_vidc/msm_vidc.c
+++ b/drivers/media/video/msm_vidc/msm_vidc.c
@@ -29,19 +29,16 @@
 	struct vb2_buffer *out_vb = NULL;
 	struct vb2_buffer *cap_vb = NULL;
 	unsigned long flags;
-	poll_wait(filp, &inst->event_handler.wait, wait);
-	if (v4l2_event_pending(&inst->event_handler))
-		return POLLPRI;
 	if (!outq->streaming && !capq->streaming) {
 		pr_err("Returning POLLERR from here: %d, %d\n",
 			outq->streaming, capq->streaming);
 		return POLLERR;
 	}
 	poll_wait(filp, &inst->event_handler.wait, wait);
-	if (v4l2_event_pending(&inst->event_handler))
-		return POLLPRI;
 	poll_wait(filp, &capq->done_wq, wait);
 	poll_wait(filp, &outq->done_wq, wait);
+	if (v4l2_event_pending(&inst->event_handler))
+		rc |= POLLPRI;
 	spin_lock_irqsave(&capq->done_lock, flags);
 	if (!list_empty(&capq->done_list))
 		cap_vb = list_first_entry(&capq->done_list, struct vb2_buffer,
diff --git a/drivers/media/video/msm_vidc/msm_vidc_common.c b/drivers/media/video/msm_vidc/msm_vidc_common.c
index a5cff9c..4a86cf5 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_common.c
+++ b/drivers/media/video/msm_vidc/msm_vidc_common.c
@@ -933,12 +933,56 @@
 {
 	int rc = 0;
 	struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance;
+	bool ip_flush = false,
+	     op_flush = false;
+
 	mutex_lock(&inst->sync_lock);
-	if (dec->cmd != V4L2_DEC_CMD_STOP)
-		return -EINVAL;
-	rc = vidc_hal_session_flush((void *)inst->session, HAL_FLUSH_OUTPUT);
+
+	switch (dec->cmd) {
+	case V4L2_DEC_QCOM_CMD_FLUSH:
+		ip_flush = dec->flags & V4L2_DEC_QCOM_CMD_FLUSH_OUTPUT;
+		op_flush = dec->flags & V4L2_DEC_QCOM_CMD_FLUSH_CAPTURE;
+		/* Only support flush on decoder (for now)*/
+		if (inst->session_type == MSM_VIDC_ENCODER) {
+			pr_err("Buffer flushing not supported for encoder\n");
+			rc = -ENOTSUPP;
+			break;
+		}
+
+		/* Certain types of flushes aren't supported such as: */
+		/* 1) Input only flush */
+		if (ip_flush && !op_flush) {
+			pr_err("Input only flush not supported\n");
+			rc = -ENOTSUPP;
+			break;
+		}
+
+		/* 2) Output only flush when in reconfig */
+		if (!ip_flush && op_flush && !inst->in_reconfig) {
+			pr_err("Output only flush only supported when reconfiguring\n");
+			rc = -ENOTSUPP;
+			break;
+		}
+
+		/* Finally flush */
+		if (op_flush && ip_flush)
+			rc = vidc_hal_session_flush(inst->session,
+					HAL_FLUSH_ALL);
+		else if (ip_flush)
+			rc = vidc_hal_session_flush(inst->session,
+					HAL_FLUSH_INPUT);
+		else if (op_flush)
+			rc = vidc_hal_session_flush(inst->session,
+					HAL_FLUSH_OUTPUT);
+
+		break;
+	default:
+		rc = -ENOTSUPP;
+		goto exit;
+	}
+
 	if (rc) {
-		pr_err("Failed to get property\n");
+		pr_err("Failed to exec decoder cmd %d\n", dec->cmd);
 		goto exit;
 	}
 exit:
diff --git a/drivers/media/video/vcap_v4l2.c b/drivers/media/video/vcap_v4l2.c
index 0a033ae..4f7c585 100644
--- a/drivers/media/video/vcap_v4l2.c
+++ b/drivers/media/video/vcap_v4l2.c
@@ -303,6 +303,105 @@
 	cd->set_vp_o = false;
 }
 
+/* VCAP Internal QBUF and DQBUF for VC + VP */
+int vcvp_qbuf(struct vb2_queue *q, struct v4l2_buffer *b)
+{
+	struct vb2_buffer *vb;
+
+	if (q->fileio) {
+		dprintk(1, "%s: file io in progress\n", __func__);
+		return -EBUSY;
+	}
+
+	if (b->type != q->type) {
+		dprintk(1, "%s: invalid buffer type\n", __func__);
+		return -EINVAL;
+	}
+
+	if (b->index >= q->num_buffers) {
+		dprintk(1, "%s: buffer index out of range\n", __func__);
+		return -EINVAL;
+	}
+
+	vb = q->bufs[b->index];
+	if (NULL == vb) {
+		dprintk(1, "%s: buffer is NULL\n", __func__);
+		return -EINVAL;
+	}
+
+	if (b->memory != q->memory) {
+		dprintk(1, "%s: invalid memory type\n", __func__);
+		return -EINVAL;
+	}
+
+	if (vb->state != VB2_BUF_STATE_DEQUEUED &&
+			vb->state != VB2_BUF_STATE_PREPARED) {
+		dprintk(1, "%s: buffer already in use\n", __func__);
+		return -EINVAL;
+	}
+
+	list_add_tail(&vb->queued_entry, &q->queued_list);
+	vb->state = VB2_BUF_STATE_QUEUED;
+
+	if (q->streaming) {
+		vb->state = VB2_BUF_STATE_ACTIVE;
+		atomic_inc(&q->queued_count);
+		q->ops->buf_queue(vb);
+	}
+	return 0;
+}
+
+int vcvp_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b)
+{
+	struct vb2_buffer *vb = NULL;
+	unsigned long flags;
+
+	if (q->fileio) {
+		dprintk(1, "%s: file io in progress\n", __func__);
+		return -EBUSY;
+	}
+
+	if (b->type != q->type) {
+		dprintk(1, "%s: invalid buffer type\n", __func__);
+		return -EINVAL;
+	}
+
+	if (!q->streaming) {
+		dprintk(1, "Streaming off, will not wait for buffers\n");
+		return -EINVAL;
+	}
+
+	if (!list_empty(&q->done_list)) {
+		spin_lock_irqsave(&q->done_lock, flags);
+		vb = list_first_entry(&q->done_list, struct vb2_buffer,
+				done_entry);
+		list_del(&vb->done_entry);
+		spin_unlock_irqrestore(&q->done_lock, flags);
+
+		switch (vb->state) {
+		case VB2_BUF_STATE_DONE:
+			dprintk(3, "%s: Returning done buffer\n", __func__);
+			break;
+		case VB2_BUF_STATE_ERROR:
+			dprintk(3, "%s: Ret done buf with err\n", __func__);
+			break;
+		default:
+			dprintk(1, "%s: Invalid buffer state\n", __func__);
+			return -EINVAL;
+		}
+
+		memcpy(b, &vb->v4l2_buf, offsetof(struct v4l2_buffer, m));
+
+		list_del(&vb->queued_entry);
+
+		vb->state = VB2_BUF_STATE_DEQUEUED;
+		return 0;
+	}
+
+	dprintk(1, "No buffers to dequeue\n");
+	return -EAGAIN;
+}
+
 int get_phys_addr(struct vcap_dev *dev, struct vb2_queue *q,
 				  struct v4l2_buffer *b)
 {
@@ -889,6 +988,14 @@
 				dprintk(1, "qbuf: buffer already in use\n");
 				return -EINVAL;
 			}
+			rc = get_phys_addr(c_data->dev, &c_data->vc_vidq, p);
+			if (rc < 0)
+				return rc;
+			rc = vcvp_qbuf(&c_data->vc_vidq, p);
+			if (rc < 0)
+				free_ion_handle(c_data->dev,
+					&c_data->vc_vidq, p);
+			return rc;
 		}
 		rc = get_phys_addr(c_data->dev, &c_data->vc_vidq, p);
 		if (rc < 0)
diff --git a/drivers/media/video/vcap_vc.c b/drivers/media/video/vcap_vc.c
index ad0718e..62cc306 100644
--- a/drivers/media/video/vcap_vc.c
+++ b/drivers/media/video/vcap_vc.c
@@ -62,19 +62,19 @@
 	struct vcap_buffer *buf_vp;
 
 	int rc;
-	p.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
 	p.memory = V4L2_MEMORY_USERPTR;
 	while (1) {
+		p.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
 		if (!vp_work->cd->streaming)
 			return;
-		rc = vb2_dqbuf(&vp_work->cd->vc_vidq, &p, O_NONBLOCK);
+		rc = vcvp_dqbuf(&vp_work->cd->vc_vidq, &p);
 		if (rc < 0)
 			return;
 
 		vb_vc = vp_work->cd->vc_vidq.bufs[p.index];
 		if (NULL == vb_vc) {
 			dprintk(1, "%s: buffer is NULL\n", __func__);
-			vb2_qbuf(&vp_work->cd->vc_vidq, &p);
+			vcvp_qbuf(&vp_work->cd->vc_vidq, &p);
 			return;
 		}
 		buf_vc = container_of(vb_vc, struct vcap_buffer, vb);
@@ -82,7 +82,7 @@
 		vb_vp = vp_work->cd->vp_in_vidq.bufs[p.index];
 		if (NULL == vb_vp) {
 			dprintk(1, "%s: buffer is NULL\n", __func__);
-			vb2_qbuf(&vp_work->cd->vc_vidq, &p);
+			vcvp_qbuf(&vp_work->cd->vc_vidq, &p);
 			return;
 		}
 		buf_vp = container_of(vb_vp, struct vcap_buffer, vb);
@@ -94,7 +94,7 @@
 		p.type = V4L2_BUF_TYPE_INTERLACED_IN_DECODER;
 
 		/* This call should not fail */
-		rc = vb2_qbuf(&vp_work->cd->vp_in_vidq, &p);
+		rc = vcvp_qbuf(&vp_work->cd->vp_in_vidq, &p);
 		if (rc < 0) {
 			pr_err("%s: qbuf to vp_in failed\n", __func__);
 			buf_vc->ion_handle = buf_vp->ion_handle;
@@ -102,7 +102,7 @@
 			buf_vp->ion_handle = NULL;
 			buf_vp->paddr = 0;
 			p.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-			vb2_qbuf(&vp_work->cd->vc_vidq, &p);
+			vcvp_qbuf(&vp_work->cd->vc_vidq, &p);
 		}
 	}
 }
diff --git a/drivers/media/video/vcap_vp.c b/drivers/media/video/vcap_vp.c
index 1b503ba..db38902 100644
--- a/drivers/media/video/vcap_vp.c
+++ b/drivers/media/video/vcap_vp.c
@@ -117,21 +117,21 @@
 	struct vcap_buffer *buf_vp;
 	int rc;
 
-	p.type = V4L2_BUF_TYPE_INTERLACED_IN_DECODER;
 	p.memory = V4L2_MEMORY_USERPTR;
 
 	/* This loop exits when there is no more buffers left */
 	while (1) {
+		p.type = V4L2_BUF_TYPE_INTERLACED_IN_DECODER;
 		if (!vp_work->cd->streaming)
 			return;
-		rc = vb2_dqbuf(&vp_work->cd->vp_in_vidq, &p, O_NONBLOCK);
+		rc = vcvp_dqbuf(&vp_work->cd->vp_in_vidq, &p);
 		if (rc < 0)
 			return;
 
 		vb_vc = vp_work->cd->vc_vidq.bufs[p.index];
 		if (NULL == vb_vc) {
 			dprintk(1, "%s: buffer is NULL\n", __func__);
-			vb2_qbuf(&vp_work->cd->vp_in_vidq, &p);
+			vcvp_qbuf(&vp_work->cd->vp_in_vidq, &p);
 			return;
 		}
 		buf_vc = container_of(vb_vc, struct vcap_buffer, vb);
@@ -139,7 +139,7 @@
 		vb_vp = vp_work->cd->vp_in_vidq.bufs[p.index];
 		if (NULL == vb_vp) {
 			dprintk(1, "%s: buffer is NULL\n", __func__);
-			vb2_qbuf(&vp_work->cd->vp_in_vidq, &p);
+			vcvp_qbuf(&vp_work->cd->vp_in_vidq, &p);
 			return;
 		}
 		buf_vp = container_of(vb_vp, struct vcap_buffer, vb);
@@ -150,7 +150,7 @@
 
 		p.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
 		/* This call should not fail */
-		rc = vb2_qbuf(&vp_work->cd->vc_vidq, &p);
+		rc = vcvp_qbuf(&vp_work->cd->vc_vidq, &p);
 		if (rc < 0) {
 			dprintk(1, "%s: qbuf to vc failed\n", __func__);
 			buf_vp->ion_handle = buf_vc->ion_handle;
@@ -158,7 +158,7 @@
 			buf_vc->ion_handle = NULL;
 			buf_vc->paddr = 0;
 			p.type = V4L2_BUF_TYPE_INTERLACED_IN_DECODER;
-			vb2_qbuf(&vp_work->cd->vp_in_vidq, &p);
+			vcvp_qbuf(&vp_work->cd->vp_in_vidq, &p);
 		}
 	}
 }
diff --git a/drivers/mfd/wcd9xxx-core.c b/drivers/mfd/wcd9xxx-core.c
index 021dcf1..2256f67 100644
--- a/drivers/mfd/wcd9xxx-core.c
+++ b/drivers/mfd/wcd9xxx-core.c
@@ -297,7 +297,6 @@
 static int wcd9xxx_device_init(struct wcd9xxx *wcd9xxx, int irq)
 {
 	int ret;
-	u8 idbyte_0, idbyte_1, idbyte_2, idbyte_3;
 	struct mfd_cell *wcd9xxx_dev = NULL;
 	int wcd9xxx_dev_size = 0;
 
@@ -321,49 +320,26 @@
 		goto err;
 	}
 
-	idbyte_0 = wcd9xxx_reg_read(wcd9xxx, WCD9XXX_A_CHIP_ID_BYTE_0);
-	idbyte_1 = wcd9xxx_reg_read(wcd9xxx, WCD9XXX_A_CHIP_ID_BYTE_1);
-	idbyte_2 = wcd9xxx_reg_read(wcd9xxx, WCD9XXX_A_CHIP_ID_BYTE_2);
-	idbyte_3 = wcd9xxx_reg_read(wcd9xxx, WCD9XXX_A_CHIP_ID_BYTE_3);
+	wcd9xxx->idbyte_0 = wcd9xxx_reg_read(wcd9xxx, WCD9XXX_A_CHIP_ID_BYTE_0);
+	wcd9xxx->idbyte_1 = wcd9xxx_reg_read(wcd9xxx, WCD9XXX_A_CHIP_ID_BYTE_1);
+	wcd9xxx->idbyte_2 = wcd9xxx_reg_read(wcd9xxx, WCD9XXX_A_CHIP_ID_BYTE_2);
+	wcd9xxx->idbyte_3 = wcd9xxx_reg_read(wcd9xxx, WCD9XXX_A_CHIP_ID_BYTE_3);
 
 	wcd9xxx->version = wcd9xxx_reg_read(wcd9xxx,
 			WCD9XXX_A_CHIP_VERSION) & 0x1F;
 	pr_info("%s : Codec version %u initialized\n",
 		__func__, wcd9xxx->version);
-	pr_info("idbyte_0[%08x] idbyte_1[%08x] idbyte_2[%08x] idbyte_3[%08x]\n",
-			idbyte_0, idbyte_1, idbyte_2, idbyte_3);
 
-	if (wcd9xxx->slim != NULL) {
-		if (!strncmp(wcd9xxx->slim->name, "tabla", 5)) {
-			if (TABLA_IS_1_X(wcd9xxx->version)) {
-				wcd9xxx_dev = tabla1x_devs;
-				wcd9xxx_dev_size = ARRAY_SIZE(tabla1x_devs);
-			} else {
-				wcd9xxx_dev = tabla_devs;
-				wcd9xxx_dev_size = ARRAY_SIZE(tabla_devs);
-			}
-		} else {
-			wcd9xxx_dev = sitar_devs;
-			wcd9xxx_dev_size = ARRAY_SIZE(sitar_devs);
-		}
-	} else {
-		/* Need to add here check for Tabla.
-		 * For now the read of version takes
-		 * care of now only tabla.
-		 */
-		pr_debug("%s : Read codec version using I2C\n",	__func__);
-		if (!strncmp(wcd9xxx_modules[0].client->name, "sitar", 5)) {
-			wcd9xxx_dev = sitar_devs;
-			wcd9xxx_dev_size = ARRAY_SIZE(sitar_devs);
-		} else if (TABLA_IS_1_X(wcd9xxx->version)) {
-			wcd9xxx_dev = tabla1x_devs;
-			wcd9xxx_dev_size = ARRAY_SIZE(tabla1x_devs);
-		} else if (TABLA_IS_2_0(wcd9xxx->version)) {
-			wcd9xxx_dev = tabla_devs;
-			wcd9xxx_dev_size = ARRAY_SIZE(tabla_devs);
-		}
+	if (wcd9xxx->idbyte_0 == 0x2) {
+		wcd9xxx_dev = tabla_devs;
+		wcd9xxx_dev_size = ARRAY_SIZE(tabla_devs);
+	} else if (wcd9xxx->idbyte_0 == 0x1) {
+		wcd9xxx_dev = tabla1x_devs;
+		wcd9xxx_dev_size = ARRAY_SIZE(tabla1x_devs);
+	} else if (wcd9xxx->idbyte_0 == 0x0) {
+		wcd9xxx_dev = sitar_devs;
+		wcd9xxx_dev_size = ARRAY_SIZE(sitar_devs);
 	}
-
 	ret = mfd_add_devices(wcd9xxx->dev, -1,
 		      wcd9xxx_dev, wcd9xxx_dev_size,
 		      NULL, 0);
@@ -766,21 +742,22 @@
 	wcd9xxx->irq = pdata->irq;
 	wcd9xxx->irq_base = pdata->irq_base;
 
-	/*read the tabla status before initializing the device type*/
-	ret = wcd9xxx_read(wcd9xxx, WCD9XXX_A_CHIP_STATUS, 1, &val, 0);
-	if (!strncmp(wcd9xxx_modules[0].client->name, "sitar", 5))
-		i2c_mode = SITAR_I2C_MODE;
-	else if (!strncmp(wcd9xxx_modules[0].client->name, "tabla", 5))
-		i2c_mode = TABLA_I2C_MODE;
-
-	if ((ret < 0) || (val != i2c_mode))
-		pr_err("failed to read the wcd9xxx status ret = %d\n", ret);
-
 	ret = wcd9xxx_device_init(wcd9xxx, wcd9xxx->irq);
 	if (ret) {
 		pr_err("%s: error, initializing device failed\n", __func__);
 		goto err_device_init;
 	}
+
+	if ((wcd9xxx->idbyte_0 == 0x2) || (wcd9xxx->idbyte_0 == 0x1))
+		i2c_mode = TABLA_I2C_MODE;
+	else if (wcd9xxx->idbyte_0 == 0x0)
+		i2c_mode = SITAR_I2C_MODE;
+
+	ret = wcd9xxx_read(wcd9xxx, WCD9XXX_A_CHIP_STATUS, 1, &val, 0);
+
+	if ((ret < 0) || (val != i2c_mode))
+		pr_err("failed to read the wcd9xxx status ret = %d\n", ret);
+
 	wcd9xxx_intf = WCD9XXX_INTERFACE_TYPE_I2C;
 
 	return ret;
@@ -1127,15 +1104,6 @@
 };
 MODULE_DEVICE_TABLE(i2c, tabla_id_table);
 
-static struct i2c_device_id sitar_id_table[] = {
-	{"sitar top level", WCD9XXX_I2C_TOP_LEVEL},
-	{"sitar analog", WCD9XXX_I2C_ANALOG},
-	{"sitar digital1", WCD9XXX_I2C_DIGITAL_1},
-	{"sitar digital2", WCD9XXX_I2C_DIGITAL_2},
-	{}
-};
-MODULE_DEVICE_TABLE(i2c, tabla_id_table);
-
 static struct i2c_driver tabla_i2c_driver = {
 	.driver                 = {
 		.owner          =       THIS_MODULE,
@@ -1148,21 +1116,9 @@
 	.suspend = wcd9xxx_i2c_suspend,
 };
 
-static struct i2c_driver sitar_i2c_driver = {
-	.driver                 = {
-		.owner          =       THIS_MODULE,
-		.name           =       "sitar-i2c-core",
-	},
-	.id_table               =       sitar_id_table,
-	.probe                  =       wcd9xxx_i2c_probe,
-	.remove                 =       __devexit_p(wcd9xxx_i2c_remove),
-	.resume	= wcd9xxx_i2c_resume,
-	.suspend = wcd9xxx_i2c_suspend,
-};
-
 static int __init wcd9xxx_init(void)
 {
-	int ret1, ret2, ret3, ret4, ret5, ret6;
+	int ret1, ret2, ret3, ret4, ret5;
 
 	ret1 = slim_driver_register(&tabla_slim_driver);
 	if (ret1 != 0)
@@ -1184,11 +1140,7 @@
 	if (ret5 != 0)
 		pr_err("Failed to register sitar SB driver: %d\n", ret5);
 
-	ret6 = i2c_add_driver(&sitar_i2c_driver);
-	if (ret6 != 0)
-		pr_err("failed to add the I2C driver\n");
-
-	return (ret1 && ret2 && ret3 && ret4 && ret5 && ret6) ? -1 : 0;
+	return (ret1 && ret2 && ret3 && ret4 && ret5) ? -1 : 0;
 }
 module_init(wcd9xxx_init);
 
diff --git a/drivers/misc/tspp.c b/drivers/misc/tspp.c
index 4d7553e..cc65929 100644
--- a/drivers/misc/tspp.c
+++ b/drivers/misc/tspp.c
@@ -1818,11 +1818,12 @@
 		goto err_bam;
 	}
 
-	if (device->tsif_pclk && clk_enable(device->tsif_pclk) != 0) {
+	if (device->tsif_pclk && clk_prepare_enable(device->tsif_pclk) != 0) {
 		dev_err(&pdev->dev, "Can't start pclk");
 		goto err_pclk;
 	}
-	if (device->tsif_ref_clk && clk_enable(device->tsif_ref_clk) != 0) {
+	if (device->tsif_ref_clk &&
+		clk_prepare_enable(device->tsif_ref_clk) != 0) {
 		dev_err(&pdev->dev, "Can't start ref clk");
 		goto err_refclk;
 	}
@@ -1849,7 +1850,7 @@
 
 err_refclk:
 	if (device->tsif_pclk)
-		clk_disable(device->tsif_pclk);
+		clk_disable_unprepare(device->tsif_pclk);
 err_pclk:
 	sps_deregister_bam_device(device->bam_handle);
 err_bam:
diff --git a/drivers/mmc/card/mmc_block_test.c b/drivers/mmc/card/mmc_block_test.c
index 0ace608..3d4b477 100644
--- a/drivers/mmc/card/mmc_block_test.c
+++ b/drivers/mmc/card/mmc_block_test.c
@@ -83,6 +83,25 @@
 	TEST_CMD23_BITS_16TO29_SET,
 	TEST_CMD23_HDR_BLK_NOT_IN_COUNT,
 	INVALID_CMD_MAX_TESTCASE = TEST_CMD23_HDR_BLK_NOT_IN_COUNT,
+
+	/*
+	 * Start of packing control test group.
+	 * in these next testcases the abbreviation FB = followed by
+	 */
+	PACKING_CONTROL_MIN_TESTCASE,
+	TEST_PACKING_EXP_ONE_OVER_TRIGGER_FB_READ =
+				PACKING_CONTROL_MIN_TESTCASE,
+	TEST_PACKING_EXP_N_OVER_TRIGGER,
+	TEST_PACKING_EXP_N_OVER_TRIGGER_FB_READ,
+	TEST_PACKING_EXP_N_OVER_TRIGGER_FLUSH_N,
+	TEST_PACKING_EXP_THRESHOLD_OVER_TRIGGER,
+	TEST_PACKING_NOT_EXP_LESS_THAN_TRIGGER_REQUESTS,
+	TEST_PACKING_NOT_EXP_TRIGGER_REQUESTS,
+	TEST_PACKING_NOT_EXP_TRIGGER_READ_TRIGGER,
+	TEST_PACKING_NOT_EXP_TRIGGER_FLUSH_TRIGGER,
+	TEST_PACK_MIX_PACKED_NO_PACKED_PACKED,
+	TEST_PACK_MIX_NO_PACKED_PACKED_NO_PACKED,
+	PACKING_CONTROL_MAX_TESTCASE = TEST_PACK_MIX_NO_PACKED_PACKED_NO_PACKED,
 };
 
 enum mmc_block_test_group {
@@ -91,6 +110,7 @@
 	TEST_SEND_WRITE_PACKING_GROUP,
 	TEST_ERR_CHECK_GROUP,
 	TEST_SEND_INVALID_GROUP,
+	TEST_PACKING_CONTROL_GROUP,
 };
 
 struct mmc_block_test_debug {
@@ -98,6 +118,7 @@
 	struct dentry *err_check_test;
 	struct dentry *send_invalid_packed_test;
 	struct dentry *random_test_seed;
+	struct dentry *packing_control_test;
 };
 
 struct mmc_block_test_data {
@@ -454,6 +475,28 @@
 		return "Test invalid - cmd23 bits [16-29] set";
 	case TEST_CMD23_HDR_BLK_NOT_IN_COUNT:
 		return "Test invalid - cmd23 header block not in count";
+	case TEST_PACKING_EXP_N_OVER_TRIGGER:
+		return "\nTest packing control - pack n";
+	case TEST_PACKING_EXP_N_OVER_TRIGGER_FB_READ:
+		return "\nTest packing control - pack n followed by read";
+	case TEST_PACKING_EXP_N_OVER_TRIGGER_FLUSH_N:
+		return "\nTest packing control - pack n followed by flush";
+	case TEST_PACKING_EXP_ONE_OVER_TRIGGER_FB_READ:
+		return "\nTest packing control - pack one followed by read";
+	case TEST_PACKING_EXP_THRESHOLD_OVER_TRIGGER:
+		return "\nTest packing control - pack threshold";
+	case TEST_PACKING_NOT_EXP_LESS_THAN_TRIGGER_REQUESTS:
+		return "\nTest packing control - no packing";
+	case TEST_PACKING_NOT_EXP_TRIGGER_REQUESTS:
+		return "\nTest packing control - no packing, trigger requests";
+	case TEST_PACKING_NOT_EXP_TRIGGER_READ_TRIGGER:
+		return "\nTest packing control - no pack, trigger-read-trigger";
+	case TEST_PACKING_NOT_EXP_TRIGGER_FLUSH_TRIGGER:
+		return "\nTest packing control- no pack, trigger-flush-trigger";
+	case TEST_PACK_MIX_PACKED_NO_PACKED_PACKED:
+		return "\nTest packing control - mix: pack -> no pack -> pack";
+	case TEST_PACK_MIX_NO_PACKED_PACKED_NO_PACKED:
+		return "\nTest packing control - mix: no pack->pack->no pack";
 	default:
 		 return "Unknown testcase";
 	}
@@ -505,7 +548,7 @@
 
 	stop_reason = mmc_packed_stats->pack_stop_reason;
 
-	for (i = 1 ; i <= max_packed_reqs ; ++i) {
+	for (i = 1; i <= max_packed_reqs; ++i) {
 		if (mmc_packed_stats->packing_events[i] !=
 		    expected_stats.packing_events[i]) {
 			test_pr_err(
@@ -710,7 +753,7 @@
 	test_pr_info("%s: Adding %d write requests, first req_id=%d", __func__,
 		     num_requests, td->wr_rd_next_req_id);
 
-	for (i = 1 ; i <= num_requests ; i++) {
+	for (i = 1; i <= num_requests; i++) {
 		start_sec = td->start_sector + 4096 * td->num_of_write_bios;
 		if (is_random)
 			pseudo_rnd_num_of_bios(bio_seed, &num_bios);
@@ -826,6 +869,185 @@
 }
 
 /*
+ * Prepare the write, read and flush requests for the packing control
+ * testcases
+ */
+static int prepare_packed_control_tests_requests(struct test_data *td,
+			int is_err_expected, int num_requests, int is_random)
+{
+	int ret = 0;
+	struct mmc_queue *mq;
+	int max_packed_reqs;
+	int temp_num_req = num_requests;
+	struct request_queue *req_q;
+	int test_packed_trigger;
+	int num_packed_reqs;
+
+	if (!td) {
+		test_pr_err("%s: NULL td\n", __func__);
+		return -EINVAL;
+	}
+
+	req_q = td->req_q;
+
+	if (!req_q) {
+		test_pr_err("%s: NULL request queue\n", __func__);
+		return -EINVAL;
+	}
+
+	mq = req_q->queuedata;
+	if (!mq) {
+		test_pr_err("%s: NULL mq", __func__);
+		return -EINVAL;
+	}
+
+	max_packed_reqs = mq->card->ext_csd.max_packed_writes;
+	test_packed_trigger = mq->num_wr_reqs_to_start_packing;
+	num_packed_reqs = num_requests - test_packed_trigger;
+
+	if (mbtd->random_test_seed == 0) {
+		mbtd->random_test_seed =
+			(unsigned int)(get_jiffies_64() & 0xFFFF);
+		test_pr_info("%s: got seed from jiffies %d",
+			     __func__, mbtd->random_test_seed);
+	}
+
+	mmc_blk_init_packed_statistics(mq->card);
+
+	if (td->test_info.testcase ==
+			TEST_PACK_MIX_NO_PACKED_PACKED_NO_PACKED) {
+		temp_num_req = num_requests;
+		num_requests = test_packed_trigger - 1;
+	}
+
+	/* Verify that the packing is disabled before starting the test */
+	mq->wr_packing_enabled = false;
+	mq->num_of_potential_packed_wr_reqs = 0;
+
+	if (td->test_info.testcase == TEST_PACK_MIX_PACKED_NO_PACKED_PACKED) {
+		mq->num_of_potential_packed_wr_reqs = test_packed_trigger + 1;
+		mq->wr_packing_enabled = true;
+		num_requests = test_packed_trigger + 2;
+	}
+
+	ret = prepare_request_add_write_reqs(td, num_requests, is_err_expected,
+					     is_random);
+	if (ret)
+		goto exit;
+
+	if (td->test_info.testcase == TEST_PACK_MIX_NO_PACKED_PACKED_NO_PACKED)
+		num_requests = temp_num_req;
+
+	memset((void *)mbtd->exp_packed_stats.pack_stop_reason, 0,
+		sizeof(mbtd->exp_packed_stats.pack_stop_reason));
+	memset(mbtd->exp_packed_stats.packing_events, 0,
+		(max_packed_reqs + 1) * sizeof(u32));
+
+	switch (td->test_info.testcase) {
+	case TEST_PACKING_EXP_N_OVER_TRIGGER_FB_READ:
+	case TEST_PACKING_EXP_ONE_OVER_TRIGGER_FB_READ:
+		ret = prepare_request_add_read(td);
+		if (ret)
+			goto exit;
+
+		mbtd->exp_packed_stats.pack_stop_reason[WRONG_DATA_DIR] = 1;
+		mbtd->exp_packed_stats.packing_events[num_packed_reqs] = 1;
+		break;
+	case TEST_PACKING_EXP_N_OVER_TRIGGER_FLUSH_N:
+		ret = prepare_request_add_flush(td);
+		if (ret)
+			goto exit;
+
+		ret = prepare_request_add_write_reqs(td, num_packed_reqs,
+					     is_err_expected, is_random);
+		if (ret)
+			goto exit;
+
+		mbtd->exp_packed_stats.pack_stop_reason[EMPTY_QUEUE] = 1;
+		mbtd->exp_packed_stats.pack_stop_reason[FLUSH_OR_DISCARD] = 1;
+		mbtd->exp_packed_stats.packing_events[num_packed_reqs] = 2;
+		break;
+	case TEST_PACKING_NOT_EXP_TRIGGER_READ_TRIGGER:
+		ret = prepare_request_add_read(td);
+		if (ret)
+			goto exit;
+
+		ret = prepare_request_add_write_reqs(td, test_packed_trigger,
+						    is_err_expected, is_random);
+		if (ret)
+			goto exit;
+
+		mbtd->exp_packed_stats.packing_events[num_packed_reqs] = 1;
+		break;
+	case TEST_PACKING_NOT_EXP_TRIGGER_FLUSH_TRIGGER:
+		ret = prepare_request_add_flush(td);
+		if (ret)
+			goto exit;
+
+		ret = prepare_request_add_write_reqs(td, test_packed_trigger,
+						    is_err_expected, is_random);
+		if (ret)
+			goto exit;
+
+		mbtd->exp_packed_stats.packing_events[num_packed_reqs] = 1;
+		break;
+	case TEST_PACK_MIX_PACKED_NO_PACKED_PACKED:
+		ret = prepare_request_add_read(td);
+		if (ret)
+			goto exit;
+
+		ret = prepare_request_add_write_reqs(td, test_packed_trigger-1,
+						    is_err_expected, is_random);
+		if (ret)
+			goto exit;
+
+		ret = prepare_request_add_write_reqs(td, num_requests,
+						    is_err_expected, is_random);
+		if (ret)
+			goto exit;
+
+		mbtd->exp_packed_stats.packing_events[num_requests] = 1;
+		mbtd->exp_packed_stats.packing_events[num_requests-1] = 1;
+		mbtd->exp_packed_stats.pack_stop_reason[WRONG_DATA_DIR] = 1;
+		mbtd->exp_packed_stats.pack_stop_reason[EMPTY_QUEUE] = 1;
+		break;
+	case TEST_PACK_MIX_NO_PACKED_PACKED_NO_PACKED:
+		ret = prepare_request_add_read(td);
+		if (ret)
+			goto exit;
+
+		ret = prepare_request_add_write_reqs(td, num_requests,
+						    is_err_expected, is_random);
+		if (ret)
+			goto exit;
+
+		ret = prepare_request_add_read(td);
+		if (ret)
+			goto exit;
+
+		ret = prepare_request_add_write_reqs(td, test_packed_trigger-1,
+						    is_err_expected, is_random);
+		if (ret)
+			goto exit;
+
+		mbtd->exp_packed_stats.pack_stop_reason[WRONG_DATA_DIR] = 1;
+		mbtd->exp_packed_stats.packing_events[num_packed_reqs] = 1;
+		break;
+	case TEST_PACKING_NOT_EXP_LESS_THAN_TRIGGER_REQUESTS:
+	case TEST_PACKING_NOT_EXP_TRIGGER_REQUESTS:
+		mbtd->exp_packed_stats.packing_events[num_packed_reqs] = 1;
+		break;
+	default:
+		mbtd->exp_packed_stats.pack_stop_reason[EMPTY_QUEUE] = 1;
+		mbtd->exp_packed_stats.packing_events[num_packed_reqs] = 1;
+	}
+	mbtd->num_requests = num_requests;
+
+exit:
+	return ret;
+}
+
+/*
  * Prepare requests for the TEST_RET_PARTIAL_FOLLOWED_BY_ABORT testcase.
  * In this testcase we have mixed error expectations from different
  * write requests, hence the special prepare function.
@@ -848,13 +1070,14 @@
 
 	mmc_blk_init_packed_statistics(mq->card);
 
-	for (i = 1 ; i <= num_requests ; i++) {
+	for (i = 1; i <= num_requests; i++) {
 		if (i > (num_requests / 2))
 			is_err_expected = 1;
 
-		start_address = td->start_sector + 4096*td->num_of_write_bios;
+		start_address = td->start_sector + 4096 * td->num_of_write_bios;
 		ret = test_iosched_add_wr_rd_test_req(is_err_expected, WRITE,
-				start_address, (i%5)+1, TEST_PATTERN_5A, NULL);
+				start_address, (i % 5) + 1, TEST_PATTERN_5A,
+				NULL);
 		if (ret) {
 			test_pr_err("%s: failed to add a write request",
 				    __func__);
@@ -888,6 +1111,8 @@
 	int num_requests;
 	int min_num_requests = 2;
 	int is_random = mbtd->is_random;
+	int max_for_double;
+	int test_packed_trigger;
 
 	req_q = test_iosched_get_req_queue();
 	if (req_q)
@@ -904,16 +1129,52 @@
 
 	max_num_requests = mq->card->ext_csd.max_packed_writes;
 	num_requests = max_num_requests - 2;
+	test_packed_trigger = mq->num_wr_reqs_to_start_packing;
+
+	/*
+	 * Here max_for_double is intended for packed control testcases
+	 * in which we issue many write requests. It's purpose is to prevent
+	 * exceeding max number of req_queue requests.
+	 */
+	max_for_double = max_num_requests - 10;
+
+	if (td->test_info.testcase ==
+				TEST_PACKING_NOT_EXP_LESS_THAN_TRIGGER_REQUESTS)
+		/* Don't expect packing, so issue up to trigger-1 reqs */
+		num_requests = test_packed_trigger - 1;
 
 	if (is_random) {
 		if (td->test_info.testcase ==
 		    TEST_RET_PARTIAL_FOLLOWED_BY_ABORT)
+			/*
+			 * Here we don't want num_requests to be less than 1
+			 * as a consequence of division by 2.
+			 */
 			min_num_requests = 3;
 
+		if (td->test_info.testcase ==
+				TEST_PACKING_NOT_EXP_LESS_THAN_TRIGGER_REQUESTS)
+			/* Don't expect packing, so issue up to trigger reqs */
+			max_num_requests = test_packed_trigger;
+
 		num_requests = pseudo_random_seed(seed, min_num_requests,
 						  max_num_requests - 1);
 	}
 
+	if (td->test_info.testcase ==
+				TEST_PACKING_NOT_EXP_LESS_THAN_TRIGGER_REQUESTS)
+		num_requests -= test_packed_trigger;
+
+	if (td->test_info.testcase == TEST_PACKING_EXP_N_OVER_TRIGGER_FLUSH_N)
+		num_requests =
+		num_requests > max_for_double ? max_for_double : num_requests;
+
+	if (mbtd->test_group == TEST_PACKING_CONTROL_GROUP)
+		num_requests += test_packed_trigger;
+
+	if (td->test_info.testcase == TEST_PACKING_NOT_EXP_TRIGGER_REQUESTS)
+		num_requests = test_packed_trigger;
+
 	return num_requests;
 }
 
@@ -929,6 +1190,7 @@
 	int num_requests = 0;
 	int ret = 0;
 	int is_random = mbtd->is_random;
+	int test_packed_trigger = mq->num_wr_reqs_to_start_packing;
 
 	if (!mq) {
 		test_pr_err("%s: NULL mq", __func__);
@@ -997,6 +1259,33 @@
 	case TEST_HDR_CMD23_PACKED_BIT_SET:
 		ret = prepare_packed_requests(td, 1, num_requests, is_random);
 		break;
+	case TEST_PACKING_EXP_N_OVER_TRIGGER:
+	case TEST_PACKING_EXP_N_OVER_TRIGGER_FB_READ:
+	case TEST_PACKING_NOT_EXP_TRIGGER_REQUESTS:
+	case TEST_PACKING_NOT_EXP_LESS_THAN_TRIGGER_REQUESTS:
+	case TEST_PACK_MIX_PACKED_NO_PACKED_PACKED:
+	case TEST_PACK_MIX_NO_PACKED_PACKED_NO_PACKED:
+		ret = prepare_packed_control_tests_requests(td, 0, num_requests,
+			is_random);
+		break;
+	case TEST_PACKING_EXP_THRESHOLD_OVER_TRIGGER:
+		ret = prepare_packed_control_tests_requests(td, 0,
+			max_num_requests, is_random);
+		break;
+	case TEST_PACKING_EXP_ONE_OVER_TRIGGER_FB_READ:
+		ret = prepare_packed_control_tests_requests(td, 0,
+			test_packed_trigger + 1,
+					is_random);
+		break;
+	case TEST_PACKING_EXP_N_OVER_TRIGGER_FLUSH_N:
+		ret = prepare_packed_control_tests_requests(td, 0, num_requests,
+			is_random);
+		break;
+	case TEST_PACKING_NOT_EXP_TRIGGER_READ_TRIGGER:
+	case TEST_PACKING_NOT_EXP_TRIGGER_FLUSH_TRIGGER:
+		ret = prepare_packed_control_tests_requests(td, 0,
+			test_packed_trigger, is_random);
+		break;
 	default:
 		test_pr_info("%s: Invalid test case...", __func__);
 		return -EINVAL;
@@ -1084,6 +1373,9 @@
 		/* disable the packing control */
 		host->caps2 &= ~MMC_CAP2_PACKED_WR_CONTROL;
 		break;
+	case TEST_PACKING_CONTROL_GROUP:
+		host->caps2 |=  MMC_CAP2_PACKED_WR_CONTROL;
+		break;
 	default:
 		break;
 	}
@@ -1135,12 +1427,12 @@
 	mbtd->test_info.get_test_case_str_fn = get_test_case_str;
 	mbtd->test_info.post_test_fn = post_test;
 
-	for (i = 0 ; i < number ; ++i) {
+	for (i = 0; i < number; ++i) {
 		test_pr_info("%s: Cycle # %d / %d", __func__, i+1, number);
 		test_pr_info("%s: ====================", __func__);
 
-		for (j = SEND_WRITE_PACKING_MIN_TESTCASE ;
-		      j <= SEND_WRITE_PACKING_MAX_TESTCASE ; j++) {
+		for (j = SEND_WRITE_PACKING_MIN_TESTCASE;
+		      j <= SEND_WRITE_PACKING_MAX_TESTCASE; j++) {
 
 			mbtd->test_info.testcase = j;
 			mbtd->is_random = RANDOM_TEST;
@@ -1233,7 +1525,7 @@
 	mbtd->test_info.get_test_case_str_fn = get_test_case_str;
 	mbtd->test_info.post_test_fn = post_test;
 
-	for (i = 0 ; i < number ; ++i) {
+	for (i = 0; i < number; ++i) {
 		test_pr_info("%s: Cycle # %d / %d", __func__, i+1, number);
 		test_pr_info("%s: ====================", __func__);
 
@@ -1332,7 +1624,7 @@
 	mbtd->test_info.get_test_case_str_fn = get_test_case_str;
 	mbtd->test_info.post_test_fn = post_test;
 
-	for (i = 0 ; i < number ; ++i) {
+	for (i = 0; i < number; ++i) {
 		test_pr_info("%s: Cycle # %d / %d", __func__, i+1, number);
 		test_pr_info("%s: ====================", __func__);
 
@@ -1408,12 +1700,123 @@
 	.read = send_invalid_packed_test_read,
 };
 
+/* packing_control TEST */
+static ssize_t write_packing_control_test_write(struct file *file,
+				const char __user *buf,
+				size_t count,
+				loff_t *ppos)
+{
+	int ret = 0;
+	int i = 0;
+	int number = -1;
+	int j = 0;
+	struct mmc_queue *mq = test_iosched_get_req_queue()->queuedata;
+	int max_num_requests = mq->card->ext_csd.max_packed_writes;
+	int test_successful = 1;
+
+	test_pr_info("%s: -- write_packing_control TEST --", __func__);
+
+	sscanf(buf, "%d", &number);
+
+	if (number <= 0)
+		number = 1;
+
+	test_pr_info("%s: max_num_requests = %d ", __func__,
+			max_num_requests);
+
+	memset(&mbtd->test_info, 0, sizeof(struct test_info));
+	mbtd->test_group = TEST_PACKING_CONTROL_GROUP;
+
+	if (validate_packed_commands_settings())
+		return count;
+
+	mbtd->test_info.data = mbtd;
+	mbtd->test_info.prepare_test_fn = prepare_test;
+	mbtd->test_info.check_test_result_fn = check_wr_packing_statistics;
+	mbtd->test_info.get_test_case_str_fn = get_test_case_str;
+
+	for (i = 0; i < number; ++i) {
+		test_pr_info("%s: Cycle # %d / %d", __func__, i+1, number);
+		test_pr_info("%s: ====================", __func__);
+
+		for (j = PACKING_CONTROL_MIN_TESTCASE;
+				j <= PACKING_CONTROL_MAX_TESTCASE; j++) {
+
+			test_successful = 1;
+			mbtd->test_info.testcase = j;
+			mbtd->is_random = RANDOM_TEST;
+			ret = test_iosched_start_test(&mbtd->test_info);
+			if (ret) {
+				test_successful = 0;
+				break;
+			}
+			/* Allow FS requests to be dispatched */
+			msleep(1000);
+
+			mbtd->test_info.testcase = j;
+			mbtd->is_random = NON_RANDOM_TEST;
+			ret = test_iosched_start_test(&mbtd->test_info);
+			if (ret) {
+				test_successful = 0;
+				break;
+			}
+			/* Allow FS requests to be dispatched */
+			msleep(1000);
+		}
+
+		if (!test_successful)
+			break;
+	}
+
+	test_pr_info("%s: Completed all the test cases.", __func__);
+
+	return count;
+}
+
+static ssize_t write_packing_control_test_read(struct file *file,
+			       char __user *buffer,
+			       size_t count,
+			       loff_t *offset)
+{
+	memset((void *)buffer, 0, count);
+
+	snprintf(buffer, count,
+		 "\nwrite_packing_control_test\n"
+		 "=========\n"
+		 "Description:\n"
+		 "This test checks the following scenarios\n"
+		 "- Packing expected - one over trigger\n"
+		 "- Packing expected - N over trigger\n"
+		 "- Packing expected - N over trigger followed by read\n"
+		 "- Packing expected - N over trigger followed by flush\n"
+		 "- Packing expected - threshold over trigger FB by flush\n"
+		 "- Packing not expected - less than trigger\n"
+		 "- Packing not expected - trigger requests\n"
+		 "- Packing not expected - trigger, read, trigger\n"
+		 "- Mixed state - packing -> no packing -> packing\n"
+		 "- Mixed state - no packing -> packing -> no packing\n");
+
+	if (message_repeat == 1) {
+		message_repeat = 0;
+		return strnlen(buffer, count);
+	} else {
+		return 0;
+	}
+}
+
+const struct file_operations write_packing_control_test_ops = {
+	.open = test_open,
+	.write = write_packing_control_test_write,
+	.read = write_packing_control_test_read,
+};
+
 static void mmc_block_test_debugfs_cleanup(void)
 {
 	debugfs_remove(mbtd->debug.random_test_seed);
 	debugfs_remove(mbtd->debug.send_write_packing_test);
 	debugfs_remove(mbtd->debug.err_check_test);
 	debugfs_remove(mbtd->debug.send_invalid_packed_test);
+	debugfs_remove(mbtd->debug.packing_control_test);
 }
 
 static int mmc_block_test_debugfs_init(void)
@@ -1465,6 +1868,16 @@
 	if (!mbtd->debug.send_invalid_packed_test)
 		goto err_nomem;
 
+	mbtd->debug.packing_control_test = debugfs_create_file(
+					"packing_control_test",
+					S_IRUGO | S_IWUGO,
+					tests_root,
+					NULL,
+					&write_packing_control_test_ops);
+
+	if (!mbtd->debug.packing_control_test)
+		goto err_nomem;
+
 	return 0;
 
 err_nomem:
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c
index a4af6c9..d1d8358 100644
--- a/drivers/mmc/host/msm_sdcc.c
+++ b/drivers/mmc/host/msm_sdcc.c
@@ -236,6 +236,14 @@
 		pr_err("%s:msmsdcc_sps_reset_ep(cons) error=%d\n",
 				mmc_hostname(host->mmc), rc);
 
+	if (host->sps.reset_device) {
+		rc = sps_device_reset(host->sps.bam_handle);
+		if (rc)
+			pr_err("%s: sps_device_reset error=%d\n",
+				mmc_hostname(host->mmc), rc);
+		host->sps.reset_device = false;
+	}
+
 	/* Restore all BAM pipes connections */
 	rc = msmsdcc_sps_restore_ep(host, &host->sps.prod);
 	if (rc)
@@ -4323,6 +4331,96 @@
 }
 
 /**
+ * Handle BAM device's global error condition
+ *
+ * This is an error handler for the SDCC bam device
+ *
+ * This function is registered as a callback with SPS-BAM
+ * driver and will called in case there are an errors for
+ * the SDCC BAM deivce. Any error conditions in the BAM
+ * device are global and will be result in this function
+ * being called once per device.
+ *
+ * This function will be called from the sps driver's
+ * interrupt context.
+ *
+ * @sps_cb_case - indicates what error it is
+ * @user - Pointer to sdcc host structure
+ */
+static void
+msmsdcc_sps_bam_global_irq_cb(enum sps_callback_case sps_cb_case, void *user)
+{
+	struct msmsdcc_host *host = (struct msmsdcc_host *)user;
+	struct mmc_request *mrq;
+	unsigned long flags;
+	int32_t error = 0;
+
+	BUG_ON(!host);
+	BUG_ON(!is_sps_mode(host));
+
+	if (sps_cb_case == SPS_CALLBACK_BAM_ERROR_IRQ) {
+		/**
+		 * Reset the all endpoints along with reseting the sps device.
+		 */
+		host->sps.pipe_reset_pending = true;
+		host->sps.reset_device = true;
+
+		pr_err("%s: BAM Global ERROR IRQ happened\n",
+			mmc_hostname(host->mmc));
+		error = EAGAIN;
+	} else if (sps_cb_case == SPS_CALLBACK_BAM_HRESP_ERR_IRQ) {
+		/**
+		 *  This means that there was an AHB access error and
+		 *  the address we are trying to read/write is something
+		 *  we dont have priviliges to do so.
+		 */
+		pr_err("%s: BAM HRESP_ERR_IRQ happened\n",
+			mmc_hostname(host->mmc));
+		error = EACCES;
+	} else {
+		/**
+		 * This should not have happened ideally. If this happens
+		 * there is some seriously wrong.
+		 */
+		pr_err("%s: BAM global IRQ callback received, type:%d\n",
+			mmc_hostname(host->mmc), (u32) sps_cb_case);
+		error = EIO;
+	}
+
+	spin_lock_irqsave(&host->lock, flags);
+
+	mrq = host->curr.mrq;
+
+	if (mrq && mrq->cmd) {
+		msmsdcc_dump_sdcc_state(host);
+
+		if (!mrq->cmd->error)
+			mrq->cmd->error = -error;
+		if (host->curr.data) {
+			if (mrq->data && !mrq->data->error)
+				mrq->data->error = -error;
+			host->curr.data_xfered = 0;
+			if (host->sps.sg && is_sps_mode(host)) {
+				/* Stop current SPS transfer */
+				msmsdcc_sps_exit_curr_xfer(host);
+			} else {
+				/* this condition should not have happened */
+				pr_err("%s: something is seriously wrong. "\
+					"Funtion: %s, line: %d\n",
+					mmc_hostname(host->mmc),
+					__func__, __LINE__);
+			}
+		} else {
+			/* this condition should not have happened */
+			pr_err("%s: something is seriously wrong. Funtion: "\
+				"%s, line: %d\n", mmc_hostname(host->mmc),
+				__func__, __LINE__);
+		}
+	}
+	spin_unlock_irqrestore(&host->lock, flags);
+}
+
+/**
  * Initialize SPS HW connected with SDCC core
  *
  * This function register BAM HW resources with
@@ -4371,6 +4469,8 @@
 	/* SPS driver wll handle the SDCC BAM IRQ */
 	bam.irq = (u32)host->bam_irqres->start;
 	bam.manage = SPS_BAM_MGR_LOCAL;
+	bam.callback = msmsdcc_sps_bam_global_irq_cb;
+	bam.user = (void *)host;
 
 	pr_info("%s: bam physical base=0x%x\n", mmc_hostname(host->mmc),
 			(u32)bam.phys_addr);
diff --git a/drivers/mmc/host/msm_sdcc.h b/drivers/mmc/host/msm_sdcc.h
index baeabd2..655f2b9 100644
--- a/drivers/mmc/host/msm_sdcc.h
+++ b/drivers/mmc/host/msm_sdcc.h
@@ -321,6 +321,7 @@
 	unsigned int			busy;
 	unsigned int			xfer_req_cnt;
 	bool				pipe_reset_pending;
+	bool				reset_device;
 	struct tasklet_struct		tlet;
 };
 
diff --git a/drivers/net/usb/rmnet_usb_data.c b/drivers/net/usb/rmnet_usb_data.c
index 55020a1..eb57693 100644
--- a/drivers/net/usb/rmnet_usb_data.c
+++ b/drivers/net/usb/rmnet_usb_data.c
@@ -558,6 +558,8 @@
 
 	udev = unet->udev;
 
+	usb_enable_autosuspend(udev);
+
 	/* allow modem to wake up suspended system */
 	device_set_wakeup_enable(&udev->dev, 1);
 
diff --git a/drivers/platform/msm/sps/sps.c b/drivers/platform/msm/sps/sps.c
index 1329f6c..0371f5a 100644
--- a/drivers/platform/msm/sps/sps.c
+++ b/drivers/platform/msm/sps/sps.c
@@ -2028,30 +2028,30 @@
 		goto device_create_err;
 	}
 
-	if (!d_type) {
-		sps->dfab_clk = clk_get(sps->dev, "dfab_clk");
-		if (IS_ERR(sps->dfab_clk)) {
-			SPS_ERR("sps:fail to get dfab_clk.");
+	sps->dfab_clk = clk_get(sps->dev, "dfab_clk");
+	if (IS_ERR(sps->dfab_clk)) {
+		SPS_ERR("sps:fail to get dfab_clk.");
+		goto clk_err;
+	} else {
+		ret = clk_set_rate(sps->dfab_clk, 64000000);
+		if (ret) {
+			SPS_ERR("sps:failed to set dfab_clk rate.");
+			clk_put(sps->dfab_clk);
 			goto clk_err;
-		} else {
-			ret = clk_set_rate(sps->dfab_clk, 64000000);
-			if (ret) {
-				SPS_ERR("sps:failed to set dfab_clk rate.");
-				clk_put(sps->dfab_clk);
-				goto clk_err;
-			}
 		}
 	}
 
-	sps->pmem_clk = clk_get(sps->dev, "mem_clk");
-	if (IS_ERR(sps->pmem_clk)) {
-		SPS_ERR("sps:fail to get pmem_clk.");
-		goto clk_err;
-	} else {
-		ret = clk_prepare_enable(sps->pmem_clk);
-		if (ret) {
-			SPS_ERR("sps:failed to enable pmem_clk. ret=%d", ret);
+	if (!d_type) {
+		sps->pmem_clk = clk_get(sps->dev, "mem_clk");
+		if (IS_ERR(sps->pmem_clk)) {
+			SPS_ERR("sps:fail to get pmem_clk.");
 			goto clk_err;
+		} else {
+			ret = clk_prepare_enable(sps->pmem_clk);
+			if (ret) {
+				SPS_ERR("sps:failed to enable pmem_clk.");
+				goto clk_err;
+			}
 		}
 	}
 
@@ -2068,26 +2068,22 @@
 		}
 	}
 
-	if (!d_type) {
-		ret = clk_prepare_enable(sps->dfab_clk);
-		if (ret) {
-			SPS_ERR("sps:failed to enable dfab_clk. ret=%d", ret);
-			goto clk_err;
-		}
+	ret = clk_prepare_enable(sps->dfab_clk);
+	if (ret) {
+		SPS_ERR("sps:failed to enable dfab_clk. ret=%d", ret);
+		goto clk_err;
 	}
 #endif
 	ret = sps_device_init();
 	if (ret) {
 		SPS_ERR("sps:sps_device_init err.");
 #ifdef CONFIG_SPS_SUPPORT_BAMDMA
-		if (!d_type)
-			clk_disable_unprepare(sps->dfab_clk);
+		clk_disable_unprepare(sps->dfab_clk);
 #endif
 		goto sps_device_init_err;
 	}
 #ifdef CONFIG_SPS_SUPPORT_BAMDMA
-	if (!d_type)
-		clk_disable_unprepare(sps->dfab_clk);
+	clk_disable_unprepare(sps->dfab_clk);
 #endif
 	sps->is_ready = true;
 
@@ -2114,9 +2110,9 @@
 	class_destroy(sps->dev_class);
 	sps_device_de_init();
 
+	clk_put(sps->dfab_clk);
 	if (!d_type)
-		clk_put(sps->dfab_clk);
-	clk_put(sps->pmem_clk);
+		clk_put(sps->pmem_clk);
 	clk_put(sps->bamdma_clk);
 
 	return 0;
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index fc0d02a..1849118 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -1169,4 +1169,13 @@
 	  This driver can also be built as a module. If so, the module
 	  will be called rtc-ls1x.
 
+config RTC_DRV_QPNP
+	tristate "Qualcomm QPNP PMIC RTC"
+	depends on SPMI && OF_SPMI && MSM_QPNP_INT
+	help
+	  Say Y here if you want to support the Qualcomm QPNP PMIC RTC.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called qpnp-rtc.
+
 endif # RTC_CLASS
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 8a3cecd..295f927 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -88,6 +88,7 @@
 obj-$(CONFIG_RTC_DRV_PS3)	+= rtc-ps3.o
 obj-$(CONFIG_RTC_DRV_PUV3)	+= rtc-puv3.o
 obj-$(CONFIG_RTC_DRV_PXA)	+= rtc-pxa.o
+obj-$(CONFIG_RTC_DRV_QPNP)      += qpnp-rtc.o
 obj-$(CONFIG_RTC_DRV_R9701)	+= rtc-r9701.o
 obj-$(CONFIG_RTC_DRV_RP5C01)	+= rtc-rp5c01.o
 obj-$(CONFIG_RTC_DRV_RS5C313)	+= rtc-rs5c313.o
diff --git a/drivers/rtc/qpnp-rtc.c b/drivers/rtc/qpnp-rtc.c
new file mode 100644
index 0000000..5650e74
--- /dev/null
+++ b/drivers/rtc/qpnp-rtc.c
@@ -0,0 +1,641 @@
+/* Copyright (c) 2012, Code Aurora Forum. 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/module.h>
+#include <linux/init.h>
+#include <linux/rtc.h>
+#include <linux/pm.h>
+#include <linux/slab.h>
+#include <linux/idr.h>
+#include <linux/of_device.h>
+#include <linux/spmi.h>
+#include <linux/spinlock.h>
+#include <linux/spmi.h>
+
+/* RTC/ALARM Register offsets */
+#define REG_OFFSET_ALARM_RW	0x40
+#define REG_OFFSET_ALARM_CTRL1	0x46
+#define REG_OFFSET_ALARM_CTRL2	0x48
+#define REG_OFFSET_RTC_WRITE	0x40
+#define REG_OFFSET_RTC_CTRL	0x46
+#define REG_OFFSET_RTC_READ	0x48
+#define REG_OFFSET_PERP_SUBTYPE	0x05
+
+/* RTC_CTRL register bit fields */
+#define BIT_RTC_ENABLE		BIT(7)
+#define BIT_RTC_ALARM_ENABLE	BIT(7)
+#define BIT_RTC_ABORT_ENABLE	BIT(0)
+#define BIT_RTC_ALARM_CLEAR	BIT(0)
+
+/* RTC/ALARM peripheral subtype values */
+#define RTC_PERPH_SUBTYPE       0x1
+#define ALARM_PERPH_SUBTYPE     0x3
+
+#define NUM_8_BIT_RTC_REGS	0x4
+
+#define TO_SECS(arr)		(arr[0] | (arr[1] << 8) | (arr[2] << 16) | \
+							(arr[3] << 24))
+
+/* rtc driver internal structure */
+struct qpnp_rtc {
+	u8  rtc_ctrl_reg;
+	u8  alarm_ctrl_reg1;
+	u16 rtc_base;
+	u16 alarm_base;
+	u32 rtc_write_enable;
+	u32 rtc_alarm_powerup;
+	int rtc_alarm_irq;
+	struct device *rtc_dev;
+	struct rtc_device *rtc;
+	struct spmi_device *spmi;
+	spinlock_t alarm_ctrl_lock;
+};
+
+static int qpnp_read_wrapper(struct qpnp_rtc *rtc_dd, u8 *rtc_val,
+			u16 base, int count)
+{
+	int rc;
+	struct spmi_device *spmi = rtc_dd->spmi;
+
+	rc = spmi_ext_register_readl(spmi->ctrl, spmi->sid, base, rtc_val,
+					count);
+	if (rc) {
+		dev_err(rtc_dd->rtc_dev, "SPMI read failed\n");
+		return rc;
+	}
+	return 0;
+}
+
+static int qpnp_write_wrapper(struct qpnp_rtc *rtc_dd, u8 *rtc_val,
+			u16 base, int count)
+{
+	int rc;
+	struct spmi_device *spmi = rtc_dd->spmi;
+
+	rc = spmi_ext_register_writel(spmi->ctrl, spmi->sid, base, rtc_val,
+					count);
+	if (rc) {
+		dev_err(rtc_dd->rtc_dev, "SPMI write failed\n");
+		return rc;
+	}
+
+	return 0;
+}
+
+static int
+qpnp_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+	int rc;
+	unsigned long secs, irq_flags;
+	u8 value[4], reg = 0, alarm_enabled = 0, ctrl_reg;
+	struct qpnp_rtc *rtc_dd = dev_get_drvdata(dev);
+
+	rtc_tm_to_time(tm, &secs);
+
+	value[0] = secs & 0xFF;
+	value[1] = (secs >> 8) & 0xFF;
+	value[2] = (secs >> 16) & 0xFF;
+	value[3] = (secs >> 24) & 0xFF;
+
+	dev_dbg(dev, "Seconds value to be written to RTC = %lu\n", secs);
+
+	spin_lock_irqsave(&rtc_dd->alarm_ctrl_lock, irq_flags);
+	ctrl_reg = rtc_dd->alarm_ctrl_reg1;
+
+	if (ctrl_reg & BIT_RTC_ALARM_ENABLE) {
+		alarm_enabled = 1;
+		ctrl_reg &= ~BIT_RTC_ALARM_ENABLE;
+		rc = qpnp_write_wrapper(rtc_dd, &ctrl_reg,
+			rtc_dd->alarm_base + REG_OFFSET_ALARM_CTRL1, 1);
+		if (rc) {
+			dev_err(dev, "Write to ALARM ctrl reg failed\n");
+			goto rtc_rw_fail;
+		}
+	} else
+		spin_unlock_irqrestore(&rtc_dd->alarm_ctrl_lock, irq_flags);
+
+	/*
+	 * 32 bit seconds value is coverted to four 8 bit values
+	 *	|<------  32 bit time value in seconds  ------>|
+	 *      <- 8 bit ->|<- 8 bit ->|<- 8 bit ->|<- 8 bit ->|
+	 *       ----------------------------------------------
+	 *      | BYTE[3]  |  BYTE[2]  |  BYTE[1]  |  BYTE[0]  |
+	 *       ----------------------------------------------
+	 *
+	 * RTC has four 8 bit registers for writting time in seconds:
+	 *             WDATA[3], WDATA[2], WDATA[1], WDATA[0]
+	 *
+	 * Write to the RTC registers should be done in following order
+	 * Clear WDATA[0] register
+	 *
+	 * Write BYTE[1], BYTE[2] and BYTE[3] of time to
+	 * RTC WDATA[3], WDATA[2], WDATA[1] registers
+	 *
+	 * Write BYTE[0] of time to RTC WDATA[0] register
+	 *
+	 * Clearing BYTE[0] and writting in the end will prevent any
+	 * unintentional overflow from WDATA[0] to higher bytes during the
+	 * write operation
+	 */
+
+	/* Clear WDATA[0] */
+	reg = 0x0;
+	rc = qpnp_write_wrapper(rtc_dd, &reg,
+				rtc_dd->rtc_base + REG_OFFSET_RTC_WRITE, 1);
+	if (rc) {
+		dev_err(dev, "Write to RTC reg failed\n");
+		goto rtc_rw_fail;
+	}
+
+	/* Write to WDATA[3], WDATA[2] and WDATA[1] */
+	rc = qpnp_write_wrapper(rtc_dd, &value[1],
+			rtc_dd->rtc_base + REG_OFFSET_RTC_WRITE + 1, 3);
+	if (rc) {
+		dev_err(dev, "Write to RTC reg failed\n");
+		goto rtc_rw_fail;
+	}
+
+	/* Write to WDATA[0] */
+	rc = qpnp_write_wrapper(rtc_dd, value,
+				rtc_dd->rtc_base + REG_OFFSET_RTC_WRITE, 1);
+	if (rc) {
+		dev_err(dev, "Write to RTC reg failed\n");
+		goto rtc_rw_fail;
+	}
+
+	if (alarm_enabled) {
+		ctrl_reg |= BIT_RTC_ALARM_ENABLE;
+		rc = qpnp_write_wrapper(rtc_dd, &ctrl_reg,
+			rtc_dd->alarm_base + REG_OFFSET_ALARM_CTRL1, 1);
+		if (rc) {
+			dev_err(dev, "Write to ALARM ctrl reg failed\n");
+			goto rtc_rw_fail;
+		}
+	}
+
+	rtc_dd->alarm_ctrl_reg1 = ctrl_reg;
+
+rtc_rw_fail:
+	if (alarm_enabled)
+		spin_unlock_irqrestore(&rtc_dd->alarm_ctrl_lock, irq_flags);
+
+	return rc;
+}
+
+static int
+qpnp_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+	int rc;
+	u8 value[4], reg;
+	unsigned long secs;
+	struct qpnp_rtc *rtc_dd = dev_get_drvdata(dev);
+
+	rc = qpnp_read_wrapper(rtc_dd, value,
+				rtc_dd->rtc_base + REG_OFFSET_RTC_READ,
+				NUM_8_BIT_RTC_REGS);
+	if (rc) {
+		dev_err(dev, "Read from RTC reg failed\n");
+		return rc;
+	}
+
+	/*
+	 * Read the LSB again and check if there has been a carry over
+	 * If there is, redo the read operation
+	 */
+	rc = qpnp_read_wrapper(rtc_dd, &reg,
+				rtc_dd->rtc_base + REG_OFFSET_RTC_READ, 1);
+	if (rc) {
+		dev_err(dev, "Read from RTC reg failed\n");
+		return rc;
+	}
+
+	if (reg < value[0]) {
+		rc = qpnp_read_wrapper(rtc_dd, value,
+				rtc_dd->rtc_base + REG_OFFSET_RTC_READ,
+				NUM_8_BIT_RTC_REGS);
+		if (rc) {
+			dev_err(dev, "Read from RTC reg failed\n");
+			return rc;
+		}
+	}
+
+	secs = TO_SECS(value);
+
+	rtc_time_to_tm(secs, tm);
+
+	rc = rtc_valid_tm(tm);
+	if (rc) {
+		dev_err(dev, "Invalid time read from RTC\n");
+		return rc;
+	}
+
+	dev_dbg(dev, "secs = %lu, h:m:s == %d:%d:%d, d/m/y = %d/%d/%d\n",
+			secs, tm->tm_hour, tm->tm_min, tm->tm_sec,
+			tm->tm_mday, tm->tm_mon, tm->tm_year);
+
+	return 0;
+}
+
+static int
+qpnp_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
+{
+	int rc;
+	u8 value[4], ctrl_reg;
+	unsigned long secs, secs_rtc, irq_flags;
+	struct qpnp_rtc *rtc_dd = dev_get_drvdata(dev);
+	struct rtc_time rtc_tm;
+
+	rtc_tm_to_time(&alarm->time, &secs);
+
+	/*
+	 * Read the current RTC time and verify if the alarm time is in the
+	 * past. If yes, return invalid
+	 */
+	rc = qpnp_rtc_read_time(dev, &rtc_tm);
+	if (rc) {
+		dev_err(dev, "Unable to read RTC time\n");
+		return -EINVAL;
+	}
+
+	rtc_tm_to_time(&rtc_tm, &secs_rtc);
+	if (secs < secs_rtc) {
+		dev_err(dev, "Trying to set alarm in the past\n");
+		return -EINVAL;
+	}
+
+	value[0] = secs & 0xFF;
+	value[1] = (secs >> 8) & 0xFF;
+	value[2] = (secs >> 16) & 0xFF;
+	value[3] = (secs >> 24) & 0xFF;
+
+	spin_lock_irqsave(&rtc_dd->alarm_ctrl_lock, irq_flags);
+
+	rc = qpnp_write_wrapper(rtc_dd, value,
+				rtc_dd->alarm_base + REG_OFFSET_ALARM_RW,
+				NUM_8_BIT_RTC_REGS);
+	if (rc) {
+		dev_err(dev, "Write to ALARM reg failed\n");
+		goto rtc_rw_fail;
+	}
+
+	ctrl_reg = (alarm->enabled) ?
+			(rtc_dd->alarm_ctrl_reg1 | BIT_RTC_ALARM_ENABLE) :
+			(rtc_dd->alarm_ctrl_reg1 & ~BIT_RTC_ALARM_ENABLE);
+
+	rc = qpnp_write_wrapper(rtc_dd, &ctrl_reg,
+			rtc_dd->alarm_base + REG_OFFSET_ALARM_CTRL1, 1);
+	if (rc) {
+		dev_err(dev, "Write to ALARM cntrol reg failed\n");
+		goto rtc_rw_fail;
+	}
+
+	rtc_dd->alarm_ctrl_reg1 = ctrl_reg;
+
+	dev_dbg(dev, "Alarm Set for h:r:s=%d:%d:%d, d/m/y=%d/%d/%d\n",
+			alarm->time.tm_hour, alarm->time.tm_min,
+			alarm->time.tm_sec, alarm->time.tm_mday,
+			alarm->time.tm_mon, alarm->time.tm_year);
+rtc_rw_fail:
+	spin_unlock_irqrestore(&rtc_dd->alarm_ctrl_lock, irq_flags);
+	return rc;
+}
+
+static int
+qpnp_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
+{
+	int rc;
+	u8 value[4];
+	unsigned long secs;
+	struct qpnp_rtc *rtc_dd = dev_get_drvdata(dev);
+
+	rc = qpnp_read_wrapper(rtc_dd, value,
+				rtc_dd->alarm_base + REG_OFFSET_ALARM_RW,
+				NUM_8_BIT_RTC_REGS);
+	if (rc) {
+		dev_err(dev, "Read from ALARM reg failed\n");
+		return rc;
+	}
+
+	secs = TO_SECS(value);
+	rtc_time_to_tm(secs, &alarm->time);
+
+	rc = rtc_valid_tm(&alarm->time);
+	if (rc) {
+		dev_err(dev, "Invalid time read from RTC\n");
+		return rc;
+	}
+
+	dev_dbg(dev, "Alarm set for - h:r:s=%d:%d:%d, d/m/y=%d/%d/%d\n",
+		alarm->time.tm_hour, alarm->time.tm_min,
+				alarm->time.tm_sec, alarm->time.tm_mday,
+				alarm->time.tm_mon, alarm->time.tm_year);
+
+	return 0;
+}
+
+
+static int
+qpnp_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
+{
+	int rc;
+	unsigned long irq_flags;
+	struct qpnp_rtc *rtc_dd = dev_get_drvdata(dev);
+	u8 ctrl_reg;
+
+	spin_lock_irqsave(&rtc_dd->alarm_ctrl_lock, irq_flags);
+	ctrl_reg = rtc_dd->alarm_ctrl_reg1;
+	ctrl_reg = enabled ? (ctrl_reg | BIT_RTC_ALARM_ENABLE) :
+				(ctrl_reg & ~BIT_RTC_ALARM_ENABLE);
+
+	rc = qpnp_write_wrapper(rtc_dd, &ctrl_reg,
+			rtc_dd->alarm_base + REG_OFFSET_ALARM_CTRL1, 1);
+	if (rc) {
+		dev_err(dev, "Write to ALARM control reg failed\n");
+		goto rtc_rw_fail;
+	}
+
+	rtc_dd->alarm_ctrl_reg1 = ctrl_reg;
+
+rtc_rw_fail:
+	spin_unlock_irqrestore(&rtc_dd->alarm_ctrl_lock, irq_flags);
+	return rc;
+}
+
+static struct rtc_class_ops qpnp_rtc_ops = {
+	.read_time = qpnp_rtc_read_time,
+	.set_alarm = qpnp_rtc_set_alarm,
+	.read_alarm = qpnp_rtc_read_alarm,
+	.alarm_irq_enable = qpnp_rtc_alarm_irq_enable,
+};
+
+static irqreturn_t qpnp_alarm_trigger(int irq, void *dev_id)
+{
+	struct qpnp_rtc *rtc_dd = dev_id;
+	u8 ctrl_reg;
+	int rc;
+	unsigned long irq_flags;
+
+	rtc_update_irq(rtc_dd->rtc, 1, RTC_IRQF | RTC_AF);
+
+	spin_lock_irqsave(&rtc_dd->alarm_ctrl_lock, irq_flags);
+
+	/* Clear the alarm enable bit */
+	ctrl_reg = rtc_dd->alarm_ctrl_reg1;
+	ctrl_reg &= ~BIT_RTC_ALARM_ENABLE;
+
+	rc = qpnp_write_wrapper(rtc_dd, &ctrl_reg,
+			rtc_dd->alarm_base + REG_OFFSET_ALARM_CTRL1, 1);
+	if (rc) {
+		spin_unlock_irqrestore(&rtc_dd->alarm_ctrl_lock, irq_flags);
+		dev_err(rtc_dd->rtc_dev,
+				"Write to ALARM control reg failed\n");
+		goto rtc_alarm_handled;
+	}
+
+	rtc_dd->alarm_ctrl_reg1 = ctrl_reg;
+	spin_unlock_irqrestore(&rtc_dd->alarm_ctrl_lock, irq_flags);
+
+	/* Set ALARM_CLR bit */
+	ctrl_reg = 0x1;
+	rc = qpnp_write_wrapper(rtc_dd, &ctrl_reg,
+			rtc_dd->alarm_base + REG_OFFSET_ALARM_CTRL2, 1);
+	if (rc)
+		dev_err(rtc_dd->rtc_dev,
+				"Write to ALARM control reg failed\n");
+
+rtc_alarm_handled:
+	return IRQ_HANDLED;
+}
+
+static int __devinit qpnp_rtc_probe(struct spmi_device *spmi)
+{
+	int rc;
+	u8 subtype;
+	struct qpnp_rtc *rtc_dd;
+	struct resource *resource;
+	struct spmi_resource *spmi_resource;
+
+	rtc_dd = devm_kzalloc(&spmi->dev, sizeof(*rtc_dd), GFP_KERNEL);
+	if (rtc_dd == NULL) {
+		dev_err(&spmi->dev, "Unable to allocate memory!\n");
+		return -ENOMEM;
+	}
+
+	/* Get the rtc write property */
+	rc = of_property_read_u32(spmi->dev.of_node, "qcom,qpnp-rtc-write",
+						&rtc_dd->rtc_write_enable);
+	if (rc && rc != -EINVAL) {
+		dev_err(&spmi->dev,
+			"Error reading rtc_write_enable property %d\n", rc);
+		return rc;
+	}
+
+	rc = of_property_read_u32(spmi->dev.of_node,
+						"qcom,qpnp-rtc-alarm-pwrup",
+						&rtc_dd->rtc_alarm_powerup);
+	if (rc && rc != -EINVAL) {
+		dev_err(&spmi->dev,
+			"Error reading rtc_alarm_powerup property %d\n", rc);
+		return rc;
+	}
+
+	/* Initialise spinlock to protect RTC control register */
+	spin_lock_init(&rtc_dd->alarm_ctrl_lock);
+
+	rtc_dd->rtc_dev = &(spmi->dev);
+	rtc_dd->spmi = spmi;
+
+	/* Get RTC/ALARM resources */
+	spmi_for_each_container_dev(spmi_resource, spmi) {
+		if (!spmi_resource) {
+			dev_err(&spmi->dev,
+				"%s: rtc_alarm: spmi resource absent!\n",
+				__func__);
+			rc = -ENXIO;
+			goto fail_rtc_enable;
+		}
+
+		resource = spmi_get_resource(spmi, spmi_resource,
+							IORESOURCE_MEM, 0);
+		if (!(resource && resource->start)) {
+			dev_err(&spmi->dev,
+				"%s: node %s IO resource absent!\n",
+				__func__, spmi->dev.of_node->full_name);
+			rc = -ENXIO;
+			goto fail_rtc_enable;
+		}
+
+		rc = qpnp_read_wrapper(rtc_dd, &subtype,
+				resource->start + REG_OFFSET_PERP_SUBTYPE, 1);
+		if (rc) {
+			dev_err(&spmi->dev,
+				"Peripheral subtype read failed\n");
+			goto fail_rtc_enable;
+		}
+
+		switch (subtype) {
+		case RTC_PERPH_SUBTYPE:
+			rtc_dd->rtc_base = resource->start;
+			break;
+		case ALARM_PERPH_SUBTYPE:
+			rtc_dd->alarm_base = resource->start;
+			rtc_dd->rtc_alarm_irq =
+				spmi_get_irq(spmi, spmi_resource, 0);
+			if (rtc_dd->rtc_alarm_irq < 0) {
+				dev_err(&spmi->dev, "ALARM IRQ absent\n");
+				rc = -ENXIO;
+				goto fail_rtc_enable;
+			}
+			break;
+		default:
+			dev_err(&spmi->dev, "Invalid peripheral subtype\n");
+			rc = -EINVAL;
+			goto fail_rtc_enable;
+		}
+	}
+
+	rtc_dd->rtc_ctrl_reg = BIT_RTC_ENABLE;
+	rc = qpnp_write_wrapper(rtc_dd, &rtc_dd->rtc_ctrl_reg,
+				rtc_dd->rtc_base + REG_OFFSET_RTC_CTRL, 1);
+	if (rc) {
+		dev_err(&spmi->dev,
+				"Write to RTC control reg failed\n");
+		goto fail_rtc_enable;
+	}
+
+	/* Enable abort enable feature */
+	rtc_dd->alarm_ctrl_reg1 = BIT_RTC_ABORT_ENABLE;
+	rc = qpnp_write_wrapper(rtc_dd, &rtc_dd->alarm_ctrl_reg1,
+			rtc_dd->alarm_base + REG_OFFSET_ALARM_CTRL1, 1);
+	if (rc) {
+		dev_err(&spmi->dev, "SPMI write failed!\n");
+		goto fail_rtc_enable;
+	}
+
+	if (rtc_dd->rtc_write_enable == true)
+		qpnp_rtc_ops.set_time = qpnp_rtc_set_time;
+
+	dev_set_drvdata(&spmi->dev, rtc_dd);
+
+	/* Register the RTC device */
+	rtc_dd->rtc = rtc_device_register("qpnp_rtc", &spmi->dev,
+						&qpnp_rtc_ops, THIS_MODULE);
+	if (IS_ERR(rtc_dd->rtc)) {
+		dev_err(&spmi->dev, "%s: RTC registration failed (%ld)\n",
+					__func__, PTR_ERR(rtc_dd->rtc));
+		rc = PTR_ERR(rtc_dd->rtc);
+		goto fail_rtc_enable;
+	}
+
+	/* Request the alarm IRQ */
+	rc = request_any_context_irq(rtc_dd->rtc_alarm_irq,
+				 qpnp_alarm_trigger, IRQF_TRIGGER_RISING,
+				 "qpnp_rtc_alarm", rtc_dd);
+	if (rc) {
+		dev_err(&spmi->dev, "Request IRQ failed (%d)\n", rc);
+		goto fail_req_irq;
+	}
+
+	device_init_wakeup(&spmi->dev, 1);
+	enable_irq_wake(rtc_dd->rtc_alarm_irq);
+
+	dev_dbg(&spmi->dev, "Probe success !!\n");
+
+	return 0;
+
+fail_req_irq:
+	rtc_device_unregister(rtc_dd->rtc);
+fail_rtc_enable:
+	dev_set_drvdata(&spmi->dev, NULL);
+
+	return rc;
+}
+
+static int __devexit qpnp_rtc_remove(struct spmi_device *spmi)
+{
+	struct qpnp_rtc *rtc_dd = dev_get_drvdata(&spmi->dev);
+
+	device_init_wakeup(&spmi->dev, 0);
+	free_irq(rtc_dd->rtc_alarm_irq, rtc_dd);
+	rtc_device_unregister(rtc_dd->rtc);
+	dev_set_drvdata(&spmi->dev, NULL);
+
+	return 0;
+}
+
+static void qpnp_rtc_shutdown(struct spmi_device *spmi)
+{
+	u8 value[4] = {0};
+	u8 reg;
+	int rc;
+	unsigned long irq_flags;
+	struct qpnp_rtc *rtc_dd = dev_get_drvdata(&spmi->dev);
+	bool rtc_alarm_powerup = rtc_dd->rtc_alarm_powerup;
+
+	if (!rtc_alarm_powerup) {
+		spin_lock_irqsave(&rtc_dd->alarm_ctrl_lock, irq_flags);
+		dev_dbg(&spmi->dev, "Disabling alarm interrupts\n");
+
+		/* Disable RTC alarms */
+		reg = rtc_dd->alarm_ctrl_reg1;
+		reg &= ~BIT_RTC_ALARM_ENABLE;
+		rc = qpnp_write_wrapper(rtc_dd, &reg,
+			rtc_dd->alarm_base + REG_OFFSET_ALARM_CTRL1, 1);
+		if (rc) {
+			dev_err(rtc_dd->rtc_dev, "SPMI write failed\n");
+			goto fail_alarm_disable;
+		}
+
+		/* Clear Alarm register */
+		rc = qpnp_write_wrapper(rtc_dd, value,
+				rtc_dd->alarm_base + REG_OFFSET_ALARM_RW,
+				NUM_8_BIT_RTC_REGS);
+		if (rc)
+			dev_err(rtc_dd->rtc_dev, "SPMI write failed\n");
+
+fail_alarm_disable:
+		spin_unlock_irqrestore(&rtc_dd->alarm_ctrl_lock, irq_flags);
+	}
+}
+
+static struct of_device_id spmi_match_table[] = {
+	{
+		.compatible = "qcom,qpnp-rtc",
+	},
+	{}
+};
+
+static struct spmi_driver qpnp_rtc_driver = {
+	.probe          = qpnp_rtc_probe,
+	.remove         = __devexit_p(qpnp_rtc_remove),
+	.shutdown       = qpnp_rtc_shutdown,
+	.driver = {
+		.name   = "qcom,qpnp-rtc",
+		.owner  = THIS_MODULE,
+		.of_match_table = spmi_match_table,
+	},
+};
+
+static int __init qpnp_rtc_init(void)
+{
+	return spmi_driver_register(&qpnp_rtc_driver);
+}
+module_init(qpnp_rtc_init);
+
+static void __exit qpnp_rtc_exit(void)
+{
+	spmi_driver_unregister(&qpnp_rtc_driver);
+}
+module_exit(qpnp_rtc_exit);
+
+MODULE_DESCRIPTION("SMPI PMIC RTC driver");
+MODULE_LICENSE("GPL V2");
diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
index d99a02a..b2d2f74 100644
--- a/drivers/thermal/Kconfig
+++ b/drivers/thermal/Kconfig
@@ -52,6 +52,16 @@
 	  Also able to set threshold temperature for both hot and cold and update
 	  when a threshold is reached.
 
+config THERMAL_TSENS8974
+	tristate "Qualcomm 8974 TSENS Temperature driver"
+	depends on THERMAL
+	help
+	  This enables the thermal sysfs driver for the TSENS device. It shows
+	  up in Sysfs as a thermal zone with multiple trip points. Also able
+	  to set threshold temperature for both warm and cool and update
+	  thermal userspace client when a threshold is reached. Warm/Cool
+	  temperature thresholds can be set independently for each sensor.
+
 config THERMAL_PM8XXX
 	tristate "Qualcomm PMIC PM8xxx Temperature Alarm"
 	depends on THERMAL
diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
index 275a692..f7e7cc6 100644
--- a/drivers/thermal/Makefile
+++ b/drivers/thermal/Makefile
@@ -8,4 +8,5 @@
 obj-$(CONFIG_THERMAL_TSENS8960) += msm8960_tsens.o
 obj-$(CONFIG_THERMAL_PM8XXX)	+= pm8xxx-tm.o
 obj-$(CONFIG_THERMAL_MONITOR)	+= msm_thermal.o
-obj-$(CONFIG_SPEAR_THERMAL)		+= spear_thermal.o
\ No newline at end of file
+obj-$(CONFIG_SPEAR_THERMAL)		+= spear_thermal.o
+obj-$(CONFIG_THERMAL_TSENS8974)	+= msm8974-tsens.o
diff --git a/drivers/thermal/msm8974-tsens.c b/drivers/thermal/msm8974-tsens.c
new file mode 100644
index 0000000..6628b79
--- /dev/null
+++ b/drivers/thermal/msm8974-tsens.c
@@ -0,0 +1,870 @@
+/* Copyright (c) 2012, Code Aurora Forum. 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/module.h>
+#include <linux/platform_device.h>
+#include <linux/thermal.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/msm_tsens.h>
+#include <linux/err.h>
+#include <linux/of.h>
+
+#include <mach/msm_iomap.h>
+
+#define TSENS_DRIVER_NAME		"msm-tsens"
+/* TSENS register info */
+#define TSENS_UPPER_LOWER_INTERRUPT_CTRL(n)		((n) + 0x1000)
+#define TSENS_INTERRUPT_EN		BIT(0)
+
+#define TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR(n)	((n) + 0x1004)
+#define TSENS_UPPER_STATUS_CLR		BIT(21)
+#define TSENS_LOWER_STATUS_CLR		BIT(20)
+#define TSENS_UPPER_THRESHOLD_MASK	0xffc00
+#define TSENS_LOWER_THRESHOLD_MASK	0x3ff
+#define TSENS_UPPER_THRESHOLD_SHIFT	10
+
+#define TSENS_S0_STATUS_ADDR(n)		((n) + 0x1030)
+#define TSENS_SN_ADDR_OFFSET		0x4
+#define TSENS_SN_STATUS_TEMP_MASK	0x3ff
+#define TSENS_SN_STATUS_LOWER_STATUS	BIT(11)
+#define TSENS_SN_STATUS_UPPER_STATUS	BIT(12)
+#define TSENS_STATUS_ADDR_OFFSET			2
+
+#define TSENS_TRDY_ADDR(n)		((n) + 0x105c)
+#define TSENS_TRDY_MASK			BIT(0)
+
+#define TSENS_CTRL_ADDR(n)		(n)
+#define TSENS_SW_RST			BIT(1)
+#define TSENS_SN_MIN_MAX_STATUS_CTRL(n)	((n) + 4)
+#define TSENS_GLOBAL_CONFIG(n)		((n) + 0x34)
+#define TSENS_S0_MAIN_CONFIG(n)		((n) + 0x38)
+#define TSENS_SN_REMOTE_CONFIG(n)	((n) + 0x3c)
+
+/* TSENS calibration Mask data */
+#define TSENS_BASE1_MASK		0xff
+#define TSENS0_POINT1_MASK		0x3f00
+#define TSENS1_POINT1_MASK		0xfc000
+#define TSENS2_POINT1_MASK		0x3f00000
+#define TSENS3_POINT1_MASK		0xfc000000
+#define TSENS4_POINT1_MASK		0x3f
+#define TSENS5_POINT1_MASK		0xfc00
+#define TSENS6_POINT1_MASK		0x3f000
+#define TSENS7_POINT1_MASK		0xfc0000
+#define TSENS8_POINT1_MASK		0x3f000000
+#define TSENS9_POINT1_MASK		0x3f
+#define TSENS10_POINT1_MASK		0xfc00
+#define TSENS_CAL_SEL_0_1		0xc0000000
+#define TSENS_CAL_SEL_2			BIT(30)
+#define TSENS_CAL_SEL_SHIFT		30
+#define TSENS_CAL_SEL_SHIFT_2		28
+#define TSENS_ONE_POINT_CALIB		0x3
+#define TSENS_TWO_POINT_CALIB		0x2
+
+#define TSENS_BASE2_MASK		0xff000
+#define TSENS0_POINT2_MASK		0x3f00000
+#define TSENS1_POINT2_MASK		0xfc000000
+#define TSENS2_POINT2_MASK		0x3f
+#define TSENS3_POINT2_MASK		0xfc00
+#define TSENS4_POINT2_MASK		0x3f000
+#define TSENS5_POINT2_MASK		0xfc0000
+#define TSENS6_POINT2_MASK		0x3f000000
+#define TSENS7_POINT2_MASK		0x3f
+#define TSENS8_POINT2_MASK		0xfc00
+#define TSENS9_POINT2_MASK		0x3f000
+#define TSENS10_POINT2_MASK		0xfc0000
+
+#define TSENS_BIT_APPEND		0x3
+#define TSENS_CAL_DEGC_POINT1		30
+#define TSENS_CAL_DEGC_POINT2		120
+#define TSENS_SLOPE_FACTOR		1000
+
+/* TSENS register data */
+#define TSENS_TRDY_RDY_MIN_TIME		2000
+#define TSENS_TRDY_RDY_MAX_TIME		2100
+#define TSENS_THRESHOLD_MAX_CODE	0x3ff
+#define TSENS_THRESHOLD_MIN_CODE	0x0
+
+#define TSENS_CTRL_INIT_DATA1		0x3fffff9
+#define TSENS_GLOBAL_INIT_DATA		0x20013
+#define TSENS_S0_MAIN_CFG_INIT_DATA	0x1ba
+#define TSENS_SN_MIN_MAX_STATUS_CTRL_DATA	0x3ffc00
+#define TSENS_SN_REMOTE_CFG_DATA	0xdba
+
+/* Trips: warm and cool */
+enum tsens_trip_type {
+	TSENS_TRIP_WARM = 0,
+	TSENS_TRIP_COOL,
+	TSENS_TRIP_NUM,
+};
+
+struct tsens_tm_device_sensor {
+	struct thermal_zone_device	*tz_dev;
+	enum thermal_device_mode	mode;
+	unsigned int			sensor_num;
+	struct work_struct		work;
+	int				offset;
+	int				calib_data_point1;
+	int				calib_data_point2;
+	uint32_t			slope_mul_tsens_factor;
+};
+
+struct tsens_tm_device {
+	struct platform_device		*pdev;
+	bool				prev_reading_avail;
+	int				tsens_factor;
+	uint32_t			tsens_num_sensor;
+	int				tsens_irq;
+	void				*tsens_addr;
+	void				*tsens_calib_addr;
+	int				tsens_len;
+	int				calib_len;
+	struct resource			*res_tsens_mem;
+	struct resource			*res_calib_mem;
+	struct tsens_tm_device_sensor	sensor[0];
+};
+
+struct tsens_tm_device *tmdev;
+
+static int tsens_tz_code_to_degc(int adc_code, int sensor_num)
+{
+	int degcbeforefactor, degc;
+	degcbeforefactor = (adc_code *
+			tmdev->sensor[sensor_num].slope_mul_tsens_factor
+			+ tmdev->sensor[sensor_num].offset);
+
+	if (degcbeforefactor == 0)
+		degc = degcbeforefactor;
+	else if (degcbeforefactor > 0)
+		degc = (degcbeforefactor + tmdev->tsens_factor/2)
+				/ tmdev->tsens_factor;
+	else
+		degc = (degcbeforefactor - tmdev->tsens_factor/2)
+				/ tmdev->tsens_factor;
+	return degc;
+}
+
+static int tsens_tz_degc_to_code(int degc, int sensor_num)
+{
+	int code = (degc * tmdev->tsens_factor -
+		tmdev->sensor[sensor_num].offset
+		+ tmdev->sensor[sensor_num].slope_mul_tsens_factor/2)
+		/ tmdev->sensor[sensor_num].slope_mul_tsens_factor;
+
+	if (code > TSENS_THRESHOLD_MAX_CODE)
+		code = TSENS_THRESHOLD_MAX_CODE;
+	else if (code < TSENS_THRESHOLD_MIN_CODE)
+		code = TSENS_THRESHOLD_MIN_CODE;
+	return code;
+}
+
+static void msm_tsens_get_temp(int sensor_num, unsigned long *temp)
+{
+	unsigned int code, sensor_addr;
+
+	if (!tmdev->prev_reading_avail) {
+		while (!(readl_relaxed(TSENS_TRDY_ADDR(tmdev->tsens_addr))
+					& TSENS_TRDY_MASK))
+			usleep_range(TSENS_TRDY_RDY_MIN_TIME,
+				TSENS_TRDY_RDY_MAX_TIME);
+		tmdev->prev_reading_avail = true;
+	}
+
+	sensor_addr =
+		(unsigned int)TSENS_S0_STATUS_ADDR(tmdev->tsens_addr);
+	code = readl_relaxed(sensor_addr +
+			(sensor_num << TSENS_STATUS_ADDR_OFFSET));
+	*temp = tsens_tz_code_to_degc((code & TSENS_SN_STATUS_TEMP_MASK),
+								sensor_num);
+}
+
+static int tsens_tz_get_temp(struct thermal_zone_device *thermal,
+			     unsigned long *temp)
+{
+	struct tsens_tm_device_sensor *tm_sensor = thermal->devdata;
+
+	if (!tm_sensor || tm_sensor->mode != THERMAL_DEVICE_ENABLED || !temp)
+		return -EINVAL;
+
+	msm_tsens_get_temp(tm_sensor->sensor_num, temp);
+
+	return 0;
+}
+
+int tsens_get_temp(struct tsens_device *device, unsigned long *temp)
+{
+	if (!tmdev)
+		return -ENODEV;
+
+	msm_tsens_get_temp(device->sensor_num, temp);
+
+	return 0;
+}
+EXPORT_SYMBOL(msm_tsens_get_temp);
+
+static int tsens_tz_get_mode(struct thermal_zone_device *thermal,
+			      enum thermal_device_mode *mode)
+{
+	struct tsens_tm_device_sensor *tm_sensor = thermal->devdata;
+
+	if (!tm_sensor || !mode)
+		return -EINVAL;
+
+	*mode = tm_sensor->mode;
+
+	return 0;
+}
+
+static int tsens_tz_get_trip_type(struct thermal_zone_device *thermal,
+				   int trip, enum thermal_trip_type *type)
+{
+	struct tsens_tm_device_sensor *tm_sensor = thermal->devdata;
+
+	if (!tm_sensor || trip < 0 || !type)
+		return -EINVAL;
+
+	switch (trip) {
+	case TSENS_TRIP_WARM:
+		*type = THERMAL_TRIP_CONFIGURABLE_HI;
+		break;
+	case TSENS_TRIP_COOL:
+		*type = THERMAL_TRIP_CONFIGURABLE_LOW;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int tsens_tz_activate_trip_type(struct thermal_zone_device *thermal,
+			int trip, enum thermal_trip_activation_mode mode)
+{
+	struct tsens_tm_device_sensor *tm_sensor = thermal->devdata;
+	unsigned int reg_cntl, code, hi_code, lo_code, mask;
+
+	if (!tm_sensor || trip < 0)
+		return -EINVAL;
+
+	lo_code = TSENS_THRESHOLD_MIN_CODE;
+	hi_code = TSENS_THRESHOLD_MAX_CODE;
+
+	reg_cntl = readl_relaxed((TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR
+				(tmdev->tsens_addr) +
+				(tm_sensor->sensor_num * 4)));
+	switch (trip) {
+	case TSENS_TRIP_WARM:
+		code = (reg_cntl & TSENS_UPPER_THRESHOLD_MASK)
+					>> TSENS_UPPER_THRESHOLD_SHIFT;
+		mask = TSENS_UPPER_STATUS_CLR;
+
+		if (!(reg_cntl & TSENS_LOWER_STATUS_CLR))
+			lo_code = (reg_cntl & TSENS_LOWER_THRESHOLD_MASK);
+		break;
+	case TSENS_TRIP_COOL:
+		code = (reg_cntl & TSENS_LOWER_THRESHOLD_MASK);
+		mask = TSENS_LOWER_STATUS_CLR;
+
+		if (!(reg_cntl & TSENS_UPPER_STATUS_CLR))
+			hi_code = (reg_cntl & TSENS_UPPER_THRESHOLD_MASK)
+					>> TSENS_UPPER_THRESHOLD_SHIFT;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (mode == THERMAL_TRIP_ACTIVATION_DISABLED)
+		writel_relaxed(reg_cntl | mask,
+			(TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR
+					(tmdev->tsens_addr) +
+					(tm_sensor->sensor_num * 4)));
+	else {
+		if (code < lo_code || code > hi_code) {
+			pr_err("%s with invalid code %x\n", __func__, code);
+			return -EINVAL;
+		}
+		writel_relaxed(reg_cntl & ~mask,
+		(TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR(tmdev->tsens_addr) +
+		(tm_sensor->sensor_num * 4)));
+	}
+	mb();
+	return 0;
+}
+
+static int tsens_tz_get_trip_temp(struct thermal_zone_device *thermal,
+				   int trip, unsigned long *temp)
+{
+	struct tsens_tm_device_sensor *tm_sensor = thermal->devdata;
+	unsigned int reg;
+
+	if (!tm_sensor || trip < 0 || !temp)
+		return -EINVAL;
+
+	reg = readl_relaxed(TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR
+						(tmdev->tsens_addr) +
+			(tm_sensor->sensor_num * TSENS_SN_ADDR_OFFSET));
+	switch (trip) {
+	case TSENS_TRIP_WARM:
+		reg = (reg & TSENS_UPPER_THRESHOLD_MASK) >>
+				TSENS_UPPER_THRESHOLD_SHIFT;
+		break;
+	case TSENS_TRIP_COOL:
+		reg = (reg & TSENS_LOWER_THRESHOLD_MASK);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	*temp = tsens_tz_code_to_degc(reg, tm_sensor->sensor_num);
+
+	return 0;
+}
+
+static int tsens_tz_notify(struct thermal_zone_device *thermal,
+				int count, enum thermal_trip_type type)
+{
+	/* TSENS driver does not shutdown the device.
+	   All Thermal notification are sent to the
+	   thermal daemon to take appropriate action */
+	pr_debug("%s debug\n", __func__);
+	return 1;
+}
+
+static int tsens_tz_set_trip_temp(struct thermal_zone_device *thermal,
+				   int trip, long temp)
+{
+	struct tsens_tm_device_sensor *tm_sensor = thermal->devdata;
+	unsigned int reg_cntl;
+	int code, hi_code, lo_code, code_err_chk;
+
+	code_err_chk = code = tsens_tz_degc_to_code(temp,
+					tm_sensor->sensor_num);
+	if (!tm_sensor || trip < 0)
+		return -EINVAL;
+
+	lo_code = TSENS_THRESHOLD_MIN_CODE;
+	hi_code = TSENS_THRESHOLD_MAX_CODE;
+
+	reg_cntl = readl_relaxed(TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR
+				(tmdev->tsens_addr) +
+				(tm_sensor->sensor_num * TSENS_SN_ADDR_OFFSET));
+	switch (trip) {
+	case TSENS_TRIP_WARM:
+		code <<= TSENS_UPPER_THRESHOLD_SHIFT;
+		reg_cntl &= ~TSENS_UPPER_THRESHOLD_MASK;
+		if (!(reg_cntl & TSENS_LOWER_STATUS_CLR))
+			lo_code = (reg_cntl & TSENS_LOWER_THRESHOLD_MASK);
+		break;
+	case TSENS_TRIP_COOL:
+		reg_cntl &= ~TSENS_LOWER_THRESHOLD_MASK;
+		if (!(reg_cntl & TSENS_UPPER_STATUS_CLR))
+			hi_code = (reg_cntl & TSENS_UPPER_THRESHOLD_MASK)
+					>> TSENS_UPPER_THRESHOLD_SHIFT;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (code_err_chk < lo_code || code_err_chk > hi_code)
+		return -EINVAL;
+
+	writel_relaxed(reg_cntl | code, (TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR
+					(tmdev->tsens_addr) +
+					(tm_sensor->sensor_num *
+					TSENS_SN_ADDR_OFFSET)));
+	mb();
+	return 0;
+}
+
+static struct thermal_zone_device_ops tsens_thermal_zone_ops = {
+	.get_temp = tsens_tz_get_temp,
+	.get_mode = tsens_tz_get_mode,
+	.get_trip_type = tsens_tz_get_trip_type,
+	.activate_trip_type = tsens_tz_activate_trip_type,
+	.get_trip_temp = tsens_tz_get_trip_temp,
+	.set_trip_temp = tsens_tz_set_trip_temp,
+	.notify = tsens_tz_notify,
+};
+
+static void notify_uspace_tsens_fn(struct work_struct *work)
+{
+	struct tsens_tm_device_sensor *tm = container_of(work,
+		struct tsens_tm_device_sensor, work);
+
+	sysfs_notify(&tm->tz_dev->device.kobj,
+					NULL, "type");
+}
+
+static irqreturn_t tsens_isr(int irq, void *data)
+{
+	struct tsens_tm_device *tm = data;
+	unsigned int i, status, threshold;
+	unsigned int sensor_status_addr, sensor_status_ctrl_addr;
+
+	sensor_status_addr =
+		(unsigned int)TSENS_S0_STATUS_ADDR(tmdev->tsens_addr);
+	sensor_status_ctrl_addr =
+		(unsigned int)TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR
+		(tmdev->tsens_addr);
+	for (i = 0; i < tmdev->tsens_num_sensor; i++) {
+		bool upper_thr = false, lower_thr = false;
+		status = readl_relaxed(sensor_status_addr);
+		threshold = readl_relaxed(sensor_status_ctrl_addr);
+		if (status & TSENS_SN_STATUS_UPPER_STATUS) {
+			writel_relaxed(threshold | TSENS_UPPER_STATUS_CLR,
+				sensor_status_ctrl_addr);
+			upper_thr = true;
+		}
+		if (status & TSENS_SN_STATUS_LOWER_STATUS) {
+			writel_relaxed(threshold | TSENS_LOWER_STATUS_CLR,
+				sensor_status_ctrl_addr);
+			lower_thr = true;
+		}
+		if (upper_thr || lower_thr) {
+			/* Notify user space */
+			schedule_work(&tm->sensor[i].work);
+			pr_debug("sensor:%d trigger temp (%d degC)\n", i,
+				tsens_tz_code_to_degc((status &
+				TSENS_SN_STATUS_TEMP_MASK), i));
+		}
+		sensor_status_addr += TSENS_SN_ADDR_OFFSET;
+		sensor_status_ctrl_addr += TSENS_SN_ADDR_OFFSET;
+	}
+	mb();
+	return IRQ_HANDLED;
+}
+
+static void tsens_hw_init(void)
+{
+	unsigned int reg_cntl = 0;
+	unsigned int i;
+
+	reg_cntl = readl_relaxed(TSENS_CTRL_ADDR(tmdev->tsens_addr));
+	writel_relaxed(reg_cntl | TSENS_SW_RST,
+			TSENS_CTRL_ADDR(tmdev->tsens_addr));
+	writel_relaxed(TSENS_CTRL_INIT_DATA1,
+			TSENS_CTRL_ADDR(tmdev->tsens_addr));
+	writel_relaxed(TSENS_GLOBAL_INIT_DATA,
+			TSENS_GLOBAL_CONFIG(tmdev->tsens_addr));
+	writel_relaxed(TSENS_S0_MAIN_CFG_INIT_DATA,
+			TSENS_S0_MAIN_CONFIG(tmdev->tsens_addr));
+	for (i = 0; i < tmdev->tsens_num_sensor; i++) {
+		writel_relaxed(TSENS_SN_MIN_MAX_STATUS_CTRL_DATA,
+			TSENS_SN_MIN_MAX_STATUS_CTRL(tmdev->tsens_addr)
+				+ (i * TSENS_SN_ADDR_OFFSET));
+		writel_relaxed(TSENS_SN_REMOTE_CFG_DATA,
+			TSENS_SN_REMOTE_CONFIG(tmdev->tsens_addr)
+				+ (i * TSENS_SN_ADDR_OFFSET));
+	}
+	writel_relaxed(TSENS_INTERRUPT_EN,
+		TSENS_UPPER_LOWER_INTERRUPT_CTRL(tmdev->tsens_addr));
+}
+
+static int tsens_calib_sensors(void)
+{
+	int i, tsens_base1_data, tsens0_point1, tsens1_point1;
+	int tsens2_point1, tsens3_point1, tsens4_point1, tsens5_point1;
+	int tsens6_point1, tsens7_point1, tsens8_point1, tsens9_point1;
+	int tsens10_point1, tsens0_point2, tsens1_point2, tsens2_point2;
+	int tsens3_point2, tsens4_point2, tsens5_point2, tsens6_point2;
+	int tsens7_point2, tsens8_point2, tsens9_point2, tsens10_point2;
+	int tsens_base2_data, tsens_calibration_mode, temp;
+	uint32_t calib_data[5];
+
+	for (i = 0; i < 5; i++)
+		calib_data[i] = readl_relaxed(tmdev->tsens_calib_addr
+					+ (i * TSENS_SN_ADDR_OFFSET));
+
+	tsens_calibration_mode = (calib_data[1] & TSENS_CAL_SEL_0_1
+			>> TSENS_CAL_SEL_SHIFT);
+	temp = (calib_data[3] & TSENS_CAL_SEL_2
+			>> TSENS_CAL_SEL_SHIFT_2);
+	tsens_calibration_mode |= temp;
+	/* Remove this after bringup */
+	tsens_calibration_mode = TSENS_ONE_POINT_CALIB;
+
+	if (!tsens_calibration_mode) {
+		pr_err("TSENS not calibrated\n");
+		return -ENODEV;
+	} else if (tsens_calibration_mode == TSENS_ONE_POINT_CALIB ||
+				TSENS_TWO_POINT_CALIB) {
+		tsens_base1_data = calib_data[0] & TSENS_BASE1_MASK;
+		tsens0_point1 = calib_data[0] & TSENS0_POINT1_MASK;
+		tsens1_point1 = calib_data[0] & TSENS1_POINT1_MASK;
+		tsens2_point1 = calib_data[0] & TSENS2_POINT1_MASK;
+		tsens3_point1 = calib_data[0] & TSENS3_POINT1_MASK;
+		tsens4_point1 = calib_data[1] & TSENS4_POINT1_MASK;
+		tsens5_point1 = calib_data[1] & TSENS5_POINT1_MASK;
+		tsens6_point1 = calib_data[1] & TSENS6_POINT1_MASK;
+		tsens7_point1 = calib_data[1] & TSENS7_POINT1_MASK;
+		tsens8_point1 = calib_data[1] & TSENS8_POINT1_MASK;
+		tsens9_point1 = calib_data[2] & TSENS9_POINT1_MASK;
+		tsens10_point1 = calib_data[2] & TSENS10_POINT1_MASK;
+	} else if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB) {
+		tsens_base2_data = calib_data[2] & TSENS_BASE2_MASK;
+		tsens0_point2 = calib_data[2] & TSENS0_POINT2_MASK;
+		tsens1_point2 = calib_data[2] & TSENS1_POINT2_MASK;
+		tsens2_point2 = calib_data[3] & TSENS2_POINT2_MASK;
+		tsens3_point2 = calib_data[3] & TSENS3_POINT2_MASK;
+		tsens4_point2 = calib_data[3] & TSENS4_POINT2_MASK;
+		tsens5_point2 = calib_data[3] & TSENS5_POINT2_MASK;
+		tsens6_point2 = calib_data[3] & TSENS6_POINT2_MASK;
+		tsens7_point2 = calib_data[4] & TSENS7_POINT2_MASK;
+		tsens8_point2 = calib_data[4] & TSENS8_POINT2_MASK;
+		tsens9_point2 = calib_data[4] & TSENS9_POINT2_MASK;
+		tsens10_point2 = calib_data[4] & TSENS10_POINT2_MASK;
+	} else
+		pr_debug("Calibration mode is unknown: %d\n",
+						tsens_calibration_mode);
+
+	tmdev->sensor[0].calib_data_point1 =
+		(((tsens_base1_data + tsens0_point1) << 2) | TSENS_BIT_APPEND);
+	tmdev->sensor[0].calib_data_point2 =
+		(((tsens_base2_data + tsens0_point2) << 2) | TSENS_BIT_APPEND);
+	tmdev->sensor[1].calib_data_point1 =
+		(((tsens_base1_data + tsens1_point1) << 2) | TSENS_BIT_APPEND);
+	tmdev->sensor[1].calib_data_point2 =
+		(((tsens_base2_data + tsens1_point2) << 2) | TSENS_BIT_APPEND);
+	tmdev->sensor[2].calib_data_point1 =
+		(((tsens_base1_data + tsens2_point1) << 2) | TSENS_BIT_APPEND);
+	tmdev->sensor[2].calib_data_point2 =
+		(((tsens_base2_data + tsens2_point2) << 2) | TSENS_BIT_APPEND);
+	tmdev->sensor[3].calib_data_point1 =
+		(((tsens_base1_data + tsens3_point1) << 2) | TSENS_BIT_APPEND);
+	tmdev->sensor[3].calib_data_point2 =
+		(((tsens_base2_data + tsens3_point2) << 2) | TSENS_BIT_APPEND);
+	tmdev->sensor[4].calib_data_point1 =
+		(((tsens_base1_data + tsens4_point1) << 2) | TSENS_BIT_APPEND);
+	tmdev->sensor[4].calib_data_point2 =
+		(((tsens_base2_data + tsens4_point2) << 2) | TSENS_BIT_APPEND);
+	tmdev->sensor[5].calib_data_point1 =
+		(((tsens_base1_data + tsens5_point1) << 2) | TSENS_BIT_APPEND);
+	tmdev->sensor[5].calib_data_point2 =
+		(((tsens_base2_data + tsens5_point2) << 2) | TSENS_BIT_APPEND);
+	tmdev->sensor[6].calib_data_point1 =
+		(((tsens_base1_data + tsens6_point1) << 2) | TSENS_BIT_APPEND);
+	tmdev->sensor[6].calib_data_point2 =
+		(((tsens_base2_data + tsens6_point2) << 2) | TSENS_BIT_APPEND);
+	tmdev->sensor[7].calib_data_point1 =
+		(((tsens_base1_data + tsens7_point1) << 2) | TSENS_BIT_APPEND);
+	tmdev->sensor[7].calib_data_point2 =
+		(((tsens_base2_data + tsens7_point2) << 2) | TSENS_BIT_APPEND);
+	tmdev->sensor[8].calib_data_point1 =
+		(((tsens_base1_data + tsens8_point1) << 2) | TSENS_BIT_APPEND);
+	tmdev->sensor[8].calib_data_point2 =
+		(((tsens_base2_data + tsens8_point2) << 2) | TSENS_BIT_APPEND);
+	tmdev->sensor[9].calib_data_point1 =
+		(((tsens_base1_data + tsens9_point1) << 2) | TSENS_BIT_APPEND);
+	tmdev->sensor[9].calib_data_point2 =
+		(((tsens_base2_data + tsens9_point2) < 2) | TSENS_BIT_APPEND);
+	tmdev->sensor[10].calib_data_point1 =
+		(((tsens_base1_data + tsens10_point1) << 2) | TSENS_BIT_APPEND);
+	tmdev->sensor[10].calib_data_point2 =
+		(((tsens_base2_data + tsens10_point2) << 2) | TSENS_BIT_APPEND);
+
+	for (i = 0; i < tmdev->tsens_num_sensor; i++) {
+		int32_t num = 0, den = 0;
+		num = TSENS_CAL_DEGC_POINT2 - TSENS_CAL_DEGC_POINT2;
+		den = tmdev->sensor[i].calib_data_point2 -
+					tmdev->sensor[i].calib_data_point1;
+		num *= tmdev->tsens_factor;
+		if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB)
+			tmdev->sensor[i].slope_mul_tsens_factor = num/den;
+		tmdev->sensor[i].offset = (TSENS_CAL_DEGC_POINT1 *
+			tmdev->tsens_factor)
+			- (tmdev->sensor[i].calib_data_point1 *
+			tmdev->sensor[i].slope_mul_tsens_factor);
+		INIT_WORK(&tmdev->sensor[i].work, notify_uspace_tsens_fn);
+		tmdev->prev_reading_avail = false;
+	}
+
+	return 0;
+}
+
+static int get_device_tree_data(struct platform_device *pdev)
+{
+	const struct device_node *of_node = pdev->dev.of_node;
+	struct resource *res_mem = NULL;
+	u32 *tsens_slope_data;
+	u32 rc = 0, i, tsens_num_sensors;
+
+	rc = of_property_read_u32(of_node,
+			"qcom,sensors", &tsens_num_sensors);
+	if (rc) {
+		dev_err(&pdev->dev, "missing sensor number\n");
+		return -ENODEV;
+	}
+
+	tsens_slope_data = devm_kzalloc(&pdev->dev,
+				tsens_num_sensors, GFP_KERNEL);
+	if (!tsens_slope_data) {
+		dev_err(&pdev->dev, "can not allocate slope data\n");
+		return -ENOMEM;
+	}
+
+	rc = of_property_read_u32_array(of_node,
+		"qcom,slope", tsens_slope_data, tsens_num_sensors/sizeof(u32));
+	if (rc) {
+		dev_err(&pdev->dev, "invalid or missing property: tsens-slope\n");
+		return rc;
+	};
+
+	tmdev = devm_kzalloc(&pdev->dev,
+			sizeof(struct tsens_tm_device) +
+			tsens_num_sensors *
+			sizeof(struct tsens_tm_device_sensor),
+			GFP_KERNEL);
+	if (tmdev == NULL) {
+		pr_err("%s: kzalloc() failed.\n", __func__);
+		return -ENOMEM;
+	}
+
+	for (i = 0; i < tsens_num_sensors; i++)
+		tmdev->sensor[i].slope_mul_tsens_factor = tsens_slope_data[i];
+	tmdev->tsens_factor = TSENS_SLOPE_FACTOR;
+	tmdev->tsens_num_sensor = tsens_num_sensors;
+
+	tmdev->tsens_irq = platform_get_irq(pdev, 0);
+	if (tmdev->tsens_irq < 0) {
+		pr_err("Invalid get irq\n");
+		return tmdev->tsens_irq;
+	}
+
+	tmdev->res_tsens_mem = platform_get_resource_byname(pdev,
+					IORESOURCE_MEM, "tsens_physical");
+	if (!tmdev->res_tsens_mem) {
+		pr_err("Could not get tsens physical address resource\n");
+		rc = -EINVAL;
+		goto fail_free_irq;
+	}
+
+	tmdev->tsens_len = tmdev->res_tsens_mem->end -
+					tmdev->res_tsens_mem->start + 1;
+
+	res_mem = request_mem_region(tmdev->res_tsens_mem->start,
+				tmdev->tsens_len, tmdev->res_tsens_mem->name);
+	if (!res_mem) {
+		pr_err("Request tsens physical memory region failed\n");
+		rc = -EINVAL;
+		goto fail_free_irq;
+	}
+
+	tmdev->tsens_addr = ioremap(res_mem->start, tmdev->tsens_len);
+	if (!tmdev->tsens_addr) {
+		pr_err("Failed to IO map TSENS registers.\n");
+		rc = -EINVAL;
+		goto fail_unmap_tsens_region;
+	}
+
+	tmdev->res_calib_mem = platform_get_resource_byname(pdev,
+				IORESOURCE_MEM, "tsens_eeprom_physical");
+	if (!tmdev->res_calib_mem) {
+		pr_err("Could not get qfprom physical address resource\n");
+		rc = -EINVAL;
+		goto fail_unmap_tsens;
+	}
+
+	tmdev->calib_len = tmdev->res_calib_mem->end -
+					tmdev->res_calib_mem->start + 1;
+
+	res_mem = request_mem_region(tmdev->res_calib_mem->start,
+				tmdev->calib_len, tmdev->res_calib_mem->name);
+	if (!res_mem) {
+		pr_err("Request calibration memory region failed\n");
+		rc = -EINVAL;
+		goto fail_unmap_tsens;
+	}
+
+	tmdev->tsens_calib_addr = ioremap(res_mem->start,
+						tmdev->calib_len);
+	if (!tmdev->tsens_calib_addr) {
+		pr_err("Failed to IO map EEPROM registers.\n");
+		rc = -EINVAL;
+		goto fail_unmap_calib_region;
+	}
+
+	return 0;
+
+fail_unmap_calib_region:
+	if (tmdev->res_calib_mem)
+		release_mem_region(tmdev->res_calib_mem->start,
+					tmdev->calib_len);
+fail_unmap_tsens:
+	if (tmdev->tsens_addr)
+		iounmap(tmdev->tsens_addr);
+fail_unmap_tsens_region:
+	if (tmdev->res_tsens_mem)
+		release_mem_region(tmdev->res_tsens_mem->start,
+					tmdev->tsens_len);
+fail_free_irq:
+	free_irq(tmdev->tsens_irq, tmdev);
+
+	return rc;
+}
+
+static int __devinit tsens_tm_probe(struct platform_device *pdev)
+{
+	int rc;
+
+	if (tmdev) {
+		pr_err("TSENS device already in use\n");
+		return -EBUSY;
+	}
+
+	if (pdev->dev.of_node)
+		rc = get_device_tree_data(pdev);
+	else
+		return -ENODEV;
+
+	tmdev->pdev = pdev;
+	rc = tsens_calib_sensors();
+	if (rc < 0)
+		goto fail;
+
+	tsens_hw_init();
+	tmdev->prev_reading_avail = true;
+
+	platform_set_drvdata(pdev, tmdev);
+
+	return 0;
+fail:
+	if (tmdev->tsens_calib_addr)
+		iounmap(tmdev->tsens_calib_addr);
+	if (tmdev->res_calib_mem)
+		release_mem_region(tmdev->res_calib_mem->start,
+					tmdev->calib_len);
+	if (tmdev->tsens_addr)
+		iounmap(tmdev->tsens_addr);
+	if (tmdev->res_tsens_mem)
+		release_mem_region(tmdev->res_tsens_mem->start,
+			tmdev->tsens_len);
+	free_irq(tmdev->tsens_irq, tmdev);
+	kfree(tmdev);
+
+	return rc;
+}
+
+static int __devinit _tsens_register_thermal(void)
+{
+	struct platform_device *pdev = tmdev->pdev;
+	int rc, i;
+
+	if (!tmdev) {
+		pr_err("%s: TSENS early init not done\n", __func__);
+		return -ENODEV;
+	}
+
+	for (i = 0; i < tmdev->tsens_num_sensor; i++) {
+		char name[18];
+		snprintf(name, sizeof(name), "tsens_tz_sensor%d", i);
+		tmdev->sensor[i].mode = THERMAL_DEVICE_ENABLED;
+		tmdev->sensor[i].sensor_num = i;
+		tmdev->sensor[i].tz_dev = thermal_zone_device_register(name,
+				TSENS_TRIP_NUM, &tmdev->sensor[i],
+				&tsens_thermal_zone_ops, 0, 0, 0, 0);
+		if (IS_ERR(tmdev->sensor[i].tz_dev)) {
+			pr_err("%s: thermal_zone_device_register() failed.\n",
+			__func__);
+			rc = -ENODEV;
+			goto fail;
+		}
+	}
+	rc = request_irq(tmdev->tsens_irq, tsens_isr,
+		IRQF_TRIGGER_RISING, "tsens_interrupt", tmdev);
+	if (rc < 0) {
+		pr_err("%s: request_irq FAIL: %d\n", __func__, rc);
+		for (i = 0; i < tmdev->tsens_num_sensor; i++)
+			thermal_zone_device_unregister(tmdev->sensor[i].tz_dev);
+		goto fail;
+	}
+	platform_set_drvdata(pdev, tmdev);
+
+	return 0;
+fail:
+	if (tmdev->tsens_calib_addr)
+		iounmap(tmdev->tsens_calib_addr);
+	if (tmdev->res_calib_mem)
+		release_mem_region(tmdev->res_calib_mem->start,
+				tmdev->calib_len);
+	if (tmdev->tsens_addr)
+		iounmap(tmdev->tsens_addr);
+	if (tmdev->res_tsens_mem)
+		release_mem_region(tmdev->res_tsens_mem->start,
+				tmdev->tsens_len);
+	kfree(tmdev);
+
+	return rc;
+}
+
+static int __devexit tsens_tm_remove(struct platform_device *pdev)
+{
+	struct tsens_tm_device *tmdev = platform_get_drvdata(pdev);
+	int i;
+
+	for (i = 0; i < tmdev->tsens_num_sensor; i++)
+		thermal_zone_device_unregister(tmdev->sensor[i].tz_dev);
+	if (tmdev->tsens_calib_addr)
+		iounmap(tmdev->tsens_calib_addr);
+	if (tmdev->res_calib_mem)
+		release_mem_region(tmdev->res_calib_mem->start,
+				tmdev->calib_len);
+	if (tmdev->tsens_addr)
+		iounmap(tmdev->tsens_addr);
+	if (tmdev->res_tsens_mem)
+		release_mem_region(tmdev->res_tsens_mem->start,
+				tmdev->tsens_len);
+	free_irq(tmdev->tsens_irq, tmdev);
+	platform_set_drvdata(pdev, NULL);
+	kfree(tmdev);
+
+	return 0;
+}
+
+static struct of_device_id tsens_match[] = {
+	{	.compatible = "qcom,msm-tsens",
+	},
+	{}
+};
+
+static struct platform_driver tsens_tm_driver = {
+	.probe = tsens_tm_probe,
+	.remove = tsens_tm_remove,
+	.driver = {
+		.name = "msm-tsens",
+		.owner = THIS_MODULE,
+		.of_match_table = tsens_match,
+	},
+};
+
+static int __init tsens_tm_init_driver(void)
+{
+	return platform_driver_register(&tsens_tm_driver);
+}
+arch_initcall(tsens_tm_init_driver);
+
+static int __init tsens_thermal_register(void)
+{
+	return _tsens_register_thermal();
+}
+module_init(tsens_thermal_register);
+
+static void __exit _tsens_tm_remove(void)
+{
+	platform_driver_unregister(&tsens_tm_driver);
+}
+module_exit(_tsens_tm_remove);
+
+MODULE_ALIAS("platform:" TSENS_DRIVER_NAME);
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index 1fbfdd8..41f8106 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -373,6 +373,17 @@
 	dwc3_writel(dwc->regs, DWC3_GCTL, reg);
 
 	/*
+	 * The default value of GUCTL[31:22] should be 0x8. But on cores
+	 * revision < 2.30a, the default value is mistakenly overridden
+	 * with 0x0. Restore the correct default value.
+	 */
+	if (dwc->revision < DWC3_REVISION_230A) {
+		reg = dwc3_readl(dwc->regs, DWC3_GUCTL);
+		reg &= ~DWC3_GUCTL_REFCLKPER;
+		reg |= 0x8 << __ffs(DWC3_GUCTL_REFCLKPER);
+		dwc3_writel(dwc->regs, DWC3_GUCTL, reg);
+	}
+	/*
 	 * Currently, the default and the recommended value for GUSB3PIPECTL
 	 * [21:19] in the RTL is 3'b100 or 32 consecutive errors. Based on
 	 * analysis and experiments in the lab, it is found that there is a
@@ -395,6 +406,11 @@
 		reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
 		reg &= ~DWC3_GUSB3PIPECTL_DELAY_P1P2P3;
 		reg |= 1 << __ffs(DWC3_GUSB3PIPECTL_DELAY_P1P2P3);
+		/*
+		 * Receiver Detection in U3/Rx.Det is mistakenly disabled in
+		 * cores < 2.30a. Fix it here.
+		 */
+		reg &= ~DWC3_GUSB3PIPECTL_DIS_RXDET_U3_RXDET;
 		dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
 	}
 
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index 98adff7..92e28f5 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -180,6 +180,9 @@
 #define DWC3_GCTL_DISSCRAMBLE	(1 << 3)
 #define DWC3_GCTL_DSBLCLKGTNG	(1 << 0)
 
+/* Global User Control Register */
+#define DWC3_GUCTL_REFCLKPER (0x3FF << 22)
+
 /* Global USB2 PHY Configuration Register */
 #define DWC3_GUSB2PHYCFG_PHYSOFTRST (1 << 31)
 #define DWC3_GUSB2PHYCFG_SUSPHY	(1 << 6)
@@ -188,6 +191,7 @@
 #define DWC3_GUSB3PIPECTL_PHYSOFTRST (1 << 31)
 #define DWC3_GUSB3PIPECTL_SUSPHY (1 << 17)
 #define DWC3_GUSB3PIPECTL_DELAY_P1P2P3 (7 << 19)
+#define DWC3_GUSB3PIPECTL_DIS_RXDET_U3_RXDET (1 << 22)
 
 /* Global TX Fifo Size Register */
 #define DWC3_GTXFIFOSIZ_TXFDEF(n) ((n) & 0xffff)
diff --git a/drivers/usb/gadget/android.c b/drivers/usb/gadget/android.c
index a13b5da..2ed642a 100644
--- a/drivers/usb/gadget/android.c
+++ b/drivers/usb/gadget/android.c
@@ -1065,9 +1065,12 @@
 static int mass_storage_function_init(struct android_usb_function *f,
 					struct usb_composite_dev *cdev)
 {
+	struct android_dev *dev = _android_dev;
 	struct mass_storage_function_config *config;
 	struct fsg_common *common;
 	int err;
+	int i;
+	const char *name[2];
 
 	config = kzalloc(sizeof(struct mass_storage_function_config),
 								GFP_KERNEL);
@@ -1075,6 +1078,15 @@
 		return -ENOMEM;
 
 	config->fsg.nluns = 1;
+	name[0] = "lun";
+	if (dev->pdata->cdrom) {
+		config->fsg.nluns = 2;
+		config->fsg.luns[1].cdrom = 1;
+		config->fsg.luns[1].ro = 1;
+		config->fsg.luns[1].removable = 1;
+		name[1] = "lun0";
+	}
+
 	config->fsg.luns[0].removable = 1;
 
 	common = fsg_common_init(NULL, cdev, &config->fsg);
@@ -1083,18 +1095,24 @@
 		return PTR_ERR(common);
 	}
 
-	err = sysfs_create_link(&f->dev->kobj,
-				&common->luns[0].dev.kobj,
-				"lun");
-	if (err) {
-		fsg_common_release(&common->ref);
-		kfree(config);
-		return err;
+	for (i = 0; i < config->fsg.nluns; i++) {
+		err = sysfs_create_link(&f->dev->kobj,
+					&common->luns[i].dev.kobj,
+					name[i]);
+		if (err)
+			goto error;
 	}
 
 	config->common = common;
 	f->config = config;
 	return 0;
+error:
+	for (; i > 0 ; i--)
+		sysfs_remove_link(&f->dev->kobj, name[i-1]);
+
+	fsg_common_release(&common->ref);
+	kfree(config);
+	return err;
 }
 
 static void mass_storage_function_cleanup(struct android_usb_function *f)
diff --git a/drivers/usb/gadget/f_tcm.c b/drivers/usb/gadget/f_tcm.c
new file mode 100644
index 0000000..d944745
--- /dev/null
+++ b/drivers/usb/gadget/f_tcm.c
@@ -0,0 +1,2434 @@
+/* Target based USB-Gadget Function
+ *
+ * UAS protocol handling, target callbacks, configfs handling,
+ * BBB (USB Mass Storage Class Bulk-Only (BBB) and Transport protocol handling.
+ *
+ * Author: Sebastian Andrzej Siewior <bigeasy at linutronix dot de>
+ * License: GPLv2 as published by FSF.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/configfs.h>
+#include <linux/ctype.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/composite.h>
+#include <linux/usb/gadget.h>
+#include <linux/usb/storage.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_tcq.h>
+#include <target/target_core_base.h>
+#include <target/target_core_fabric.h>
+#include <target/target_core_fabric_configfs.h>
+#include <target/target_core_configfs.h>
+#include <target/configfs_macros.h>
+#include <asm/unaligned.h>
+
+#include "f_tcm.h"
+
+static struct target_fabric_configfs *usbg_fabric_configfs;
+static int (*usbg_connect_cb) (bool connect);
+
+static inline struct f_uas *to_f_uas(struct usb_function *f)
+{
+	return container_of(f, struct f_uas, function);
+}
+
+static void usbg_cmd_release(struct kref *);
+
+static inline void usbg_cleanup_cmd(struct usbg_cmd *cmd)
+{
+	kref_put(&cmd->ref, usbg_cmd_release);
+}
+
+/* Start bot.c code */
+
+static int bot_enqueue_cmd_cbw(struct f_uas *fu)
+{
+	int ret;
+
+	if (fu->flags & USBG_BOT_CMD_PEND)
+		return 0;
+
+	ret = usb_ep_queue(fu->ep_out, fu->cmd.req, GFP_ATOMIC);
+	if (!ret)
+		fu->flags |= USBG_BOT_CMD_PEND;
+	return ret;
+}
+
+static void bot_status_complete(struct usb_ep *ep, struct usb_request *req)
+{
+	struct usbg_cmd *cmd = req->context;
+	struct f_uas *fu = cmd->fu;
+
+	usbg_cleanup_cmd(cmd);
+	if (req->status < 0) {
+		pr_err("ERR %s(%d)\n", __func__, __LINE__);
+		return;
+	}
+
+	/* CSW completed, wait for next CBW */
+	bot_enqueue_cmd_cbw(fu);
+}
+
+static void bot_enqueue_sense_code(struct f_uas *fu, struct usbg_cmd *cmd)
+{
+	struct bulk_cs_wrap *csw = &fu->bot_status.csw;
+	int ret;
+	u8 *sense;
+	unsigned int csw_stat;
+
+	csw_stat = cmd->csw_code;
+
+	/*
+	 * We can't send SENSE as a response. So we take ASC & ASCQ from our
+	 * sense buffer and queue it and hope the host sends a REQUEST_SENSE
+	 * command where it learns why we failed.
+	 */
+	sense = cmd->sense_iu.sense;
+
+	csw->Tag = cmd->bot_tag;
+	csw->Status = csw_stat;
+	fu->bot_status.req->context = cmd;
+	ret = usb_ep_queue(fu->ep_in, fu->bot_status.req, GFP_ATOMIC);
+	if (ret)
+		pr_err("%s(%d) ERR: %d\n", __func__, __LINE__, ret);
+}
+
+static void bot_err_compl(struct usb_ep *ep, struct usb_request *req)
+{
+	struct usbg_cmd *cmd = req->context;
+	struct f_uas *fu = cmd->fu;
+
+	if (req->status < 0)
+		pr_err("ERR %s(%d)\n", __func__, __LINE__);
+
+	if (cmd->data_len) {
+		if (cmd->data_len > ep->maxpacket) {
+			req->length = ep->maxpacket;
+			cmd->data_len -= ep->maxpacket;
+		} else {
+			req->length = cmd->data_len;
+			cmd->data_len = 0;
+		}
+
+		usb_ep_queue(ep, req, GFP_ATOMIC);
+		return ;
+	}
+	bot_enqueue_sense_code(fu, cmd);
+}
+
+static void bot_send_bad_status(struct usbg_cmd *cmd)
+{
+	struct f_uas *fu = cmd->fu;
+	struct bulk_cs_wrap *csw = &fu->bot_status.csw;
+	struct usb_request *req;
+	struct usb_ep *ep;
+
+	csw->Residue = cpu_to_le32(cmd->data_len);
+
+	if (cmd->data_len) {
+		if (cmd->is_read) {
+			ep = fu->ep_in;
+			req = fu->bot_req_in;
+		} else {
+			ep = fu->ep_out;
+			req = fu->bot_req_out;
+		}
+
+		if (cmd->data_len > fu->ep_in->maxpacket) {
+			req->length = ep->maxpacket;
+			cmd->data_len -= ep->maxpacket;
+		} else {
+			req->length = cmd->data_len;
+			cmd->data_len = 0;
+		}
+		req->complete = bot_err_compl;
+		req->context = cmd;
+		req->buf = fu->cmd.buf;
+		usb_ep_queue(ep, req, GFP_KERNEL);
+	} else {
+		bot_enqueue_sense_code(fu, cmd);
+	}
+}
+
+static int bot_send_status(struct usbg_cmd *cmd, bool moved_data)
+{
+	struct f_uas *fu = cmd->fu;
+	struct bulk_cs_wrap *csw = &fu->bot_status.csw;
+	int ret;
+
+	if (cmd->se_cmd.scsi_status == SAM_STAT_GOOD) {
+		if (!moved_data && cmd->data_len) {
+			/*
+			 * the host wants to move data, we don't. Fill / empty
+			 * the pipe and then send the csw with reside set.
+			 */
+			cmd->csw_code = US_BULK_STAT_OK;
+			bot_send_bad_status(cmd);
+			return 0;
+		}
+
+		csw->Tag = cmd->bot_tag;
+		csw->Residue = cpu_to_le32(0);
+		csw->Status = US_BULK_STAT_OK;
+		fu->bot_status.req->context = cmd;
+
+		ret = usb_ep_queue(fu->ep_in, fu->bot_status.req, GFP_KERNEL);
+		if (ret)
+			pr_err("%s(%d) ERR: %d\n", __func__, __LINE__, ret);
+	} else {
+		cmd->csw_code = US_BULK_STAT_FAIL;
+		bot_send_bad_status(cmd);
+	}
+	return 0;
+}
+
+/*
+ * Called after command (no data transfer) or after the write (to device)
+ * operation is completed
+ */
+static int bot_send_status_response(struct usbg_cmd *cmd)
+{
+	bool moved_data = false;
+
+	if (!cmd->is_read)
+		moved_data = true;
+	return bot_send_status(cmd, moved_data);
+}
+
+/* Read request completed, now we have to send the CSW */
+static void bot_read_compl(struct usb_ep *ep, struct usb_request *req)
+{
+	struct usbg_cmd *cmd = req->context;
+
+	if (req->status < 0)
+		pr_err("ERR %s(%d)\n", __func__, __LINE__);
+
+	bot_send_status(cmd, true);
+}
+
+static int bot_send_read_response(struct usbg_cmd *cmd)
+{
+	struct f_uas *fu = cmd->fu;
+	struct se_cmd *se_cmd = &cmd->se_cmd;
+	struct usb_gadget *gadget = fuas_to_gadget(fu);
+	int ret;
+
+	if (!cmd->data_len) {
+		cmd->csw_code = US_BULK_STAT_PHASE;
+		bot_send_bad_status(cmd);
+		return 0;
+	}
+
+	if (!gadget->sg_supported) {
+		cmd->data_buf = kmalloc(se_cmd->data_length, GFP_ATOMIC);
+		if (!cmd->data_buf)
+			return -ENOMEM;
+
+		sg_copy_to_buffer(se_cmd->t_data_sg,
+				se_cmd->t_data_nents,
+				cmd->data_buf,
+				se_cmd->data_length);
+
+		fu->bot_req_in->buf = cmd->data_buf;
+	} else {
+		fu->bot_req_in->buf = NULL;
+		fu->bot_req_in->num_sgs = se_cmd->t_data_nents;
+		fu->bot_req_in->sg = se_cmd->t_data_sg;
+	}
+
+	fu->bot_req_in->complete = bot_read_compl;
+	fu->bot_req_in->length = se_cmd->data_length;
+	fu->bot_req_in->context = cmd;
+	ret = usb_ep_queue(fu->ep_in, fu->bot_req_in, GFP_ATOMIC);
+	if (ret)
+		pr_err("%s(%d)\n", __func__, __LINE__);
+	return 0;
+}
+
+static void usbg_data_write_cmpl(struct usb_ep *, struct usb_request *);
+static int usbg_prepare_w_request(struct usbg_cmd *, struct usb_request *);
+
+static int bot_send_write_request(struct usbg_cmd *cmd)
+{
+	struct f_uas *fu = cmd->fu;
+	struct se_cmd *se_cmd = &cmd->se_cmd;
+	struct usb_gadget *gadget = fuas_to_gadget(fu);
+	int ret;
+
+	init_completion(&cmd->write_complete);
+	cmd->fu = fu;
+
+	if (!cmd->data_len) {
+		cmd->csw_code = US_BULK_STAT_PHASE;
+		return -EINVAL;
+	}
+
+	if (!gadget->sg_supported) {
+		cmd->data_buf = kmalloc(se_cmd->data_length, GFP_KERNEL);
+		if (!cmd->data_buf)
+			return -ENOMEM;
+
+		fu->bot_req_out->buf = cmd->data_buf;
+	} else {
+		fu->bot_req_out->buf = NULL;
+		fu->bot_req_out->num_sgs = se_cmd->t_data_nents;
+		fu->bot_req_out->sg = se_cmd->t_data_sg;
+	}
+
+	fu->bot_req_out->complete = usbg_data_write_cmpl;
+	fu->bot_req_out->length = se_cmd->data_length;
+	fu->bot_req_out->context = cmd;
+
+	ret = usbg_prepare_w_request(cmd, fu->bot_req_out);
+	if (ret)
+		goto cleanup;
+	ret = usb_ep_queue(fu->ep_out, fu->bot_req_out, GFP_KERNEL);
+	if (ret)
+		pr_err("%s(%d)\n", __func__, __LINE__);
+
+	wait_for_completion(&cmd->write_complete);
+	transport_generic_process_write(se_cmd);
+cleanup:
+	return ret;
+}
+
+static int bot_submit_command(struct f_uas *, void *, unsigned int);
+
+static void bot_cmd_complete(struct usb_ep *ep, struct usb_request *req)
+{
+	struct f_uas *fu = req->context;
+	int ret;
+
+	fu->flags &= ~USBG_BOT_CMD_PEND;
+
+	if (req->status < 0)
+		return;
+
+	ret = bot_submit_command(fu, req->buf, req->actual);
+	if (ret)
+		pr_err("%s(%d): %d\n", __func__, __LINE__, ret);
+}
+
+static int bot_prepare_reqs(struct f_uas *fu)
+{
+	int ret;
+
+	fu->bot_req_in = usb_ep_alloc_request(fu->ep_in, GFP_KERNEL);
+	if (!fu->bot_req_in)
+		goto err;
+
+	fu->bot_req_out = usb_ep_alloc_request(fu->ep_out, GFP_KERNEL);
+	if (!fu->bot_req_out)
+		goto err_out;
+
+	fu->cmd.req = usb_ep_alloc_request(fu->ep_out, GFP_KERNEL);
+	if (!fu->cmd.req)
+		goto err_cmd;
+
+	fu->bot_status.req = usb_ep_alloc_request(fu->ep_in, GFP_KERNEL);
+	if (!fu->bot_status.req)
+		goto err_sts;
+
+	fu->bot_status.req->buf = &fu->bot_status.csw;
+	fu->bot_status.req->length = US_BULK_CS_WRAP_LEN;
+	fu->bot_status.req->complete = bot_status_complete;
+	fu->bot_status.csw.Signature = cpu_to_le32(US_BULK_CS_SIGN);
+
+	fu->cmd.buf = kmalloc(fu->ep_out->maxpacket, GFP_KERNEL);
+	if (!fu->cmd.buf)
+		goto err_buf;
+
+	fu->cmd.req->complete = bot_cmd_complete;
+	fu->cmd.req->buf = fu->cmd.buf;
+	fu->cmd.req->length = fu->ep_out->maxpacket;
+	fu->cmd.req->context = fu;
+
+	ret = bot_enqueue_cmd_cbw(fu);
+	if (ret)
+		goto err_queue;
+	return 0;
+err_queue:
+	kfree(fu->cmd.buf);
+	fu->cmd.buf = NULL;
+err_buf:
+	usb_ep_free_request(fu->ep_in, fu->bot_status.req);
+err_sts:
+	usb_ep_free_request(fu->ep_out, fu->cmd.req);
+	fu->cmd.req = NULL;
+err_cmd:
+	usb_ep_free_request(fu->ep_out, fu->bot_req_out);
+	fu->bot_req_out = NULL;
+err_out:
+	usb_ep_free_request(fu->ep_in, fu->bot_req_in);
+	fu->bot_req_in = NULL;
+err:
+	pr_err("BOT: endpoint setup failed\n");
+	return -ENOMEM;
+}
+
+void bot_cleanup_old_alt(struct f_uas *fu)
+{
+	if (!(fu->flags & USBG_ENABLED))
+		return;
+
+	usb_ep_disable(fu->ep_in);
+	usb_ep_disable(fu->ep_out);
+
+	if (!fu->bot_req_in)
+		return;
+
+	usb_ep_free_request(fu->ep_in, fu->bot_req_in);
+	usb_ep_free_request(fu->ep_out, fu->bot_req_out);
+	usb_ep_free_request(fu->ep_out, fu->cmd.req);
+	usb_ep_free_request(fu->ep_out, fu->bot_status.req);
+
+	kfree(fu->cmd.buf);
+
+	fu->bot_req_in = NULL;
+	fu->bot_req_out = NULL;
+	fu->cmd.req = NULL;
+	fu->bot_status.req = NULL;
+	fu->cmd.buf = NULL;
+}
+
+static void bot_set_alt(struct f_uas *fu)
+{
+	struct usb_function *f = &fu->function;
+	struct usb_gadget *gadget = f->config->cdev->gadget;
+	int ret;
+
+	fu->flags = USBG_IS_BOT;
+
+	config_ep_by_speed(gadget, f, fu->ep_in);
+	ret = usb_ep_enable(fu->ep_in);
+	if (ret)
+		goto err_b_in;
+
+	config_ep_by_speed(gadget, f, fu->ep_out);
+	ret = usb_ep_enable(fu->ep_out);
+	if (ret)
+		goto err_b_out;
+
+	ret = bot_prepare_reqs(fu);
+	if (ret)
+		goto err_wq;
+	fu->flags |= USBG_ENABLED;
+	pr_info("Using the BOT protocol\n");
+	return;
+err_wq:
+	usb_ep_disable(fu->ep_out);
+err_b_out:
+	usb_ep_disable(fu->ep_in);
+err_b_in:
+	fu->flags = USBG_IS_BOT;
+}
+
+static int usbg_bot_setup(struct usb_function *f,
+		const struct usb_ctrlrequest *ctrl)
+{
+	struct f_uas *fu = to_f_uas(f);
+	struct usb_composite_dev *cdev = f->config->cdev;
+	u16 w_value = le16_to_cpu(ctrl->wValue);
+	u16 w_length = le16_to_cpu(ctrl->wLength);
+	int luns;
+	u8 *ret_lun;
+
+	switch (ctrl->bRequest) {
+	case US_BULK_GET_MAX_LUN:
+		if (ctrl->bRequestType != (USB_DIR_IN | USB_TYPE_CLASS |
+					USB_RECIP_INTERFACE))
+			return -ENOTSUPP;
+
+		if (w_length < 1)
+			return -EINVAL;
+		if (w_value != 0)
+			return -EINVAL;
+		luns = atomic_read(&fu->tpg->tpg_port_count);
+		if (!luns) {
+			pr_err("No LUNs configured?\n");
+			return -EINVAL;
+		}
+		/*
+		 * If 4 LUNs are present we return 3 i.e. LUN 0..3 can be
+		 * accessed. The upper limit is 0xf
+		 */
+		luns--;
+		if (luns > 0xf) {
+			pr_info_once("Limiting the number of luns to 16\n");
+			luns = 0xf;
+		}
+		ret_lun = cdev->req->buf;
+		*ret_lun = luns;
+		cdev->req->length = 1;
+		return usb_ep_queue(cdev->gadget->ep0, cdev->req, GFP_ATOMIC);
+		break;
+
+	case US_BULK_RESET_REQUEST:
+		/* XXX maybe we should remove previous requests for IN + OUT */
+		bot_enqueue_cmd_cbw(fu);
+		return 0;
+		break;
+	};
+	return -ENOTSUPP;
+}
+
+/* Start uas.c code */
+
+static void uasp_cleanup_one_stream(struct f_uas *fu, struct uas_stream *stream)
+{
+	/* We have either all three allocated or none */
+	if (!stream->req_in)
+		return;
+
+	usb_ep_free_request(fu->ep_in, stream->req_in);
+	usb_ep_free_request(fu->ep_out, stream->req_out);
+	usb_ep_free_request(fu->ep_status, stream->req_status);
+
+	stream->req_in = NULL;
+	stream->req_out = NULL;
+	stream->req_status = NULL;
+}
+
+static void uasp_free_cmdreq(struct f_uas *fu)
+{
+	usb_ep_free_request(fu->ep_cmd, fu->cmd.req);
+	kfree(fu->cmd.buf);
+	fu->cmd.req = NULL;
+	fu->cmd.buf = NULL;
+}
+
+static void uasp_cleanup_old_alt(struct f_uas *fu)
+{
+	int i;
+
+	if (!(fu->flags & USBG_ENABLED))
+		return;
+
+	usb_ep_disable(fu->ep_in);
+	usb_ep_disable(fu->ep_out);
+	usb_ep_disable(fu->ep_status);
+	usb_ep_disable(fu->ep_cmd);
+
+	for (i = 0; i < UASP_SS_EP_COMP_NUM_STREAMS; i++)
+		uasp_cleanup_one_stream(fu, &fu->stream[i]);
+	uasp_free_cmdreq(fu);
+}
+
+static void uasp_status_data_cmpl(struct usb_ep *ep, struct usb_request *req);
+
+static int uasp_prepare_r_request(struct usbg_cmd *cmd)
+{
+	struct se_cmd *se_cmd = &cmd->se_cmd;
+	struct f_uas *fu = cmd->fu;
+	struct usb_gadget *gadget = fuas_to_gadget(fu);
+	struct uas_stream *stream = cmd->stream;
+
+	if (!gadget->sg_supported) {
+		cmd->data_buf = kmalloc(se_cmd->data_length, GFP_ATOMIC);
+		if (!cmd->data_buf)
+			return -ENOMEM;
+
+		sg_copy_to_buffer(se_cmd->t_data_sg,
+				se_cmd->t_data_nents,
+				cmd->data_buf,
+				se_cmd->data_length);
+
+		stream->req_in->buf = cmd->data_buf;
+	} else {
+		stream->req_in->buf = NULL;
+		stream->req_in->num_sgs = se_cmd->t_data_nents;
+		stream->req_in->sg = se_cmd->t_data_sg;
+	}
+
+	stream->req_in->complete = uasp_status_data_cmpl;
+	stream->req_in->length = se_cmd->data_length;
+	stream->req_in->context = cmd;
+
+	cmd->state = UASP_SEND_STATUS;
+	return 0;
+}
+
+static void uasp_prepare_status(struct usbg_cmd *cmd)
+{
+	struct se_cmd *se_cmd = &cmd->se_cmd;
+	struct sense_iu *iu = &cmd->sense_iu;
+	struct uas_stream *stream = cmd->stream;
+
+	cmd->state = UASP_QUEUE_COMMAND;
+	iu->iu_id = IU_ID_STATUS;
+	iu->tag = cpu_to_be16(cmd->tag);
+
+	/*
+	 * iu->status_qual = cpu_to_be16(STATUS QUALIFIER SAM-4. Where R U?);
+	 */
+	iu->len = cpu_to_be16(se_cmd->scsi_sense_length);
+	iu->status = se_cmd->scsi_status;
+	stream->req_status->context = cmd;
+	stream->req_status->length = se_cmd->scsi_sense_length + 16;
+	stream->req_status->buf = iu;
+	stream->req_status->complete = uasp_status_data_cmpl;
+}
+
+static void uasp_status_data_cmpl(struct usb_ep *ep, struct usb_request *req)
+{
+	struct usbg_cmd *cmd = req->context;
+	struct uas_stream *stream = cmd->stream;
+	struct f_uas *fu = cmd->fu;
+	int ret;
+
+	if (req->status < 0)
+		goto cleanup;
+
+	switch (cmd->state) {
+	case UASP_SEND_DATA:
+		ret = uasp_prepare_r_request(cmd);
+		if (ret)
+			goto cleanup;
+		ret = usb_ep_queue(fu->ep_in, stream->req_in, GFP_ATOMIC);
+		if (ret)
+			pr_err("%s(%d) => %d\n", __func__, __LINE__, ret);
+		break;
+
+	case UASP_RECEIVE_DATA:
+		ret = usbg_prepare_w_request(cmd, stream->req_out);
+		if (ret)
+			goto cleanup;
+		ret = usb_ep_queue(fu->ep_out, stream->req_out, GFP_ATOMIC);
+		if (ret)
+			pr_err("%s(%d) => %d\n", __func__, __LINE__, ret);
+		break;
+
+	case UASP_SEND_STATUS:
+		uasp_prepare_status(cmd);
+		ret = usb_ep_queue(fu->ep_status, stream->req_status,
+				GFP_ATOMIC);
+		if (ret)
+			pr_err("%s(%d) => %d\n", __func__, __LINE__, ret);
+		break;
+
+	case UASP_QUEUE_COMMAND:
+		usbg_cleanup_cmd(cmd);
+		usb_ep_queue(fu->ep_cmd, fu->cmd.req, GFP_ATOMIC);
+		break;
+
+	default:
+		BUG();
+	};
+	return;
+
+cleanup:
+	usbg_cleanup_cmd(cmd);
+}
+
+static int uasp_send_status_response(struct usbg_cmd *cmd)
+{
+	struct f_uas *fu = cmd->fu;
+	struct uas_stream *stream = cmd->stream;
+	struct sense_iu *iu = &cmd->sense_iu;
+
+	iu->tag = cpu_to_be16(cmd->tag);
+	stream->req_status->complete = uasp_status_data_cmpl;
+	stream->req_status->context = cmd;
+	cmd->fu = fu;
+	uasp_prepare_status(cmd);
+	return usb_ep_queue(fu->ep_status, stream->req_status, GFP_ATOMIC);
+}
+
+static int uasp_send_read_response(struct usbg_cmd *cmd)
+{
+	struct f_uas *fu = cmd->fu;
+	struct uas_stream *stream = cmd->stream;
+	struct sense_iu *iu = &cmd->sense_iu;
+	int ret;
+
+	cmd->fu = fu;
+
+	iu->tag = cpu_to_be16(cmd->tag);
+	if (fu->flags & USBG_USE_STREAMS) {
+
+		ret = uasp_prepare_r_request(cmd);
+		if (ret)
+			goto out;
+		ret = usb_ep_queue(fu->ep_in, stream->req_in, GFP_ATOMIC);
+		if (ret) {
+			pr_err("%s(%d) => %d\n", __func__, __LINE__, ret);
+			kfree(cmd->data_buf);
+			cmd->data_buf = NULL;
+		}
+
+	} else {
+
+		iu->iu_id = IU_ID_READ_READY;
+		iu->tag = cpu_to_be16(cmd->tag);
+
+		stream->req_status->complete = uasp_status_data_cmpl;
+		stream->req_status->context = cmd;
+
+		cmd->state = UASP_SEND_DATA;
+		stream->req_status->buf = iu;
+		stream->req_status->length = sizeof(struct iu);
+
+		ret = usb_ep_queue(fu->ep_status, stream->req_status,
+				GFP_ATOMIC);
+		if (ret)
+			pr_err("%s(%d) => %d\n", __func__, __LINE__, ret);
+	}
+out:
+	return ret;
+}
+
+static int uasp_send_write_request(struct usbg_cmd *cmd)
+{
+	struct f_uas *fu = cmd->fu;
+	struct se_cmd *se_cmd = &cmd->se_cmd;
+	struct uas_stream *stream = cmd->stream;
+	struct sense_iu *iu = &cmd->sense_iu;
+	int ret;
+
+	init_completion(&cmd->write_complete);
+	cmd->fu = fu;
+
+	iu->tag = cpu_to_be16(cmd->tag);
+
+	if (fu->flags & USBG_USE_STREAMS) {
+
+		ret = usbg_prepare_w_request(cmd, stream->req_out);
+		if (ret)
+			goto cleanup;
+		ret = usb_ep_queue(fu->ep_out, stream->req_out, GFP_ATOMIC);
+		if (ret)
+			pr_err("%s(%d)\n", __func__, __LINE__);
+
+	} else {
+
+		iu->iu_id = IU_ID_WRITE_READY;
+		iu->tag = cpu_to_be16(cmd->tag);
+
+		stream->req_status->complete = uasp_status_data_cmpl;
+		stream->req_status->context = cmd;
+
+		cmd->state = UASP_RECEIVE_DATA;
+		stream->req_status->buf = iu;
+		stream->req_status->length = sizeof(struct iu);
+
+		ret = usb_ep_queue(fu->ep_status, stream->req_status,
+				GFP_ATOMIC);
+		if (ret)
+			pr_err("%s(%d)\n", __func__, __LINE__);
+	}
+
+	wait_for_completion(&cmd->write_complete);
+	transport_generic_process_write(se_cmd);
+cleanup:
+	return ret;
+}
+
+static int usbg_submit_command(struct f_uas *, void *, unsigned int);
+
+static void uasp_cmd_complete(struct usb_ep *ep, struct usb_request *req)
+{
+	struct f_uas *fu = req->context;
+	int ret;
+
+	if (req->status < 0)
+		return;
+
+	ret = usbg_submit_command(fu, req->buf, req->actual);
+	/*
+	 * Once we tune for performance enqueue the command req here again so
+	 * we can receive a second command while we processing this one. Pay
+	 * attention to properly sync STAUS endpoint with DATA IN + OUT so you
+	 * don't break HS.
+	 */
+	if (!ret)
+		return;
+	usb_ep_queue(fu->ep_cmd, fu->cmd.req, GFP_ATOMIC);
+}
+
+static int uasp_alloc_stream_res(struct f_uas *fu, struct uas_stream *stream)
+{
+	stream->req_in = usb_ep_alloc_request(fu->ep_in, GFP_KERNEL);
+	if (!stream->req_in)
+		goto out;
+
+	stream->req_out = usb_ep_alloc_request(fu->ep_out, GFP_KERNEL);
+	if (!stream->req_out)
+		goto err_out;
+
+	stream->req_status = usb_ep_alloc_request(fu->ep_status, GFP_KERNEL);
+	if (!stream->req_status)
+		goto err_sts;
+
+	return 0;
+err_sts:
+	usb_ep_free_request(fu->ep_status, stream->req_status);
+	stream->req_status = NULL;
+err_out:
+	usb_ep_free_request(fu->ep_out, stream->req_out);
+	stream->req_out = NULL;
+out:
+	return -ENOMEM;
+}
+
+static int uasp_alloc_cmd(struct f_uas *fu)
+{
+	fu->cmd.req = usb_ep_alloc_request(fu->ep_cmd, GFP_KERNEL);
+	if (!fu->cmd.req)
+		goto err;
+
+	fu->cmd.buf = kmalloc(fu->ep_cmd->maxpacket, GFP_KERNEL);
+	if (!fu->cmd.buf)
+		goto err_buf;
+
+	fu->cmd.req->complete = uasp_cmd_complete;
+	fu->cmd.req->buf = fu->cmd.buf;
+	fu->cmd.req->length = fu->ep_cmd->maxpacket;
+	fu->cmd.req->context = fu;
+	return 0;
+
+err_buf:
+	usb_ep_free_request(fu->ep_cmd, fu->cmd.req);
+err:
+	return -ENOMEM;
+}
+
+static void uasp_setup_stream_res(struct f_uas *fu, int max_streams)
+{
+	int i;
+
+	for (i = 0; i < max_streams; i++) {
+		struct uas_stream *s = &fu->stream[i];
+
+		s->req_in->stream_id = i + 1;
+		s->req_out->stream_id = i + 1;
+		s->req_status->stream_id = i + 1;
+	}
+}
+
+static int uasp_prepare_reqs(struct f_uas *fu)
+{
+	int ret;
+	int i;
+	int max_streams;
+
+	if (fu->flags & USBG_USE_STREAMS)
+		max_streams = UASP_SS_EP_COMP_NUM_STREAMS;
+	else
+		max_streams = 1;
+
+	for (i = 0; i < max_streams; i++) {
+		ret = uasp_alloc_stream_res(fu, &fu->stream[i]);
+		if (ret)
+			goto err_cleanup;
+	}
+
+	ret = uasp_alloc_cmd(fu);
+	if (ret)
+		goto err_free_stream;
+	uasp_setup_stream_res(fu, max_streams);
+
+	ret = usb_ep_queue(fu->ep_cmd, fu->cmd.req, GFP_ATOMIC);
+	if (ret)
+		goto err_free_stream;
+
+	return 0;
+
+err_free_stream:
+	uasp_free_cmdreq(fu);
+
+err_cleanup:
+	if (i) {
+		do {
+			uasp_cleanup_one_stream(fu, &fu->stream[i - 1]);
+			i--;
+		} while (i);
+	}
+	pr_err("UASP: endpoint setup failed\n");
+	return ret;
+}
+
+static void uasp_set_alt(struct f_uas *fu)
+{
+	struct usb_function *f = &fu->function;
+	struct usb_gadget *gadget = f->config->cdev->gadget;
+	int ret;
+
+	fu->flags = USBG_IS_UAS;
+
+	if (gadget->speed == USB_SPEED_SUPER)
+		fu->flags |= USBG_USE_STREAMS;
+
+	config_ep_by_speed(gadget, f, fu->ep_in);
+	ret = usb_ep_enable(fu->ep_in);
+	if (ret)
+		goto err_b_in;
+
+	config_ep_by_speed(gadget, f, fu->ep_out);
+	ret = usb_ep_enable(fu->ep_out);
+	if (ret)
+		goto err_b_out;
+
+	config_ep_by_speed(gadget, f, fu->ep_cmd);
+	ret = usb_ep_enable(fu->ep_cmd);
+	if (ret)
+		goto err_cmd;
+	config_ep_by_speed(gadget, f, fu->ep_status);
+	ret = usb_ep_enable(fu->ep_status);
+	if (ret)
+		goto err_status;
+
+	ret = uasp_prepare_reqs(fu);
+	if (ret)
+		goto err_wq;
+	fu->flags |= USBG_ENABLED;
+
+	pr_info("Using the UAS protocol\n");
+	return;
+err_wq:
+	usb_ep_disable(fu->ep_status);
+err_status:
+	usb_ep_disable(fu->ep_cmd);
+err_cmd:
+	usb_ep_disable(fu->ep_out);
+err_b_out:
+	usb_ep_disable(fu->ep_in);
+err_b_in:
+	fu->flags = 0;
+}
+
+static int get_cmd_dir(const unsigned char *cdb)
+{
+	int ret;
+
+	switch (cdb[0]) {
+	case READ_6:
+	case READ_10:
+	case READ_12:
+	case READ_16:
+	case INQUIRY:
+	case MODE_SENSE:
+	case MODE_SENSE_10:
+	case SERVICE_ACTION_IN:
+	case MAINTENANCE_IN:
+	case PERSISTENT_RESERVE_IN:
+	case SECURITY_PROTOCOL_IN:
+	case ACCESS_CONTROL_IN:
+	case REPORT_LUNS:
+	case READ_BLOCK_LIMITS:
+	case READ_POSITION:
+	case READ_CAPACITY:
+	case READ_TOC:
+	case READ_FORMAT_CAPACITIES:
+	case REQUEST_SENSE:
+		ret = DMA_FROM_DEVICE;
+		break;
+
+	case WRITE_6:
+	case WRITE_10:
+	case WRITE_12:
+	case WRITE_16:
+	case MODE_SELECT:
+	case MODE_SELECT_10:
+	case WRITE_VERIFY:
+	case WRITE_VERIFY_12:
+	case PERSISTENT_RESERVE_OUT:
+	case MAINTENANCE_OUT:
+	case SECURITY_PROTOCOL_OUT:
+	case ACCESS_CONTROL_OUT:
+		ret = DMA_TO_DEVICE;
+		break;
+	case ALLOW_MEDIUM_REMOVAL:
+	case TEST_UNIT_READY:
+	case SYNCHRONIZE_CACHE:
+	case START_STOP:
+	case ERASE:
+	case REZERO_UNIT:
+	case SEEK_10:
+	case SPACE:
+	case VERIFY:
+	case WRITE_FILEMARKS:
+		ret = DMA_NONE;
+		break;
+	default:
+		pr_warn("target: Unknown data direction for SCSI Opcode "
+				"0x%02x\n", cdb[0]);
+		ret = -EINVAL;
+	}
+	return ret;
+}
+
+static void usbg_data_write_cmpl(struct usb_ep *ep, struct usb_request *req)
+{
+	struct usbg_cmd *cmd = req->context;
+	struct se_cmd *se_cmd = &cmd->se_cmd;
+
+	if (req->status < 0) {
+		pr_err("%s() state %d transfer failed\n", __func__, cmd->state);
+		goto cleanup;
+	}
+
+	if (req->num_sgs == 0) {
+		sg_copy_from_buffer(se_cmd->t_data_sg,
+				se_cmd->t_data_nents,
+				cmd->data_buf,
+				se_cmd->data_length);
+	}
+
+	complete(&cmd->write_complete);
+	return;
+
+cleanup:
+	usbg_cleanup_cmd(cmd);
+}
+
+static int usbg_prepare_w_request(struct usbg_cmd *cmd, struct usb_request *req)
+{
+	struct se_cmd *se_cmd = &cmd->se_cmd;
+	struct f_uas *fu = cmd->fu;
+	struct usb_gadget *gadget = fuas_to_gadget(fu);
+
+	if (!gadget->sg_supported) {
+		cmd->data_buf = kmalloc(se_cmd->data_length, GFP_ATOMIC);
+		if (!cmd->data_buf)
+			return -ENOMEM;
+
+		req->buf = cmd->data_buf;
+	} else {
+		req->buf = NULL;
+		req->num_sgs = se_cmd->t_data_nents;
+		req->sg = se_cmd->t_data_sg;
+	}
+
+	req->complete = usbg_data_write_cmpl;
+	req->length = se_cmd->data_length;
+	req->context = cmd;
+	return 0;
+}
+
+static int usbg_send_status_response(struct se_cmd *se_cmd)
+{
+	struct usbg_cmd *cmd = container_of(se_cmd, struct usbg_cmd,
+			se_cmd);
+	struct f_uas *fu = cmd->fu;
+
+	if (fu->flags & USBG_IS_BOT)
+		return bot_send_status_response(cmd);
+	else
+		return uasp_send_status_response(cmd);
+}
+
+static int usbg_send_write_request(struct se_cmd *se_cmd)
+{
+	struct usbg_cmd *cmd = container_of(se_cmd, struct usbg_cmd,
+			se_cmd);
+	struct f_uas *fu = cmd->fu;
+
+	if (fu->flags & USBG_IS_BOT)
+		return bot_send_write_request(cmd);
+	else
+		return uasp_send_write_request(cmd);
+}
+
+static int usbg_send_read_response(struct se_cmd *se_cmd)
+{
+	struct usbg_cmd *cmd = container_of(se_cmd, struct usbg_cmd,
+			se_cmd);
+	struct f_uas *fu = cmd->fu;
+
+	if (fu->flags & USBG_IS_BOT)
+		return bot_send_read_response(cmd);
+	else
+		return uasp_send_read_response(cmd);
+}
+
+static void usbg_cmd_work(struct work_struct *work)
+{
+	struct usbg_cmd *cmd = container_of(work, struct usbg_cmd, work);
+	struct se_cmd *se_cmd;
+	struct tcm_usbg_nexus *tv_nexus;
+	struct usbg_tpg *tpg;
+	int dir;
+
+	se_cmd = &cmd->se_cmd;
+	tpg = cmd->fu->tpg;
+	tv_nexus = tpg->tpg_nexus;
+	dir = get_cmd_dir(cmd->cmd_buf);
+	if (dir < 0) {
+		transport_init_se_cmd(se_cmd,
+				tv_nexus->tvn_se_sess->se_tpg->se_tpg_tfo,
+				tv_nexus->tvn_se_sess, cmd->data_len, DMA_NONE,
+				cmd->prio_attr, cmd->sense_iu.sense);
+
+		transport_send_check_condition_and_sense(se_cmd,
+				TCM_UNSUPPORTED_SCSI_OPCODE, 1);
+		usbg_cleanup_cmd(cmd);
+		return;
+	}
+
+	target_submit_cmd(se_cmd, tv_nexus->tvn_se_sess,
+			cmd->cmd_buf, cmd->sense_iu.sense, cmd->unpacked_lun,
+			0, cmd->prio_attr, dir, TARGET_SCF_UNKNOWN_SIZE);
+}
+
+static int usbg_submit_command(struct f_uas *fu,
+		void *cmdbuf, unsigned int len)
+{
+	struct command_iu *cmd_iu = cmdbuf;
+	struct usbg_cmd *cmd;
+	struct usbg_tpg *tpg;
+	struct se_cmd *se_cmd;
+	struct tcm_usbg_nexus *tv_nexus;
+	u32 cmd_len;
+	int ret;
+
+	if (cmd_iu->iu_id != IU_ID_COMMAND) {
+		pr_err("Unsupported type %d\n", cmd_iu->iu_id);
+		return -EINVAL;
+	}
+
+	cmd = kzalloc(sizeof *cmd, GFP_ATOMIC);
+	if (!cmd)
+		return -ENOMEM;
+
+	cmd->fu = fu;
+
+	/* XXX until I figure out why I can't free in on complete */
+	kref_init(&cmd->ref);
+	kref_get(&cmd->ref);
+
+	tpg = fu->tpg;
+	cmd_len = (cmd_iu->len & ~0x3) + 16;
+	if (cmd_len > USBG_MAX_CMD)
+		goto err;
+
+	memcpy(cmd->cmd_buf, cmd_iu->cdb, cmd_len);
+
+	cmd->tag = be16_to_cpup(&cmd_iu->tag);
+	if (fu->flags & USBG_USE_STREAMS) {
+		if (cmd->tag > UASP_SS_EP_COMP_NUM_STREAMS)
+			goto err;
+		if (!cmd->tag)
+			cmd->stream = &fu->stream[0];
+		else
+			cmd->stream = &fu->stream[cmd->tag - 1];
+	} else {
+		cmd->stream = &fu->stream[0];
+	}
+
+	tv_nexus = tpg->tpg_nexus;
+	if (!tv_nexus) {
+		pr_err("Missing nexus, ignoring command\n");
+		goto err;
+	}
+
+	switch (cmd_iu->prio_attr & 0x7) {
+	case UAS_HEAD_TAG:
+		cmd->prio_attr = MSG_HEAD_TAG;
+		break;
+	case UAS_ORDERED_TAG:
+		cmd->prio_attr = MSG_ORDERED_TAG;
+		break;
+	case UAS_ACA:
+		cmd->prio_attr = MSG_ACA_TAG;
+		break;
+	default:
+		pr_debug_once("Unsupported prio_attr: %02x.\n",
+				cmd_iu->prio_attr);
+	case UAS_SIMPLE_TAG:
+		cmd->prio_attr = MSG_SIMPLE_TAG;
+		break;
+	}
+
+	se_cmd = &cmd->se_cmd;
+	cmd->unpacked_lun = scsilun_to_int(&cmd_iu->lun);
+
+	INIT_WORK(&cmd->work, usbg_cmd_work);
+	ret = queue_work(tpg->workqueue, &cmd->work);
+	if (ret < 0)
+		goto err;
+
+	return 0;
+err:
+	kfree(cmd);
+	return -EINVAL;
+}
+
+static void bot_cmd_work(struct work_struct *work)
+{
+	struct usbg_cmd *cmd = container_of(work, struct usbg_cmd, work);
+	struct se_cmd *se_cmd;
+	struct tcm_usbg_nexus *tv_nexus;
+	struct usbg_tpg *tpg;
+	int dir;
+
+	se_cmd = &cmd->se_cmd;
+	tpg = cmd->fu->tpg;
+	tv_nexus = tpg->tpg_nexus;
+	dir = get_cmd_dir(cmd->cmd_buf);
+	if (dir < 0) {
+		transport_init_se_cmd(se_cmd,
+				tv_nexus->tvn_se_sess->se_tpg->se_tpg_tfo,
+				tv_nexus->tvn_se_sess, cmd->data_len, DMA_NONE,
+				cmd->prio_attr, cmd->sense_iu.sense);
+
+		transport_send_check_condition_and_sense(se_cmd,
+				TCM_UNSUPPORTED_SCSI_OPCODE, 1);
+		usbg_cleanup_cmd(cmd);
+		return;
+	}
+
+	target_submit_cmd(se_cmd, tv_nexus->tvn_se_sess,
+			cmd->cmd_buf, cmd->sense_iu.sense, cmd->unpacked_lun,
+			cmd->data_len, cmd->prio_attr, dir, 0);
+}
+
+static int bot_submit_command(struct f_uas *fu,
+		void *cmdbuf, unsigned int len)
+{
+	struct bulk_cb_wrap *cbw = cmdbuf;
+	struct usbg_cmd *cmd;
+	struct usbg_tpg *tpg;
+	struct se_cmd *se_cmd;
+	struct tcm_usbg_nexus *tv_nexus;
+	u32 cmd_len;
+	int ret;
+
+	if (cbw->Signature != cpu_to_le32(US_BULK_CB_SIGN)) {
+		pr_err("Wrong signature on CBW\n");
+		return -EINVAL;
+	}
+	if (len != 31) {
+		pr_err("Wrong length for CBW\n");
+		return -EINVAL;
+	}
+
+	cmd_len = cbw->Length;
+	if (cmd_len < 1 || cmd_len > 16)
+		return -EINVAL;
+
+	cmd = kzalloc(sizeof *cmd, GFP_ATOMIC);
+	if (!cmd)
+		return -ENOMEM;
+
+	cmd->fu = fu;
+
+	/* XXX until I figure out why I can't free in on complete */
+	kref_init(&cmd->ref);
+	kref_get(&cmd->ref);
+
+	tpg = fu->tpg;
+
+	memcpy(cmd->cmd_buf, cbw->CDB, cmd_len);
+
+	cmd->bot_tag = cbw->Tag;
+
+	tv_nexus = tpg->tpg_nexus;
+	if (!tv_nexus) {
+		pr_err("Missing nexus, ignoring command\n");
+		goto err;
+	}
+
+	cmd->prio_attr = MSG_SIMPLE_TAG;
+	se_cmd = &cmd->se_cmd;
+	cmd->unpacked_lun = cbw->Lun;
+	cmd->is_read = cbw->Flags & US_BULK_FLAG_IN ? 1 : 0;
+	cmd->data_len = le32_to_cpu(cbw->DataTransferLength);
+
+	INIT_WORK(&cmd->work, bot_cmd_work);
+	ret = queue_work(tpg->workqueue, &cmd->work);
+	if (ret < 0)
+		goto err;
+
+	return 0;
+err:
+	kfree(cmd);
+	return -EINVAL;
+}
+
+/* Start fabric.c code */
+
+static int usbg_check_true(struct se_portal_group *se_tpg)
+{
+	return 1;
+}
+
+static int usbg_check_false(struct se_portal_group *se_tpg)
+{
+	return 0;
+}
+
+static char *usbg_get_fabric_name(void)
+{
+	return "usb_gadget";
+}
+
+static u8 usbg_get_fabric_proto_ident(struct se_portal_group *se_tpg)
+{
+	struct usbg_tpg *tpg = container_of(se_tpg,
+				struct usbg_tpg, se_tpg);
+	struct usbg_tport *tport = tpg->tport;
+	u8 proto_id;
+
+	switch (tport->tport_proto_id) {
+	case SCSI_PROTOCOL_SAS:
+	default:
+		proto_id = sas_get_fabric_proto_ident(se_tpg);
+		break;
+	}
+
+	return proto_id;
+}
+
+static char *usbg_get_fabric_wwn(struct se_portal_group *se_tpg)
+{
+	struct usbg_tpg *tpg = container_of(se_tpg,
+				struct usbg_tpg, se_tpg);
+	struct usbg_tport *tport = tpg->tport;
+
+	return &tport->tport_name[0];
+}
+
+static u16 usbg_get_tag(struct se_portal_group *se_tpg)
+{
+	struct usbg_tpg *tpg = container_of(se_tpg,
+				struct usbg_tpg, se_tpg);
+	return tpg->tport_tpgt;
+}
+
+static u32 usbg_get_default_depth(struct se_portal_group *se_tpg)
+{
+	return 1;
+}
+
+static u32 usbg_get_pr_transport_id(
+	struct se_portal_group *se_tpg,
+	struct se_node_acl *se_nacl,
+	struct t10_pr_registration *pr_reg,
+	int *format_code,
+	unsigned char *buf)
+{
+	struct usbg_tpg *tpg = container_of(se_tpg,
+				struct usbg_tpg, se_tpg);
+	struct usbg_tport *tport = tpg->tport;
+	int ret = 0;
+
+	switch (tport->tport_proto_id) {
+	case SCSI_PROTOCOL_SAS:
+	default:
+		ret = sas_get_pr_transport_id(se_tpg, se_nacl, pr_reg,
+					format_code, buf);
+		break;
+	}
+
+	return ret;
+}
+
+static u32 usbg_get_pr_transport_id_len(
+	struct se_portal_group *se_tpg,
+	struct se_node_acl *se_nacl,
+	struct t10_pr_registration *pr_reg,
+	int *format_code)
+{
+	struct usbg_tpg *tpg = container_of(se_tpg,
+				struct usbg_tpg, se_tpg);
+	struct usbg_tport *tport = tpg->tport;
+	int ret = 0;
+
+	switch (tport->tport_proto_id) {
+	case SCSI_PROTOCOL_SAS:
+	default:
+		ret = sas_get_pr_transport_id_len(se_tpg, se_nacl, pr_reg,
+					format_code);
+		break;
+	}
+
+	return ret;
+}
+
+static char *usbg_parse_pr_out_transport_id(
+	struct se_portal_group *se_tpg,
+	const char *buf,
+	u32 *out_tid_len,
+	char **port_nexus_ptr)
+{
+	struct usbg_tpg *tpg = container_of(se_tpg,
+				struct usbg_tpg, se_tpg);
+	struct usbg_tport *tport = tpg->tport;
+	char *tid = NULL;
+
+	switch (tport->tport_proto_id) {
+	case SCSI_PROTOCOL_SAS:
+	default:
+		tid = sas_parse_pr_out_transport_id(se_tpg, buf, out_tid_len,
+					port_nexus_ptr);
+	}
+
+	return tid;
+}
+
+static struct se_node_acl *usbg_alloc_fabric_acl(struct se_portal_group *se_tpg)
+{
+	struct usbg_nacl *nacl;
+
+	nacl = kzalloc(sizeof(struct usbg_nacl), GFP_KERNEL);
+	if (!nacl) {
+		printk(KERN_ERR "Unable to alocate struct usbg_nacl\n");
+		return NULL;
+	}
+
+	return &nacl->se_node_acl;
+}
+
+static void usbg_release_fabric_acl(
+	struct se_portal_group *se_tpg,
+	struct se_node_acl *se_nacl)
+{
+	struct usbg_nacl *nacl = container_of(se_nacl,
+			struct usbg_nacl, se_node_acl);
+	kfree(nacl);
+}
+
+static u32 usbg_tpg_get_inst_index(struct se_portal_group *se_tpg)
+{
+	return 1;
+}
+
+static int usbg_new_cmd(struct se_cmd *se_cmd)
+{
+	struct usbg_cmd *cmd = container_of(se_cmd, struct usbg_cmd,
+			se_cmd);
+	int ret;
+
+	ret = target_setup_cmd_from_cdb(se_cmd, cmd->cmd_buf);
+	if (ret)
+		return ret;
+
+	return transport_generic_map_mem_to_cmd(se_cmd, NULL, 0, NULL, 0);
+}
+
+static void usbg_cmd_release(struct kref *ref)
+{
+	struct usbg_cmd *cmd = container_of(ref, struct usbg_cmd,
+			ref);
+
+	transport_generic_free_cmd(&cmd->se_cmd, 0);
+}
+
+static void usbg_release_cmd(struct se_cmd *se_cmd)
+{
+	struct usbg_cmd *cmd = container_of(se_cmd, struct usbg_cmd,
+			se_cmd);
+	kfree(cmd->data_buf);
+	kfree(cmd);
+	return;
+}
+
+static int usbg_shutdown_session(struct se_session *se_sess)
+{
+	return 0;
+}
+
+static void usbg_close_session(struct se_session *se_sess)
+{
+	return;
+}
+
+static u32 usbg_sess_get_index(struct se_session *se_sess)
+{
+	return 0;
+}
+
+/*
+ * XXX Error recovery: return != 0 if we expect writes. Dunno when that could be
+ */
+static int usbg_write_pending_status(struct se_cmd *se_cmd)
+{
+	return 0;
+}
+
+static void usbg_set_default_node_attrs(struct se_node_acl *nacl)
+{
+	return;
+}
+
+static u32 usbg_get_task_tag(struct se_cmd *se_cmd)
+{
+	struct usbg_cmd *cmd = container_of(se_cmd, struct usbg_cmd,
+			se_cmd);
+	struct f_uas *fu = cmd->fu;
+
+	if (fu->flags & USBG_IS_BOT)
+		return le32_to_cpu(cmd->bot_tag);
+	else
+		return cmd->tag;
+}
+
+static int usbg_get_cmd_state(struct se_cmd *se_cmd)
+{
+	return 0;
+}
+
+static int usbg_queue_tm_rsp(struct se_cmd *se_cmd)
+{
+	return 0;
+}
+
+static u16 usbg_set_fabric_sense_len(struct se_cmd *se_cmd, u32 sense_length)
+{
+	return 0;
+}
+
+static u16 usbg_get_fabric_sense_len(void)
+{
+	return 0;
+}
+
+static const char *usbg_check_wwn(const char *name)
+{
+	const char *n;
+	unsigned int len;
+
+	n = strstr(name, "naa.");
+	if (!n)
+		return NULL;
+	n += 4;
+	len = strlen(n);
+	if (len == 0 || len > USBG_NAMELEN - 1)
+		return NULL;
+	return n;
+}
+
+static struct se_node_acl *usbg_make_nodeacl(
+	struct se_portal_group *se_tpg,
+	struct config_group *group,
+	const char *name)
+{
+	struct se_node_acl *se_nacl, *se_nacl_new;
+	struct usbg_nacl *nacl;
+	u64 wwpn = 0;
+	u32 nexus_depth;
+	const char *wnn_name;
+
+	wnn_name = usbg_check_wwn(name);
+	if (!wnn_name)
+		return ERR_PTR(-EINVAL);
+	se_nacl_new = usbg_alloc_fabric_acl(se_tpg);
+	if (!(se_nacl_new))
+		return ERR_PTR(-ENOMEM);
+
+	nexus_depth = 1;
+	/*
+	 * se_nacl_new may be released by core_tpg_add_initiator_node_acl()
+	 * when converting a NodeACL from demo mode -> explict
+	 */
+	se_nacl = core_tpg_add_initiator_node_acl(se_tpg, se_nacl_new,
+				name, nexus_depth);
+	if (IS_ERR(se_nacl)) {
+		usbg_release_fabric_acl(se_tpg, se_nacl_new);
+		return se_nacl;
+	}
+	/*
+	 * Locate our struct usbg_nacl and set the FC Nport WWPN
+	 */
+	nacl = container_of(se_nacl, struct usbg_nacl, se_node_acl);
+	nacl->iport_wwpn = wwpn;
+	snprintf(nacl->iport_name, sizeof(nacl->iport_name), "%s", name);
+	return se_nacl;
+}
+
+static void usbg_drop_nodeacl(struct se_node_acl *se_acl)
+{
+	struct usbg_nacl *nacl = container_of(se_acl,
+				struct usbg_nacl, se_node_acl);
+	core_tpg_del_initiator_node_acl(se_acl->se_tpg, se_acl, 1);
+	kfree(nacl);
+}
+
+struct usbg_tpg *the_only_tpg_I_currently_have;
+
+static struct se_portal_group *usbg_make_tpg(
+	struct se_wwn *wwn,
+	struct config_group *group,
+	const char *name)
+{
+	struct usbg_tport *tport = container_of(wwn, struct usbg_tport,
+			tport_wwn);
+	struct usbg_tpg *tpg;
+	unsigned long tpgt;
+	int ret;
+
+	if (strstr(name, "tpgt_") != name)
+		return ERR_PTR(-EINVAL);
+	if (kstrtoul(name + 5, 0, &tpgt) || tpgt > UINT_MAX)
+		return ERR_PTR(-EINVAL);
+	if (the_only_tpg_I_currently_have) {
+		pr_err("Until the gadget framework can't handle multiple\n");
+		pr_err("gadgets, you can't do this here.\n");
+		return ERR_PTR(-EBUSY);
+	}
+
+	tpg = kzalloc(sizeof(struct usbg_tpg), GFP_KERNEL);
+	if (!tpg) {
+		printk(KERN_ERR "Unable to allocate struct usbg_tpg");
+		return ERR_PTR(-ENOMEM);
+	}
+	mutex_init(&tpg->tpg_mutex);
+	atomic_set(&tpg->tpg_port_count, 0);
+	tpg->workqueue = alloc_workqueue("tcm_usb_gadget", 0, 1);
+	if (!tpg->workqueue) {
+		kfree(tpg);
+		return NULL;
+	}
+
+	tpg->tport = tport;
+	tpg->tport_tpgt = tpgt;
+
+	ret = core_tpg_register(&usbg_fabric_configfs->tf_ops, wwn,
+				&tpg->se_tpg, tpg,
+				TRANSPORT_TPG_TYPE_NORMAL);
+	if (ret < 0) {
+		destroy_workqueue(tpg->workqueue);
+		kfree(tpg);
+		return NULL;
+	}
+	the_only_tpg_I_currently_have = tpg;
+	return &tpg->se_tpg;
+}
+
+static void usbg_drop_tpg(struct se_portal_group *se_tpg)
+{
+	struct usbg_tpg *tpg = container_of(se_tpg,
+				struct usbg_tpg, se_tpg);
+
+	core_tpg_deregister(se_tpg);
+	destroy_workqueue(tpg->workqueue);
+	kfree(tpg);
+	the_only_tpg_I_currently_have = NULL;
+}
+
+static struct se_wwn *usbg_make_tport(
+	struct target_fabric_configfs *tf,
+	struct config_group *group,
+	const char *name)
+{
+	struct usbg_tport *tport;
+	const char *wnn_name;
+	u64 wwpn = 0;
+
+	wnn_name = usbg_check_wwn(name);
+	if (!wnn_name)
+		return ERR_PTR(-EINVAL);
+
+	tport = kzalloc(sizeof(struct usbg_tport), GFP_KERNEL);
+	if (!(tport)) {
+		printk(KERN_ERR "Unable to allocate struct usbg_tport");
+		return ERR_PTR(-ENOMEM);
+	}
+	tport->tport_wwpn = wwpn;
+	snprintf(tport->tport_name, sizeof(tport->tport_name), wnn_name);
+	return &tport->tport_wwn;
+}
+
+static void usbg_drop_tport(struct se_wwn *wwn)
+{
+	struct usbg_tport *tport = container_of(wwn,
+				struct usbg_tport, tport_wwn);
+	kfree(tport);
+}
+
+/*
+ * If somebody feels like dropping the version property, go ahead.
+ */
+static ssize_t usbg_wwn_show_attr_version(
+	struct target_fabric_configfs *tf,
+	char *page)
+{
+	return sprintf(page, "usb-gadget fabric module\n");
+}
+TF_WWN_ATTR_RO(usbg, version);
+
+static struct configfs_attribute *usbg_wwn_attrs[] = {
+	&usbg_wwn_version.attr,
+	NULL,
+};
+
+static ssize_t tcm_usbg_tpg_show_enable(
+		struct se_portal_group *se_tpg,
+		char *page)
+{
+	struct usbg_tpg  *tpg = container_of(se_tpg, struct usbg_tpg, se_tpg);
+
+	return snprintf(page, PAGE_SIZE, "%u\n", tpg->gadget_connect);
+}
+
+static int usbg_attach(struct usbg_tpg *tpg)
+{
+	return usbg_connect_cb(true);
+}
+
+static void usbg_detach(struct usbg_tpg *tpg)
+{
+	usbg_connect_cb(false);
+}
+
+static ssize_t tcm_usbg_tpg_store_enable(
+		struct se_portal_group *se_tpg,
+		const char *page,
+		size_t count)
+{
+	struct usbg_tpg  *tpg = container_of(se_tpg, struct usbg_tpg, se_tpg);
+	unsigned long op;
+	ssize_t ret;
+
+	ret = kstrtoul(page, 0, &op);
+	if (ret < 0)
+		return -EINVAL;
+	if (op > 1)
+		return -EINVAL;
+
+	if (op && tpg->gadget_connect)
+		goto out;
+	if (!op && !tpg->gadget_connect)
+		goto out;
+
+	if (op) {
+		ret = usbg_attach(tpg);
+		if (ret)
+			goto out;
+	} else {
+		usbg_detach(tpg);
+	}
+	tpg->gadget_connect = op;
+out:
+	return count;
+}
+TF_TPG_BASE_ATTR(tcm_usbg, enable, S_IRUGO | S_IWUSR);
+
+static ssize_t tcm_usbg_tpg_show_nexus(
+		struct se_portal_group *se_tpg,
+		char *page)
+{
+	struct usbg_tpg *tpg = container_of(se_tpg, struct usbg_tpg, se_tpg);
+	struct tcm_usbg_nexus *tv_nexus;
+	ssize_t ret;
+
+	mutex_lock(&tpg->tpg_mutex);
+	tv_nexus = tpg->tpg_nexus;
+	if (!tv_nexus) {
+		ret = -ENODEV;
+		goto out;
+	}
+	ret = snprintf(page, PAGE_SIZE, "%s\n",
+			tv_nexus->tvn_se_sess->se_node_acl->initiatorname);
+out:
+	mutex_unlock(&tpg->tpg_mutex);
+	return ret;
+}
+
+static int tcm_usbg_make_nexus(struct usbg_tpg *tpg, char *name)
+{
+	struct se_portal_group *se_tpg;
+	struct tcm_usbg_nexus *tv_nexus;
+	int ret;
+
+	mutex_lock(&tpg->tpg_mutex);
+	if (tpg->tpg_nexus) {
+		ret = -EEXIST;
+		pr_debug("tpg->tpg_nexus already exists\n");
+		goto err_unlock;
+	}
+	se_tpg = &tpg->se_tpg;
+
+	ret = -ENOMEM;
+	tv_nexus = kzalloc(sizeof(*tv_nexus), GFP_KERNEL);
+	if (!tv_nexus) {
+		pr_err("Unable to allocate struct tcm_vhost_nexus\n");
+		goto err_unlock;
+	}
+	tv_nexus->tvn_se_sess = transport_init_session();
+	if (IS_ERR(tv_nexus->tvn_se_sess))
+		goto err_free;
+
+	/*
+	 * Since we are running in 'demo mode' this call with generate a
+	 * struct se_node_acl for the tcm_vhost struct se_portal_group with
+	 * the SCSI Initiator port name of the passed configfs group 'name'.
+	 */
+	tv_nexus->tvn_se_sess->se_node_acl = core_tpg_check_initiator_node_acl(
+			se_tpg, name);
+	if (!tv_nexus->tvn_se_sess->se_node_acl) {
+		pr_debug("core_tpg_check_initiator_node_acl() failed"
+				" for %s\n", name);
+		goto err_session;
+	}
+	/*
+	 * Now register the TCM vHost virtual I_T Nexus as active with the
+	 * call to __transport_register_session()
+	 */
+	__transport_register_session(se_tpg, tv_nexus->tvn_se_sess->se_node_acl,
+			tv_nexus->tvn_se_sess, tv_nexus);
+	tpg->tpg_nexus = tv_nexus;
+	mutex_unlock(&tpg->tpg_mutex);
+	return 0;
+
+err_session:
+	transport_free_session(tv_nexus->tvn_se_sess);
+err_free:
+	kfree(tv_nexus);
+err_unlock:
+	mutex_unlock(&tpg->tpg_mutex);
+	return ret;
+}
+
+static int tcm_usbg_drop_nexus(struct usbg_tpg *tpg)
+{
+	struct se_session *se_sess;
+	struct tcm_usbg_nexus *tv_nexus;
+	int ret = -ENODEV;
+
+	mutex_lock(&tpg->tpg_mutex);
+	tv_nexus = tpg->tpg_nexus;
+	if (!tv_nexus)
+		goto out;
+
+	se_sess = tv_nexus->tvn_se_sess;
+	if (!se_sess)
+		goto out;
+
+	if (atomic_read(&tpg->tpg_port_count)) {
+		ret = -EPERM;
+		pr_err("Unable to remove Host I_T Nexus with"
+				" active TPG port count: %d\n",
+				atomic_read(&tpg->tpg_port_count));
+		goto out;
+	}
+
+	pr_debug("Removing I_T Nexus to Initiator Port: %s\n",
+			tv_nexus->tvn_se_sess->se_node_acl->initiatorname);
+	/*
+	 * Release the SCSI I_T Nexus to the emulated vHost Target Port
+	 */
+	transport_deregister_session(tv_nexus->tvn_se_sess);
+	tpg->tpg_nexus = NULL;
+
+	kfree(tv_nexus);
+out:
+	mutex_unlock(&tpg->tpg_mutex);
+	return 0;
+}
+
+static ssize_t tcm_usbg_tpg_store_nexus(
+		struct se_portal_group *se_tpg,
+		const char *page,
+		size_t count)
+{
+	struct usbg_tpg *tpg = container_of(se_tpg, struct usbg_tpg, se_tpg);
+	unsigned char i_port[USBG_NAMELEN], *ptr;
+	int ret;
+
+	if (!strncmp(page, "NULL", 4)) {
+		ret = tcm_usbg_drop_nexus(tpg);
+		return (!ret) ? count : ret;
+	}
+	if (strlen(page) > USBG_NAMELEN) {
+		pr_err("Emulated NAA Sas Address: %s, exceeds"
+				" max: %d\n", page, USBG_NAMELEN);
+		return -EINVAL;
+	}
+	snprintf(i_port, USBG_NAMELEN, "%s", page);
+
+	ptr = strstr(i_port, "naa.");
+	if (!ptr) {
+		pr_err("Missing 'naa.' prefix\n");
+		return -EINVAL;
+	}
+
+	if (i_port[strlen(i_port) - 1] == '\n')
+		i_port[strlen(i_port) - 1] = '\0';
+
+	ret = tcm_usbg_make_nexus(tpg, &i_port[4]);
+	if (ret < 0)
+		return ret;
+	return count;
+}
+TF_TPG_BASE_ATTR(tcm_usbg, nexus, S_IRUGO | S_IWUSR);
+
+static struct configfs_attribute *usbg_base_attrs[] = {
+	&tcm_usbg_tpg_enable.attr,
+	&tcm_usbg_tpg_nexus.attr,
+	NULL,
+};
+
+static int usbg_port_link(struct se_portal_group *se_tpg, struct se_lun *lun)
+{
+	struct usbg_tpg *tpg = container_of(se_tpg, struct usbg_tpg, se_tpg);
+
+	atomic_inc(&tpg->tpg_port_count);
+	smp_mb__after_atomic_inc();
+	return 0;
+}
+
+static void usbg_port_unlink(struct se_portal_group *se_tpg,
+		struct se_lun *se_lun)
+{
+	struct usbg_tpg *tpg = container_of(se_tpg, struct usbg_tpg, se_tpg);
+
+	atomic_dec(&tpg->tpg_port_count);
+	smp_mb__after_atomic_dec();
+}
+
+static int usbg_check_stop_free(struct se_cmd *se_cmd)
+{
+	struct usbg_cmd *cmd = container_of(se_cmd, struct usbg_cmd,
+			se_cmd);
+
+	kref_put(&cmd->ref, usbg_cmd_release);
+	return 1;
+}
+
+static struct target_core_fabric_ops usbg_ops = {
+	.get_fabric_name		= usbg_get_fabric_name,
+	.get_fabric_proto_ident		= usbg_get_fabric_proto_ident,
+	.tpg_get_wwn			= usbg_get_fabric_wwn,
+	.tpg_get_tag			= usbg_get_tag,
+	.tpg_get_default_depth		= usbg_get_default_depth,
+	.tpg_get_pr_transport_id	= usbg_get_pr_transport_id,
+	.tpg_get_pr_transport_id_len	= usbg_get_pr_transport_id_len,
+	.tpg_parse_pr_out_transport_id	= usbg_parse_pr_out_transport_id,
+	.tpg_check_demo_mode		= usbg_check_true,
+	.tpg_check_demo_mode_cache	= usbg_check_false,
+	.tpg_check_demo_mode_write_protect = usbg_check_false,
+	.tpg_check_prod_mode_write_protect = usbg_check_false,
+	.tpg_alloc_fabric_acl		= usbg_alloc_fabric_acl,
+	.tpg_release_fabric_acl		= usbg_release_fabric_acl,
+	.tpg_get_inst_index		= usbg_tpg_get_inst_index,
+	.new_cmd_map			= usbg_new_cmd,
+	.release_cmd			= usbg_release_cmd,
+	.shutdown_session		= usbg_shutdown_session,
+	.close_session			= usbg_close_session,
+	.sess_get_index			= usbg_sess_get_index,
+	.sess_get_initiator_sid		= NULL,
+	.write_pending			= usbg_send_write_request,
+	.write_pending_status		= usbg_write_pending_status,
+	.set_default_node_attributes	= usbg_set_default_node_attrs,
+	.get_task_tag			= usbg_get_task_tag,
+	.get_cmd_state			= usbg_get_cmd_state,
+	.queue_data_in			= usbg_send_read_response,
+	.queue_status			= usbg_send_status_response,
+	.queue_tm_rsp			= usbg_queue_tm_rsp,
+	.get_fabric_sense_len		= usbg_get_fabric_sense_len,
+	.set_fabric_sense_len		= usbg_set_fabric_sense_len,
+	.check_stop_free		= usbg_check_stop_free,
+
+	.fabric_make_wwn		= usbg_make_tport,
+	.fabric_drop_wwn		= usbg_drop_tport,
+	.fabric_make_tpg		= usbg_make_tpg,
+	.fabric_drop_tpg		= usbg_drop_tpg,
+	.fabric_post_link		= usbg_port_link,
+	.fabric_pre_unlink		= usbg_port_unlink,
+	.fabric_make_np			= NULL,
+	.fabric_drop_np			= NULL,
+	.fabric_make_nodeacl		= usbg_make_nodeacl,
+	.fabric_drop_nodeacl		= usbg_drop_nodeacl,
+};
+
+static int usbg_register_configfs(void)
+{
+	struct target_fabric_configfs *fabric;
+	int ret;
+
+	fabric = target_fabric_configfs_init(THIS_MODULE, "usb_gadget");
+	if (IS_ERR(fabric)) {
+		printk(KERN_ERR "target_fabric_configfs_init() failed\n");
+		return PTR_ERR(fabric);
+	}
+
+	fabric->tf_ops = usbg_ops;
+	TF_CIT_TMPL(fabric)->tfc_wwn_cit.ct_attrs = usbg_wwn_attrs;
+	TF_CIT_TMPL(fabric)->tfc_tpg_base_cit.ct_attrs = usbg_base_attrs;
+	TF_CIT_TMPL(fabric)->tfc_tpg_attrib_cit.ct_attrs = NULL;
+	TF_CIT_TMPL(fabric)->tfc_tpg_param_cit.ct_attrs = NULL;
+	TF_CIT_TMPL(fabric)->tfc_tpg_np_base_cit.ct_attrs = NULL;
+	TF_CIT_TMPL(fabric)->tfc_tpg_nacl_base_cit.ct_attrs = NULL;
+	TF_CIT_TMPL(fabric)->tfc_tpg_nacl_attrib_cit.ct_attrs = NULL;
+	TF_CIT_TMPL(fabric)->tfc_tpg_nacl_auth_cit.ct_attrs = NULL;
+	TF_CIT_TMPL(fabric)->tfc_tpg_nacl_param_cit.ct_attrs = NULL;
+	ret = target_fabric_configfs_register(fabric);
+	if (ret < 0) {
+		printk(KERN_ERR "target_fabric_configfs_register() failed"
+				" for usb-gadget\n");
+		return ret;
+	}
+	usbg_fabric_configfs = fabric;
+	return 0;
+};
+
+static void usbg_deregister_configfs(void)
+{
+	if (!(usbg_fabric_configfs))
+		return;
+
+	target_fabric_configfs_deregister(usbg_fabric_configfs);
+	usbg_fabric_configfs = NULL;
+};
+
+/* Start gadget.c code */
+
+static struct usb_interface_descriptor bot_intf_desc = {
+	.bLength =              sizeof(bot_intf_desc),
+	.bDescriptorType =      USB_DT_INTERFACE,
+	.bAlternateSetting =	0,
+	.bNumEndpoints =        2,
+	.bAlternateSetting =	USB_G_ALT_INT_BBB,
+	.bInterfaceClass =      USB_CLASS_MASS_STORAGE,
+	.bInterfaceSubClass =   USB_SC_SCSI,
+	.bInterfaceProtocol =   USB_PR_BULK,
+	/* .iInterface =           DYNAMIC */
+};
+
+static struct usb_interface_descriptor uasp_intf_desc = {
+	.bLength =		sizeof(uasp_intf_desc),
+	.bDescriptorType =	USB_DT_INTERFACE,
+	.bNumEndpoints =	4,
+	.bAlternateSetting =	USB_G_ALT_INT_UAS,
+	.bInterfaceClass =	USB_CLASS_MASS_STORAGE,
+	.bInterfaceSubClass =	USB_SC_SCSI,
+	.bInterfaceProtocol =	USB_PR_UAS,
+	/* .iInterface =           DYNAMIC */
+};
+
+static struct usb_endpoint_descriptor uasp_bi_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+	.bEndpointAddress =	USB_DIR_IN,
+	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize =	cpu_to_le16(512),
+};
+
+static struct usb_endpoint_descriptor uasp_fs_bi_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+	.bEndpointAddress =	USB_DIR_IN,
+	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
+};
+
+static struct usb_pipe_usage_descriptor uasp_bi_pipe_desc = {
+	.bLength =		sizeof(uasp_bi_pipe_desc),
+	.bDescriptorType =	USB_DT_PIPE_USAGE,
+	.bPipeID =		DATA_IN_PIPE_ID,
+};
+
+static struct usb_endpoint_descriptor uasp_ss_bi_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+	.bEndpointAddress =	USB_DIR_IN,
+	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize =	cpu_to_le16(1024),
+};
+
+static struct usb_ss_ep_comp_descriptor uasp_bi_ep_comp_desc = {
+	.bLength =		sizeof(uasp_bi_ep_comp_desc),
+	.bDescriptorType =	USB_DT_SS_ENDPOINT_COMP,
+	.bMaxBurst =		0,
+	.bmAttributes =		UASP_SS_EP_COMP_LOG_STREAMS,
+	.wBytesPerInterval =	0,
+};
+
+static struct usb_ss_ep_comp_descriptor bot_bi_ep_comp_desc = {
+	.bLength =		sizeof(bot_bi_ep_comp_desc),
+	.bDescriptorType =	USB_DT_SS_ENDPOINT_COMP,
+	.bMaxBurst =		0,
+};
+
+static struct usb_endpoint_descriptor uasp_bo_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+	.bEndpointAddress =	USB_DIR_OUT,
+	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize =	cpu_to_le16(512),
+};
+
+static struct usb_endpoint_descriptor uasp_fs_bo_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+	.bEndpointAddress =	USB_DIR_OUT,
+	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
+};
+
+static struct usb_pipe_usage_descriptor uasp_bo_pipe_desc = {
+	.bLength =		sizeof(uasp_bo_pipe_desc),
+	.bDescriptorType =	USB_DT_PIPE_USAGE,
+	.bPipeID =		DATA_OUT_PIPE_ID,
+};
+
+static struct usb_endpoint_descriptor uasp_ss_bo_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+	.bEndpointAddress =	USB_DIR_OUT,
+	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize =	cpu_to_le16(0x400),
+};
+
+static struct usb_ss_ep_comp_descriptor uasp_bo_ep_comp_desc = {
+	.bLength =		sizeof(uasp_bo_ep_comp_desc),
+	.bDescriptorType =	USB_DT_SS_ENDPOINT_COMP,
+	.bmAttributes =		UASP_SS_EP_COMP_LOG_STREAMS,
+};
+
+static struct usb_ss_ep_comp_descriptor bot_bo_ep_comp_desc = {
+	.bLength =		sizeof(bot_bo_ep_comp_desc),
+	.bDescriptorType =	USB_DT_SS_ENDPOINT_COMP,
+};
+
+static struct usb_endpoint_descriptor uasp_status_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+	.bEndpointAddress =	USB_DIR_IN,
+	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize =	cpu_to_le16(512),
+};
+
+static struct usb_endpoint_descriptor uasp_fs_status_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+	.bEndpointAddress =	USB_DIR_IN,
+	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
+};
+
+static struct usb_pipe_usage_descriptor uasp_status_pipe_desc = {
+	.bLength =		sizeof(uasp_status_pipe_desc),
+	.bDescriptorType =	USB_DT_PIPE_USAGE,
+	.bPipeID =		STATUS_PIPE_ID,
+};
+
+static struct usb_endpoint_descriptor uasp_ss_status_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+	.bEndpointAddress =	USB_DIR_IN,
+	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize =	cpu_to_le16(1024),
+};
+
+static struct usb_ss_ep_comp_descriptor uasp_status_in_ep_comp_desc = {
+	.bLength =		sizeof(uasp_status_in_ep_comp_desc),
+	.bDescriptorType =	USB_DT_SS_ENDPOINT_COMP,
+	.bmAttributes =		UASP_SS_EP_COMP_LOG_STREAMS,
+};
+
+static struct usb_endpoint_descriptor uasp_cmd_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+	.bEndpointAddress =	USB_DIR_OUT,
+	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize =	cpu_to_le16(512),
+};
+
+static struct usb_endpoint_descriptor uasp_fs_cmd_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+	.bEndpointAddress =	USB_DIR_OUT,
+	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
+};
+
+static struct usb_pipe_usage_descriptor uasp_cmd_pipe_desc = {
+	.bLength =		sizeof(uasp_cmd_pipe_desc),
+	.bDescriptorType =	USB_DT_PIPE_USAGE,
+	.bPipeID =		CMD_PIPE_ID,
+};
+
+static struct usb_endpoint_descriptor uasp_ss_cmd_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+	.bEndpointAddress =	USB_DIR_OUT,
+	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize =	cpu_to_le16(1024),
+};
+
+static struct usb_ss_ep_comp_descriptor uasp_cmd_comp_desc = {
+	.bLength =		sizeof(uasp_cmd_comp_desc),
+	.bDescriptorType =	USB_DT_SS_ENDPOINT_COMP,
+};
+
+static struct usb_descriptor_header *uasp_fs_function_desc[] = {
+	(struct usb_descriptor_header *) &bot_intf_desc,
+	(struct usb_descriptor_header *) &uasp_fs_bi_desc,
+	(struct usb_descriptor_header *) &uasp_fs_bo_desc,
+
+	(struct usb_descriptor_header *) &uasp_intf_desc,
+	(struct usb_descriptor_header *) &uasp_fs_bi_desc,
+	(struct usb_descriptor_header *) &uasp_bi_pipe_desc,
+	(struct usb_descriptor_header *) &uasp_fs_bo_desc,
+	(struct usb_descriptor_header *) &uasp_bo_pipe_desc,
+	(struct usb_descriptor_header *) &uasp_fs_status_desc,
+	(struct usb_descriptor_header *) &uasp_status_pipe_desc,
+	(struct usb_descriptor_header *) &uasp_fs_cmd_desc,
+	(struct usb_descriptor_header *) &uasp_cmd_pipe_desc,
+};
+
+static struct usb_descriptor_header *uasp_hs_function_desc[] = {
+	(struct usb_descriptor_header *) &bot_intf_desc,
+	(struct usb_descriptor_header *) &uasp_bi_desc,
+	(struct usb_descriptor_header *) &uasp_bo_desc,
+
+	(struct usb_descriptor_header *) &uasp_intf_desc,
+	(struct usb_descriptor_header *) &uasp_bi_desc,
+	(struct usb_descriptor_header *) &uasp_bi_pipe_desc,
+	(struct usb_descriptor_header *) &uasp_bo_desc,
+	(struct usb_descriptor_header *) &uasp_bo_pipe_desc,
+	(struct usb_descriptor_header *) &uasp_status_desc,
+	(struct usb_descriptor_header *) &uasp_status_pipe_desc,
+	(struct usb_descriptor_header *) &uasp_cmd_desc,
+	(struct usb_descriptor_header *) &uasp_cmd_pipe_desc,
+	NULL,
+};
+
+static struct usb_descriptor_header *uasp_ss_function_desc[] = {
+	(struct usb_descriptor_header *) &bot_intf_desc,
+	(struct usb_descriptor_header *) &uasp_ss_bi_desc,
+	(struct usb_descriptor_header *) &bot_bi_ep_comp_desc,
+	(struct usb_descriptor_header *) &uasp_ss_bo_desc,
+	(struct usb_descriptor_header *) &bot_bo_ep_comp_desc,
+
+	(struct usb_descriptor_header *) &uasp_intf_desc,
+	(struct usb_descriptor_header *) &uasp_ss_bi_desc,
+	(struct usb_descriptor_header *) &uasp_bi_ep_comp_desc,
+	(struct usb_descriptor_header *) &uasp_bi_pipe_desc,
+	(struct usb_descriptor_header *) &uasp_ss_bo_desc,
+	(struct usb_descriptor_header *) &uasp_bo_ep_comp_desc,
+	(struct usb_descriptor_header *) &uasp_bo_pipe_desc,
+	(struct usb_descriptor_header *) &uasp_ss_status_desc,
+	(struct usb_descriptor_header *) &uasp_status_in_ep_comp_desc,
+	(struct usb_descriptor_header *) &uasp_status_pipe_desc,
+	(struct usb_descriptor_header *) &uasp_ss_cmd_desc,
+	(struct usb_descriptor_header *) &uasp_cmd_comp_desc,
+	(struct usb_descriptor_header *) &uasp_cmd_pipe_desc,
+	NULL,
+};
+
+static struct usb_string tcm_us_strings[] = {
+	[0].s = "Bulk Only Transport",
+	[1].s = "USB Attached SCSI",
+	{  } /* end of list */
+};
+
+static struct usb_gadget_strings tcm_stringtab = {
+	.language = 0x0409,
+	.strings = tcm_us_strings,
+};
+
+static struct usb_gadget_strings *tcm_strings[] = {
+	&tcm_stringtab,
+	NULL,
+};
+
+static void give_back_ep(struct usb_ep **pep)
+{
+	struct usb_ep *ep = *pep;
+	if (!ep)
+		return;
+	ep->driver_data = NULL;
+}
+
+static int usbg_bind(struct usb_configuration *c, struct usb_function *f)
+{
+	struct f_uas		*fu = to_f_uas(f);
+	struct usb_gadget	*gadget = c->cdev->gadget;
+	struct usb_ep		*ep;
+	int			iface;
+
+	iface = usb_interface_id(c, f);
+	if (iface < 0)
+		return iface;
+
+	bot_intf_desc.bInterfaceNumber = iface;
+	uasp_intf_desc.bInterfaceNumber = iface;
+	fu->iface = iface;
+	ep = usb_ep_autoconfig_ss(gadget, &uasp_ss_bi_desc,
+			&uasp_bi_ep_comp_desc);
+	if (!ep)
+		goto ep_fail;
+
+	ep->driver_data = fu;
+	fu->ep_in = ep;
+
+	ep = usb_ep_autoconfig_ss(gadget, &uasp_ss_bo_desc,
+			&uasp_bo_ep_comp_desc);
+	if (!ep)
+		goto ep_fail;
+	ep->driver_data = fu;
+	fu->ep_out = ep;
+
+	ep = usb_ep_autoconfig_ss(gadget, &uasp_ss_status_desc,
+			&uasp_status_in_ep_comp_desc);
+	if (!ep)
+		goto ep_fail;
+	ep->driver_data = fu;
+	fu->ep_status = ep;
+
+	ep = usb_ep_autoconfig_ss(gadget, &uasp_ss_cmd_desc,
+			&uasp_cmd_comp_desc);
+	if (!ep)
+		goto ep_fail;
+	ep->driver_data = fu;
+	fu->ep_cmd = ep;
+
+	/* Assume endpoint addresses are the same for both speeds */
+	uasp_bi_desc.bEndpointAddress =	uasp_ss_bi_desc.bEndpointAddress;
+	uasp_bo_desc.bEndpointAddress = uasp_ss_bo_desc.bEndpointAddress;
+	uasp_status_desc.bEndpointAddress =
+		uasp_ss_status_desc.bEndpointAddress;
+	uasp_cmd_desc.bEndpointAddress = uasp_ss_cmd_desc.bEndpointAddress;
+
+	uasp_fs_bi_desc.bEndpointAddress = uasp_ss_bi_desc.bEndpointAddress;
+	uasp_fs_bo_desc.bEndpointAddress = uasp_ss_bo_desc.bEndpointAddress;
+	uasp_fs_status_desc.bEndpointAddress =
+		uasp_ss_status_desc.bEndpointAddress;
+	uasp_fs_cmd_desc.bEndpointAddress = uasp_ss_cmd_desc.bEndpointAddress;
+
+	return 0;
+ep_fail:
+	pr_err("Can't claim all required eps\n");
+
+	give_back_ep(&fu->ep_in);
+	give_back_ep(&fu->ep_out);
+	give_back_ep(&fu->ep_status);
+	give_back_ep(&fu->ep_cmd);
+	return -ENOTSUPP;
+}
+
+static void usbg_unbind(struct usb_configuration *c, struct usb_function *f)
+{
+	struct f_uas *fu = to_f_uas(f);
+
+	kfree(fu);
+}
+
+struct guas_setup_wq {
+	struct work_struct work;
+	struct f_uas *fu;
+	unsigned int alt;
+};
+
+static void usbg_delayed_set_alt(struct work_struct *wq)
+{
+	struct guas_setup_wq *work = container_of(wq, struct guas_setup_wq,
+			work);
+	struct f_uas *fu = work->fu;
+	int alt = work->alt;
+
+	kfree(work);
+
+	if (fu->flags & USBG_IS_BOT)
+		bot_cleanup_old_alt(fu);
+	if (fu->flags & USBG_IS_UAS)
+		uasp_cleanup_old_alt(fu);
+
+	if (alt == USB_G_ALT_INT_BBB)
+		bot_set_alt(fu);
+	else if (alt == USB_G_ALT_INT_UAS)
+		uasp_set_alt(fu);
+	usb_composite_setup_continue(fu->function.config->cdev);
+}
+
+static int usbg_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
+{
+	struct f_uas *fu = to_f_uas(f);
+
+	if ((alt == USB_G_ALT_INT_BBB) || (alt == USB_G_ALT_INT_UAS)) {
+		struct guas_setup_wq *work;
+
+		work = kmalloc(sizeof(*work), GFP_ATOMIC);
+		if (!work)
+			return -ENOMEM;
+		INIT_WORK(&work->work, usbg_delayed_set_alt);
+		work->fu = fu;
+		work->alt = alt;
+		schedule_work(&work->work);
+		return USB_GADGET_DELAYED_STATUS;
+	}
+	return -EOPNOTSUPP;
+}
+
+static void usbg_disable(struct usb_function *f)
+{
+	struct f_uas *fu = to_f_uas(f);
+
+	if (fu->flags & USBG_IS_UAS)
+		uasp_cleanup_old_alt(fu);
+	else if (fu->flags & USBG_IS_BOT)
+		bot_cleanup_old_alt(fu);
+	fu->flags = 0;
+}
+
+static int usbg_setup(struct usb_function *f,
+		const struct usb_ctrlrequest *ctrl)
+{
+	struct f_uas *fu = to_f_uas(f);
+
+	if (!(fu->flags & USBG_IS_BOT))
+		return -EOPNOTSUPP;
+
+	return usbg_bot_setup(f, ctrl);
+}
+
+static int tcm_bind_config(struct usb_configuration *c)
+{
+	struct f_uas *fu;
+	int ret;
+
+	fu = kzalloc(sizeof(*fu), GFP_KERNEL);
+	if (!fu)
+		return -ENOMEM;
+	fu->function.name = "Target Function";
+	fu->function.descriptors = uasp_fs_function_desc;
+	fu->function.hs_descriptors = uasp_hs_function_desc;
+	fu->function.ss_descriptors = uasp_ss_function_desc;
+	fu->function.strings = tcm_strings;
+	fu->function.bind = usbg_bind;
+	fu->function.unbind = usbg_unbind;
+	fu->function.set_alt = usbg_set_alt;
+	fu->function.setup = usbg_setup;
+	fu->function.disable = usbg_disable;
+	fu->tpg = the_only_tpg_I_currently_have;
+
+	/* BOT interface string */
+	ret = usb_string_id(c->cdev);
+	if (ret < 0)
+		goto err;
+	tcm_us_strings[0].id = ret;
+	bot_intf_desc.iInterface = ret;
+
+	/* data interface label */
+	ret = usb_string_id(c->cdev);
+	if (ret < 0)
+		goto err;
+	tcm_us_strings[1].id = ret;
+	uasp_intf_desc.iInterface = ret;
+
+	ret = usb_add_function(c, &fu->function);
+	if (ret)
+		goto err;
+
+	return 0;
+err:
+	kfree(fu);
+	return ret;
+}
+
+static int f_tcm_init(int (*connect_cb)(bool connect))
+{
+	int ret;
+
+	usbg_connect_cb = connect_cb;
+	ret = usbg_register_configfs();
+	return ret;
+}
+
+static void f_tcm_exit(void)
+{
+	usbg_deregister_configfs();
+	usbg_connect_cb = NULL;
+}
diff --git a/drivers/usb/gadget/tcm_usb_gadget.h b/drivers/usb/gadget/f_tcm.h
similarity index 93%
rename from drivers/usb/gadget/tcm_usb_gadget.h
rename to drivers/usb/gadget/f_tcm.h
index bb18999..bed8435 100644
--- a/drivers/usb/gadget/tcm_usb_gadget.h
+++ b/drivers/usb/gadget/f_tcm.h
@@ -16,13 +16,6 @@
 #define UASP_SS_EP_COMP_LOG_STREAMS 4
 #define UASP_SS_EP_COMP_NUM_STREAMS (1 << UASP_SS_EP_COMP_LOG_STREAMS)
 
-#define USB_G_STR_MANUFACTOR    1
-#define USB_G_STR_PRODUCT       2
-#define USB_G_STR_SERIAL        3
-#define USB_G_STR_CONFIG        4
-#define USB_G_STR_INT_UAS       5
-#define USB_G_STR_INT_BBB       6
-
 #define USB_G_ALT_INT_BBB       0
 #define USB_G_ALT_INT_UAS       1
 
diff --git a/drivers/usb/gadget/tcm_usb_gadget.c b/drivers/usb/gadget/tcm_usb_gadget.c
index c46439c..8787768 100644
--- a/drivers/usb/gadget/tcm_usb_gadget.c
+++ b/drivers/usb/gadget/tcm_usb_gadget.c
@@ -1,4 +1,4 @@
-/* Target based USB-Gadget
+/* Target based USB-Gadget Function
  *
  * UAS protocol handling, target callbacks, configfs handling,
  * BBB (USB Mass Storage Class Bulk-Only (BBB) and Transport protocol handling.
@@ -6,2208 +6,28 @@
  * Author: Sebastian Andrzej Siewior <bigeasy at linutronix dot de>
  * License: GPLv2 as published by FSF.
  */
-#include <linux/kernel.h>
+
+#include <linux/init.h>
 #include <linux/module.h>
-#include <linux/types.h>
-#include <linux/string.h>
-#include <linux/configfs.h>
-#include <linux/ctype.h>
-#include <linux/usb/ch9.h>
+
 #include <linux/usb/composite.h>
 #include <linux/usb/gadget.h>
-#include <linux/usb/storage.h>
-#include <scsi/scsi.h>
-#include <scsi/scsi_tcq.h>
-#include <target/target_core_base.h>
-#include <target/target_core_fabric.h>
-#include <target/target_core_fabric_configfs.h>
-#include <target/target_core_configfs.h>
-#include <target/configfs_macros.h>
-#include <asm/unaligned.h>
 
 #include "usbstring.c"
 #include "epautoconf.c"
 #include "config.c"
 #include "composite.c"
 
-#include "tcm_usb_gadget.h"
-
-static struct target_fabric_configfs *usbg_fabric_configfs;
-
-static inline struct f_uas *to_f_uas(struct usb_function *f)
-{
-	return container_of(f, struct f_uas, function);
-}
-
-static void usbg_cmd_release(struct kref *);
-
-static inline void usbg_cleanup_cmd(struct usbg_cmd *cmd)
-{
-	kref_put(&cmd->ref, usbg_cmd_release);
-}
-
-/* Start bot.c code */
-
-static int bot_enqueue_cmd_cbw(struct f_uas *fu)
-{
-	int ret;
-
-	if (fu->flags & USBG_BOT_CMD_PEND)
-		return 0;
-
-	ret = usb_ep_queue(fu->ep_out, fu->cmd.req, GFP_ATOMIC);
-	if (!ret)
-		fu->flags |= USBG_BOT_CMD_PEND;
-	return ret;
-}
-
-static void bot_status_complete(struct usb_ep *ep, struct usb_request *req)
-{
-	struct usbg_cmd *cmd = req->context;
-	struct f_uas *fu = cmd->fu;
-
-	usbg_cleanup_cmd(cmd);
-	if (req->status < 0) {
-		pr_err("ERR %s(%d)\n", __func__, __LINE__);
-		return;
-	}
-
-	/* CSW completed, wait for next CBW */
-	bot_enqueue_cmd_cbw(fu);
-}
-
-static void bot_enqueue_sense_code(struct f_uas *fu, struct usbg_cmd *cmd)
-{
-	struct bulk_cs_wrap *csw = &fu->bot_status.csw;
-	int ret;
-	u8 *sense;
-	unsigned int csw_stat;
-
-	csw_stat = cmd->csw_code;
-
-	/*
-	 * We can't send SENSE as a response. So we take ASC & ASCQ from our
-	 * sense buffer and queue it and hope the host sends a REQUEST_SENSE
-	 * command where it learns why we failed.
-	 */
-	sense = cmd->sense_iu.sense;
-
-	csw->Tag = cmd->bot_tag;
-	csw->Status = csw_stat;
-	fu->bot_status.req->context = cmd;
-	ret = usb_ep_queue(fu->ep_in, fu->bot_status.req, GFP_ATOMIC);
-	if (ret)
-		pr_err("%s(%d) ERR: %d\n", __func__, __LINE__, ret);
-}
-
-static void bot_err_compl(struct usb_ep *ep, struct usb_request *req)
-{
-	struct usbg_cmd *cmd = req->context;
-	struct f_uas *fu = cmd->fu;
-
-	if (req->status < 0)
-		pr_err("ERR %s(%d)\n", __func__, __LINE__);
-
-	if (cmd->data_len) {
-		if (cmd->data_len > ep->maxpacket) {
-			req->length = ep->maxpacket;
-			cmd->data_len -= ep->maxpacket;
-		} else {
-			req->length = cmd->data_len;
-			cmd->data_len = 0;
-		}
-
-		usb_ep_queue(ep, req, GFP_ATOMIC);
-		return ;
-	}
-	bot_enqueue_sense_code(fu, cmd);
-}
-
-static void bot_send_bad_status(struct usbg_cmd *cmd)
-{
-	struct f_uas *fu = cmd->fu;
-	struct bulk_cs_wrap *csw = &fu->bot_status.csw;
-	struct usb_request *req;
-	struct usb_ep *ep;
-
-	csw->Residue = cpu_to_le32(cmd->data_len);
-
-	if (cmd->data_len) {
-		if (cmd->is_read) {
-			ep = fu->ep_in;
-			req = fu->bot_req_in;
-		} else {
-			ep = fu->ep_out;
-			req = fu->bot_req_out;
-		}
-
-		if (cmd->data_len > fu->ep_in->maxpacket) {
-			req->length = ep->maxpacket;
-			cmd->data_len -= ep->maxpacket;
-		} else {
-			req->length = cmd->data_len;
-			cmd->data_len = 0;
-		}
-		req->complete = bot_err_compl;
-		req->context = cmd;
-		req->buf = fu->cmd.buf;
-		usb_ep_queue(ep, req, GFP_KERNEL);
-	} else {
-		bot_enqueue_sense_code(fu, cmd);
-	}
-}
-
-static int bot_send_status(struct usbg_cmd *cmd, bool moved_data)
-{
-	struct f_uas *fu = cmd->fu;
-	struct bulk_cs_wrap *csw = &fu->bot_status.csw;
-	int ret;
-
-	if (cmd->se_cmd.scsi_status == SAM_STAT_GOOD) {
-		if (!moved_data && cmd->data_len) {
-			/*
-			 * the host wants to move data, we don't. Fill / empty
-			 * the pipe and then send the csw with reside set.
-			 */
-			cmd->csw_code = US_BULK_STAT_OK;
-			bot_send_bad_status(cmd);
-			return 0;
-		}
-
-		csw->Tag = cmd->bot_tag;
-		csw->Residue = cpu_to_le32(0);
-		csw->Status = US_BULK_STAT_OK;
-		fu->bot_status.req->context = cmd;
-
-		ret = usb_ep_queue(fu->ep_in, fu->bot_status.req, GFP_KERNEL);
-		if (ret)
-			pr_err("%s(%d) ERR: %d\n", __func__, __LINE__, ret);
-	} else {
-		cmd->csw_code = US_BULK_STAT_FAIL;
-		bot_send_bad_status(cmd);
-	}
-	return 0;
-}
-
-/*
- * Called after command (no data transfer) or after the write (to device)
- * operation is completed
- */
-static int bot_send_status_response(struct usbg_cmd *cmd)
-{
-	bool moved_data = false;
-
-	if (!cmd->is_read)
-		moved_data = true;
-	return bot_send_status(cmd, moved_data);
-}
-
-/* Read request completed, now we have to send the CSW */
-static void bot_read_compl(struct usb_ep *ep, struct usb_request *req)
-{
-	struct usbg_cmd *cmd = req->context;
-
-	if (req->status < 0)
-		pr_err("ERR %s(%d)\n", __func__, __LINE__);
-
-	bot_send_status(cmd, true);
-}
-
-static int bot_send_read_response(struct usbg_cmd *cmd)
-{
-	struct f_uas *fu = cmd->fu;
-	struct se_cmd *se_cmd = &cmd->se_cmd;
-	struct usb_gadget *gadget = fuas_to_gadget(fu);
-	int ret;
-
-	if (!cmd->data_len) {
-		cmd->csw_code = US_BULK_STAT_PHASE;
-		bot_send_bad_status(cmd);
-		return 0;
-	}
-
-	if (!gadget->sg_supported) {
-		cmd->data_buf = kmalloc(se_cmd->data_length, GFP_ATOMIC);
-		if (!cmd->data_buf)
-			return -ENOMEM;
-
-		sg_copy_to_buffer(se_cmd->t_data_sg,
-				se_cmd->t_data_nents,
-				cmd->data_buf,
-				se_cmd->data_length);
-
-		fu->bot_req_in->buf = cmd->data_buf;
-	} else {
-		fu->bot_req_in->buf = NULL;
-		fu->bot_req_in->num_sgs = se_cmd->t_data_nents;
-		fu->bot_req_in->sg = se_cmd->t_data_sg;
-	}
-
-	fu->bot_req_in->complete = bot_read_compl;
-	fu->bot_req_in->length = se_cmd->data_length;
-	fu->bot_req_in->context = cmd;
-	ret = usb_ep_queue(fu->ep_in, fu->bot_req_in, GFP_ATOMIC);
-	if (ret)
-		pr_err("%s(%d)\n", __func__, __LINE__);
-	return 0;
-}
-
-static void usbg_data_write_cmpl(struct usb_ep *, struct usb_request *);
-static int usbg_prepare_w_request(struct usbg_cmd *, struct usb_request *);
-
-static int bot_send_write_request(struct usbg_cmd *cmd)
-{
-	struct f_uas *fu = cmd->fu;
-	struct se_cmd *se_cmd = &cmd->se_cmd;
-	struct usb_gadget *gadget = fuas_to_gadget(fu);
-	int ret;
-
-	init_completion(&cmd->write_complete);
-	cmd->fu = fu;
-
-	if (!cmd->data_len) {
-		cmd->csw_code = US_BULK_STAT_PHASE;
-		return -EINVAL;
-	}
-
-	if (!gadget->sg_supported) {
-		cmd->data_buf = kmalloc(se_cmd->data_length, GFP_KERNEL);
-		if (!cmd->data_buf)
-			return -ENOMEM;
-
-		fu->bot_req_out->buf = cmd->data_buf;
-	} else {
-		fu->bot_req_out->buf = NULL;
-		fu->bot_req_out->num_sgs = se_cmd->t_data_nents;
-		fu->bot_req_out->sg = se_cmd->t_data_sg;
-	}
-
-	fu->bot_req_out->complete = usbg_data_write_cmpl;
-	fu->bot_req_out->length = se_cmd->data_length;
-	fu->bot_req_out->context = cmd;
-
-	ret = usbg_prepare_w_request(cmd, fu->bot_req_out);
-	if (ret)
-		goto cleanup;
-	ret = usb_ep_queue(fu->ep_out, fu->bot_req_out, GFP_KERNEL);
-	if (ret)
-		pr_err("%s(%d)\n", __func__, __LINE__);
-
-	wait_for_completion(&cmd->write_complete);
-	transport_generic_process_write(se_cmd);
-cleanup:
-	return ret;
-}
-
-static int bot_submit_command(struct f_uas *, void *, unsigned int);
-
-static void bot_cmd_complete(struct usb_ep *ep, struct usb_request *req)
-{
-	struct f_uas *fu = req->context;
-	int ret;
-
-	fu->flags &= ~USBG_BOT_CMD_PEND;
-
-	if (req->status < 0)
-		return;
-
-	ret = bot_submit_command(fu, req->buf, req->actual);
-	if (ret)
-		pr_err("%s(%d): %d\n", __func__, __LINE__, ret);
-}
-
-static int bot_prepare_reqs(struct f_uas *fu)
-{
-	int ret;
-
-	fu->bot_req_in = usb_ep_alloc_request(fu->ep_in, GFP_KERNEL);
-	if (!fu->bot_req_in)
-		goto err;
-
-	fu->bot_req_out = usb_ep_alloc_request(fu->ep_out, GFP_KERNEL);
-	if (!fu->bot_req_out)
-		goto err_out;
-
-	fu->cmd.req = usb_ep_alloc_request(fu->ep_out, GFP_KERNEL);
-	if (!fu->cmd.req)
-		goto err_cmd;
-
-	fu->bot_status.req = usb_ep_alloc_request(fu->ep_in, GFP_KERNEL);
-	if (!fu->bot_status.req)
-		goto err_sts;
-
-	fu->bot_status.req->buf = &fu->bot_status.csw;
-	fu->bot_status.req->length = US_BULK_CS_WRAP_LEN;
-	fu->bot_status.req->complete = bot_status_complete;
-	fu->bot_status.csw.Signature = cpu_to_le32(US_BULK_CS_SIGN);
-
-	fu->cmd.buf = kmalloc(fu->ep_out->maxpacket, GFP_KERNEL);
-	if (!fu->cmd.buf)
-		goto err_buf;
-
-	fu->cmd.req->complete = bot_cmd_complete;
-	fu->cmd.req->buf = fu->cmd.buf;
-	fu->cmd.req->length = fu->ep_out->maxpacket;
-	fu->cmd.req->context = fu;
-
-	ret = bot_enqueue_cmd_cbw(fu);
-	if (ret)
-		goto err_queue;
-	return 0;
-err_queue:
-	kfree(fu->cmd.buf);
-	fu->cmd.buf = NULL;
-err_buf:
-	usb_ep_free_request(fu->ep_in, fu->bot_status.req);
-err_sts:
-	usb_ep_free_request(fu->ep_out, fu->cmd.req);
-	fu->cmd.req = NULL;
-err_cmd:
-	usb_ep_free_request(fu->ep_out, fu->bot_req_out);
-	fu->bot_req_out = NULL;
-err_out:
-	usb_ep_free_request(fu->ep_in, fu->bot_req_in);
-	fu->bot_req_in = NULL;
-err:
-	pr_err("BOT: endpoint setup failed\n");
-	return -ENOMEM;
-}
-
-void bot_cleanup_old_alt(struct f_uas *fu)
-{
-	if (!(fu->flags & USBG_ENABLED))
-		return;
-
-	usb_ep_disable(fu->ep_in);
-	usb_ep_disable(fu->ep_out);
-
-	if (!fu->bot_req_in)
-		return;
-
-	usb_ep_free_request(fu->ep_in, fu->bot_req_in);
-	usb_ep_free_request(fu->ep_out, fu->bot_req_out);
-	usb_ep_free_request(fu->ep_out, fu->cmd.req);
-	usb_ep_free_request(fu->ep_out, fu->bot_status.req);
-
-	kfree(fu->cmd.buf);
-
-	fu->bot_req_in = NULL;
-	fu->bot_req_out = NULL;
-	fu->cmd.req = NULL;
-	fu->bot_status.req = NULL;
-	fu->cmd.buf = NULL;
-}
-
-static void bot_set_alt(struct f_uas *fu)
-{
-	struct usb_function *f = &fu->function;
-	struct usb_gadget *gadget = f->config->cdev->gadget;
-	int ret;
-
-	fu->flags = USBG_IS_BOT;
-
-	config_ep_by_speed(gadget, f, fu->ep_in);
-	ret = usb_ep_enable(fu->ep_in);
-	if (ret)
-		goto err_b_in;
-
-	config_ep_by_speed(gadget, f, fu->ep_out);
-	ret = usb_ep_enable(fu->ep_out);
-	if (ret)
-		goto err_b_out;
-
-	ret = bot_prepare_reqs(fu);
-	if (ret)
-		goto err_wq;
-	fu->flags |= USBG_ENABLED;
-	pr_info("Using the BOT protocol\n");
-	return;
-err_wq:
-	usb_ep_disable(fu->ep_out);
-err_b_out:
-	usb_ep_disable(fu->ep_in);
-err_b_in:
-	fu->flags = USBG_IS_BOT;
-}
-
-static int usbg_bot_setup(struct usb_function *f,
-		const struct usb_ctrlrequest *ctrl)
-{
-	struct f_uas *fu = to_f_uas(f);
-	struct usb_composite_dev *cdev = f->config->cdev;
-	u16 w_value = le16_to_cpu(ctrl->wValue);
-	u16 w_length = le16_to_cpu(ctrl->wLength);
-	int luns;
-	u8 *ret_lun;
-
-	switch (ctrl->bRequest) {
-	case US_BULK_GET_MAX_LUN:
-		if (ctrl->bRequestType != (USB_DIR_IN | USB_TYPE_CLASS |
-					USB_RECIP_INTERFACE))
-			return -ENOTSUPP;
-
-		if (w_length < 1)
-			return -EINVAL;
-		if (w_value != 0)
-			return -EINVAL;
-		luns = atomic_read(&fu->tpg->tpg_port_count);
-		if (!luns) {
-			pr_err("No LUNs configured?\n");
-			return -EINVAL;
-		}
-		/*
-		 * If 4 LUNs are present we return 3 i.e. LUN 0..3 can be
-		 * accessed. The upper limit is 0xf
-		 */
-		luns--;
-		if (luns > 0xf) {
-			pr_info_once("Limiting the number of luns to 16\n");
-			luns = 0xf;
-		}
-		ret_lun = cdev->req->buf;
-		*ret_lun = luns;
-		cdev->req->length = 1;
-		return usb_ep_queue(cdev->gadget->ep0, cdev->req, GFP_ATOMIC);
-		break;
-
-	case US_BULK_RESET_REQUEST:
-		/* XXX maybe we should remove previous requests for IN + OUT */
-		bot_enqueue_cmd_cbw(fu);
-		return 0;
-		break;
-	};
-	return -ENOTSUPP;
-}
-
-/* Start uas.c code */
-
-static void uasp_cleanup_one_stream(struct f_uas *fu, struct uas_stream *stream)
-{
-	/* We have either all three allocated or none */
-	if (!stream->req_in)
-		return;
-
-	usb_ep_free_request(fu->ep_in, stream->req_in);
-	usb_ep_free_request(fu->ep_out, stream->req_out);
-	usb_ep_free_request(fu->ep_status, stream->req_status);
-
-	stream->req_in = NULL;
-	stream->req_out = NULL;
-	stream->req_status = NULL;
-}
-
-static void uasp_free_cmdreq(struct f_uas *fu)
-{
-	usb_ep_free_request(fu->ep_cmd, fu->cmd.req);
-	kfree(fu->cmd.buf);
-	fu->cmd.req = NULL;
-	fu->cmd.buf = NULL;
-}
-
-static void uasp_cleanup_old_alt(struct f_uas *fu)
-{
-	int i;
-
-	if (!(fu->flags & USBG_ENABLED))
-		return;
-
-	usb_ep_disable(fu->ep_in);
-	usb_ep_disable(fu->ep_out);
-	usb_ep_disable(fu->ep_status);
-	usb_ep_disable(fu->ep_cmd);
-
-	for (i = 0; i < UASP_SS_EP_COMP_NUM_STREAMS; i++)
-		uasp_cleanup_one_stream(fu, &fu->stream[i]);
-	uasp_free_cmdreq(fu);
-}
-
-static void uasp_status_data_cmpl(struct usb_ep *ep, struct usb_request *req);
-
-static int uasp_prepare_r_request(struct usbg_cmd *cmd)
-{
-	struct se_cmd *se_cmd = &cmd->se_cmd;
-	struct f_uas *fu = cmd->fu;
-	struct usb_gadget *gadget = fuas_to_gadget(fu);
-	struct uas_stream *stream = cmd->stream;
-
-	if (!gadget->sg_supported) {
-		cmd->data_buf = kmalloc(se_cmd->data_length, GFP_ATOMIC);
-		if (!cmd->data_buf)
-			return -ENOMEM;
-
-		sg_copy_to_buffer(se_cmd->t_data_sg,
-				se_cmd->t_data_nents,
-				cmd->data_buf,
-				se_cmd->data_length);
-
-		stream->req_in->buf = cmd->data_buf;
-	} else {
-		stream->req_in->buf = NULL;
-		stream->req_in->num_sgs = se_cmd->t_data_nents;
-		stream->req_in->sg = se_cmd->t_data_sg;
-	}
-
-	stream->req_in->complete = uasp_status_data_cmpl;
-	stream->req_in->length = se_cmd->data_length;
-	stream->req_in->context = cmd;
-
-	cmd->state = UASP_SEND_STATUS;
-	return 0;
-}
-
-static void uasp_prepare_status(struct usbg_cmd *cmd)
-{
-	struct se_cmd *se_cmd = &cmd->se_cmd;
-	struct sense_iu *iu = &cmd->sense_iu;
-	struct uas_stream *stream = cmd->stream;
-
-	cmd->state = UASP_QUEUE_COMMAND;
-	iu->iu_id = IU_ID_STATUS;
-	iu->tag = cpu_to_be16(cmd->tag);
-
-	/*
-	 * iu->status_qual = cpu_to_be16(STATUS QUALIFIER SAM-4. Where R U?);
-	 */
-	iu->len = cpu_to_be16(se_cmd->scsi_sense_length);
-	iu->status = se_cmd->scsi_status;
-	stream->req_status->context = cmd;
-	stream->req_status->length = se_cmd->scsi_sense_length + 16;
-	stream->req_status->buf = iu;
-	stream->req_status->complete = uasp_status_data_cmpl;
-}
-
-static void uasp_status_data_cmpl(struct usb_ep *ep, struct usb_request *req)
-{
-	struct usbg_cmd *cmd = req->context;
-	struct uas_stream *stream = cmd->stream;
-	struct f_uas *fu = cmd->fu;
-	int ret;
-
-	if (req->status < 0)
-		goto cleanup;
-
-	switch (cmd->state) {
-	case UASP_SEND_DATA:
-		ret = uasp_prepare_r_request(cmd);
-		if (ret)
-			goto cleanup;
-		ret = usb_ep_queue(fu->ep_in, stream->req_in, GFP_ATOMIC);
-		if (ret)
-			pr_err("%s(%d) => %d\n", __func__, __LINE__, ret);
-		break;
-
-	case UASP_RECEIVE_DATA:
-		ret = usbg_prepare_w_request(cmd, stream->req_out);
-		if (ret)
-			goto cleanup;
-		ret = usb_ep_queue(fu->ep_out, stream->req_out, GFP_ATOMIC);
-		if (ret)
-			pr_err("%s(%d) => %d\n", __func__, __LINE__, ret);
-		break;
-
-	case UASP_SEND_STATUS:
-		uasp_prepare_status(cmd);
-		ret = usb_ep_queue(fu->ep_status, stream->req_status,
-				GFP_ATOMIC);
-		if (ret)
-			pr_err("%s(%d) => %d\n", __func__, __LINE__, ret);
-		break;
-
-	case UASP_QUEUE_COMMAND:
-		usbg_cleanup_cmd(cmd);
-		usb_ep_queue(fu->ep_cmd, fu->cmd.req, GFP_ATOMIC);
-		break;
-
-	default:
-		BUG();
-	};
-	return;
-
-cleanup:
-	usbg_cleanup_cmd(cmd);
-}
-
-static int uasp_send_status_response(struct usbg_cmd *cmd)
-{
-	struct f_uas *fu = cmd->fu;
-	struct uas_stream *stream = cmd->stream;
-	struct sense_iu *iu = &cmd->sense_iu;
-
-	iu->tag = cpu_to_be16(cmd->tag);
-	stream->req_status->complete = uasp_status_data_cmpl;
-	stream->req_status->context = cmd;
-	cmd->fu = fu;
-	uasp_prepare_status(cmd);
-	return usb_ep_queue(fu->ep_status, stream->req_status, GFP_ATOMIC);
-}
-
-static int uasp_send_read_response(struct usbg_cmd *cmd)
-{
-	struct f_uas *fu = cmd->fu;
-	struct uas_stream *stream = cmd->stream;
-	struct sense_iu *iu = &cmd->sense_iu;
-	int ret;
-
-	cmd->fu = fu;
-
-	iu->tag = cpu_to_be16(cmd->tag);
-	if (fu->flags & USBG_USE_STREAMS) {
-
-		ret = uasp_prepare_r_request(cmd);
-		if (ret)
-			goto out;
-		ret = usb_ep_queue(fu->ep_in, stream->req_in, GFP_ATOMIC);
-		if (ret) {
-			pr_err("%s(%d) => %d\n", __func__, __LINE__, ret);
-			kfree(cmd->data_buf);
-			cmd->data_buf = NULL;
-		}
-
-	} else {
-
-		iu->iu_id = IU_ID_READ_READY;
-		iu->tag = cpu_to_be16(cmd->tag);
-
-		stream->req_status->complete = uasp_status_data_cmpl;
-		stream->req_status->context = cmd;
-
-		cmd->state = UASP_SEND_DATA;
-		stream->req_status->buf = iu;
-		stream->req_status->length = sizeof(struct iu);
-
-		ret = usb_ep_queue(fu->ep_status, stream->req_status,
-				GFP_ATOMIC);
-		if (ret)
-			pr_err("%s(%d) => %d\n", __func__, __LINE__, ret);
-	}
-out:
-	return ret;
-}
-
-static int uasp_send_write_request(struct usbg_cmd *cmd)
-{
-	struct f_uas *fu = cmd->fu;
-	struct se_cmd *se_cmd = &cmd->se_cmd;
-	struct uas_stream *stream = cmd->stream;
-	struct sense_iu *iu = &cmd->sense_iu;
-	int ret;
-
-	init_completion(&cmd->write_complete);
-	cmd->fu = fu;
-
-	iu->tag = cpu_to_be16(cmd->tag);
-
-	if (fu->flags & USBG_USE_STREAMS) {
-
-		ret = usbg_prepare_w_request(cmd, stream->req_out);
-		if (ret)
-			goto cleanup;
-		ret = usb_ep_queue(fu->ep_out, stream->req_out, GFP_ATOMIC);
-		if (ret)
-			pr_err("%s(%d)\n", __func__, __LINE__);
-
-	} else {
-
-		iu->iu_id = IU_ID_WRITE_READY;
-		iu->tag = cpu_to_be16(cmd->tag);
-
-		stream->req_status->complete = uasp_status_data_cmpl;
-		stream->req_status->context = cmd;
-
-		cmd->state = UASP_RECEIVE_DATA;
-		stream->req_status->buf = iu;
-		stream->req_status->length = sizeof(struct iu);
-
-		ret = usb_ep_queue(fu->ep_status, stream->req_status,
-				GFP_ATOMIC);
-		if (ret)
-			pr_err("%s(%d)\n", __func__, __LINE__);
-	}
-
-	wait_for_completion(&cmd->write_complete);
-	transport_generic_process_write(se_cmd);
-cleanup:
-	return ret;
-}
-
-static int usbg_submit_command(struct f_uas *, void *, unsigned int);
-
-static void uasp_cmd_complete(struct usb_ep *ep, struct usb_request *req)
-{
-	struct f_uas *fu = req->context;
-	int ret;
-
-	if (req->status < 0)
-		return;
-
-	ret = usbg_submit_command(fu, req->buf, req->actual);
-	/*
-	 * Once we tune for performance enqueue the command req here again so
-	 * we can receive a second command while we processing this one. Pay
-	 * attention to properly sync STAUS endpoint with DATA IN + OUT so you
-	 * don't break HS.
-	 */
-	if (!ret)
-		return;
-	usb_ep_queue(fu->ep_cmd, fu->cmd.req, GFP_ATOMIC);
-}
-
-static int uasp_alloc_stream_res(struct f_uas *fu, struct uas_stream *stream)
-{
-	stream->req_in = usb_ep_alloc_request(fu->ep_in, GFP_KERNEL);
-	if (!stream->req_in)
-		goto out;
-
-	stream->req_out = usb_ep_alloc_request(fu->ep_out, GFP_KERNEL);
-	if (!stream->req_out)
-		goto err_out;
-
-	stream->req_status = usb_ep_alloc_request(fu->ep_status, GFP_KERNEL);
-	if (!stream->req_status)
-		goto err_sts;
-
-	return 0;
-err_sts:
-	usb_ep_free_request(fu->ep_status, stream->req_status);
-	stream->req_status = NULL;
-err_out:
-	usb_ep_free_request(fu->ep_out, stream->req_out);
-	stream->req_out = NULL;
-out:
-	return -ENOMEM;
-}
-
-static int uasp_alloc_cmd(struct f_uas *fu)
-{
-	fu->cmd.req = usb_ep_alloc_request(fu->ep_cmd, GFP_KERNEL);
-	if (!fu->cmd.req)
-		goto err;
-
-	fu->cmd.buf = kmalloc(fu->ep_cmd->maxpacket, GFP_KERNEL);
-	if (!fu->cmd.buf)
-		goto err_buf;
-
-	fu->cmd.req->complete = uasp_cmd_complete;
-	fu->cmd.req->buf = fu->cmd.buf;
-	fu->cmd.req->length = fu->ep_cmd->maxpacket;
-	fu->cmd.req->context = fu;
-	return 0;
-
-err_buf:
-	usb_ep_free_request(fu->ep_cmd, fu->cmd.req);
-err:
-	return -ENOMEM;
-}
-
-static void uasp_setup_stream_res(struct f_uas *fu, int max_streams)
-{
-	int i;
-
-	for (i = 0; i < max_streams; i++) {
-		struct uas_stream *s = &fu->stream[i];
-
-		s->req_in->stream_id = i + 1;
-		s->req_out->stream_id = i + 1;
-		s->req_status->stream_id = i + 1;
-	}
-}
-
-static int uasp_prepare_reqs(struct f_uas *fu)
-{
-	int ret;
-	int i;
-	int max_streams;
-
-	if (fu->flags & USBG_USE_STREAMS)
-		max_streams = UASP_SS_EP_COMP_NUM_STREAMS;
-	else
-		max_streams = 1;
-
-	for (i = 0; i < max_streams; i++) {
-		ret = uasp_alloc_stream_res(fu, &fu->stream[i]);
-		if (ret)
-			goto err_cleanup;
-	}
-
-	ret = uasp_alloc_cmd(fu);
-	if (ret)
-		goto err_free_stream;
-	uasp_setup_stream_res(fu, max_streams);
-
-	ret = usb_ep_queue(fu->ep_cmd, fu->cmd.req, GFP_ATOMIC);
-	if (ret)
-		goto err_free_stream;
-
-	return 0;
-
-err_free_stream:
-	uasp_free_cmdreq(fu);
-
-err_cleanup:
-	if (i) {
-		do {
-			uasp_cleanup_one_stream(fu, &fu->stream[i - 1]);
-			i--;
-		} while (i);
-	}
-	pr_err("UASP: endpoint setup failed\n");
-	return ret;
-}
-
-static void uasp_set_alt(struct f_uas *fu)
-{
-	struct usb_function *f = &fu->function;
-	struct usb_gadget *gadget = f->config->cdev->gadget;
-	int ret;
-
-	fu->flags = USBG_IS_UAS;
-
-	if (gadget->speed == USB_SPEED_SUPER)
-		fu->flags |= USBG_USE_STREAMS;
-
-	config_ep_by_speed(gadget, f, fu->ep_in);
-	ret = usb_ep_enable(fu->ep_in);
-	if (ret)
-		goto err_b_in;
-
-	config_ep_by_speed(gadget, f, fu->ep_out);
-	ret = usb_ep_enable(fu->ep_out);
-	if (ret)
-		goto err_b_out;
-
-	config_ep_by_speed(gadget, f, fu->ep_cmd);
-	ret = usb_ep_enable(fu->ep_cmd);
-	if (ret)
-		goto err_cmd;
-	config_ep_by_speed(gadget, f, fu->ep_status);
-	ret = usb_ep_enable(fu->ep_status);
-	if (ret)
-		goto err_status;
-
-	ret = uasp_prepare_reqs(fu);
-	if (ret)
-		goto err_wq;
-	fu->flags |= USBG_ENABLED;
-
-	pr_info("Using the UAS protocol\n");
-	return;
-err_wq:
-	usb_ep_disable(fu->ep_status);
-err_status:
-	usb_ep_disable(fu->ep_cmd);
-err_cmd:
-	usb_ep_disable(fu->ep_out);
-err_b_out:
-	usb_ep_disable(fu->ep_in);
-err_b_in:
-	fu->flags = 0;
-}
-
-static int get_cmd_dir(const unsigned char *cdb)
-{
-	int ret;
-
-	switch (cdb[0]) {
-	case READ_6:
-	case READ_10:
-	case READ_12:
-	case READ_16:
-	case INQUIRY:
-	case MODE_SENSE:
-	case MODE_SENSE_10:
-	case SERVICE_ACTION_IN:
-	case MAINTENANCE_IN:
-	case PERSISTENT_RESERVE_IN:
-	case SECURITY_PROTOCOL_IN:
-	case ACCESS_CONTROL_IN:
-	case REPORT_LUNS:
-	case READ_BLOCK_LIMITS:
-	case READ_POSITION:
-	case READ_CAPACITY:
-	case READ_TOC:
-	case READ_FORMAT_CAPACITIES:
-	case REQUEST_SENSE:
-		ret = DMA_FROM_DEVICE;
-		break;
-
-	case WRITE_6:
-	case WRITE_10:
-	case WRITE_12:
-	case WRITE_16:
-	case MODE_SELECT:
-	case MODE_SELECT_10:
-	case WRITE_VERIFY:
-	case WRITE_VERIFY_12:
-	case PERSISTENT_RESERVE_OUT:
-	case MAINTENANCE_OUT:
-	case SECURITY_PROTOCOL_OUT:
-	case ACCESS_CONTROL_OUT:
-		ret = DMA_TO_DEVICE;
-		break;
-	case ALLOW_MEDIUM_REMOVAL:
-	case TEST_UNIT_READY:
-	case SYNCHRONIZE_CACHE:
-	case START_STOP:
-	case ERASE:
-	case REZERO_UNIT:
-	case SEEK_10:
-	case SPACE:
-	case VERIFY:
-	case WRITE_FILEMARKS:
-		ret = DMA_NONE;
-		break;
-	default:
-		pr_warn("target: Unknown data direction for SCSI Opcode "
-				"0x%02x\n", cdb[0]);
-		ret = -EINVAL;
-	}
-	return ret;
-}
-
-static void usbg_data_write_cmpl(struct usb_ep *ep, struct usb_request *req)
-{
-	struct usbg_cmd *cmd = req->context;
-	struct se_cmd *se_cmd = &cmd->se_cmd;
-
-	if (req->status < 0) {
-		pr_err("%s() state %d transfer failed\n", __func__, cmd->state);
-		goto cleanup;
-	}
-
-	if (req->num_sgs == 0) {
-		sg_copy_from_buffer(se_cmd->t_data_sg,
-				se_cmd->t_data_nents,
-				cmd->data_buf,
-				se_cmd->data_length);
-	}
-
-	complete(&cmd->write_complete);
-	return;
-
-cleanup:
-	usbg_cleanup_cmd(cmd);
-}
-
-static int usbg_prepare_w_request(struct usbg_cmd *cmd, struct usb_request *req)
-{
-	struct se_cmd *se_cmd = &cmd->se_cmd;
-	struct f_uas *fu = cmd->fu;
-	struct usb_gadget *gadget = fuas_to_gadget(fu);
-
-	if (!gadget->sg_supported) {
-		cmd->data_buf = kmalloc(se_cmd->data_length, GFP_ATOMIC);
-		if (!cmd->data_buf)
-			return -ENOMEM;
-
-		req->buf = cmd->data_buf;
-	} else {
-		req->buf = NULL;
-		req->num_sgs = se_cmd->t_data_nents;
-		req->sg = se_cmd->t_data_sg;
-	}
-
-	req->complete = usbg_data_write_cmpl;
-	req->length = se_cmd->data_length;
-	req->context = cmd;
-	return 0;
-}
-
-static int usbg_send_status_response(struct se_cmd *se_cmd)
-{
-	struct usbg_cmd *cmd = container_of(se_cmd, struct usbg_cmd,
-			se_cmd);
-	struct f_uas *fu = cmd->fu;
-
-	if (fu->flags & USBG_IS_BOT)
-		return bot_send_status_response(cmd);
-	else
-		return uasp_send_status_response(cmd);
-}
-
-static int usbg_send_write_request(struct se_cmd *se_cmd)
-{
-	struct usbg_cmd *cmd = container_of(se_cmd, struct usbg_cmd,
-			se_cmd);
-	struct f_uas *fu = cmd->fu;
-
-	if (fu->flags & USBG_IS_BOT)
-		return bot_send_write_request(cmd);
-	else
-		return uasp_send_write_request(cmd);
-}
-
-static int usbg_send_read_response(struct se_cmd *se_cmd)
-{
-	struct usbg_cmd *cmd = container_of(se_cmd, struct usbg_cmd,
-			se_cmd);
-	struct f_uas *fu = cmd->fu;
-
-	if (fu->flags & USBG_IS_BOT)
-		return bot_send_read_response(cmd);
-	else
-		return uasp_send_read_response(cmd);
-}
-
-static void usbg_cmd_work(struct work_struct *work)
-{
-	struct usbg_cmd *cmd = container_of(work, struct usbg_cmd, work);
-	struct se_cmd *se_cmd;
-	struct tcm_usbg_nexus *tv_nexus;
-	struct usbg_tpg *tpg;
-	int dir;
-
-	se_cmd = &cmd->se_cmd;
-	tpg = cmd->fu->tpg;
-	tv_nexus = tpg->tpg_nexus;
-	dir = get_cmd_dir(cmd->cmd_buf);
-	if (dir < 0) {
-		transport_init_se_cmd(se_cmd,
-				tv_nexus->tvn_se_sess->se_tpg->se_tpg_tfo,
-				tv_nexus->tvn_se_sess, cmd->data_len, DMA_NONE,
-				cmd->prio_attr, cmd->sense_iu.sense);
-
-		transport_send_check_condition_and_sense(se_cmd,
-				TCM_UNSUPPORTED_SCSI_OPCODE, 1);
-		usbg_cleanup_cmd(cmd);
-		return;
-	}
-
-	target_submit_cmd(se_cmd, tv_nexus->tvn_se_sess,
-			cmd->cmd_buf, cmd->sense_iu.sense, cmd->unpacked_lun,
-			0, cmd->prio_attr, dir, TARGET_SCF_UNKNOWN_SIZE);
-}
-
-static int usbg_submit_command(struct f_uas *fu,
-		void *cmdbuf, unsigned int len)
-{
-	struct command_iu *cmd_iu = cmdbuf;
-	struct usbg_cmd *cmd;
-	struct usbg_tpg *tpg;
-	struct se_cmd *se_cmd;
-	struct tcm_usbg_nexus *tv_nexus;
-	u32 cmd_len;
-	int ret;
-
-	if (cmd_iu->iu_id != IU_ID_COMMAND) {
-		pr_err("Unsupported type %d\n", cmd_iu->iu_id);
-		return -EINVAL;
-	}
-
-	cmd = kzalloc(sizeof *cmd, GFP_ATOMIC);
-	if (!cmd)
-		return -ENOMEM;
-
-	cmd->fu = fu;
-
-	/* XXX until I figure out why I can't free in on complete */
-	kref_init(&cmd->ref);
-	kref_get(&cmd->ref);
-
-	tpg = fu->tpg;
-	cmd_len = (cmd_iu->len & ~0x3) + 16;
-	if (cmd_len > USBG_MAX_CMD)
-		goto err;
-
-	memcpy(cmd->cmd_buf, cmd_iu->cdb, cmd_len);
-
-	cmd->tag = be16_to_cpup(&cmd_iu->tag);
-	if (fu->flags & USBG_USE_STREAMS) {
-		if (cmd->tag > UASP_SS_EP_COMP_NUM_STREAMS)
-			goto err;
-		if (!cmd->tag)
-			cmd->stream = &fu->stream[0];
-		else
-			cmd->stream = &fu->stream[cmd->tag - 1];
-	} else {
-		cmd->stream = &fu->stream[0];
-	}
-
-	tv_nexus = tpg->tpg_nexus;
-	if (!tv_nexus) {
-		pr_err("Missing nexus, ignoring command\n");
-		goto err;
-	}
-
-	switch (cmd_iu->prio_attr & 0x7) {
-	case UAS_HEAD_TAG:
-		cmd->prio_attr = MSG_HEAD_TAG;
-		break;
-	case UAS_ORDERED_TAG:
-		cmd->prio_attr = MSG_ORDERED_TAG;
-		break;
-	case UAS_ACA:
-		cmd->prio_attr = MSG_ACA_TAG;
-		break;
-	default:
-		pr_debug_once("Unsupported prio_attr: %02x.\n",
-				cmd_iu->prio_attr);
-	case UAS_SIMPLE_TAG:
-		cmd->prio_attr = MSG_SIMPLE_TAG;
-		break;
-	}
-
-	se_cmd = &cmd->se_cmd;
-	cmd->unpacked_lun = scsilun_to_int(&cmd_iu->lun);
-
-	INIT_WORK(&cmd->work, usbg_cmd_work);
-	ret = queue_work(tpg->workqueue, &cmd->work);
-	if (ret < 0)
-		goto err;
-
-	return 0;
-err:
-	kfree(cmd);
-	return -EINVAL;
-}
-
-static void bot_cmd_work(struct work_struct *work)
-{
-	struct usbg_cmd *cmd = container_of(work, struct usbg_cmd, work);
-	struct se_cmd *se_cmd;
-	struct tcm_usbg_nexus *tv_nexus;
-	struct usbg_tpg *tpg;
-	int dir;
-
-	se_cmd = &cmd->se_cmd;
-	tpg = cmd->fu->tpg;
-	tv_nexus = tpg->tpg_nexus;
-	dir = get_cmd_dir(cmd->cmd_buf);
-	if (dir < 0) {
-		transport_init_se_cmd(se_cmd,
-				tv_nexus->tvn_se_sess->se_tpg->se_tpg_tfo,
-				tv_nexus->tvn_se_sess, cmd->data_len, DMA_NONE,
-				cmd->prio_attr, cmd->sense_iu.sense);
-
-		transport_send_check_condition_and_sense(se_cmd,
-				TCM_UNSUPPORTED_SCSI_OPCODE, 1);
-		usbg_cleanup_cmd(cmd);
-		return;
-	}
-
-	target_submit_cmd(se_cmd, tv_nexus->tvn_se_sess,
-			cmd->cmd_buf, cmd->sense_iu.sense, cmd->unpacked_lun,
-			cmd->data_len, cmd->prio_attr, dir, 0);
-}
-
-static int bot_submit_command(struct f_uas *fu,
-		void *cmdbuf, unsigned int len)
-{
-	struct bulk_cb_wrap *cbw = cmdbuf;
-	struct usbg_cmd *cmd;
-	struct usbg_tpg *tpg;
-	struct se_cmd *se_cmd;
-	struct tcm_usbg_nexus *tv_nexus;
-	u32 cmd_len;
-	int ret;
-
-	if (cbw->Signature != cpu_to_le32(US_BULK_CB_SIGN)) {
-		pr_err("Wrong signature on CBW\n");
-		return -EINVAL;
-	}
-	if (len != 31) {
-		pr_err("Wrong length for CBW\n");
-		return -EINVAL;
-	}
-
-	cmd_len = cbw->Length;
-	if (cmd_len < 1 || cmd_len > 16)
-		return -EINVAL;
-
-	cmd = kzalloc(sizeof *cmd, GFP_ATOMIC);
-	if (!cmd)
-		return -ENOMEM;
-
-	cmd->fu = fu;
-
-	/* XXX until I figure out why I can't free in on complete */
-	kref_init(&cmd->ref);
-	kref_get(&cmd->ref);
-
-	tpg = fu->tpg;
-
-	memcpy(cmd->cmd_buf, cbw->CDB, cmd_len);
-
-	cmd->bot_tag = cbw->Tag;
-
-	tv_nexus = tpg->tpg_nexus;
-	if (!tv_nexus) {
-		pr_err("Missing nexus, ignoring command\n");
-		goto err;
-	}
-
-	cmd->prio_attr = MSG_SIMPLE_TAG;
-	se_cmd = &cmd->se_cmd;
-	cmd->unpacked_lun = cbw->Lun;
-	cmd->is_read = cbw->Flags & US_BULK_FLAG_IN ? 1 : 0;
-	cmd->data_len = le32_to_cpu(cbw->DataTransferLength);
-
-	INIT_WORK(&cmd->work, bot_cmd_work);
-	ret = queue_work(tpg->workqueue, &cmd->work);
-	if (ret < 0)
-		goto err;
-
-	return 0;
-err:
-	kfree(cmd);
-	return -EINVAL;
-}
-
-/* Start fabric.c code */
-
-static int usbg_check_true(struct se_portal_group *se_tpg)
-{
-	return 1;
-}
-
-static int usbg_check_false(struct se_portal_group *se_tpg)
-{
-	return 0;
-}
-
-static char *usbg_get_fabric_name(void)
-{
-	return "usb_gadget";
-}
-
-static u8 usbg_get_fabric_proto_ident(struct se_portal_group *se_tpg)
-{
-	struct usbg_tpg *tpg = container_of(se_tpg,
-				struct usbg_tpg, se_tpg);
-	struct usbg_tport *tport = tpg->tport;
-	u8 proto_id;
-
-	switch (tport->tport_proto_id) {
-	case SCSI_PROTOCOL_SAS:
-	default:
-		proto_id = sas_get_fabric_proto_ident(se_tpg);
-		break;
-	}
-
-	return proto_id;
-}
-
-static char *usbg_get_fabric_wwn(struct se_portal_group *se_tpg)
-{
-	struct usbg_tpg *tpg = container_of(se_tpg,
-				struct usbg_tpg, se_tpg);
-	struct usbg_tport *tport = tpg->tport;
-
-	return &tport->tport_name[0];
-}
-
-static u16 usbg_get_tag(struct se_portal_group *se_tpg)
-{
-	struct usbg_tpg *tpg = container_of(se_tpg,
-				struct usbg_tpg, se_tpg);
-	return tpg->tport_tpgt;
-}
-
-static u32 usbg_get_default_depth(struct se_portal_group *se_tpg)
-{
-	return 1;
-}
-
-static u32 usbg_get_pr_transport_id(
-	struct se_portal_group *se_tpg,
-	struct se_node_acl *se_nacl,
-	struct t10_pr_registration *pr_reg,
-	int *format_code,
-	unsigned char *buf)
-{
-	struct usbg_tpg *tpg = container_of(se_tpg,
-				struct usbg_tpg, se_tpg);
-	struct usbg_tport *tport = tpg->tport;
-	int ret = 0;
-
-	switch (tport->tport_proto_id) {
-	case SCSI_PROTOCOL_SAS:
-	default:
-		ret = sas_get_pr_transport_id(se_tpg, se_nacl, pr_reg,
-					format_code, buf);
-		break;
-	}
-
-	return ret;
-}
-
-static u32 usbg_get_pr_transport_id_len(
-	struct se_portal_group *se_tpg,
-	struct se_node_acl *se_nacl,
-	struct t10_pr_registration *pr_reg,
-	int *format_code)
-{
-	struct usbg_tpg *tpg = container_of(se_tpg,
-				struct usbg_tpg, se_tpg);
-	struct usbg_tport *tport = tpg->tport;
-	int ret = 0;
-
-	switch (tport->tport_proto_id) {
-	case SCSI_PROTOCOL_SAS:
-	default:
-		ret = sas_get_pr_transport_id_len(se_tpg, se_nacl, pr_reg,
-					format_code);
-		break;
-	}
-
-	return ret;
-}
-
-static char *usbg_parse_pr_out_transport_id(
-	struct se_portal_group *se_tpg,
-	const char *buf,
-	u32 *out_tid_len,
-	char **port_nexus_ptr)
-{
-	struct usbg_tpg *tpg = container_of(se_tpg,
-				struct usbg_tpg, se_tpg);
-	struct usbg_tport *tport = tpg->tport;
-	char *tid = NULL;
-
-	switch (tport->tport_proto_id) {
-	case SCSI_PROTOCOL_SAS:
-	default:
-		tid = sas_parse_pr_out_transport_id(se_tpg, buf, out_tid_len,
-					port_nexus_ptr);
-	}
-
-	return tid;
-}
-
-static struct se_node_acl *usbg_alloc_fabric_acl(struct se_portal_group *se_tpg)
-{
-	struct usbg_nacl *nacl;
-
-	nacl = kzalloc(sizeof(struct usbg_nacl), GFP_KERNEL);
-	if (!nacl) {
-		printk(KERN_ERR "Unable to alocate struct usbg_nacl\n");
-		return NULL;
-	}
-
-	return &nacl->se_node_acl;
-}
-
-static void usbg_release_fabric_acl(
-	struct se_portal_group *se_tpg,
-	struct se_node_acl *se_nacl)
-{
-	struct usbg_nacl *nacl = container_of(se_nacl,
-			struct usbg_nacl, se_node_acl);
-	kfree(nacl);
-}
-
-static u32 usbg_tpg_get_inst_index(struct se_portal_group *se_tpg)
-{
-	return 1;
-}
-
-static int usbg_new_cmd(struct se_cmd *se_cmd)
-{
-	struct usbg_cmd *cmd = container_of(se_cmd, struct usbg_cmd,
-			se_cmd);
-	int ret;
-
-	ret = target_setup_cmd_from_cdb(se_cmd, cmd->cmd_buf);
-	if (ret)
-		return ret;
-
-	return transport_generic_map_mem_to_cmd(se_cmd, NULL, 0, NULL, 0);
-}
-
-static void usbg_cmd_release(struct kref *ref)
-{
-	struct usbg_cmd *cmd = container_of(ref, struct usbg_cmd,
-			ref);
-
-	transport_generic_free_cmd(&cmd->se_cmd, 0);
-}
-
-static void usbg_release_cmd(struct se_cmd *se_cmd)
-{
-	struct usbg_cmd *cmd = container_of(se_cmd, struct usbg_cmd,
-			se_cmd);
-	kfree(cmd->data_buf);
-	kfree(cmd);
-	return;
-}
-
-static int usbg_shutdown_session(struct se_session *se_sess)
-{
-	return 0;
-}
-
-static void usbg_close_session(struct se_session *se_sess)
-{
-	return;
-}
-
-static u32 usbg_sess_get_index(struct se_session *se_sess)
-{
-	return 0;
-}
-
-/*
- * XXX Error recovery: return != 0 if we expect writes. Dunno when that could be
- */
-static int usbg_write_pending_status(struct se_cmd *se_cmd)
-{
-	return 0;
-}
-
-static void usbg_set_default_node_attrs(struct se_node_acl *nacl)
-{
-	return;
-}
-
-static u32 usbg_get_task_tag(struct se_cmd *se_cmd)
-{
-	struct usbg_cmd *cmd = container_of(se_cmd, struct usbg_cmd,
-			se_cmd);
-	struct f_uas *fu = cmd->fu;
-
-	if (fu->flags & USBG_IS_BOT)
-		return le32_to_cpu(cmd->bot_tag);
-	else
-		return cmd->tag;
-}
-
-static int usbg_get_cmd_state(struct se_cmd *se_cmd)
-{
-	return 0;
-}
-
-static int usbg_queue_tm_rsp(struct se_cmd *se_cmd)
-{
-	return 0;
-}
-
-static u16 usbg_set_fabric_sense_len(struct se_cmd *se_cmd, u32 sense_length)
-{
-	return 0;
-}
-
-static u16 usbg_get_fabric_sense_len(void)
-{
-	return 0;
-}
-
-static const char *usbg_check_wwn(const char *name)
-{
-	const char *n;
-	unsigned int len;
-
-	n = strstr(name, "naa.");
-	if (!n)
-		return NULL;
-	n += 4;
-	len = strlen(n);
-	if (len == 0 || len > USBG_NAMELEN - 1)
-		return NULL;
-	return n;
-}
-
-static struct se_node_acl *usbg_make_nodeacl(
-	struct se_portal_group *se_tpg,
-	struct config_group *group,
-	const char *name)
-{
-	struct se_node_acl *se_nacl, *se_nacl_new;
-	struct usbg_nacl *nacl;
-	u64 wwpn = 0;
-	u32 nexus_depth;
-	const char *wnn_name;
-
-	wnn_name = usbg_check_wwn(name);
-	if (!wnn_name)
-		return ERR_PTR(-EINVAL);
-	se_nacl_new = usbg_alloc_fabric_acl(se_tpg);
-	if (!(se_nacl_new))
-		return ERR_PTR(-ENOMEM);
-
-	nexus_depth = 1;
-	/*
-	 * se_nacl_new may be released by core_tpg_add_initiator_node_acl()
-	 * when converting a NodeACL from demo mode -> explict
-	 */
-	se_nacl = core_tpg_add_initiator_node_acl(se_tpg, se_nacl_new,
-				name, nexus_depth);
-	if (IS_ERR(se_nacl)) {
-		usbg_release_fabric_acl(se_tpg, se_nacl_new);
-		return se_nacl;
-	}
-	/*
-	 * Locate our struct usbg_nacl and set the FC Nport WWPN
-	 */
-	nacl = container_of(se_nacl, struct usbg_nacl, se_node_acl);
-	nacl->iport_wwpn = wwpn;
-	snprintf(nacl->iport_name, sizeof(nacl->iport_name), "%s", name);
-	return se_nacl;
-}
-
-static void usbg_drop_nodeacl(struct se_node_acl *se_acl)
-{
-	struct usbg_nacl *nacl = container_of(se_acl,
-				struct usbg_nacl, se_node_acl);
-	core_tpg_del_initiator_node_acl(se_acl->se_tpg, se_acl, 1);
-	kfree(nacl);
-}
-
-struct usbg_tpg *the_only_tpg_I_currently_have;
-
-static struct se_portal_group *usbg_make_tpg(
-	struct se_wwn *wwn,
-	struct config_group *group,
-	const char *name)
-{
-	struct usbg_tport *tport = container_of(wwn, struct usbg_tport,
-			tport_wwn);
-	struct usbg_tpg *tpg;
-	unsigned long tpgt;
-	int ret;
-
-	if (strstr(name, "tpgt_") != name)
-		return ERR_PTR(-EINVAL);
-	if (kstrtoul(name + 5, 0, &tpgt) || tpgt > UINT_MAX)
-		return ERR_PTR(-EINVAL);
-	if (the_only_tpg_I_currently_have) {
-		pr_err("Until the gadget framework can't handle multiple\n");
-		pr_err("gadgets, you can't do this here.\n");
-		return ERR_PTR(-EBUSY);
-	}
-
-	tpg = kzalloc(sizeof(struct usbg_tpg), GFP_KERNEL);
-	if (!tpg) {
-		printk(KERN_ERR "Unable to allocate struct usbg_tpg");
-		return ERR_PTR(-ENOMEM);
-	}
-	mutex_init(&tpg->tpg_mutex);
-	atomic_set(&tpg->tpg_port_count, 0);
-	tpg->workqueue = alloc_workqueue("tcm_usb_gadget", 0, 1);
-	if (!tpg->workqueue) {
-		kfree(tpg);
-		return NULL;
-	}
-
-	tpg->tport = tport;
-	tpg->tport_tpgt = tpgt;
-
-	ret = core_tpg_register(&usbg_fabric_configfs->tf_ops, wwn,
-				&tpg->se_tpg, tpg,
-				TRANSPORT_TPG_TYPE_NORMAL);
-	if (ret < 0) {
-		destroy_workqueue(tpg->workqueue);
-		kfree(tpg);
-		return NULL;
-	}
-	the_only_tpg_I_currently_have = tpg;
-	return &tpg->se_tpg;
-}
-
-static void usbg_drop_tpg(struct se_portal_group *se_tpg)
-{
-	struct usbg_tpg *tpg = container_of(se_tpg,
-				struct usbg_tpg, se_tpg);
-
-	core_tpg_deregister(se_tpg);
-	destroy_workqueue(tpg->workqueue);
-	kfree(tpg);
-	the_only_tpg_I_currently_have = NULL;
-}
-
-static struct se_wwn *usbg_make_tport(
-	struct target_fabric_configfs *tf,
-	struct config_group *group,
-	const char *name)
-{
-	struct usbg_tport *tport;
-	const char *wnn_name;
-	u64 wwpn = 0;
-
-	wnn_name = usbg_check_wwn(name);
-	if (!wnn_name)
-		return ERR_PTR(-EINVAL);
-
-	tport = kzalloc(sizeof(struct usbg_tport), GFP_KERNEL);
-	if (!(tport)) {
-		printk(KERN_ERR "Unable to allocate struct usbg_tport");
-		return ERR_PTR(-ENOMEM);
-	}
-	tport->tport_wwpn = wwpn;
-	snprintf(tport->tport_name, sizeof(tport->tport_name), wnn_name);
-	return &tport->tport_wwn;
-}
-
-static void usbg_drop_tport(struct se_wwn *wwn)
-{
-	struct usbg_tport *tport = container_of(wwn,
-				struct usbg_tport, tport_wwn);
-	kfree(tport);
-}
-
-/*
- * If somebody feels like dropping the version property, go ahead.
- */
-static ssize_t usbg_wwn_show_attr_version(
-	struct target_fabric_configfs *tf,
-	char *page)
-{
-	return sprintf(page, "usb-gadget fabric module\n");
-}
-TF_WWN_ATTR_RO(usbg, version);
-
-static struct configfs_attribute *usbg_wwn_attrs[] = {
-	&usbg_wwn_version.attr,
-	NULL,
-};
-
-static ssize_t tcm_usbg_tpg_show_enable(
-		struct se_portal_group *se_tpg,
-		char *page)
-{
-	struct usbg_tpg  *tpg = container_of(se_tpg, struct usbg_tpg, se_tpg);
-
-	return snprintf(page, PAGE_SIZE, "%u\n", tpg->gadget_connect);
-}
-
-static int usbg_attach(struct usbg_tpg *);
-static void usbg_detach(struct usbg_tpg *);
-
-static ssize_t tcm_usbg_tpg_store_enable(
-		struct se_portal_group *se_tpg,
-		const char *page,
-		size_t count)
-{
-	struct usbg_tpg  *tpg = container_of(se_tpg, struct usbg_tpg, se_tpg);
-	unsigned long op;
-	ssize_t ret;
-
-	ret = kstrtoul(page, 0, &op);
-	if (ret < 0)
-		return -EINVAL;
-	if (op > 1)
-		return -EINVAL;
-
-	if (op && tpg->gadget_connect)
-		goto out;
-	if (!op && !tpg->gadget_connect)
-		goto out;
-
-	if (op) {
-		ret = usbg_attach(tpg);
-		if (ret)
-			goto out;
-	} else {
-		usbg_detach(tpg);
-	}
-	tpg->gadget_connect = op;
-out:
-	return count;
-}
-TF_TPG_BASE_ATTR(tcm_usbg, enable, S_IRUGO | S_IWUSR);
-
-static ssize_t tcm_usbg_tpg_show_nexus(
-		struct se_portal_group *se_tpg,
-		char *page)
-{
-	struct usbg_tpg *tpg = container_of(se_tpg, struct usbg_tpg, se_tpg);
-	struct tcm_usbg_nexus *tv_nexus;
-	ssize_t ret;
-
-	mutex_lock(&tpg->tpg_mutex);
-	tv_nexus = tpg->tpg_nexus;
-	if (!tv_nexus) {
-		ret = -ENODEV;
-		goto out;
-	}
-	ret = snprintf(page, PAGE_SIZE, "%s\n",
-			tv_nexus->tvn_se_sess->se_node_acl->initiatorname);
-out:
-	mutex_unlock(&tpg->tpg_mutex);
-	return ret;
-}
-
-static int tcm_usbg_make_nexus(struct usbg_tpg *tpg, char *name)
-{
-	struct se_portal_group *se_tpg;
-	struct tcm_usbg_nexus *tv_nexus;
-	int ret;
-
-	mutex_lock(&tpg->tpg_mutex);
-	if (tpg->tpg_nexus) {
-		ret = -EEXIST;
-		pr_debug("tpg->tpg_nexus already exists\n");
-		goto err_unlock;
-	}
-	se_tpg = &tpg->se_tpg;
-
-	ret = -ENOMEM;
-	tv_nexus = kzalloc(sizeof(*tv_nexus), GFP_KERNEL);
-	if (!tv_nexus) {
-		pr_err("Unable to allocate struct tcm_vhost_nexus\n");
-		goto err_unlock;
-	}
-	tv_nexus->tvn_se_sess = transport_init_session();
-	if (IS_ERR(tv_nexus->tvn_se_sess))
-		goto err_free;
-
-	/*
-	 * Since we are running in 'demo mode' this call with generate a
-	 * struct se_node_acl for the tcm_vhost struct se_portal_group with
-	 * the SCSI Initiator port name of the passed configfs group 'name'.
-	 */
-	tv_nexus->tvn_se_sess->se_node_acl = core_tpg_check_initiator_node_acl(
-			se_tpg, name);
-	if (!tv_nexus->tvn_se_sess->se_node_acl) {
-		pr_debug("core_tpg_check_initiator_node_acl() failed"
-				" for %s\n", name);
-		goto err_session;
-	}
-	/*
-	 * Now register the TCM vHost virtual I_T Nexus as active with the
-	 * call to __transport_register_session()
-	 */
-	__transport_register_session(se_tpg, tv_nexus->tvn_se_sess->se_node_acl,
-			tv_nexus->tvn_se_sess, tv_nexus);
-	tpg->tpg_nexus = tv_nexus;
-	mutex_unlock(&tpg->tpg_mutex);
-	return 0;
-
-err_session:
-	transport_free_session(tv_nexus->tvn_se_sess);
-err_free:
-	kfree(tv_nexus);
-err_unlock:
-	mutex_unlock(&tpg->tpg_mutex);
-	return ret;
-}
-
-static int tcm_usbg_drop_nexus(struct usbg_tpg *tpg)
-{
-	struct se_session *se_sess;
-	struct tcm_usbg_nexus *tv_nexus;
-	int ret = -ENODEV;
-
-	mutex_lock(&tpg->tpg_mutex);
-	tv_nexus = tpg->tpg_nexus;
-	if (!tv_nexus)
-		goto out;
-
-	se_sess = tv_nexus->tvn_se_sess;
-	if (!se_sess)
-		goto out;
-
-	if (atomic_read(&tpg->tpg_port_count)) {
-		ret = -EPERM;
-		pr_err("Unable to remove Host I_T Nexus with"
-				" active TPG port count: %d\n",
-				atomic_read(&tpg->tpg_port_count));
-		goto out;
-	}
-
-	pr_debug("Removing I_T Nexus to Initiator Port: %s\n",
-			tv_nexus->tvn_se_sess->se_node_acl->initiatorname);
-	/*
-	 * Release the SCSI I_T Nexus to the emulated vHost Target Port
-	 */
-	transport_deregister_session(tv_nexus->tvn_se_sess);
-	tpg->tpg_nexus = NULL;
-
-	kfree(tv_nexus);
-out:
-	mutex_unlock(&tpg->tpg_mutex);
-	return 0;
-}
-
-static ssize_t tcm_usbg_tpg_store_nexus(
-		struct se_portal_group *se_tpg,
-		const char *page,
-		size_t count)
-{
-	struct usbg_tpg *tpg = container_of(se_tpg, struct usbg_tpg, se_tpg);
-	unsigned char i_port[USBG_NAMELEN], *ptr;
-	int ret;
-
-	if (!strncmp(page, "NULL", 4)) {
-		ret = tcm_usbg_drop_nexus(tpg);
-		return (!ret) ? count : ret;
-	}
-	if (strlen(page) > USBG_NAMELEN) {
-		pr_err("Emulated NAA Sas Address: %s, exceeds"
-				" max: %d\n", page, USBG_NAMELEN);
-		return -EINVAL;
-	}
-	snprintf(i_port, USBG_NAMELEN, "%s", page);
-
-	ptr = strstr(i_port, "naa.");
-	if (!ptr) {
-		pr_err("Missing 'naa.' prefix\n");
-		return -EINVAL;
-	}
-
-	if (i_port[strlen(i_port) - 1] == '\n')
-		i_port[strlen(i_port) - 1] = '\0';
-
-	ret = tcm_usbg_make_nexus(tpg, &i_port[4]);
-	if (ret < 0)
-		return ret;
-	return count;
-}
-TF_TPG_BASE_ATTR(tcm_usbg, nexus, S_IRUGO | S_IWUSR);
-
-static struct configfs_attribute *usbg_base_attrs[] = {
-	&tcm_usbg_tpg_enable.attr,
-	&tcm_usbg_tpg_nexus.attr,
-	NULL,
-};
-
-static int usbg_port_link(struct se_portal_group *se_tpg, struct se_lun *lun)
-{
-	struct usbg_tpg *tpg = container_of(se_tpg, struct usbg_tpg, se_tpg);
-
-	atomic_inc(&tpg->tpg_port_count);
-	smp_mb__after_atomic_inc();
-	return 0;
-}
-
-static void usbg_port_unlink(struct se_portal_group *se_tpg,
-		struct se_lun *se_lun)
-{
-	struct usbg_tpg *tpg = container_of(se_tpg, struct usbg_tpg, se_tpg);
-
-	atomic_dec(&tpg->tpg_port_count);
-	smp_mb__after_atomic_dec();
-}
-
-static int usbg_check_stop_free(struct se_cmd *se_cmd)
-{
-	struct usbg_cmd *cmd = container_of(se_cmd, struct usbg_cmd,
-			se_cmd);
-
-	kref_put(&cmd->ref, usbg_cmd_release);
-	return 1;
-}
-
-static struct target_core_fabric_ops usbg_ops = {
-	.get_fabric_name		= usbg_get_fabric_name,
-	.get_fabric_proto_ident		= usbg_get_fabric_proto_ident,
-	.tpg_get_wwn			= usbg_get_fabric_wwn,
-	.tpg_get_tag			= usbg_get_tag,
-	.tpg_get_default_depth		= usbg_get_default_depth,
-	.tpg_get_pr_transport_id	= usbg_get_pr_transport_id,
-	.tpg_get_pr_transport_id_len	= usbg_get_pr_transport_id_len,
-	.tpg_parse_pr_out_transport_id	= usbg_parse_pr_out_transport_id,
-	.tpg_check_demo_mode		= usbg_check_true,
-	.tpg_check_demo_mode_cache	= usbg_check_false,
-	.tpg_check_demo_mode_write_protect = usbg_check_false,
-	.tpg_check_prod_mode_write_protect = usbg_check_false,
-	.tpg_alloc_fabric_acl		= usbg_alloc_fabric_acl,
-	.tpg_release_fabric_acl		= usbg_release_fabric_acl,
-	.tpg_get_inst_index		= usbg_tpg_get_inst_index,
-	.new_cmd_map			= usbg_new_cmd,
-	.release_cmd			= usbg_release_cmd,
-	.shutdown_session		= usbg_shutdown_session,
-	.close_session			= usbg_close_session,
-	.sess_get_index			= usbg_sess_get_index,
-	.sess_get_initiator_sid		= NULL,
-	.write_pending			= usbg_send_write_request,
-	.write_pending_status		= usbg_write_pending_status,
-	.set_default_node_attributes	= usbg_set_default_node_attrs,
-	.get_task_tag			= usbg_get_task_tag,
-	.get_cmd_state			= usbg_get_cmd_state,
-	.queue_data_in			= usbg_send_read_response,
-	.queue_status			= usbg_send_status_response,
-	.queue_tm_rsp			= usbg_queue_tm_rsp,
-	.get_fabric_sense_len		= usbg_get_fabric_sense_len,
-	.set_fabric_sense_len		= usbg_set_fabric_sense_len,
-	.check_stop_free		= usbg_check_stop_free,
-
-	.fabric_make_wwn		= usbg_make_tport,
-	.fabric_drop_wwn		= usbg_drop_tport,
-	.fabric_make_tpg		= usbg_make_tpg,
-	.fabric_drop_tpg		= usbg_drop_tpg,
-	.fabric_post_link		= usbg_port_link,
-	.fabric_pre_unlink		= usbg_port_unlink,
-	.fabric_make_np			= NULL,
-	.fabric_drop_np			= NULL,
-	.fabric_make_nodeacl		= usbg_make_nodeacl,
-	.fabric_drop_nodeacl		= usbg_drop_nodeacl,
-};
-
-static int usbg_register_configfs(void)
-{
-	struct target_fabric_configfs *fabric;
-	int ret;
-
-	fabric = target_fabric_configfs_init(THIS_MODULE, "usb_gadget");
-	if (IS_ERR(fabric)) {
-		printk(KERN_ERR "target_fabric_configfs_init() failed\n");
-		return PTR_ERR(fabric);
-	}
-
-	fabric->tf_ops = usbg_ops;
-	TF_CIT_TMPL(fabric)->tfc_wwn_cit.ct_attrs = usbg_wwn_attrs;
-	TF_CIT_TMPL(fabric)->tfc_tpg_base_cit.ct_attrs = usbg_base_attrs;
-	TF_CIT_TMPL(fabric)->tfc_tpg_attrib_cit.ct_attrs = NULL;
-	TF_CIT_TMPL(fabric)->tfc_tpg_param_cit.ct_attrs = NULL;
-	TF_CIT_TMPL(fabric)->tfc_tpg_np_base_cit.ct_attrs = NULL;
-	TF_CIT_TMPL(fabric)->tfc_tpg_nacl_base_cit.ct_attrs = NULL;
-	TF_CIT_TMPL(fabric)->tfc_tpg_nacl_attrib_cit.ct_attrs = NULL;
-	TF_CIT_TMPL(fabric)->tfc_tpg_nacl_auth_cit.ct_attrs = NULL;
-	TF_CIT_TMPL(fabric)->tfc_tpg_nacl_param_cit.ct_attrs = NULL;
-	ret = target_fabric_configfs_register(fabric);
-	if (ret < 0) {
-		printk(KERN_ERR "target_fabric_configfs_register() failed"
-				" for usb-gadget\n");
-		return ret;
-	}
-	usbg_fabric_configfs = fabric;
-	return 0;
-};
-
-static void usbg_deregister_configfs(void)
-{
-	if (!(usbg_fabric_configfs))
-		return;
-
-	target_fabric_configfs_deregister(usbg_fabric_configfs);
-	usbg_fabric_configfs = NULL;
-};
-
-/* Start gadget.c code */
-
-static struct usb_interface_descriptor bot_intf_desc = {
-	.bLength =              sizeof(bot_intf_desc),
-	.bDescriptorType =      USB_DT_INTERFACE,
-	.bAlternateSetting =	0,
-	.bNumEndpoints =        2,
-	.bAlternateSetting =	USB_G_ALT_INT_BBB,
-	.bInterfaceClass =      USB_CLASS_MASS_STORAGE,
-	.bInterfaceSubClass =   USB_SC_SCSI,
-	.bInterfaceProtocol =   USB_PR_BULK,
-	.iInterface =           USB_G_STR_INT_UAS,
-};
-
-static struct usb_interface_descriptor uasp_intf_desc = {
-	.bLength =		sizeof(uasp_intf_desc),
-	.bDescriptorType =	USB_DT_INTERFACE,
-	.bNumEndpoints =	4,
-	.bAlternateSetting =	USB_G_ALT_INT_UAS,
-	.bInterfaceClass =	USB_CLASS_MASS_STORAGE,
-	.bInterfaceSubClass =	USB_SC_SCSI,
-	.bInterfaceProtocol =	USB_PR_UAS,
-	.iInterface =		USB_G_STR_INT_BBB,
-};
-
-static struct usb_endpoint_descriptor uasp_bi_desc = {
-	.bLength =		USB_DT_ENDPOINT_SIZE,
-	.bDescriptorType =	USB_DT_ENDPOINT,
-	.bEndpointAddress =	USB_DIR_IN,
-	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
-	.wMaxPacketSize =	cpu_to_le16(512),
-};
-
-static struct usb_endpoint_descriptor uasp_fs_bi_desc = {
-	.bLength =		USB_DT_ENDPOINT_SIZE,
-	.bDescriptorType =	USB_DT_ENDPOINT,
-	.bEndpointAddress =	USB_DIR_IN,
-	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
-};
-
-static struct usb_pipe_usage_descriptor uasp_bi_pipe_desc = {
-	.bLength =		sizeof(uasp_bi_pipe_desc),
-	.bDescriptorType =	USB_DT_PIPE_USAGE,
-	.bPipeID =		DATA_IN_PIPE_ID,
-};
-
-static struct usb_endpoint_descriptor uasp_ss_bi_desc = {
-	.bLength =		USB_DT_ENDPOINT_SIZE,
-	.bDescriptorType =	USB_DT_ENDPOINT,
-	.bEndpointAddress =	USB_DIR_IN,
-	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
-	.wMaxPacketSize =	cpu_to_le16(1024),
-};
-
-static struct usb_ss_ep_comp_descriptor uasp_bi_ep_comp_desc = {
-	.bLength =		sizeof(uasp_bi_ep_comp_desc),
-	.bDescriptorType =	USB_DT_SS_ENDPOINT_COMP,
-	.bMaxBurst =		0,
-	.bmAttributes =		UASP_SS_EP_COMP_LOG_STREAMS,
-	.wBytesPerInterval =	0,
-};
-
-static struct usb_ss_ep_comp_descriptor bot_bi_ep_comp_desc = {
-	.bLength =		sizeof(bot_bi_ep_comp_desc),
-	.bDescriptorType =	USB_DT_SS_ENDPOINT_COMP,
-	.bMaxBurst =		0,
-};
-
-static struct usb_endpoint_descriptor uasp_bo_desc = {
-	.bLength =		USB_DT_ENDPOINT_SIZE,
-	.bDescriptorType =	USB_DT_ENDPOINT,
-	.bEndpointAddress =	USB_DIR_OUT,
-	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
-	.wMaxPacketSize =	cpu_to_le16(512),
-};
-
-static struct usb_endpoint_descriptor uasp_fs_bo_desc = {
-	.bLength =		USB_DT_ENDPOINT_SIZE,
-	.bDescriptorType =	USB_DT_ENDPOINT,
-	.bEndpointAddress =	USB_DIR_OUT,
-	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
-};
-
-static struct usb_pipe_usage_descriptor uasp_bo_pipe_desc = {
-	.bLength =		sizeof(uasp_bo_pipe_desc),
-	.bDescriptorType =	USB_DT_PIPE_USAGE,
-	.bPipeID =		DATA_OUT_PIPE_ID,
-};
-
-static struct usb_endpoint_descriptor uasp_ss_bo_desc = {
-	.bLength =		USB_DT_ENDPOINT_SIZE,
-	.bDescriptorType =	USB_DT_ENDPOINT,
-	.bEndpointAddress =	USB_DIR_OUT,
-	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
-	.wMaxPacketSize =	cpu_to_le16(0x400),
-};
-
-static struct usb_ss_ep_comp_descriptor uasp_bo_ep_comp_desc = {
-	.bLength =		sizeof(uasp_bo_ep_comp_desc),
-	.bDescriptorType =	USB_DT_SS_ENDPOINT_COMP,
-	.bmAttributes =		UASP_SS_EP_COMP_LOG_STREAMS,
-};
-
-static struct usb_ss_ep_comp_descriptor bot_bo_ep_comp_desc = {
-	.bLength =		sizeof(bot_bo_ep_comp_desc),
-	.bDescriptorType =	USB_DT_SS_ENDPOINT_COMP,
-};
-
-static struct usb_endpoint_descriptor uasp_status_desc = {
-	.bLength =		USB_DT_ENDPOINT_SIZE,
-	.bDescriptorType =	USB_DT_ENDPOINT,
-	.bEndpointAddress =	USB_DIR_IN,
-	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
-	.wMaxPacketSize =	cpu_to_le16(512),
-};
-
-static struct usb_endpoint_descriptor uasp_fs_status_desc = {
-	.bLength =		USB_DT_ENDPOINT_SIZE,
-	.bDescriptorType =	USB_DT_ENDPOINT,
-	.bEndpointAddress =	USB_DIR_IN,
-	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
-};
-
-static struct usb_pipe_usage_descriptor uasp_status_pipe_desc = {
-	.bLength =		sizeof(uasp_status_pipe_desc),
-	.bDescriptorType =	USB_DT_PIPE_USAGE,
-	.bPipeID =		STATUS_PIPE_ID,
-};
-
-static struct usb_endpoint_descriptor uasp_ss_status_desc = {
-	.bLength =		USB_DT_ENDPOINT_SIZE,
-	.bDescriptorType =	USB_DT_ENDPOINT,
-	.bEndpointAddress =	USB_DIR_IN,
-	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
-	.wMaxPacketSize =	cpu_to_le16(1024),
-};
-
-static struct usb_ss_ep_comp_descriptor uasp_status_in_ep_comp_desc = {
-	.bLength =		sizeof(uasp_status_in_ep_comp_desc),
-	.bDescriptorType =	USB_DT_SS_ENDPOINT_COMP,
-	.bmAttributes =		UASP_SS_EP_COMP_LOG_STREAMS,
-};
-
-static struct usb_endpoint_descriptor uasp_cmd_desc = {
-	.bLength =		USB_DT_ENDPOINT_SIZE,
-	.bDescriptorType =	USB_DT_ENDPOINT,
-	.bEndpointAddress =	USB_DIR_OUT,
-	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
-	.wMaxPacketSize =	cpu_to_le16(512),
-};
-
-static struct usb_endpoint_descriptor uasp_fs_cmd_desc = {
-	.bLength =		USB_DT_ENDPOINT_SIZE,
-	.bDescriptorType =	USB_DT_ENDPOINT,
-	.bEndpointAddress =	USB_DIR_OUT,
-	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
-};
-
-static struct usb_pipe_usage_descriptor uasp_cmd_pipe_desc = {
-	.bLength =		sizeof(uasp_cmd_pipe_desc),
-	.bDescriptorType =	USB_DT_PIPE_USAGE,
-	.bPipeID =		CMD_PIPE_ID,
-};
-
-static struct usb_endpoint_descriptor uasp_ss_cmd_desc = {
-	.bLength =		USB_DT_ENDPOINT_SIZE,
-	.bDescriptorType =	USB_DT_ENDPOINT,
-	.bEndpointAddress =	USB_DIR_OUT,
-	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
-	.wMaxPacketSize =	cpu_to_le16(1024),
-};
-
-static struct usb_ss_ep_comp_descriptor uasp_cmd_comp_desc = {
-	.bLength =		sizeof(uasp_cmd_comp_desc),
-	.bDescriptorType =	USB_DT_SS_ENDPOINT_COMP,
-};
-
-static struct usb_descriptor_header *uasp_fs_function_desc[] = {
-	(struct usb_descriptor_header *) &bot_intf_desc,
-	(struct usb_descriptor_header *) &uasp_fs_bi_desc,
-	(struct usb_descriptor_header *) &uasp_fs_bo_desc,
-
-	(struct usb_descriptor_header *) &uasp_intf_desc,
-	(struct usb_descriptor_header *) &uasp_fs_bi_desc,
-	(struct usb_descriptor_header *) &uasp_bi_pipe_desc,
-	(struct usb_descriptor_header *) &uasp_fs_bo_desc,
-	(struct usb_descriptor_header *) &uasp_bo_pipe_desc,
-	(struct usb_descriptor_header *) &uasp_fs_status_desc,
-	(struct usb_descriptor_header *) &uasp_status_pipe_desc,
-	(struct usb_descriptor_header *) &uasp_fs_cmd_desc,
-	(struct usb_descriptor_header *) &uasp_cmd_pipe_desc,
-};
-
-static struct usb_descriptor_header *uasp_hs_function_desc[] = {
-	(struct usb_descriptor_header *) &bot_intf_desc,
-	(struct usb_descriptor_header *) &uasp_bi_desc,
-	(struct usb_descriptor_header *) &uasp_bo_desc,
-
-	(struct usb_descriptor_header *) &uasp_intf_desc,
-	(struct usb_descriptor_header *) &uasp_bi_desc,
-	(struct usb_descriptor_header *) &uasp_bi_pipe_desc,
-	(struct usb_descriptor_header *) &uasp_bo_desc,
-	(struct usb_descriptor_header *) &uasp_bo_pipe_desc,
-	(struct usb_descriptor_header *) &uasp_status_desc,
-	(struct usb_descriptor_header *) &uasp_status_pipe_desc,
-	(struct usb_descriptor_header *) &uasp_cmd_desc,
-	(struct usb_descriptor_header *) &uasp_cmd_pipe_desc,
-	NULL,
-};
-
-static struct usb_descriptor_header *uasp_ss_function_desc[] = {
-	(struct usb_descriptor_header *) &bot_intf_desc,
-	(struct usb_descriptor_header *) &uasp_ss_bi_desc,
-	(struct usb_descriptor_header *) &bot_bi_ep_comp_desc,
-	(struct usb_descriptor_header *) &uasp_ss_bo_desc,
-	(struct usb_descriptor_header *) &bot_bo_ep_comp_desc,
-
-	(struct usb_descriptor_header *) &uasp_intf_desc,
-	(struct usb_descriptor_header *) &uasp_ss_bi_desc,
-	(struct usb_descriptor_header *) &uasp_bi_ep_comp_desc,
-	(struct usb_descriptor_header *) &uasp_bi_pipe_desc,
-	(struct usb_descriptor_header *) &uasp_ss_bo_desc,
-	(struct usb_descriptor_header *) &uasp_bo_ep_comp_desc,
-	(struct usb_descriptor_header *) &uasp_bo_pipe_desc,
-	(struct usb_descriptor_header *) &uasp_ss_status_desc,
-	(struct usb_descriptor_header *) &uasp_status_in_ep_comp_desc,
-	(struct usb_descriptor_header *) &uasp_status_pipe_desc,
-	(struct usb_descriptor_header *) &uasp_ss_cmd_desc,
-	(struct usb_descriptor_header *) &uasp_cmd_comp_desc,
-	(struct usb_descriptor_header *) &uasp_cmd_pipe_desc,
-	NULL,
-};
+#include "f_tcm.c"
 
 #define UAS_VENDOR_ID	0x0525	/* NetChip */
 #define UAS_PRODUCT_ID	0xa4a5	/* Linux-USB File-backed Storage Gadget */
 
+#define USB_G_STR_MANUFACTOR    1
+#define USB_G_STR_PRODUCT       2
+#define USB_G_STR_SERIAL        3
+#define USB_G_STR_CONFIG        4
+
 static struct usb_device_descriptor usbg_device_desc = {
 	.bLength =		sizeof(usbg_device_desc),
 	.bDescriptorType =	USB_DT_DEVICE,
@@ -2227,8 +47,6 @@
 	{ USB_G_STR_PRODUCT,	"Target Product"},
 	{ USB_G_STR_SERIAL,	"000000000001"},
 	{ USB_G_STR_CONFIG,	"default config"},
-	{ USB_G_STR_INT_UAS,	"USB Attached SCSI"},
-	{ USB_G_STR_INT_BBB,	"Bulk Only Transport"},
 	{ },
 };
 
@@ -2242,11 +60,6 @@
 	NULL,
 };
 
-static int guas_unbind(struct usb_composite_dev *cdev)
-{
-	return 0;
-}
-
 static struct usb_configuration usbg_config_driver = {
 	.label                  = "Linux Target",
 	.bConfigurationValue    = 1,
@@ -2254,183 +67,9 @@
 	.bmAttributes           = USB_CONFIG_ATT_SELFPOWER,
 };
 
-static void give_back_ep(struct usb_ep **pep)
-{
-	struct usb_ep *ep = *pep;
-	if (!ep)
-		return;
-	ep->driver_data = NULL;
-}
-
-static int usbg_bind(struct usb_configuration *c, struct usb_function *f)
-{
-	struct f_uas		*fu = to_f_uas(f);
-	struct usb_gadget	*gadget = c->cdev->gadget;
-	struct usb_ep		*ep;
-	int			iface;
-
-	iface = usb_interface_id(c, f);
-	if (iface < 0)
-		return iface;
-
-	bot_intf_desc.bInterfaceNumber = iface;
-	uasp_intf_desc.bInterfaceNumber = iface;
-	fu->iface = iface;
-	ep = usb_ep_autoconfig_ss(gadget, &uasp_ss_bi_desc,
-			&uasp_bi_ep_comp_desc);
-	if (!ep)
-		goto ep_fail;
-
-	ep->driver_data = fu;
-	fu->ep_in = ep;
-
-	ep = usb_ep_autoconfig_ss(gadget, &uasp_ss_bo_desc,
-			&uasp_bo_ep_comp_desc);
-	if (!ep)
-		goto ep_fail;
-	ep->driver_data = fu;
-	fu->ep_out = ep;
-
-	ep = usb_ep_autoconfig_ss(gadget, &uasp_ss_status_desc,
-			&uasp_status_in_ep_comp_desc);
-	if (!ep)
-		goto ep_fail;
-	ep->driver_data = fu;
-	fu->ep_status = ep;
-
-	ep = usb_ep_autoconfig_ss(gadget, &uasp_ss_cmd_desc,
-			&uasp_cmd_comp_desc);
-	if (!ep)
-		goto ep_fail;
-	ep->driver_data = fu;
-	fu->ep_cmd = ep;
-
-	/* Assume endpoint addresses are the same for both speeds */
-	uasp_bi_desc.bEndpointAddress =	uasp_ss_bi_desc.bEndpointAddress;
-	uasp_bo_desc.bEndpointAddress = uasp_ss_bo_desc.bEndpointAddress;
-	uasp_status_desc.bEndpointAddress =
-		uasp_ss_status_desc.bEndpointAddress;
-	uasp_cmd_desc.bEndpointAddress = uasp_ss_cmd_desc.bEndpointAddress;
-
-	uasp_fs_bi_desc.bEndpointAddress = uasp_ss_bi_desc.bEndpointAddress;
-	uasp_fs_bo_desc.bEndpointAddress = uasp_ss_bo_desc.bEndpointAddress;
-	uasp_fs_status_desc.bEndpointAddress =
-		uasp_ss_status_desc.bEndpointAddress;
-	uasp_fs_cmd_desc.bEndpointAddress = uasp_ss_cmd_desc.bEndpointAddress;
-
-	return 0;
-ep_fail:
-	pr_err("Can't claim all required eps\n");
-
-	give_back_ep(&fu->ep_in);
-	give_back_ep(&fu->ep_out);
-	give_back_ep(&fu->ep_status);
-	give_back_ep(&fu->ep_cmd);
-	return -ENOTSUPP;
-}
-
-static void usbg_unbind(struct usb_configuration *c, struct usb_function *f)
-{
-	struct f_uas *fu = to_f_uas(f);
-
-	kfree(fu);
-}
-
-struct guas_setup_wq {
-	struct work_struct work;
-	struct f_uas *fu;
-	unsigned int alt;
-};
-
-static void usbg_delayed_set_alt(struct work_struct *wq)
-{
-	struct guas_setup_wq *work = container_of(wq, struct guas_setup_wq,
-			work);
-	struct f_uas *fu = work->fu;
-	int alt = work->alt;
-
-	kfree(work);
-
-	if (fu->flags & USBG_IS_BOT)
-		bot_cleanup_old_alt(fu);
-	if (fu->flags & USBG_IS_UAS)
-		uasp_cleanup_old_alt(fu);
-
-	if (alt == USB_G_ALT_INT_BBB)
-		bot_set_alt(fu);
-	else if (alt == USB_G_ALT_INT_UAS)
-		uasp_set_alt(fu);
-	usb_composite_setup_continue(fu->function.config->cdev);
-}
-
-static int usbg_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
-{
-	struct f_uas *fu = to_f_uas(f);
-
-	if ((alt == USB_G_ALT_INT_BBB) || (alt == USB_G_ALT_INT_UAS)) {
-		struct guas_setup_wq *work;
-
-		work = kmalloc(sizeof(*work), GFP_ATOMIC);
-		if (!work)
-			return -ENOMEM;
-		INIT_WORK(&work->work, usbg_delayed_set_alt);
-		work->fu = fu;
-		work->alt = alt;
-		schedule_work(&work->work);
-		return USB_GADGET_DELAYED_STATUS;
-	}
-	return -EOPNOTSUPP;
-}
-
-static void usbg_disable(struct usb_function *f)
-{
-	struct f_uas *fu = to_f_uas(f);
-
-	if (fu->flags & USBG_IS_UAS)
-		uasp_cleanup_old_alt(fu);
-	else if (fu->flags & USBG_IS_BOT)
-		bot_cleanup_old_alt(fu);
-	fu->flags = 0;
-}
-
-static int usbg_setup(struct usb_function *f,
-		const struct usb_ctrlrequest *ctrl)
-{
-	struct f_uas *fu = to_f_uas(f);
-
-	if (!(fu->flags & USBG_IS_BOT))
-		return -EOPNOTSUPP;
-
-	return usbg_bot_setup(f, ctrl);
-}
-
 static int usbg_cfg_bind(struct usb_configuration *c)
 {
-	struct f_uas *fu;
-	int ret;
-
-	fu = kzalloc(sizeof(*fu), GFP_KERNEL);
-	if (!fu)
-		return -ENOMEM;
-	fu->function.name = "Target Function";
-	fu->function.descriptors = uasp_fs_function_desc;
-	fu->function.hs_descriptors = uasp_hs_function_desc;
-	fu->function.ss_descriptors = uasp_ss_function_desc;
-	fu->function.bind = usbg_bind;
-	fu->function.unbind = usbg_unbind;
-	fu->function.set_alt = usbg_set_alt;
-	fu->function.setup = usbg_setup;
-	fu->function.disable = usbg_disable;
-	fu->tpg = the_only_tpg_I_currently_have;
-
-	ret = usb_add_function(c, &fu->function);
-	if (ret)
-		goto err;
-
-	return 0;
-err:
-	kfree(fu);
-	return ret;
+	return tcm_bind_config(c);
 }
 
 static int usb_target_bind(struct usb_composite_dev *cdev)
@@ -2439,6 +78,11 @@
 
 	ret = usb_add_config(cdev, &usbg_config_driver,
 			usbg_cfg_bind);
+	return ret;
+}
+
+static int guas_unbind(struct usb_composite_dev *cdev)
+{
 	return 0;
 }
 
@@ -2450,28 +94,30 @@
 	.unbind         = guas_unbind,
 };
 
-static int usbg_attach(struct usbg_tpg *tpg)
+static int usbg_attach_cb(bool connect)
 {
-	return usb_composite_probe(&usbg_driver, usb_target_bind);
-}
+	int ret = 0;
 
-static void usbg_detach(struct usbg_tpg *tpg)
-{
-	usb_composite_unregister(&usbg_driver);
+	if (connect)
+		ret = usb_composite_probe(&usbg_driver, usb_target_bind);
+	else
+		usb_composite_unregister(&usbg_driver);
+
+	return ret;
 }
 
 static int __init usb_target_gadget_init(void)
 {
 	int ret;
 
-	ret = usbg_register_configfs();
+	ret = f_tcm_init(&usbg_attach_cb);
 	return ret;
 }
 module_init(usb_target_gadget_init);
 
 static void __exit usb_target_gadget_exit(void)
 {
-	usbg_deregister_configfs();
+	f_tcm_exit();
 }
 module_exit(usb_target_gadget_exit);
 
diff --git a/drivers/video/msm/mdp4_overlay_dsi_video.c b/drivers/video/msm/mdp4_overlay_dsi_video.c
index c7c2476..bc4476e 100644
--- a/drivers/video/msm/mdp4_overlay_dsi_video.c
+++ b/drivers/video/msm/mdp4_overlay_dsi_video.c
@@ -570,8 +570,13 @@
 {
 	if (blt_cfg_changed) {
 		mdp_is_in_isr = TRUE;
-		mdp4_overlayproc_cfg(dsi_pipe);
-		mdp4_overlay_dmap_xy(dsi_pipe);
+		if (dsi_pipe->ov_blt_addr) {
+			mdp4_overlay_dmap_xy(dsi_pipe);
+			mdp4_overlayproc_cfg(dsi_pipe);
+		} else {
+			mdp4_overlayproc_cfg(dsi_pipe);
+			mdp4_overlay_dmap_xy(dsi_pipe);
+		}
 		mdp_is_in_isr = FALSE;
 		if (dsi_pipe->ov_blt_addr) {
 			mdp4_dsi_video_blt_ov_update(dsi_pipe);
diff --git a/drivers/video/msm/mdp4_overlay_dtv.c b/drivers/video/msm/mdp4_overlay_dtv.c
index 12448e4..b90812f 100644
--- a/drivers/video/msm/mdp4_overlay_dtv.c
+++ b/drivers/video/msm/mdp4_overlay_dtv.c
@@ -678,8 +678,8 @@
 		msleep(20);
 	}
 
-	mdp4_overlayproc_cfg(dtv_pipe);
 	mdp4_overlay_dmae_xy(dtv_pipe);
+	mdp4_overlayproc_cfg(dtv_pipe);
 	MDP_OUTP(MDP_BASE + DTV_BASE, 1);	/* start dtv */
 }
 
diff --git a/drivers/video/msm/mdp4_overlay_lcdc.c b/drivers/video/msm/mdp4_overlay_lcdc.c
index 3739332..bcc4ea6 100644
--- a/drivers/video/msm/mdp4_overlay_lcdc.c
+++ b/drivers/video/msm/mdp4_overlay_lcdc.c
@@ -561,8 +561,8 @@
 		msleep(20);
 	}
 
-	mdp4_overlayproc_cfg(lcdc_pipe);
 	mdp4_overlay_dmap_xy(lcdc_pipe);
+	mdp4_overlayproc_cfg(lcdc_pipe);
 	if (lcdc_pipe->ov_blt_addr) {
 		mdp4_overlay_lcdc_prefill(mfd);
 		mdp4_overlay_lcdc_prefill(mfd);
diff --git a/drivers/video/msm/msm_fb.c b/drivers/video/msm/msm_fb.c
index 18ee3e6..5f58af7 100644
--- a/drivers/video/msm/msm_fb.c
+++ b/drivers/video/msm/msm_fb.c
@@ -107,6 +107,9 @@
 static int msm_fb_ioctl(struct fb_info *info, unsigned int cmd,
 			unsigned long arg);
 static int msm_fb_mmap(struct fb_info *info, struct vm_area_struct * vma);
+static int mdp_bl_scale_config(struct msm_fb_data_type *mfd,
+						struct mdp_bl_scale_data *data);
+static void msm_fb_scale_bl(__u32 *bl_lvl);
 
 #ifdef MSM_FB_ENABLE_DBGFS
 
@@ -116,6 +119,7 @@
 int msm_fb_debugfs_file_index;
 struct dentry *msm_fb_debugfs_root;
 struct dentry *msm_fb_debugfs_file[MSM_FB_MAX_DBGFS];
+static int bl_scale, bl_min_lvl;
 
 DEFINE_MUTEX(msm_fb_notify_update_sem);
 void msmfb_no_update_notify_timer_cb(unsigned long data)
@@ -372,6 +376,8 @@
 
 	mfd->panel_info.frame_count = 0;
 	mfd->bl_level = 0;
+	bl_scale = 1024;
+	bl_min_lvl = 255;
 #ifdef CONFIG_FB_MSM_OVERLAY
 	mfd->overlay_play_enable = 1;
 #endif
@@ -746,11 +752,41 @@
 
 static int unset_bl_level, bl_updated;
 static int bl_level_old;
+static int mdp_bl_scale_config(struct msm_fb_data_type *mfd,
+						struct mdp_bl_scale_data *data)
+{
+	int ret = 0;
+	int curr_bl = mfd->bl_level;
+	bl_scale = data->scale;
+	bl_min_lvl = data->min_lvl;
+	pr_debug("%s: update scale = %d, min_lvl = %d\n", __func__, bl_scale,
+								bl_min_lvl);
+
+	/* update current backlight to use new scaling*/
+	msm_fb_set_backlight(mfd, curr_bl);
+
+	return ret;
+}
+
+static void msm_fb_scale_bl(__u32 *bl_lvl)
+{
+	__u32 temp = *bl_lvl;
+	if (temp >= bl_min_lvl) {
+		/* bl_scale is the numerator of scaling fraction (x/1024)*/
+		temp = ((*bl_lvl) * bl_scale) / 1024;
+
+		/*if less than minimum level, use min level*/
+		if (temp < bl_min_lvl)
+			temp = bl_min_lvl;
+	}
+
+	(*bl_lvl) = temp;
+}
 
 void msm_fb_set_backlight(struct msm_fb_data_type *mfd, __u32 bkl_lvl)
 {
 	struct msm_fb_panel_data *pdata;
-
+	__u32 temp = bkl_lvl;
 	if (!mfd->panel_power_on || !bl_updated) {
 		unset_bl_level = bkl_lvl;
 		return;
@@ -758,17 +794,19 @@
 		unset_bl_level = 0;
 	}
 
+	msm_fb_scale_bl(&temp);
 	pdata = (struct msm_fb_panel_data *)mfd->pdev->dev.platform_data;
 
 	if ((pdata) && (pdata->set_backlight)) {
 		down(&mfd->sem);
-		if (bl_level_old == bkl_lvl) {
+		if (bl_level_old == temp) {
 			up(&mfd->sem);
 			return;
 		}
-		mfd->bl_level = bkl_lvl;
+		mfd->bl_level = temp;
 		pdata->set_backlight(mfd);
-		bl_level_old = mfd->bl_level;
+		mfd->bl_level = bkl_lvl;
+		bl_level_old = temp;
 		up(&mfd->sem);
 	}
 }
@@ -3133,7 +3171,8 @@
 	return 0;
 }
 
-static int msmfb_handle_pp_ioctl(struct msmfb_mdp_pp *pp_ptr)
+static int msmfb_handle_pp_ioctl(struct msm_fb_data_type *mfd,
+						struct msmfb_mdp_pp *pp_ptr)
 {
 	int ret = -1;
 
@@ -3178,6 +3217,11 @@
 						&pp_ptr->data.qseed_cfg_data);
 		break;
 #endif
+	case mdp_bl_scale_cfg:
+		ret = mdp_bl_scale_config(mfd, (struct mdp_bl_scale_data *)
+				&pp_ptr->data.bl_scale_data);
+		break;
+
 	default:
 		pr_warn("Unsupported request to MDP_PP IOCTL.\n");
 		ret = -EINVAL;
@@ -3496,7 +3540,7 @@
 		if (ret)
 			return ret;
 
-		ret = msmfb_handle_pp_ioctl(&mdp_pp);
+		ret = msmfb_handle_pp_ioctl(mfd, &mdp_pp);
 		break;
 
 	default:
diff --git a/include/linux/Kbuild b/include/linux/Kbuild
index 28c0917..b2b79b1 100644
--- a/include/linux/Kbuild
+++ b/include/linux/Kbuild
@@ -259,6 +259,7 @@
 header-y += msdos_fs.h
 header-y += msg.h
 header-y += msm_adc.h
+header-y += epm_adc.h
 header-y += mtio.h
 header-y += n_r3964.h
 header-y += nbd.h
diff --git a/include/linux/epm_adc.h b/include/linux/epm_adc.h
index 1af97fe..9cf2acf 100644
--- a/include/linux/epm_adc.h
+++ b/include/linux/epm_adc.h
@@ -1,16 +1,3 @@
-/*
- * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
 #ifndef __EPM_ADC_H
 #define __EPM_ADC_H
 
@@ -26,6 +13,7 @@
 	int32_t physical;
 };
 
+#ifdef __KERNEL__
 struct epm_chan_properties {
 	uint32_t resistorValue;
 	uint32_t gain;
@@ -41,6 +29,7 @@
 	uint32_t bus_id;
 	uint32_t gpio_expander_base_addr;
 };
+#endif
 
 #define EPM_ADC_IOCTL_CODE		0x91
 
diff --git a/include/linux/mfd/wcd9xxx/core.h b/include/linux/mfd/wcd9xxx/core.h
index 2657ec3..17be2cb 100644
--- a/include/linux/mfd/wcd9xxx/core.h
+++ b/include/linux/mfd/wcd9xxx/core.h
@@ -155,6 +155,11 @@
 
 	int num_rx_port;
 	int num_tx_port;
+
+	u8 idbyte_0;
+	u8 idbyte_1;
+	u8 idbyte_2;
+	u8 idbyte_3;
 };
 
 int wcd9xxx_reg_read(struct wcd9xxx *wcd9xxx, unsigned short reg);
diff --git a/include/linux/msm_kgsl.h b/include/linux/msm_kgsl.h
index e67190f..7afc896 100644
--- a/include/linux/msm_kgsl.h
+++ b/include/linux/msm_kgsl.h
@@ -49,8 +49,6 @@
 	KGSL_CTX_STAT_UNKNOWN_CONTEXT_RESET_EXT		= 0x00000003
 };
 
-#define KGSL_MAX_PWRLEVELS 5
-
 #define KGSL_CONVERT_TO_MBPS(val) \
 	(val*1000*1000U)
 
@@ -135,12 +133,6 @@
 	unsigned int flags; /* contains KGSL_FLAGS_ values */
 };
 
-struct kgsl_pwrlevel {
-	unsigned int gpu_freq;
-	unsigned int bus_freq;
-	unsigned int io_fraction;
-};
-
 struct kgsl_version {
 	unsigned int drv_major;
 	unsigned int drv_minor;
@@ -148,50 +140,6 @@
 	unsigned int dev_minor;
 };
 
-#ifdef __KERNEL__
-
-#define KGSL_3D0_REG_MEMORY	"kgsl_3d0_reg_memory"
-#define KGSL_3D0_IRQ		"kgsl_3d0_irq"
-#define KGSL_2D0_REG_MEMORY	"kgsl_2d0_reg_memory"
-#define KGSL_2D0_IRQ		"kgsl_2d0_irq"
-#define KGSL_2D1_REG_MEMORY	"kgsl_2d1_reg_memory"
-#define KGSL_2D1_IRQ		"kgsl_2d1_irq"
-
-enum kgsl_iommu_context_id {
-	KGSL_IOMMU_CONTEXT_USER = 0,
-	KGSL_IOMMU_CONTEXT_PRIV = 1,
-};
-
-struct kgsl_iommu_ctx {
-	const char *iommu_ctx_name;
-	enum kgsl_iommu_context_id ctx_id;
-};
-
-struct kgsl_device_iommu_data {
-	const struct kgsl_iommu_ctx *iommu_ctxs;
-	int iommu_ctx_count;
-	unsigned int physstart;
-	unsigned int physend;
-};
-
-struct kgsl_device_platform_data {
-	struct kgsl_pwrlevel pwrlevel[KGSL_MAX_PWRLEVELS];
-	int init_level;
-	int num_levels;
-	int (*set_grp_async)(void);
-	unsigned int idle_timeout;
-	bool strtstp_sleepwake;
-	unsigned int nap_allowed;
-	unsigned int clk_map;
-	unsigned int idle_needed;
-	struct msm_bus_scale_pdata *bus_scale_table;
-	struct kgsl_device_iommu_data *iommu_data;
-	int iommu_count;
-	struct msm_dcvs_core_info *core_info;
-};
-
-#endif
-
 /* structure holds list of ibs */
 struct kgsl_ibdesc {
 	unsigned int gpuaddr;
diff --git a/include/linux/msm_mdp.h b/include/linux/msm_mdp.h
index 19728fe..d8edbc8 100644
--- a/include/linux/msm_mdp.h
+++ b/include/linux/msm_mdp.h
@@ -434,7 +434,6 @@
 	uint32_t *data;
 };
 
-
 struct mdp_lut_cfg_data {
 	uint32_t lut_type;
 	union {
@@ -452,12 +451,17 @@
 	uint32_t *data;
 };
 
+struct mdp_bl_scale_data {
+	uint32_t min_lvl;
+	uint32_t scale;
+};
 
 enum {
 	mdp_op_pcc_cfg,
 	mdp_op_csc_cfg,
 	mdp_op_lut_cfg,
 	mdp_op_qseed_cfg,
+	mdp_bl_scale_cfg,
 	mdp_op_max,
 };
 
@@ -468,6 +472,7 @@
 		struct mdp_csc_cfg_data csc_cfg_data;
 		struct mdp_lut_cfg_data lut_cfg_data;
 		struct mdp_qseed_cfg_data qseed_cfg_data;
+		struct mdp_bl_scale_data bl_scale_data;
 	} data;
 };
 
diff --git a/include/linux/usb/android.h b/include/linux/usb/android.h
index bf65ebb..7c2b33b 100644
--- a/include/linux/usb/android.h
+++ b/include/linux/usb/android.h
@@ -21,6 +21,7 @@
 	int (*update_pid_and_serial_num)(uint32_t, const char *);
 	u32 swfi_latency;
 	u8 usb_core_id;
+	bool cdrom;
 };
 
 #endif	/* __LINUX_USB_ANDROID_H */
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index 42f7349..f5e1ffa 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -2047,6 +2047,7 @@
 #define V4L2_DEC_CMD_STOP        (1)
 #define V4L2_DEC_CMD_PAUSE       (2)
 #define V4L2_DEC_CMD_RESUME      (3)
+#define V4L2_DEC_QCOM_CMD_FLUSH  (4)
 
 /* Flags for V4L2_DEC_CMD_START */
 #define V4L2_DEC_CMD_START_MUTE_AUDIO	(1 << 0)
@@ -2058,6 +2059,10 @@
 #define V4L2_DEC_CMD_STOP_TO_BLACK	(1 << 0)
 #define V4L2_DEC_CMD_STOP_IMMEDIATELY	(1 << 1)
 
+/* Flags for V4L2_DEC_QCOM_CMD_FLUSH */
+#define V4L2_DEC_QCOM_CMD_FLUSH_OUTPUT  (1 << 0)
+#define V4L2_DEC_QCOM_CMD_FLUSH_CAPTURE (1 << 1)
+
 /* Play format requirements (returned by the driver): */
 
 /* The decoder has no special format requirements */
diff --git a/include/media/vcap_v4l2.h b/include/media/vcap_v4l2.h
index 045c107..e1d69d5 100644
--- a/include/media/vcap_v4l2.h
+++ b/include/media/vcap_v4l2.h
@@ -226,4 +226,8 @@
 
 int get_phys_addr(struct vcap_dev *dev, struct vb2_queue *q,
 				  struct v4l2_buffer *b);
+
+int vcvp_qbuf(struct vb2_queue *q, struct v4l2_buffer *b);
+int vcvp_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b);
+
 #endif
diff --git a/include/sound/q6asm.h b/include/sound/q6asm.h
index d38dbd5..60268b4 100644
--- a/include/sound/q6asm.h
+++ b/include/sound/q6asm.h
@@ -151,6 +151,7 @@
 
 	atomic_t		cmd_state;
 	atomic_t		time_flag;
+	atomic_t		nowait_cmd_cnt;
 	wait_queue_head_t	cmd_wait;
 	wait_queue_head_t	time_wait;
 
diff --git a/sound/soc/msm/qdsp6/q6asm.c b/sound/soc/msm/qdsp6/q6asm.c
index 59c390e..02c6245 100644
--- a/sound/soc/msm/qdsp6/q6asm.c
+++ b/sound/soc/msm/qdsp6/q6asm.c
@@ -805,6 +805,7 @@
 	uint32_t token;
 	unsigned long dsp_flags;
 	uint32_t *payload;
+	uint32_t wakeup_flag = 1;
 
 
 	if ((ac == NULL) || (data == NULL)) {
@@ -816,7 +817,13 @@
 			ac->session);
 		return -EINVAL;
 	}
-
+	if (atomic_read(&ac->nowait_cmd_cnt) > 0) {
+		pr_debug("%s: nowait_cmd_cnt %d\n",
+				__func__,
+				atomic_read(&ac->nowait_cmd_cnt));
+		atomic_dec(&ac->nowait_cmd_cnt);
+		wakeup_flag = 0;
+	}
 	payload = data->payload;
 
 	if (data->opcode == RESET_EVENTS) {
@@ -862,7 +869,7 @@
 		case ASM_STREAM_CMD_SET_ENCDEC_PARAM:
 		case ASM_STREAM_CMD_OPEN_WRITE_COMPRESSED:
 		case ASM_STREAM_CMD_OPEN_READ_COMPRESSED:
-			if (atomic_read(&ac->cmd_state)) {
+			if (atomic_read(&ac->cmd_state) && wakeup_flag) {
 				atomic_set(&ac->cmd_state, 0);
 				if (payload[1] == ADSP_EUNSUPPORTED)
 					atomic_set(&ac->cmd_response, 1);
@@ -1618,12 +1625,12 @@
 	run.flags    = flags;
 	run.msw_ts   = msw_ts;
 	run.lsw_ts   = lsw_ts;
-
 	rc = apr_send_pkt(ac->apr, (uint32_t *) &run);
 	if (rc < 0) {
 		pr_err("%s:Commmand run failed[%d]", __func__, rc);
 		return -EINVAL;
 	}
+	atomic_inc(&ac->nowait_cmd_cnt);
 	return 0;
 }
 
@@ -3541,11 +3548,13 @@
 	pr_debug("%s:session[%d]opcode[0x%x] ", __func__,
 						ac->session,
 						hdr.opcode);
+
 	rc = apr_send_pkt(ac->apr, (uint32_t *) &hdr);
 	if (rc < 0) {
 		pr_err("%s:Commmand 0x%x failed\n", __func__, hdr.opcode);
 		goto fail_cmd;
 	}
+	atomic_inc(&ac->nowait_cmd_cnt);
 	return 0;
 fail_cmd:
 	return -EINVAL;