Merge "serial: msm_geni: Introduce serial driver for GENI based cores" into msm-4.9
diff --git a/AndroidKernel.mk b/AndroidKernel.mk
new file mode 100644
index 0000000..d28f7ba
--- /dev/null
+++ b/AndroidKernel.mk
@@ -0,0 +1,168 @@
+#Android makefile to build kernel as a part of Android Build
+PERL		= perl
+
+KERNEL_TARGET := $(strip $(INSTALLED_KERNEL_TARGET))
+ifeq ($(KERNEL_TARGET),)
+INSTALLED_KERNEL_TARGET := $(PRODUCT_OUT)/kernel
+endif
+
+TARGET_KERNEL_ARCH := $(strip $(TARGET_KERNEL_ARCH))
+ifeq ($(TARGET_KERNEL_ARCH),)
+KERNEL_ARCH := arm
+else
+KERNEL_ARCH := $(TARGET_KERNEL_ARCH)
+endif
+
+TARGET_KERNEL_HEADER_ARCH := $(strip $(TARGET_KERNEL_HEADER_ARCH))
+ifeq ($(TARGET_KERNEL_HEADER_ARCH),)
+KERNEL_HEADER_ARCH := $(KERNEL_ARCH)
+else
+$(warning Forcing kernel header generation only for '$(TARGET_KERNEL_HEADER_ARCH)')
+KERNEL_HEADER_ARCH := $(TARGET_KERNEL_HEADER_ARCH)
+endif
+
+KERNEL_HEADER_DEFCONFIG := $(strip $(KERNEL_HEADER_DEFCONFIG))
+ifeq ($(KERNEL_HEADER_DEFCONFIG),)
+KERNEL_HEADER_DEFCONFIG := $(KERNEL_DEFCONFIG)
+endif
+
+# Force 32-bit binder IPC for 64bit kernel with 32bit userspace
+ifeq ($(KERNEL_ARCH),arm64)
+ifeq ($(TARGET_ARCH),arm)
+KERNEL_CONFIG_OVERRIDE := CONFIG_ANDROID_BINDER_IPC_32BIT=y
+endif
+endif
+
+TARGET_KERNEL_CROSS_COMPILE_PREFIX := $(strip $(TARGET_KERNEL_CROSS_COMPILE_PREFIX))
+ifeq ($(TARGET_KERNEL_CROSS_COMPILE_PREFIX),)
+KERNEL_CROSS_COMPILE := arm-eabi-
+else
+KERNEL_CROSS_COMPILE := $(TARGET_KERNEL_CROSS_COMPILE_PREFIX)
+endif
+
+ifeq ($(TARGET_PREBUILT_KERNEL),)
+
+KERNEL_GCC_NOANDROID_CHK := $(shell (echo "int main() {return 0;}" | $(KERNEL_CROSS_COMPILE)gcc -E -mno-android - > /dev/null 2>&1 ; echo $$?))
+ifeq ($(strip $(KERNEL_GCC_NOANDROID_CHK)),0)
+KERNEL_CFLAGS := KCFLAGS=-mno-android
+endif
+
+mkfile_path := $(abspath $(lastword $(MAKEFILE_LIST)))
+current_dir := $(notdir $(patsubst %/,%,$(dir $(mkfile_path))))
+TARGET_KERNEL := msm-$(TARGET_KERNEL_VERSION)
+ifeq ($(TARGET_KERNEL),$(current_dir))
+    # New style, kernel/msm-version
+    BUILD_ROOT_LOC := ../../
+    TARGET_KERNEL_SOURCE := kernel/$(TARGET_KERNEL)
+    KERNEL_OUT := $(TARGET_OUT_INTERMEDIATES)/kernel/$(TARGET_KERNEL)
+    KERNEL_SYMLINK := $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ
+    KERNEL_USR := $(KERNEL_SYMLINK)/usr
+else
+    # Legacy style, kernel source directly under kernel
+    KERNEL_LEGACY_DIR := true
+    BUILD_ROOT_LOC := ../
+    TARGET_KERNEL_SOURCE := kernel
+    KERNEL_OUT := $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ
+endif
+
+KERNEL_CONFIG := $(KERNEL_OUT)/.config
+
+ifeq ($(KERNEL_DEFCONFIG)$(wildcard $(KERNEL_CONFIG)),)
+$(error Kernel configuration not defined, cannot build kernel)
+else
+
+ifeq ($(TARGET_USES_UNCOMPRESSED_KERNEL),true)
+$(info Using uncompressed kernel)
+TARGET_PREBUILT_INT_KERNEL := $(KERNEL_OUT)/arch/$(KERNEL_ARCH)/boot/Image
+else
+ifeq ($(KERNEL_ARCH),arm64)
+TARGET_PREBUILT_INT_KERNEL := $(KERNEL_OUT)/arch/$(KERNEL_ARCH)/boot/Image.gz
+else
+TARGET_PREBUILT_INT_KERNEL := $(KERNEL_OUT)/arch/$(KERNEL_ARCH)/boot/zImage
+endif
+endif
+
+ifeq ($(TARGET_KERNEL_APPEND_DTB), true)
+$(info Using appended DTB)
+TARGET_PREBUILT_INT_KERNEL := $(TARGET_PREBUILT_INT_KERNEL)-dtb
+endif
+
+KERNEL_HEADERS_INSTALL := $(KERNEL_OUT)/usr
+KERNEL_MODULES_INSTALL := system
+KERNEL_MODULES_OUT := $(TARGET_OUT)/lib/modules
+
+TARGET_PREBUILT_KERNEL := $(TARGET_PREBUILT_INT_KERNEL)
+
+define mv-modules
+mdpath=`find $(KERNEL_MODULES_OUT) -type f -name modules.dep`;\
+if [ "$$mdpath" != "" ];then\
+mpath=`dirname $$mdpath`;\
+ko=`find $$mpath/kernel -type f -name *.ko`;\
+for i in $$ko; do mv $$i $(KERNEL_MODULES_OUT)/; done;\
+fi
+endef
+
+define clean-module-folder
+mdpath=`find $(KERNEL_MODULES_OUT) -type f -name modules.dep`;\
+if [ "$$mdpath" != "" ];then\
+mpath=`dirname $$mdpath`; rm -rf $$mpath;\
+fi
+endef
+
+ifneq ($(KERNEL_LEGACY_DIR),true)
+$(KERNEL_USR): $(KERNEL_HEADERS_INSTALL)
+	rm -rf $(KERNEL_SYMLINK)
+	ln -s kernel/$(TARGET_KERNEL) $(KERNEL_SYMLINK)
+
+$(TARGET_PREBUILT_INT_KERNEL): $(KERNEL_USR)
+endif
+
+$(KERNEL_OUT):
+	mkdir -p $(KERNEL_OUT)
+
+$(KERNEL_CONFIG): $(KERNEL_OUT)
+	$(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) $(KERNEL_DEFCONFIG)
+	$(hide) if [ ! -z "$(KERNEL_CONFIG_OVERRIDE)" ]; then \
+			echo "Overriding kernel config with '$(KERNEL_CONFIG_OVERRIDE)'"; \
+			echo $(KERNEL_CONFIG_OVERRIDE) >> $(KERNEL_OUT)/.config; \
+			$(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) oldconfig; fi
+
+$(TARGET_PREBUILT_INT_KERNEL): $(KERNEL_OUT) $(KERNEL_HEADERS_INSTALL)
+	$(hide) echo "Building kernel..."
+	$(hide) rm -rf $(KERNEL_OUT)/arch/$(KERNEL_ARCH)/boot/dts
+	$(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) $(KERNEL_CFLAGS)
+	$(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) $(KERNEL_CFLAGS) modules
+	$(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) INSTALL_MOD_PATH=$(BUILD_ROOT_LOC)../$(KERNEL_MODULES_INSTALL) INSTALL_MOD_STRIP=1 ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) modules_install
+	$(mv-modules)
+	$(clean-module-folder)
+
+$(KERNEL_HEADERS_INSTALL): $(KERNEL_OUT)
+	$(hide) if [ ! -z "$(KERNEL_HEADER_DEFCONFIG)" ]; then \
+			rm -f $(BUILD_ROOT_LOC)$(KERNEL_CONFIG); \
+			$(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) ARCH=$(KERNEL_HEADER_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) $(KERNEL_HEADER_DEFCONFIG); \
+			$(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) ARCH=$(KERNEL_HEADER_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) headers_install;\
+			if [ -d "$(KERNEL_HEADERS_INSTALL)/include/bringup_headers" ]; then \
+				cp -Rf  $(KERNEL_HEADERS_INSTALL)/include/bringup_headers/* $(KERNEL_HEADERS_INSTALL)/include/ ;\
+			fi ;\
+			fi
+	$(hide) if [ "$(KERNEL_HEADER_DEFCONFIG)" != "$(KERNEL_DEFCONFIG)" ]; then \
+			echo "Used a different defconfig for header generation"; \
+			rm -f $(BUILD_ROOT_LOC)$(KERNEL_CONFIG); \
+			$(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) $(KERNEL_DEFCONFIG); fi
+	$(hide) if [ ! -z "$(KERNEL_CONFIG_OVERRIDE)" ]; then \
+			echo "Overriding kernel config with '$(KERNEL_CONFIG_OVERRIDE)'"; \
+			echo $(KERNEL_CONFIG_OVERRIDE) >> $(KERNEL_OUT)/.config; \
+			$(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) oldconfig; fi
+
+kerneltags: $(KERNEL_OUT) $(KERNEL_CONFIG)
+	$(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) tags
+
+kernelconfig: $(KERNEL_OUT) $(KERNEL_CONFIG)
+	env KCONFIG_NOTIMESTAMP=true \
+	     $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) menuconfig
+	env KCONFIG_NOTIMESTAMP=true \
+	     $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) savedefconfig
+	cp $(KERNEL_OUT)/defconfig $(TARGET_KERNEL_SOURCE)/arch/$(KERNEL_ARCH)/configs/$(KERNEL_DEFCONFIG)
+
+endif
+endif
diff --git a/Documentation/devicetree/bindings/arm/coresight.txt b/Documentation/devicetree/bindings/arm/coresight.txt
index 2e5c1ee..53e4295 100644
--- a/Documentation/devicetree/bindings/arm/coresight.txt
+++ b/Documentation/devicetree/bindings/arm/coresight.txt
@@ -84,6 +84,11 @@
 
 	* coresight-name: unique descriptive name of the component.
 
+* Additional required property for coresight-dummy devices:
+	* qcom,dummy-source: Configure the device as source.
+
+	* qcom,dummy-sink: Configure the device as sink.
+
 * Optional properties for all components:
 	* reg-names: names corresponding to each reg property value.
 
diff --git a/Documentation/devicetree/bindings/arm/msm/wil6210.txt b/Documentation/devicetree/bindings/arm/msm/wil6210.txt
new file mode 100644
index 0000000..b381bdeb
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/wil6210.txt
@@ -0,0 +1,52 @@
+wil6210 - Qualcomm Technologies Inc. 802.11ad Wireless Driver
+
+wil6210 driver is responsible for managing 802.11ad chipset
+connected to MSM over PCIe interface.
+
+The platform data is needed in order to perform proper
+bus-scaling and SMMU initialization by the driver.
+
+Required properties:
+
+- compatible: "qcom,wil6210"
+- qcom,smmu-support: Boolean flag indicating whether PCIe has SMMU support
+- qcom,pcie-parent: phandle for the PCIe root complex to which 11ad card is connected
+- Refer to "Documentation/devicetree/bindings/arm/msm/msm_bus.txt" for
+  the below optional properties:
+	- qcom,msm-bus,name
+	- qcom,msm-bus,num-cases
+	- qcom,msm-bus,num-paths
+	- qcom,msm-bus,vectors-KBps
+
+Optional properties:
+- qcom,sleep-clk-en: GPIO for sleep clock used for low power modes by 11ad card
+- qcom,wigig-en: Enable GPIO connected to 11ad card
+- qcom,use-ext-supply: Boolean flag to indicate if 11ad SIP uses external power supply
+- vdd-supply: phandle to 11ad VDD regulator node
+- vddio-supply: phandle to 11ad VDDIO regulator node
+- qcom,use-ext-clocks: Boolean flag to indicate if 11ad SIP uses external clocks
+- clocks	    : List of phandle and clock specifier pairs
+- clock-names       : List of clock input name strings sorted in the same
+		      order as the clocks property.
+
+Example:
+	wil6210: qcom,wil6210 {
+		compatible = "qcom,wil6210";
+		qcom,smmu-support;
+		qcom,pcie-parent = <&pcie1>;
+		qcom,wigig-en = <&tlmm 94 0>;
+		qcom,msm-bus,name = "wil6210";
+		qcom,msm-bus,num-cases = <2>;
+		qcom,msm-bus,num-paths = <1>;
+		qcom,msm-bus,vectors-KBps =
+			<100 512 0 0>,
+			<100 512 600000 800000>; /* ~4.6Gbps (MCS12) */
+		qcom,use-ext-supply;
+		vdd-supply= <&pm8998_s7>;
+		vddio-supply= <&pm8998_s5>;
+		qcom,use-ext-clocks;
+		clocks = <&clock_gcc clk_rf_clk3>,
+			 <&clock_gcc clk_rf_clk3_pin>;
+		clock-names = "rf_clk3_clk", "rf_clk3_pin_clk";
+	};
+
diff --git a/Documentation/devicetree/bindings/display/msm/sde-rsc.txt b/Documentation/devicetree/bindings/display/msm/sde-rsc.txt
new file mode 100644
index 0000000..7e54fdd
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/msm/sde-rsc.txt
@@ -0,0 +1,72 @@
+Qualcomm Technologies, Inc. SDE RSC
+
+Snapdragon Display Engine implements display rsc to driver
+display core to different modes for power saving
+
+Required properties
+- compatible:			Must be "qcom,sde-rsc"
+- reg:				Offset and length of the register set for
+				the device.
+- reg-names:			Names to refer to register sets related
+				to this device
+
+Optional properties:
+- clocks:			List of phandles for clock device nodes
+				needed by the device.
+- clock-names:			List of clock names needed by the device.
+- vdd-supply:			phandle for vdd regulator device node.
+- qcom,sde-rsc-version:		U32 property represents the rsc version. It helps to
+				select correct sequence for sde rsc based on version.
+- qcom,sde-dram-channels:	U32 property represents the number of channels in the
+				Bus memory controller.
+- qcom,sde-num-nrt-paths:	U32 property represents the number of non-realtime
+				paths in each Bus Scaling Usecase. This value depends on
+				number of AXI ports that are dedicated to non-realtime VBIF
+				for particular chipset.
+				These paths must be defined after rt-paths in
+				"qcom,msm-bus,vectors-KBps" vector request.
+
+Bus Scaling Subnodes:
+- qcom,sde-data-bus:		Property to provide Bus scaling for data bus access for
+				sde blocks.
+
+Bus Scaling Data:
+- qcom,msm-bus,name:		String property describing client name.
+- qcom,msm-bus,active-only:	Boolean context flag for requests in active or
+				dual (active & sleep) contex
+- qcom,msm-bus,num-cases:	This is the number of Bus Scaling use cases
+				defined in the vectors property.
+- qcom,msm-bus,num-paths:	This represents the number of paths in each
+				Bus Scaling Usecase.
+- qcom,msm-bus,vectors-KBps:	* A series of 4 cell properties, with a format
+				of (src, dst, ab, ib) which is defined at
+				Documentation/devicetree/bindings/arm/msm/msm_bus.txt
+				* Current values of src & dst are defined at
+				include/linux/msm-bus-board.h
+Example:
+	sde_rscc {
+		cell-index = <0>;
+		compatible = "qcom,sde-rsc";
+		reg = <0xaf20000 0x1c44>,
+			<0xaf30000 0x3fd4>;
+		reg-names = "drv", "wrapper";
+		clocks = <&clock_mmss clk_mdss_ahb_clk>,
+			<&clock_mmss clk_mdss_axi_clk>;
+		clock-names = "iface_clk", "bus_clk";
+		vdd-supply = <&gdsc_mdss>;
+
+		qcom,sde-rsc-version = <1>;
+		qcom,sde-dram-channels = <2>;
+		qcom,sde-num-nrt-paths = <1>;
+
+		qcom,sde-data-bus {
+		      qcom,msm-bus,name = "sde_rsc";
+		      qcom,msm-bus,active-only;
+		      qcom,msm-bus,num-cases = <3>;
+		      qcom,msm-bus,num-paths = <2>;
+		      qcom,msm-bus,vectors-KBps =
+		          <22 512 0 0>, <23 512 0 0>,
+		          <22 512 0 6400000>, <23 512 0 6400000>,
+		          <22 512 0 6400000>, <23 512 0 6400000>;
+		};
+	};
diff --git a/Documentation/devicetree/bindings/drm/msm/mdss-dsi-panel.txt b/Documentation/devicetree/bindings/drm/msm/mdss-dsi-panel.txt
index c7f43bc..62efecc 100644
--- a/Documentation/devicetree/bindings/drm/msm/mdss-dsi-panel.txt
+++ b/Documentation/devicetree/bindings/drm/msm/mdss-dsi-panel.txt
@@ -144,6 +144,13 @@
 					0xff = default value.
 - qcom,mdss-dsi-border-color:		Defines the border color value if border is present.
 					0 = default value.
+- qcom,mdss-dsi-panel-jitter:		An integer value defines the panel jitter timing for rsc
+					backoff time. The jitter configurition causes the early
+					wakeup if panel needs to adjust before vsync.
+					Default jitter value is 5%. Max allowed value is 25%.
+- qcom,mdss-dsi-panel-prefill-lines:	An integer value defines the panel prefill lines required to
+					calculate the backoff time of rsc.
+					Default value is 16 lines. Max allowed value is vtotal.
 - qcom,mdss-dsi-pan-enable-dynamic-fps:	Boolean used to enable change in frame rate dynamically.
 - qcom,mdss-dsi-pan-fps-update:		A string that specifies when to change the frame rate.
 					"dfps_suspend_resume_mode"= FPS change request is
@@ -634,6 +641,8 @@
 						<40 120 128>,
 						<128 240 64>;
 		qcom,mdss-dsi-panel-orientation = "180"
+		qcom,mdss-dsi-panel-jitter = <0x8>;
+		qcom,mdss-dsi-panel-prefill-lines = <0x10>;
 		qcom,mdss-dsi-force-clock-lane-hs;
 		qcom,compression-mode = "dsc";
 		qcom,adjust-timer-wakeup-ms = <1>;
diff --git a/Documentation/devicetree/bindings/qdsp/msm-cdsp-loader.txt b/Documentation/devicetree/bindings/qdsp/msm-cdsp-loader.txt
new file mode 100644
index 0000000..155514f
--- /dev/null
+++ b/Documentation/devicetree/bindings/qdsp/msm-cdsp-loader.txt
@@ -0,0 +1,16 @@
+Qualcomm Technologies, Inc. CDSP Loader Driver
+
+msm-cdsp-loader driver implements the mechanism that allows to load CDSP firmware images.
+
+Required properties:
+
+ - compatible:  This must be "qcom,msm-cdsp-loader".
+ - qcom,proc-img-to-load: CDSP firmware name, must be "cdsp".
+
+Example:
+ The following for sdm660.
+
+	qcom,msm-cdsp-loader {
+		compatible = "qcom,cdsp-loader";
+		qcom,proc-img-to-load = "cdsp";
+	};
diff --git a/Documentation/media/uapi/v4l/pixfmt-007.rst b/Documentation/media/uapi/v4l/pixfmt-007.rst
index 44bb5a7..95a23a2 100644
--- a/Documentation/media/uapi/v4l/pixfmt-007.rst
+++ b/Documentation/media/uapi/v4l/pixfmt-007.rst
@@ -211,7 +211,13 @@
 The :ref:`srgb` standard defines the colorspace used by most webcams
 and computer graphics. The default transfer function is
 ``V4L2_XFER_FUNC_SRGB``. The default Y'CbCr encoding is
-``V4L2_YCBCR_ENC_601``. The default Y'CbCr quantization is full range.
+``V4L2_YCBCR_ENC_601``. The default Y'CbCr quantization is limited range.
+
+Note that the :ref:`sycc` standard specifies full range quantization,
+however all current capture hardware supported by the kernel convert
+R'G'B' to limited range Y'CbCr. So choosing full range as the default
+would break how applications interpret the quantization range.
+
 The chromaticities of the primary colors and the white reference are:
 
 
@@ -276,7 +282,7 @@
 
 Y' is clamped to the range [0…1] and Cb and Cr are clamped to the range
 [-0.5…0.5]. This transform is identical to one defined in SMPTE
-170M/BT.601. The Y'CbCr quantization is full range.
+170M/BT.601. The Y'CbCr quantization is limited range.
 
 
 .. _col-adobergb:
@@ -288,10 +294,15 @@
 graphics that use the AdobeRGB colorspace. This is also known as the
 :ref:`oprgb` standard. The default transfer function is
 ``V4L2_XFER_FUNC_ADOBERGB``. The default Y'CbCr encoding is
-``V4L2_YCBCR_ENC_601``. The default Y'CbCr quantization is full
-range. The chromaticities of the primary colors and the white reference
-are:
+``V4L2_YCBCR_ENC_601``. The default Y'CbCr quantization is limited
+range.
 
+Note that the :ref:`oprgb` standard specifies full range quantization,
+however all current capture hardware supported by the kernel convert
+R'G'B' to limited range Y'CbCr. So choosing full range as the default
+would break how applications interpret the quantization range.
+
+The chromaticities of the primary colors and the white reference are:
 
 
 .. tabularcolumns:: |p{4.4cm}|p{4.4cm}|p{8.7cm}|
@@ -344,7 +355,7 @@
 
 Y' is clamped to the range [0…1] and Cb and Cr are clamped to the range
 [-0.5…0.5]. This transform is identical to one defined in SMPTE
-170M/BT.601. The Y'CbCr quantization is full range.
+170M/BT.601. The Y'CbCr quantization is limited range.
 
 
 .. _col-bt2020:
diff --git a/Makefile b/Makefile
index 18d0eaa..30807c0 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
 VERSION = 4
 PATCHLEVEL = 9
-SUBLEVEL = 9
+SUBLEVEL = 12
 EXTRAVERSION =
 NAME = Roaring Lionus
 
diff --git a/arch/arc/kernel/unaligned.c b/arch/arc/kernel/unaligned.c
index 91ebe38..5f69c3b 100644
--- a/arch/arc/kernel/unaligned.c
+++ b/arch/arc/kernel/unaligned.c
@@ -243,7 +243,7 @@
 
 	/* clear any remanants of delay slot */
 	if (delay_mode(regs)) {
-		regs->ret = regs->bta ~1U;
+		regs->ret = regs->bta & ~1U;
 		regs->status32 &= ~STATUS_DE_MASK;
 	} else {
 		regs->ret += state.instr_len;
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 00be82f..63ea69d 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -548,6 +548,31 @@
 	help
 	  Support for Intel/Marvell's PXA2xx/PXA3xx processor line.
 
+config ARCH_QCOM
+       bool "Qualcomm MSM (non-multiplatform)"
+       select ARCH_REQUIRE_GPIOLIB
+       select CPU_V7
+       select AUTO_ZRELADDR
+       select HAVE_SMP
+       select CLKDEV_LOOKUP
+       select GENERIC_CLOCKEVENTS
+       select GENERIC_ALLOCATOR
+       select ARM_PATCH_PHYS_VIRT
+       select ARM_HAS_SG_CHAIN
+       select ARCH_HAS_OPP
+       select SOC_BUS
+       select MULTI_IRQ_HANDLER
+       select PM_OPP
+       select SPARSE_IRQ
+       select USE_OF
+       select PINCTRL
+       help
+         Support for Qualcomm MSM/QSD based systems.  This runs on the
+         apps processor of the MSM/QSD and depends on a shared memory
+         interface to the modem processor which runs the baseband
+         stack and controls some vital subsystems
+         (clock and power control, etc).
+
 config ARCH_RPC
 	bool "RiscPC"
 	depends on MMU
@@ -1478,7 +1503,7 @@
 config ARCH_NR_GPIO
 	int
 	default 1024 if ARCH_BRCMSTB || ARCH_SHMOBILE || ARCH_TEGRA || \
-		ARCH_ZYNQ
+		ARCH_ZYNQ || ARCH_QCOM
 	default 512 if ARCH_EXYNOS || ARCH_KEYSTONE || SOC_OMAP5 || \
 		SOC_DRA7XX || ARCH_S3C24XX || ARCH_S3C64XX || ARCH_S5PV210
 	default 416 if ARCH_SUNXI
diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug
index 17dcd94..771896f 100644
--- a/arch/arm/Kconfig.debug
+++ b/arch/arm/Kconfig.debug
@@ -1712,7 +1712,7 @@
 config UNCOMPRESS_INCLUDE
 	string
 	default "debug/uncompress.h" if ARCH_MULTIPLATFORM || ARCH_MSM || \
-					PLAT_SAMSUNG || ARM_SINGLE_ARMV7M
+				ARCH_QCOM || PLAT_SAMSUNG || ARM_SINGLE_ARMV7M
 	default "mach/uncompress.h"
 
 config EARLY_PRINTK
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index b53a7b4..f56516c 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -309,6 +309,8 @@
 KBUILD_DTBS := dtbs
 endif
 
+DTSSUBDIR	:= qcom
+
 all:	$(KBUILD_IMAGE) $(KBUILD_DTBS)
 
 boot := arch/arm/boot
@@ -337,13 +339,9 @@
 %.dtb: | scripts
 	$(Q)$(MAKE) $(build)=$(boot)/dts MACHINE=$(MACHINE) $(boot)/dts/$@
 
-PHONY += dtbs dtbs_install
-
-dtbs: prepare scripts
-	$(Q)$(MAKE) $(build)=$(boot)/dts
-
-dtbs_install:
-	$(Q)$(MAKE) $(dtbinst)=$(boot)/dts
+dtbs: scripts
+	$(Q)$(MAKE) $(build)=$(boot)/dts MACHINE=$(MACHINE) dtbs
+	$(foreach DIR, $(DTSSUBDIR), $(Q)$(MAKE) $(build)=$(boot)/dts/$(DIR) MACHINE=$(MACHINE) dtbs)
 
 PHONY += vdso_install
 vdso_install:
@@ -352,7 +350,7 @@
 endif
 
 zImage-dtb: vmlinux scripts dtbs
-	$(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $(boot)/$@
+	$(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) DTSSUBDIR=$(DTSSUBDIR) $(boot)/$@
 
 # We use MRPROPER_FILES and CLEAN_FILES now
 archclean:
diff --git a/arch/arm/boot/Makefile b/arch/arm/boot/Makefile
index da75630..4175dfe 100644
--- a/arch/arm/boot/Makefile
+++ b/arch/arm/boot/Makefile
@@ -13,10 +13,11 @@
 
 OBJCOPYFLAGS	:=-O binary -R .comment -S
 
-ifneq ($(MACHINE),)
-include $(MACHINE)/Makefile.boot
-endif
 include $(srctree)/arch/arm/boot/dts/Makefile
+ifneq ($(DTSSUBDIR),)
+DTSSUBDIR_INCS=$(foreach DIR, $(DTSSUBDIR), $(addsuffix /Makefile, $(addprefix $(srctree)/arch/arm/boot/dts/, $(DIR))))
+include $(DTSSUBDIR_INCS)
+endif
 
 # Note: the following conditions must always be true:
 #   ZRELADDR == virt_to_phys(PAGE_OFFSET + TEXT_OFFSET)
diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
index 54f95d3..4266ea6 100644
--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
@@ -970,5 +970,10 @@
 targets += dtbs dtbs_install
 targets += $(DTB_LIST)
 
+ifeq ($(CONFIG_ARM64),y)
 always		:= $(DTB_LIST)
+else
+dtbs: $(addprefix $(obj)/, $(DTB_LIST))
+	$(Q)rm -f $(obj)/../*.dtb
+endif
 clean-files	:= *.dtb
diff --git a/arch/arm/boot/dts/imx6dl.dtsi b/arch/arm/boot/dts/imx6dl.dtsi
index 1ade195..7aa120f 100644
--- a/arch/arm/boot/dts/imx6dl.dtsi
+++ b/arch/arm/boot/dts/imx6dl.dtsi
@@ -137,7 +137,7 @@
 &gpio4 {
 	gpio-ranges = <&iomuxc  5 136 1>, <&iomuxc  6 145 1>, <&iomuxc  7 150 1>,
 		      <&iomuxc  8 146 1>, <&iomuxc  9 151 1>, <&iomuxc 10 147 1>,
-		      <&iomuxc 11 151 1>, <&iomuxc 12 148 1>, <&iomuxc 13 153 1>,
+		      <&iomuxc 11 152 1>, <&iomuxc 12 148 1>, <&iomuxc 13 153 1>,
 		      <&iomuxc 14 149 1>, <&iomuxc 15 154 1>, <&iomuxc 16  39 7>,
 		      <&iomuxc 23  56 1>, <&iomuxc 24  61 7>, <&iomuxc 31  46 1>;
 };
diff --git a/arch/arm/boot/dts/qcom/Makefile b/arch/arm/boot/dts/qcom/Makefile
new file mode 100644
index 0000000..14422e5
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/Makefile
@@ -0,0 +1,16 @@
+
+
+
+ifeq ($(CONFIG_ARM64),y)
+always          := $(dtb-y)
+subdir-y        := $(dts-dirs)
+else
+targets += dtbs
+targets += $(addprefix ../, $(dtb-y))
+
+$(obj)/../%.dtb: $(src)/%.dts FORCE
+	$(call if_changed_dep,dtc)
+
+dtbs: $(addprefix $(obj)/../,$(dtb-y))
+endif
+clean-files := *.dtb
diff --git a/arch/arm/include/asm/cacheflush.h b/arch/arm/include/asm/cacheflush.h
index bdd283b..58c6398 100644
--- a/arch/arm/include/asm/cacheflush.h
+++ b/arch/arm/include/asm/cacheflush.h
@@ -94,6 +94,21 @@
  *	DMA Cache Coherency
  *	===================
  *
+ *	dma_inv_range(start, end)
+ *
+ *		Invalidate (discard) the specified virtual address range.
+ *		May not write back any entries.  If 'start' or 'end'
+ *		are not cache line aligned, those lines must be written
+ *		back.
+ *		- start  - virtual start address
+ *		- end    - virtual end address
+ *
+ *	dma_clean_range(start, end)
+ *
+ *		Clean (write back) the specified virtual address range.
+ *		- start  - virtual start address
+ *		- end    - virtual end address
+ *
  *	dma_flush_range(start, end)
  *
  *		Clean and invalidate the specified virtual address range.
@@ -115,6 +130,8 @@
 	void (*dma_map_area)(const void *, size_t, int);
 	void (*dma_unmap_area)(const void *, size_t, int);
 
+	void (*dma_inv_range)(const void *, const void *);
+	void (*dma_clean_range)(const void *, const void *);
 	void (*dma_flush_range)(const void *, const void *);
 };
 
@@ -140,6 +157,8 @@
  * is visible to DMA, or data written by DMA to system memory is
  * visible to the CPU.
  */
+#define dmac_inv_range			cpu_cache.dma_inv_range
+#define dmac_clean_range		cpu_cache.dma_clean_range
 #define dmac_flush_range		cpu_cache.dma_flush_range
 
 #else
@@ -159,6 +178,8 @@
  * is visible to DMA, or data written by DMA to system memory is
  * visible to the CPU.
  */
+extern void dmac_inv_range(const void *, const void *);
+extern void dmac_clean_range(const void *, const void *);
 extern void dmac_flush_range(const void *, const void *);
 
 #endif
diff --git a/arch/arm/include/asm/glue-cache.h b/arch/arm/include/asm/glue-cache.h
index 01c3d92..d14f310 100644
--- a/arch/arm/include/asm/glue-cache.h
+++ b/arch/arm/include/asm/glue-cache.h
@@ -155,6 +155,8 @@
 #define __cpuc_flush_dcache_area	__glue(_CACHE,_flush_kern_dcache_area)
 
 #define dmac_flush_range		__glue(_CACHE,_dma_flush_range)
+#define dmac_inv_range			__glue(_CACHE, _dma_inv_range)
+#define dmac_clean_range		__glue(_CACHE, _dma_clean_range)
 #endif
 
 #endif
diff --git a/arch/arm/include/asm/io.h b/arch/arm/include/asm/io.h
index 021692c..66003a8 100644
--- a/arch/arm/include/asm/io.h
+++ b/arch/arm/include/asm/io.h
@@ -29,6 +29,7 @@
 #include <asm/byteorder.h>
 #include <asm/memory.h>
 #include <asm-generic/pci_iomap.h>
+#include <linux/msm_rtb.h>
 #include <xen/xen.h>
 
 /*
@@ -62,23 +63,21 @@
  * the bus. Rather than special-case the machine, just let the compiler
  * generate the access for CPUs prior to ARMv6.
  */
-#define __raw_readw(a)         (__chk_io_ptr(a), *(volatile unsigned short __force *)(a))
-#define __raw_writew(v,a)      ((void)(__chk_io_ptr(a), *(volatile unsigned short __force *)(a) = (v)))
+#define __raw_readw_no_log(a)         (__chk_io_ptr(a), *(volatile unsigned short __force *)(a))
+#define __raw_writew_no_log(v, a)      ((void)(__chk_io_ptr(a), *(volatile unsigned short __force *)(a) = (v)))
 #else
 /*
  * When running under a hypervisor, we want to avoid I/O accesses with
  * writeback addressing modes as these incur a significant performance
  * overhead (the address generation must be emulated in software).
  */
-#define __raw_writew __raw_writew
-static inline void __raw_writew(u16 val, volatile void __iomem *addr)
+static inline void __raw_writew_no_log(u16 val, volatile void __iomem *addr)
 {
 	asm volatile("strh %1, %0"
 		     : : "Q" (*(volatile u16 __force *)addr), "r" (val));
 }
 
-#define __raw_readw __raw_readw
-static inline u16 __raw_readw(const volatile void __iomem *addr)
+static inline u16 __raw_readw_no_log(const volatile void __iomem *addr)
 {
 	u16 val;
 	asm volatile("ldrh %0, %1"
@@ -88,22 +87,30 @@
 }
 #endif
 
-#define __raw_writeb __raw_writeb
-static inline void __raw_writeb(u8 val, volatile void __iomem *addr)
+static inline void __raw_writeb_no_log(u8 val, volatile void __iomem *addr)
 {
 	asm volatile("strb %1, %0"
 		     : : "Qo" (*(volatile u8 __force *)addr), "r" (val));
 }
 
-#define __raw_writel __raw_writel
-static inline void __raw_writel(u32 val, volatile void __iomem *addr)
+static inline void __raw_writel_no_log(u32 val, volatile void __iomem *addr)
 {
 	asm volatile("str %1, %0"
 		     : : "Qo" (*(volatile u32 __force *)addr), "r" (val));
 }
 
-#define __raw_readb __raw_readb
-static inline u8 __raw_readb(const volatile void __iomem *addr)
+static inline void __raw_writeq_no_log(u64 val, volatile void __iomem *addr)
+{
+	register u64 v asm ("r2");
+
+	v = val;
+
+	asm volatile("strd %1, %0"
+		     : "+Qo" (*(volatile u64 __force *)addr)
+		     : "r" (v));
+}
+
+static inline u8 __raw_readb_no_log(const volatile void __iomem *addr)
 {
 	u8 val;
 	asm volatile("ldrb %0, %1"
@@ -112,8 +119,7 @@
 	return val;
 }
 
-#define __raw_readl __raw_readl
-static inline u32 __raw_readl(const volatile void __iomem *addr)
+static inline u32 __raw_readl_no_log(const volatile void __iomem *addr)
 {
 	u32 val;
 	asm volatile("ldr %0, %1"
@@ -122,6 +128,58 @@
 	return val;
 }
 
+static inline u64 __raw_readq_no_log(const volatile void __iomem *addr)
+{
+	register u64 val asm ("r2");
+
+	asm volatile("ldrd %1, %0"
+		     : "+Qo" (*(volatile u64 __force *)addr),
+		       "=r" (val));
+	return val;
+}
+
+/*
+ * There may be cases when clients don't want to support or can't support the
+ * logging. The appropriate functions can be used but clients should carefully
+ * consider why they can't support the logging.
+ */
+
+#define __raw_write_logged(v, a, _t)	({ \
+	int _ret; \
+	volatile void __iomem *_a = (a); \
+	void *_addr = (void __force *)(_a); \
+	_ret = uncached_logk(LOGK_WRITEL, _addr); \
+	ETB_WAYPOINT; \
+	__raw_write##_t##_no_log((v), _a); \
+	if (_ret) \
+		LOG_BARRIER; \
+	})
+
+
+#define __raw_writeb(v, a)	__raw_write_logged((v), (a), b)
+#define __raw_writew(v, a)	__raw_write_logged((v), (a), w)
+#define __raw_writel(v, a)	__raw_write_logged((v), (a), l)
+#define __raw_writeq(v, a)	__raw_write_logged((v), (a), q)
+
+#define __raw_read_logged(a, _l, _t)		({ \
+	unsigned _t __a; \
+	const volatile void __iomem *_a = (a); \
+	void *_addr = (void __force *)(_a); \
+	int _ret; \
+	_ret = uncached_logk(LOGK_READL, _addr); \
+	ETB_WAYPOINT; \
+	__a = __raw_read##_l##_no_log(_a);\
+	if (_ret) \
+		LOG_BARRIER; \
+	__a; \
+	})
+
+
+#define __raw_readb(a)		__raw_read_logged((a), b, char)
+#define __raw_readw(a)		__raw_read_logged((a), w, short)
+#define __raw_readl(a)		__raw_read_logged((a), l, int)
+#define __raw_readq(a)		__raw_read_logged((a), q, long long)
+
 /*
  * Architecture ioremap implementation.
  */
@@ -291,18 +349,32 @@
 					__raw_readw(c)); __r; })
 #define readl_relaxed(c) ({ u32 __r = le32_to_cpu((__force __le32) \
 					__raw_readl(c)); __r; })
+#define readq_relaxed(c) ({ u64 __r = le64_to_cpu((__force __le64) \
+					__raw_readq(c)); __r; })
+#define readb_relaxed_no_log(c)	({ u8 __r = __raw_readb_no_log(c); __r; })
+#define readl_relaxed_no_log(c) ({ u32 __r = le32_to_cpu((__force __le32) \
+					__raw_readl_no_log(c)); __r; })
+#define readq_relaxed_no_log(c) ({ u64 __r = le64_to_cpu((__force __le64) \
+					__raw_readq_no_log(c)); __r; })
 
-#define writeb_relaxed(v,c)	__raw_writeb(v,c)
-#define writew_relaxed(v,c)	__raw_writew((__force u16) cpu_to_le16(v),c)
-#define writel_relaxed(v,c)	__raw_writel((__force u32) cpu_to_le32(v),c)
+
+#define writeb_relaxed(v, c)	__raw_writeb(v, c)
+#define writew_relaxed(v, c)	__raw_writew((__force u16) cpu_to_le16(v), c)
+#define writel_relaxed(v, c)	__raw_writel((__force u32) cpu_to_le32(v), c)
+#define writeq_relaxed(v, c)	__raw_writeq((__force u64) cpu_to_le64(v), c)
+#define writeb_relaxed_no_log(v, c)	((void)__raw_writeb_no_log((v), (c)))
+#define writel_relaxed_no_log(v, c) __raw_writel_no_log((__force u32) cpu_to_le32(v), c)
+#define writeq_relaxed_no_log(v, c) __raw_writeq_no_log((__force u64) cpu_to_le64(v), c)
 
 #define readb(c)		({ u8  __v = readb_relaxed(c); __iormb(); __v; })
 #define readw(c)		({ u16 __v = readw_relaxed(c); __iormb(); __v; })
 #define readl(c)		({ u32 __v = readl_relaxed(c); __iormb(); __v; })
+#define readq(c)		({ u64 __v = readq_relaxed(c); __iormb(); __v; })
 
 #define writeb(v,c)		({ __iowmb(); writeb_relaxed(v,c); })
 #define writew(v,c)		({ __iowmb(); writew_relaxed(v,c); })
 #define writel(v,c)		({ __iowmb(); writel_relaxed(v,c); })
+#define writeq(v, c)		({ __iowmb(); writeq_relaxed(v, c); })
 
 #define readsb(p,d,l)		__raw_readsb(p,d,l)
 #define readsw(p,d,l)		__raw_readsw(p,d,l)
@@ -410,6 +482,23 @@
 
 void iounmap(volatile void __iomem *iomem_cookie);
 #define iounmap iounmap
+/*
+ * io{read,write}{8,16,32,64} macros
+ */
+#ifndef ioread8
+#define ioread8(p)	({ unsigned int __v = __raw_readb(p); __iormb(); __v; })
+#define ioread16(p)	({ unsigned int __v = le16_to_cpu((__force __le16)__raw_readw(p)); __iormb(); __v; })
+#define ioread32(p)	({ unsigned int __v = le32_to_cpu((__force __le32)__raw_readl(p)); __iormb(); __v; })
+#define ioread64(p)	({ unsigned int __v = le64_to_cpu((__force __le64)__raw_readq(p)); __iormb(); __v; })
+
+#define ioread64be(p)	({ unsigned int __v = be64_to_cpu((__force __be64)__raw_readq(p)); __iormb(); __v; })
+
+#define iowrite8(v, p)	({ __iowmb(); __raw_writeb(v, p); })
+#define iowrite16(v, p)	({ __iowmb(); __raw_writew((__force __u16)cpu_to_le16(v), p); })
+#define iowrite32(v, p)	({ __iowmb(); __raw_writel((__force __u32)cpu_to_le32(v), p); })
+#define iowrite64(v, p)	({ __iowmb(); __raw_writeq((__force __u64)cpu_to_le64(v), p); })
+
+#define iowrite64be(v, p) ({ __iowmb(); __raw_writeq((__force __u64)cpu_to_be64(v), p); })
 
 void *arch_memremap_wb(phys_addr_t phys_addr, size_t size);
 #define arch_memremap_wb arch_memremap_wb
@@ -431,6 +520,7 @@
 #define ioport_unmap ioport_unmap
 extern void ioport_unmap(void __iomem *addr);
 #endif
+#endif
 
 struct pci_dev;
 
diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c
index ce131ed..ae738a6 100644
--- a/arch/arm/kernel/ptrace.c
+++ b/arch/arm/kernel/ptrace.c
@@ -600,7 +600,7 @@
 		   const void *kbuf, const void __user *ubuf)
 {
 	int ret;
-	struct pt_regs newregs;
+	struct pt_regs newregs = *task_pt_regs(target);
 
 	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
 				 &newregs,
diff --git a/arch/arm/kernel/topology.c b/arch/arm/kernel/topology.c
index 792340f..b27bef5 100644
--- a/arch/arm/kernel/topology.c
+++ b/arch/arm/kernel/topology.c
@@ -58,6 +58,144 @@
 	per_cpu(cpu_scale, cpu) = capacity;
 }
 
+static int __init get_cpu_for_node(struct device_node *node)
+{
+	struct device_node *cpu_node;
+	int cpu;
+
+	cpu_node = of_parse_phandle(node, "cpu", 0);
+	if (!cpu_node)
+		return -EINVAL;
+
+	for_each_possible_cpu(cpu) {
+		if (of_get_cpu_node(cpu, NULL) == cpu_node) {
+			of_node_put(cpu_node);
+			return cpu;
+		}
+	}
+
+	pr_crit("Unable to find CPU node for %s\n", cpu_node->full_name);
+
+	of_node_put(cpu_node);
+	return -EINVAL;
+}
+
+static int __init parse_core(struct device_node *core, int cluster_id,
+			     int core_id)
+{
+	char name[10];
+	bool leaf = true;
+	int i = 0;
+	int cpu;
+	struct device_node *t;
+
+	do {
+		snprintf(name, sizeof(name), "thread%d", i);
+		t = of_get_child_by_name(core, name);
+		if (t) {
+			leaf = false;
+			cpu = get_cpu_for_node(t);
+			if (cpu >= 0) {
+				cpu_topology[cpu].socket_id = cluster_id;
+				cpu_topology[cpu].core_id = core_id;
+				cpu_topology[cpu].thread_id = i;
+			} else {
+				pr_err("%s: Can't get CPU for thread\n",
+					t->full_name);
+				of_node_put(t);
+				return -EINVAL;
+			}
+			of_node_put(t);
+		}
+		i++;
+	} while (t);
+
+	cpu = get_cpu_for_node(core);
+	if (cpu >= 0) {
+		if (!leaf) {
+			pr_err("%s: Core has both threads and CPU\n",
+				core->full_name);
+			return -EINVAL;
+		}
+
+		cpu_topology[cpu].socket_id = cluster_id;
+		cpu_topology[cpu].core_id = core_id;
+	} else if (leaf) {
+		pr_err("%s: Can't get CPU for leaf core\n", core->full_name);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int __init parse_cluster(struct device_node *cluster, int depth)
+{
+	static int cluster_id __initdata;
+	char name[10];
+	bool leaf = true;
+	bool has_cores = false;
+	struct device_node *c;
+	int core_id = 0;
+	int i, ret;
+
+	/*
+	 * First check for child clusters; we currently ignore any
+	 * information about the nesting of clusters and present the
+	 * scheduler with a flat list of them.
+	 */
+	i = 0;
+	do {
+		snprintf(name, sizeof(name), "cluster%d", i);
+		c = of_get_child_by_name(cluster, name);
+		if (c) {
+			leaf = false;
+			ret = parse_cluster(c, depth + 1);
+			of_node_put(c);
+			if (ret != 0)
+				return ret;
+		}
+		i++;
+	} while (c);
+
+	/* Now check for cores */
+	i = 0;
+	do {
+		snprintf(name, sizeof(name), "core%d", i);
+		c = of_get_child_by_name(cluster, name);
+		if (c) {
+			has_cores = true;
+
+			if (depth == 0) {
+				pr_err("%s: cpu-map children should be clusters\n",
+					c->full_name);
+				of_node_put(c);
+				return -EINVAL;
+		}
+
+		if (leaf) {
+			ret = parse_core(c, cluster_id, core_id++);
+		} else {
+			pr_err("%s: Non-leaf cluster with core %s\n",
+				cluster->full_name, name);
+			ret = -EINVAL;
+		}
+
+		of_node_put(c);
+		if (ret != 0)
+			return ret;
+		}
+		i++;
+	} while (c);
+
+	if (leaf && !has_cores)
+		pr_warn("%s: empty cluster\n", cluster->full_name);
+
+	if (leaf)
+		cluster_id++;
+
+	return 0;
+}
+
 #ifdef CONFIG_OF
 struct cpu_efficiency {
 	const char *compatible;
@@ -93,14 +231,40 @@
  * 'average' CPU is of middle capacity. Also see the comments near
  * table_efficiency[] and update_cpu_capacity().
  */
-static void __init parse_dt_topology(void)
+static int __init parse_dt_topology(void)
 {
 	const struct cpu_efficiency *cpu_eff;
-	struct device_node *cn = NULL;
+	struct device_node *cn = NULL, *map;
 	unsigned long min_capacity = ULONG_MAX;
 	unsigned long max_capacity = 0;
 	unsigned long capacity = 0;
-	int cpu = 0;
+	int cpu = 0, ret = 0;
+
+	cn = of_find_node_by_path("/cpus");
+	if (!cn) {
+		pr_err("No CPU information found in DT\n");
+		return 0;
+	}
+
+	/*
+	 * When topology is provided cpu-map is essentially a root
+	 * cluster with restricted subnodes.
+	 */
+	map = of_get_child_by_name(cn, "cpu-map");
+	if (!map)
+		goto out;
+
+	ret = parse_cluster(map, 0);
+	if (ret != 0)
+		goto out_map;
+
+	/*
+	 * Check that all cores are in the topology; the SMP code will
+	 * only mark cores described in the DT as possible.
+	 */
+	for_each_possible_cpu(cpu)
+		if (cpu_topology[cpu].socket_id == -1)
+			ret = -EINVAL;
 
 	__cpu_capacity = kcalloc(nr_cpu_ids, sizeof(*__cpu_capacity),
 				 GFP_NOWAIT);
@@ -156,7 +320,11 @@
 	else
 		middle_capacity = ((max_capacity / 3)
 				>> (SCHED_CAPACITY_SHIFT-1)) + 1;
-
+out_map:
+	of_node_put(map);
+out:
+	of_node_put(cn);
+	return ret;
 }
 
 static const struct sched_group_energy * const cpu_core_energy(int cpu);
@@ -182,7 +350,7 @@
 }
 
 #else
-static inline void parse_dt_topology(void) {}
+static inline int parse_dt_topology(void) {}
 static inline void update_cpu_capacity(unsigned int cpuid) {}
 #endif
 
@@ -242,9 +410,8 @@
 	struct cputopo_arm *cpuid_topo = &cpu_topology[cpuid];
 	unsigned int mpidr;
 
-	/* If the cpu topology has been already set, just return */
 	if (cpuid_topo->core_id != -1)
-		return;
+		goto topology_populated;
 
 	mpidr = read_cpuid_mpidr();
 
@@ -277,14 +444,14 @@
 		cpuid_topo->socket_id = -1;
 	}
 
-	update_siblings_masks(cpuid);
-
-	update_cpu_capacity(cpuid);
-
-	pr_info("CPU%u: thread %d, cpu %d, socket %d, mpidr %x\n",
+	pr_info("CPU%u: thread %d, cpu %d, cluster %d, mpidr %x\n",
 		cpuid, cpu_topology[cpuid].thread_id,
 		cpu_topology[cpuid].core_id,
 		cpu_topology[cpuid].socket_id, mpidr);
+
+topology_populated:
+	update_siblings_masks(cpuid);
+	update_cpu_capacity(cpuid);
 }
 
 /*
@@ -442,7 +609,17 @@
 	}
 	smp_wmb();
 
-	parse_dt_topology();
+	if (parse_dt_topology()) {
+		struct cputopo_arm *cpu_topo = &(cpu_topology[cpu]);
+
+		cpu_topo->thread_id = -1;
+		cpu_topo->core_id =  -1;
+		cpu_topo->socket_id = -1;
+		cpumask_clear(&cpu_topo->core_sibling);
+		cpumask_clear(&cpu_topo->thread_sibling);
+
+		set_capacity_scale(cpu, SCHED_CAPACITY_SCALE);
+	}
 
 	for_each_possible_cpu(cpu)
 		update_siblings_masks(cpu);
diff --git a/arch/arm/lib/getuser.S b/arch/arm/lib/getuser.S
index 8ecfd15..df73914 100644
--- a/arch/arm/lib/getuser.S
+++ b/arch/arm/lib/getuser.S
@@ -67,7 +67,7 @@
 ENDPROC(__get_user_4)
 
 ENTRY(__get_user_8)
-	check_uaccess r0, 8, r1, r2, __get_user_bad
+	check_uaccess r0, 8, r1, r2, __get_user_bad8
 #ifdef CONFIG_THUMB2_KERNEL
 5: TUSER(ldr)	r2, [r0]
 6: TUSER(ldr)	r3, [r0, #4]
diff --git a/arch/arm/mach-qcom/Kconfig b/arch/arm/mach-qcom/Kconfig
index 46ed10a..6e6ebcb 100644
--- a/arch/arm/mach-qcom/Kconfig
+++ b/arch/arm/mach-qcom/Kconfig
@@ -1,30 +1,46 @@
-menuconfig ARCH_QCOM
-	bool "Qualcomm Support"
-	depends on ARCH_MULTI_V7
-	select ARCH_SUPPORTS_BIG_ENDIAN
-	select ARM_GIC
-	select ARM_AMBA
-	select PINCTRL
-	select QCOM_SCM if SMP
-	help
-	  Support for Qualcomm's devicetree based systems.
-
 if ARCH_QCOM
+menu "QCOM SoC Type"
 
 config ARCH_MSM8X60
 	bool "Enable support for MSM8X60"
+	select ARCH_SUPPORTS_BIG_ENDIAN
+	select ARM_GIC
+	select ARM_AMBA
+	select QCOM_SCM if SMP
 	select CLKSRC_QCOM
+	select CLKSRC_OF
+	select COMMON_CLK
 
 config ARCH_MSM8960
 	bool "Enable support for MSM8960"
 	select CLKSRC_QCOM
+	select ARCH_SUPPORTS_BIG_ENDIAN
+	select ARM_GIC
+	select ARM_AMBA
+	select QCOM_SCM if SMP
+	select CLKSRC_OF
+	select COMMON_CLK
+
 
 config ARCH_MSM8974
 	bool "Enable support for MSM8974"
 	select HAVE_ARM_ARCH_TIMER
+	select ARCH_SUPPORTS_BIG_ENDIAN
+	select ARM_GIC
+	select ARM_AMBA
+	select QCOM_SCM if SMP
+	select CLKSRC_OF
+	select COMMON_CLK
 
 config ARCH_MDM9615
 	bool "Enable support for MDM9615"
 	select CLKSRC_QCOM
+	select ARCH_SUPPORTS_BIG_ENDIAN
+	select ARM_GIC
+	select ARM_AMBA
+	select QCOM_SCM if SMP
+	select CLKSRC_OF
+	select COMMON_CLK
 
+endmenu
 endif
diff --git a/arch/arm/mach-qcom/Makefile b/arch/arm/mach-qcom/Makefile
index 12878e9..e7ffa04 100644
--- a/arch/arm/mach-qcom/Makefile
+++ b/arch/arm/mach-qcom/Makefile
@@ -1 +1,2 @@
+obj-$(CONFIG_USE_OF) += board-dt.o
 obj-$(CONFIG_SMP)	+= platsmp.o
diff --git a/arch/arm/mach-qcom/board-dt.c b/arch/arm/mach-qcom/board-dt.c
new file mode 100644
index 0000000..866cb74
--- /dev/null
+++ b/arch/arm/mach-qcom/board-dt.c
@@ -0,0 +1,28 @@
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/of_fdt.h>
+
+#include "board-dt.h"
+
+void __init board_dt_populate(struct of_dev_auxdata *adata)
+{
+	of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
+
+	/* Explicitly parent the /soc devices to the root node to preserve
+	 * the kernel ABI (sysfs structure, etc) until userspace is updated
+	 */
+	of_platform_populate(of_find_node_by_path("/soc"),
+			     of_default_bus_match_table, adata, NULL);
+}
diff --git a/arch/arm/mach-qcom/board-dt.h b/arch/arm/mach-qcom/board-dt.h
new file mode 100644
index 0000000..0f36e04
--- /dev/null
+++ b/arch/arm/mach-qcom/board-dt.h
@@ -0,0 +1,15 @@
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/of_platform.h>
+
+void __init board_dt_populate(struct of_dev_auxdata *adata);
diff --git a/arch/arm/mm/cache-v7.S b/arch/arm/mm/cache-v7.S
index a134d8a..2ddf364 100644
--- a/arch/arm/mm/cache-v7.S
+++ b/arch/arm/mm/cache-v7.S
@@ -349,7 +349,7 @@
  *	- start   - virtual start address of region
  *	- end     - virtual end address of region
  */
-v7_dma_inv_range:
+ENTRY(v7_dma_inv_range)
 	dcache_line_size r2, r3
 	sub	r3, r2, #1
 	tst	r0, r3
@@ -377,7 +377,7 @@
  *	- start   - virtual start address of region
  *	- end     - virtual end address of region
  */
-v7_dma_clean_range:
+ENTRY(v7_dma_clean_range)
 	dcache_line_size r2, r3
 	sub	r3, r2, #1
 	bic	r0, r0, r3
diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c
index 217ddb2..aec74bf 100644
--- a/arch/arm/mm/fault.c
+++ b/arch/arm/mm/fault.c
@@ -610,9 +610,9 @@
 
 void __init early_abt_enable(void)
 {
-	fsr_info[22].fn = early_abort_handler;
+	fsr_info[FSR_FS_AEA].fn = early_abort_handler;
 	local_abt_enable();
-	fsr_info[22].fn = do_bad;
+	fsr_info[FSR_FS_AEA].fn = do_bad;
 }
 
 #ifndef CONFIG_ARM_LPAE
diff --git a/arch/arm/mm/fault.h b/arch/arm/mm/fault.h
index 67532f2..afc1f84 100644
--- a/arch/arm/mm/fault.h
+++ b/arch/arm/mm/fault.h
@@ -11,11 +11,15 @@
 #define FSR_FS5_0		(0x3f)
 
 #ifdef CONFIG_ARM_LPAE
+#define FSR_FS_AEA		17
+
 static inline int fsr_fs(unsigned int fsr)
 {
 	return fsr & FSR_FS5_0;
 }
 #else
+#define FSR_FS_AEA		22
+
 static inline int fsr_fs(unsigned int fsr)
 {
 	return (fsr & FSR_FS3_0) | (fsr & FSR_FS4) >> 6;
diff --git a/arch/arm/mm/proc-macros.S b/arch/arm/mm/proc-macros.S
index 0d40c28..60bd916 100644
--- a/arch/arm/mm/proc-macros.S
+++ b/arch/arm/mm/proc-macros.S
@@ -325,6 +325,8 @@
 	.long	\name\()_flush_kern_dcache_area
 	.long	\name\()_dma_map_area
 	.long	\name\()_dma_unmap_area
+	.long   \name\()_dma_inv_range
+	.long   \name\()_dma_clean_range
 	.long	\name\()_dma_flush_range
 	.size	\name\()_cache_fns, . - \name\()_cache_fns
 .endm
diff --git a/arch/arm/mm/proc-syms.c b/arch/arm/mm/proc-syms.c
index 054b491..70e8b7d 100644
--- a/arch/arm/mm/proc-syms.c
+++ b/arch/arm/mm/proc-syms.c
@@ -30,6 +30,9 @@
 EXPORT_SYMBOL(__cpuc_flush_user_range);
 EXPORT_SYMBOL(__cpuc_coherent_kern_range);
 EXPORT_SYMBOL(__cpuc_flush_dcache_area);
+EXPORT_SYMBOL(dmac_inv_range);
+EXPORT_SYMBOL(dmac_clean_range);
+EXPORT_SYMBOL(dmac_flush_range);
 #else
 EXPORT_SYMBOL(cpu_cache);
 #endif
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 0b50576..6293973 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -838,7 +838,7 @@
 endif
 
 config ARM64_SW_TTBR0_PAN
-	bool "Emulate Priviledged Access Never using TTBR0_EL1 switching"
+	bool "Emulate Privileged Access Never using TTBR0_EL1 switching"
 	help
 	  Enabling this option prevents the kernel from accessing
 	  user-space memory directly by pointing TTBR0_EL1 to a reserved
diff --git a/arch/arm64/boot/dts/qcom/sdm845-coresight.dtsi b/arch/arm64/boot/dts/qcom/sdm845-coresight.dtsi
index d36c0ff..e7ff343 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-coresight.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-coresight.dtsi
@@ -13,11 +13,19 @@
 &soc {
 
 	replicator_qdss: replicator@6046000 {
-		compatible = "arm,coresight-replicator";
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b909>;
+
+		reg = <0x6046000 0x1000>;
+		reg-names = "replicator-base";
 
 		coresight-name = "coresight-replicator";
 
-		ports{
+		clocks = <&clock_gcc RPMH_QDSS_CLK>,
+			 <&clock_gcc RPMH_QDSS_A_CLK>;
+		clock-names = "apb_pclk", "core_a_clk";
+
+		ports {
 			#address-cells = <1>;
 			#size-cells = <0>;
 
@@ -40,7 +48,215 @@
 		};
 	};
 
-	tmc_etr:tmc@6048000 {
+	replicator_swao: replicator@6b0a000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b909>;
+
+		reg = <0x6b0a000 0x1000>;
+		reg-names = "replicator-base";
+
+		coresight-name = "coresight-replicator-swao";
+
+		clocks = <&clock_gcc RPMH_QDSS_CLK>,
+			 <&clock_gcc RPMH_QDSS_A_CLK>;
+		clock-names = "apb_pclk", "core_a_clk";
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port@0 {
+				reg = <0>;
+				replicator_swao_in_tmc_etf_swao: endpoint {
+					slave-mode;
+					remote-endpoint =
+						<&tmc_etf_swao_out_replicator>;
+				};
+			};
+
+			/* Always have EUD before funnel leading to ETR. If both
+			 * sink are active we need to give preference to EUD
+			 * over ETR
+			 */
+			port@1 {
+				reg = <1>;
+				replicator_swao_out_eud: endpoint {
+					remote-endpoint =
+					  <&eud_in_replicator_swao>;
+				};
+			};
+
+			port@2 {
+				reg = <0>;
+				replicator_swao_out_funnel_in2: endpoint {
+					remote-endpoint =
+					  <&funnel_in2_in_replicator_swao>;
+				};
+			};
+
+		};
+	};
+
+	tmc_etf_swao: tmc@6b09000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b961>;
+
+		reg = <0x6b09000 0x1000>;
+		reg-names = "tmc-base";
+
+		coresight-name = "coresight-tmc-etf-swao";
+
+		clocks = <&clock_gcc RPMH_QDSS_CLK>,
+			 <&clock_gcc RPMH_QDSS_A_CLK>;
+		clock-names = "apb_pclk", "core_a_clk";
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port@0 {
+				reg = <0>;
+				tmc_etf_swao_out_replicator: endpoint {
+					remote-endpoint=
+					  <&replicator_swao_in_tmc_etf_swao>;
+				};
+			};
+
+			port@1 {
+				reg = <0>;
+				tmc_etf_swao_in_funnel_swao: endpoint {
+					slave-mode;
+					remote-endpoint=
+					  <&funnel_swao_out_tmc_etf_swao>;
+				};
+			};
+		};
+
+	};
+
+	funnel_swao:funnel@0x6b08000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b908>;
+
+		reg = <0x6b08000 0x1000>;
+		reg-names = "funnel-base";
+
+		coresight-name = "coresight-funnel-swao";
+
+		clocks = <&clock_gcc RPMH_QDSS_CLK>,
+			 <&clock_gcc RPMH_QDSS_A_CLK>;
+		clock-names = "apb_pclk", "core_a_clk";
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port@0 {
+				reg = <0>;
+				funnel_swao_out_tmc_etf_swao: endpoint {
+					remote-endpoint =
+						<&tmc_etf_swao_in_funnel_swao>;
+				};
+			};
+
+			port@1 {
+				reg = <7>;
+				funnel_swao_in_tpda_swao: endpoint {
+					slave-mode;
+					remote-endpoint=
+						<&tpda_swao_out_funnel_swao>;
+				};
+			};
+		};
+	};
+
+	tpda_swao: tpda@6b01000 {
+		compatible = "qcom,coresight-tpda";
+		reg = <0x6b01000 0x1000>;
+		reg-names = "tpda-base";
+
+		coresight-name = "coresight-tpda-swao";
+
+		qcom,tpda-atid = <71>;
+		qcom,dsb-elem-size = <1 32>;
+		qcom,cmb-elem-size = <0 64>;
+
+		clocks = <&clock_gcc RPMH_QDSS_CLK>,
+			 <&clock_gcc RPMH_QDSS_A_CLK>;
+		clock-names = "core_clk", "core_a_clk";
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port@0 {
+				reg = <0>;
+				tpda_swao_out_funnel_swao: endpoint {
+					remote-endpoint =
+						<&funnel_swao_in_tpda_swao>;
+				};
+
+			};
+
+			port@1 {
+				reg = <0>;
+				tpda_swao_in_tpdm_swao0: endpoint {
+					slave-mode;
+					remote-endpoint =
+						<&tpdm_swao0_out_tpda_swao>;
+				};
+			};
+
+			port@2 {
+				reg = <1>;
+				tpda_swao_in_tpdm_swao1: endpoint {
+					slave-mode;
+					remote-endpoint =
+						<&tpdm_swao1_out_tpda_swao>;
+				};
+
+			};
+		};
+	};
+
+	tpdm_swao0: tpdm@6b02000 {
+		compatible = "qcom,coresight-tpdm";
+
+		reg = <0x6b02000 0x1000>;
+		reg-names = "tpdm-base";
+
+		coresight-name = "coresight-tpdm-swao-0";
+
+		clocks = <&clock_gcc RPMH_QDSS_CLK>,
+			 <&clock_gcc RPMH_QDSS_A_CLK>;
+		clock-names = "core_clk", "core_a_clk";
+
+		port {
+			tpdm_swao0_out_tpda_swao: endpoint {
+			remote-endpoint = <&tpda_swao_in_tpdm_swao0>;
+			};
+		};
+	};
+
+	tpdm_swao1: tpdm@6b03000 {
+		compatible = "qcom,coresight-tpdm";
+		reg = <0x6b03000 0x1000>;
+		reg-names = "tpdm-base";
+
+		coresight-name="coresight-tpdm-swao-1";
+
+		clocks = <&clock_gcc RPMH_QDSS_CLK>,
+			 <&clock_gcc RPMH_QDSS_A_CLK>;
+		clock-names = "core_clk", "core_a_clk";
+
+		port {
+			tpdm_swao1_out_tpda_swao: endpoint {
+				remote-endpoint = <&tpda_swao_in_tpdm_swao1>;
+			};
+		};
+	};
+
+	tmc_etr: tmc@6048000 {
 		compatible = "arm,primecell";
 		arm,primecell-periphid = <0x0003b961>;
 
@@ -65,7 +281,7 @@
 		};
 	};
 
-	tmc_etf:tmc@6047000 {
+	tmc_etf: tmc@6047000 {
 		compatible = "arm,primecell";
 		arm,primecell-periphid = <0x0003b961>;
 
@@ -104,6 +320,51 @@
 
 	};
 
+	funnel_merg: funnel@6045000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b908>;
+
+		reg = <0x6045000 0x1000>;
+		reg-names = "funnel-base";
+
+		coresight-name = "coresight-funnel-merg";
+
+		clocks = <&clock_gcc RPMH_QDSS_CLK>,
+			 <&clock_gcc RPMH_QDSS_A_CLK>;
+		clock-names = "apb_pclk", "core_a_clk";
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port@0 {
+				reg = <0>;
+				funnel_merg_out_tmc_etf: endpoint {
+					remote-endpoint =
+						<&tmc_etf_in_funnel_merg>;
+				};
+			};
+
+			port@1 {
+				reg = <0>;
+				funnel_merg_in_funnel_in0: endpoint {
+					slave-mode;
+					remote-endpoint =
+						<&funnel_in0_out_funnel_merg>;
+				};
+			};
+
+			port@2 {
+				reg = <2>;
+				funnel_merg_in_funnel_in2: endpoint {
+					slave-mode;
+					remote-endpoint =
+						<&funnel_in2_out_funnel_merg>;
+				};
+			};
+		};
+	};
+
 	stm: stm@6002000 {
 		compatible = "arm,primecell";
 		arm,primecell-periphid = <0x0003b962>;
@@ -152,6 +413,24 @@
 			};
 
 			port@1 {
+				reg = <3>;
+				funnel_in0_in_funnel_spss: endpoint {
+					slave-mode;
+					remote-endpoint =
+						<&funnel_spss_out_funnel_in0>;
+				};
+			};
+
+			port@2 {
+				reg = <6>;
+				funnel_in0_in_funnel_qatb: endpoint {
+					slave-mode;
+					remote-endpoint =
+						<&funnel_qatb_out_funnel_in0>;
+				};
+			};
+
+			port@3 {
 				reg = <7>;
 				funnel_in0_in_stm: endpoint {
 					slave-mode;
@@ -161,14 +440,14 @@
 		};
 	};
 
-	funnel_merg:funnel@6045000 {
+	funnel_in2: funnel@0x6043000 {
 		compatible = "arm,primecell";
 		arm,primecell-periphid = <0x0003b908>;
 
-		reg = <0x6045000 0x1000>;
+		reg = <0x6043000 0x1000>;
 		reg-names = "funnel-base";
 
-		coresight-name = "coresight-funnel-merg";
+		coresight-name = "coresight-funnel-in2";
 
 		clocks = <&clock_gcc RPMH_QDSS_CLK>,
 			 <&clock_gcc RPMH_QDSS_A_CLK>;
@@ -180,18 +459,325 @@
 
 			port@0 {
 				reg = <0>;
-				funnel_merg_out_tmc_etf: endpoint {
+				funnel_in2_out_funnel_merg: endpoint {
 					remote-endpoint =
-						<&tmc_etf_in_funnel_merg>;
+					  <&funnel_merg_in_funnel_in2>;
+				};
+			};
+
+			port@1 {
+				reg = <1>;
+				funnel_in2_in_replicator_swao: endpoint {
+					slave-mode;
+					remote-endpoint =
+					  <&replicator_swao_out_funnel_in2>;
+				};
+
+			};
+
+			port@2 {
+				reg = <5>;
+				funnel_in2_in_funnel_apss_merg: endpoint {
+					slave-mode;
+					remote-endpoint =
+					  <&funnel_apss_merg_out_funnel_in2>;
+				};
+			};
+
+		};
+	};
+
+	tpda: tpda@6004000 {
+		compatible = "qcom,coresight-tpda";
+		reg = <0x6004000 0x1000>;
+		reg-names = "tpda-base";
+
+		coresight-name = "coresight-tpda";
+
+		qcom,tpda-atid = <65>;
+		qcom,bc-elem-size = <13 32>;
+		qcom,tc-elem-size = <7 32>,
+				    <13 32>;
+		qcom,dsb-elem-size = <13 32>;
+		qcom,cmb-elem-size = <7 32>,
+				     <8 32>,
+				     <13 64>;
+
+		clocks = <&clock_gcc RPMH_QDSS_CLK>,
+			 <&clock_gcc RPMH_QDSS_A_CLK>;
+		clock-names = "core_clk", "core_a_clk";
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			port@0 {
+				reg = <0>;
+				tpda_out_funnel_qatb: endpoint {
+					remote-endpoint =
+						<&funnel_qatb_in_tpda>;
+				};
+
+			};
+
+			port@1 {
+				reg = <7>;
+				tpda_in_tpdm_vsense: endpoint {
+					slave-mode;
+					remote-endpoint =
+						<&tpdm_vsense_out_tpda>;
+				};
+			};
+
+			port@2 {
+				reg = <8>;
+				tpda_in_tpdm_dcc: endpoint {
+					slave-mode;
+					remote-endpoint =
+						<&tpdm_dcc_out_tpda>;
+				};
+			};
+
+			port@3 {
+				reg = <13>;
+				tpda_in_tpdm_pimem: endpoint {
+					slave-mode;
+					remote-endpoint =
+						<&tpdm_pimem_out_tpda>;
+				};
+			};
+		};
+	};
+
+	tpdm_pimem: tpdm@6850000 {
+		compatible = "qcom,coresight-tpdm";
+		reg = <0x6850000 0x1000>;
+		reg-names = "tpdm-base";
+
+		coresight-name = "coresight-tpdm-pimem";
+
+		clocks = <&clock_gcc RPMH_QDSS_CLK>,
+			 <&clock_gcc RPMH_QDSS_A_CLK>;
+		clock-names = "core_clk", "core_a_clk";
+
+		port {
+			tpdm_pimem_out_tpda: endpoint {
+				remote-endpoint = <&tpda_in_tpdm_pimem>;
+			};
+		};
+	};
+
+
+	tpdm_dcc: tpdm@6870000 {
+		compatible = "qcom,coresight-tpdm";
+		reg = <0x6870000 0x1000>;
+		reg-names = "tpdm-base";
+
+		coresight-name = "coresight-tpdm-dcc";
+
+		clocks = <&clock_gcc RPMH_QDSS_CLK>,
+			 <&clock_gcc RPMH_QDSS_A_CLK>;
+		clock-names = "core_clk", "core_a_clk";
+
+		port {
+			tpdm_dcc_out_tpda: endpoint {
+				remote-endpoint = <&tpda_in_tpdm_dcc>;
+			};
+		};
+	};
+
+	tpdm_vsense: tpdm@6840000 {
+		compatible = "qcom,coresight-tpdm";
+		reg = <0x6840000 0x1000>;
+		reg-names = "tpdm-base";
+
+		coresight-name = "coresight-tpdm-vsense";
+
+		clocks = <&clock_gcc RPMH_QDSS_CLK>,
+			 <&clock_gcc RPMH_QDSS_A_CLK>;
+		clock-names = "core_clk", "core_a_clk";
+
+		port{
+			tpdm_vsense_out_tpda: endpoint {
+				remote-endpoint = <&tpda_in_tpdm_vsense>;
+			};
+		};
+	};
+
+	tpda_olc: tpda@7832000 {
+		compatible = "qcom,coresight-tpda";
+		reg = <0x7832000 0x1000>;
+		reg-names = "tpda-base";
+
+		coresight-name = "coresight-tpda-olc";
+
+		qcom,tpda-atid = <69>;
+		qcom,cmb-elem-size = <0 64>;
+
+		clocks = <&clock_gcc RPMH_QDSS_CLK>,
+			 <&clock_gcc RPMH_QDSS_A_CLK>;
+		clock-names = "core_clk", "core_a_clk";
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			port@0 {
+				reg = <0>;
+				tpda_olc_out_funnel_apss_merg: endpoint {
+					remote-endpoint =
+						<&funnel_apss_merg_in_tpda_olc>;
+				};
+			};
+			port@1 {
+				reg = <0>;
+				tpda_olc_in_tpdm_olc: endpoint {
+					slave-mode;
+					remote-endpoint =
+						<&tpdm_olc_out_tpda_olc>;
+				};
+			};
+		};
+	};
+
+	tpdm_olc: tpdm@7830000 {
+		compatible = "qcom,coresight-tpdm";
+		reg = <0x7830000 0x1000>;
+		reg-names = "tpdm-base";
+
+		coresight-name = "coresight-tpdm-olc";
+
+		clocks = <&clock_gcc RPMH_QDSS_CLK>,
+			 <&clock_gcc RPMH_QDSS_A_CLK>;
+		clock-names = "core_clk", "core_a_clk";
+
+		port{
+			tpdm_olc_out_tpda_olc: endpoint {
+				remote-endpoint = <&tpda_olc_in_tpdm_olc>;
+			};
+		};
+	};
+
+	tpda_spss: tpda@6882000 {
+		compatible = "qcom,coresight-tpda";
+		reg = <0x6882000 0x1000>;
+		reg-names = "tpda-base";
+
+		coresight-name = "coresight-tpda-spss";
+
+		qcom,tpda-atid = <70>;
+		qcom,dsb-elem-size = <0 32>;
+
+		clocks = <&clock_gcc RPMH_QDSS_CLK>,
+			 <&clock_gcc RPMH_QDSS_A_CLK>;
+		clock-names = "core_clk", "core_a_clk";
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			port@0 {
+				reg = <0>;
+				tpda_spss_out_funnel_spss: endpoint {
+					remote-endpoint =
+						<&funnel_spss_in_tpda_spss>;
+				};
+			};
+			port@1 {
+				reg = <0>;
+				tpda_spss_in_tpdm_spss: endpoint {
+					slave-mode;
+					remote-endpoint =
+						<&tpdm_spss_out_tpda_spss>;
+				};
+			};
+		};
+	};
+
+	tpdm_spss: tpdm@6880000 {
+		compatible = "qcom,coresight-tpdm";
+		reg = <0x6880000 0x1000>;
+		reg-names = "tpdm-base";
+
+		coresight-name = "coresight-tpdm-spss";
+
+		clocks = <&clock_gcc RPMH_QDSS_CLK>,
+			 <&clock_gcc RPMH_QDSS_A_CLK>;
+		clock-names = "core_clk", "core_a_clk";
+
+		qcom,msr-fix-req;
+
+		port{
+			tpdm_spss_out_tpda_spss: endpoint {
+				remote-endpoint = <&tpda_spss_in_tpdm_spss>;
+			};
+		};
+	};
+
+	funnel_spss: funnel@6883000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b908>;
+
+		reg = <0x6883000 0x1000>;
+		reg-names = "funnel-base";
+
+		coresight-name = "coresight-funnel-spss";
+
+		clocks = <&clock_gcc RPMH_QDSS_CLK>,
+			 <&clock_gcc RPMH_QDSS_A_CLK>;
+		clock-names = "apb_pclk", "core_a_clk";
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port@0 {
+				reg = <0>;
+				funnel_spss_out_funnel_in0: endpoint {
+					remote-endpoint =
+					    <&funnel_in0_in_funnel_spss>;
 				};
 			};
 
 			port@1 {
 				reg = <0>;
-				funnel_merg_in_funnel_in0: endpoint {
+				funnel_spss_in_tpda_spss: endpoint {
 					slave-mode;
 					remote-endpoint =
-						<&funnel_in0_out_funnel_merg>;
+						<&tpda_spss_out_funnel_spss>;
+				};
+			};
+		};
+	};
+
+	funnel_qatb: funnel@6005000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b908>;
+
+		reg = <0x6005000 0x1000>;
+		reg-names = "funnel-base";
+
+		coresight-name = "coresight-funnel-qatb";
+
+		clocks = <&clock_gcc RPMH_QDSS_CLK>,
+			 <&clock_gcc RPMH_QDSS_A_CLK>;
+		clock-names = "apb_pclk", "core_a_clk";
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port@0 {
+				reg = <0>;
+				funnel_qatb_out_funnel_in0: endpoint {
+					remote-endpoint =
+						<&funnel_in0_in_funnel_qatb>;
+				};
+			};
+
+			port@1 {
+				reg = <0>;
+				funnel_qatb_in_tpda: endpoint {
+					slave-mode;
+					remote-endpoint =
+						<&tpda_out_funnel_qatb>;
 				};
 			};
 		};
@@ -389,9 +975,9 @@
 		clock-names = "core_clk", "core_a_clk";
 	};
 
-	cti_cpu0: cti@7420000 {
+	cti_cpu0: cti@7020000 {
 		compatible = "arm,coresight-cti";
-		reg = <0x7420000 0x1000>;
+		reg = <0x7020000 0x1000>;
 		reg-names = "cti-base";
 
 		coresight-name = "coresight-cti-cpu0";
@@ -402,9 +988,9 @@
 		clock-names = "core_clk", "core_a_clk";
 	};
 
-	cti_cpu1: cti@7520000 {
+	cti_cpu1: cti@7120000 {
 		compatible = "arm,coresight-cti";
-		reg = <0x7520000 0x1000>;
+		reg = <0x7120000 0x1000>;
 		reg-names = "cti-base";
 
 		coresight-name = "coresight-cti-cpu1";
@@ -415,9 +1001,9 @@
 		clock-names = "core_clk", "core_a_clk";
 	};
 
-	cti_cpu2: cti@7620000 {
+	cti_cpu2: cti@7220000 {
 		compatible = "arm,coresight-cti";
-		reg = <0x7620000 0x1000>;
+		reg = <0x7220000 0x1000>;
 		reg-names = "cti-base";
 
 		coresight-name = "coresight-cti-cpu2";
@@ -428,9 +1014,9 @@
 		clock-names = "core_clk", "core_a_clk";
 	};
 
-	cti_cpu3: cti@7720000 {
+	cti_cpu3: cti@7320000 {
 		compatible = "arm,coresight-cti";
-		reg = <0x7720000 0x1000>;
+		reg = <0x7320000 0x1000>;
 		reg-names = "cti-base";
 
 		coresight-name = "coresight-cti-cpu3";
@@ -441,9 +1027,9 @@
 		clock-names = "core_clk", "core_a_clk";
 	};
 
-	cti_cpu4: cti@7020000 {
+	cti_cpu4: cti@7420000 {
 		compatible = "arm,coresight-cti";
-		reg = <0x7020000 0x1000>;
+		reg = <0x7420000 0x1000>;
 		reg-names = "cti-base";
 
 		coresight-name = "coresight-cti-cpu4";
@@ -454,9 +1040,9 @@
 		clock-names = "core_clk", "core_a_clk";
 	};
 
-	cti_cpu5: cti@7120000 {
+	cti_cpu5: cti@7520000 {
 		compatible = "arm,coresight-cti";
-		reg = <0x7120000 0x1000>;
+		reg = <0x7520000 0x1000>;
 		reg-names = "cti-base";
 
 		coresight-name = "coresight-cti-cpu5";
@@ -467,9 +1053,9 @@
 		clock-names = "core_clk", "core_a_clk";
 	};
 
-	cti_cpu6: cti@7220000 {
+	cti_cpu6: cti@7620000 {
 		compatible = "arm,coresight-cti";
-		reg = <0x7220000 0x1000>;
+		reg = <0x7620000 0x1000>;
 		reg-names = "cti-base";
 
 		coresight-name = "coresight-cti-cpu6";
@@ -480,9 +1066,9 @@
 		clock-names = "core_clk", "core_a_clk";
 	};
 
-	cti_cpu7: cti@7320000 {
+	cti_cpu7: cti@7720000 {
 		compatible = "arm,coresight-cti";
-		reg = <0x7320000 0x1000>;
+		reg = <0x7720000 0x1000>;
 		reg-names = "cti-base";
 
 		coresight-name = "coresight-cti-cpu7";
@@ -492,4 +1078,91 @@
 			 <&clock_gcc RPMH_QDSS_A_CLK>;
 		clock-names = "core_clk", "core_a_clk";
 	};
+
+	dummy_eud: dummy_sink {
+		compatible = "qcom,coresight-dummy";
+
+		coresight-name = "coresight-eud";
+
+		qcom,dummy-sink;
+		port {
+			eud_in_replicator_swao: endpoint {
+				slave-mode;
+				remote-endpoint =
+					<&replicator_swao_out_eud>;
+			};
+		};
+	};
+
+	funnel_apss_merg: funnel@7810000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b908>;
+
+		reg = <0x7810000 0x1000>;
+		reg-names = "funnel-base";
+
+		coresight-name = "coresight-funnel-apss-merg";
+
+		clocks = <&clock_gcc RPMH_QDSS_CLK>,
+			 <&clock_gcc RPMH_QDSS_A_CLK>;
+		clock-names = "apb_pclk", "core_a_clk";
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port@0 {
+				reg = <0>;
+				funnel_apss_merg_out_funnel_in2: endpoint {
+					remote-endpoint =
+					    <&funnel_in2_in_funnel_apss_merg>;
+				};
+			};
+
+			port@1 {
+				reg = <0>;
+				funnel_apss_merg_in_funnel_apss: endpoint {
+					slave-mode;
+					remote-endpoint =
+					    <&funnel_apss_out_funnel_apss_merg>;
+				};
+			};
+
+			port@2 {
+				reg = <1>;
+				funnel_apss_merg_in_tpda_olc: endpoint {
+					slave-mode;
+					remote-endpoint =
+					    <&tpda_olc_out_funnel_apss_merg>;
+				};
+			};
+		};
+	};
+
+	funnel_apss: funnel@7800000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b908>;
+
+		reg = <0x7800000 0x1000>;
+		reg-names = "funnel-base";
+
+		coresight-name = "coresight-funnel-apss";
+
+		clocks = <&clock_gcc RPMH_QDSS_CLK>,
+			 <&clock_gcc RPMH_QDSS_A_CLK>;
+		clock-names = "apb_pclk", "core_a_clk";
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port@0 {
+				reg = <0>;
+				funnel_apss_out_funnel_apss_merg: endpoint {
+					remote-endpoint =
+					    <&funnel_apss_merg_in_funnel_apss>;
+				};
+			};
+		};
+	};
 };
diff --git a/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi b/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi
index 342eec7..34743ca 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi
@@ -36,6 +36,9 @@
 		#interrupt-cells = <1>;
 		iommus = <&apps_smmu 0x880>;
 
+		#address-cells = <1>;
+		#size-cells = <0>;
+
 		/* hw blocks */
 		qcom,sde-off = <0x1000>;
 		qcom,sde-len = <0x45C>;
@@ -162,4 +165,30 @@
 				<1 590 0 300000>;
 		};
 	};
+
+	sde_rscc: qcom,sde_rscc@af20000 {
+		status = "disabled";
+		cell-index = <0>;
+		compatible = "qcom,sde-rsc";
+		reg = <0xaf20000 0x1c44>,
+			<0xaf30000 0x3fd4>;
+		reg-names = "drv", "wrapper";
+		qcom,sde-rsc-version = <1>;
+
+		vdd-supply = <&mdss_core_gdsc>;
+		qcom,sde-dram-channels = <2>;
+
+		/* data and reg bus scale settings */
+		qcom,sde-data-bus {
+			qcom,msm-bus,name = "disp_rsc";
+			qcom,msm-bus,active-only;
+			qcom,msm-bus,num-cases = <3>;
+			qcom,msm-bus,num-paths = <2>;
+			qcom,msm-bus,vectors-KBps =
+			    <20003 20512 0 0>, <20004 20512 0 0>,
+			    <20003 20512 0 6400000>, <20004 20512 0 6400000>,
+			    <20003 20512 0 6400000>, <20004 20512 0 6400000>;
+		};
+
+	};
 };
diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi
index f3b529c..8974ef8 100644
--- a/arch/arm64/boot/dts/qcom/sdm845.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi
@@ -710,7 +710,7 @@
 		      <0x1f65000 0x008>,
 		      <0x1f64000 0x008>,
 		      <0x4180000 0x020>,
-		      <0x00179000 0x004>;
+		      <0xc2b0000 0x004>;
 		reg-names = "qdsp6_base", "halt_q6", "halt_modem",
 			    "halt_nc", "rmb_base", "restart_reg";
 
diff --git a/arch/arm64/configs/sdm845-perf_defconfig b/arch/arm64/configs/sdm845-perf_defconfig
index 7422ef7..283103f 100644
--- a/arch/arm64/configs/sdm845-perf_defconfig
+++ b/arch/arm64/configs/sdm845-perf_defconfig
@@ -53,6 +53,7 @@
 CONFIG_ARMV8_DEPRECATED=y
 CONFIG_SWP_EMULATION=y
 # CONFIG_ARM64_VHE is not set
+CONFIG_RANDOMIZE_BASE=y
 # CONFIG_EFI is not set
 CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE=y
 # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
@@ -61,6 +62,7 @@
 CONFIG_PM_WAKELOCKS=y
 CONFIG_PM_WAKELOCKS_LIMIT=0
 # CONFIG_PM_WAKELOCKS_GC is not set
+CONFIG_CPU_IDLE=y
 CONFIG_CPU_FREQ=y
 CONFIG_CPU_FREQ_GOV_POWERSAVE=y
 CONFIG_CPU_FREQ_GOV_USERSPACE=y
@@ -331,6 +333,7 @@
 CONFIG_USB_CONFIGFS_F_CDEV=y
 CONFIG_USB_CONFIGFS_F_CCID=y
 CONFIG_USB_CONFIGFS_F_GSI=y
+CONFIG_USB_CONFIGFS_F_QDSS=y
 CONFIG_MMC=y
 CONFIG_MMC_BLOCK_MINORS=32
 CONFIG_MMC_TEST=y
@@ -381,6 +384,8 @@
 CONFIG_MSM_PIL_MSS_QDSP6V5=y
 CONFIG_ICNSS=y
 CONFIG_QCOM_COMMAND_DB=y
+CONFIG_MSM_EVENT_TIMER=y
+CONFIG_MSM_PM=y
 CONFIG_EXTCON=y
 CONFIG_IIO=y
 CONFIG_QCOM_RRADC=y
@@ -413,7 +418,10 @@
 CONFIG_CORESIGHT_LINK_AND_SINK_TMC=y
 CONFIG_CORESIGHT_QCOM_REPLICATOR=y
 CONFIG_CORESIGHT_STM=y
+CONFIG_CORESIGHT_TPDA=y
+CONFIG_CORESIGHT_TPDM=y
 CONFIG_CORESIGHT_CTI=y
+CONFIG_CORESIGHT_DUMMY=y
 CONFIG_SECURITY=y
 CONFIG_SECURITY_SELINUX=y
 CONFIG_SECURITY_SMACK=y
diff --git a/arch/arm64/configs/sdm845_defconfig b/arch/arm64/configs/sdm845_defconfig
index f79c11a..9ca8e0a 100644
--- a/arch/arm64/configs/sdm845_defconfig
+++ b/arch/arm64/configs/sdm845_defconfig
@@ -57,6 +57,7 @@
 CONFIG_CP15_BARRIER_EMULATION=y
 CONFIG_SETEND_EMULATION=y
 # CONFIG_ARM64_VHE is not set
+CONFIG_RANDOMIZE_BASE=y
 CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE=y
 # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
 CONFIG_COMPAT=y
@@ -65,6 +66,7 @@
 CONFIG_PM_WAKELOCKS_LIMIT=0
 # CONFIG_PM_WAKELOCKS_GC is not set
 CONFIG_PM_DEBUG=y
+CONFIG_CPU_IDLE=y
 CONFIG_CPU_FREQ=y
 CONFIG_CPU_FREQ_GOV_POWERSAVE=y
 CONFIG_CPU_FREQ_GOV_USERSPACE=y
@@ -337,6 +339,7 @@
 CONFIG_USB_CONFIGFS_F_CDEV=y
 CONFIG_USB_CONFIGFS_F_CCID=y
 CONFIG_USB_CONFIGFS_F_GSI=y
+CONFIG_USB_CONFIGFS_F_QDSS=y
 CONFIG_MMC=y
 CONFIG_MMC_BLOCK_MINORS=32
 CONFIG_MMC_TEST=y
@@ -345,6 +348,9 @@
 CONFIG_MMC_SDHCI_MSM=y
 CONFIG_EDAC=y
 CONFIG_EDAC_MM_EDAC=y
+CONFIG_EDAC_KRYO3XX_ARM64=y
+CONFIG_EDAC_KRYO3XX_ARM64_PANIC_ON_CE=y
+CONFIG_EDAC_KRYO3XX_ARM64_PANIC_ON_UE=y
 CONFIG_EDAC_QCOM_LLCC=y
 CONFIG_EDAC_QCOM_LLCC_PANIC_ON_CE=y
 CONFIG_EDAC_QCOM_LLCC_PANIC_ON_UE=y
@@ -393,6 +399,8 @@
 CONFIG_ICNSS=y
 CONFIG_ICNSS_DEBUG=y
 CONFIG_QCOM_COMMAND_DB=y
+CONFIG_MSM_EVENT_TIMER=y
+CONFIG_MSM_PM=y
 CONFIG_EXTCON=y
 CONFIG_IIO=y
 CONFIG_QCOM_RRADC=y
@@ -433,6 +441,8 @@
 CONFIG_DEBUG_STACK_USAGE=y
 CONFIG_DEBUG_MEMORY_INIT=y
 CONFIG_LOCKUP_DETECTOR=y
+CONFIG_BOOTPARAM_HARDLOCKUP_PANIC=y
+CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC=y
 CONFIG_WQ_WATCHDOG=y
 CONFIG_PANIC_TIMEOUT=5
 CONFIG_SCHEDSTATS=y
@@ -462,7 +472,10 @@
 CONFIG_CORESIGHT_SOURCE_ETM4X=y
 CONFIG_CORESIGHT_QCOM_REPLICATOR=y
 CONFIG_CORESIGHT_STM=y
+CONFIG_CORESIGHT_TPDA=y
+CONFIG_CORESIGHT_TPDM=y
 CONFIG_CORESIGHT_CTI=y
+CONFIG_CORESIGHT_DUMMY=y
 CONFIG_SECURITY=y
 CONFIG_SECURITY_SELINUX=y
 CONFIG_SECURITY_SMACK=y
diff --git a/arch/arm64/include/asm/futex.h b/arch/arm64/include/asm/futex.h
index 71dfa3b..85c4a89 100644
--- a/arch/arm64/include/asm/futex.h
+++ b/arch/arm64/include/asm/futex.h
@@ -21,10 +21,7 @@
 #include <linux/futex.h>
 #include <linux/uaccess.h>
 
-#include <asm/alternative.h>
-#include <asm/cpufeature.h>
 #include <asm/errno.h>
-#include <asm/sysreg.h>
 
 #define __futex_atomic_op(insn, ret, oldval, uaddr, tmp, oparg)		\
 do {									\
diff --git a/arch/arm64/include/asm/hardirq.h b/arch/arm64/include/asm/hardirq.h
index 8740297..1473fc2 100644
--- a/arch/arm64/include/asm/hardirq.h
+++ b/arch/arm64/include/asm/hardirq.h
@@ -20,7 +20,7 @@
 #include <linux/threads.h>
 #include <asm/irq.h>
 
-#define NR_IPI	6
+#define NR_IPI	7
 
 typedef struct {
 	unsigned int __softirq_pending;
diff --git a/arch/arm64/include/asm/irq.h b/arch/arm64/include/asm/irq.h
index b77197d..96fbe7a 100644
--- a/arch/arm64/include/asm/irq.h
+++ b/arch/arm64/include/asm/irq.h
@@ -56,5 +56,8 @@
 	return (low <= sp && sp <= high);
 }
 
+void arch_trigger_all_cpu_backtrace(void);
+#define arch_trigger_all_cpu_backtrace arch_trigger_all_cpu_backtrace
+
 #endif /* !__ASSEMBLER__ */
 #endif
diff --git a/arch/arm64/include/asm/mmu_context.h b/arch/arm64/include/asm/mmu_context.h
index 52a0e43..0363fe8 100644
--- a/arch/arm64/include/asm/mmu_context.h
+++ b/arch/arm64/include/asm/mmu_context.h
@@ -208,9 +208,11 @@
 	 * Update the saved TTBR0_EL1 of the scheduled-in task as the previous
 	 * value may have not been initialised yet (activate_mm caller) or the
 	 * ASID has changed since the last run (following the context switch
-	 * of another thread of the same process).
+	 * of another thread of the same process). Avoid setting the reserved
+	 * TTBR0_EL1 to swapper_pg_dir (init_mm; e.g. via idle_task_exit).
 	 */
-	update_saved_ttbr0(tsk, next);
+	if (next != &init_mm)
+		update_saved_ttbr0(tsk, next);
 }
 
 #define deactivate_mm(tsk,mm)	do { } while (0)
diff --git a/arch/arm64/include/asm/thread_info.h b/arch/arm64/include/asm/thread_info.h
index 8b2703e..d1472eb 100644
--- a/arch/arm64/include/asm/thread_info.h
+++ b/arch/arm64/include/asm/thread_info.h
@@ -51,6 +51,9 @@
 	u64			ttbr0;		/* saved TTBR0_EL1 */
 #endif
 	struct task_struct	*task;		/* main task structure */
+#ifdef CONFIG_ARM64_SW_TTBR0_PAN
+	u64			ttbr0;		/* saved TTBR0_EL1 */
+#endif
 	int			preempt_count;	/* 0 => preemptable, <0 => bug */
 	int			cpu;		/* cpu */
 };
diff --git a/arch/arm64/include/asm/uaccess.h b/arch/arm64/include/asm/uaccess.h
index 9e06272..73fee2c 100644
--- a/arch/arm64/include/asm/uaccess.h
+++ b/arch/arm64/include/asm/uaccess.h
@@ -18,6 +18,10 @@
 #ifndef __ASM_UACCESS_H
 #define __ASM_UACCESS_H
 
+#include <asm/alternative.h>
+#include <asm/kernel-pgtable.h>
+#include <asm/sysreg.h>
+
 #ifndef __ASSEMBLY__
 
 /*
@@ -28,11 +32,9 @@
 #include <linux/string.h>
 #include <linux/thread_info.h>
 
-#include <asm/alternative.h>
 #include <asm/cpufeature.h>
 #include <asm/kernel-pgtable.h>
 #include <asm/ptrace.h>
-#include <asm/sysreg.h>
 #include <asm/errno.h>
 #include <asm/memory.h>
 #include <asm/compiler.h>
@@ -126,7 +128,7 @@
  * User access enabling/disabling.
  */
 #ifdef CONFIG_ARM64_SW_TTBR0_PAN
-static inline void uaccess_ttbr0_disable(void)
+static inline void __uaccess_ttbr0_disable(void)
 {
 	unsigned long ttbr;
 
@@ -136,7 +138,7 @@
 	isb();
 }
 
-static inline void uaccess_ttbr0_enable(void)
+static inline void __uaccess_ttbr0_enable(void)
 {
 	unsigned long flags;
 
@@ -150,30 +152,44 @@
 	isb();
 	local_irq_restore(flags);
 }
-#else
-static inline void uaccess_ttbr0_disable(void)
+
+static inline bool uaccess_ttbr0_disable(void)
 {
+	if (!system_uses_ttbr0_pan())
+		return false;
+	__uaccess_ttbr0_disable();
+	return true;
 }
 
-static inline void uaccess_ttbr0_enable(void)
+static inline bool uaccess_ttbr0_enable(void)
 {
+	if (!system_uses_ttbr0_pan())
+		return false;
+	__uaccess_ttbr0_enable();
+	return true;
+}
+#else
+static inline bool uaccess_ttbr0_disable(void)
+{
+	return false;
+}
+
+static inline bool uaccess_ttbr0_enable(void)
+{
+	return false;
 }
 #endif
 
 #define __uaccess_disable(alt)						\
 do {									\
-	if (system_uses_ttbr0_pan())					\
-		uaccess_ttbr0_disable();				\
-	else								\
+	if (!uaccess_ttbr0_disable())					\
 		asm(ALTERNATIVE("nop", SET_PSTATE_PAN(1), alt,		\
 				CONFIG_ARM64_PAN));			\
 } while (0)
 
 #define __uaccess_enable(alt)						\
 do {									\
-	if (system_uses_ttbr0_pan())					\
-		uaccess_ttbr0_enable();					\
-	else								\
+	if (!uaccess_ttbr0_enable())					\
 		asm(ALTERNATIVE("nop", SET_PSTATE_PAN(0), alt,		\
 				CONFIG_ARM64_PAN));			\
 } while (0)
@@ -411,69 +427,62 @@
 
 #else	/* __ASSEMBLY__ */
 
-#include <asm/alternative.h>
 #include <asm/assembler.h>
-#include <asm/kernel-pgtable.h>
 
 /*
  * User access enabling/disabling macros.
  */
-	.macro	uaccess_ttbr0_disable, tmp1
+#ifdef CONFIG_ARM64_SW_TTBR0_PAN
+	.macro	__uaccess_ttbr0_disable, tmp1
 	mrs	\tmp1, ttbr1_el1		// swapper_pg_dir
 	add	\tmp1, \tmp1, #SWAPPER_DIR_SIZE	// reserved_ttbr0 at the end of swapper_pg_dir
 	msr	ttbr0_el1, \tmp1		// set reserved TTBR0_EL1
 	isb
 	.endm
 
-	.macro	uaccess_ttbr0_enable, tmp1
+	.macro	__uaccess_ttbr0_enable, tmp1
 	get_thread_info \tmp1
-	ldr	\tmp1, [\tmp1, #TI_TTBR0]	// load saved TTBR0_EL1
+	ldr	\tmp1, [\tmp1, #TSK_TI_TTBR0]	// load saved TTBR0_EL1
 	msr	ttbr0_el1, \tmp1		// set the non-PAN TTBR0_EL1
 	isb
 	.endm
 
+	.macro	uaccess_ttbr0_disable, tmp1
+alternative_if_not ARM64_HAS_PAN
+	__uaccess_ttbr0_disable \tmp1
+alternative_else_nop_endif
+	.endm
+
+	.macro	uaccess_ttbr0_enable, tmp1, tmp2
+alternative_if_not ARM64_HAS_PAN
+	save_and_disable_irq \tmp2		// avoid preemption
+	__uaccess_ttbr0_enable \tmp1
+	restore_irq \tmp2
+alternative_else_nop_endif
+	.endm
+#else
+	.macro	uaccess_ttbr0_disable, tmp1
+	.endm
+
+	.macro	uaccess_ttbr0_enable, tmp1, tmp2
+	.endm
+#endif
+
 /*
  * These macros are no-ops when UAO is present.
  */
 	.macro	uaccess_disable_not_uao, tmp1
-#ifdef CONFIG_ARM64_SW_TTBR0_PAN
-alternative_if_not ARM64_HAS_PAN
 	uaccess_ttbr0_disable \tmp1
-alternative_else
-	nop
-	nop
-	nop
-	nop
-alternative_endif
-#endif
-alternative_if_not ARM64_ALT_PAN_NOT_UAO
-	nop
-alternative_else
+alternative_if ARM64_ALT_PAN_NOT_UAO
 	SET_PSTATE_PAN(1)
-alternative_endif
+alternative_else_nop_endif
 	.endm
 
 	.macro	uaccess_enable_not_uao, tmp1, tmp2
-#ifdef CONFIG_ARM64_SW_TTBR0_PAN
-alternative_if_not ARM64_HAS_PAN
-	save_and_disable_irq \tmp2		// avoid preemption
-	uaccess_ttbr0_enable \tmp1
-	restore_irq \tmp2
-alternative_else
-	nop
-	nop
-	nop
-	nop
-	nop
-	nop
-	nop
-alternative_endif
-#endif
-alternative_if_not ARM64_ALT_PAN_NOT_UAO
-	nop
-alternative_else
+	uaccess_ttbr0_enable \tmp1, \tmp2
+alternative_if ARM64_ALT_PAN_NOT_UAO
 	SET_PSTATE_PAN(0)
-alternative_endif
+alternative_else_nop_endif
 	.endm
 
 #endif	/* __ASSEMBLY__ */
diff --git a/arch/arm64/include/uapi/asm/sigcontext.h b/arch/arm64/include/uapi/asm/sigcontext.h
index ee469be..c731ca0 100644
--- a/arch/arm64/include/uapi/asm/sigcontext.h
+++ b/arch/arm64/include/uapi/asm/sigcontext.h
@@ -16,6 +16,7 @@
 #ifndef _UAPI__ASM_SIGCONTEXT_H
 #define _UAPI__ASM_SIGCONTEXT_H
 
+#ifdef CONFIG_64BIT
 #include <linux/types.h>
 
 /*
@@ -61,4 +62,35 @@
 	__u64 esr;
 };
 
+#else /* CONFIG_64BIT */
+
+/*
+ * Signal context structure - contains all info to do with the state
+ * before the signal handler was invoked.  Note: only add new entries
+ * to the end of the structure.
+ */
+struct sigcontext {
+	unsigned long trap_no;
+	unsigned long error_code;
+	unsigned long oldmask;
+	unsigned long arm_r0;
+	unsigned long arm_r1;
+	unsigned long arm_r2;
+	unsigned long arm_r3;
+	unsigned long arm_r4;
+	unsigned long arm_r5;
+	unsigned long arm_r6;
+	unsigned long arm_r7;
+	unsigned long arm_r8;
+	unsigned long arm_r9;
+	unsigned long arm_r10;
+	unsigned long arm_fp;
+	unsigned long arm_ip;
+	unsigned long arm_sp;
+	unsigned long arm_lr;
+	unsigned long arm_pc;
+	unsigned long arm_cpsr;
+	unsigned long fault_address;
+};
+#endif /* CONFIG_64BIT */
 #endif /* _UAPI__ASM_SIGCONTEXT_H */
diff --git a/arch/arm64/kernel/armv8_deprecated.c b/arch/arm64/kernel/armv8_deprecated.c
index fbdb8bb..bdb35b9 100644
--- a/arch/arm64/kernel/armv8_deprecated.c
+++ b/arch/arm64/kernel/armv8_deprecated.c
@@ -14,7 +14,6 @@
 #include <linux/slab.h>
 #include <linux/sysctl.h>
 
-#include <asm/alternative.h>
 #include <asm/cpufeature.h>
 #include <asm/insn.h>
 #include <asm/opcodes.h>
diff --git a/arch/arm64/kernel/asm-offsets.c b/arch/arm64/kernel/asm-offsets.c
index e555321..d42e61c 100644
--- a/arch/arm64/kernel/asm-offsets.c
+++ b/arch/arm64/kernel/asm-offsets.c
@@ -44,6 +44,9 @@
 #endif
   DEFINE(TI_TASK,		offsetof(struct thread_info, task));
   DEFINE(TI_CPU,		offsetof(struct thread_info, cpu));
+#ifdef CONFIG_ARM64_SW_TTBR0_PAN
+  DEFINE(TSK_TI_TTBR0,		offsetof(struct thread_info, ttbr0));
+#endif
   BLANK();
   DEFINE(THREAD_CPU_CONTEXT,	offsetof(struct task_struct, thread.cpu_context));
   BLANK();
diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S
index 324b288..1f0cea7 100644
--- a/arch/arm64/kernel/entry.S
+++ b/arch/arm64/kernel/entry.S
@@ -121,11 +121,9 @@
 	 * feature as all TTBR0_EL1 accesses are disabled, not just those to
 	 * user mappings.
 	 */
-alternative_if_not ARM64_HAS_PAN
-	nop
-alternative_else
+alternative_if ARM64_HAS_PAN
 	b	1f				// skip TTBR0 PAN
-alternative_endif
+alternative_else_nop_endif
 
 	.if	\el != 0
 	mrs	x21, ttbr0_el1
@@ -135,7 +133,7 @@
 	and	x23, x23, #~PSR_PAN_BIT		// Clear the emulated PAN in the saved SPSR
 	.endif
 
-	uaccess_ttbr0_disable x21
+	__uaccess_ttbr0_disable x21
 1:
 #endif
 
@@ -184,17 +182,15 @@
 	 * Restore access to TTBR0_EL1. If returning to EL0, no need for SPSR
 	 * PAN bit checking.
 	 */
-alternative_if_not ARM64_HAS_PAN
-	nop
-alternative_else
+alternative_if ARM64_HAS_PAN
 	b	2f				// skip TTBR0 PAN
-alternative_endif
+alternative_else_nop_endif
 
 	.if	\el != 0
-	tbnz	x22, #_PSR_PAN_BIT, 1f		// Skip re-enabling TTBR0 access if previously disabled
+	tbnz	x22, #22, 1f			// Skip re-enabling TTBR0 access if the PSR_PAN_BIT is set
 	.endif
 
-	uaccess_ttbr0_enable x0
+	__uaccess_ttbr0_enable x0
 
 	.if	\el == 0
 	/*
diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c
index 6a4348b1..0f62709 100644
--- a/arch/arm64/kernel/smp.c
+++ b/arch/arm64/kernel/smp.c
@@ -73,7 +73,8 @@
 	IPI_CPU_STOP,
 	IPI_TIMER,
 	IPI_IRQ_WORK,
-	IPI_WAKEUP
+	IPI_WAKEUP,
+	IPI_CPU_BACKTRACE,
 };
 
 #ifdef CONFIG_ARM64_VHE
@@ -760,6 +761,7 @@
 	S(IPI_TIMER, "Timer broadcast interrupts"),
 	S(IPI_IRQ_WORK, "IRQ work interrupts"),
 	S(IPI_WAKEUP, "CPU wake-up interrupts"),
+	S(IPI_CPU_BACKTRACE, "CPU backtrace"),
 };
 
 static void smp_cross_call(const struct cpumask *target, unsigned int ipinr)
@@ -846,6 +848,72 @@
 		cpu_relax();
 }
 
+static cpumask_t backtrace_mask;
+static DEFINE_RAW_SPINLOCK(backtrace_lock);
+
+/* "in progress" flag of arch_trigger_all_cpu_backtrace */
+static unsigned long backtrace_flag;
+
+static void smp_send_all_cpu_backtrace(void)
+{
+	unsigned int this_cpu = smp_processor_id();
+	int i;
+
+	if (test_and_set_bit(0, &backtrace_flag))
+		/*
+		 * If there is already a trigger_all_cpu_backtrace() in progress
+		 * (backtrace_flag == 1), don't output double cpu dump infos.
+		 */
+		return;
+
+	cpumask_copy(&backtrace_mask, cpu_online_mask);
+	cpumask_clear_cpu(this_cpu, &backtrace_mask);
+
+	pr_info("Backtrace for cpu %d (current):\n", this_cpu);
+	dump_stack();
+
+	pr_info("\nsending IPI to all other CPUs:\n");
+	if (!cpumask_empty(&backtrace_mask))
+		smp_cross_call(&backtrace_mask, IPI_CPU_BACKTRACE);
+
+	/* Wait for up to 10 seconds for all other CPUs to do the backtrace */
+	for (i = 0; i < 10 * 1000; i++) {
+		if (cpumask_empty(&backtrace_mask))
+			break;
+		mdelay(1);
+	}
+
+	clear_bit(0, &backtrace_flag);
+	smp_mb__after_atomic();
+}
+
+/*
+ * ipi_cpu_backtrace - handle IPI from smp_send_all_cpu_backtrace()
+ */
+static void ipi_cpu_backtrace(unsigned int cpu, struct pt_regs *regs)
+{
+	if (cpumask_test_cpu(cpu, &backtrace_mask)) {
+		raw_spin_lock(&backtrace_lock);
+		pr_warn("IPI backtrace for cpu %d\n", cpu);
+		show_regs(regs);
+		raw_spin_unlock(&backtrace_lock);
+		cpumask_clear_cpu(cpu, &backtrace_mask);
+	}
+}
+
+#ifdef CONFIG_SMP
+void arch_trigger_all_cpu_backtrace(void)
+{
+	smp_send_all_cpu_backtrace();
+}
+#else
+void arch_trigger_all_cpu_backtrace(void)
+{
+	dump_stack();
+}
+#endif
+
+
 /*
  * Main handler for inter-processor interrupts
  */
@@ -900,6 +968,10 @@
 		break;
 #endif
 
+	case IPI_CPU_BACKTRACE:
+		ipi_cpu_backtrace(cpu, regs);
+		break;
+
 	default:
 		pr_crit("CPU%u: Unknown IPI message 0x%x\n", cpu, ipinr);
 		break;
diff --git a/arch/arm64/kernel/traps.c b/arch/arm64/kernel/traps.c
index d5c4242..d84c7d0 100644
--- a/arch/arm64/kernel/traps.c
+++ b/arch/arm64/kernel/traps.c
@@ -317,7 +317,7 @@
 
 	if (!user_mode(regs))
 		bug_type = report_bug(regs->pc, regs);
-	if (bug_type != BUG_TRAP_TYPE_NONE)
+	if (bug_type != BUG_TRAP_TYPE_NONE && !strlen(str))
 		str = "Oops - BUG";
 
 	ret = __die(str, err, thread, regs);
@@ -470,9 +470,10 @@
 }
 
 #define __user_cache_maint(insn, address, res)			\
-	if (untagged_addr(address) >= user_addr_max())		\
+	if (untagged_addr(address) >= user_addr_max()) {	\
 		res = -EFAULT;					\
-	else							\
+	} else {						\
+		uaccess_ttbr0_enable();				\
 		asm volatile (					\
 			"1:	" insn ", %1\n"			\
 			"	mov	%w0, #0\n"		\
@@ -484,7 +485,9 @@
 			"	.popsection\n"			\
 			_ASM_EXTABLE(1b, 3b)			\
 			: "=r" (res)				\
-			: "r" (address), "i" (-EFAULT) )
+			: "r" (address), "i" (-EFAULT));	\
+		uaccess_ttbr0_disable();			\
+	}
 
 static void user_cache_maint_handler(unsigned int esr, struct pt_regs *regs)
 {
diff --git a/arch/arm64/lib/clear_user.S b/arch/arm64/lib/clear_user.S
index 08b5f18..d7150e3 100644
--- a/arch/arm64/lib/clear_user.S
+++ b/arch/arm64/lib/clear_user.S
@@ -17,9 +17,6 @@
  */
 #include <linux/linkage.h>
 
-#include <asm/assembler.h>
-#include <asm/cpufeature.h>
-#include <asm/sysreg.h>
 #include <asm/uaccess.h>
 
 	.text
diff --git a/arch/arm64/lib/copy_from_user.S b/arch/arm64/lib/copy_from_user.S
index 5f8f812..cfe1339 100644
--- a/arch/arm64/lib/copy_from_user.S
+++ b/arch/arm64/lib/copy_from_user.S
@@ -16,10 +16,7 @@
 
 #include <linux/linkage.h>
 
-#include <asm/assembler.h>
 #include <asm/cache.h>
-#include <asm/cpufeature.h>
-#include <asm/sysreg.h>
 #include <asm/uaccess.h>
 
 /*
diff --git a/arch/arm64/lib/copy_in_user.S b/arch/arm64/lib/copy_in_user.S
index 9b04ff3..718b1c4 100644
--- a/arch/arm64/lib/copy_in_user.S
+++ b/arch/arm64/lib/copy_in_user.S
@@ -18,10 +18,7 @@
 
 #include <linux/linkage.h>
 
-#include <asm/assembler.h>
 #include <asm/cache.h>
-#include <asm/cpufeature.h>
-#include <asm/sysreg.h>
 #include <asm/uaccess.h>
 
 /*
diff --git a/arch/arm64/lib/copy_to_user.S b/arch/arm64/lib/copy_to_user.S
index 8077e4f..e99e31c 100644
--- a/arch/arm64/lib/copy_to_user.S
+++ b/arch/arm64/lib/copy_to_user.S
@@ -16,10 +16,7 @@
 
 #include <linux/linkage.h>
 
-#include <asm/assembler.h>
 #include <asm/cache.h>
-#include <asm/cpufeature.h>
-#include <asm/sysreg.h>
 #include <asm/uaccess.h>
 
 /*
diff --git a/arch/arm64/mm/cache.S b/arch/arm64/mm/cache.S
index db00fc9..97de0eb 100644
--- a/arch/arm64/mm/cache.S
+++ b/arch/arm64/mm/cache.S
@@ -23,6 +23,7 @@
 #include <asm/assembler.h>
 #include <asm/cpufeature.h>
 #include <asm/alternative.h>
+#include <asm/uaccess.h>
 
 /*
  *	__flush_dcache_all()
@@ -121,6 +122,7 @@
  *	- end     - virtual end address of region
  */
 ENTRY(__flush_cache_user_range)
+	uaccess_ttbr0_enable x2, x3
 	dcache_line_size x2, x3
 	sub	x3, x2, #1
 	bic	x4, x0, x3
@@ -142,10 +144,12 @@
 	dsb	ish
 	isb
 	mov	x0, #0
+1:
+	uaccess_ttbr0_disable x1
 	ret
 9:
 	mov	x0, #-EFAULT
-	ret
+	b	1b
 ENDPROC(flush_icache_range)
 ENDPROC(__flush_cache_user_range)
 
diff --git a/arch/arm64/xen/hypercall.S b/arch/arm64/xen/hypercall.S
index a23b2e8..b41aff2 100644
--- a/arch/arm64/xen/hypercall.S
+++ b/arch/arm64/xen/hypercall.S
@@ -92,7 +92,6 @@
 	mov x2, x3
 	mov x3, x4
 	mov x4, x5
-#ifdef CONFIG_ARM64_SW_TTBR0_PAN
 	/*
 	 * Privcmd calls are issued by the userspace. The kernel needs to
 	 * enable access to TTBR0_EL1 as the hypervisor would issue stage 1
@@ -101,15 +100,12 @@
 	 * need the explicit uaccess_enable/disable if the TTBR0 PAN emulation
 	 * is enabled (it implies that hardware UAO and PAN disabled).
 	 */
-	uaccess_enable_not_uao x6, x7
-#endif
+	uaccess_ttbr0_enable x6, x7
 	hvc XEN_IMM
 
-#ifdef CONFIG_ARM64_SW_TTBR0_PAN
 	/*
 	 * Disable userspace access from kernel once the hyp call completed.
 	 */
-	uaccess_disable_not_uao x6
-#endif
+	uaccess_ttbr0_disable x6
 	ret
 ENDPROC(privcmd_call);
diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h
index 9e1499f..13f5fad 100644
--- a/arch/powerpc/include/asm/reg.h
+++ b/arch/powerpc/include/asm/reg.h
@@ -641,9 +641,10 @@
 #define   SRR1_ISI_N_OR_G	0x10000000 /* ISI: Access is no-exec or G */
 #define   SRR1_ISI_PROT		0x08000000 /* ISI: Other protection fault */
 #define   SRR1_WAKEMASK		0x00380000 /* reason for wakeup */
-#define   SRR1_WAKEMASK_P8	0x003c0000 /* reason for wakeup on POWER8 */
+#define   SRR1_WAKEMASK_P8	0x003c0000 /* reason for wakeup on POWER8 and 9 */
 #define   SRR1_WAKESYSERR	0x00300000 /* System error */
 #define   SRR1_WAKEEE		0x00200000 /* External interrupt */
+#define   SRR1_WAKEHVI		0x00240000 /* Hypervisor Virtualization Interrupt (P9) */
 #define   SRR1_WAKEMT		0x00280000 /* mtctrl */
 #define	  SRR1_WAKEHMI		0x00280000 /* Hypervisor maintenance */
 #define   SRR1_WAKEDEC		0x00180000 /* Decrementer interrupt */
diff --git a/arch/powerpc/include/asm/xics.h b/arch/powerpc/include/asm/xics.h
index f0b2385..e0b9e57 100644
--- a/arch/powerpc/include/asm/xics.h
+++ b/arch/powerpc/include/asm/xics.h
@@ -44,6 +44,7 @@
 
 #ifdef CONFIG_PPC_POWERNV
 extern int icp_opal_init(void);
+extern void icp_opal_flush_interrupt(void);
 #else
 static inline int icp_opal_init(void) { return -ENODEV; }
 #endif
diff --git a/arch/powerpc/mm/init_64.c b/arch/powerpc/mm/init_64.c
index 16ada1e..d5ce34d 100644
--- a/arch/powerpc/mm/init_64.c
+++ b/arch/powerpc/mm/init_64.c
@@ -424,7 +424,8 @@
 void __init mmu_early_init_devtree(void)
 {
 	/* Disable radix mode based on kernel command line. */
-	if (disable_radix)
+	/* We don't yet have the machinery to do radix as a guest. */
+	if (disable_radix || !(mfmsr() & MSR_HV))
 		cur_cpu_spec->mmu_features &= ~MMU_FTR_TYPE_RADIX;
 
 	if (early_radix_enabled())
diff --git a/arch/powerpc/mm/tlb-radix.c b/arch/powerpc/mm/tlb-radix.c
index 3493cf4..71697ff 100644
--- a/arch/powerpc/mm/tlb-radix.c
+++ b/arch/powerpc/mm/tlb-radix.c
@@ -50,9 +50,7 @@
 	for (set = 0; set < POWER9_TLB_SETS_RADIX ; set++) {
 		__tlbiel_pid(pid, set, ric);
 	}
-	if (cpu_has_feature(CPU_FTR_POWER9_DD1))
-		asm volatile(PPC_INVALIDATE_ERAT : : :"memory");
-	return;
+	asm volatile(PPC_INVALIDATE_ERAT "; isync" : : :"memory");
 }
 
 static inline void _tlbie_pid(unsigned long pid, unsigned long ric)
@@ -85,8 +83,6 @@
 	asm volatile(PPC_TLBIEL(%0, %4, %3, %2, %1)
 		     : : "r"(rb), "i"(r), "i"(prs), "i"(ric), "r"(rs) : "memory");
 	asm volatile("ptesync": : :"memory");
-	if (cpu_has_feature(CPU_FTR_POWER9_DD1))
-		asm volatile(PPC_INVALIDATE_ERAT : : :"memory");
 }
 
 static inline void _tlbie_va(unsigned long va, unsigned long pid,
diff --git a/arch/powerpc/platforms/powernv/smp.c b/arch/powerpc/platforms/powernv/smp.c
index c789258..eec0e8d 100644
--- a/arch/powerpc/platforms/powernv/smp.c
+++ b/arch/powerpc/platforms/powernv/smp.c
@@ -155,8 +155,10 @@
 		wmask = SRR1_WAKEMASK_P8;
 
 	idle_states = pnv_get_supported_cpuidle_states();
+
 	/* We don't want to take decrementer interrupts while we are offline,
-	 * so clear LPCR:PECE1. We keep PECE2 enabled.
+	 * so clear LPCR:PECE1. We keep PECE2 (and LPCR_PECE_HVEE on P9)
+	 * enabled as to let IPIs in.
 	 */
 	mtspr(SPRN_LPCR, mfspr(SPRN_LPCR) & ~(u64)LPCR_PECE1);
 
@@ -206,8 +208,12 @@
 		 * contains 0.
 		 */
 		if (((srr1 & wmask) == SRR1_WAKEEE) ||
+		    ((srr1 & wmask) == SRR1_WAKEHVI) ||
 		    (local_paca->irq_happened & PACA_IRQ_EE)) {
-			icp_native_flush_interrupt();
+			if (cpu_has_feature(CPU_FTR_ARCH_300))
+				icp_opal_flush_interrupt();
+			else
+				icp_native_flush_interrupt();
 		} else if ((srr1 & wmask) == SRR1_WAKEHDBELL) {
 			unsigned long msg = PPC_DBELL_TYPE(PPC_DBELL_SERVER);
 			asm volatile(PPC_MSGCLR(%0) : : "r" (msg));
@@ -221,6 +227,8 @@
 		if (srr1 && !generic_check_cpu_restart(cpu))
 			DBG("CPU%d Unexpected exit while offline !\n", cpu);
 	}
+
+	/* Re-enable decrementer interrupts */
 	mtspr(SPRN_LPCR, mfspr(SPRN_LPCR) | LPCR_PECE1);
 	DBG("CPU%d coming online...\n", cpu);
 }
diff --git a/arch/powerpc/sysdev/xics/icp-opal.c b/arch/powerpc/sysdev/xics/icp-opal.c
index 60c5765..c96c0cb 100644
--- a/arch/powerpc/sysdev/xics/icp-opal.c
+++ b/arch/powerpc/sysdev/xics/icp-opal.c
@@ -132,6 +132,35 @@
 	return smp_ipi_demux();
 }
 
+/*
+ * Called when an interrupt is received on an off-line CPU to
+ * clear the interrupt, so that the CPU can go back to nap mode.
+ */
+void icp_opal_flush_interrupt(void)
+{
+	unsigned int xirr;
+	unsigned int vec;
+
+	do {
+		xirr = icp_opal_get_xirr();
+		vec = xirr & 0x00ffffff;
+		if (vec == XICS_IRQ_SPURIOUS)
+			break;
+		if (vec == XICS_IPI) {
+			/* Clear pending IPI */
+			int cpu = smp_processor_id();
+			kvmppc_set_host_ipi(cpu, 0);
+			opal_int_set_mfrr(get_hard_smp_processor_id(cpu), 0xff);
+		} else {
+			pr_err("XICS: hw interrupt 0x%x to offline cpu, "
+			       "disabling\n", vec);
+			xics_mask_unknown_vec(vec);
+		}
+
+		/* EOI the interrupt */
+	} while (opal_int_eoi(xirr) > 0);
+}
+
 #endif /* CONFIG_SMP */
 
 static const struct icp_ops icp_opal_ops = {
diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h
index 984a7bf..83db0ea 100644
--- a/arch/x86/include/asm/processor.h
+++ b/arch/x86/include/asm/processor.h
@@ -104,6 +104,7 @@
 	__u8			x86_phys_bits;
 	/* CPUID returned core id bits: */
 	__u8			x86_coreid_bits;
+	__u8			cu_id;
 	/* Max extended CPUID function supported: */
 	__u32			extended_cpuid_level;
 	/* Maximum supported CPUID level, -1=no CPUID: */
diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c
index 7249f15..d1e2556 100644
--- a/arch/x86/kernel/apic/io_apic.c
+++ b/arch/x86/kernel/apic/io_apic.c
@@ -1876,7 +1876,6 @@
 	.irq_ack		= irq_chip_ack_parent,
 	.irq_eoi		= ioapic_ack_level,
 	.irq_set_affinity	= ioapic_set_affinity,
-	.irq_retrigger		= irq_chip_retrigger_hierarchy,
 	.flags			= IRQCHIP_SKIP_SET_WAKE,
 };
 
@@ -1888,7 +1887,6 @@
 	.irq_ack		= irq_chip_ack_parent,
 	.irq_eoi		= ioapic_ir_ack_level,
 	.irq_set_affinity	= ioapic_set_affinity,
-	.irq_retrigger		= irq_chip_retrigger_hierarchy,
 	.flags			= IRQCHIP_SKIP_SET_WAKE,
 };
 
diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c
index 1d31672..2b4cf04 100644
--- a/arch/x86/kernel/cpu/amd.c
+++ b/arch/x86/kernel/cpu/amd.c
@@ -309,8 +309,22 @@
 
 	/* get information required for multi-node processors */
 	if (boot_cpu_has(X86_FEATURE_TOPOEXT)) {
+		u32 eax, ebx, ecx, edx;
 
-		node_id = cpuid_ecx(0x8000001e) & 7;
+		cpuid(0x8000001e, &eax, &ebx, &ecx, &edx);
+
+		node_id  = ecx & 0xff;
+		smp_num_siblings = ((ebx >> 8) & 0xff) + 1;
+
+		if (c->x86 == 0x15)
+			c->cu_id = ebx & 0xff;
+
+		if (c->x86 >= 0x17) {
+			c->cpu_core_id = ebx & 0xff;
+
+			if (smp_num_siblings > 1)
+				c->x86_max_cores /= smp_num_siblings;
+		}
 
 		/*
 		 * We may have multiple LLCs if L3 caches exist, so check if we
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
index 023c7bf..4eece91 100644
--- a/arch/x86/kernel/cpu/common.c
+++ b/arch/x86/kernel/cpu/common.c
@@ -1015,6 +1015,7 @@
 	c->x86_model_id[0] = '\0';  /* Unset */
 	c->x86_max_cores = 1;
 	c->x86_coreid_bits = 0;
+	c->cu_id = 0xff;
 #ifdef CONFIG_X86_64
 	c->x86_clflush_size = 64;
 	c->x86_phys_bits = 36;
diff --git a/arch/x86/kernel/fpu/core.c b/arch/x86/kernel/fpu/core.c
index ebb4e95..96d80df 100644
--- a/arch/x86/kernel/fpu/core.c
+++ b/arch/x86/kernel/fpu/core.c
@@ -236,7 +236,8 @@
 	 * it will #GP. Make sure it is replaced after the memset().
 	 */
 	if (static_cpu_has(X86_FEATURE_XSAVES))
-		state->xsave.header.xcomp_bv = XCOMP_BV_COMPACTED_FORMAT;
+		state->xsave.header.xcomp_bv = XCOMP_BV_COMPACTED_FORMAT |
+					       xfeatures_mask;
 
 	if (static_cpu_has(X86_FEATURE_FXSR))
 		fpstate_init_fxstate(&state->fxsave);
diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c
index e9bbe02..36171bc 100644
--- a/arch/x86/kernel/smpboot.c
+++ b/arch/x86/kernel/smpboot.c
@@ -423,9 +423,15 @@
 		int cpu1 = c->cpu_index, cpu2 = o->cpu_index;
 
 		if (c->phys_proc_id == o->phys_proc_id &&
-		    per_cpu(cpu_llc_id, cpu1) == per_cpu(cpu_llc_id, cpu2) &&
-		    c->cpu_core_id == o->cpu_core_id)
-			return topology_sane(c, o, "smt");
+		    per_cpu(cpu_llc_id, cpu1) == per_cpu(cpu_llc_id, cpu2)) {
+			if (c->cpu_core_id == o->cpu_core_id)
+				return topology_sane(c, o, "smt");
+
+			if ((c->cu_id != 0xff) &&
+			    (o->cu_id != 0xff) &&
+			    (c->cu_id == o->cu_id))
+				return topology_sane(c, o, "smt");
+		}
 
 	} else if (c->phys_proc_id == o->phys_proc_id &&
 		   c->cpu_core_id == o->cpu_core_id) {
diff --git a/arch/x86/mm/dump_pagetables.c b/arch/x86/mm/dump_pagetables.c
index ea9c49a..8aa6bea 100644
--- a/arch/x86/mm/dump_pagetables.c
+++ b/arch/x86/mm/dump_pagetables.c
@@ -15,6 +15,7 @@
 #include <linux/debugfs.h>
 #include <linux/mm.h>
 #include <linux/init.h>
+#include <linux/sched.h>
 #include <linux/seq_file.h>
 
 #include <asm/pgtable.h>
@@ -406,6 +407,7 @@
 		} else
 			note_page(m, &st, __pgprot(0), 1);
 
+		cond_resched();
 		start++;
 	}
 
diff --git a/crypto/algif_aead.c b/crypto/algif_aead.c
index e9c0993..e8817e2 100644
--- a/crypto/algif_aead.c
+++ b/crypto/algif_aead.c
@@ -671,9 +671,9 @@
 unlock:
 	list_for_each_entry_safe(rsgl, tmp, &ctx->list, list) {
 		af_alg_free_sg(&rsgl->sgl);
+		list_del(&rsgl->list);
 		if (rsgl != &ctx->first_rsgl)
 			sock_kfree_s(sk, rsgl, sizeof(*rsgl));
-		list_del(&rsgl->list);
 	}
 	INIT_LIST_HEAD(&ctx->list);
 	aead_wmem_wakeup(sk);
diff --git a/drivers/acpi/nfit/core.c b/drivers/acpi/nfit/core.c
index 312c4b4..6eb6733 100644
--- a/drivers/acpi/nfit/core.c
+++ b/drivers/acpi/nfit/core.c
@@ -2704,6 +2704,7 @@
 	struct acpi_nfit_desc *acpi_desc = to_acpi_nfit_desc(nd_desc);
 	struct device *dev = acpi_desc->dev;
 	struct acpi_nfit_flush_work flush;
+	int rc;
 
 	/* bounce the device lock to flush acpi_nfit_add / acpi_nfit_notify */
 	device_lock(dev);
@@ -2716,7 +2717,10 @@
 	INIT_WORK_ONSTACK(&flush.work, flush_probe);
 	COMPLETION_INITIALIZER_ONSTACK(flush.cmp);
 	queue_work(nfit_wq, &flush.work);
-	return wait_for_completion_interruptible(&flush.cmp);
+
+	rc = wait_for_completion_interruptible(&flush.cmp);
+	cancel_work_sync(&flush.work);
+	return rc;
 }
 
 static int acpi_nfit_clear_to_send(struct nvdimm_bus_descriptor *nd_desc,
diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c
index 3fd76d9..a13a45e 100644
--- a/drivers/clk/qcom/clk-rcg2.c
+++ b/drivers/clk/qcom/clk-rcg2.c
@@ -378,6 +378,7 @@
 {
 	struct clk_rcg2 *rcg = to_clk_rcg2(hw);
 	const struct freq_tbl *f;
+	int ret;
 
 	f = qcom_find_freq(rcg->freq_tbl, rate);
 	if (!f)
@@ -392,7 +393,13 @@
 		return 0;
 	}
 
-	return clk_rcg2_configure(rcg, f);
+	ret = clk_rcg2_configure(rcg, f);
+	if (ret)
+		return ret;
+
+	/* Update current frequency with the requested frequency. */
+	rcg->current_freq = rate;
+	return ret;
 }
 
 static int clk_rcg2_set_rate(struct clk_hw *hw, unsigned long rate,
@@ -410,7 +417,7 @@
 static int clk_rcg2_enable(struct clk_hw *hw)
 {
 	struct clk_rcg2 *rcg = to_clk_rcg2(hw);
-	unsigned long rate = clk_get_rate(hw->clk);
+	unsigned long rate;
 	const struct freq_tbl *f;
 
 	if (!rcg->enable_safe_config)
@@ -424,6 +431,7 @@
 	 * is always on while APPS is online. Therefore, the RCG can safely be
 	 * switched.
 	 */
+	rate = rcg->current_freq;
 	f = qcom_find_freq(rcg->freq_tbl, rate);
 	if (!f)
 		return -EINVAL;
diff --git a/drivers/clk/qcom/gcc-sdm845.c b/drivers/clk/qcom/gcc-sdm845.c
index 92e0ffa..a1a1501 100644
--- a/drivers/clk/qcom/gcc-sdm845.c
+++ b/drivers/clk/qcom/gcc-sdm845.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -50,7 +50,6 @@
 	P_CORE_BI_PLL_TEST_SE,
 	P_GPLL0_OUT_EVEN,
 	P_GPLL0_OUT_MAIN,
-	P_GPLL1_OUT_MAIN,
 	P_GPLL4_OUT_MAIN,
 	P_SLEEP_CLK,
 };
@@ -122,7 +121,7 @@
 static const struct parent_map gcc_parent_map_5[] = {
 	{ P_BI_TCXO, 0 },
 	{ P_GPLL0_OUT_MAIN, 1 },
-	{ P_GPLL1_OUT_MAIN, 4 },
+	{ P_GPLL4_OUT_MAIN, 5 },
 	{ P_GPLL0_OUT_EVEN, 6 },
 	{ P_CORE_BI_PLL_TEST_SE, 7 },
 };
@@ -130,7 +129,7 @@
 static const char * const gcc_parent_names_5[] = {
 	"bi_tcxo",
 	"gpll0",
-	"gpll1",
+	"gpll4",
 	"gpll0_out_even",
 	"core_bi_pll_test_se",
 };
@@ -138,28 +137,12 @@
 static const struct parent_map gcc_parent_map_6[] = {
 	{ P_BI_TCXO, 0 },
 	{ P_GPLL0_OUT_MAIN, 1 },
-	{ P_GPLL4_OUT_MAIN, 5 },
-	{ P_GPLL0_OUT_EVEN, 6 },
-	{ P_CORE_BI_PLL_TEST_SE, 7 },
-};
-
-static const char * const gcc_parent_names_6[] = {
-	"bi_tcxo",
-	"gpll0",
-	"gpll4",
-	"gpll0_out_even",
-	"core_bi_pll_test_se",
-};
-
-static const struct parent_map gcc_parent_map_7[] = {
-	{ P_BI_TCXO, 0 },
-	{ P_GPLL0_OUT_MAIN, 1 },
 	{ P_AUD_REF_CLK, 2 },
 	{ P_GPLL0_OUT_EVEN, 6 },
 	{ P_CORE_BI_PLL_TEST_SE, 7 },
 };
 
-static const char * const gcc_parent_names_7[] = {
+static const char * const gcc_parent_names_6[] = {
 	"bi_tcxo",
 	"gpll0",
 	"aud_ref_clk",
@@ -264,7 +247,6 @@
 
 static const struct freq_tbl ftbl_gcc_cpuss_rbcpr_clk_src[] = {
 	F(19200000, P_BI_TCXO, 1, 0, 0),
-	F(50000000, P_GPLL0_OUT_MAIN, 12, 0, 0),
 	{ }
 };
 
@@ -280,9 +262,8 @@
 		.num_parents = 3,
 		.flags = CLK_SET_RATE_PARENT,
 		.ops = &clk_rcg2_ops,
-		VDD_CX_FMAX_MAP2(
-			MIN, 19200000,
-			NOMINAL, 50000000),
+		VDD_CX_FMAX_MAP1(
+			MIN, 19200000),
 	},
 };
 
@@ -471,57 +452,17 @@
 	},
 };
 
-static const struct freq_tbl ftbl_gcc_qupv3_wrap0_core_2x_clk_src[] = {
-	F(19200000, P_BI_TCXO, 1, 0, 0),
-	F(50000000, P_GPLL0_OUT_EVEN, 6, 0, 0),
-	F(100000000, P_GPLL0_OUT_MAIN, 6, 0, 0),
-	F(150000000, P_GPLL0_OUT_MAIN, 4, 0, 0),
-	F(200000000, P_GPLL0_OUT_MAIN, 3, 0, 0),
-	F(236888889, P_GPLL1_OUT_MAIN, 4.5, 0, 0),
-	{ }
-};
-
-static struct clk_rcg2 gcc_qupv3_wrap0_core_2x_clk_src = {
-	.cmd_rcgr = 0x17018,
-	.mnd_width = 0,
-	.hid_width = 5,
-	.parent_map = gcc_parent_map_5,
-	.freq_tbl = ftbl_gcc_qupv3_wrap0_core_2x_clk_src,
-	.enable_safe_config = true,
-	.clkr.hw.init = &(struct clk_init_data){
-		.name = "gcc_qupv3_wrap0_core_2x_clk_src",
-		.parent_names = gcc_parent_names_5,
-		.num_parents = 5,
-		.flags = CLK_SET_RATE_PARENT,
-		.ops = &clk_rcg2_ops,
-		VDD_CX_FMAX_MAP6(
-			MIN, 19200000,
-			LOWER, 50000000,
-			LOW, 100000000,
-			LOW_L1, 150000000,
-			NOMINAL, 200000000,
-			HIGH, 236888889),
-	},
-};
-
 static const struct freq_tbl ftbl_gcc_qupv3_wrap0_s0_clk_src[] = {
-	F(3686400, P_GPLL0_OUT_MAIN, 1, 96, 15625),
-	F(14745600, P_GPLL0_OUT_MAIN, 1, 384, 15625),
-	F(16000000, P_GPLL0_OUT_MAIN, 5, 2, 15),
+	F(7372800, P_GPLL0_OUT_EVEN, 1, 384, 15625),
+	F(14745600, P_GPLL0_OUT_EVEN, 1, 768, 15625),
 	F(19200000, P_BI_TCXO, 1, 0, 0),
-	F(24000000, P_GPLL0_OUT_MAIN, 5, 1, 5),
-	F(32000000, P_GPLL0_OUT_MAIN, 1, 4, 75),
-	F(40000000, P_GPLL0_OUT_MAIN, 15, 0, 0),
-	F(46400000, P_GPLL0_OUT_MAIN, 1, 29, 375),
-	F(48000000, P_GPLL0_OUT_MAIN, 12.5, 0, 0),
-	F(50000000, P_GPLL0_OUT_EVEN, 6, 0, 0),
-	F(51200000, P_GPLL0_OUT_MAIN, 1, 32, 375),
-	F(56000000, P_GPLL0_OUT_MAIN, 1, 7, 75),
-	F(58982400, P_GPLL0_OUT_MAIN, 1, 1536, 15625),
-	F(60000000, P_GPLL0_OUT_MAIN, 10, 0, 0),
-	F(63157895, P_GPLL0_OUT_MAIN, 9.5, 0, 0),
-	F(100000000, P_GPLL0_OUT_MAIN, 6, 0, 0),
-	F(150000000, P_GPLL0_OUT_MAIN, 4, 0, 0),
+	F(29491200, P_GPLL0_OUT_EVEN, 1, 1536, 15625),
+	F(32000000, P_GPLL0_OUT_EVEN, 1, 8, 75),
+	F(48000000, P_GPLL0_OUT_EVEN, 1, 4, 25),
+	F(64000000, P_GPLL0_OUT_EVEN, 1, 16, 75),
+	F(80000000, P_GPLL0_OUT_EVEN, 1, 4, 15),
+	F(96000000, P_GPLL0_OUT_EVEN, 1, 8, 25),
+	F(100000000, P_GPLL0_OUT_EVEN, 3, 0, 0),
 	{ }
 };
 
@@ -538,11 +479,10 @@
 		.num_parents = 4,
 		.flags = CLK_SET_RATE_PARENT,
 		.ops = &clk_rcg2_ops,
-		VDD_CX_FMAX_MAP4(
+		VDD_CX_FMAX_MAP3(
 			MIN, 19200000,
 			LOWER, 75000000,
-			LOW, 100000000,
-			NOMINAL, 150000000),
+			LOW, 100000000),
 	},
 };
 
@@ -559,11 +499,10 @@
 		.num_parents = 4,
 		.flags = CLK_SET_RATE_PARENT,
 		.ops = &clk_rcg2_ops,
-		VDD_CX_FMAX_MAP4(
+		VDD_CX_FMAX_MAP3(
 			MIN, 19200000,
 			LOWER, 75000000,
-			LOW, 100000000,
-			NOMINAL, 150000000),
+			LOW, 100000000),
 	},
 };
 
@@ -580,11 +519,10 @@
 		.num_parents = 4,
 		.flags = CLK_SET_RATE_PARENT,
 		.ops = &clk_rcg2_ops,
-		VDD_CX_FMAX_MAP4(
+		VDD_CX_FMAX_MAP3(
 			MIN, 19200000,
 			LOWER, 75000000,
-			LOW, 100000000,
-			NOMINAL, 150000000),
+			LOW, 100000000),
 	},
 };
 
@@ -601,11 +539,10 @@
 		.num_parents = 4,
 		.flags = CLK_SET_RATE_PARENT,
 		.ops = &clk_rcg2_ops,
-		VDD_CX_FMAX_MAP4(
+		VDD_CX_FMAX_MAP3(
 			MIN, 19200000,
 			LOWER, 75000000,
-			LOW, 100000000,
-			NOMINAL, 150000000),
+			LOW, 100000000),
 	},
 };
 
@@ -622,11 +559,10 @@
 		.num_parents = 4,
 		.flags = CLK_SET_RATE_PARENT,
 		.ops = &clk_rcg2_ops,
-		VDD_CX_FMAX_MAP4(
+		VDD_CX_FMAX_MAP3(
 			MIN, 19200000,
 			LOWER, 75000000,
-			LOW, 100000000,
-			NOMINAL, 150000000),
+			LOW, 100000000),
 	},
 };
 
@@ -643,11 +579,10 @@
 		.num_parents = 4,
 		.flags = CLK_SET_RATE_PARENT,
 		.ops = &clk_rcg2_ops,
-		VDD_CX_FMAX_MAP4(
+		VDD_CX_FMAX_MAP3(
 			MIN, 19200000,
 			LOWER, 75000000,
-			LOW, 100000000,
-			NOMINAL, 150000000),
+			LOW, 100000000),
 	},
 };
 
@@ -664,11 +599,10 @@
 		.num_parents = 4,
 		.flags = CLK_SET_RATE_PARENT,
 		.ops = &clk_rcg2_ops,
-		VDD_CX_FMAX_MAP4(
+		VDD_CX_FMAX_MAP3(
 			MIN, 19200000,
 			LOWER, 75000000,
-			LOW, 100000000,
-			NOMINAL, 150000000),
+			LOW, 100000000),
 	},
 };
 
@@ -685,11 +619,10 @@
 		.num_parents = 4,
 		.flags = CLK_SET_RATE_PARENT,
 		.ops = &clk_rcg2_ops,
-		VDD_CX_FMAX_MAP4(
+		VDD_CX_FMAX_MAP3(
 			MIN, 19200000,
 			LOWER, 75000000,
-			LOW, 100000000,
-			NOMINAL, 150000000),
+			LOW, 100000000),
 	},
 };
 
@@ -706,11 +639,10 @@
 		.num_parents = 4,
 		.flags = CLK_SET_RATE_PARENT,
 		.ops = &clk_rcg2_ops,
-		VDD_CX_FMAX_MAP4(
+		VDD_CX_FMAX_MAP3(
 			MIN, 19200000,
 			LOWER, 75000000,
-			LOW, 100000000,
-			NOMINAL, 150000000),
+			LOW, 100000000),
 	},
 };
 
@@ -727,11 +659,10 @@
 		.num_parents = 4,
 		.flags = CLK_SET_RATE_PARENT,
 		.ops = &clk_rcg2_ops,
-		VDD_CX_FMAX_MAP4(
+		VDD_CX_FMAX_MAP3(
 			MIN, 19200000,
 			LOWER, 75000000,
-			LOW, 100000000,
-			NOMINAL, 150000000),
+			LOW, 100000000),
 	},
 };
 
@@ -748,11 +679,10 @@
 		.num_parents = 4,
 		.flags = CLK_SET_RATE_PARENT,
 		.ops = &clk_rcg2_ops,
-		VDD_CX_FMAX_MAP4(
+		VDD_CX_FMAX_MAP3(
 			MIN, 19200000,
 			LOWER, 75000000,
-			LOW, 100000000,
-			NOMINAL, 150000000),
+			LOW, 100000000),
 	},
 };
 
@@ -769,11 +699,10 @@
 		.num_parents = 4,
 		.flags = CLK_SET_RATE_PARENT,
 		.ops = &clk_rcg2_ops,
-		VDD_CX_FMAX_MAP4(
+		VDD_CX_FMAX_MAP3(
 			MIN, 19200000,
 			LOWER, 75000000,
-			LOW, 100000000,
-			NOMINAL, 150000000),
+			LOW, 100000000),
 	},
 };
 
@@ -790,11 +719,10 @@
 		.num_parents = 4,
 		.flags = CLK_SET_RATE_PARENT,
 		.ops = &clk_rcg2_ops,
-		VDD_CX_FMAX_MAP4(
+		VDD_CX_FMAX_MAP3(
 			MIN, 19200000,
 			LOWER, 75000000,
-			LOW, 100000000,
-			NOMINAL, 150000000),
+			LOW, 100000000),
 	},
 };
 
@@ -811,11 +739,10 @@
 		.num_parents = 4,
 		.flags = CLK_SET_RATE_PARENT,
 		.ops = &clk_rcg2_ops,
-		VDD_CX_FMAX_MAP4(
+		VDD_CX_FMAX_MAP3(
 			MIN, 19200000,
 			LOWER, 75000000,
-			LOW, 100000000,
-			NOMINAL, 150000000),
+			LOW, 100000000),
 	},
 };
 
@@ -832,11 +759,10 @@
 		.num_parents = 4,
 		.flags = CLK_SET_RATE_PARENT,
 		.ops = &clk_rcg2_ops,
-		VDD_CX_FMAX_MAP4(
+		VDD_CX_FMAX_MAP3(
 			MIN, 19200000,
 			LOWER, 75000000,
-			LOW, 100000000,
-			NOMINAL, 150000000),
+			LOW, 100000000),
 	},
 };
 
@@ -853,11 +779,10 @@
 		.num_parents = 4,
 		.flags = CLK_SET_RATE_PARENT,
 		.ops = &clk_rcg2_ops,
-		VDD_CX_FMAX_MAP4(
+		VDD_CX_FMAX_MAP3(
 			MIN, 19200000,
 			LOWER, 75000000,
-			LOW, 100000000,
-			NOMINAL, 150000000),
+			LOW, 100000000),
 	},
 };
 
@@ -872,12 +797,12 @@
 	.cmd_rcgr = 0x1400c,
 	.mnd_width = 8,
 	.hid_width = 5,
-	.parent_map = gcc_parent_map_6,
+	.parent_map = gcc_parent_map_5,
 	.freq_tbl = ftbl_gcc_sdcc2_apps_clk_src,
 	.enable_safe_config = true,
 	.clkr.hw.init = &(struct clk_init_data){
 		.name = "gcc_sdcc2_apps_clk_src",
-		.parent_names = gcc_parent_names_6,
+		.parent_names = gcc_parent_names_5,
 		.num_parents = 5,
 		.flags = CLK_SET_RATE_PARENT,
 		.ops = &clk_rcg2_ops,
@@ -903,7 +828,7 @@
 	.hid_width = 5,
 	.parent_map = gcc_parent_map_3,
 	.freq_tbl = ftbl_gcc_sdcc4_apps_clk_src,
-		.enable_safe_config = true,
+	.enable_safe_config = true,
 	.clkr.hw.init = &(struct clk_init_data){
 		.name = "gcc_sdcc4_apps_clk_src",
 		.parent_names = gcc_parent_names_3,
@@ -927,11 +852,11 @@
 	.cmd_rcgr = 0x36010,
 	.mnd_width = 8,
 	.hid_width = 5,
-	.parent_map = gcc_parent_map_7,
+	.parent_map = gcc_parent_map_6,
 	.freq_tbl = ftbl_gcc_tsif_ref_clk_src,
 	.clkr.hw.init = &(struct clk_init_data){
 		.name = "gcc_tsif_ref_clk_src",
-		.parent_names = gcc_parent_names_7,
+		.parent_names = gcc_parent_names_6,
 		.num_parents = 5,
 		.flags = CLK_SET_RATE_PARENT,
 		.ops = &clk_rcg2_ops,
@@ -940,21 +865,12 @@
 	},
 };
 
-static const struct freq_tbl ftbl_gcc_ufs_card_axi_clk_src[] = {
-	F(25000000, P_GPLL0_OUT_EVEN, 12, 0, 0),
-	F(50000000, P_GPLL0_OUT_EVEN, 6, 0, 0),
-	F(100000000, P_GPLL0_OUT_MAIN, 6, 0, 0),
-	F(200000000, P_GPLL0_OUT_MAIN, 3, 0, 0),
-	F(240000000, P_GPLL0_OUT_MAIN, 2.5, 0, 0),
-	{ }
-};
-
 static struct clk_rcg2 gcc_ufs_card_axi_clk_src = {
 	.cmd_rcgr = 0x7501c,
 	.mnd_width = 8,
 	.hid_width = 5,
 	.parent_map = gcc_parent_map_0,
-	.freq_tbl = ftbl_gcc_ufs_card_axi_clk_src,
+	.freq_tbl = ftbl_gcc_gp1_clk_src,
 	.enable_safe_config = true,
 	.clkr.hw.init = &(struct clk_init_data){
 		.name = "gcc_ufs_card_axi_clk_src",
@@ -962,11 +878,10 @@
 		.num_parents = 4,
 		.flags = CLK_SET_RATE_PARENT,
 		.ops = &clk_rcg2_ops,
-		VDD_CX_FMAX_MAP4(
+		VDD_CX_FMAX_MAP3(
 			MIN, 50000000,
 			LOW, 100000000,
-			NOMINAL, 200000000,
-			HIGH, 240000000),
+			NOMINAL, 200000000),
 	},
 };
 
@@ -998,17 +913,12 @@
 	},
 };
 
-static const struct freq_tbl ftbl_gcc_ufs_card_phy_aux_clk_src[] = {
-	F(19200000, P_BI_TCXO, 1, 0, 0),
-	{ }
-};
-
 static struct clk_rcg2 gcc_ufs_card_phy_aux_clk_src = {
 	.cmd_rcgr = 0x75090,
 	.mnd_width = 0,
 	.hid_width = 5,
 	.parent_map = gcc_parent_map_4,
-	.freq_tbl = ftbl_gcc_ufs_card_phy_aux_clk_src,
+	.freq_tbl = ftbl_gcc_cpuss_rbcpr_clk_src,
 	.clkr.hw.init = &(struct clk_init_data){
 		.name = "gcc_ufs_card_phy_aux_clk_src",
 		.parent_names = gcc_parent_names_4,
@@ -1047,12 +957,21 @@
 	},
 };
 
+static const struct freq_tbl ftbl_gcc_ufs_phy_axi_clk_src[] = {
+	F(25000000, P_GPLL0_OUT_EVEN, 12, 0, 0),
+	F(50000000, P_GPLL0_OUT_EVEN, 6, 0, 0),
+	F(100000000, P_GPLL0_OUT_MAIN, 6, 0, 0),
+	F(200000000, P_GPLL0_OUT_MAIN, 3, 0, 0),
+	F(240000000, P_GPLL0_OUT_MAIN, 2.5, 0, 0),
+	{ }
+};
+
 static struct clk_rcg2 gcc_ufs_phy_axi_clk_src = {
 	.cmd_rcgr = 0x7701c,
 	.mnd_width = 8,
 	.hid_width = 5,
 	.parent_map = gcc_parent_map_0,
-	.freq_tbl = ftbl_gcc_ufs_card_axi_clk_src,
+	.freq_tbl = ftbl_gcc_ufs_phy_axi_clk_src,
 	.enable_safe_config = true,
 	.clkr.hw.init = &(struct clk_init_data){
 		.name = "gcc_ufs_phy_axi_clk_src",
@@ -1227,7 +1146,7 @@
 	.mnd_width = 0,
 	.hid_width = 5,
 	.parent_map = gcc_parent_map_2,
-	.freq_tbl = ftbl_gcc_ufs_card_phy_aux_clk_src,
+	.freq_tbl = ftbl_gcc_cpuss_rbcpr_clk_src,
 	.clkr.hw.init = &(struct clk_init_data){
 		.name = "gcc_usb3_prim_phy_aux_clk_src",
 		.parent_names = gcc_parent_names_2,
@@ -1244,7 +1163,7 @@
 	.mnd_width = 0,
 	.hid_width = 5,
 	.parent_map = gcc_parent_map_2,
-	.freq_tbl = ftbl_gcc_ufs_card_phy_aux_clk_src,
+	.freq_tbl = ftbl_gcc_cpuss_rbcpr_clk_src,
 	.enable_safe_config = true,
 	.clkr.hw.init = &(struct clk_init_data){
 		.name = "gcc_usb3_sec_phy_aux_clk_src",
@@ -2195,11 +2114,6 @@
 		.enable_mask = BIT(9),
 		.hw.init = &(struct clk_init_data){
 			.name = "gcc_qupv3_wrap0_core_2x_clk",
-			.parent_names = (const char *[]){
-				"gcc_qupv3_wrap0_core_2x_clk_src",
-			},
-			.num_parents = 1,
-			.flags = CLK_SET_RATE_PARENT,
 			.ops = &clk_branch2_ops,
 		},
 	},
@@ -2213,11 +2127,6 @@
 		.enable_mask = BIT(8),
 		.hw.init = &(struct clk_init_data){
 			.name = "gcc_qupv3_wrap0_core_clk",
-			.parent_names = (const char *[]){
-				"gcc_qupv3_wrap0_core_2x_clk_src",
-			},
-			.num_parents = 1,
-			.flags = CLK_SET_RATE_PARENT,
 			.ops = &clk_branch2_ops,
 		},
 	},
@@ -2375,11 +2284,6 @@
 		.enable_mask = BIT(18),
 		.hw.init = &(struct clk_init_data){
 			.name = "gcc_qupv3_wrap1_core_2x_clk",
-			.parent_names = (const char *[]){
-				"gcc_qupv3_wrap0_core_2x_clk_src",
-			},
-			.num_parents = 1,
-			.flags = CLK_SET_RATE_PARENT,
 			.ops = &clk_branch2_ops,
 		},
 	},
@@ -2393,11 +2297,6 @@
 		.enable_mask = BIT(19),
 		.hw.init = &(struct clk_init_data){
 			.name = "gcc_qupv3_wrap1_core_clk",
-			.parent_names = (const char *[]){
-				"gcc_qupv3_wrap0_core_2x_clk_src",
-			},
-			.num_parents = 1,
-			.flags = CLK_SET_RATE_PARENT,
 			.ops = &clk_branch2_ops,
 		},
 	},
@@ -3382,8 +3281,6 @@
 	[GCC_QMIP_DISP_AHB_CLK] = &gcc_qmip_disp_ahb_clk.clkr,
 	[GCC_QMIP_VIDEO_AHB_CLK] = &gcc_qmip_video_ahb_clk.clkr,
 	[GCC_QUPV3_WRAP0_CORE_2X_CLK] = &gcc_qupv3_wrap0_core_2x_clk.clkr,
-	[GCC_QUPV3_WRAP0_CORE_2X_CLK_SRC] =
-					&gcc_qupv3_wrap0_core_2x_clk_src.clkr,
 	[GCC_QUPV3_WRAP0_CORE_CLK] = &gcc_qupv3_wrap0_core_clk.clkr,
 	[GCC_QUPV3_WRAP0_S0_CLK] = &gcc_qupv3_wrap0_s0_clk.clkr,
 	[GCC_QUPV3_WRAP0_S0_CLK_SRC] = &gcc_qupv3_wrap0_s0_clk_src.clkr,
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c
index e5a2016..82e62c5 100644
--- a/drivers/clocksource/arm_arch_timer.c
+++ b/drivers/clocksource/arm_arch_timer.c
@@ -824,6 +824,7 @@
 
 	arch_timer_banner(arch_timers_present);
 	arch_counter_register(arch_timers_present);
+	clocksource_select_force();
 	return arch_timer_arch_init();
 }
 
diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig
index 0173b8b..884e557 100644
--- a/drivers/cpufreq/Kconfig
+++ b/drivers/cpufreq/Kconfig
@@ -120,14 +120,15 @@
 	  loading your cpufreq low-level hardware driver, using the
 	  'interactive' governor for latency-sensitive workloads.
 
-config CPU_FREQ_DEFAULT_GOV_INTERACTIVE
-	bool "interactive"
-	select CPU_FREQ_GOV_INTERACTIVE
+config CPU_FREQ_DEFAULT_GOV_SCHEDUTIL
+	bool "schedutil"
+	depends on SMP
+	select CPU_FREQ_GOV_SCHEDUTIL
+	select CPU_FREQ_GOV_PERFORMANCE
 	help
-	  Use the CPUFreq governor 'interactive' as default. This allows
-	  you to get a full dynamic cpu frequency capable system by simply
-	  loading your cpufreq low-level hardware driver, using the
-	  'interactive' governor for latency-sensitive workloads.
+	  Use the 'schedutil' CPUFreq governor by default. If unsure,
+	  have a look at the help section of that governor. The fallback
+	  governor will be 'performance'.
 
 endchoice
 
@@ -243,6 +244,23 @@
 
 	  If in doubt, say N.
 
+config CPU_FREQ_GOV_SCHEDUTIL
+	bool "'schedutil' cpufreq policy governor"
+	depends on CPU_FREQ && SMP
+	select CPU_FREQ_GOV_ATTR_SET
+	select IRQ_WORK
+	help
+	  This governor makes decisions based on the utilization data provided
+	  by the scheduler.  It sets the CPU frequency to be proportional to
+	  the utilization/capacity ratio coming from the scheduler.  If the
+	  utilization is frequency-invariant, the new frequency is also
+	  proportional to the maximum available frequency.  If that is not the
+	  case, it is proportional to the current frequency of the CPU.  The
+	  frequency tipping point is at utilization/capacity equal to 80% in
+	  both cases.
+
+	  If in doubt, say N.
+
 comment "CPU frequency scaling drivers"
 
 config CPUFREQ_DT
diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c
index 4737520..80fa656 100644
--- a/drivers/cpufreq/intel_pstate.c
+++ b/drivers/cpufreq/intel_pstate.c
@@ -820,6 +820,25 @@
 	wrmsrl_on_cpu(cpudata->cpu, MSR_PM_ENABLE, 0x1);
 }
 
+#define MSR_IA32_POWER_CTL_BIT_EE	19
+
+/* Disable energy efficiency optimization */
+static void intel_pstate_disable_ee(int cpu)
+{
+	u64 power_ctl;
+	int ret;
+
+	ret = rdmsrl_on_cpu(cpu, MSR_IA32_POWER_CTL, &power_ctl);
+	if (ret)
+		return;
+
+	if (!(power_ctl & BIT(MSR_IA32_POWER_CTL_BIT_EE))) {
+		pr_info("Disabling energy efficiency optimization\n");
+		power_ctl |= BIT(MSR_IA32_POWER_CTL_BIT_EE);
+		wrmsrl_on_cpu(cpu, MSR_IA32_POWER_CTL, power_ctl);
+	}
+}
+
 static int atom_get_min_pstate(void)
 {
 	u64 value;
@@ -1420,6 +1439,11 @@
 	{}
 };
 
+static const struct x86_cpu_id intel_pstate_cpu_ee_disable_ids[] = {
+	ICPU(INTEL_FAM6_KABYLAKE_DESKTOP, core_params),
+	{}
+};
+
 static int intel_pstate_init_cpu(unsigned int cpunum)
 {
 	struct cpudata *cpu;
@@ -1435,6 +1459,12 @@
 	cpu->cpu = cpunum;
 
 	if (hwp_active) {
+		const struct x86_cpu_id *id;
+
+		id = x86_match_cpu(intel_pstate_cpu_ee_disable_ids);
+		if (id)
+			intel_pstate_disable_ee(cpunum);
+
 		intel_pstate_hwp_enable(cpu);
 		pid_params.sample_rate_ms = 50;
 		pid_params.sample_rate_ns = 50 * NSEC_PER_MSEC;
diff --git a/drivers/cpuidle/lpm-levels.c b/drivers/cpuidle/lpm-levels.c
index cc380a0..8b59bee 100644
--- a/drivers/cpuidle/lpm-levels.c
+++ b/drivers/cpuidle/lpm-levels.c
@@ -381,7 +381,9 @@
 	struct lpm_cluster *cluster = per_cpu(cpu_cluster, cpu);
 
 	hrtimer_try_to_cancel(&cluster->histtimer);
-	hrtimer_try_to_cancel(&cluster->parent->histtimer);
+
+	if (cluster->parent)
+		hrtimer_try_to_cancel(&cluster->parent->histtimer);
 }
 
 static enum hrtimer_restart clusttimer_fn(struct hrtimer *h)
diff --git a/drivers/crypto/ccp/ccp-dev-v5.c b/drivers/crypto/ccp/ccp-dev-v5.c
index faf3cb3..a388bf2 100644
--- a/drivers/crypto/ccp/ccp-dev-v5.c
+++ b/drivers/crypto/ccp/ccp-dev-v5.c
@@ -955,7 +955,7 @@
 static void ccp5_config(struct ccp_device *ccp)
 {
 	/* Public side */
-	iowrite32(0x00001249, ccp->io_regs + CMD5_REQID_CONFIG_OFFSET);
+	iowrite32(0x0, ccp->io_regs + CMD5_REQID_CONFIG_OFFSET);
 }
 
 static void ccp5other_config(struct ccp_device *ccp)
diff --git a/drivers/crypto/ccp/ccp-dev.h b/drivers/crypto/ccp/ccp-dev.h
index da5f4a6..340aef1 100644
--- a/drivers/crypto/ccp/ccp-dev.h
+++ b/drivers/crypto/ccp/ccp-dev.h
@@ -238,6 +238,7 @@
 	struct ccp_device *ccp;
 
 	spinlock_t lock;
+	struct list_head created;
 	struct list_head pending;
 	struct list_head active;
 	struct list_head complete;
diff --git a/drivers/crypto/ccp/ccp-dmaengine.c b/drivers/crypto/ccp/ccp-dmaengine.c
index 6553912..e5d9278 100644
--- a/drivers/crypto/ccp/ccp-dmaengine.c
+++ b/drivers/crypto/ccp/ccp-dmaengine.c
@@ -63,6 +63,7 @@
 	ccp_free_desc_resources(chan->ccp, &chan->complete);
 	ccp_free_desc_resources(chan->ccp, &chan->active);
 	ccp_free_desc_resources(chan->ccp, &chan->pending);
+	ccp_free_desc_resources(chan->ccp, &chan->created);
 
 	spin_unlock_irqrestore(&chan->lock, flags);
 }
@@ -273,6 +274,7 @@
 	spin_lock_irqsave(&chan->lock, flags);
 
 	cookie = dma_cookie_assign(tx_desc);
+	list_del(&desc->entry);
 	list_add_tail(&desc->entry, &chan->pending);
 
 	spin_unlock_irqrestore(&chan->lock, flags);
@@ -426,7 +428,7 @@
 
 	spin_lock_irqsave(&chan->lock, sflags);
 
-	list_add_tail(&desc->entry, &chan->pending);
+	list_add_tail(&desc->entry, &chan->created);
 
 	spin_unlock_irqrestore(&chan->lock, sflags);
 
@@ -610,6 +612,7 @@
 	/*TODO: Purge the complete list? */
 	ccp_free_desc_resources(chan->ccp, &chan->active);
 	ccp_free_desc_resources(chan->ccp, &chan->pending);
+	ccp_free_desc_resources(chan->ccp, &chan->created);
 
 	spin_unlock_irqrestore(&chan->lock, flags);
 
@@ -679,6 +682,7 @@
 		chan->ccp = ccp;
 
 		spin_lock_init(&chan->lock);
+		INIT_LIST_HEAD(&chan->created);
 		INIT_LIST_HEAD(&chan->pending);
 		INIT_LIST_HEAD(&chan->active);
 		INIT_LIST_HEAD(&chan->complete);
diff --git a/drivers/crypto/chelsio/chcr_core.c b/drivers/crypto/chelsio/chcr_core.c
index fb5f9bb..6aece3f 100644
--- a/drivers/crypto/chelsio/chcr_core.c
+++ b/drivers/crypto/chelsio/chcr_core.c
@@ -51,6 +51,7 @@
 int assign_chcr_device(struct chcr_dev **dev)
 {
 	struct uld_ctx *u_ctx;
+	int ret = -ENXIO;
 
 	/*
 	 * Which device to use if multiple devices are available TODO
@@ -58,15 +59,14 @@
 	 * must go to the same device to maintain the ordering.
 	 */
 	mutex_lock(&dev_mutex); /* TODO ? */
-	u_ctx = list_first_entry(&uld_ctx_list, struct uld_ctx, entry);
-	if (!u_ctx) {
-		mutex_unlock(&dev_mutex);
-		return -ENXIO;
+	list_for_each_entry(u_ctx, &uld_ctx_list, entry)
+		if (u_ctx && u_ctx->dev) {
+			*dev = u_ctx->dev;
+			ret = 0;
+			break;
 	}
-
-	*dev = u_ctx->dev;
 	mutex_unlock(&dev_mutex);
-	return 0;
+	return ret;
 }
 
 static int chcr_dev_add(struct uld_ctx *u_ctx)
@@ -203,10 +203,8 @@
 
 static int __init chcr_crypto_init(void)
 {
-	if (cxgb4_register_uld(CXGB4_ULD_CRYPTO, &chcr_uld_info)) {
+	if (cxgb4_register_uld(CXGB4_ULD_CRYPTO, &chcr_uld_info))
 		pr_err("ULD register fail: No chcr crypto support in cxgb4");
-		return -1;
-	}
 
 	return 0;
 }
diff --git a/drivers/crypto/qat/qat_c62x/adf_drv.c b/drivers/crypto/qat/qat_c62x/adf_drv.c
index bc5cbc1..5b2d78a 100644
--- a/drivers/crypto/qat/qat_c62x/adf_drv.c
+++ b/drivers/crypto/qat/qat_c62x/adf_drv.c
@@ -233,7 +233,7 @@
 			      &hw_data->accel_capabilities_mask);
 
 	/* Find and map all the device's BARS */
-	i = 0;
+	i = (hw_data->fuses & ADF_DEVICE_FUSECTL_MASK) ? 1 : 0;
 	bar_mask = pci_select_bars(pdev, IORESOURCE_MEM);
 	for_each_set_bit(bar_nr, (const unsigned long *)&bar_mask,
 			 ADF_PCI_MAX_BARS * 2) {
diff --git a/drivers/crypto/qat/qat_common/adf_accel_devices.h b/drivers/crypto/qat/qat_common/adf_accel_devices.h
index e882253..33f0a62 100644
--- a/drivers/crypto/qat/qat_common/adf_accel_devices.h
+++ b/drivers/crypto/qat/qat_common/adf_accel_devices.h
@@ -69,6 +69,7 @@
 #define ADF_ERRSOU5 (0x3A000 + 0xD8)
 #define ADF_DEVICE_FUSECTL_OFFSET 0x40
 #define ADF_DEVICE_LEGFUSE_OFFSET 0x4C
+#define ADF_DEVICE_FUSECTL_MASK 0x80000000
 #define ADF_PCI_MAX_BARS 3
 #define ADF_DEVICE_NAME_LENGTH 32
 #define ADF_ETR_MAX_RINGS_PER_BANK 16
diff --git a/drivers/crypto/qat/qat_common/qat_hal.c b/drivers/crypto/qat/qat_common/qat_hal.c
index 1e480f1..8c4fd25 100644
--- a/drivers/crypto/qat/qat_common/qat_hal.c
+++ b/drivers/crypto/qat/qat_common/qat_hal.c
@@ -456,7 +456,7 @@
 	unsigned int csr_val;
 	int times = 30;
 
-	if (handle->pci_dev->device == ADF_C3XXX_PCI_DEVICE_ID)
+	if (handle->pci_dev->device != ADF_DH895XCC_PCI_DEVICE_ID)
 		return 0;
 
 	csr_val = ADF_CSR_RD(csr_addr, 0);
@@ -716,7 +716,7 @@
 		(void __iomem *)((uintptr_t)handle->hal_cap_ae_xfer_csr_addr_v +
 				 LOCAL_TO_XFER_REG_OFFSET);
 	handle->pci_dev = pci_info->pci_dev;
-	if (handle->pci_dev->device != ADF_C3XXX_PCI_DEVICE_ID) {
+	if (handle->pci_dev->device == ADF_DH895XCC_PCI_DEVICE_ID) {
 		sram_bar =
 			&pci_info->pci_bars[hw_data->get_sram_bar_id(hw_data)];
 		handle->hal_sram_addr_v = sram_bar->virt_addr;
diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index e6862a7..4e19bde 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -1759,16 +1759,16 @@
 
 	if (ret && arg->flags & DRM_MODE_PAGE_FLIP_EVENT) {
 		/*
-		 * TEST_ONLY and PAGE_FLIP_EVENT are mutually exclusive,
-		 * if they weren't, this code should be called on success
-		 * for TEST_ONLY too.
+		 * Free the allocated event. drm_atomic_helper_setup_commit
+		 * can allocate an event too, so only free it if it's ours
+		 * to prevent a double free in drm_atomic_state_clear.
 		 */
-
 		for_each_crtc_in_state(state, crtc, crtc_state, i) {
-			if (!crtc_state->event)
-				continue;
-
-			drm_event_cancel_free(dev, &crtc_state->event->base);
+			struct drm_pending_vblank_event *event = crtc_state->event;
+			if (event && (event->base.fence || event->base.file_priv)) {
+				drm_event_cancel_free(dev, &event->base);
+				crtc_state->event = NULL;
+			}
 		}
 	}
 
diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c
index aa64448..f59771d 100644
--- a/drivers/gpu/drm/drm_dp_mst_topology.c
+++ b/drivers/gpu/drm/drm_dp_mst_topology.c
@@ -1817,7 +1817,7 @@
 				mgr->payloads[i].vcpi = req_payload.vcpi;
 			} else if (mgr->payloads[i].num_slots) {
 				mgr->payloads[i].num_slots = 0;
-				drm_dp_destroy_payload_step1(mgr, port, port->vcpi.vcpi, &mgr->payloads[i]);
+				drm_dp_destroy_payload_step1(mgr, port, mgr->payloads[i].vcpi, &mgr->payloads[i]);
 				req_payload.payload_state = mgr->payloads[i].payload_state;
 				mgr->payloads[i].start_slot = 0;
 			}
diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c
index a218c2e..0c400f8 100644
--- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c
+++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c
@@ -1215,14 +1215,14 @@
 			if (exec[i].offset !=
 			    gen8_canonical_addr(exec[i].offset & PAGE_MASK))
 				return -EINVAL;
-
-			/* From drm_mm perspective address space is continuous,
-			 * so from this point we're always using non-canonical
-			 * form internally.
-			 */
-			exec[i].offset = gen8_noncanonical_addr(exec[i].offset);
 		}
 
+		/* From drm_mm perspective address space is continuous,
+		 * so from this point we're always using non-canonical
+		 * form internally.
+		 */
+		exec[i].offset = gen8_noncanonical_addr(exec[i].offset);
+
 		if (exec[i].alignment && !is_power_of_2(exec[i].alignment))
 			return -EINVAL;
 
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 8079e5b..b9be8a6 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -4280,10 +4280,10 @@
 	drm_crtc_vblank_put(&intel_crtc->base);
 
 	wake_up_all(&dev_priv->pending_flip_queue);
-	queue_work(dev_priv->wq, &work->unpin_work);
-
 	trace_i915_flip_complete(intel_crtc->plane,
 				 work->pending_flip_obj);
+
+	queue_work(dev_priv->wq, &work->unpin_work);
 }
 
 static int intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc)
diff --git a/drivers/gpu/drm/i915/intel_dpll_mgr.c b/drivers/gpu/drm/i915/intel_dpll_mgr.c
index 1c59ca5..cae27c5 100644
--- a/drivers/gpu/drm/i915/intel_dpll_mgr.c
+++ b/drivers/gpu/drm/i915/intel_dpll_mgr.c
@@ -1723,7 +1723,8 @@
 		return NULL;
 
 	if ((encoder->type == INTEL_OUTPUT_DP ||
-	     encoder->type == INTEL_OUTPUT_EDP) &&
+	     encoder->type == INTEL_OUTPUT_EDP ||
+	     encoder->type == INTEL_OUTPUT_DP_MST) &&
 	    !bxt_ddi_dp_set_dpll_hw_state(clock, &dpll_hw_state))
 		return NULL;
 
diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile
index af327f1..b67efc8 100644
--- a/drivers/gpu/drm/msm/Makefile
+++ b/drivers/gpu/drm/msm/Makefile
@@ -51,6 +51,8 @@
 	sde_io_util.o \
 	sde/sde_hw_reg_dma_v1_color_proc.o \
 	sde/sde_hw_color_proc_v4.o \
+	sde_rsc.o \
+	sde_rsc_hw.o \
 
 # use drm gpu driver only if qcom_kgsl driver not available
 ifneq ($(CONFIG_QCOM_KGSL),y)
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c
index f54852d..1525cb2 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c
@@ -2660,13 +2660,19 @@
 {
 	struct dsi_display *display;
 	struct dsi_panel_phy_props phy_props;
+	struct dsi_mode_info *timing;
 	int i, rc;
 
 	if (!info || !disp) {
 		pr_err("invalid params\n");
 		return -EINVAL;
 	}
+
 	display = disp;
+	if (!display->panel) {
+		pr_err("invalid display panel\n");
+		return -EINVAL;
+	}
 
 	mutex_lock(&display->display_lock);
 	rc = dsi_panel_get_phy_props(display->panel, &phy_props);
@@ -2677,12 +2683,18 @@
 	}
 
 	info->intf_type = DRM_MODE_CONNECTOR_DSI;
+	timing = &display->panel->mode.timing;
 
 	info->num_of_h_tiles = display->ctrl_count;
 	for (i = 0; i < info->num_of_h_tiles; i++)
 		info->h_tile_instance[i] = display->ctrl[i].ctrl->index;
 
 	info->is_connected = true;
+	info->is_primary = true;
+	info->frame_rate = timing->refresh_rate;
+	info->vtotal = DSI_V_TOTAL(timing);
+	info->prefill_lines = display->panel->panel_prefill_lines;
+	info->jitter = display->panel->panel_jitter;
 	info->width_mm = phy_props.panel_width_mm;
 	info->height_mm = phy_props.panel_height_mm;
 	info->max_width = 1920;
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c
index fa10b55..23f0577 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c
@@ -24,6 +24,10 @@
 
 #define DEFAULT_MDP_TRANSFER_TIME 14000
 
+#define DEFAULT_PANEL_JITTER		5
+#define MAX_PANEL_JITTER		25
+#define DEFAULT_PANEL_PREFILL_LINES	16
+
 static int dsi_panel_vreg_get(struct dsi_panel *panel)
 {
 	int rc = 0;
@@ -1361,6 +1365,37 @@
 	return rc;
 }
 
+static int dsi_panel_parse_jitter_config(struct dsi_panel *panel,
+				     struct device_node *of_node)
+{
+	int rc;
+
+	rc = of_property_read_u32(of_node, "qcom,mdss-dsi-panel-jitter",
+				  &panel->panel_jitter);
+	if (rc) {
+		pr_debug("panel jitter is not defined rc=%d\n", rc);
+		panel->panel_jitter = DEFAULT_PANEL_JITTER;
+	} else if (panel->panel_jitter > MAX_PANEL_JITTER) {
+		pr_debug("invalid jitter config=%d setting to:%d\n",
+			panel->panel_jitter, DEFAULT_PANEL_JITTER);
+		panel->panel_jitter = DEFAULT_PANEL_JITTER;
+	}
+
+	rc = of_property_read_u32(of_node, "qcom,mdss-dsi-panel-prefill-lines",
+				  &panel->panel_prefill_lines);
+	if (rc) {
+		pr_debug("panel prefill lines are not defined rc=%d\n", rc);
+		panel->panel_prefill_lines = DEFAULT_PANEL_PREFILL_LINES;
+	} else if (panel->panel_prefill_lines >=
+					DSI_V_TOTAL(&panel->mode.timing))  {
+		pr_debug("invalid prefill lines config=%d setting to:%d\n",
+		      panel->panel_prefill_lines, DEFAULT_PANEL_PREFILL_LINES);
+		panel->panel_prefill_lines = DEFAULT_PANEL_PREFILL_LINES;
+	}
+
+	return 0;
+}
+
 static int dsi_panel_parse_power_cfg(struct device *parent,
 				     struct dsi_panel *panel,
 				     struct device_node *of_node)
@@ -1643,6 +1678,10 @@
 	if (rc)
 		pr_err("failed to parse backlight config, rc=%d\n", rc);
 
+	rc = dsi_panel_parse_jitter_config(panel, of_node);
+	if (rc)
+		pr_err("failed to parse panel jitter config, rc=%d\n", rc);
+
 	panel->panel_of_node = of_node;
 	drm_panel_init(&panel->drm_panel);
 	mutex_init(&panel->panel_lock);
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.h b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.h
index 7b60193..386e8a9 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.h
@@ -176,6 +176,8 @@
 	bool ulps_enabled;
 	bool allow_phy_power_off;
 
+	u32 panel_jitter;
+	u32 panel_prefill_lines;
 	bool panel_initialized;
 };
 
diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h
index 585e206..ca4d213 100644
--- a/drivers/gpu/drm/msm/msm_drv.h
+++ b/drivers/gpu/drm/msm/msm_drv.h
@@ -205,6 +205,11 @@
  *                      this is max width supported by controller
  * @max_height:         Max height of display. In case of hot pluggable display
  *                      this is max height supported by controller
+ * @is_primary:         Set to true if display is primary display
+ * @frame_rate:		Display frame rate
+ * @prefill_lines:	prefill lines based on porches.
+ * @vtotal:		display vertical total
+ * @jitter:		display jitter configuration
  * @compression:        Compression supported by the display
  */
 struct msm_display_info {
@@ -222,6 +227,12 @@
 	uint32_t max_width;
 	uint32_t max_height;
 
+	bool is_primary;
+	uint32_t frame_rate;
+	uint32_t prefill_lines;
+	uint32_t vtotal;
+	uint32_t jitter;
+
 	enum msm_display_compression compression;
 };
 
diff --git a/drivers/gpu/drm/msm/sde/sde_color_processing.c b/drivers/gpu/drm/msm/sde/sde_color_processing.c
index 6892646..f7fcd01 100644
--- a/drivers/gpu/drm/msm/sde/sde_color_processing.c
+++ b/drivers/gpu/drm/msm/sde/sde_color_processing.c
@@ -531,9 +531,10 @@
 			hw_dspp->ops.setup_cont(hw_dspp, &hw_cfg);
 			break;
 		case SDE_CP_CRTC_DSPP_MEMCOLOR:
-			if (!hw_dspp || !hw_dspp->ops.setup_pa_memcolor)
+			if (!hw_dspp || !hw_dspp->ops.setup_pa_memcolor) {
 				ret = -EINVAL;
 				continue;
+			}
 			hw_dspp->ops.setup_pa_memcolor(hw_dspp, &hw_cfg);
 			break;
 		case SDE_CP_CRTC_DSPP_SIXZONE:
@@ -638,16 +639,18 @@
 		if (!ctl)
 			continue;
 		if (set_dspp_flush && ctl->ops.get_bitmask_dspp
-				&& sde_crtc->mixers[i].hw_dspp)
+				&& sde_crtc->mixers[i].hw_dspp) {
 			ctl->ops.get_bitmask_dspp(ctl,
 					&flush_mask,
 					sde_crtc->mixers[i].hw_dspp->idx);
 			ctl->ops.update_pending_flush(ctl, flush_mask);
+		}
 		if (set_lm_flush && ctl->ops.get_bitmask_mixer
-				&& sde_crtc->mixers[i].hw_lm)
+				&& sde_crtc->mixers[i].hw_lm) {
 			flush_mask = ctl->ops.get_bitmask_mixer(ctl,
 					sde_crtc->mixers[i].hw_lm->idx);
 			ctl->ops.update_pending_flush(ctl, flush_mask);
+		}
 	}
 }
 
diff --git a/drivers/gpu/drm/msm/sde/sde_core_perf.c b/drivers/gpu/drm/msm/sde/sde_core_perf.c
index 0ba644d..7a68f91 100644
--- a/drivers/gpu/drm/msm/sde/sde_core_perf.c
+++ b/drivers/gpu/drm/msm/sde/sde_core_perf.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -22,16 +22,10 @@
 #include "msm_prop.h"
 
 #include "sde_kms.h"
-#include "sde_fence.h"
-#include "sde_formats.h"
-#include "sde_hw_sspp.h"
 #include "sde_trace.h"
 #include "sde_crtc.h"
-#include "sde_plane.h"
-#include "sde_encoder.h"
-#include "sde_wb.h"
+#include "sde_rsc.h"
 #include "sde_core_perf.h"
-#include "sde_trace.h"
 
 static struct sde_kms *_sde_crtc_get_kms(struct drm_crtc *crtc)
 {
@@ -59,20 +53,23 @@
 static bool _sde_core_video_mode_intf_connected(struct drm_crtc *crtc)
 {
 	struct drm_crtc *tmp_crtc;
+	bool intf_connected = false;
 
 	if (!crtc)
-		return 0;
+		goto end;
 
 	drm_for_each_crtc(tmp_crtc, crtc->dev) {
 		if ((sde_crtc_get_intf_mode(tmp_crtc) == INTF_MODE_VIDEO) &&
 				_sde_core_perf_crtc_is_power_on(tmp_crtc)) {
 			SDE_DEBUG("video interface connected crtc:%d\n",
 				tmp_crtc->base.id);
-			return true;
+			intf_connected = true;
+			goto end;
 		}
 	}
 
-	return false;
+end:
+	return intf_connected;
 }
 
 int sde_core_perf_crtc_check(struct drm_crtc *crtc,
@@ -80,6 +77,7 @@
 {
 	u32 bw, threshold;
 	u64 bw_sum_of_intfs = 0;
+	enum sde_crtc_client_type curr_client_type;
 	bool is_video_mode;
 	struct sde_crtc_state *sde_cstate;
 	struct drm_crtc *tmp_crtc;
@@ -97,16 +95,18 @@
 	}
 
 	/* we only need bandwidth check on real-time clients (interfaces) */
-	if (sde_crtc_is_wb(crtc))
+	if (sde_crtc_get_client_type(crtc) == NRT_CLIENT)
 		return 0;
 
 	sde_cstate = to_sde_crtc_state(state);
 
 	bw_sum_of_intfs = sde_crtc_get_property(sde_cstate, CRTC_PROP_CORE_AB);
+	curr_client_type = sde_crtc_get_client_type(crtc);
 
 	drm_for_each_crtc(tmp_crtc, crtc->dev) {
 		if (_sde_core_perf_crtc_is_power_on(tmp_crtc) &&
-				sde_crtc_is_rt(tmp_crtc) && tmp_crtc != crtc) {
+		    (sde_crtc_get_client_type(tmp_crtc) == curr_client_type) &&
+		    (tmp_crtc != crtc)) {
 			struct sde_crtc_state *tmp_cstate =
 					to_sde_crtc_state(tmp_crtc->state);
 
@@ -131,7 +131,7 @@
 		return -E2BIG;
 	} else if (bw > threshold) {
 		sde_cstate->cur_perf.bw_ctl = 0;
-		SDE_DEBUG("exceeds bandwidth: %ukb > %ukb\n", bw, threshold);
+		SDE_ERROR("exceeds bandwidth: %ukb > %ukb\n", bw, threshold);
 		return -E2BIG;
 	}
 
@@ -158,23 +158,23 @@
 			perf->max_per_pipe_ib, perf->bw_ctl);
 }
 
-static u64 _sde_core_perf_crtc_calc_client_vote(struct sde_kms *kms,
-		struct drm_crtc *crtc, struct sde_core_perf_params *perf,
-		bool nrt_client, u32 core_clk)
+static void _sde_core_perf_crtc_update_bus(struct sde_kms *kms,
+		struct drm_crtc *crtc)
 {
-	u64 bw_sum_of_intfs = 0;
+	u64 bw_sum_of_intfs = 0, bus_ab_quota, bus_ib_quota;
+	struct sde_core_perf_params perf = {0};
+	enum sde_crtc_client_type curr_client_type
+					= sde_crtc_get_client_type(crtc);
 	struct drm_crtc *tmp_crtc;
+	struct sde_crtc_state *sde_cstate;
+	struct msm_drm_private *priv = kms->dev->dev_private;
 
 	drm_for_each_crtc(tmp_crtc, crtc->dev) {
-		if (_sde_core_perf_crtc_is_power_on(crtc) &&
-		    /* RealTime clients */
-		    ((!nrt_client) ||
-		    /* Non-RealTime clients */
-		    (nrt_client && sde_crtc_is_nrt(tmp_crtc)))) {
-			struct sde_crtc_state *sde_cstate =
-					to_sde_crtc_state(tmp_crtc->state);
+		if (_sde_core_perf_crtc_is_power_on(tmp_crtc) &&
+		    (curr_client_type == sde_crtc_get_client_type(tmp_crtc))) {
+			sde_cstate = to_sde_crtc_state(tmp_crtc->state);
 
-			perf->max_per_pipe_ib = max(perf->max_per_pipe_ib,
+			perf.max_per_pipe_ib = max(perf.max_per_pipe_ib,
 				sde_cstate->cur_perf.max_per_pipe_ib);
 
 			bw_sum_of_intfs += sde_cstate->cur_perf.bw_ctl;
@@ -185,57 +185,38 @@
 		}
 	}
 
-	return bw_sum_of_intfs;
-}
+	bus_ab_quota = max(bw_sum_of_intfs, kms->perf.perf_tune.min_bus_vote);
+	bus_ib_quota = perf.max_per_pipe_ib;
 
-static void _sde_core_perf_crtc_update_client_vote(struct sde_kms *kms,
-	struct sde_core_perf_params *params, bool nrt_client, u64 bw_vote)
-{
-	struct msm_drm_private *priv = kms->dev->dev_private;
-	u64 bus_ab_quota, bus_ib_quota;
+	switch (curr_client_type) {
+	case NRT_CLIENT:
+		sde_power_data_bus_set_quota(&priv->phandle, kms->core_client,
+				SDE_POWER_HANDLE_DATA_BUS_CLIENT_NRT,
+				bus_ab_quota, bus_ib_quota);
+		SDE_DEBUG("client:%s ab=%llu ib=%llu\n", "nrt",
+				bus_ab_quota, bus_ib_quota);
+		break;
 
-	bus_ab_quota = max(bw_vote, kms->perf.perf_tune.min_bus_vote);
-	bus_ib_quota = params->max_per_pipe_ib;
-
-	SDE_ATRACE_INT("bus_quota", bus_ib_quota);
-	sde_power_data_bus_set_quota(&priv->phandle, kms->core_client,
-		nrt_client ? SDE_POWER_HANDLE_DATA_BUS_CLIENT_NRT :
+	case RT_CLIENT:
+		sde_power_data_bus_set_quota(&priv->phandle, kms->core_client,
 				SDE_POWER_HANDLE_DATA_BUS_CLIENT_RT,
-		bus_ab_quota, bus_ib_quota);
-	SDE_DEBUG("client:%s ab=%llu ib=%llu\n", nrt_client ? "nrt" : "rt",
-		bus_ab_quota, bus_ib_quota);
-}
+				bus_ab_quota, bus_ib_quota);
+		SDE_DEBUG("client:%s ab=%llu ib=%llu\n", "rt",
+				bus_ab_quota, bus_ib_quota);
+		break;
 
-static void _sde_core_perf_crtc_update_bus(struct sde_kms *kms,
-		struct drm_crtc *crtc, u32 core_clk)
-{
-	u64 bw_sum_of_rt_intfs = 0, bw_sum_of_nrt_intfs = 0;
-	struct sde_core_perf_params params = {0};
+	case RT_RSC_CLIENT:
+		sde_cstate = to_sde_crtc_state(crtc->state);
+		sde_rsc_client_vote(sde_cstate->rsc_client, bus_ab_quota,
+					bus_ib_quota);
+		SDE_DEBUG("client:%s ab=%llu ib=%llu\n", "rt_rsc",
+				bus_ab_quota, bus_ib_quota);
+		break;
 
-	SDE_ATRACE_BEGIN(__func__);
-
-	/*
-	 * non-real time client
-	 */
-	if (sde_crtc_is_nrt(crtc)) {
-		bw_sum_of_nrt_intfs = _sde_core_perf_crtc_calc_client_vote(
-				kms, crtc, &params, true, core_clk);
-		_sde_core_perf_crtc_update_client_vote(kms, &params, true,
-			bw_sum_of_nrt_intfs);
+	default:
+		SDE_ERROR("invalid client type:%d\n", curr_client_type);
+		break;
 	}
-
-	/*
-	 * real time client
-	 */
-	if (!sde_crtc_is_nrt(crtc) ||
-		sde_crtc_is_wb(crtc)) {
-		bw_sum_of_rt_intfs = _sde_core_perf_crtc_calc_client_vote(kms,
-				crtc, &params, false, core_clk);
-		_sde_core_perf_crtc_update_client_vote(kms, &params, false,
-			bw_sum_of_rt_intfs);
-	}
-
-	SDE_ATRACE_END(__func__);
 }
 
 /**
@@ -265,9 +246,9 @@
 
 	sde_cstate = to_sde_crtc_state(crtc->state);
 
-	/* only do this for command panel or writeback */
+	/* only do this for command mode rt client (non-rsc client) */
 	if ((sde_crtc_get_intf_mode(crtc) != INTF_MODE_CMD) &&
-			(sde_crtc_get_intf_mode(crtc) != INTF_MODE_WB_LINE))
+		(sde_crtc_get_client_type(crtc) != RT_RSC_CLIENT))
 		return;
 
 	/*
@@ -288,22 +269,15 @@
 		sde_cstate->cur_perf.bw_ctl = 0;
 		sde_cstate->new_perf.bw_ctl = 0;
 		SDE_DEBUG("Release BW crtc=%d\n", crtc->base.id);
-		_sde_core_perf_crtc_update_bus(kms, crtc, 0);
+		_sde_core_perf_crtc_update_bus(kms, crtc);
 	}
 }
 
-static int _sde_core_select_clk_lvl(struct sde_kms *kms,
-			u32 clk_rate)
-{
-	return clk_round_rate(kms->perf.core_clk, clk_rate);
-}
-
 static u32 _sde_core_perf_get_core_clk_rate(struct sde_kms *kms)
 {
 	u32 clk_rate = 0;
 	struct drm_crtc *crtc;
 	struct sde_crtc_state *sde_cstate;
-	int ncrtc = 0;
 
 	drm_for_each_crtc(crtc, kms->dev) {
 		if (_sde_core_perf_crtc_is_power_on(crtc)) {
@@ -312,11 +286,9 @@
 							clk_rate);
 			clk_rate = clk_round_rate(kms->perf.core_clk, clk_rate);
 		}
-		ncrtc++;
 	}
-	clk_rate = _sde_core_select_clk_lvl(kms, clk_rate);
 
-	SDE_DEBUG("clk:%u ncrtc:%d\n", clk_rate, ncrtc);
+	SDE_DEBUG("clk:%u\n", clk_rate);
 
 	return clk_rate;
 }
@@ -351,8 +323,6 @@
 	SDE_DEBUG("crtc:%d stop_req:%d core_clk:%u\n",
 			crtc->base.id, stop_req, kms->perf.core_clk_rate);
 
-	SDE_ATRACE_BEGIN(__func__);
-
 	old = &sde_cstate->cur_perf;
 	new = &sde_cstate->new_perf;
 
@@ -392,38 +362,28 @@
 		update_clk = 1;
 	}
 
-	/*
-	 * Calculate mdp clock before bandwidth calculation. If traffic shaper
-	 * is enabled and clock increased, the bandwidth calculation can
-	 * use the new clock for the rotator bw calculation.
-	 */
-	if (update_clk)
-		clk_rate = _sde_core_perf_get_core_clk_rate(kms);
-
 	if (update_bus)
-		_sde_core_perf_crtc_update_bus(kms, crtc, clk_rate);
+		_sde_core_perf_crtc_update_bus(kms, crtc);
 
 	/*
 	 * Update the clock after bandwidth vote to ensure
 	 * bandwidth is available before clock rate is increased.
 	 */
 	if (update_clk) {
-		SDE_ATRACE_INT(kms->perf.clk_name, clk_rate);
+		clk_rate = _sde_core_perf_get_core_clk_rate(kms);
+
 		SDE_EVT32(kms->dev, stop_req, clk_rate);
 		ret = sde_power_clk_set_rate(&priv->phandle,
 				kms->perf.clk_name, clk_rate);
 		if (ret) {
 			SDE_ERROR("failed to set %s clock rate %u\n",
 					kms->perf.clk_name, clk_rate);
-			goto end;
+			return;
 		}
 
 		kms->perf.core_clk_rate = clk_rate;
 		SDE_DEBUG("update clk rate = %d HZ\n", clk_rate);
 	}
-
-end:
-	SDE_ATRACE_END(__func__);
 }
 
 #ifdef CONFIG_DEBUG_FS
diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.c b/drivers/gpu/drm/msm/sde/sde_crtc.c
index ba68652..821f93f 100644
--- a/drivers/gpu/drm/msm/sde/sde_crtc.c
+++ b/drivers/gpu/drm/msm/sde/sde_crtc.c
@@ -417,7 +417,6 @@
 	SDE_EVT32(DRMID(crtc));
 
 	/* identify connectors attached to this crtc */
-	cstate->is_rt = false;
 	cstate->num_connectors = 0;
 
 	drm_for_each_connector(conn, crtc->dev)
@@ -425,9 +424,6 @@
 				cstate->num_connectors < MAX_CONNECTORS) {
 			cstate->connectors[cstate->num_connectors++] = conn;
 			sde_connector_prepare_fence(conn);
-
-			if (conn->connector_type != DRM_MODE_CONNECTOR_VIRTUAL)
-				cstate->is_rt = true;
 		}
 
 	if (cstate->num_connectors > 0 && cstate->connectors[0]->encoder)
@@ -440,15 +436,6 @@
 	sde_fence_prepare(&sde_crtc->output_fence);
 }
 
-bool sde_crtc_is_rt(struct drm_crtc *crtc)
-{
-	if (!crtc || !crtc->state) {
-		SDE_ERROR("invalid crtc or state\n");
-		return true;
-	}
-	return to_sde_crtc_state(crtc->state)->is_rt;
-}
-
 /* if file!=NULL, this is preclose potential cancel-flip path */
 static void _sde_crtc_complete_flip(struct drm_crtc *crtc,
 		struct drm_file *file)
@@ -542,8 +529,6 @@
 					crtc->base.id,
 					ktime_to_ns(fevent->ts));
 			SDE_EVT32(DRMID(crtc), fevent->event, 1);
-			sde_power_data_bus_bandwidth_ctrl(&priv->phandle,
-					sde_kms->core_client, false);
 			sde_core_perf_crtc_release_bw(crtc);
 		} else {
 			SDE_EVT32(DRMID(crtc), fevent->event, 2);
@@ -882,10 +867,12 @@
 static void sde_crtc_atomic_flush(struct drm_crtc *crtc,
 		struct drm_crtc_state *old_crtc_state)
 {
+	struct drm_encoder *encoder;
 	struct sde_crtc *sde_crtc;
 	struct drm_device *dev;
 	struct drm_plane *plane;
 	unsigned long flags;
+	struct sde_crtc_state *cstate;
 
 	if (!crtc) {
 		SDE_ERROR("invalid crtc\n");
@@ -901,7 +888,7 @@
 	SDE_DEBUG("crtc%d\n", crtc->base.id);
 
 	sde_crtc = to_sde_crtc(crtc);
-
+	cstate = to_sde_crtc_state(crtc->state);
 	dev = crtc->dev;
 
 	if (sde_crtc->event) {
@@ -923,6 +910,17 @@
 	/* wait for acquire fences before anything else is done */
 	_sde_crtc_wait_for_fences(crtc);
 
+	if (!cstate->rsc_update) {
+		drm_for_each_encoder(encoder, dev) {
+			if (encoder->crtc != crtc)
+				continue;
+
+			cstate->rsc_client =
+				sde_encoder_update_rsc_client(encoder, true);
+		}
+		cstate->rsc_update = true;
+	}
+
 	/* update performance setting before crtc kickoff */
 	sde_core_perf_crtc_update(crtc, 1, false);
 
@@ -1003,8 +1001,6 @@
 		/* acquire bandwidth and other resources */
 		SDE_DEBUG("crtc%d first commit\n", crtc->base.id);
 		SDE_EVT32(DRMID(crtc), 1);
-		sde_power_data_bus_bandwidth_ctrl(&priv->phandle,
-				sde_kms->core_client, true);
 	} else {
 		SDE_DEBUG("crtc%d commit\n", crtc->base.id);
 		SDE_EVT32(DRMID(crtc), 2);
@@ -1095,6 +1091,7 @@
 {
 	struct msm_drm_private *priv;
 	struct sde_crtc *sde_crtc;
+	struct sde_crtc_state *cstate;
 	struct drm_encoder *encoder;
 	struct sde_kms *sde_kms;
 
@@ -1103,6 +1100,7 @@
 		return;
 	}
 	sde_crtc = to_sde_crtc(crtc);
+	cstate = to_sde_crtc_state(crtc->state);
 	sde_kms = _sde_crtc_get_kms(crtc);
 	priv = sde_kms->dev->dev_private;
 
@@ -1129,8 +1127,6 @@
 		SDE_ERROR("crtc%d invalid frame pending\n",
 				crtc->base.id);
 		SDE_EVT32(DRMID(crtc));
-		sde_power_data_bus_bandwidth_ctrl(&priv->phandle,
-				sde_kms->core_client, false);
 		sde_core_perf_crtc_release_bw(crtc);
 		atomic_set(&sde_crtc->frame_pending, 0);
 	}
@@ -1141,6 +1137,9 @@
 		if (encoder->crtc != crtc)
 			continue;
 		sde_encoder_register_frame_event_callback(encoder, NULL, NULL);
+		sde_encoder_update_rsc_client(encoder, false);
+		cstate->rsc_client = NULL;
+		cstate->rsc_update = false;
 	}
 
 	memset(sde_crtc->mixers, 0, sizeof(sde_crtc->mixers));
@@ -1875,7 +1874,7 @@
 	struct sde_crtc_state *cstate = to_sde_crtc_state(crtc->state);
 
 	seq_printf(s, "num_connectors: %d\n", cstate->num_connectors);
-	seq_printf(s, "is_rt: %d\n", cstate->is_rt);
+	seq_printf(s, "client type: %d\n", sde_crtc_get_client_type(crtc));
 	seq_printf(s, "intf_mode: %d\n", cstate->intf_mode);
 	seq_printf(s, "bw_ctl: %llu\n", cstate->cur_perf.bw_ctl);
 	seq_printf(s, "core_clk_rate: %u\n", cstate->cur_perf.core_clk_rate);
diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.h b/drivers/gpu/drm/msm/sde/sde_crtc.h
index 91fdaed..c4546b9 100644
--- a/drivers/gpu/drm/msm/sde/sde_crtc.h
+++ b/drivers/gpu/drm/msm/sde/sde_crtc.h
@@ -31,6 +31,20 @@
 #define SDE_CRTC_FRAME_EVENT_SIZE	2
 
 /**
+ * enum sde_crtc_client_type: crtc client type
+ * @RT_CLIENT:	RealTime client like video/cmd mode display
+ *              voting through apps rsc
+ * @NRT_CLIENT:	Non-RealTime client like WB display
+ *              voting through apps rsc
+ * @RT_RSC_CLIENT:	Realtime display RSC voting client
+ */
+enum sde_crtc_client_type {
+	RT_CLIENT,
+	NRT_CLIENT,
+	RT_RSC_CLIENT,
+};
+
+/**
  * struct sde_crtc_mixer: stores the map for each virtual pipeline in the CRTC
  * @hw_lm:	LM HW Driver context
  * @hw_ctl:	CTL Path HW driver context
@@ -136,8 +150,8 @@
  * @base: Base drm crtc state structure
  * @connectors    : Currently associated drm connectors
  * @num_connectors: Number of associated drm connectors
- * @is_rt         : Whether or not the current commit contains RT connectors
  * @intf_mode     : Interface mode of the primary connector
+ * @rsc_client    : sde rsc client when mode is valid
  * @property_values: Current crtc property values
  * @input_fence_timeout_ns : Cached input fence timeout, in ns
  * @property_blobs: Reference pointers for blob properties
@@ -151,8 +165,9 @@
 
 	struct drm_connector *connectors[MAX_CONNECTORS];
 	int num_connectors;
-	bool is_rt;
 	enum sde_intf_mode intf_mode;
+	struct sde_rsc_client *rsc_client;
+	bool rsc_update;
 
 	uint64_t property_values[CRTC_PROP_COUNT];
 	uint64_t input_fence_timeout_ns;
@@ -255,13 +270,6 @@
 void sde_crtc_cancel_pending_flip(struct drm_crtc *crtc, struct drm_file *file);
 
 /**
- * sde_crtc_is_rt - query whether real time connectors are present on the crtc
- * @crtc: Pointer to drm crtc structure
- * Returns: True if a connector is present with real time constraints
- */
-bool sde_crtc_is_rt(struct drm_crtc *crtc);
-
-/**
  * sde_crtc_get_intf_mode - get interface mode of the given crtc
  * @crtc: Pointert to crtc
  */
@@ -274,24 +282,20 @@
 }
 
 /**
- * sde_core_perf_crtc_is_wb - check if writeback is primary output of this crtc
+ * sde_crtc_get_client_type - check the crtc type- rt, nrt, rsc, etc.
  * @crtc: Pointer to crtc
  */
-static inline bool sde_crtc_is_wb(struct drm_crtc *crtc)
+static inline enum sde_crtc_client_type sde_crtc_get_client_type(
+						struct drm_crtc *crtc)
 {
 	struct sde_crtc_state *cstate =
 			crtc ? to_sde_crtc_state(crtc->state) : NULL;
 
-	return cstate ? (cstate->intf_mode == INTF_MODE_WB_LINE) : false;
-}
+	if (!cstate)
+		return NRT_CLIENT;
 
-/**
- * sde_crtc_is_nrt - check if primary output of this crtc is non-realtime client
- * @crtc: Pointer to crtc
- */
-static inline bool sde_crtc_is_nrt(struct drm_crtc *crtc)
-{
-	return sde_crtc_is_wb(crtc);
+	return cstate->rsc_client ? RT_RSC_CLIENT :
+	    (cstate->intf_mode == INTF_MODE_WB_LINE ? NRT_CLIENT : RT_CLIENT);
 }
 
 /**
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.c b/drivers/gpu/drm/msm/sde/sde_encoder.c
index 282fd88..059471d 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder.c
@@ -32,6 +32,9 @@
 #include "sde_formats.h"
 #include "sde_encoder_phys.h"
 #include "sde_color_processing.h"
+#include "sde_rsc.h"
+
+#include "sde_power_handle.h"
 
 #define SDE_DEBUG_ENC(e, fmt, ...) SDE_DEBUG("enc%d " fmt,\
 		(e) ? (e)->base.base.id : -1, ##__VA_ARGS__)
@@ -111,6 +114,10 @@
 
 	atomic_t frame_done_timeout;
 	struct timer_list frame_done_timer;
+
+	struct sde_rsc_client *rsc_client;
+	struct msm_display_info disp_info;
+	bool rsc_state_update;
 };
 
 #define to_sde_encoder_virt(x) container_of(x, struct sde_encoder_virt, base)
@@ -157,6 +164,8 @@
 	SDE_DEBUG_ENC(sde_enc, "\n");
 
 	mutex_lock(&sde_enc->enc_lock);
+	sde_rsc_client_destroy(sde_enc->rsc_client);
+
 	for (i = 0; i < sde_enc->num_phys_encs; i++) {
 		struct sde_encoder_phys *phys = sde_enc->phys_encs[i];
 
@@ -390,6 +399,7 @@
 	sde_power_resource_enable(&priv->phandle, sde_kms->core_client, true);
 
 	sde_enc->cur_master = NULL;
+
 	for (i = 0; i < sde_enc->num_phys_encs; i++) {
 		struct sde_encoder_phys *phys = sde_enc->phys_encs[i];
 
@@ -559,6 +569,49 @@
 	}
 }
 
+struct sde_rsc_client *sde_encoder_update_rsc_client(
+		struct drm_encoder *drm_enc, bool enable)
+{
+	struct sde_encoder_virt *sde_enc;
+	enum sde_rsc_state rsc_state;
+	struct sde_rsc_cmd_config rsc_config;
+	int ret;
+
+	if (!drm_enc) {
+		SDE_ERROR("invalid encoder\n");
+		return NULL;
+	}
+
+	sde_enc = to_sde_encoder_virt(drm_enc);
+	if (!sde_enc->disp_info.is_primary)
+		return NULL;
+
+	rsc_state = enable ?
+		(sde_enc->disp_info.capabilities & MSM_DISPLAY_CAP_CMD_MODE ?
+		SDE_RSC_CMD_STATE : SDE_RSC_VID_STATE) : SDE_RSC_IDLE_STATE;
+
+	if (rsc_state != SDE_RSC_IDLE_STATE && !sde_enc->rsc_state_update) {
+		rsc_config.fps = sde_enc->disp_info.frame_rate;
+		rsc_config.vtotal = sde_enc->disp_info.vtotal;
+		rsc_config.prefill_lines = sde_enc->disp_info.prefill_lines;
+		rsc_config.jitter = sde_enc->disp_info.jitter;
+		sde_enc->rsc_state_update = true;
+
+		ret = sde_rsc_client_state_update(sde_enc->rsc_client,
+			rsc_state, &rsc_config,
+			drm_enc->crtc ? drm_enc->crtc->index : -1);
+	} else {
+		ret = sde_rsc_client_state_update(sde_enc->rsc_client,
+			rsc_state, NULL,
+			drm_enc->crtc ? drm_enc->crtc->index : -1);
+	}
+
+	if (ret)
+		SDE_ERROR("sde rsc client update failed ret:%d\n", ret);
+
+	return sde_enc->rsc_client;
+}
+
 void sde_encoder_register_frame_event_callback(struct drm_encoder *drm_enc,
 		void (*frame_event_cb)(void *, u32 event),
 		void *frame_event_cb_data)
@@ -1266,7 +1319,6 @@
 	}
 	mutex_unlock(&sde_enc->enc_lock);
 
-
 	return ret;
 }
 
@@ -1310,6 +1362,7 @@
 	struct drm_encoder *drm_enc = NULL;
 	struct sde_encoder_virt *sde_enc = NULL;
 	int drm_enc_mode = DRM_MODE_ENCODER_NONE;
+	char name[SDE_NAME_SIZE];
 	int ret = 0;
 
 	sde_enc = kzalloc(sizeof(*sde_enc), GFP_KERNEL);
@@ -1336,6 +1389,17 @@
 
 	_sde_encoder_init_debugfs(drm_enc, sde_enc, sde_kms);
 
+	snprintf(name, SDE_NAME_SIZE, "rsc_enc%u", drm_enc->base.id);
+	sde_enc->rsc_client = sde_rsc_client_create(SDE_RSC_INDEX, name,
+					disp_info->is_primary);
+	if (IS_ERR_OR_NULL(sde_enc->rsc_client)) {
+		SDE_ERROR("sde rsc client create failed :%ld\n",
+						PTR_ERR(sde_enc->rsc_client));
+		sde_enc->rsc_client = NULL;
+	}
+
+	memcpy(&sde_enc->disp_info, disp_info, sizeof(*disp_info));
+
 	SDE_DEBUG_ENC(sde_enc, "created\n");
 
 	return drm_enc;
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.h b/drivers/gpu/drm/msm/sde/sde_encoder.h
index 61435c9..e0c28b5 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder.h
+++ b/drivers/gpu/drm/msm/sde/sde_encoder.h
@@ -73,6 +73,15 @@
 		void (*cb)(void *, u32), void *data);
 
 /**
+ * sde_encoder_update_rsc_client - updates the rsc client state for primary
+ *      for primary display.
+ * @encoder:	encoder pointer
+ * @enable:	enable/disable the client
+ */
+struct sde_rsc_client *sde_encoder_update_rsc_client(
+		struct drm_encoder *encoder, bool enable);
+
+/**
  * sde_encoder_prepare_for_kickoff - schedule double buffer flip of the ctl
  *	path (i.e. ctl flush and start) at next appropriate time.
  *	Immediately: if no previous commit is outstanding.
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys.h b/drivers/gpu/drm/msm/sde/sde_encoder_phys.h
index 0ee0f13..d8f096c 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder_phys.h
+++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys.h
@@ -27,6 +27,8 @@
 #include "sde_encoder.h"
 #include "sde_connector.h"
 
+#include "sde_rsc.h"
+
 #define SDE_ENCODER_NAME_MAX	16
 
 /* wait for at most 2 vsync for lowest refresh rate (24hz) */
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c b/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c
index e00b4d2..f61077a 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c
@@ -506,9 +506,6 @@
 	if (WARN_ON(!vid_enc->hw_intf->ops.enable_timing))
 		return;
 
-	sde_power_data_bus_bandwidth_ctrl(&priv->phandle,
-			phys_enc->sde_kms->core_client, true);
-
 	sde_encoder_helper_split_config(phys_enc, vid_enc->hw_intf->idx);
 
 	sde_encoder_phys_vid_setup_timing_engine(phys_enc);
@@ -740,9 +737,6 @@
 		sde_encoder_phys_vid_control_vblank_irq(phys_enc, false);
 	}
 
-	sde_power_data_bus_bandwidth_ctrl(&priv->phandle,
-			phys_enc->sde_kms->core_client, false);
-
 	if (atomic_read(&phys_enc->vblank_refcount))
 		SDE_ERROR_VIDENC(vid_enc, "invalid vblank refcount %d\n",
 				atomic_read(&phys_enc->vblank_refcount));
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_catalog_8996.c b/drivers/gpu/drm/msm/sde/sde_hw_catalog_8996.c
deleted file mode 100644
index 652331f..0000000
--- a/drivers/gpu/drm/msm/sde/sde_hw_catalog_8996.c
+++ /dev/null
@@ -1,671 +0,0 @@
-/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-#include "sde_hw_catalog.h"
-#include "sde_hw_mdss.h"
-#include "sde_hwio.h"
-
-/* VIG layer capability */
-#define VIG_17X_MASK \
-	(BIT(SDE_SSPP_SRC) | BIT(SDE_SSPP_SCALER_QSEED2) |\
-	BIT(SDE_SSPP_CSC) | BIT(SDE_SSPP_HSIC) |\
-	BIT(SDE_SSPP_PCC) | BIT(SDE_SSPP_IGC) |\
-	BIT(SDE_SSPP_MEMCOLOR) | BIT(SDE_SSPP_QOS))
-
-/* RGB layer capability */
-#define RGB_17X_MASK \
-	(BIT(SDE_SSPP_SRC) | BIT(SDE_SSPP_SCALER_RGB) |\
-	BIT(SDE_SSPP_PCC) | BIT(SDE_SSPP_IGC) | BIT(SDE_SSPP_QOS))
-
-/* DMA layer capability */
-#define DMA_17X_MASK \
-	(BIT(SDE_SSPP_SRC) | BIT(SDE_SSPP_PCC) | BIT(SDE_SSPP_IGC) |\
-	BIT(SDE_SSPP_QOS))
-
-/* Cursor layer capability */
-#define CURSOR_17X_MASK  (BIT(SDE_SSPP_SRC) | BIT(SDE_SSPP_CURSOR))
-
-#define MIXER_17X_MASK (BIT(SDE_MIXER_SOURCESPLIT) |\
-	BIT(SDE_MIXER_GC))
-
-#define DSPP_17X_MASK \
-	(BIT(SDE_DSPP_IGC) | BIT(SDE_DSPP_PCC) |\
-	BIT(SDE_DSPP_GC) | BIT(SDE_DSPP_HSIC) | BIT(SDE_DSPP_GAMUT) |\
-	BIT(SDE_DSPP_DITHER) | BIT(SDE_DSPP_HIST) | BIT(SDE_DSPP_MEMCOLOR) |\
-	BIT(SDE_DSPP_SIXZONE) | BIT(SDE_DSPP_AD) | BIT(SDE_DSPP_VLUT))
-
-#define PINGPONG_17X_MASK \
-	(BIT(SDE_PINGPONG_TE) | BIT(SDE_PINGPONG_DSC))
-
-#define PINGPONG_17X_SPLIT_MASK \
-	(PINGPONG_17X_MASK | BIT(SDE_PINGPONG_SPLIT) |\
-	BIT(SDE_PINGPONG_TE2))
-
-#define WB01_17X_MASK \
-	(BIT(SDE_WB_LINE_MODE) | BIT(SDE_WB_BLOCK_MODE) |\
-	BIT(SDE_WB_CSC) | BIT(SDE_WB_CHROMA_DOWN) | BIT(SDE_WB_DOWNSCALE) |\
-	BIT(SDE_WB_DITHER) | BIT(SDE_WB_TRAFFIC_SHAPER) |\
-	BIT(SDE_WB_UBWC_1_0) | BIT(SDE_WB_YUV_CONFIG))
-
-#define WB2_17X_MASK \
-	(BIT(SDE_WB_LINE_MODE) | BIT(SDE_WB_TRAFFIC_SHAPER) |\
-	BIT(SDE_WB_YUV_CONFIG))
-
-#define DECIMATION_17X_MAX_H	4
-#define DECIMATION_17X_MAX_V	4
-
-#define RES_1080p		((u64)(1088*1920))
-#define RES_UHD			((u64)(3840*2160))
-
-static const struct sde_format_extended plane_formats[] = {
-	{DRM_FORMAT_ARGB8888, 0},
-	{DRM_FORMAT_ABGR8888, 0},
-	{DRM_FORMAT_RGBA8888, 0},
-	{DRM_FORMAT_RGBA8888, DRM_FORMAT_MOD_QCOM_COMPRESSED},
-	{DRM_FORMAT_BGRA8888, 0},
-	{DRM_FORMAT_XRGB8888, 0},
-	{DRM_FORMAT_RGBX8888, 0},
-	{DRM_FORMAT_RGBX8888, DRM_FORMAT_MOD_QCOM_COMPRESSED},
-	{DRM_FORMAT_RGB888, 0},
-	{DRM_FORMAT_BGR888, 0},
-	{DRM_FORMAT_RGB565, 0},
-	{DRM_FORMAT_RGB565, DRM_FORMAT_MOD_QCOM_COMPRESSED},
-	{DRM_FORMAT_BGR565, 0},
-	{DRM_FORMAT_ARGB1555, 0},
-	{DRM_FORMAT_ABGR1555, 0},
-	{DRM_FORMAT_RGBA5551, 0},
-	{DRM_FORMAT_BGRA5551, 0},
-	{DRM_FORMAT_XRGB1555, 0},
-	{DRM_FORMAT_XBGR1555, 0},
-	{DRM_FORMAT_RGBX5551, 0},
-	{DRM_FORMAT_BGRX5551, 0},
-	{DRM_FORMAT_ARGB4444, 0},
-	{DRM_FORMAT_ABGR4444, 0},
-	{DRM_FORMAT_RGBA4444, 0},
-	{DRM_FORMAT_BGRA4444, 0},
-	{DRM_FORMAT_XRGB4444, 0},
-	{DRM_FORMAT_XBGR4444, 0},
-	{DRM_FORMAT_RGBX4444, 0},
-	{DRM_FORMAT_BGRX4444, 0},
-	{0, 0},
-};
-
-static const struct sde_format_extended plane_formats_yuv[] = {
-	{DRM_FORMAT_ARGB8888, 0},
-	{DRM_FORMAT_ABGR8888, 0},
-	{DRM_FORMAT_RGBA8888, 0},
-	{DRM_FORMAT_RGBA8888, DRM_FORMAT_MOD_QCOM_COMPRESSED},
-	{DRM_FORMAT_BGRA8888, 0},
-	{DRM_FORMAT_XRGB8888, 0},
-	{DRM_FORMAT_RGBX8888, 0},
-	{DRM_FORMAT_RGBX8888, DRM_FORMAT_MOD_QCOM_COMPRESSED},
-	{DRM_FORMAT_RGB888, 0},
-	{DRM_FORMAT_BGR888, 0},
-	{DRM_FORMAT_RGB565, 0},
-	{DRM_FORMAT_RGB565, DRM_FORMAT_MOD_QCOM_COMPRESSED},
-	{DRM_FORMAT_BGR565, 0},
-	{DRM_FORMAT_ARGB1555, 0},
-	{DRM_FORMAT_ABGR1555, 0},
-	{DRM_FORMAT_RGBA5551, 0},
-	{DRM_FORMAT_BGRA5551, 0},
-	{DRM_FORMAT_XRGB1555, 0},
-	{DRM_FORMAT_XBGR1555, 0},
-	{DRM_FORMAT_RGBX5551, 0},
-	{DRM_FORMAT_BGRX5551, 0},
-	{DRM_FORMAT_ARGB4444, 0},
-	{DRM_FORMAT_ABGR4444, 0},
-	{DRM_FORMAT_RGBA4444, 0},
-	{DRM_FORMAT_BGRA4444, 0},
-	{DRM_FORMAT_XRGB4444, 0},
-	{DRM_FORMAT_XBGR4444, 0},
-	{DRM_FORMAT_RGBX4444, 0},
-	{DRM_FORMAT_BGRX4444, 0},
-	{DRM_FORMAT_NV12, 0},
-	{DRM_FORMAT_NV12, DRM_FORMAT_MOD_QCOM_COMPRESSED},
-	{DRM_FORMAT_NV21, 0},
-	{DRM_FORMAT_NV16, 0},
-	{DRM_FORMAT_NV61, 0},
-	{DRM_FORMAT_VYUY, 0},
-	{DRM_FORMAT_UYVY, 0},
-	{DRM_FORMAT_YUYV, 0},
-	{DRM_FORMAT_YVYU, 0},
-	{DRM_FORMAT_YUV420, 0},
-	{DRM_FORMAT_YVU420, 0},
-	{0, 0},
-};
-
-static const struct sde_format_extended wb0_formats[] = {
-	{DRM_FORMAT_RGB565, 0},
-	{DRM_FORMAT_RGB888, 0},
-	{DRM_FORMAT_ARGB8888, 0},
-	{DRM_FORMAT_RGBA8888, 0},
-	{DRM_FORMAT_XRGB8888, 0},
-	{DRM_FORMAT_RGBX8888, 0},
-	{DRM_FORMAT_ARGB1555, 0},
-	{DRM_FORMAT_RGBA5551, 0},
-	{DRM_FORMAT_XRGB1555, 0},
-	{DRM_FORMAT_RGBX5551, 0},
-	{DRM_FORMAT_ARGB4444, 0},
-	{DRM_FORMAT_RGBA4444, 0},
-	{DRM_FORMAT_RGBX4444, 0},
-	{DRM_FORMAT_XRGB4444, 0},
-
-	{DRM_FORMAT_BGR565, 0},
-	{DRM_FORMAT_BGR888, 0},
-	{DRM_FORMAT_ABGR8888, 0},
-	{DRM_FORMAT_BGRA8888, 0},
-	{DRM_FORMAT_BGRX8888, 0},
-	{DRM_FORMAT_ABGR1555, 0},
-	{DRM_FORMAT_BGRA5551, 0},
-	{DRM_FORMAT_XBGR1555, 0},
-	{DRM_FORMAT_BGRX5551, 0},
-	{DRM_FORMAT_ABGR4444, 0},
-	{DRM_FORMAT_BGRA4444, 0},
-	{DRM_FORMAT_BGRX4444, 0},
-	{DRM_FORMAT_XBGR4444, 0},
-
-	{DRM_FORMAT_RGBX8888, DRM_FORMAT_MOD_QCOM_COMPRESSED},
-	{DRM_FORMAT_RGBA8888, DRM_FORMAT_MOD_QCOM_COMPRESSED},
-	{DRM_FORMAT_RGB565, DRM_FORMAT_MOD_QCOM_COMPRESSED},
-
-	{DRM_FORMAT_YUV420, 0},
-	{DRM_FORMAT_NV12, 0},
-	{DRM_FORMAT_NV16, 0},
-	{DRM_FORMAT_NV21, 0},
-	{DRM_FORMAT_NV61, 0},
-	{DRM_FORMAT_UYVY, 0},
-	{DRM_FORMAT_YUYV, 0},
-
-	{DRM_FORMAT_NV12, DRM_FORMAT_MOD_QCOM_COMPRESSED},
-	{DRM_FORMAT_AYUV, DRM_FORMAT_MOD_QCOM_COMPRESSED},
-
-	{0, 0},
-};
-
-static const struct sde_format_extended wb2_formats[] = {
-	{DRM_FORMAT_RGB565, 0},
-	{DRM_FORMAT_RGB888, 0},
-	{DRM_FORMAT_ARGB8888, 0},
-	{DRM_FORMAT_RGBA8888, 0},
-	{DRM_FORMAT_XRGB8888, 0},
-	{DRM_FORMAT_RGBX8888, 0},
-	{DRM_FORMAT_ARGB1555, 0},
-	{DRM_FORMAT_RGBA5551, 0},
-	{DRM_FORMAT_XRGB1555, 0},
-	{DRM_FORMAT_RGBX5551, 0},
-	{DRM_FORMAT_ARGB4444, 0},
-	{DRM_FORMAT_RGBA4444, 0},
-	{DRM_FORMAT_RGBX4444, 0},
-	{DRM_FORMAT_XRGB4444, 0},
-
-	{DRM_FORMAT_BGR565, 0},
-	{DRM_FORMAT_BGR888, 0},
-	{DRM_FORMAT_ABGR8888, 0},
-	{DRM_FORMAT_BGRA8888, 0},
-	{DRM_FORMAT_BGRX8888, 0},
-	{DRM_FORMAT_ABGR1555, 0},
-	{DRM_FORMAT_BGRA5551, 0},
-	{DRM_FORMAT_XBGR1555, 0},
-	{DRM_FORMAT_BGRX5551, 0},
-	{DRM_FORMAT_ABGR4444, 0},
-	{DRM_FORMAT_BGRA4444, 0},
-	{DRM_FORMAT_BGRX4444, 0},
-	{DRM_FORMAT_XBGR4444, 0},
-
-	{DRM_FORMAT_YUV420, 0},
-	{DRM_FORMAT_NV12, 0},
-	{DRM_FORMAT_NV16, 0},
-	{DRM_FORMAT_YUYV, 0},
-
-	{0, 0},
-};
-
-/**
- * set_cfg_1xx_init(): populate sde sub-blocks reg offsets and instance counts
- */
-static inline int set_cfg_1xx_init(struct sde_mdss_cfg *cfg)
-{
-
-	/* Layer capability */
-	static const struct sde_sspp_sub_blks vig_layer = {
-		.maxlinewidth = 2560,
-		.danger_lut_linear = 0x000f,
-		.safe_lut_linear = 0xfffc,
-		.danger_lut_tile = 0xffff,
-		.safe_lut_tile = 0xff00,
-		.danger_lut_nrt = 0x0,
-		.safe_lut_nrt = 0xffff,
-		.creq_lut_nrt = 0x0,
-		.creq_vblank = 0x2,
-		.danger_vblank = 0,
-		.pixel_ram_size = 50 * 1024,
-		.maxdwnscale = 4, .maxupscale = 20,
-		.maxhdeciexp = DECIMATION_17X_MAX_H,
-		.maxvdeciexp = DECIMATION_17X_MAX_V,
-		.src_blk = {.id = SDE_SSPP_SRC,
-			.base = 0x00, .len = 0x150,},
-		.scaler_blk = {.id = SDE_SSPP_SCALER_QSEED2,
-			.base = 0x200, .len = 0x70,},
-		.csc_blk = {.id = SDE_SSPP_CSC,
-			.base = 0x320, .len = 0x44,},
-		.format_list = plane_formats_yuv,
-		.igc_blk = {.id = SDE_SSPP_IGC, .base = 0x0, .len = 0x0,
-			.version = SDE_COLOR_PROCESS_VER(0x1, 0x0)},
-		.pcc_blk = {.id = SDE_SSPP_PCC, .base = 0x0, .len = 0x0,
-			.version = SDE_COLOR_PROCESS_VER(0x1, 0x0)},
-		.hsic = {.id = SDE_SSPP_HSIC, .base = 0x0, .len = 0x0,
-			.version = SDE_COLOR_PROCESS_VER(0x1, 0x0)},
-		.memcolor = {.id = SDE_SSPP_MEMCOLOR, .base = 0x0, .len = 0x0,
-			.version = SDE_COLOR_PROCESS_VER(0x1, 0x0)},
-	};
-
-	static const struct sde_sspp_sub_blks layer = {
-		.maxlinewidth = 2560,
-		.danger_lut_linear = 0x000f,
-		.safe_lut_linear = 0xfffc,
-		.danger_lut_tile = 0xffff,
-		.safe_lut_tile = 0xff00,
-		.danger_lut_nrt = 0x0,
-		.safe_lut_nrt = 0xffff,
-		.creq_lut_nrt = 0x0,
-		.creq_vblank = 0x2,
-		.danger_vblank = 0,
-		.pixel_ram_size = 50 * 1024,
-		.maxdwnscale = 4, .maxupscale = 20,
-		.maxhdeciexp = DECIMATION_17X_MAX_H,
-		.maxvdeciexp = DECIMATION_17X_MAX_V,
-		.src_blk = {.id = SDE_SSPP_SRC,
-			.base = 0x00, .len = 0x150,},
-		.scaler_blk = {.id = SDE_SSPP_SCALER_QSEED2,
-			.base = 0x200, .len = 0x70,},
-		.csc_blk = {.id = SDE_SSPP_CSC,
-			.base = 0x320, .len = 0x44,},
-		.format_list = plane_formats,
-		.igc_blk = {.id = SDE_SSPP_IGC, .base = 0x0, .len = 0x0,
-			.version = SDE_COLOR_PROCESS_VER(0x1, 0x0)},
-		.pcc_blk = {.id = SDE_SSPP_PCC, .base = 0x0, .len = 0x0,
-			.version = SDE_COLOR_PROCESS_VER(0x1, 0x0)},
-	};
-
-	static const struct sde_sspp_sub_blks dma = {
-		.maxlinewidth = 2560,
-		.danger_lut_linear = 0x000f,
-		.safe_lut_linear = 0xfffc,
-		.danger_lut_tile = 0xffff,
-		.safe_lut_tile = 0xff00,
-		.danger_lut_nrt = 0x0,
-		.safe_lut_nrt = 0xffff,
-		.creq_lut_nrt = 0x0,
-		.creq_vblank = 0x2,
-		.danger_vblank = 0,
-		.pixel_ram_size = 50 * 1024,
-		.maxdwnscale = 1, .maxupscale = 1,
-		.maxhdeciexp = DECIMATION_17X_MAX_H,
-		.maxvdeciexp = DECIMATION_17X_MAX_V,
-		.src_blk = {.id = SDE_SSPP_SRC, .base = 0x00, .len = 0x150,},
-		.scaler_blk = {.id = 0, .base = 0x00, .len = 0x0,},
-		.csc_blk = {.id = 0, .base = 0x00, .len = 0x0,},
-		.format_list = plane_formats,
-		.igc_blk = {.id = SDE_SSPP_IGC, .base = 0x0, .len = 0x0,
-			.version = SDE_COLOR_PROCESS_VER(0x1, 0x0)},
-		.pcc_blk = {.id = SDE_SSPP_PCC, .base = 0x0, .len = 0x0,
-			.version = SDE_COLOR_PROCESS_VER(0x1, 0x0)},
-	};
-
-	static const struct sde_sspp_sub_blks cursor = {
-		.maxlinewidth = 128,
-		.maxdwnscale = 1, .maxupscale = 1,
-		.maxhdeciexp = 0,
-		.maxvdeciexp = 0,
-		.src_blk = {.id = SDE_SSPP_SRC, .base = 0x00, .len = 0x150,},
-		.scaler_blk = {.id = 0, .base = 0x00, .len = 0x0,},
-		.csc_blk = {.id = 0, .base = 0x00, .len = 0x0,},
-		.format_list = plane_formats,
-	};
-
-	/* MIXER capability */
-	static const struct sde_lm_sub_blks lm = {
-		.maxwidth = 2560,
-		.maxblendstages = 7, /* excluding base layer */
-		.blendstage_base = { /* offsets relative to mixer base */
-			0x20, 0x50, 0x80, 0xB0, 0x230, 0x260, 0x290 },
-		.gc = {.id = SDE_DSPP_GC, .base = 0x0, .len = 0x0,
-			.version = SDE_COLOR_PROCESS_VER(0x1, 0x0)},
-	};
-
-	/* DSPP capability */
-	static const struct sde_dspp_sub_blks dspp = {
-		.igc = {.id = SDE_DSPP_IGC, .base = 0x0, .len = 0x0,
-			.version = SDE_COLOR_PROCESS_VER(0x1, 0x0)},
-		.pcc = {.id = SDE_DSPP_PCC, .base = 0x0, .len = 0x0,
-			.version = SDE_COLOR_PROCESS_VER(0x1, 0x0)},
-		.gamut = {.id = SDE_DSPP_GAMUT, .base = 0x0, .len = 0x0,
-			.version = SDE_COLOR_PROCESS_VER(0x1, 0x0)},
-		.dither = {.id = SDE_DSPP_DITHER, .base = 0x0, .len = 0x0,
-			.version = SDE_COLOR_PROCESS_VER(0x1, 0x0)},
-		.hsic = {.id = SDE_DSPP_HSIC, .base = 0x00, .len = 0x0,
-			.version = SDE_COLOR_PROCESS_VER(0x1, 0x0)},
-		.memcolor = {.id = SDE_DSPP_MEMCOLOR, .base = 0x00, .len = 0x0,
-			.version = SDE_COLOR_PROCESS_VER(0x1, 0x0)},
-		.sixzone = {.id = SDE_DSPP_SIXZONE, .base = 0x00, .len = 0x0,
-			.version = SDE_COLOR_PROCESS_VER(0x1, 0x0)},
-		.hist = {.id = SDE_DSPP_HIST, .base = 0x00, .len = 0x0,
-			.version = SDE_COLOR_PROCESS_VER(0x1, 0x0)},
-		.gc = {.id = SDE_DSPP_GC, .base = 0x0, .len = 0x0,
-			.version = SDE_COLOR_PROCESS_VER(0x1, 0x0)},
-		.ad = {.id = SDE_DSPP_AD, .base = 0x00, .len = 0x0,
-			.version = SDE_COLOR_PROCESS_VER(0x3, 0x0)},
-		.vlut = {.id = SDE_DSPP_VLUT, .base = 0x1400, .len = 0x0,
-			.version = SDE_COLOR_PROCESS_VER(0x1, 0x0)},
-	};
-
-	/* PINGPONG capability */
-	static const struct sde_pingpong_sub_blks pingpong = {
-		.te = {.id = SDE_PINGPONG_TE, .base = 0x0000, .len = 0x0,
-			.version = 0x1},
-		.te2 = {.id = SDE_PINGPONG_TE2, .base = 0x2000, .len = 0x0,
-			.version = 0x1},
-		.dsc = {.id = SDE_PINGPONG_DSC, .base = 0x10000, .len = 0x0,
-			.version = 0x1},
-	};
-
-	/* Writeback 0/1 capability */
-	static const struct sde_wb_sub_blocks wb0 = {
-		.maxlinewidth = 2048,
-	};
-
-	/* Writeback 2 capability */
-	static const struct sde_wb_sub_blocks wb2 = {
-		.maxlinewidth = 4096,
-	};
-
-	static const struct sde_vbif_dynamic_ot_cfg dynamic_ot_cfg[] = {
-		{RES_1080p * 30, 2},
-		{RES_1080p * 60, 4},
-		{RES_UHD * 30, 16},
-	};
-
-	/* Setup Register maps and defaults */
-	*cfg = (struct sde_mdss_cfg){
-		.mdss_count = 1,
-		.mdss = {
-			{.id = MDP_TOP, .base = 0x00000000, .features = 0}
-		},
-		.mdp_count = 1,
-		.mdp = {
-			{.id = MDP_TOP, .base = 0x00001000, .features = 0,
-				.highest_bank_bit = 0x2,
-				.clk_ctrls[SDE_CLK_CTRL_VIG0] = {
-					.reg_off = 0x2AC, .bit_off = 0},
-				.clk_ctrls[SDE_CLK_CTRL_VIG1] = {
-					.reg_off = 0x2B4, .bit_off = 0},
-				.clk_ctrls[SDE_CLK_CTRL_VIG2] = {
-					.reg_off = 0x2BC, .bit_off = 0},
-				.clk_ctrls[SDE_CLK_CTRL_VIG3] = {
-					.reg_off = 0x2C4, .bit_off = 0},
-				.clk_ctrls[SDE_CLK_CTRL_RGB0] = {
-					.reg_off = 0x2AC, .bit_off = 4},
-				.clk_ctrls[SDE_CLK_CTRL_RGB1] = {
-					.reg_off = 0x2B4, .bit_off = 4},
-				.clk_ctrls[SDE_CLK_CTRL_RGB2] = {
-					.reg_off = 0x2BC, .bit_off = 4},
-				.clk_ctrls[SDE_CLK_CTRL_RGB3] = {
-					.reg_off = 0x2C4, .bit_off = 4},
-				.clk_ctrls[SDE_CLK_CTRL_DMA0] = {
-					.reg_off = 0x2AC, .bit_off = 8},
-				.clk_ctrls[SDE_CLK_CTRL_DMA1] = {
-					.reg_off = 0x2B4, .bit_off = 8},
-				.clk_ctrls[SDE_CLK_CTRL_CURSOR0] = {
-					.reg_off = 0x3A8, .bit_off = 16},
-				.clk_ctrls[SDE_CLK_CTRL_CURSOR1] = {
-					.reg_off = 0x3B0, .bit_off = 16},
-				.clk_ctrls[SDE_CLK_CTRL_WB0] = {
-					.reg_off = 0x2BC, .bit_off = 8},
-				.clk_ctrls[SDE_CLK_CTRL_WB1] = {
-					.reg_off = 0x2BC, .bit_off = 12},
-				.clk_ctrls[SDE_CLK_CTRL_WB2] = {
-					.reg_off = 0x2BC, .bit_off = 16},
-			},
-		},
-		.ctl_count = 5,
-		.ctl = {
-			{.id = CTL_0,
-				.base = 0x00002000,
-				.features = BIT(SDE_CTL_SPLIT_DISPLAY) |
-					BIT(SDE_CTL_PINGPONG_SPLIT) },
-			{.id = CTL_1,
-				.base = 0x00002200,
-				.features = BIT(SDE_CTL_SPLIT_DISPLAY) },
-			{.id = CTL_2,
-				.base = 0x00002400},
-			{.id = CTL_3,
-				.base = 0x00002600},
-			{.id = CTL_4,
-				.base = 0x00002800},
-		},
-			/* 4 VIG, + 4 RGB + 2 DMA + 2 CURSOR */
-		.sspp_count = 12,
-		.sspp = {
-			{.id = SSPP_VIG0, .base = 0x00005000,
-			.features = VIG_17X_MASK, .sblk = &vig_layer,
-			.xin_id = 0,
-			.clk_ctrl = SDE_CLK_CTRL_VIG0},
-			{.id = SSPP_VIG1, .base = 0x00007000,
-			.features = VIG_17X_MASK, .sblk = &vig_layer,
-			.xin_id = 4,
-			.clk_ctrl = SDE_CLK_CTRL_VIG1},
-			{.id = SSPP_VIG2, .base = 0x00009000,
-			.features = VIG_17X_MASK, .sblk = &vig_layer,
-			.xin_id = 8,
-			.clk_ctrl = SDE_CLK_CTRL_VIG2},
-			{.id = SSPP_VIG3, .base = 0x0000b000,
-			.features = VIG_17X_MASK, .sblk = &vig_layer,
-			.xin_id = 12,
-			.clk_ctrl = SDE_CLK_CTRL_VIG3},
-
-			{.id = SSPP_RGB0, .base = 0x00015000,
-			.features = RGB_17X_MASK, .sblk = &layer,
-			.xin_id = 1,
-			.clk_ctrl = SDE_CLK_CTRL_RGB0},
-			{.id = SSPP_RGB1, .base = 0x00017000,
-			.features = RGB_17X_MASK, .sblk = &layer,
-			.xin_id = 5,
-			.clk_ctrl = SDE_CLK_CTRL_RGB1},
-			{.id = SSPP_RGB2, .base = 0x00019000,
-			.features = RGB_17X_MASK, .sblk = &layer,
-			.xin_id = 9,
-			.clk_ctrl = SDE_CLK_CTRL_RGB2},
-			{.id = SSPP_RGB3, .base = 0x0001B000,
-			.features = RGB_17X_MASK, .sblk = &layer,
-			.xin_id = 13,
-			.clk_ctrl = SDE_CLK_CTRL_RGB3},
-
-			{.id = SSPP_DMA0, .base = 0x00025000,
-			.features = DMA_17X_MASK, .sblk = &dma,
-			.xin_id = 2,
-			.clk_ctrl = SDE_CLK_CTRL_DMA0},
-			{.id = SSPP_DMA1, .base = 0x00027000,
-			.features = DMA_17X_MASK, .sblk = &dma,
-			.xin_id = 10,
-			.clk_ctrl = SDE_CLK_CTRL_DMA1},
-
-			{.id = SSPP_CURSOR0, .base = 0x00035000,
-			.features = CURSOR_17X_MASK, .sblk = &cursor,
-			.xin_id = 7,
-			.clk_ctrl = SDE_CLK_CTRL_CURSOR0},
-			{.id = SSPP_CURSOR1, .base = 0x00037000,
-			.features = CURSOR_17X_MASK, .sblk = &cursor,
-			.xin_id = 7,
-			.clk_ctrl = SDE_CLK_CTRL_CURSOR1},
-		},
-		.mixer_count = 6,
-		.mixer = {
-			{.id = LM_0, .base = 0x00045000,
-				.features = MIXER_17X_MASK,
-				.sblk = &lm,
-				.dspp = DSPP_0,
-				.pingpong = PINGPONG_0,
-				.lm_pair_mask = (1 << LM_1) },
-			{.id = LM_1, .base = 0x00046000,
-				.features = MIXER_17X_MASK,
-				.sblk = &lm,
-				.dspp = DSPP_1,
-				.pingpong = PINGPONG_1,
-				.lm_pair_mask = (1 << LM_0) },
-			{.id = LM_2, .base = 0x00047000,
-				.features = MIXER_17X_MASK,
-				.sblk = &lm,
-				.dspp = DSPP_MAX,
-				.pingpong = PINGPONG_2,
-				.lm_pair_mask = (1 << LM_5) },
-			{.id = LM_3, .base = 0x00048000,
-				.features = MIXER_17X_MASK,
-				.sblk = &lm,
-				.dspp = DSPP_MAX,
-				.pingpong = PINGPONG_MAX},
-			{.id = LM_4, .base = 0x00049000,
-				.features = MIXER_17X_MASK,
-				.sblk = &lm,
-				.dspp = DSPP_MAX,
-				.pingpong = PINGPONG_MAX},
-			{.id = LM_5, .base = 0x0004a000,
-				.features = MIXER_17X_MASK,
-				.sblk = &lm,
-				.dspp = DSPP_MAX,
-				.pingpong = PINGPONG_3,
-				.lm_pair_mask = (1 << LM_2) },
-		},
-		.dspp_count = 2,
-		.dspp = {
-			{.id = DSPP_0, .base = 0x00055000,
-			.features = DSPP_17X_MASK,
-				.sblk = &dspp},
-			{.id = DSPP_1, .base = 0x00057000,
-			.features = DSPP_17X_MASK,
-				.sblk = &dspp},
-		},
-		.pingpong_count = 4,
-		.pingpong = {
-			{.id = PINGPONG_0, .base = 0x00071000,
-				.features = PINGPONG_17X_SPLIT_MASK,
-				.sblk = &pingpong},
-			{.id = PINGPONG_1, .base = 0x00071800,
-				.features = PINGPONG_17X_SPLIT_MASK,
-				.sblk = &pingpong},
-			{.id = PINGPONG_2, .base = 0x00072000,
-				.features = PINGPONG_17X_MASK,
-				.sblk = &pingpong},
-			{.id = PINGPONG_3, .base = 0x00072800,
-				.features = PINGPONG_17X_MASK,
-				.sblk = &pingpong},
-		},
-		.cdm_count = 1,
-		.cdm = {
-			{.id = CDM_0, .base = 0x0007A200, .features = 0,
-				.intf_connect = BIT(INTF_3),
-				.wb_connect = BIT(WB_2),}
-		},
-		.intf_count = 4,
-		.intf = {
-			{.id = INTF_0, .base = 0x0006B000,
-				.type = INTF_NONE, .controller_id = 0,
-				.prog_fetch_lines_worst_case = 21},
-			{.id = INTF_1, .base = 0x0006B800,
-				.type = INTF_DSI, .controller_id = 0,
-				.prog_fetch_lines_worst_case = 21},
-			{.id = INTF_2, .base = 0x0006C000,
-				.type = INTF_DSI, .controller_id = 1,
-				.prog_fetch_lines_worst_case = 21},
-			{.id = INTF_3, .base = 0x0006C800,
-				.type = INTF_HDMI, .controller_id = 0,
-				.prog_fetch_lines_worst_case = 21},
-		},
-		.wb_count = 3,
-		.wb = {
-			{.id = WB_0, .base = 0x00065000,
-				.features = WB01_17X_MASK,
-				.sblk = &wb0,
-				.format_list = wb0_formats,
-				.vbif_idx = VBIF_NRT,
-				.xin_id = 3,
-				.clk_ctrl = SDE_CLK_CTRL_WB0},
-			{.id = WB_1, .base = 0x00065800,
-				.features = WB01_17X_MASK,
-				.sblk = &wb0,
-				.format_list = wb0_formats,
-				.vbif_idx = VBIF_NRT,
-				.xin_id = 11,
-				.clk_ctrl = SDE_CLK_CTRL_WB1},
-			{.id = WB_2, .base = 0x00066000,
-				.features = WB2_17X_MASK,
-				.sblk = &wb2,
-				.format_list = wb2_formats,
-				.vbif_idx = VBIF_NRT,
-				.xin_id = 6,
-				.clk_ctrl = SDE_CLK_CTRL_WB2},
-		},
-		.vbif_count = 2,
-		.vbif = {
-			{.id = VBIF_0,
-				.base = 0, /* 0x000B0000 */
-				.features = BIT(SDE_VBIF_QOS_OTLIM),
-				.default_ot_rd_limit = 32,
-				.default_ot_wr_limit = 16,
-				.xin_halt_timeout = 0x4000,
-				.dynamic_ot_rd_tbl = {
-					.count = ARRAY_SIZE(dynamic_ot_cfg),
-					.cfg = dynamic_ot_cfg},
-				.dynamic_ot_wr_tbl = {
-					.count = ARRAY_SIZE(dynamic_ot_cfg),
-					.cfg = dynamic_ot_cfg},
-			},
-			{.id = VBIF_1,
-				.base = 0, /* 0x000B8000 */
-				.features = BIT(SDE_VBIF_QOS_OTLIM),
-				.default_ot_rd_limit = 32,
-				.default_ot_wr_limit = 16,
-				.xin_halt_timeout = 0x4000,
-				.dynamic_ot_rd_tbl = {
-					.count = ARRAY_SIZE(dynamic_ot_cfg),
-					.cfg = dynamic_ot_cfg},
-				.dynamic_ot_wr_tbl = {
-					.count = ARRAY_SIZE(dynamic_ot_cfg),
-					.cfg = dynamic_ot_cfg},
-			},
-		},
-	};
-	return 0;
-}
-
-/**
- * sde_mdp_cfg_170_init(): Populate the sde sub-blocks catalog information
- */
-struct sde_mdss_cfg *sde_mdss_cfg_170_init(u32 step)
-{
-	struct sde_mdss_cfg *m = NULL;
-
-	/*
-	 * This function, for each sub-block sets,
-	 * instance count, IO regions,
-	 * default capabilities and this version capabilities,
-	 * Additional catalog items
-	 */
-
-	m = kzalloc(sizeof(*m), GFP_KERNEL);
-	if (!m)
-		return NULL;
-
-	set_cfg_1xx_init(m);
-	m->hwversion = SDE_HW_VER(1, 7, step);
-
-	return m;
-}
diff --git a/drivers/gpu/drm/msm/sde/sde_plane.c b/drivers/gpu/drm/msm/sde/sde_plane.c
index e144a0d..3416396 100644
--- a/drivers/gpu/drm/msm/sde/sde_plane.c
+++ b/drivers/gpu/drm/msm/sde/sde_plane.c
@@ -1203,7 +1203,7 @@
 		return 0;
 	pstate->pending = true;
 
-	psde->is_rt_pipe = sde_crtc_is_rt(crtc);
+	psde->is_rt_pipe = (sde_crtc_get_client_type(crtc) != NRT_CLIENT);
 	_sde_plane_set_qos_ctrl(plane, false, SDE_PLANE_QOS_PANIC_CTRL);
 
 	/* update roi config */
@@ -2687,7 +2687,7 @@
 
 	_sde_plane_init_debugfs(psde, kms);
 
-	DRM_INFO("%s created for pipe %u\n", psde->pipe_name, pipe);
+	SDE_DEBUG("%s created for pipe %u\n", psde->pipe_name, pipe);
 	return plane;
 
 clean_sspp:
diff --git a/drivers/gpu/drm/msm/sde_power_handle.c b/drivers/gpu/drm/msm/sde_power_handle.c
index da56891..5157b9c 100644
--- a/drivers/gpu/drm/msm/sde_power_handle.c
+++ b/drivers/gpu/drm/msm/sde_power_handle.c
@@ -371,14 +371,11 @@
 	pdbus->curr_bw_uc_idx = new_uc_idx;
 	pdbus->ao_bw_uc_idx = new_uc_idx;
 
-	if ((pdbus->bus_ref_cnt == 0) && pdbus->curr_bw_uc_idx) {
-		rc = 0;
-	} else { /* vote BW if bus_bw_cnt > 0 or uc_idx is zero */
-		SDE_ATRACE_BEGIN("msm_bus_scale_req");
-		rc = msm_bus_scale_client_update_request(pdbus->data_bus_hdl,
+	SDE_ATRACE_BEGIN("msm_bus_scale_req");
+	rc = msm_bus_scale_client_update_request(pdbus->data_bus_hdl,
 			new_uc_idx);
-		SDE_ATRACE_END("msm_bus_scale_req");
-	}
+	SDE_ATRACE_END("msm_bus_scale_req");
+
 	return rc;
 }
 
@@ -583,57 +580,6 @@
 }
 #endif
 
-void sde_power_data_bus_bandwidth_ctrl(struct sde_power_handle *phandle,
-		struct sde_power_client *pclient, int enable)
-{
-	struct sde_power_data_bus_handle *pdbus;
-	int changed = 0;
-
-	if (!phandle || !pclient) {
-		pr_err("invalid power/client handle\n");
-		return;
-	}
-
-	pdbus = &phandle->data_bus_handle;
-
-	mutex_lock(&phandle->phandle_lock);
-	if (enable) {
-		if (pdbus->bus_ref_cnt == 0)
-			changed++;
-		pdbus->bus_ref_cnt++;
-	} else {
-		if (pdbus->bus_ref_cnt) {
-			pdbus->bus_ref_cnt--;
-			if (pdbus->bus_ref_cnt == 0)
-				changed++;
-		} else {
-			pr_debug("Can not be turned off\n");
-		}
-	}
-
-	pr_debug("%pS: task:%s bw_cnt=%d changed=%d enable=%d\n",
-		__builtin_return_address(0), current->group_leader->comm,
-		pdbus->bus_ref_cnt, changed, enable);
-
-	if (changed) {
-		SDE_ATRACE_INT("data_bus_ctrl", enable);
-
-		if (!enable) {
-			if (!pdbus->handoff_pending) {
-				msm_bus_scale_client_update_request(
-						pdbus->data_bus_hdl, 0);
-				pdbus->ao_bw_uc_idx = 0;
-			}
-		} else {
-			msm_bus_scale_client_update_request(
-					pdbus->data_bus_hdl,
-					pdbus->curr_bw_uc_idx);
-		}
-	}
-
-	mutex_unlock(&phandle->phandle_lock);
-}
-
 int sde_power_resource_init(struct platform_device *pdev,
 	struct sde_power_handle *phandle)
 {
diff --git a/drivers/gpu/drm/msm/sde_power_handle.h b/drivers/gpu/drm/msm/sde_power_handle.h
index b982d17..4f0348f 100644
--- a/drivers/gpu/drm/msm/sde_power_handle.h
+++ b/drivers/gpu/drm/msm/sde_power_handle.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -75,8 +75,6 @@
  * @bus_channels: number of memory bus channels
  * @curr_bw_uc_idx: current use case index of data bus
  * @ao_bw_uc_idx: active only use case index of data bus
- * @bus_ref_cnt: reference count of data bus enable request
- * @handoff_pending: True to indicate if bootloader hand-over is pending
  */
 struct sde_power_data_bus_handle {
 	struct msm_bus_scale_pdata *data_bus_scale_table;
@@ -86,8 +84,6 @@
 	u32 bus_channels;
 	u32 curr_bw_uc_idx;
 	u32 ao_bw_uc_idx;
-	u32 bus_ref_cnt;
-	int handoff_pending;
 };
 
 /**
diff --git a/drivers/gpu/drm/msm/sde_rsc.c b/drivers/gpu/drm/msm/sde_rsc.c
new file mode 100644
index 0000000..b36e17c
--- /dev/null
+++ b/drivers/gpu/drm/msm/sde_rsc.c
@@ -0,0 +1,961 @@
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#define pr_fmt(fmt)	"[sde_rsc:%s:%d]: " fmt, __func__, __LINE__
+
+#include <linux/kernel.h>
+#include <linux/debugfs.h>
+#include <linux/of.h>
+#include <linux/string.h>
+#include <linux/of_address.h>
+#include <linux/component.h>
+#include <linux/slab.h>
+#include <linux/mutex.h>
+#include <linux/of_platform.h>
+#include <linux/module.h>
+
+#include <soc/qcom/rpmh.h>
+#include <drm/drmP.h>
+#include <drm/drm_irq.h>
+#include "sde_rsc.h"
+
+/* this time is ~0.02ms */
+#define RSC_BACKOFF_TIME_NS		 20000
+
+/* next two values should be same based on doc */
+
+/* this time is ~0.2ms */
+#define RSC_MODE_THRESHOLD_TIME_IN_NS	200000
+/* this time is ~0.2ms */
+#define RSC_TIME_SLOT_0_NS		200000
+
+#define DEFAULT_PANEL_FPS		60
+#define DEFAULT_PANEL_JITTER		5
+#define DEFAULT_PANEL_PREFILL_LINES	16
+#define DEFAULT_PANEL_VTOTAL		(480 + DEFAULT_PANEL_PREFILL_LINES)
+#define TICKS_IN_NANO_SECOND		1000000000
+
+#define MAX_BUFFER_SIZE 256
+
+#define TRY_CMD_MODE_SWITCH		0xFFFF
+
+static struct sde_rsc_priv *rsc_prv_list[MAX_RSC_COUNT];
+
+/**
+ * sde_rsc_client_create() - create the client for sde rsc.
+ * Different displays like DSI, HDMI, DP, WB, etc should call this
+ * api to register their vote for rpmh. They still need to vote for
+ * power handle to get the clocks.
+
+ * @rsc_index:   A client will be created on this RSC. As of now only
+ *               SDE_RSC_INDEX is valid rsc index.
+ * @name:	 Caller needs to provide some valid string to identify
+ *               the client. "primary", "dp", "hdmi" are suggested name.
+ * @is_primary:	 Caller needs to provide information if client is primary
+ *               or not. Primary client votes will be redirected to
+ *               display rsc.
+ *
+ * Return: client node pointer.
+ */
+struct sde_rsc_client *sde_rsc_client_create(u32 rsc_index, char *client_name,
+	bool is_primary_client)
+{
+	struct sde_rsc_client *client;
+	struct sde_rsc_priv *rsc;
+
+	if (!client_name) {
+		pr_err("client name is null- not supported\n");
+		return ERR_PTR(-EINVAL);
+	} else if (rsc_index >= MAX_RSC_COUNT) {
+		pr_err("invalid rsc index\n");
+		return ERR_PTR(-EINVAL);
+	} else if (!rsc_prv_list[rsc_index]) {
+		pr_err("rsc not probed yet or not available\n");
+		return ERR_PTR(-EINVAL);
+	}
+
+	rsc = rsc_prv_list[rsc_index];
+	client = kzalloc(sizeof(struct sde_rsc_client), GFP_KERNEL);
+	if (!client)
+		return ERR_PTR(-ENOMEM);
+
+	mutex_lock(&rsc->client_lock);
+	strlcpy(client->name, client_name, MAX_RSC_CLIENT_NAME_LEN);
+	client->current_state = SDE_RSC_IDLE_STATE;
+	client->rsc_index = rsc_index;
+	if (is_primary_client)
+		rsc->primary_client = client;
+	pr_debug("client %s rsc index:%d primary:%d\n", client_name,
+						rsc_index, is_primary_client);
+
+	list_add(&client->list, &rsc->client_list);
+	mutex_unlock(&rsc->client_lock);
+
+	return client;
+}
+
+/**
+ * sde_rsc_client_destroy() - Destroy the sde rsc client.
+ *
+ * @client:	 Client pointer provided by sde_rsc_client_create().
+ *
+ * Return: none
+ */
+void sde_rsc_client_destroy(struct sde_rsc_client *client)
+{
+	struct sde_rsc_priv *rsc;
+
+	if (!client) {
+		pr_debug("invalid client\n");
+		goto end;
+	} else if (client->rsc_index >= MAX_RSC_COUNT) {
+		pr_err("invalid rsc index\n");
+		goto end;
+	}
+
+	pr_debug("client %s destroyed\n", client->name);
+	rsc = rsc_prv_list[client->rsc_index];
+	if (!rsc)
+		goto end;
+
+	mutex_lock(&rsc->client_lock);
+	if (client->current_state != SDE_RSC_IDLE_STATE)
+		sde_rsc_client_state_update(client, SDE_RSC_IDLE_STATE,
+								NULL, -1);
+	list_del_init(&client->list);
+	mutex_unlock(&rsc->client_lock);
+
+	kfree(client);
+end:
+	return;
+}
+
+static u32 sde_rsc_timer_calculate(struct sde_rsc_priv *rsc,
+	struct sde_rsc_cmd_config *cmd_config)
+{
+	const u32 cxo_period_ns = 52;
+	u64 rsc_backoff_time_ns = RSC_BACKOFF_TIME_NS;
+	u64 rsc_mode_threshold_time_ns = RSC_MODE_THRESHOLD_TIME_IN_NS;
+	u64 rsc_time_slot_0_ns = RSC_TIME_SLOT_0_NS;
+	u64 rsc_time_slot_1_ns;
+	const u64 pdc_jitter = 20; /* 20% more */
+
+	u64 frame_time_ns, frame_jitter;
+	u64 line_time_ns, prefill_time_ns;
+	u64 pdc_backoff_time_ns;
+	s64 total;
+	int ret = 0;
+
+	if (cmd_config)
+		memcpy(&rsc->cmd_config, cmd_config, sizeof(*cmd_config));
+
+	/* calculate for 640x480 60 fps resolution by default */
+	if (!rsc->cmd_config.fps)
+		rsc->cmd_config.fps = DEFAULT_PANEL_FPS;
+	if (!rsc->cmd_config.jitter)
+		rsc->cmd_config.jitter = DEFAULT_PANEL_JITTER;
+	if (!rsc->cmd_config.vtotal)
+		rsc->cmd_config.vtotal = DEFAULT_PANEL_VTOTAL;
+	if (!rsc->cmd_config.prefill_lines)
+		rsc->cmd_config.prefill_lines = DEFAULT_PANEL_PREFILL_LINES;
+	pr_debug("frame fps:%d jitter:%d vtotal:%d prefill lines:%d\n",
+		rsc->cmd_config.fps, rsc->cmd_config.jitter,
+		rsc->cmd_config.vtotal, rsc->cmd_config.prefill_lines);
+
+	/* 1 nano second */
+	frame_time_ns = TICKS_IN_NANO_SECOND;
+	frame_time_ns = div_u64(frame_time_ns, rsc->cmd_config.fps);
+
+	frame_jitter = frame_time_ns * rsc->cmd_config.jitter;
+	/* convert it to percentage */
+	frame_jitter = div_u64(frame_jitter, 100);
+
+	line_time_ns = frame_time_ns;
+	line_time_ns = div_u64(line_time_ns, rsc->cmd_config.vtotal);
+	prefill_time_ns = line_time_ns * rsc->cmd_config.prefill_lines;
+
+	total = frame_time_ns - frame_jitter - prefill_time_ns;
+	if (total < 0) {
+		pr_err("invalid total time period time:%llu jiter_time:%llu blanking time:%llu\n",
+			frame_time_ns, frame_jitter, prefill_time_ns);
+		total = 0;
+	}
+
+	total = div_u64(total, cxo_period_ns);
+	rsc->timer_config.static_wakeup_time_ns = total;
+
+	pr_debug("frame time:%llu frame jiter_time:%llu\n",
+			frame_time_ns, frame_jitter);
+	pr_debug("line time:%llu prefill time ps:%llu\n",
+			line_time_ns, prefill_time_ns);
+	pr_debug("static wakeup time:%lld cxo:%u\n", total, cxo_period_ns);
+
+	pdc_backoff_time_ns = rsc_backoff_time_ns;
+	rsc_backoff_time_ns = div_u64(rsc_backoff_time_ns, cxo_period_ns);
+	rsc->timer_config.rsc_backoff_time_ns = (u32) rsc_backoff_time_ns;
+
+	pdc_backoff_time_ns *= pdc_jitter;
+	pdc_backoff_time_ns = div_u64(pdc_backoff_time_ns, 100);
+	rsc->timer_config.pdc_backoff_time_ns = (u32) pdc_backoff_time_ns;
+
+	rsc_mode_threshold_time_ns =
+			div_u64(rsc_mode_threshold_time_ns, cxo_period_ns);
+	rsc->timer_config.rsc_mode_threshold_time_ns
+					= (u32) rsc_mode_threshold_time_ns;
+
+	/* time_slot_0 for mode0 latency */
+	rsc_time_slot_0_ns = div_u64(rsc_time_slot_0_ns, cxo_period_ns);
+	rsc->timer_config.rsc_time_slot_0_ns = (u32) rsc_time_slot_0_ns;
+
+	/* time_slot_1 for mode1 latency */
+	rsc_time_slot_1_ns = frame_time_ns;
+	rsc_time_slot_1_ns = div_u64(rsc_time_slot_1_ns, cxo_period_ns);
+	rsc->timer_config.rsc_time_slot_1_ns = (u32) rsc_time_slot_1_ns;
+
+	/* mode 2 is infinite */
+	rsc->timer_config.rsc_time_slot_2_ns = 0xFFFFFFFF;
+
+	if (rsc->hw_ops.init) {
+		ret = rsc->hw_ops.init(rsc);
+		if (ret)
+			pr_err("sde rsc: hw init failed ret:%d\n", ret);
+	}
+
+	return ret;
+}
+
+static int sde_rsc_switch_to_idle(struct sde_rsc_priv *rsc)
+{
+	struct sde_rsc_client *client;
+	int rc = 0;
+
+	list_for_each_entry(client, &rsc->client_list, list)
+		if (client->current_state != SDE_RSC_IDLE_STATE)
+			return TRY_CMD_MODE_SWITCH;
+
+	if (rsc->hw_ops.state_update)
+		rc = rsc->hw_ops.state_update(rsc, SDE_RSC_IDLE_STATE);
+
+	return rc;
+}
+
+static bool sde_rsc_switch_to_cmd(struct sde_rsc_priv *rsc,
+	struct sde_rsc_cmd_config *config,
+	struct sde_rsc_client *caller_client, bool wait_req)
+{
+	struct sde_rsc_client *client;
+	int rc = 0;
+
+	if (!rsc->primary_client) {
+		pr_err("primary client not available for cmd state switch\n");
+		rc = -EINVAL;
+		goto end;
+	} else if (caller_client != rsc->primary_client) {
+		pr_err("primary client state:%d not cmd state request\n",
+			rsc->primary_client->current_state);
+		rc = -EINVAL;
+		goto end;
+	}
+
+	/* update timers - might not be available at next switch */
+	if (config)
+		sde_rsc_timer_calculate(rsc, config);
+
+	/* any one client in video state blocks the cmd state switch */
+	list_for_each_entry(client, &rsc->client_list, list)
+		if (client->current_state == SDE_RSC_VID_STATE)
+			goto end;
+
+	if (rsc->hw_ops.state_update)
+		rc = rsc->hw_ops.state_update(rsc, SDE_RSC_CMD_STATE);
+
+	/* wait for vsync */
+	if (!rc && wait_req)
+		drm_wait_one_vblank(rsc->master_drm,
+						rsc->primary_client->crtc_id);
+end:
+	return rc;
+}
+
+static bool sde_rsc_switch_to_vid(struct sde_rsc_priv *rsc,
+	struct sde_rsc_cmd_config *config,
+	struct sde_rsc_client *caller_client, bool wait_req)
+{
+	int rc = 0;
+
+	/* update timers - might not be available at next switch */
+	if (config && (caller_client == rsc->primary_client))
+		sde_rsc_timer_calculate(rsc, config);
+
+	/* video state switch should be done immediately */
+	if (rsc->hw_ops.state_update)
+		rc = rsc->hw_ops.state_update(rsc, SDE_RSC_VID_STATE);
+
+	/* wait for vsync */
+	if (!rc && rsc->primary_client && wait_req)
+		drm_wait_one_vblank(rsc->master_drm,
+						rsc->primary_client->crtc_id);
+	return rc;
+}
+
+/**
+ * sde_rsc_client_state_update() - rsc client state update
+ * Video mode and command mode are supported as modes. A client need to
+ * set this property during panel config time. A switching client can set the
+ * property to change the state
+ *
+ * @client:	 Client pointer provided by sde_rsc_client_create().
+ * @state:	 Client state - video/cmd
+ * @config:	 fps, vtotal, porches, etc configuration for command mode
+ *               panel
+ * @crtc_id:	 current client's crtc id
+ *
+ * Return: error code.
+ */
+int sde_rsc_client_state_update(struct sde_rsc_client *caller_client,
+	enum sde_rsc_state state,
+	struct sde_rsc_cmd_config *config, int crtc_id)
+{
+	int rc = 0;
+	struct sde_rsc_priv *rsc;
+	bool wait_requested = false;
+
+	if (!caller_client) {
+		pr_err("invalid client for rsc state update\n");
+		return -EINVAL;
+	} else if (caller_client->rsc_index >= MAX_RSC_COUNT) {
+		pr_err("invalid rsc index\n");
+		return -EINVAL;
+	}
+
+	rsc = rsc_prv_list[caller_client->rsc_index];
+	if (!rsc)
+		return -EINVAL;
+
+	mutex_lock(&rsc->client_lock);
+	caller_client->crtc_id = crtc_id;
+	caller_client->current_state = state;
+
+	if (rsc->master_drm == NULL) {
+		pr_err("invalid master component binding\n");
+		rc = -EINVAL;
+		goto end;
+	} else if ((rsc->current_state == state) &&
+				(state != SDE_RSC_CMD_UPDATE_STATE)) {
+		pr_debug("no state change: %d\n", state);
+		goto end;
+	}
+
+	pr_debug("%pS: rsc state:%d request client:%s state:%d\n",
+		__builtin_return_address(0), rsc->current_state,
+		caller_client->name, state);
+
+	wait_requested = (rsc->current_state != SDE_RSC_IDLE_STATE);
+
+	if (rsc->power_collapse)
+		sde_power_resource_enable(&rsc->phandle, rsc->pclient, true);
+
+	switch (state) {
+	case SDE_RSC_IDLE_STATE:
+		rc = sde_rsc_switch_to_idle(rsc);
+		/* video state client might be exiting; try cmd state switch */
+		if (rc == TRY_CMD_MODE_SWITCH)
+			rc = sde_rsc_switch_to_cmd(rsc, NULL,
+					rsc->primary_client, wait_requested);
+		break;
+
+	case SDE_RSC_CMD_STATE:
+	case SDE_RSC_CMD_UPDATE_STATE:
+		rc = sde_rsc_switch_to_cmd(rsc, config, caller_client,
+								wait_requested);
+		break;
+
+	case SDE_RSC_VID_STATE:
+		rc = sde_rsc_switch_to_vid(rsc, config, caller_client,
+								wait_requested);
+		break;
+
+	default:
+		pr_err("invalid state handling %d\n", state);
+		break;
+	}
+
+	if (rc) {
+		pr_err("state update failed rc:%d\n", rc);
+		goto end;
+	}
+
+	pr_debug("state switch successfully complete: %d\n", state);
+	rsc->current_state = state;
+
+	if (rsc->power_collapse)
+		sde_power_resource_enable(&rsc->phandle, rsc->pclient, false);
+end:
+	mutex_unlock(&rsc->client_lock);
+	return rc;
+}
+
+/**
+ * sde_rsc_client_vote() - ab/ib vote from rsc client
+ *
+ * @client:	 Client pointer provided by sde_rsc_client_create().
+ * @ab:		 aggregated bandwidth vote from client.
+ * @ib:		 instant bandwidth vote from client.
+ *
+ * Return: error code.
+ */
+int sde_rsc_client_vote(struct sde_rsc_client *caller_client,
+	u64 ab_vote, u64 ib_vote)
+{
+	int rc = 0;
+	struct sde_rsc_priv *rsc;
+	bool amc_mode = false;
+	enum rpmh_state state;
+
+	if (!caller_client) {
+		pr_err("invalid client for ab/ib vote\n");
+		return -EINVAL;
+	} else if (caller_client->rsc_index >= MAX_RSC_COUNT) {
+		pr_err("invalid rsc index\n");
+		return -EINVAL;
+	}
+
+	rsc = rsc_prv_list[caller_client->rsc_index];
+	if (!rsc)
+		return -EINVAL;
+
+	if (caller_client != rsc->primary_client) {
+		pr_err("only primary client can use sde rsc:: curr client name:%s\n",
+							caller_client->name);
+		return -EINVAL;
+	}
+	pr_debug("client:%s ab:%llu ib:%llu\n",
+			caller_client->name, ab_vote, ib_vote);
+
+	mutex_lock(&rsc->client_lock);
+	if ((caller_client->current_state == SDE_RSC_IDLE_STATE) ||
+		(rsc->current_state == SDE_RSC_IDLE_STATE)) {
+
+		pr_err("invalid state: client state:%d rsc state:%d\n",
+			caller_client->current_state, rsc->current_state);
+		rc = -EINVAL;
+		goto end;
+	}
+
+	if (rsc->hw_ops.is_amc_mode)
+		amc_mode = rsc->hw_ops.is_amc_mode(rsc);
+
+	if (rsc->current_state == SDE_RSC_CMD_STATE)
+		state = RPMH_WAKE_ONLY_STATE;
+	else if (amc_mode)
+		state = RPMH_ACTIVE_ONLY_STATE;
+	else
+		state = RPMH_AWAKE_STATE;
+
+	if (rsc->hw_ops.tcs_wait) {
+		rc = rsc->hw_ops.tcs_wait(rsc);
+		if (rc) {
+			pr_err("tcs is still busy; can't send command\n");
+			if (rsc->hw_ops.tcs_use_ok)
+				rsc->hw_ops.tcs_use_ok(rsc);
+			goto end;
+		}
+	}
+
+	sde_power_data_bus_set_quota(&rsc->phandle, rsc->pclient,
+		SDE_POWER_HANDLE_DATA_BUS_CLIENT_RT, ab_vote, ib_vote);
+
+	if (rsc->hw_ops.tcs_use_ok)
+		rsc->hw_ops.tcs_use_ok(rsc);
+
+end:
+	mutex_unlock(&rsc->client_lock);
+	return rc;
+}
+
+static int _sde_debugfs_status_show(struct seq_file *s, void *data)
+{
+	struct sde_rsc_priv *rsc;
+	struct sde_rsc_client *client;
+	int ret;
+
+	if (!s || !s->private)
+		return -EINVAL;
+
+	rsc = s->private;
+
+	mutex_lock(&rsc->client_lock);
+	seq_printf(s, "rsc current state:%d\n", rsc->current_state);
+	seq_printf(s, "wraper backoff time(ns):%d\n",
+				rsc->timer_config.static_wakeup_time_ns);
+	seq_printf(s, "rsc backoff time(ns):%d\n",
+				rsc->timer_config.rsc_backoff_time_ns);
+	seq_printf(s, "pdc backoff time(ns):%d\n",
+				rsc->timer_config.pdc_backoff_time_ns);
+	seq_printf(s, "rsc mode threshold time(ns):%d\n",
+				rsc->timer_config.rsc_mode_threshold_time_ns);
+	seq_printf(s, "rsc time slot 0(ns):%d\n",
+				rsc->timer_config.rsc_time_slot_0_ns);
+	seq_printf(s, "rsc time slot 1(ns):%d\n",
+				rsc->timer_config.rsc_time_slot_1_ns);
+	seq_printf(s, "frame fps:%d jitter:%d vtotal:%d prefill lines:%d\n",
+			rsc->cmd_config.fps, rsc->cmd_config.jitter,
+			rsc->cmd_config.vtotal, rsc->cmd_config.prefill_lines);
+
+	seq_puts(s, "\n");
+
+	list_for_each_entry(client, &rsc->client_list, list)
+		seq_printf(s, "\t client:%s state:%d\n",
+				client->name, client->current_state);
+
+	sde_power_resource_enable(&rsc->phandle, rsc->pclient, true);
+
+	if (rsc->hw_ops.debug_show) {
+		ret = rsc->hw_ops.debug_show(s, rsc);
+		if (ret)
+			pr_err("sde rsc: hw debug failed ret:%d\n", ret);
+	}
+
+	sde_power_resource_enable(&rsc->phandle, rsc->pclient, false);
+	mutex_unlock(&rsc->client_lock);
+
+	return 0;
+}
+
+static int _sde_debugfs_status_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, _sde_debugfs_status_show, inode->i_private);
+}
+
+static int _sde_debugfs_mode_ctrl_open(struct inode *inode, struct file *file)
+{
+	/* non-seekable */
+	file->private_data = inode->i_private;
+	return nonseekable_open(inode, file);
+}
+
+static ssize_t _sde_debugfs_mode_ctrl_read(struct file *file, char __user *buf,
+				size_t count, loff_t *ppos)
+{
+	struct sde_rsc_priv *rsc = file->private_data;
+	char buffer[MAX_BUFFER_SIZE];
+	int blen = 0;
+
+	if (*ppos || !rsc || !rsc->hw_ops.mode_ctrl)
+		return 0;
+
+	mutex_lock(&rsc->client_lock);
+	sde_power_resource_enable(&rsc->phandle, rsc->pclient, true);
+
+	blen = rsc->hw_ops.mode_ctrl(rsc, MODE_READ, buffer,
+							MAX_BUFFER_SIZE, 0);
+
+	sde_power_resource_enable(&rsc->phandle, rsc->pclient, false);
+	mutex_unlock(&rsc->client_lock);
+
+	if (blen < 0)
+		return 0;
+
+	if (copy_to_user(buf, buffer, blen))
+		return -EFAULT;
+
+	*ppos += blen;
+	return blen;
+}
+
+static ssize_t _sde_debugfs_mode_ctrl_write(struct file *file,
+			const char __user *p, size_t count, loff_t *ppos)
+{
+	struct sde_rsc_priv *rsc = file->private_data;
+	char *input, *mode;
+	u32 mode0_state = 0, mode1_state = 0, mode2_state = 0;
+
+	if (!rsc || !rsc->hw_ops.mode_ctrl)
+		return 0;
+
+	input = kmalloc(count, GFP_KERNEL);
+	if (!input)
+		return -ENOMEM;
+
+	if (copy_from_user(input, p, count)) {
+		kfree(input);
+		return -EFAULT;
+	}
+	input[count - 1] = '\0';
+
+	mutex_lock(&rsc->client_lock);
+	sde_power_resource_enable(&rsc->phandle, rsc->pclient, true);
+
+	mode = strnstr(input, "mode0=", strlen("mode0="));
+	if (mode) {
+		mode0_state = mode[0] - '0';
+		mode0_state &= BIT(0);
+		rsc->hw_ops.mode_ctrl(rsc, MODE0_UPDATE, NULL, 0, mode0_state);
+		goto end;
+	}
+
+	mode = strnstr(input, "mode1=", strlen("mode1="));
+	if (mode) {
+		mode1_state = mode[0] - '0';
+		mode1_state &= BIT(0);
+		rsc->hw_ops.mode_ctrl(rsc, MODE1_UPDATE, NULL, 0, mode1_state);
+		goto end;
+	}
+
+	mode = strnstr(input, "mode2=", strlen("mode2="));
+	if (mode) {
+		mode2_state = mode[0] - '0';
+		mode2_state &= BIT(0);
+		rsc->hw_ops.mode_ctrl(rsc, MODE2_UPDATE, NULL, 0, mode2_state);
+	}
+
+end:
+	sde_power_resource_enable(&rsc->phandle, rsc->pclient, false);
+	mutex_unlock(&rsc->client_lock);
+
+	pr_err("req: mode0:%d mode1:%d mode2:%d\n", mode0_state, mode1_state,
+								mode2_state);
+	kfree(input);
+	return count;
+}
+
+static int _sde_debugfs_vsync_mode_open(struct inode *inode, struct file *file)
+{
+	/* non-seekable */
+	file->private_data = inode->i_private;
+	return nonseekable_open(inode, file);
+}
+
+static ssize_t _sde_debugfs_vsync_mode_read(struct file *file, char __user *buf,
+				size_t count, loff_t *ppos)
+{
+	struct sde_rsc_priv *rsc = file->private_data;
+	char buffer[MAX_BUFFER_SIZE];
+	int blen = 0;
+
+	if (*ppos || !rsc || !rsc->hw_ops.hw_vsync)
+		return 0;
+
+	mutex_lock(&rsc->client_lock);
+	sde_power_resource_enable(&rsc->phandle, rsc->pclient, true);
+
+	blen = rsc->hw_ops.hw_vsync(rsc, VSYNC_READ, buffer,
+						MAX_BUFFER_SIZE, 0);
+
+	sde_power_resource_enable(&rsc->phandle, rsc->pclient, false);
+	mutex_unlock(&rsc->client_lock);
+
+	if (blen < 0)
+		return 0;
+
+	if (copy_to_user(buf, buffer, blen))
+		return -EFAULT;
+
+	*ppos += blen;
+	return blen;
+}
+
+static ssize_t _sde_debugfs_vsync_mode_write(struct file *file,
+			const char __user *p, size_t count, loff_t *ppos)
+{
+	struct sde_rsc_priv *rsc = file->private_data;
+	char *input, *vsync_mode;
+	u32 vsync_state = 0;
+
+	if (!rsc || !rsc->hw_ops.hw_vsync)
+		return 0;
+
+	input = kmalloc(count, GFP_KERNEL);
+	if (!input)
+		return -ENOMEM;
+
+	if (copy_from_user(input, p, count)) {
+		kfree(input);
+		return -EFAULT;
+	}
+	input[count - 1] = '\0';
+
+	vsync_mode = strnstr(input, "vsync_mode=", strlen("vsync_mode="));
+	if (vsync_mode) {
+		vsync_state = vsync_mode[0] - '0';
+		vsync_state &= 0x7;
+	}
+
+	mutex_lock(&rsc->client_lock);
+	sde_power_resource_enable(&rsc->phandle, rsc->pclient, true);
+
+	if (vsync_state)
+		rsc->hw_ops.hw_vsync(rsc, VSYNC_ENABLE, NULL,
+							0, vsync_state - 1);
+	else
+		rsc->hw_ops.hw_vsync(rsc, VSYNC_DISABLE, NULL, 0, 0);
+
+	sde_power_resource_enable(&rsc->phandle, rsc->pclient, false);
+	mutex_unlock(&rsc->client_lock);
+
+	kfree(input);
+	return count;
+}
+
+static const struct file_operations debugfs_status_fops = {
+	.open =		_sde_debugfs_status_open,
+	.read =		seq_read,
+	.llseek =	seq_lseek,
+	.release =	single_release,
+};
+
+static const struct file_operations mode_control_fops = {
+	.open =		_sde_debugfs_mode_ctrl_open,
+	.read =		_sde_debugfs_mode_ctrl_read,
+	.write =	_sde_debugfs_mode_ctrl_write,
+};
+
+static const struct file_operations vsync_status_fops = {
+	.open =		_sde_debugfs_vsync_mode_open,
+	.read =		_sde_debugfs_vsync_mode_read,
+	.write =	_sde_debugfs_vsync_mode_write,
+};
+
+static void _sde_rsc_init_debugfs(struct sde_rsc_priv *rsc, char *name)
+{
+	rsc->debugfs_root = debugfs_create_dir(name, NULL);
+	if (!rsc->debugfs_root)
+		return;
+
+	/* don't error check these */
+	debugfs_create_file("status", 0444, rsc->debugfs_root, rsc,
+							&debugfs_status_fops);
+	debugfs_create_file("mode_control", 0644, rsc->debugfs_root, rsc,
+							&mode_control_fops);
+	debugfs_create_file("vsync_mode", 0644, rsc->debugfs_root, rsc,
+							&vsync_status_fops);
+	debugfs_create_x32("debug_mode", 0644, rsc->debugfs_root,
+							&rsc->debug_mode);
+}
+
+static void sde_rsc_deinit(struct platform_device *pdev,
+					struct sde_rsc_priv *rsc)
+{
+	if (!rsc)
+		return;
+
+	if (rsc->pclient)
+		sde_power_resource_enable(&rsc->phandle, rsc->pclient, false);
+	if (rsc->fs)
+		devm_regulator_put(rsc->fs);
+	if (rsc->wrapper_io.base)
+		msm_dss_iounmap(&rsc->wrapper_io);
+	if (rsc->drv_io.base)
+		msm_dss_iounmap(&rsc->drv_io);
+	if (rsc->pclient)
+		sde_power_client_destroy(&rsc->phandle, rsc->pclient);
+
+	sde_power_resource_deinit(pdev, &rsc->phandle);
+	debugfs_remove_recursive(rsc->debugfs_root);
+	kfree(rsc);
+}
+
+/**
+ * sde_rsc_bind - bind rsc device with controlling device
+ * @dev:        Pointer to base of platform device
+ * @master:     Pointer to container of drm device
+ * @data:       Pointer to private data
+ * Returns:     Zero on success
+ */
+static int sde_rsc_bind(struct device *dev,
+		struct device *master,
+		void *data)
+{
+	struct sde_rsc_priv *rsc;
+	struct drm_device *drm;
+	struct platform_device *pdev = to_platform_device(dev);
+
+	if (!dev || !pdev || !master) {
+		pr_err("invalid param(s), dev %pK, pdev %pK, master %pK\n",
+				dev, pdev, master);
+		return -EINVAL;
+	}
+
+	drm = dev_get_drvdata(master);
+	rsc = platform_get_drvdata(pdev);
+	if (!drm || !rsc) {
+		pr_err("invalid param(s), drm %pK, rsc %pK\n",
+				drm, rsc);
+		return -EINVAL;
+	}
+
+	mutex_lock(&rsc->client_lock);
+	rsc->master_drm = drm;
+	mutex_unlock(&rsc->client_lock);
+
+	return 0;
+}
+
+/**
+ * sde_rsc_unbind - unbind rsc from controlling device
+ * @dev:        Pointer to base of platform device
+ * @master:     Pointer to container of drm device
+ * @data:       Pointer to private data
+ */
+static void sde_rsc_unbind(struct device *dev,
+		struct device *master, void *data)
+{
+	struct sde_rsc_priv *rsc;
+	struct platform_device *pdev = to_platform_device(dev);
+
+	if (!dev || !pdev) {
+		pr_err("invalid param(s)\n");
+		return;
+	}
+
+	rsc = platform_get_drvdata(pdev);
+	if (!rsc) {
+		pr_err("invalid display rsc\n");
+		return;
+	}
+
+	mutex_lock(&rsc->client_lock);
+	rsc->master_drm = NULL;
+	mutex_unlock(&rsc->client_lock);
+}
+
+static const struct component_ops sde_rsc_comp_ops = {
+	.bind = sde_rsc_bind,
+	.unbind = sde_rsc_unbind,
+};
+
+static int sde_rsc_probe(struct platform_device *pdev)
+{
+	int ret;
+	struct sde_rsc_priv *rsc;
+	static int counter;
+	char  name[MAX_RSC_CLIENT_NAME_LEN];
+
+	rsc = kzalloc(sizeof(*rsc), GFP_KERNEL);
+	if (!rsc) {
+		ret = -ENOMEM;
+		goto rsc_alloc_fail;
+	}
+
+	platform_set_drvdata(pdev, rsc);
+	of_property_read_u32(pdev->dev.of_node, "qcom,sde-rsc-version",
+								&rsc->version);
+
+	ret = sde_power_resource_init(pdev, &rsc->phandle);
+	if (ret) {
+		pr_err("sde rsc:power resource init failed ret:%d\n", ret);
+		goto sde_rsc_fail;
+	}
+
+	rsc->pclient = sde_power_client_create(&rsc->phandle, "rsc");
+	if (IS_ERR_OR_NULL(rsc->pclient)) {
+		ret = PTR_ERR(rsc->pclient);
+		rsc->pclient = NULL;
+		pr_err("sde rsc:power client create failed ret:%d\n", ret);
+		goto sde_rsc_fail;
+	}
+
+	ret = msm_dss_ioremap_byname(pdev, &rsc->wrapper_io, "wrapper");
+	if (ret) {
+		pr_err("sde rsc: wrapper io data mapping failed ret=%d\n", ret);
+		goto sde_rsc_fail;
+	}
+
+	ret = msm_dss_ioremap_byname(pdev, &rsc->drv_io, "drv");
+	if (ret) {
+		pr_err("sde rsc: drv io data mapping failed ret:%d\n", ret);
+		goto sde_rsc_fail;
+	}
+
+	rsc->fs = devm_regulator_get(&pdev->dev, "vdd");
+	if (IS_ERR_OR_NULL(rsc->fs)) {
+		rsc->fs = NULL;
+		pr_err("unable to get regulator\n");
+		goto sde_rsc_fail;
+	}
+
+	ret = sde_rsc_hw_register(rsc);
+	if (ret) {
+		pr_err("sde rsc: hw register failed ret:%d\n", ret);
+		goto sde_rsc_fail;
+	}
+
+	/* these clocks are always on */
+	if (sde_power_resource_enable(&rsc->phandle, rsc->pclient, true)) {
+		pr_err("failed to enable sde rsc power resources\n");
+		goto sde_rsc_fail;
+	}
+
+	if (sde_rsc_timer_calculate(rsc, NULL))
+		goto sde_rsc_fail;
+
+	INIT_LIST_HEAD(&rsc->client_list);
+	mutex_init(&rsc->client_lock);
+
+	pr_info("sde rsc index:%d probed successfully\n",
+				SDE_RSC_INDEX + counter);
+
+	rsc_prv_list[SDE_RSC_INDEX + counter] = rsc;
+	snprintf(name, MAX_RSC_CLIENT_NAME_LEN, "%s%d", "sde_rsc", counter);
+	_sde_rsc_init_debugfs(rsc, name);
+	counter++;
+
+	ret = component_add(&pdev->dev, &sde_rsc_comp_ops);
+	if (ret)
+		pr_debug("component add failed, ret=%d\n", ret);
+	ret = 0;
+
+	return ret;
+
+sde_rsc_fail:
+	sde_rsc_deinit(pdev, rsc);
+rsc_alloc_fail:
+	return ret;
+}
+
+static int sde_rsc_remove(struct platform_device *pdev)
+{
+	struct sde_rsc_priv *rsc = platform_get_drvdata(pdev);
+
+	sde_rsc_deinit(pdev, rsc);
+	return 0;
+}
+
+static const struct of_device_id dt_match[] = {
+	{ .compatible = "qcom,sde-rsc"},
+	{}
+};
+
+MODULE_DEVICE_TABLE(of, dt_match);
+
+static struct platform_driver sde_rsc_platform_driver = {
+	.probe      = sde_rsc_probe,
+	.remove     = sde_rsc_remove,
+	.driver     = {
+		.name   = "sde_rsc",
+		.of_match_table = dt_match,
+	},
+};
+
+static int __init sde_rsc_register(void)
+{
+	return platform_driver_register(&sde_rsc_platform_driver);
+}
+
+static void __exit sde_rsc_unregister(void)
+{
+	platform_driver_unregister(&sde_rsc_platform_driver);
+}
+
+module_init(sde_rsc_register);
+module_exit(sde_rsc_unregister);
diff --git a/drivers/gpu/drm/msm/sde_rsc.h b/drivers/gpu/drm/msm/sde_rsc.h
new file mode 100644
index 0000000..e9a55b6
--- /dev/null
+++ b/drivers/gpu/drm/msm/sde_rsc.h
@@ -0,0 +1,302 @@
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef _SDE_RSC_H_
+#define _SDE_RSC_H_
+
+#include <linux/kernel.h>
+#include <linux/sde_io_util.h>
+
+#include <soc/qcom/tcs.h>
+#include "sde_power_handle.h"
+
+#define SDE_RSC_COMPATIBLE "disp_rscc"
+
+#define MAX_RSC_CLIENT_NAME_LEN 128
+
+/* primary display rsc index */
+#define SDE_RSC_INDEX		0
+
+/* rsc index max count */
+#define MAX_RSC_COUNT		5
+
+struct sde_rsc_priv;
+
+/**
+ * rsc_mode_req: sde rsc mode request information
+ * MODE_READ: read vsync status
+ * MODE0_UPDATE: mode0 status , this should be 0x0
+ * MODE1_UPDATE: mode1 status , this should be 0x1
+ * MODE2_UPDATE: mode2 status , this should be 0x2
+ */
+enum rsc_mode_req {
+	MODE_READ,
+	MODE0_UPDATE = 0x1,
+	MODE1_UPDATE = 0x2,
+	MODE2_UPDATE = 0x3,
+};
+
+/**
+ * rsc_vsync_req: sde rsc vsync request information
+ * VSYNC_READ: read vsync status
+ * VSYNC_ENABLE: enable rsc wrapper vsync status
+ * VSYNC_DISABLE: disable rsc wrapper vsync status
+ */
+enum rsc_vsync_req {
+	VSYNC_READ,
+	VSYNC_ENABLE,
+	VSYNC_DISABLE,
+};
+
+/**
+ * sde_rsc_state: sde rsc state information
+ * SDE_RSC_MODE_IDLE: A client requests for idle state when there is no
+ *                    pixel or cmd transfer expected. An idle vote from
+ *                    all clients lead to power collapse state.
+ * SDE_RSC_MODE_CMD:  A client requests for cmd state when it wants to
+ *                    enable the solver mode.
+ * SDE_RSC_MODE_CMD_UPDATE: A clients requests for cmd_update state when
+ *                    it wants to update the backoff time during solver
+ *                    enable state. Inline-rotation is one good example
+ *                    use case. It increases the prefill lines by 128 lines.
+ * SDE_RSC_MODE_VID:  A client requests for vid state it wants to avoid
+ *                    solver enable because client is fetching data from
+ *                    continuously.
+ */
+enum sde_rsc_state {
+	SDE_RSC_IDLE_STATE,
+	SDE_RSC_CMD_STATE,
+	SDE_RSC_CMD_UPDATE_STATE,
+	SDE_RSC_VID_STATE,
+};
+
+/**
+ * struct sde_rsc_client: stores the rsc client for sde driver
+ * @name:	name of the client
+ * @current_state:   current client state
+ * @crtc_id:		crtc_id associated with this rsc client.
+ * @rsc_index:	rsc index of a client - only index "0" valid.
+ * @list:	list to attach power handle master list
+ */
+struct sde_rsc_client {
+	char name[MAX_RSC_CLIENT_NAME_LEN];
+	short current_state;
+	int crtc_id;
+	u32 rsc_index;
+	struct list_head list;
+};
+
+/**
+ * struct sde_rsc_hw_ops - sde resource state coordinator hardware ops
+ * @init:			Initialize the sequencer, solver, qtimer,
+				etc. hardware blocks on RSC.
+ * @tcs_wait:			Waits for TCS block OK to allow sending a
+ *				TCS command.
+ * @hw_vsync:			Enables the vsync on RSC block.
+ * @tcs_use_ok:			set TCS set to high to allow RSC to use it.
+ * @mode2_entry:		Request to entry mode2 when all clients are
+ *                              requesting power collapse.
+ * @mode2_exit:			Request to exit mode2 when one of the client
+ *                              is requesting against the power collapse
+ * @is_amc_mode:		Check current amc mode status
+ * @state_update:		Enable/override the solver based on rsc state
+ *                              status (command/video)
+ * @mode_show:			shows current mode status, mode0/1/2
+ * @debug_show:			Show current debug status.
+ */
+
+struct sde_rsc_hw_ops {
+	int (*init)(struct sde_rsc_priv *rsc);
+	int (*tcs_wait)(struct sde_rsc_priv *rsc);
+	int (*hw_vsync)(struct sde_rsc_priv *rsc, enum rsc_vsync_req request,
+		char *buffer, int buffer_size, u32 mode);
+	int (*tcs_use_ok)(struct sde_rsc_priv *rsc);
+	int (*mode2_entry)(struct sde_rsc_priv *rsc);
+	int (*mode2_exit)(struct sde_rsc_priv *rsc);
+	bool (*is_amc_mode)(struct sde_rsc_priv *rsc);
+	int (*state_update)(struct sde_rsc_priv *rsc, enum sde_rsc_state state);
+	int (*debug_show)(struct seq_file *s, struct sde_rsc_priv *rsc);
+	int (*mode_ctrl)(struct sde_rsc_priv *rsc, enum rsc_mode_req request,
+		char *buffer, int buffer_size, bool mode);
+};
+
+/**
+ * struct sde_rsc_cmd_config: provides panel configuration to rsc
+ * when client is command mode. It is not required to set it during
+ * video mode.
+ *
+ * @fps:	panel te interval
+ * @vtotal:	current vertical total (height + vbp + vfp)
+ * @jitter:	panel can set the jitter to wake up rsc/solver early
+ *              This value causes mdp core to exit certain mode
+ *              early. Default is 10% jitter
+ * @prefill_lines:	max prefill lines based on panel
+ */
+struct sde_rsc_cmd_config {
+	u32 fps;
+	u32 vtotal;
+	u32 jitter;
+	u32 prefill_lines;
+};
+
+/**
+ * struct sde_rsc_timer_config: this is internal configuration between
+ * rsc and rsc_hw API.
+ *
+ * @static_wakeup_time_ns:	wrapper backoff time in nano seconds
+ * @rsc_backoff_time_ns:	rsc backoff time in nano seconds
+ * @pdc_backoff_time_ns:	pdc backoff time in nano seconds
+ * @rsc_mode_threshold_time_ns:	rsc mode threshold time in nano seconds
+ * @rsc_time_slot_0_ns:		mode-0 time slot threshold in nano seconds
+ * @rsc_time_slot_1_ns:		mode-1 time slot threshold in nano seconds
+ * @rsc_time_slot_2_ns:		mode-2 time slot threshold in nano seconds
+ */
+struct sde_rsc_timer_config {
+	u32 static_wakeup_time_ns;
+
+	u32 rsc_backoff_time_ns;
+	u32 pdc_backoff_time_ns;
+	u32 rsc_mode_threshold_time_ns;
+	u32 rsc_time_slot_0_ns;
+	u32 rsc_time_slot_1_ns;
+	u32 rsc_time_slot_2_ns;
+};
+
+/**
+ * struct sde_rsc_priv: sde resource state coordinator(rsc) private handle
+ * @version:		rsc sequence version
+ * @phandle:		module power handle for clocks
+ * @pclient:		module power client of phandle
+ * @fs:			"MDSS GDSC" handle
+ *
+ * @drv_io:		sde drv io data mapping
+ * @wrapper_io:		wrapper io data mapping
+ *
+ * @client_list:	current rsc client list handle
+ * @client_lock:	current rsc client synchronization lock
+ *
+ * timer_config:	current rsc timer configuration
+ * cmd_config:		current panel config
+ * current_state:	current rsc state (video/command), solver
+ *                      override/enabled.
+ * debug_mode:		enables the logging for each register read/write
+ * debugfs_root:	debugfs file system root node
+ *
+ * hw_ops:		sde rsc hardware operations
+ * power_collapse:	if all clients are in IDLE state then it enters in
+ *			mode2 state and enable the power collapse state
+ * power_collapse_block:By default, rsc move to mode-2 if all clients are in
+ *			invalid state. It can be blocked by this boolean entry.
+ * primary_client:	A client which is allowed to make command state request
+ *			and ab/ib vote on display rsc
+ * master_drm:		Primary client waits for vsync on this drm object based
+ *			on crtc id
+ */
+struct sde_rsc_priv {
+	u32 version;
+	struct sde_power_handle phandle;
+	struct sde_power_client *pclient;
+	struct regulator *fs;
+
+	struct dss_io_data drv_io;
+	struct dss_io_data wrapper_io;
+
+	struct list_head client_list;
+	struct mutex client_lock;
+
+	struct sde_rsc_timer_config timer_config;
+	struct sde_rsc_cmd_config cmd_config;
+	u32	current_state;
+
+	u32 debug_mode;
+	struct dentry *debugfs_root;
+
+	struct sde_rsc_hw_ops hw_ops;
+	bool power_collapse;
+	bool power_collapse_block;
+	struct sde_rsc_client *primary_client;
+
+	struct drm_device *master_drm;
+};
+
+/**
+ * sde_rsc_client_create() - create the client for sde rsc.
+ * Different displays like DSI, HDMI, DP, WB, etc should call this
+ * api to register their vote for rpmh. They still need to vote for
+ * power handle to get the clocks.
+
+ * @rsc_index:   A client will be created on this RSC. As of now only
+ *               SDE_RSC_INDEX is valid rsc index.
+ * @name:	 Caller needs to provide some valid string to identify
+ *               the client. "primary", "dp", "hdmi" are suggested name.
+ * @is_primary:	 Caller needs to provide information if client is primary
+ *               or not. Primary client votes will be redirected to
+ *               display rsc.
+ * @config:	 fps, vtotal, porches, etc configuration for command mode
+ *               panel
+ *
+ * Return: client node pointer.
+ */
+struct sde_rsc_client *sde_rsc_client_create(u32 rsc_index, char *name,
+		bool is_primary_display);
+
+/**
+ * sde_rsc_client_destroy() - Destroy the sde rsc client.
+ *
+ * @client:	 Client pointer provided by sde_rsc_client_create().
+ *
+ * Return: none
+ */
+void sde_rsc_client_destroy(struct sde_rsc_client *client);
+
+/**
+ * sde_rsc_client_state_update() - rsc client state update
+ * Video mode and command mode are supported as modes. A client need to
+ * set this property during panel time. A switching client can set the
+ * property to change the state
+ *
+ * @client:	 Client pointer provided by sde_rsc_client_create().
+ * @state:	 Client state - video/cmd
+ * @config:	 fps, vtotal, porches, etc configuration for command mode
+ *               panel
+ * @crtc_id:	 current client's crtc id
+ *
+ * Return: error code.
+ */
+int sde_rsc_client_state_update(struct sde_rsc_client *client,
+	enum sde_rsc_state state,
+	struct sde_rsc_cmd_config *config, int crtc_id);
+
+/**
+ * sde_rsc_client_vote() - ab/ib vote from rsc client
+ *
+ * @client:	 Client pointer provided by sde_rsc_client_create().
+ * @ab:		 aggregated bandwidth vote from client.
+ * @ib:		 instant bandwidth vote from client.
+ *
+ * Return: error code.
+ */
+int sde_rsc_client_vote(struct sde_rsc_client *caller_client,
+	u64 ab_vote, u64 ib_vote);
+
+/**
+ * sde_rsc_hw_register() - register hardware API
+ *
+ * @client:	 Client pointer provided by sde_rsc_client_create().
+ *
+ * Return: error code.
+ */
+int sde_rsc_hw_register(struct sde_rsc_priv *rsc);
+
+
+#endif /* _SDE_RSC_H_ */
diff --git a/drivers/gpu/drm/msm/sde_rsc_hw.c b/drivers/gpu/drm/msm/sde_rsc_hw.c
new file mode 100644
index 0000000..8dd04bd
--- /dev/null
+++ b/drivers/gpu/drm/msm/sde_rsc_hw.c
@@ -0,0 +1,681 @@
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#define pr_fmt(fmt)	"[sde_rsc_hw:%s:%d]: " fmt, __func__, __LINE__
+
+#include <linux/kernel.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+
+#include "sde_rsc.h"
+
+/* display rsc offset */
+#define SDE_RSCC_PDC_SEQ_START_ADDR_REG_OFFSET_DRV0	0x020
+#define SDE_RSCC_PDC_MATCH_VALUE_LO_REG_OFFSET_DRV0	0x024
+#define SDE_RSCC_PDC_MATCH_VALUE_HI_REG_OFFSET_DRV0	0x028
+#define SDE_RSCC_PDC_SLAVE_ID_DRV0			0x02c
+#define SDE_RSCC_SEQ_CFG_BR_ADDR_0_DRV0			0x410
+#define SDE_RSCC_SEQ_CFG_BR_ADDR_1_DRV0			0x414
+#define SDE_RSCC_SEQ_MEM_0_DRV0				0x600
+#define SDE_RSCC_SOLVER_OVERRIDE_CTRL_DRV0		0xc14
+#define SDE_RSCC_ERROR_IRQ_STATUS_DRV0			0x0d0
+#define SDE_RSCC_SEQ_BUSY_DRV0				0x404
+#define SDE_RSCC_SOLVER_STATUS0_DRV0			0xc24
+#define SDE_RSCC_SOLVER_STATUS1_DRV0			0xc28
+#define SDE_RSCC_SOLVER_STATUS2_DRV0			0xc2c
+#define SDE_RSCC_AMC_TCS_MODE_IRQ_STATUS_DRV0		0x1c00
+
+#define SDE_RSCC_SOFT_WAKEUP_TIME_LO_DRV0		0xc04
+#define SDE_RSCC_MAX_IDLE_DURATION_DRV0			0xc0c
+#define SDE_RSC_SOLVER_TIME_SLOT_TABLE_0_DRV0		0x1000
+#define SDE_RSC_SOLVER_TIME_SLOT_TABLE_1_DRV0		0x1004
+#define SDE_RSC_SOLVER_TIME_SLOT_TABLE_2_DRV0		0x1008
+#define SDE_RSC_SOLVER_TIME_SLOT_TABLE_3_DRV0		0x100c
+
+#define SDE_RSC_SOLVER_SOLVER_MODES_ENABLED_DRV0	0xc20
+#define SDE_RSC_SOLVER_MODE_PRI_TABLE_SLOT0_PRI0_DRV0	0x1080
+#define SDE_RSC_SOLVER_MODE_PRI_TABLE_SLOT1_PRI0_DRV0	0x1100
+#define SDE_RSC_SOLVER_MODE_PRI_TABLE_SLOT1_PRI3_DRV0	0x110c
+#define SDE_RSC_SOLVER_MODE_PRI_TABLE_SLOT2_PRI0_DRV0	0x1180
+#define SDE_RSC_SOLVER_MODE_PRI_TABLE_SLOT2_PRI3_DRV0	0x118c
+
+#define SDE_RSC_SOLVER_OVERRIDE_MODE_DRV0		0xc18
+#define SDE_RSC_SOLVER_OVERRIDE_CTRL_DRV0		0xc14
+#define SDE_RSC_TIMERS_CONSIDERED_DRV0			0xc00
+#define SDE_RSC_SOLVER_OVERRIDE_IDLE_TIME_DRV0		0xc1c
+
+#define SDE_RSC_SOLVER_MODE_PARM0_DRV0_MODE0		0xc30
+#define SDE_RSC_SOLVER_MODE_PARM1_DRV0_MODE0		0xc34
+#define SDE_RSC_SOLVER_MODE_PARM2_DRV0_MODE0		0xc38
+#define SDE_RSC_SOLVER_MODE_PARM3_DRV0_MODE0		0xc40
+
+#define SDE_RSC_SOLVER_MODE_PARM0_DRV0_MODE1		0xc4c
+#define SDE_RSC_SOLVER_MODE_PARM1_DRV0_MODE1		0xc50
+#define SDE_RSC_SOLVER_MODE_PARM2_DRV0_MODE1		0xc54
+#define SDE_RSC_SOLVER_MODE_PARM3_DRV0_MODE1		0xc5c
+
+#define SDE_RSC_SOLVER_MODE_PARM0_DRV0_MODE2		0xc68
+#define SDE_RSC_SOLVER_MODE_PARM1_DRV0_MODE2		0xc6c
+#define SDE_RSC_SOLVER_MODE_PARM2_DRV0_MODE2		0xc70
+#define SDE_RSC_SOLVER_MODE_PARM3_DRV0_MODE2		0xc78
+
+#define SDE_RSCC_TCS_DRV0_CONTROL			0x1c14
+
+#define SDE_RSCC_WRAPPER_CTRL				0x000
+#define SDE_RSCC_WRAPPER_OVERRIDE_CTRL			0x004
+#define SDE_RSCC_WRAPPER_STATIC_WAKEUP_0		0x008
+#define SDE_RSCC_WRAPPER_RSCC_MODE_THRESHOLD		0x00c
+#define SDE_RSCC_WRAPPER_DEBUG_BUS			0x010
+#define SDE_RSCC_WRAPPER_VSYNC_TIMESTAMP0		0x018
+#define SDE_RSCC_WRAPPER_VSYNC_TIMESTAMP1		0x01c
+#define SDE_RSCC_SPARE_PWR_EVENT			0x020
+#define SDE_RSCC_PWR_CTRL				0x024
+
+/* qtimer offset */
+#define SDE_RSCC_QTMR_AC_HW_FRAME_SEL_1			0x1FE0
+#define SDE_RSCC_QTMR_AC_HW_FRAME_SEL_2			0x1FF0
+#define SDE_RSCC_QTMR_AC_CNTACR0_FG0			0x1040
+#define SDE_RSCC_QTMR_AC_CNTACR1_FG0			0x1044
+#define SDE_RSCC_F0_QTMR_V1_CNTP_CVAL_LO		0x2020
+#define SDE_RSCC_F0_QTMR_V1_CNTP_CVAL_HI		0x2024
+#define SDE_RSCC_F1_QTMR_V1_CNTP_CVAL_LO		0x3020
+#define SDE_RSCC_F1_QTMR_V1_CNTP_CVAL_HI		0x3024
+#define SDE_RSCC_F0_QTMR_V1_CNTP_CTL			0x202C
+#define SDE_RSCC_F1_QTMR_V1_CNTP_CTL			0x302C
+
+/* mdp and dsi clocks in clock gate state */
+#define DISP_MDP_DSI_CLK_GATE		0x7f0
+
+/* mdp and dsi clocks in clock ungate state */
+#define MDSS_CORE_GDSCR			0x0
+#define DISP_MDP_DSI_CLK_UNGATE		0x5000
+
+#define MAX_CHECK_LOOPS			500
+
+static int rsc_hw_qtimer_init(struct sde_rsc_priv *rsc)
+{
+	pr_debug("rsc hardware qtimer init\n");
+
+	dss_reg_w(&rsc->wrapper_io, SDE_RSCC_QTMR_AC_HW_FRAME_SEL_1,
+						0xffffffff, rsc->debug_mode);
+	dss_reg_w(&rsc->wrapper_io, SDE_RSCC_QTMR_AC_HW_FRAME_SEL_2,
+						0xffffffff, rsc->debug_mode);
+
+	dss_reg_w(&rsc->wrapper_io, SDE_RSCC_QTMR_AC_CNTACR0_FG0,
+						0x1, rsc->debug_mode);
+	dss_reg_w(&rsc->wrapper_io, SDE_RSCC_QTMR_AC_CNTACR1_FG0,
+						0x1, rsc->debug_mode);
+
+	dss_reg_w(&rsc->wrapper_io, SDE_RSCC_F0_QTMR_V1_CNTP_CVAL_LO,
+						0xffffffff, rsc->debug_mode);
+	dss_reg_w(&rsc->wrapper_io, SDE_RSCC_F0_QTMR_V1_CNTP_CVAL_HI,
+						0xffffffff, rsc->debug_mode);
+	dss_reg_w(&rsc->wrapper_io, SDE_RSCC_F1_QTMR_V1_CNTP_CVAL_LO,
+						0xffffffff, rsc->debug_mode);
+	dss_reg_w(&rsc->wrapper_io, SDE_RSCC_F1_QTMR_V1_CNTP_CVAL_HI,
+						0xffffffff, rsc->debug_mode);
+
+	dss_reg_w(&rsc->wrapper_io, SDE_RSCC_F0_QTMR_V1_CNTP_CTL,
+						0x1, rsc->debug_mode);
+	dss_reg_w(&rsc->wrapper_io, SDE_RSCC_F1_QTMR_V1_CNTP_CTL,
+						0x1, rsc->debug_mode);
+
+	return 0;
+}
+
+static int rsc_hw_pdc_init(struct sde_rsc_priv *rsc)
+{
+	pr_debug("rsc hardware pdc init\n");
+
+	dss_reg_w(&rsc->drv_io, SDE_RSCC_PDC_SEQ_START_ADDR_REG_OFFSET_DRV0,
+						0x4520, rsc->debug_mode);
+	dss_reg_w(&rsc->drv_io, SDE_RSCC_PDC_MATCH_VALUE_LO_REG_OFFSET_DRV0,
+						0x4510, rsc->debug_mode);
+	dss_reg_w(&rsc->drv_io, SDE_RSCC_PDC_MATCH_VALUE_HI_REG_OFFSET_DRV0,
+						0x4514, rsc->debug_mode);
+	dss_reg_w(&rsc->drv_io, SDE_RSCC_PDC_SLAVE_ID_DRV0,
+						0x1, rsc->debug_mode);
+
+	return 0;
+}
+
+static int rsc_hw_wrapper_init(struct sde_rsc_priv *rsc)
+{
+	pr_debug("rsc hardware wrapper init\n");
+
+	dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_STATIC_WAKEUP_0,
+		rsc->timer_config.static_wakeup_time_ns, rsc->debug_mode);
+
+	dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_RSCC_MODE_THRESHOLD,
+		rsc->timer_config.rsc_mode_threshold_time_ns, rsc->debug_mode);
+
+	dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_OVERRIDE_CTRL,
+						BIT(8), rsc->debug_mode);
+	return 0;
+}
+
+static int rsc_hw_seq_memory_init(struct sde_rsc_priv *rsc)
+{
+	pr_debug("rsc sequencer memory init\n");
+
+	/* Mode - 0 sequence */
+	dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0x0,
+						0xe0a88bab, rsc->debug_mode);
+	dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0x4,
+						0x8babec39, rsc->debug_mode);
+	dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0x8,
+						0x8bab2088, rsc->debug_mode);
+
+	/* Mode - 1 sequence */
+	dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0xc,
+						0x39e038a8, rsc->debug_mode);
+	dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0x10,
+						0x888babec, rsc->debug_mode);
+	dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0x14,
+						0xaaa8a020, rsc->debug_mode);
+
+	/* Mode - 2 sequence */
+	dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0x18,
+						0xe1a138eb, rsc->debug_mode);
+	dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0x1c,
+						0xa2ede081, rsc->debug_mode);
+	dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0x20,
+						0x8a3982e2, rsc->debug_mode);
+	dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0x24,
+						0xa92088ea, rsc->debug_mode);
+	dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0x28,
+						0x89e6a6e9, rsc->debug_mode);
+
+	/* tcs sleep sequence */
+	dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0x2c,
+						0xa7e9a920, rsc->debug_mode);
+	dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0x30,
+						0x002089e7, rsc->debug_mode);
+
+	/* branch address */
+	dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_CFG_BR_ADDR_0_DRV0,
+						0x27, rsc->debug_mode);
+	dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_CFG_BR_ADDR_1_DRV0,
+						0x2d, rsc->debug_mode);
+
+	return 0;
+}
+
+static int rsc_hw_solver_init(struct sde_rsc_priv *rsc)
+{
+	const u32 mode_0_start_addr = 0x0;
+	const u32 mode_1_start_addr = 0xa;
+	const u32 mode_2_start_addr = 0x15;
+
+	pr_debug("rsc solver init\n");
+
+	dss_reg_w(&rsc->drv_io, SDE_RSCC_SOFT_WAKEUP_TIME_LO_DRV0,
+					0x7FFFFFFF, rsc->debug_mode);
+	dss_reg_w(&rsc->drv_io, SDE_RSCC_MAX_IDLE_DURATION_DRV0,
+					0xEFFFFFFF, rsc->debug_mode);
+
+	dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_TIME_SLOT_TABLE_0_DRV0,
+						0x0, rsc->debug_mode);
+	dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_TIME_SLOT_TABLE_1_DRV0,
+		rsc->timer_config.rsc_time_slot_0_ns, rsc->debug_mode);
+	dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_TIME_SLOT_TABLE_2_DRV0,
+		rsc->timer_config.rsc_time_slot_1_ns, rsc->debug_mode);
+	dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_TIME_SLOT_TABLE_3_DRV0,
+		rsc->timer_config.rsc_time_slot_2_ns, rsc->debug_mode);
+
+	dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_SOLVER_MODES_ENABLED_DRV0,
+						0x7, rsc->debug_mode);
+
+	dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PRI_TABLE_SLOT0_PRI0_DRV0,
+						0x0, rsc->debug_mode);
+	dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PRI_TABLE_SLOT1_PRI0_DRV0,
+						0x1, rsc->debug_mode);
+	dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PRI_TABLE_SLOT1_PRI3_DRV0,
+						0x1, rsc->debug_mode);
+	dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PRI_TABLE_SLOT2_PRI0_DRV0,
+						0x2, rsc->debug_mode);
+	dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PRI_TABLE_SLOT2_PRI3_DRV0,
+						0x2, rsc->debug_mode);
+
+	dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_OVERRIDE_MODE_DRV0,
+						0x0, rsc->debug_mode);
+	dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_OVERRIDE_CTRL_DRV0,
+					mode_0_start_addr, rsc->debug_mode);
+	dss_reg_w(&rsc->drv_io, SDE_RSC_TIMERS_CONSIDERED_DRV0,
+						0x1, rsc->debug_mode);
+	dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_OVERRIDE_IDLE_TIME_DRV0,
+						0x01000010, rsc->debug_mode);
+
+	dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PARM0_DRV0_MODE0,
+					mode_0_start_addr, rsc->debug_mode);
+	dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PARM1_DRV0_MODE0,
+					0x80000010, rsc->debug_mode);
+	dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PARM2_DRV0_MODE0,
+			rsc->timer_config.rsc_backoff_time_ns, rsc->debug_mode);
+	dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PARM3_DRV0_MODE0,
+			rsc->timer_config.pdc_backoff_time_ns, rsc->debug_mode);
+
+	dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PARM0_DRV0_MODE1,
+					mode_1_start_addr, rsc->debug_mode);
+	dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PARM1_DRV0_MODE1,
+					0x80000010, rsc->debug_mode);
+	dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PARM2_DRV0_MODE1,
+			rsc->timer_config.rsc_backoff_time_ns, rsc->debug_mode);
+	dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PARM3_DRV0_MODE1,
+			rsc->timer_config.pdc_backoff_time_ns, rsc->debug_mode);
+
+	dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PARM0_DRV0_MODE2,
+					mode_2_start_addr, rsc->debug_mode);
+	dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PARM1_DRV0_MODE2,
+					0x80000010, rsc->debug_mode);
+	dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PARM2_DRV0_MODE2,
+			rsc->timer_config.rsc_backoff_time_ns, rsc->debug_mode);
+	dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PARM3_DRV0_MODE2,
+			rsc->timer_config.pdc_backoff_time_ns, rsc->debug_mode);
+
+	return 0;
+}
+
+int sde_rsc_mode2_entry(struct sde_rsc_priv *rsc)
+{
+	int rc;
+	int count, wrapper_status;
+
+	if (rsc->power_collapse_block)
+		return -EINVAL;
+
+	rc = regulator_set_mode(rsc->fs, REGULATOR_MODE_FAST);
+	if (rc) {
+		pr_err("vdd reg fast mode set failed rc:%d\n", rc);
+		goto end;
+	}
+
+	rc = -EBUSY;
+	wrapper_status = dss_reg_r(&rsc->wrapper_io, SDE_RSCC_WRAPPER_CTRL,
+				rsc->debug_mode);
+	wrapper_status |= BIT(3);
+	wrapper_status |= BIT(0);
+	dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_CTRL,
+					wrapper_status, rsc->debug_mode);
+	/* make sure that mode-2 is triggered before wait*/
+	wmb();
+
+	/* check for sequence running status before exiting */
+	for (count = MAX_CHECK_LOOPS; count > 0; count--) {
+		if (!regulator_is_enabled(rsc->fs)) {
+			rc = 0;
+			break;
+		}
+		usleep_range(1, 2);
+	}
+
+	if (rc)
+		pr_err("vdd fs is still enabled\n");
+
+end:
+	return rc;
+}
+
+int sde_rsc_mode2_exit(struct sde_rsc_priv *rsc)
+{
+	int rc = -EBUSY;
+	int count, reg;
+
+	// needs review with HPG sequence
+	dss_reg_w(&rsc->wrapper_io, SDE_RSCC_F1_QTMR_V1_CNTP_CVAL_LO,
+					0x0, rsc->debug_mode);
+	dss_reg_w(&rsc->wrapper_io, SDE_RSCC_F1_QTMR_V1_CNTP_CVAL_HI,
+					0x0, rsc->debug_mode);
+
+	reg = dss_reg_r(&rsc->wrapper_io, SDE_RSCC_WRAPPER_CTRL,
+				rsc->debug_mode);
+	reg &= ~BIT(3);
+	dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_CTRL,
+					reg, rsc->debug_mode);
+
+	reg = dss_reg_r(&rsc->wrapper_io, SDE_RSCC_SPARE_PWR_EVENT,
+							rsc->debug_mode);
+	reg |= BIT(13);
+	dss_reg_w(&rsc->wrapper_io, SDE_RSCC_SPARE_PWR_EVENT,
+							reg, rsc->debug_mode);
+
+	/* make sure that mode-2 exit before wait*/
+	wmb();
+
+	/* check for sequence running status before exiting */
+	for (count = MAX_CHECK_LOOPS; count > 0; count--) {
+		if (regulator_is_enabled(rsc->fs)) {
+			rc = 0;
+			break;
+		}
+		usleep_range(1, 2);
+	}
+
+	reg = dss_reg_r(&rsc->wrapper_io, SDE_RSCC_SPARE_PWR_EVENT,
+							rsc->debug_mode);
+	reg &= ~BIT(13);
+	dss_reg_w(&rsc->wrapper_io, SDE_RSCC_SPARE_PWR_EVENT,
+							reg, rsc->debug_mode);
+
+	if (rc)
+		pr_err("vdd reg is not enabled yet\n");
+
+	rc = regulator_set_mode(rsc->fs, REGULATOR_MODE_NORMAL);
+	if (rc)
+		pr_err("vdd reg normal mode set failed rc:%d\n", rc);
+
+	return rc;
+}
+
+static int sde_rsc_state_update(struct sde_rsc_priv *rsc,
+						enum sde_rsc_state state)
+{
+	int rc = 0;
+	int reg;
+
+	if (rsc->power_collapse) {
+		rc = sde_rsc_mode2_exit(rsc);
+		if (rc)
+			pr_err("power collapse: mode2 exit failed\n");
+		else
+			rsc->power_collapse = false;
+	}
+
+	switch (state) {
+	case SDE_RSC_CMD_STATE:
+		pr_debug("command mode handling\n");
+
+		dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_CTRL,
+						0x1, rsc->debug_mode);
+		dss_reg_w(&rsc->drv_io, SDE_RSCC_SOLVER_OVERRIDE_CTRL_DRV0,
+							0x0, rsc->debug_mode);
+		reg = dss_reg_r(&rsc->wrapper_io,
+			SDE_RSCC_WRAPPER_OVERRIDE_CTRL, rsc->debug_mode);
+		reg |= (BIT(0) | BIT(8));
+		reg &= ~(BIT(1) | BIT(2) | BIT(3) | BIT(6) | BIT(7));
+		dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_OVERRIDE_CTRL,
+							reg, rsc->debug_mode);
+		/* make sure that solver is enabled */
+		wmb();
+		break;
+
+	case SDE_RSC_VID_STATE:
+		pr_debug("video mode handling\n");
+
+		dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_CTRL,
+						0x1, rsc->debug_mode);
+		reg = dss_reg_r(&rsc->wrapper_io,
+			SDE_RSCC_WRAPPER_OVERRIDE_CTRL, rsc->debug_mode);
+		reg |= BIT(8);
+		reg &= ~(BIT(1) | BIT(0));
+		dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_OVERRIDE_CTRL,
+							reg, rsc->debug_mode);
+		dss_reg_w(&rsc->drv_io, SDE_RSCC_SOLVER_OVERRIDE_CTRL_DRV0,
+							0x1, rsc->debug_mode);
+		/* make sure that solver mode is override */
+		wmb();
+		break;
+
+	case SDE_RSC_IDLE_STATE:
+		rc = sde_rsc_mode2_entry(rsc);
+		if (rc)
+			pr_err("power collapse - mode 2 entry failed\n");
+		else
+			rsc->power_collapse = true;
+		break;
+
+	default:
+		pr_err("state:%d handling is not supported\n", state);
+		break;
+	}
+
+	return rc;
+}
+
+int rsc_hw_init(struct sde_rsc_priv *rsc)
+{
+	int rc = 0;
+
+	rc = rsc_hw_qtimer_init(rsc);
+	if (rc) {
+		pr_err("rsc hw qtimer init failed\n");
+		goto end;
+	}
+
+	rc = rsc_hw_wrapper_init(rsc);
+	if (rc) {
+		pr_err("rsc hw wrapper init failed\n");
+		goto end;
+	}
+
+	rc = rsc_hw_seq_memory_init(rsc);
+	if (rc) {
+		pr_err("rsc sequencer memory init failed\n");
+		goto end;
+	}
+
+	rc = rsc_hw_solver_init(rsc);
+	if (rc) {
+		pr_err("rsc solver init failed\n");
+		goto end;
+	}
+
+	rc = rsc_hw_pdc_init(rsc);
+	if (rc) {
+		pr_err("rsc hw pdc init failed\n");
+		goto end;
+	}
+
+	/* make sure that hw is initialized */
+	wmb();
+
+	pr_info("sde rsc init successfully done\n");
+end:
+	return rc;
+}
+
+int rsc_hw_mode_ctrl(struct sde_rsc_priv *rsc, enum rsc_mode_req request,
+		char *buffer, int buffer_size, bool mode)
+{
+	u32 blen = 0;
+	u32 slot_time;
+
+	switch (request) {
+	case MODE_READ:
+		if (!buffer || !buffer_size)
+			return blen;
+
+		blen = snprintf(buffer, buffer_size - blen,
+			"mode_status:0x%x\n",
+			dss_reg_r(&rsc->drv_io, SDE_RSCC_SOLVER_STATUS2_DRV0,
+			rsc->debug_mode));
+		break;
+
+	case MODE0_UPDATE:
+		slot_time = mode ? rsc->timer_config.rsc_time_slot_0_ns :
+				rsc->timer_config.rsc_time_slot_2_ns;
+		dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_TIME_SLOT_TABLE_1_DRV0,
+						slot_time, rsc->debug_mode);
+		slot_time = mode ? rsc->timer_config.rsc_time_slot_1_ns :
+				rsc->timer_config.rsc_time_slot_2_ns;
+		dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_TIME_SLOT_TABLE_2_DRV0,
+						slot_time, rsc->debug_mode);
+		rsc->power_collapse_block = mode;
+		break;
+
+	case MODE1_UPDATE:
+		slot_time = mode ? rsc->timer_config.rsc_time_slot_1_ns :
+				rsc->timer_config.rsc_time_slot_2_ns;
+		dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_TIME_SLOT_TABLE_2_DRV0,
+						slot_time, rsc->debug_mode);
+		rsc->power_collapse_block = mode;
+		break;
+
+	case MODE2_UPDATE:
+		rsc->power_collapse_block = mode;
+		break;
+
+	default:
+		break;
+	}
+
+	return blen;
+}
+
+int sde_rsc_debug_show(struct seq_file *s, struct sde_rsc_priv *rsc)
+{
+	seq_printf(s, "override ctrl:0x%x\n",
+		 dss_reg_r(&rsc->wrapper_io, SDE_RSCC_WRAPPER_OVERRIDE_CTRL,
+				rsc->debug_mode));
+	seq_printf(s, "power ctrl:0x%x\n",
+		 dss_reg_r(&rsc->wrapper_io, SDE_RSCC_PWR_CTRL,
+				rsc->debug_mode));
+	seq_printf(s, "vsycn timestamp0:0x%x\n",
+		 dss_reg_r(&rsc->wrapper_io, SDE_RSCC_WRAPPER_VSYNC_TIMESTAMP0,
+				rsc->debug_mode));
+	seq_printf(s, "vsycn timestamp1:0x%x\n",
+		 dss_reg_r(&rsc->wrapper_io, SDE_RSCC_WRAPPER_VSYNC_TIMESTAMP1,
+				rsc->debug_mode));
+
+	seq_printf(s, "error irq status:0x%x\n",
+		 dss_reg_r(&rsc->drv_io, SDE_RSCC_ERROR_IRQ_STATUS_DRV0,
+				rsc->debug_mode));
+
+	seq_printf(s, "seq busy status:0x%x\n",
+		 dss_reg_r(&rsc->drv_io, SDE_RSCC_SEQ_BUSY_DRV0,
+				rsc->debug_mode));
+
+	seq_printf(s, "solver override ctrl status:0x%x\n",
+		 dss_reg_r(&rsc->drv_io, SDE_RSCC_SOLVER_OVERRIDE_CTRL_DRV0,
+				rsc->debug_mode));
+	seq_printf(s, "solver override status:0x%x\n",
+		 dss_reg_r(&rsc->drv_io, SDE_RSCC_SOLVER_STATUS0_DRV0,
+				rsc->debug_mode));
+	seq_printf(s, "solver timeslot status:0x%x\n",
+		 dss_reg_r(&rsc->drv_io, SDE_RSCC_SOLVER_STATUS1_DRV0,
+				rsc->debug_mode));
+	seq_printf(s, "solver mode status:0x%x\n",
+		 dss_reg_r(&rsc->drv_io, SDE_RSCC_SOLVER_STATUS2_DRV0,
+				rsc->debug_mode));
+
+	seq_printf(s, "amc status:0x%x\n",
+		 dss_reg_r(&rsc->drv_io, SDE_RSCC_AMC_TCS_MODE_IRQ_STATUS_DRV0,
+				rsc->debug_mode));
+
+	return 0;
+}
+
+int rsc_hw_vsync(struct sde_rsc_priv *rsc, enum rsc_vsync_req request,
+		char *buffer, int buffer_size, u32 mode)
+{
+	u32 blen = 0, reg;
+
+	switch (request) {
+	case VSYNC_READ:
+		if (!buffer || !buffer_size)
+			return blen;
+
+		blen = snprintf(buffer, buffer_size - blen, "vsync0:0x%x\n",
+			 dss_reg_r(&rsc->drv_io,
+				SDE_RSCC_WRAPPER_VSYNC_TIMESTAMP0,
+				rsc->debug_mode));
+		if (blen >= buffer_size)
+			return blen;
+
+		blen += snprintf(buffer + blen, buffer_size - blen,
+			"vsync1:0x%x\n",
+			 dss_reg_r(&rsc->drv_io,
+				SDE_RSCC_WRAPPER_VSYNC_TIMESTAMP1,
+				rsc->debug_mode));
+		break;
+
+	case VSYNC_ENABLE:
+		reg = BIT(8) | BIT(9) | ((mode & 0x7) < 10);
+		dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_DEBUG_BUS,
+					mode, rsc->debug_mode);
+		break;
+
+	case VSYNC_DISABLE:
+		dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_DEBUG_BUS,
+						0x0, rsc->debug_mode);
+		break;
+	}
+
+	return blen;
+}
+
+bool rsc_hw_is_amc_mode(struct sde_rsc_priv *rsc)
+{
+	return dss_reg_r(&rsc->drv_io, SDE_RSCC_TCS_DRV0_CONTROL,
+			rsc->debug_mode) & BIT(16);
+}
+
+int rsc_hw_tcs_wait(struct sde_rsc_priv *rsc)
+{
+	int rc = -EBUSY;
+	int count, seq_status;
+
+	dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_CTRL,
+						0x0, rsc->debug_mode);
+	seq_status = dss_reg_r(&rsc->wrapper_io, SDE_RSCC_WRAPPER_CTRL,
+			rsc->debug_mode) & BIT(1);
+	/* if seq busy - set TCS use OK to high and wait for 200us */
+	if (seq_status) {
+		dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_CTRL,
+						0x1, rsc->debug_mode);
+		usleep_range(100, 200);
+		dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_CTRL,
+						0x0, rsc->debug_mode);
+	}
+
+	/* check for sequence running status before exiting */
+	for (count = MAX_CHECK_LOOPS; count > 0; count--) {
+		seq_status = dss_reg_r(&rsc->wrapper_io, SDE_RSCC_WRAPPER_CTRL,
+				rsc->debug_mode) & BIT(1);
+		if (!seq_status) {
+			rc = 0;
+			break;
+		}
+		usleep_range(1, 2);
+	}
+
+	return rc;
+}
+
+int rsc_hw_tcs_use_ok(struct sde_rsc_priv *rsc)
+{
+	dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_CTRL,
+						0x1, rsc->debug_mode);
+	return 0;
+}
+
+int sde_rsc_hw_register(struct sde_rsc_priv *rsc)
+{
+	pr_debug("rsc hardware register\n");
+
+	rsc->hw_ops.init = rsc_hw_init;
+
+	rsc->hw_ops.tcs_wait = rsc_hw_tcs_wait;
+	rsc->hw_ops.tcs_use_ok = rsc_hw_tcs_use_ok;
+	rsc->hw_ops.is_amc_mode = rsc_hw_is_amc_mode;
+
+	rsc->hw_ops.mode2_entry = sde_rsc_mode2_entry;
+	rsc->hw_ops.mode2_exit = sde_rsc_mode2_exit;
+
+	rsc->hw_ops.hw_vsync = rsc_hw_vsync;
+	rsc->hw_ops.state_update = sde_rsc_state_update;
+	rsc->hw_ops.debug_show = sde_rsc_debug_show;
+	rsc->hw_ops.mode_ctrl = rsc_hw_mode_ctrl;
+
+	return 0;
+}
diff --git a/drivers/gpu/drm/radeon/radeon_cursor.c b/drivers/gpu/drm/radeon/radeon_cursor.c
index fb16070..4a4f953 100644
--- a/drivers/gpu/drm/radeon/radeon_cursor.c
+++ b/drivers/gpu/drm/radeon/radeon_cursor.c
@@ -205,8 +205,8 @@
 	}
 
 	if (x <= (crtc->x - w) || y <= (crtc->y - radeon_crtc->cursor_height) ||
-	    x >= (crtc->x + crtc->mode.crtc_hdisplay) ||
-	    y >= (crtc->y + crtc->mode.crtc_vdisplay))
+	    x >= (crtc->x + crtc->mode.hdisplay) ||
+	    y >= (crtc->y + crtc->mode.vdisplay))
 		goto out_of_bounds;
 
 	x += xorigin;
diff --git a/drivers/gpu/msm/adreno_a5xx.c b/drivers/gpu/msm/adreno_a5xx.c
index f04baac..8dc97d9 100644
--- a/drivers/gpu/msm/adreno_a5xx.c
+++ b/drivers/gpu/msm/adreno_a5xx.c
@@ -156,6 +156,8 @@
 	{ adreno_is_a530, a530_efuse_leakage },
 	{ adreno_is_a530, a530_efuse_speed_bin },
 	{ adreno_is_a505, a530_efuse_speed_bin },
+	{ adreno_is_a512, a530_efuse_speed_bin },
+	{ adreno_is_a508, a530_efuse_speed_bin },
 };
 
 static void a5xx_check_features(struct adreno_device *adreno_dev)
diff --git a/drivers/gpu/msm/adreno_cp_parser.c b/drivers/gpu/msm/adreno_cp_parser.c
index 2007c10..efc0868 100644
--- a/drivers/gpu/msm/adreno_cp_parser.c
+++ b/drivers/gpu/msm/adreno_cp_parser.c
@@ -53,7 +53,7 @@
 static int adreno_ib_find_objs(struct kgsl_device *device,
 				struct kgsl_process_private *process,
 				uint64_t gpuaddr, uint64_t dwords,
-				int obj_type,
+				uint64_t ib2base, int obj_type,
 				struct adreno_ib_object_list *ib_obj_list,
 				int ib_level);
 
@@ -484,7 +484,7 @@
 		ret = adreno_ib_find_objs(device, process,
 			ib_parse_vars->set_draw_groups[i].cmd_stream_addr,
 			ib_parse_vars->set_draw_groups[i].cmd_stream_dwords,
-			SNAPSHOT_GPU_OBJECT_DRAW,
+			0, SNAPSHOT_GPU_OBJECT_DRAW,
 			ib_obj_list, 2);
 		if (ret)
 			break;
@@ -687,8 +687,8 @@
 			if (cmd_stream_dwords)
 				ret = adreno_ib_find_objs(device, process,
 					cmd_stream_addr, cmd_stream_dwords,
-					SNAPSHOT_GPU_OBJECT_DRAW, ib_obj_list,
-					2);
+					0, SNAPSHOT_GPU_OBJECT_DRAW,
+					ib_obj_list, 2);
 			if (ret)
 				break;
 			continue;
@@ -700,7 +700,7 @@
 			gpuaddr = gpuaddr << 32 | ptr[i + 1];
 			ret = adreno_ib_find_objs(device, process,
 				gpuaddr, (ptr[i] & 0x0000FFFF),
-				SNAPSHOT_GPU_OBJECT_IB,
+				0, SNAPSHOT_GPU_OBJECT_IB,
 				ib_obj_list, 2);
 			if (ret)
 				break;
@@ -763,7 +763,7 @@
 		if (flags & 0x8) {
 			ret = adreno_ib_find_objs(device, process,
 				ptr[i + 1], (ptr[i] & 0x0000FFFF),
-				SNAPSHOT_GPU_OBJECT_IB,
+				0, SNAPSHOT_GPU_OBJECT_IB,
 				ib_obj_list, 2);
 			if (ret)
 				break;
@@ -778,6 +778,7 @@
  * @process: Process in which the IB is allocated
  * @gpuaddr: IB2 gpuaddr
  * @dwords: IB2 size in dwords
+ * @ib2base: Base address of active IB2
  * @ib_obj_list: List of objects found in IB
  * @ib_level: The level from which function is called, either from IB1 or IB2
  *
@@ -786,7 +787,7 @@
  */
 static int adreno_cp_parse_ib2(struct kgsl_device *device,
 			struct kgsl_process_private *process,
-			uint64_t gpuaddr, uint64_t dwords,
+			uint64_t gpuaddr, uint64_t dwords, uint64_t ib2base,
 			struct adreno_ib_object_list *ib_obj_list,
 			int ib_level)
 {
@@ -798,6 +799,10 @@
 	 */
 	if (ib_level == 2)
 		return -EINVAL;
+
+	/* Save current IB2 statically */
+	if (ib2base == gpuaddr)
+		kgsl_snapshot_push_object(process, gpuaddr, dwords);
 	/*
 	 * only try to find sub objects iff this IB has
 	 * not been processed already
@@ -812,7 +817,7 @@
 			return 0;
 	}
 
-	return adreno_ib_find_objs(device, process, gpuaddr, dwords,
+	return adreno_ib_find_objs(device, process, gpuaddr, dwords, ib2base,
 		SNAPSHOT_GPU_OBJECT_IB, ib_obj_list, 2);
 }
 
@@ -821,6 +826,7 @@
  * @device: The device pointer on which the IB executes
  * @process: The process in which the IB and all contained objects are mapped.
  * @gpuaddr: The gpu address of the IB
+ * @ib2base: IB2 base address
  * @dwords: Size of ib in dwords
  * @obj_type: The object type can be either an IB or a draw state sequence
  * @ib_obj_list: The list in which the IB and the objects in it are added.
@@ -833,7 +839,7 @@
 static int adreno_ib_find_objs(struct kgsl_device *device,
 				struct kgsl_process_private *process,
 				uint64_t gpuaddr, uint64_t dwords,
-				int obj_type,
+				uint64_t ib2base, int obj_type,
 				struct adreno_ib_object_list *ib_obj_list,
 				int ib_level)
 {
@@ -909,7 +915,7 @@
 				uint64_t size = src[i + 2];
 
 				ret = adreno_cp_parse_ib2(device, process,
-						gpuaddrib2, size,
+						gpuaddrib2, size, ib2base,
 						ib_obj_list, ib_level);
 				if (ret)
 					goto done;
@@ -936,7 +942,7 @@
 				gpuaddrib2 = gpuaddrib2 << 32 | src[i + 1];
 
 				ret = adreno_cp_parse_ib2(device, process,
-						gpuaddrib2, size,
+						gpuaddrib2, size, ib2base,
 						ib_obj_list, ib_level);
 				if (ret)
 					goto done;
@@ -988,6 +994,7 @@
  * @process: The process in which the IB and all contained objects are mapped
  * @gpuaddr: The gpu address of the IB
  * @dwords: Size of ib in dwords
+ * @ib2base: Base address of active IB2
  * @ib_obj_list: The list in which the IB and the objects in it are added.
  *
  * Find all the memory objects that an IB needs for execution and place
@@ -999,7 +1006,7 @@
  */
 int adreno_ib_create_object_list(struct kgsl_device *device,
 		struct kgsl_process_private *process,
-		uint64_t gpuaddr, uint64_t dwords,
+		uint64_t gpuaddr, uint64_t dwords, uint64_t ib2base,
 		struct adreno_ib_object_list **out_ib_obj_list)
 {
 	int ret = 0;
@@ -1022,7 +1029,7 @@
 		return -ENOMEM;
 	}
 
-	ret = adreno_ib_find_objs(device, process, gpuaddr, dwords,
+	ret = adreno_ib_find_objs(device, process, gpuaddr, dwords, ib2base,
 		SNAPSHOT_GPU_OBJECT_IB, ib_obj_list, 1);
 
 	/* Even if there was an error return the remaining objects found */
diff --git a/drivers/gpu/msm/adreno_cp_parser.h b/drivers/gpu/msm/adreno_cp_parser.h
index cdd983e..1fa46c1 100644
--- a/drivers/gpu/msm/adreno_cp_parser.h
+++ b/drivers/gpu/msm/adreno_cp_parser.h
@@ -179,7 +179,7 @@
 int adreno_ib_create_object_list(
 		struct kgsl_device *device,
 		struct kgsl_process_private *process,
-		uint64_t gpuaddr, uint64_t dwords,
+		uint64_t gpuaddr, uint64_t dwords, uint64_t ib2base,
 		struct adreno_ib_object_list **out_ib_obj_list);
 
 void adreno_ib_destroy_obj_list(struct adreno_ib_object_list *ib_obj_list);
diff --git a/drivers/gpu/msm/adreno_debugfs.c b/drivers/gpu/msm/adreno_debugfs.c
index f6c9805..2d38a1a 100644
--- a/drivers/gpu/msm/adreno_debugfs.c
+++ b/drivers/gpu/msm/adreno_debugfs.c
@@ -167,6 +167,7 @@
  * KGSL_CONTEXT_PRIV_DEVICE_SPECIFIC so it is ok to cross the streams here.
  */
 static const struct flag_entry context_priv[] = {
+	{ KGSL_CONTEXT_PRIV_SUBMITTED, "submitted"},
 	{ KGSL_CONTEXT_PRIV_DETACHED, "detached"},
 	{ KGSL_CONTEXT_PRIV_INVALID, "invalid"},
 	{ KGSL_CONTEXT_PRIV_PAGEFAULT, "pagefault"},
diff --git a/drivers/gpu/msm/adreno_dispatch.c b/drivers/gpu/msm/adreno_dispatch.c
index f6b27f7..3fa38fa 100644
--- a/drivers/gpu/msm/adreno_dispatch.c
+++ b/drivers/gpu/msm/adreno_dispatch.c
@@ -2330,10 +2330,6 @@
 	if (adreno_drawqueue_is_empty(drawqueue))
 		return count;
 
-	/* Don't update the drawqueue timeout if we are about to preempt out */
-	if (!adreno_in_preempt_state(adreno_dev, ADRENO_PREEMPT_NONE))
-		return count;
-
 	/* Don't update the drawqueue timeout if it isn't active */
 	if (!drawqueue_is_current(drawqueue))
 		return count;
diff --git a/drivers/gpu/msm/adreno_drawctxt.c b/drivers/gpu/msm/adreno_drawctxt.c
index cd7ffe7..9f4e185 100644
--- a/drivers/gpu/msm/adreno_drawctxt.c
+++ b/drivers/gpu/msm/adreno_drawctxt.c
@@ -215,10 +215,12 @@
 	int ret = 0;
 
 	/*
-	 * If the context is invalid then return immediately - we may end up
-	 * waiting for a timestamp that will never come
+	 * If the context is invalid (OR) not submitted commands to GPU
+	 * then return immediately - we may end up waiting for a timestamp
+	 * that will never come
 	 */
-	if (kgsl_context_invalid(context))
+	if (kgsl_context_invalid(context) ||
+			!test_bit(KGSL_CONTEXT_PRIV_SUBMITTED, &context->priv))
 		goto done;
 
 	trace_adreno_drawctxt_wait_start(drawctxt->rb->id, context->id,
diff --git a/drivers/gpu/msm/adreno_perfcounter.c b/drivers/gpu/msm/adreno_perfcounter.c
index c81ea69..a7068e1 100644
--- a/drivers/gpu/msm/adreno_perfcounter.c
+++ b/drivers/gpu/msm/adreno_perfcounter.c
@@ -638,6 +638,9 @@
 static void _power_counter_enable_alwayson(struct adreno_device *adreno_dev,
 				struct adreno_perfcounters *counters)
 {
+	if (!ADRENO_FEATURE(adreno_dev, ADRENO_GPMU))
+		return;
+
 	kgsl_regwrite(KGSL_DEVICE(adreno_dev),
 		A5XX_GPMU_ALWAYS_ON_COUNTER_RESET, 1);
 	counters->groups[KGSL_PERFCOUNTER_GROUP_ALWAYSON_PWR].regs[0].value = 0;
@@ -674,6 +677,9 @@
 	struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
 	struct adreno_perfcount_register *reg;
 
+	if (!ADRENO_FEATURE(adreno_dev, ADRENO_GPMU))
+		return;
+
 	reg = &counters->groups[group].regs[counter];
 	kgsl_regwrite(device, reg->select, countable);
 	kgsl_regwrite(device, A5XX_GPMU_POWER_COUNTER_ENABLE, 1);
@@ -927,6 +933,9 @@
 	struct adreno_perfcount_register *reg;
 	unsigned int lo = 0, hi = 0;
 
+	if (!ADRENO_FEATURE(adreno_dev, ADRENO_GPMU))
+		return 0;
+
 	reg = &group->regs[counter];
 
 	kgsl_regread(device, reg->offset, &lo);
diff --git a/drivers/gpu/msm/adreno_ringbuffer.c b/drivers/gpu/msm/adreno_ringbuffer.c
index 2aa9b00..78182b7 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.c
+++ b/drivers/gpu/msm/adreno_ringbuffer.c
@@ -938,6 +938,7 @@
 					drawobj->timestamp, time);
 
 	if (!ret) {
+		set_bit(KGSL_CONTEXT_PRIV_SUBMITTED, &context->priv);
 		cmdobj->global_ts = drawctxt->internal_timestamp;
 
 		/* Put the timevalues in the profiling buffer */
diff --git a/drivers/gpu/msm/adreno_snapshot.c b/drivers/gpu/msm/adreno_snapshot.c
index f17d349..92b541d 100644
--- a/drivers/gpu/msm/adreno_snapshot.c
+++ b/drivers/gpu/msm/adreno_snapshot.c
@@ -27,8 +27,6 @@
 
 #define SNAPSHOT_OBJ_BUFSIZE 64
 
-#define SNAPSHOT_OBJ_TYPE_IB 0
-
 /* Used to print error message if an IB has too many objects in it */
 static int ib_max_objs;
 
@@ -53,8 +51,7 @@
 }
 
 /* Push a new buffer object onto the list */
-static void push_object(int type,
-	struct kgsl_process_private *process,
+void kgsl_snapshot_push_object(struct kgsl_process_private *process,
 	uint64_t gpuaddr, uint64_t dwords)
 {
 	int index;
@@ -101,7 +98,6 @@
 	}
 
 	/* Put it on the list of things to parse */
-	objbuf[objbufptr].type = type;
 	objbuf[objbufptr].gpuaddr = gpuaddr;
 	objbuf[objbufptr].size = dwords << 2;
 	objbuf[objbufptr++].entry = entry;
@@ -112,8 +108,7 @@
  * to be dumped
  */
 
-static int find_object(int type, uint64_t gpuaddr,
-		struct kgsl_process_private *process)
+static int find_object(uint64_t gpuaddr, struct kgsl_process_private *process)
 {
 	int index;
 
@@ -131,14 +126,12 @@
  * @snapshot: The snapshot data.
  * @process: The process to which the IB belongs
  * @ib_obj_list: List of the IB objects
- * @ib2base: IB2 base address at time of the fault
  *
  * Returns 0 on success else error code
  */
 static int snapshot_freeze_obj_list(struct kgsl_snapshot *snapshot,
 		struct kgsl_process_private *process,
-		struct adreno_ib_object_list *ib_obj_list,
-		uint64_t ib2base)
+		struct adreno_ib_object_list *ib_obj_list)
 {
 	int ret = 0;
 	struct adreno_ib_object *ib_objs;
@@ -163,21 +156,15 @@
 		}
 
 		if (freeze) {
-			/* Save current IB2 statically */
-			if (ib2base == ib_objs->gpuaddr) {
-				push_object(SNAPSHOT_OBJ_TYPE_IB,
-				process, ib_objs->gpuaddr, ib_objs->size >> 2);
+			temp_ret = kgsl_snapshot_get_object(snapshot,
+					    process, ib_objs->gpuaddr,
+					    ib_objs->size,
+					    ib_objs->snapshot_obj_type);
+			if (temp_ret < 0) {
+				if (ret >= 0)
+					ret = temp_ret;
 			} else {
-				temp_ret = kgsl_snapshot_get_object(snapshot,
-					process, ib_objs->gpuaddr,
-					ib_objs->size,
-					ib_objs->snapshot_obj_type);
-				if (temp_ret < 0) {
-					if (ret >= 0)
-						ret = temp_ret;
-				} else {
-					snapshot_frozen_objsize += temp_ret;
-				}
+				snapshot_frozen_objsize += temp_ret;
 			}
 		}
 	}
@@ -203,8 +190,7 @@
 	 * list
 	 */
 	if (gpuaddr == snapshot->ib1base) {
-		push_object(SNAPSHOT_OBJ_TYPE_IB, process,
-			gpuaddr, dwords);
+		kgsl_snapshot_push_object(process, gpuaddr, dwords);
 		return;
 	}
 
@@ -213,7 +199,8 @@
 		return;
 
 	if (-E2BIG == adreno_ib_create_object_list(device, process,
-				gpuaddr, dwords, &ib_obj_list))
+				gpuaddr, dwords, snapshot->ib2base,
+				&ib_obj_list))
 		ib_max_objs = 1;
 
 	if (ib_obj_list)
@@ -559,8 +546,7 @@
 	int index = -ENOENT;
 
 	if (!snapshot->ib1dumped)
-		index = find_object(SNAPSHOT_OBJ_TYPE_IB, snapshot->ib1base,
-				snapshot->process);
+		index = find_object(snapshot->ib1base, snapshot->process);
 
 	/* only do this for IB1 because the IB2's are part of IB1 objects */
 	if ((index != -ENOENT) &&
@@ -569,19 +555,19 @@
 					objbuf[index].entry->priv,
 					objbuf[index].gpuaddr,
 					objbuf[index].size >> 2,
+					snapshot->ib2base,
 					&ib_obj_list))
 			ib_max_objs = 1;
 		if (ib_obj_list) {
 			/* freeze the IB objects in the IB */
 			snapshot_freeze_obj_list(snapshot,
 					objbuf[index].entry->priv,
-					ib_obj_list, snapshot->ib2base);
+					ib_obj_list);
 			adreno_ib_destroy_obj_list(ib_obj_list);
 		}
 	} else {
 		/* Get the IB2 index from parsed object */
-		index = find_object(SNAPSHOT_OBJ_TYPE_IB, snapshot->ib2base,
-				snapshot->process);
+		index = find_object(snapshot->ib2base, snapshot->process);
 
 		if (index != -ENOENT)
 			parse_ib(device, snapshot, snapshot->process,
@@ -624,6 +610,7 @@
 	struct adreno_ib_object_list *ib_obj_list;
 	struct kgsl_snapshot *snapshot;
 	struct kgsl_snapshot_object *obj;
+	struct kgsl_memdesc *memdesc;
 
 	if (meta == NULL || meta->snapshot == NULL || meta->obj == NULL) {
 		KGSL_CORE_ERR("snapshot: bad metadata");
@@ -631,13 +618,18 @@
 	}
 	snapshot = meta->snapshot;
 	obj = meta->obj;
+	memdesc = &obj->entry->memdesc;
+
+	/* If size is zero get it from the medesc size */
+	if (!obj->size)
+		obj->size = (memdesc->size - (obj->gpuaddr - memdesc->gpuaddr));
 
 	if (remain < (obj->size + sizeof(*header))) {
 		KGSL_CORE_ERR("snapshot: Not enough memory for the ib\n");
 		return 0;
 	}
 
-	src = kgsl_gpuaddr_to_vaddr(&obj->entry->memdesc, obj->gpuaddr);
+	src = kgsl_gpuaddr_to_vaddr(memdesc, obj->gpuaddr);
 	if (src == NULL) {
 		KGSL_DRV_ERR(device,
 			"snapshot: Unable to map GPU memory object 0x%016llX into the kernel\n",
@@ -653,13 +645,14 @@
 		if (-E2BIG == adreno_ib_create_object_list(device,
 				obj->entry->priv,
 				obj->gpuaddr, obj->size >> 2,
+				snapshot->ib2base,
 				&ib_obj_list))
 			ib_max_objs = 1;
 		if (ib_obj_list) {
 			/* freeze the IB objects in the IB */
 			snapshot_freeze_obj_list(snapshot,
 						obj->entry->priv,
-						ib_obj_list, meta->ib2base);
+						ib_obj_list);
 			adreno_ib_destroy_obj_list(ib_obj_list);
 		}
 	}
@@ -688,26 +681,18 @@
 {
 	struct snapshot_ib_meta meta;
 
-	switch (objbuf[obj].type) {
-	case SNAPSHOT_OBJ_TYPE_IB:
-		meta.snapshot = snapshot;
-		meta.obj = &objbuf[obj];
-		meta.ib1base = snapshot->ib1base;
-		meta.ib1size = snapshot->ib1size;
-		meta.ib2base = snapshot->ib2base;
-		meta.ib2size = snapshot->ib2size;
+	meta.snapshot = snapshot;
+	meta.obj = &objbuf[obj];
+	meta.ib1base = snapshot->ib1base;
+	meta.ib1size = snapshot->ib1size;
+	meta.ib2base = snapshot->ib2base;
+	meta.ib2size = snapshot->ib2size;
 
-		kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_IB_V2,
+	kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_IB_V2,
 			snapshot, snapshot_ib, &meta);
-		if (objbuf[obj].entry) {
-			kgsl_memdesc_unmap(&(objbuf[obj].entry->memdesc));
-			kgsl_mem_entry_put(objbuf[obj].entry);
-		}
-		break;
-	default:
-		KGSL_CORE_ERR("snapshot: Invalid snapshot object type: %d\n",
-			objbuf[obj].type);
-		break;
+	if (objbuf[obj].entry) {
+		kgsl_memdesc_unmap(&(objbuf[obj].entry->memdesc));
+		kgsl_mem_entry_put(objbuf[obj].entry);
 	}
 }
 
@@ -910,10 +895,10 @@
 	 * figure how often this really happens.
 	 */
 
-	if (-ENOENT == find_object(SNAPSHOT_OBJ_TYPE_IB, snapshot->ib1base,
-			snapshot->process) && snapshot->ib1size) {
-		push_object(SNAPSHOT_OBJ_TYPE_IB, snapshot->process,
-			snapshot->ib1base, snapshot->ib1size);
+	if (-ENOENT == find_object(snapshot->ib1base, snapshot->process) &&
+			snapshot->ib1size) {
+		kgsl_snapshot_push_object(snapshot->process, snapshot->ib1base,
+				snapshot->ib1size);
 		KGSL_CORE_ERR(
 		"CP_IB1_BASE not found in the ringbuffer.Dumping %x dwords of the buffer.\n",
 		snapshot->ib1size);
@@ -927,10 +912,9 @@
 	 * correct size.
 	 */
 
-	if (-ENOENT == find_object(SNAPSHOT_OBJ_TYPE_IB, snapshot->ib2base,
-		snapshot->process)) {
-		push_object(SNAPSHOT_OBJ_TYPE_IB, snapshot->process,
-			snapshot->ib2base, snapshot->ib2size);
+	if (-ENOENT == find_object(snapshot->ib2base, snapshot->process)) {
+		kgsl_snapshot_push_object(snapshot->process, snapshot->ib2base,
+				snapshot->ib2size);
 	}
 
 	/*
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index 56eae50..280e660 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -3627,6 +3627,9 @@
 	if (!IS_ALIGNED(offset | size, kgsl_memdesc_get_pagesize(memdesc)))
 		return false;
 
+	if (offset + size < offset)
+		return false;
+
 	if (!(flags & KGSL_SPARSE_BIND_MULTIPLE_TO_PHYS) &&
 			offset + size > memdesc->size)
 		return false;
@@ -3754,7 +3757,7 @@
 			break;
 
 		/* Sanity check initial range */
-		if (obj.size == 0 ||
+		if (obj.size == 0 || obj.virtoffset + obj.size < obj.size ||
 			obj.virtoffset + obj.size > virt_entry->memdesc.size ||
 			!(IS_ALIGNED(obj.virtoffset | obj.size, pg_sz))) {
 			ret = -EINVAL;
diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h
index ae164bc..556809c 100644
--- a/drivers/gpu/msm/kgsl_device.h
+++ b/drivers/gpu/msm/kgsl_device.h
@@ -325,6 +325,7 @@
 
 /**
  * enum bits for struct kgsl_context.priv
+ * @KGSL_CONTEXT_PRIV_SUBMITTED - The context has submitted commands to gpu.
  * @KGSL_CONTEXT_PRIV_DETACHED  - The context has been destroyed by userspace
  *	and is no longer using the gpu.
  * @KGSL_CONTEXT_PRIV_INVALID - The context has been destroyed by the kernel
@@ -334,7 +335,8 @@
  *	reserved for devices specific use.
  */
 enum kgsl_context_priv {
-	KGSL_CONTEXT_PRIV_DETACHED = 0,
+	KGSL_CONTEXT_PRIV_SUBMITTED = 0,
+	KGSL_CONTEXT_PRIV_DETACHED,
 	KGSL_CONTEXT_PRIV_INVALID,
 	KGSL_CONTEXT_PRIV_PAGEFAULT,
 	KGSL_CONTEXT_PRIV_DEVICE_SPECIFIC = 16,
diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c
index eaf0995..b32cb63 100644
--- a/drivers/gpu/msm/kgsl_iommu.c
+++ b/drivers/gpu/msm/kgsl_iommu.c
@@ -813,6 +813,13 @@
 
 	ptname = MMU_FEATURE(mmu, KGSL_MMU_GLOBAL_PAGETABLE) ?
 		KGSL_MMU_GLOBAL_PT : tid;
+	/*
+	 * Trace needs to be logged before searching the faulting
+	 * address in free list as it takes quite long time in
+	 * search and delays the trace unnecessarily.
+	 */
+	trace_kgsl_mmu_pagefault(ctx->kgsldev, addr,
+			ptname, write ? "write" : "read");
 
 	if (test_bit(KGSL_FT_PAGEFAULT_LOG_ONE_PER_PAGE,
 		&adreno_dev->ft_pf_policy))
@@ -849,8 +856,6 @@
 		}
 	}
 
-	trace_kgsl_mmu_pagefault(ctx->kgsldev, addr,
-			ptname, write ? "write" : "read");
 
 	/*
 	 * We do not want the h/w to resume fetching data from an iommu
diff --git a/drivers/gpu/msm/kgsl_pwrscale.c b/drivers/gpu/msm/kgsl_pwrscale.c
index ee38f93b..fc5f5a8 100644
--- a/drivers/gpu/msm/kgsl_pwrscale.c
+++ b/drivers/gpu/msm/kgsl_pwrscale.c
@@ -925,11 +925,15 @@
 			"qcom,enable-midframe-timer")) {
 		kgsl_midframe = kzalloc(
 				sizeof(struct kgsl_midframe_info), GFP_KERNEL);
-		hrtimer_init(&kgsl_midframe->timer,
-				CLOCK_MONOTONIC, HRTIMER_MODE_REL);
-		kgsl_midframe->timer.function =
-				kgsl_pwrscale_midframe_timer;
-		kgsl_midframe->device = device;
+		if (kgsl_midframe) {
+			hrtimer_init(&kgsl_midframe->timer,
+					CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+			kgsl_midframe->timer.function =
+					kgsl_pwrscale_midframe_timer;
+			kgsl_midframe->device = device;
+		} else
+			KGSL_PWR_ERR(device,
+				"Failed to enable-midframe-timer feature\n");
 	}
 
 	/*
diff --git a/drivers/gpu/msm/kgsl_snapshot.c b/drivers/gpu/msm/kgsl_snapshot.c
index 4b1b5bc..40d239c 100644
--- a/drivers/gpu/msm/kgsl_snapshot.c
+++ b/drivers/gpu/msm/kgsl_snapshot.c
@@ -158,8 +158,10 @@
 	header->osid = KGSL_SNAPSHOT_OS_LINUX_V3;
 
 	/* Get the kernel build information */
-	strlcpy(header->release, utsname()->release, sizeof(header->release));
-	strlcpy(header->version, utsname()->version, sizeof(header->version));
+	strlcpy(header->release, init_utsname()->release,
+			sizeof(header->release));
+	strlcpy(header->version, init_utsname()->version,
+			sizeof(header->version));
 
 	/* Get the Unix time for the timestamp */
 	header->seconds = get_seconds();
diff --git a/drivers/gpu/msm/kgsl_snapshot.h b/drivers/gpu/msm/kgsl_snapshot.h
index e2ded87..2cb8b8f 100644
--- a/drivers/gpu/msm/kgsl_snapshot.h
+++ b/drivers/gpu/msm/kgsl_snapshot.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -255,4 +255,6 @@
 	__u64 size;    /* Size of the object (in dwords) */
 } __packed;
 
+void kgsl_snapshot_push_object(struct kgsl_process_private *process,
+	uint64_t gpuaddr, uint64_t dwords);
 #endif
diff --git a/drivers/hv/channel.c b/drivers/hv/channel.c
index 16f91c8..5fb4c6d 100644
--- a/drivers/hv/channel.c
+++ b/drivers/hv/channel.c
@@ -39,7 +39,7 @@
  * vmbus_setevent- Trigger an event notification on the specified
  * channel.
  */
-static void vmbus_setevent(struct vmbus_channel *channel)
+void vmbus_setevent(struct vmbus_channel *channel)
 {
 	struct hv_monitor_page *monitorpage;
 
@@ -65,6 +65,7 @@
 		vmbus_set_event(channel);
 	}
 }
+EXPORT_SYMBOL_GPL(vmbus_setevent);
 
 /*
  * vmbus_open - Open the specified channel.
@@ -635,8 +636,6 @@
 	u32 packetlen_aligned = ALIGN(packetlen, sizeof(u64));
 	struct kvec bufferlist[3];
 	u64 aligned_data = 0;
-	int ret;
-	bool signal = false;
 	bool lock = channel->acquire_ring_lock;
 	int num_vecs = ((bufferlen != 0) ? 3 : 1);
 
@@ -656,33 +655,9 @@
 	bufferlist[2].iov_base = &aligned_data;
 	bufferlist[2].iov_len = (packetlen_aligned - packetlen);
 
-	ret = hv_ringbuffer_write(&channel->outbound, bufferlist, num_vecs,
-				  &signal, lock, channel->signal_policy);
+	return hv_ringbuffer_write(channel, bufferlist, num_vecs,
+				   lock, kick_q);
 
-	/*
-	 * Signalling the host is conditional on many factors:
-	 * 1. The ring state changed from being empty to non-empty.
-	 *    This is tracked by the variable "signal".
-	 * 2. The variable kick_q tracks if more data will be placed
-	 *    on the ring. We will not signal if more data is
-	 *    to be placed.
-	 *
-	 * Based on the channel signal state, we will decide
-	 * which signaling policy will be applied.
-	 *
-	 * If we cannot write to the ring-buffer; signal the host
-	 * even if we may not have written anything. This is a rare
-	 * enough condition that it should not matter.
-	 * NOTE: in this case, the hvsock channel is an exception, because
-	 * it looks the host side's hvsock implementation has a throttling
-	 * mechanism which can hurt the performance otherwise.
-	 */
-
-	if (((ret == 0) && kick_q && signal) ||
-	    (ret && !is_hvsock_channel(channel)))
-		vmbus_setevent(channel);
-
-	return ret;
 }
 EXPORT_SYMBOL(vmbus_sendpacket_ctl);
 
@@ -723,7 +698,6 @@
 				     u32 flags,
 				     bool kick_q)
 {
-	int ret;
 	int i;
 	struct vmbus_channel_packet_page_buffer desc;
 	u32 descsize;
@@ -731,7 +705,6 @@
 	u32 packetlen_aligned;
 	struct kvec bufferlist[3];
 	u64 aligned_data = 0;
-	bool signal = false;
 	bool lock = channel->acquire_ring_lock;
 
 	if (pagecount > MAX_PAGE_BUFFER_COUNT)
@@ -769,29 +742,8 @@
 	bufferlist[2].iov_base = &aligned_data;
 	bufferlist[2].iov_len = (packetlen_aligned - packetlen);
 
-	ret = hv_ringbuffer_write(&channel->outbound, bufferlist, 3,
-				  &signal, lock, channel->signal_policy);
-
-	/*
-	 * Signalling the host is conditional on many factors:
-	 * 1. The ring state changed from being empty to non-empty.
-	 *    This is tracked by the variable "signal".
-	 * 2. The variable kick_q tracks if more data will be placed
-	 *    on the ring. We will not signal if more data is
-	 *    to be placed.
-	 *
-	 * Based on the channel signal state, we will decide
-	 * which signaling policy will be applied.
-	 *
-	 * If we cannot write to the ring-buffer; signal the host
-	 * even if we may not have written anything. This is a rare
-	 * enough condition that it should not matter.
-	 */
-
-	if (((ret == 0) && kick_q && signal) || (ret))
-		vmbus_setevent(channel);
-
-	return ret;
+	return hv_ringbuffer_write(channel, bufferlist, 3,
+				   lock, kick_q);
 }
 EXPORT_SYMBOL_GPL(vmbus_sendpacket_pagebuffer_ctl);
 
@@ -822,12 +774,10 @@
 			      u32 desc_size,
 			      void *buffer, u32 bufferlen, u64 requestid)
 {
-	int ret;
 	u32 packetlen;
 	u32 packetlen_aligned;
 	struct kvec bufferlist[3];
 	u64 aligned_data = 0;
-	bool signal = false;
 	bool lock = channel->acquire_ring_lock;
 
 	packetlen = desc_size + bufferlen;
@@ -848,13 +798,8 @@
 	bufferlist[2].iov_base = &aligned_data;
 	bufferlist[2].iov_len = (packetlen_aligned - packetlen);
 
-	ret = hv_ringbuffer_write(&channel->outbound, bufferlist, 3,
-				  &signal, lock, channel->signal_policy);
-
-	if (ret == 0 && signal)
-		vmbus_setevent(channel);
-
-	return ret;
+	return hv_ringbuffer_write(channel, bufferlist, 3,
+				   lock, true);
 }
 EXPORT_SYMBOL_GPL(vmbus_sendpacket_mpb_desc);
 
@@ -866,14 +811,12 @@
 				struct hv_multipage_buffer *multi_pagebuffer,
 				void *buffer, u32 bufferlen, u64 requestid)
 {
-	int ret;
 	struct vmbus_channel_packet_multipage_buffer desc;
 	u32 descsize;
 	u32 packetlen;
 	u32 packetlen_aligned;
 	struct kvec bufferlist[3];
 	u64 aligned_data = 0;
-	bool signal = false;
 	bool lock = channel->acquire_ring_lock;
 	u32 pfncount = NUM_PAGES_SPANNED(multi_pagebuffer->offset,
 					 multi_pagebuffer->len);
@@ -913,13 +856,8 @@
 	bufferlist[2].iov_base = &aligned_data;
 	bufferlist[2].iov_len = (packetlen_aligned - packetlen);
 
-	ret = hv_ringbuffer_write(&channel->outbound, bufferlist, 3,
-				  &signal, lock, channel->signal_policy);
-
-	if (ret == 0 && signal)
-		vmbus_setevent(channel);
-
-	return ret;
+	return hv_ringbuffer_write(channel, bufferlist, 3,
+				   lock, true);
 }
 EXPORT_SYMBOL_GPL(vmbus_sendpacket_multipagebuffer);
 
@@ -941,16 +879,9 @@
 		   u32 bufferlen, u32 *buffer_actual_len, u64 *requestid,
 		   bool raw)
 {
-	int ret;
-	bool signal = false;
+	return hv_ringbuffer_read(channel, buffer, bufferlen,
+				  buffer_actual_len, requestid, raw);
 
-	ret = hv_ringbuffer_read(&channel->inbound, buffer, bufferlen,
-				 buffer_actual_len, requestid, &signal, raw);
-
-	if (signal)
-		vmbus_setevent(channel);
-
-	return ret;
 }
 
 int vmbus_recvpacket(struct vmbus_channel *channel, void *buffer,
diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c
index 1bc1d479..caf3418 100644
--- a/drivers/hv/channel_mgmt.c
+++ b/drivers/hv/channel_mgmt.c
@@ -449,8 +449,6 @@
 	}
 
 	dev_type = hv_get_dev_type(newchannel);
-	if (dev_type == HV_NIC)
-		set_channel_signal_state(newchannel, HV_SIGNAL_POLICY_EXPLICIT);
 
 	init_vp_index(newchannel, dev_type);
 
diff --git a/drivers/hv/hyperv_vmbus.h b/drivers/hv/hyperv_vmbus.h
index a5b4442..2b13f2a 100644
--- a/drivers/hv/hyperv_vmbus.h
+++ b/drivers/hv/hyperv_vmbus.h
@@ -527,14 +527,14 @@
 
 void hv_ringbuffer_cleanup(struct hv_ring_buffer_info *ring_info);
 
-int hv_ringbuffer_write(struct hv_ring_buffer_info *ring_info,
+int hv_ringbuffer_write(struct vmbus_channel *channel,
 		    struct kvec *kv_list,
-		    u32 kv_count, bool *signal, bool lock,
-		    enum hv_signal_policy policy);
+		    u32 kv_count, bool lock,
+		    bool kick_q);
 
-int hv_ringbuffer_read(struct hv_ring_buffer_info *inring_info,
+int hv_ringbuffer_read(struct vmbus_channel *channel,
 		       void *buffer, u32 buflen, u32 *buffer_actual_len,
-		       u64 *requestid, bool *signal, bool raw);
+		       u64 *requestid, bool raw);
 
 void hv_ringbuffer_get_debuginfo(struct hv_ring_buffer_info *ring_info,
 			    struct hv_ring_buffer_debug_info *debug_info);
diff --git a/drivers/hv/ring_buffer.c b/drivers/hv/ring_buffer.c
index 08043da..308dbda 100644
--- a/drivers/hv/ring_buffer.c
+++ b/drivers/hv/ring_buffer.c
@@ -66,21 +66,25 @@
  *	   once the ring buffer is empty, it will clear the
  *	   interrupt_mask and re-check to see if new data has
  *	   arrived.
+ *
+ * KYS: Oct. 30, 2016:
+ * It looks like Windows hosts have logic to deal with DOS attacks that
+ * can be triggered if it receives interrupts when it is not expecting
+ * the interrupt. The host expects interrupts only when the ring
+ * transitions from empty to non-empty (or full to non full on the guest
+ * to host ring).
+ * So, base the signaling decision solely on the ring state until the
+ * host logic is fixed.
  */
 
-static bool hv_need_to_signal(u32 old_write, struct hv_ring_buffer_info *rbi,
-			      enum hv_signal_policy policy)
+static void hv_signal_on_write(u32 old_write, struct vmbus_channel *channel,
+			       bool kick_q)
 {
+	struct hv_ring_buffer_info *rbi = &channel->outbound;
+
 	virt_mb();
 	if (READ_ONCE(rbi->ring_buffer->interrupt_mask))
-		return false;
-
-	/*
-	 * When the client wants to control signaling,
-	 * we only honour the host interrupt mask.
-	 */
-	if (policy == HV_SIGNAL_POLICY_EXPLICIT)
-		return true;
+		return;
 
 	/* check interrupt_mask before read_index */
 	virt_rmb();
@@ -89,9 +93,9 @@
 	 * ring transitions from being empty to non-empty.
 	 */
 	if (old_write == READ_ONCE(rbi->ring_buffer->read_index))
-		return true;
+		vmbus_setevent(channel);
 
-	return false;
+	return;
 }
 
 /* Get the next write location for the specified ring buffer. */
@@ -280,9 +284,9 @@
 }
 
 /* Write to the ring buffer. */
-int hv_ringbuffer_write(struct hv_ring_buffer_info *outring_info,
-		    struct kvec *kv_list, u32 kv_count, bool *signal, bool lock,
-		    enum hv_signal_policy policy)
+int hv_ringbuffer_write(struct vmbus_channel *channel,
+		    struct kvec *kv_list, u32 kv_count, bool lock,
+		    bool kick_q)
 {
 	int i = 0;
 	u32 bytes_avail_towrite;
@@ -292,6 +296,7 @@
 	u32 old_write;
 	u64 prev_indices = 0;
 	unsigned long flags = 0;
+	struct hv_ring_buffer_info *outring_info = &channel->outbound;
 
 	for (i = 0; i < kv_count; i++)
 		totalbytes_towrite += kv_list[i].iov_len;
@@ -344,13 +349,13 @@
 	if (lock)
 		spin_unlock_irqrestore(&outring_info->ring_lock, flags);
 
-	*signal = hv_need_to_signal(old_write, outring_info, policy);
+	hv_signal_on_write(old_write, channel, kick_q);
 	return 0;
 }
 
-int hv_ringbuffer_read(struct hv_ring_buffer_info *inring_info,
+int hv_ringbuffer_read(struct vmbus_channel *channel,
 		       void *buffer, u32 buflen, u32 *buffer_actual_len,
-		       u64 *requestid, bool *signal, bool raw)
+		       u64 *requestid, bool raw)
 {
 	u32 bytes_avail_toread;
 	u32 next_read_location = 0;
@@ -359,6 +364,7 @@
 	u32 offset;
 	u32 packetlen;
 	int ret = 0;
+	struct hv_ring_buffer_info *inring_info = &channel->inbound;
 
 	if (buflen <= 0)
 		return -EINVAL;
@@ -377,6 +383,7 @@
 		return ret;
 	}
 
+	init_cached_read_index(channel);
 	next_read_location = hv_get_next_read_location(inring_info);
 	next_read_location = hv_copyfrom_ringbuffer(inring_info, &desc,
 						    sizeof(desc),
@@ -416,7 +423,7 @@
 	/* Update the read index */
 	hv_set_next_read_location(inring_info, next_read_location);
 
-	*signal = hv_need_to_signal_on_read(inring_info);
+	hv_signal_on_read(channel);
 
 	return ret;
 }
diff --git a/drivers/hwtracing/coresight/Kconfig b/drivers/hwtracing/coresight/Kconfig
index 7f1ac30..87201c1 100644
--- a/drivers/hwtracing/coresight/Kconfig
+++ b/drivers/hwtracing/coresight/Kconfig
@@ -149,4 +149,12 @@
 	  Hardware Event across STM interface. It configures Coresight
 	  Hardware Event mux control registers to select hardware events
 	  based on user input.
+
+config CORESIGHT_DUMMY
+	bool "Dummy driver support"
+	help
+	  Enables support for dummy driver. Dummy driver can be
+	  used for CoreSight sources/sinks that are owned and configured by some other
+	  subsystem and use Linux drivers to configure rest of trace path.
+
 endif
diff --git a/drivers/hwtracing/coresight/Makefile b/drivers/hwtracing/coresight/Makefile
index 7019968..196c9b6 100644
--- a/drivers/hwtracing/coresight/Makefile
+++ b/drivers/hwtracing/coresight/Makefile
@@ -22,3 +22,4 @@
 obj-$(CONFIG_CORESIGHT_CTI) += coresight-cti.o
 obj-$(CONFIG_CORESIGHT_CSR) += coresight-csr.o
 obj-$(CONFIG_CORESIGHT_HWEVENT) += coresight-hwevent.o
+obj-$(CONFIG_CORESIGHT_SOURCE_DUMMY) += coresight-dummy.o
diff --git a/drivers/hwtracing/coresight/coresight-dummy.c b/drivers/hwtracing/coresight/coresight-dummy.c
new file mode 100644
index 0000000..a0268b4
--- /dev/null
+++ b/drivers/hwtracing/coresight/coresight-dummy.c
@@ -0,0 +1,171 @@
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/coresight.h>
+#include <linux/of.h>
+
+#define DUMMY_TRACE_ID_START	256
+
+struct dummy_drvdata {
+	struct device			*dev;
+	struct coresight_device		*csdev;
+	int				traceid;
+};
+
+static int dummy_source_enable(struct coresight_device *csdev,
+			       struct perf_event *event, u32 mode)
+{
+	struct dummy_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+
+	dev_info(drvdata->dev, "Dummy source enabled\n");
+
+	return 0;
+}
+
+static void dummy_source_disable(struct coresight_device *csdev,
+				 struct perf_event *event)
+{
+	struct dummy_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+
+	dev_info(drvdata->dev, "Dummy source disabled\n");
+}
+
+static int dummy_sink_enable(struct coresight_device *csdev, u32 mode)
+{
+	struct dummy_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+
+	dev_info(drvdata->dev, "Dummy sink enabled\n");
+
+	return 0;
+}
+
+static void dummy_sink_disable(struct coresight_device *csdev)
+{
+	struct dummy_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+
+	dev_info(drvdata->dev, "Dummy sink disabled\n");
+}
+
+static int dummy_trace_id(struct coresight_device *csdev)
+{
+	struct dummy_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+
+	return drvdata->traceid;
+}
+
+static const struct coresight_ops_source dummy_source_ops = {
+	.trace_id	= dummy_trace_id,
+	.enable		= dummy_source_enable,
+	.disable	= dummy_source_disable,
+};
+
+static const struct coresight_ops_sink dummy_sink_ops = {
+	.enable		= dummy_sink_enable,
+	.disable	= dummy_sink_disable,
+};
+
+static const struct coresight_ops dummy_cs_ops = {
+	.source_ops	= &dummy_source_ops,
+	.sink_ops	= &dummy_sink_ops,
+};
+
+static int dummy_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct coresight_platform_data *pdata;
+	struct dummy_drvdata *drvdata;
+	struct coresight_desc *desc;
+	static int traceid = DUMMY_TRACE_ID_START;
+
+	pdata = of_get_coresight_platform_data(dev, pdev->dev.of_node);
+	if (IS_ERR(pdata))
+		return PTR_ERR(pdata);
+	pdev->dev.platform_data = pdata;
+
+	drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
+	if (!drvdata)
+		return -ENOMEM;
+
+	drvdata->dev = &pdev->dev;
+	platform_set_drvdata(pdev, drvdata);
+
+	desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
+	if (!desc)
+		return -ENOMEM;
+
+	drvdata->traceid = traceid++;
+
+	if (of_property_read_bool(pdev->dev.of_node, "qcom,dummy-source")) {
+		desc->type = CORESIGHT_DEV_TYPE_SOURCE;
+		desc->subtype.source_subtype =
+					CORESIGHT_DEV_SUBTYPE_SOURCE_PROC;
+	} else if (of_property_read_bool(pdev->dev.of_node,
+					 "qcom,dummy-sink")) {
+		desc->type = CORESIGHT_DEV_TYPE_SINK;
+		desc->subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_BUFFER;
+	} else {
+		dev_info(dev, "Device type not set.\n");
+		return -EINVAL;
+	}
+
+	desc->ops = &dummy_cs_ops;
+	desc->pdata = pdev->dev.platform_data;
+	desc->dev = &pdev->dev;
+	drvdata->csdev = coresight_register(desc);
+	if (IS_ERR(drvdata->csdev))
+		return PTR_ERR(drvdata->csdev);
+
+	dev_info(dev, "Dummy device initialized\n");
+
+	return 0;
+}
+
+static int dummy_remove(struct platform_device *pdev)
+{
+	struct dummy_drvdata *drvdata = platform_get_drvdata(pdev);
+
+	coresight_unregister(drvdata->csdev);
+	return 0;
+}
+
+static const struct of_device_id dummy_match[] = {
+	{.compatible = "qcom,coresight-dummy"},
+	{}
+};
+
+static struct platform_driver dummy_driver = {
+	.probe	= dummy_probe,
+	.remove	= dummy_remove,
+	.driver	= {
+		.name   = "coresight-dummy",
+		.owner	= THIS_MODULE,
+		.of_match_table = dummy_match,
+	},
+};
+
+int __init dummy_init(void)
+{
+	return platform_driver_register(&dummy_driver);
+}
+module_init(dummy_init);
+
+void __exit dummy_exit(void)
+{
+	platform_driver_unregister(&dummy_driver);
+}
+module_exit(dummy_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("CoreSight dummy source driver");
diff --git a/drivers/hwtracing/coresight/coresight-etm-perf.c b/drivers/hwtracing/coresight/coresight-etm-perf.c
index 2cd7c71..a9cedba 100644
--- a/drivers/hwtracing/coresight/coresight-etm-perf.c
+++ b/drivers/hwtracing/coresight/coresight-etm-perf.c
@@ -120,6 +120,7 @@
 	cpumask_t *mask;
 	struct etm_event_data *event_data;
 	struct coresight_device *sink;
+	struct coresight_device *source;
 
 	event_data = container_of(work, struct etm_event_data, work);
 	mask = &event_data->mask;
@@ -135,8 +136,9 @@
 	}
 
 	for_each_cpu(cpu, mask) {
+		source = coresight_get_source(event_data->path[cpu]);
 		if (!(IS_ERR_OR_NULL(event_data->path[cpu])))
-			coresight_release_path(event_data->path[cpu]);
+			coresight_release_path(source, event_data->path[cpu]);
 	}
 
 	kfree(event_data->path);
diff --git a/drivers/hwtracing/coresight/coresight-priv.h b/drivers/hwtracing/coresight/coresight-priv.h
index aa5538c..3af358a 100644
--- a/drivers/hwtracing/coresight/coresight-priv.h
+++ b/drivers/hwtracing/coresight/coresight-priv.h
@@ -1,4 +1,5 @@
-/* Copyright (c) 2011-2012, 2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2012, 2016-2017, The Linux Foundation.
+ * All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -134,8 +135,10 @@
 void coresight_disable_path(struct list_head *path);
 int coresight_enable_path(struct list_head *path, u32 mode);
 struct coresight_device *coresight_get_sink(struct list_head *path);
+struct coresight_device *coresight_get_source(struct list_head *path);
 struct list_head *coresight_build_path(struct coresight_device *csdev);
-void coresight_release_path(struct list_head *path);
+void coresight_release_path(struct coresight_device *csdev,
+			    struct list_head *path);
 
 #ifdef CONFIG_CORESIGHT_SOURCE_ETM3X
 extern int etm_readl_cp14(u32 off, unsigned int *val);
diff --git a/drivers/hwtracing/coresight/coresight-replicator-qcom.c b/drivers/hwtracing/coresight/coresight-replicator-qcom.c
index 0a3d15f..0bd8b78 100644
--- a/drivers/hwtracing/coresight/coresight-replicator-qcom.c
+++ b/drivers/hwtracing/coresight/coresight-replicator-qcom.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011-2015, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2015, 2017, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -47,6 +47,8 @@
 {
 	struct replicator_state *drvdata = dev_get_drvdata(csdev->dev.parent);
 
+	pm_runtime_get_sync(drvdata->dev);
+
 	CS_UNLOCK(drvdata->base);
 
 	/*
@@ -83,6 +85,7 @@
 
 	CS_LOCK(drvdata->base);
 
+	pm_runtime_put(drvdata->dev);
 	dev_info(drvdata->dev, "REPLICATOR disabled\n");
 }
 
diff --git a/drivers/hwtracing/coresight/coresight-tpdm.c b/drivers/hwtracing/coresight/coresight-tpdm.c
index 95d7a90..1ccf3da 100644
--- a/drivers/hwtracing/coresight/coresight-tpdm.c
+++ b/drivers/hwtracing/coresight/coresight-tpdm.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -655,7 +655,7 @@
 }
 
 static int tpdm_enable(struct coresight_device *csdev,
-		       struct perf_event_attr *attr,  u32 mode)
+		       struct perf_event *event, u32 mode)
 {
 	struct tpdm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
 	int ret;
@@ -731,7 +731,8 @@
 	TPDM_LOCK(drvdata);
 }
 
-static void tpdm_disable(struct coresight_device *csdev)
+static void tpdm_disable(struct coresight_device *csdev,
+			 struct perf_event *event)
 {
 	struct tpdm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
 
diff --git a/drivers/hwtracing/coresight/coresight.c b/drivers/hwtracing/coresight/coresight.c
index 7bf00a0..3a4474d 100644
--- a/drivers/hwtracing/coresight/coresight.c
+++ b/drivers/hwtracing/coresight/coresight.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012, 2017, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -39,19 +39,17 @@
 	struct list_head link;
 };
 
-/*
- * When operating Coresight drivers from the sysFS interface, only a single
- * path can exist from a tracer (associated to a CPU) to a sink.
+/**
+ * struct coresight_path - path from source to sink
+ * @path:	Address of path list.
+ * @link:	hook to the list.
  */
-static DEFINE_PER_CPU(struct list_head *, tracer_path);
+struct coresight_path {
+	struct list_head *path;
+	struct list_head link;
+};
 
-/*
- * As of this writing only a single STM can be found in CS topologies.  Since
- * there is no way to know if we'll ever see more and what kind of
- * configuration they will enact, for the time being only define a single path
- * for STM.
- */
-static struct list_head *stm_path;
+static LIST_HEAD(cs_active_paths);
 
 static int coresight_id_match(struct device *dev, void *data)
 {
@@ -152,6 +150,7 @@
 		if (sink_ops(csdev)->disable) {
 			sink_ops(csdev)->disable(csdev);
 			csdev->enable = false;
+			csdev->activated = false;
 		}
 	}
 }
@@ -353,6 +352,20 @@
 	goto out;
 }
 
+struct coresight_device *coresight_get_source(struct list_head *path)
+{
+	struct coresight_device *csdev;
+
+	if (!path)
+		return NULL;
+
+	csdev = list_first_entry(path, struct coresight_node, link)->csdev;
+	if (csdev->type != CORESIGHT_DEV_TYPE_SOURCE)
+		return NULL;
+
+	return csdev;
+}
+
 struct coresight_device *coresight_get_sink(struct list_head *path)
 {
 	struct coresight_device *csdev;
@@ -446,14 +459,23 @@
  * coresight_release_path - release a previously built path.
  * @path:	the path to release.
  *
+ * Remove coresight path entry from source device
  * Go through all the elements of a path and 1) removed it from the list and
  * 2) free the memory allocated for each node.
  */
-void coresight_release_path(struct list_head *path)
+void coresight_release_path(struct coresight_device *csdev,
+			    struct list_head *path)
 {
-	struct coresight_device *csdev;
 	struct coresight_node *nd, *next;
 
+	if (csdev != NULL && csdev->node != NULL) {
+		/* Remove path entry from source device */
+		list_del(&csdev->node->link);
+		kfree(csdev->node);
+		csdev->node = NULL;
+	}
+
+	/* Free the path */
 	list_for_each_entry_safe(nd, next, path, link) {
 		csdev = nd->csdev;
 
@@ -494,9 +516,25 @@
 	return 0;
 }
 
+int coresight_store_path(struct coresight_device *csdev, struct list_head *path)
+{
+	struct coresight_path *node;
+
+	node = kzalloc(sizeof(struct coresight_path), GFP_KERNEL);
+	if (!node)
+		return -ENOMEM;
+
+	node->path = path;
+	list_add(&node->link, &cs_active_paths);
+
+	csdev->node = node;
+
+	return 0;
+}
+
 int coresight_enable(struct coresight_device *csdev)
 {
-	int cpu, ret = 0;
+	int ret = 0;
 	struct list_head *path;
 
 	mutex_lock(&coresight_mutex);
@@ -523,25 +561,9 @@
 	if (ret)
 		goto err_source;
 
-	switch (csdev->subtype.source_subtype) {
-	case CORESIGHT_DEV_SUBTYPE_SOURCE_PROC:
-		/*
-		 * When working from sysFS it is important to keep track
-		 * of the paths that were created so that they can be
-		 * undone in 'coresight_disable()'.  Since there can only
-		 * be a single session per tracer (when working from sysFS)
-		 * a per-cpu variable will do just fine.
-		 */
-		cpu = source_ops(csdev)->cpu_id(csdev);
-		per_cpu(tracer_path, cpu) = path;
-		break;
-	case CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE:
-		stm_path = path;
-		break;
-	default:
-		/* We can't be here */
-		break;
-	}
+	ret = coresight_store_path(csdev, path);
+	if (ret)
+		goto err_source;
 
 out:
 	mutex_unlock(&coresight_mutex);
@@ -551,15 +573,14 @@
 	coresight_disable_path(path);
 
 err_path:
-	coresight_release_path(path);
+	coresight_release_path(csdev, path);
 	goto out;
 }
 EXPORT_SYMBOL_GPL(coresight_enable);
 
 void coresight_disable(struct coresight_device *csdev)
 {
-	int cpu, ret;
-	struct list_head *path = NULL;
+	int  ret;
 
 	mutex_lock(&coresight_mutex);
 
@@ -570,24 +591,12 @@
 	if (!csdev->enable)
 		goto out;
 
-	switch (csdev->subtype.source_subtype) {
-	case CORESIGHT_DEV_SUBTYPE_SOURCE_PROC:
-		cpu = source_ops(csdev)->cpu_id(csdev);
-		path = per_cpu(tracer_path, cpu);
-		per_cpu(tracer_path, cpu) = NULL;
-		break;
-	case CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE:
-		path = stm_path;
-		stm_path = NULL;
-		break;
-	default:
-		/* We can't be here */
-		break;
-	}
+	if (csdev->node == NULL)
+		goto out;
 
 	coresight_disable_source(csdev);
-	coresight_disable_path(path);
-	coresight_release_path(path);
+	coresight_disable_path(csdev->node->path);
+	coresight_release_path(csdev, csdev->node->path);
 
 out:
 	mutex_unlock(&coresight_mutex);
@@ -876,8 +885,42 @@
 	return -EAGAIN;
 }
 
+static ssize_t reset_source_sink_store(struct bus_type *bus,
+				       const char *buf, size_t size)
+{
+	int ret = 0;
+	unsigned long val;
+	struct coresight_path *cspath = NULL;
+	struct coresight_path *cspath_next = NULL;
+	struct coresight_device *csdev;
+
+	ret = kstrtoul(buf, 10, &val);
+	if (ret)
+		return ret;
+
+	mutex_lock(&coresight_mutex);
+
+	list_for_each_entry_safe(cspath, cspath_next, &cs_active_paths, link) {
+		csdev = coresight_get_source(cspath->path);
+		if (!csdev)
+			continue;
+		coresight_disable(csdev);
+	}
+
+	mutex_unlock(&coresight_mutex);
+	return size;
+}
+static BUS_ATTR_WO(reset_source_sink);
+
+static struct attribute *coresight_reset_source_sink_attrs[] = {
+	&bus_attr_reset_source_sink.attr,
+	NULL,
+};
+ATTRIBUTE_GROUPS(coresight_reset_source_sink);
+
 struct bus_type coresight_bustype = {
-	.name	= "coresight",
+	.name		= "coresight",
+	.bus_groups	= coresight_reset_source_sink_groups,
 };
 
 static int __init coresight_init(void)
diff --git a/drivers/i2c/busses/i2c-designware-core.c b/drivers/i2c/busses/i2c-designware-core.c
index b403fa5..809f4d4 100644
--- a/drivers/i2c/busses/i2c-designware-core.c
+++ b/drivers/i2c/busses/i2c-designware-core.c
@@ -475,30 +475,28 @@
 static void i2c_dw_xfer_init(struct dw_i2c_dev *dev)
 {
 	struct i2c_msg *msgs = dev->msgs;
-	u32 ic_tar = 0;
+	u32 ic_con, ic_tar = 0;
 
 	/* Disable the adapter */
 	__i2c_dw_enable_and_wait(dev, false);
 
 	/* if the slave address is ten bit address, enable 10BITADDR */
-	if (dev->dynamic_tar_update_enabled) {
+	ic_con = dw_readl(dev, DW_IC_CON);
+	if (msgs[dev->msg_write_idx].flags & I2C_M_TEN) {
+		ic_con |= DW_IC_CON_10BITADDR_MASTER;
 		/*
 		 * If I2C_DYNAMIC_TAR_UPDATE is set, the 10-bit addressing
-		 * mode has to be enabled via bit 12 of IC_TAR register,
-		 * otherwise bit 4 of IC_CON is used.
+		 * mode has to be enabled via bit 12 of IC_TAR register.
+		 * We set it always as I2C_DYNAMIC_TAR_UPDATE can't be
+		 * detected from registers.
 		 */
-		if (msgs[dev->msg_write_idx].flags & I2C_M_TEN)
-			ic_tar = DW_IC_TAR_10BITADDR_MASTER;
+		ic_tar = DW_IC_TAR_10BITADDR_MASTER;
 	} else {
-		u32 ic_con = dw_readl(dev, DW_IC_CON);
-
-		if (msgs[dev->msg_write_idx].flags & I2C_M_TEN)
-			ic_con |= DW_IC_CON_10BITADDR_MASTER;
-		else
-			ic_con &= ~DW_IC_CON_10BITADDR_MASTER;
-		dw_writel(dev, ic_con, DW_IC_CON);
+		ic_con &= ~DW_IC_CON_10BITADDR_MASTER;
 	}
 
+	dw_writel(dev, ic_con, DW_IC_CON);
+
 	/*
 	 * Set the slave (target) address and enable 10-bit addressing mode
 	 * if applicable.
@@ -923,7 +921,6 @@
 {
 	struct i2c_adapter *adap = &dev->adapter;
 	int r;
-	u32 reg;
 
 	init_completion(&dev->cmd_complete);
 
@@ -931,26 +928,6 @@
 	if (r)
 		return r;
 
-	r = i2c_dw_acquire_lock(dev);
-	if (r)
-		return r;
-
-	/*
-	 * Test if dynamic TAR update is enabled in this controller by writing
-	 * to IC_10BITADDR_MASTER field in IC_CON: when it is enabled this
-	 * field is read-only so it should not succeed
-	 */
-	reg = dw_readl(dev, DW_IC_CON);
-	dw_writel(dev, reg ^ DW_IC_CON_10BITADDR_MASTER, DW_IC_CON);
-
-	if ((dw_readl(dev, DW_IC_CON) & DW_IC_CON_10BITADDR_MASTER) ==
-	    (reg & DW_IC_CON_10BITADDR_MASTER)) {
-		dev->dynamic_tar_update_enabled = true;
-		dev_dbg(dev->dev, "Dynamic TAR update enabled");
-	}
-
-	i2c_dw_release_lock(dev);
-
 	snprintf(adap->name, sizeof(adap->name),
 		 "Synopsys DesignWare I2C adapter");
 	adap->retries = 3;
diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h
index 0d44d2a..22bfbe1 100644
--- a/drivers/i2c/busses/i2c-designware-core.h
+++ b/drivers/i2c/busses/i2c-designware-core.h
@@ -117,7 +117,6 @@
 	int			(*acquire_lock)(struct dw_i2c_dev *dev);
 	void			(*release_lock)(struct dw_i2c_dev *dev);
 	bool			pm_runtime_disabled;
-	bool			dynamic_tar_update_enabled;
 };
 
 #define ACCESS_SWAP		0x00000001
diff --git a/drivers/infiniband/sw/rxe/rxe_mr.c b/drivers/infiniband/sw/rxe/rxe_mr.c
index 1869152..9b732c5 100644
--- a/drivers/infiniband/sw/rxe/rxe_mr.c
+++ b/drivers/infiniband/sw/rxe/rxe_mr.c
@@ -59,9 +59,11 @@
 
 	case RXE_MEM_TYPE_MR:
 	case RXE_MEM_TYPE_FMR:
-		return ((iova < mem->iova) ||
-			((iova + length) > (mem->iova + mem->length))) ?
-			-EFAULT : 0;
+		if (iova < mem->iova ||
+		    length > mem->length ||
+		    iova > mem->iova + mem->length - length)
+			return -EFAULT;
+		return 0;
 
 	default:
 		return -EFAULT;
diff --git a/drivers/infiniband/sw/rxe/rxe_resp.c b/drivers/infiniband/sw/rxe/rxe_resp.c
index dd3d88a..ccf6247 100644
--- a/drivers/infiniband/sw/rxe/rxe_resp.c
+++ b/drivers/infiniband/sw/rxe/rxe_resp.c
@@ -472,7 +472,7 @@
 				goto err2;
 			}
 
-			resid = mtu;
+			qp->resp.resid = mtu;
 		} else {
 			if (pktlen != resid) {
 				state = RESPST_ERR_LENGTH;
diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c
index 92595b9..022be0e 100644
--- a/drivers/input/misc/uinput.c
+++ b/drivers/input/misc/uinput.c
@@ -263,13 +263,21 @@
 		return -EINVAL;
 	}
 
-	if (test_bit(ABS_MT_SLOT, dev->absbit)) {
-		nslot = input_abs_get_max(dev, ABS_MT_SLOT) + 1;
-		error = input_mt_init_slots(dev, nslot, 0);
-		if (error)
+	if (test_bit(EV_ABS, dev->evbit)) {
+		input_alloc_absinfo(dev);
+		if (!dev->absinfo) {
+			error = -EINVAL;
 			goto fail1;
-	} else if (test_bit(ABS_MT_POSITION_X, dev->absbit)) {
-		input_set_events_per_packet(dev, 60);
+		}
+
+		if (test_bit(ABS_MT_SLOT, dev->absbit)) {
+			nslot = input_abs_get_max(dev, ABS_MT_SLOT) + 1;
+			error = input_mt_init_slots(dev, nslot, 0);
+			if (error)
+				goto fail1;
+		} else if (test_bit(ABS_MT_POSITION_X, dev->absbit)) {
+			input_set_events_per_packet(dev, 60);
+		}
 	}
 
 	if (test_bit(EV_FF, dev->evbit) && !udev->ff_effects_max) {
diff --git a/drivers/input/mouse/elan_i2c_core.c b/drivers/input/mouse/elan_i2c_core.c
index d15b338..ed1935f 100644
--- a/drivers/input/mouse/elan_i2c_core.c
+++ b/drivers/input/mouse/elan_i2c_core.c
@@ -1232,6 +1232,7 @@
 	{ "ELAN0000", 0 },
 	{ "ELAN0100", 0 },
 	{ "ELAN0600", 0 },
+	{ "ELAN0605", 0 },
 	{ "ELAN1000", 0 },
 	{ }
 };
diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index 4d6ee1b..c704c47 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -635,7 +635,7 @@
 	__be32 pci_sid;
 	int err = 0;
 
-	memset(&it, sizeof(it), 0);
+	memset(&it, 0, sizeof(it));
 	np = dev_get_dev_node(dev);
 	if (!np || !of_find_property(np, "#stream-id-cells", NULL)) {
 		of_node_put(np);
diff --git a/drivers/mailbox/qti-tcs.c b/drivers/mailbox/qti-tcs.c
index acf14d8..bcd5fb9 100644
--- a/drivers/mailbox/qti-tcs.c
+++ b/drivers/mailbox/qti-tcs.c
@@ -79,7 +79,6 @@
 
 /* Control/Hidden TCS */
 #define TCS_HIDDEN_MAX_SLOTS		3
-#define TCS_HIDDEN_CMD0_DRV_ADDR	0x34
 #define TCS_HIDDEN_CMD0_DRV_DATA	0x38
 #define TCS_HIDDEN_CMD_SHIFT		0x08
 
@@ -830,15 +829,12 @@
 static void __tcs_write_hidden(void *base, int d, struct tcs_mbox_msg *msg)
 {
 	int i;
-	void __iomem *addr;
-	const u32 offset = TCS_HIDDEN_CMD0_DRV_DATA - TCS_HIDDEN_CMD0_DRV_ADDR;
+	void __iomem *addr = base + TCS_HIDDEN_CMD0_DRV_DATA;
 
-	addr = base + TCS_HIDDEN_CMD0_DRV_ADDR;
 	for (i = 0; i < msg->num_payload; i++) {
 		/* Only data is write capable */
-		writel_relaxed(cpu_to_le32(msg->payload[i].data),
-							addr + offset);
-		trace_rpmh_control_msg(addr + offset, msg->payload[i].data);
+		writel_relaxed(cpu_to_le32(msg->payload[i].data), addr);
+		trace_rpmh_control_msg(addr, msg->payload[i].data);
 		addr += TCS_HIDDEN_CMD_SHIFT;
 	}
 }
@@ -899,11 +895,6 @@
 		goto tx_done;
 	}
 
-	if (msg->is_complete) {
-		dev_err(dev, "Incorrect ctrl request.\n");
-		goto tx_done;
-	}
-
 	/* Post the message to the TCS without trigger */
 	ret = tcs_mbox_write(chan, msg, false);
 
diff --git a/drivers/md/bcache/bcache.h b/drivers/md/bcache/bcache.h
index 6b420a5..c3ea03c 100644
--- a/drivers/md/bcache/bcache.h
+++ b/drivers/md/bcache/bcache.h
@@ -425,7 +425,7 @@
 	 * until a gc finishes - otherwise we could pointlessly burn a ton of
 	 * cpu
 	 */
-	unsigned		invalidate_needs_gc:1;
+	unsigned		invalidate_needs_gc;
 
 	bool			discard; /* Get rid of? */
 
@@ -593,8 +593,8 @@
 
 	/* Counts how many sectors bio_insert has added to the cache */
 	atomic_t		sectors_to_gc;
+	wait_queue_head_t	gc_wait;
 
-	wait_queue_head_t	moving_gc_wait;
 	struct keybuf		moving_gc_keys;
 	/* Number of moving GC bios in flight */
 	struct semaphore	moving_in_flight;
diff --git a/drivers/md/bcache/btree.c b/drivers/md/bcache/btree.c
index 81d3db4..2efdce0 100644
--- a/drivers/md/bcache/btree.c
+++ b/drivers/md/bcache/btree.c
@@ -1757,32 +1757,34 @@
 	bch_moving_gc(c);
 }
 
-static int bch_gc_thread(void *arg)
+static bool gc_should_run(struct cache_set *c)
 {
-	struct cache_set *c = arg;
 	struct cache *ca;
 	unsigned i;
 
-	while (1) {
-again:
-		bch_btree_gc(c);
+	for_each_cache(ca, c, i)
+		if (ca->invalidate_needs_gc)
+			return true;
 
-		set_current_state(TASK_INTERRUPTIBLE);
+	if (atomic_read(&c->sectors_to_gc) < 0)
+		return true;
+
+	return false;
+}
+
+static int bch_gc_thread(void *arg)
+{
+	struct cache_set *c = arg;
+
+	while (1) {
+		wait_event_interruptible(c->gc_wait,
+			   kthread_should_stop() || gc_should_run(c));
+
 		if (kthread_should_stop())
 			break;
 
-		mutex_lock(&c->bucket_lock);
-
-		for_each_cache(ca, c, i)
-			if (ca->invalidate_needs_gc) {
-				mutex_unlock(&c->bucket_lock);
-				set_current_state(TASK_RUNNING);
-				goto again;
-			}
-
-		mutex_unlock(&c->bucket_lock);
-
-		schedule();
+		set_gc_sectors(c);
+		bch_btree_gc(c);
 	}
 
 	return 0;
@@ -1790,11 +1792,10 @@
 
 int bch_gc_thread_start(struct cache_set *c)
 {
-	c->gc_thread = kthread_create(bch_gc_thread, c, "bcache_gc");
+	c->gc_thread = kthread_run(bch_gc_thread, c, "bcache_gc");
 	if (IS_ERR(c->gc_thread))
 		return PTR_ERR(c->gc_thread);
 
-	set_task_state(c->gc_thread, TASK_INTERRUPTIBLE);
 	return 0;
 }
 
diff --git a/drivers/md/bcache/btree.h b/drivers/md/bcache/btree.h
index 5c391fa..9b80417 100644
--- a/drivers/md/bcache/btree.h
+++ b/drivers/md/bcache/btree.h
@@ -260,8 +260,7 @@
 
 static inline void wake_up_gc(struct cache_set *c)
 {
-	if (c->gc_thread)
-		wake_up_process(c->gc_thread);
+	wake_up(&c->gc_wait);
 }
 
 #define MAP_DONE	0
diff --git a/drivers/md/bcache/request.c b/drivers/md/bcache/request.c
index 40ffe5e..a37c177 100644
--- a/drivers/md/bcache/request.c
+++ b/drivers/md/bcache/request.c
@@ -196,10 +196,8 @@
 	struct data_insert_op *op = container_of(cl, struct data_insert_op, cl);
 	struct bio *bio = op->bio, *n;
 
-	if (atomic_sub_return(bio_sectors(bio), &op->c->sectors_to_gc) < 0) {
-		set_gc_sectors(op->c);
+	if (atomic_sub_return(bio_sectors(bio), &op->c->sectors_to_gc) < 0)
 		wake_up_gc(op->c);
-	}
 
 	if (op->bypass)
 		return bch_data_invalidate(cl);
diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c
index 849ad44..66669c8 100644
--- a/drivers/md/bcache/super.c
+++ b/drivers/md/bcache/super.c
@@ -1491,6 +1491,7 @@
 	mutex_init(&c->bucket_lock);
 	init_waitqueue_head(&c->btree_cache_wait);
 	init_waitqueue_head(&c->bucket_wait);
+	init_waitqueue_head(&c->gc_wait);
 	sema_init(&c->uuid_write_mutex, 1);
 
 	spin_lock_init(&c->btree_gc_time.lock);
@@ -1550,6 +1551,7 @@
 
 	for_each_cache(ca, c, i)
 		c->nbuckets += ca->sb.nbuckets;
+	set_gc_sectors(c);
 
 	if (CACHE_SYNC(&c->sb)) {
 		LIST_HEAD(journal);
diff --git a/drivers/md/dm-rq.c b/drivers/md/dm-rq.c
index 31a89c8..2c96542 100644
--- a/drivers/md/dm-rq.c
+++ b/drivers/md/dm-rq.c
@@ -804,6 +804,10 @@
 		int srcu_idx;
 		struct dm_table *map = dm_get_live_table(md, &srcu_idx);
 
+		if (unlikely(!map)) {
+			dm_put_live_table(md, srcu_idx);
+			return;
+		}
 		ti = dm_table_find_target(map, pos);
 		dm_put_live_table(md, srcu_idx);
 	}
diff --git a/drivers/media/platform/msm/vidc/msm_vdec.c b/drivers/media/platform/msm/vidc/msm_vdec.c
index bf0148c..68848a8 100644
--- a/drivers/media/platform/msm/vidc/msm_vdec.c
+++ b/drivers/media/platform/msm/vidc/msm_vdec.c
@@ -504,6 +504,7 @@
 		.num_planes = 1,
 		.get_frame_size = get_frame_size_compressed,
 		.type = OUTPUT_PORT,
+		.defer_outputs = false,
 	},
 	{
 		.name = "Mpeg2",
@@ -512,6 +513,7 @@
 		.num_planes = 1,
 		.get_frame_size = get_frame_size_compressed,
 		.type = OUTPUT_PORT,
+		.defer_outputs = false,
 	},
 	{
 		.name = "H263",
@@ -520,6 +522,7 @@
 		.num_planes = 1,
 		.get_frame_size = get_frame_size_compressed,
 		.type = OUTPUT_PORT,
+		.defer_outputs = false,
 	},
 	{
 		.name = "VC1",
@@ -528,6 +531,7 @@
 		.num_planes = 1,
 		.get_frame_size = get_frame_size_compressed,
 		.type = OUTPUT_PORT,
+		.defer_outputs = false,
 	},
 	{
 		.name = "VC1 SP",
@@ -536,6 +540,7 @@
 		.num_planes = 1,
 		.get_frame_size = get_frame_size_compressed,
 		.type = OUTPUT_PORT,
+		.defer_outputs = false,
 	},
 	{
 		.name = "H264",
@@ -544,6 +549,7 @@
 		.num_planes = 1,
 		.get_frame_size = get_frame_size_compressed,
 		.type = OUTPUT_PORT,
+		.defer_outputs = false,
 	},
 	{
 		.name = "H264_MVC",
@@ -552,6 +558,7 @@
 		.num_planes = 1,
 		.get_frame_size = get_frame_size_compressed,
 		.type = OUTPUT_PORT,
+		.defer_outputs = false,
 	},
 	{
 		.name = "HEVC",
@@ -560,6 +567,7 @@
 		.num_planes = 1,
 		.get_frame_size = get_frame_size_compressed,
 		.type = OUTPUT_PORT,
+		.defer_outputs = false,
 	},
 	{
 		.name = "VP8",
@@ -568,6 +576,7 @@
 		.num_planes = 1,
 		.get_frame_size = get_frame_size_compressed,
 		.type = OUTPUT_PORT,
+		.defer_outputs = false,
 	},
 	{
 		.name = "VP9",
@@ -576,6 +585,7 @@
 		.num_planes = 1,
 		.get_frame_size = get_frame_size_compressed_full_yuv,
 		.type = OUTPUT_PORT,
+		.defer_outputs = true,
 	},
 };
 
@@ -1767,7 +1777,7 @@
 			case V4L2_MPEG_VIDC_VIDEO_DPB_COLOR_FMT_NONE:
 				if (!msm_comm_g_ctrl_for_id(inst, control.id)) {
 					rc = msm_comm_release_output_buffers(
-						inst);
+						inst, false);
 					if (rc)
 						dprintk(VIDC_ERR,
 							"%s Release output buffers failed\n",
diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c
index 1b93ee9..4a1fd76 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc.c
@@ -1041,6 +1041,7 @@
 	q->mem_ops = &msm_vidc_vb2_mem_ops;
 	q->drv_priv = inst;
 	q->allow_zero_bytesused = 1;
+	q->copy_timestamp = 1;
 	return vb2_queue_init(q);
 }
 
@@ -1387,7 +1388,13 @@
 				"Failed to release persist buffers\n");
 		}
 
-		if (msm_comm_release_output_buffers(inst)) {
+		/*
+		 * At this point all buffes should be with driver
+		 * irrespective of scenario
+		 */
+		msm_comm_validate_output_buffers(inst);
+
+		if (msm_comm_release_output_buffers(inst, true)) {
 			dprintk(VIDC_ERR,
 				"Failed to release output buffers\n");
 		}
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index a134364..00feba6 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -1414,7 +1414,7 @@
 	put_inst(inst);
 }
 
-void validate_output_buffers(struct msm_vidc_inst *inst)
+void msm_comm_validate_output_buffers(struct msm_vidc_inst *inst)
 {
 	struct internal_buf *binfo;
 	u32 buffers_owned_by_driver = 0;
@@ -1440,11 +1440,13 @@
 	}
 	mutex_unlock(&inst->outputbufs.lock);
 
-	if (buffers_owned_by_driver != output_buf->buffer_count_actual)
+	if (buffers_owned_by_driver != output_buf->buffer_count_actual) {
 		dprintk(VIDC_WARN,
 			"OUTPUT Buffer count mismatch %d of %d\n",
 			buffers_owned_by_driver,
 			output_buf->buffer_count_actual);
+		msm_vidc_handle_hw_error(inst->core);
+	}
 }
 
 int msm_comm_queue_output_buffers(struct msm_vidc_inst *inst)
@@ -1524,7 +1526,11 @@
 
 	if (msm_comm_get_stream_output_mode(inst) ==
 			HAL_VIDEO_DECODER_SECONDARY) {
-		validate_output_buffers(inst);
+
+		if (!(inst->fmts[OUTPUT_PORT].defer_outputs &&
+				inst->in_reconfig))
+			msm_comm_validate_output_buffers(inst);
+
 		if (!inst->in_reconfig) {
 			rc = msm_comm_queue_output_buffers(inst);
 			if (rc) {
@@ -2012,7 +2018,7 @@
 	struct vidc_hal_fbd *fill_buf_done;
 	enum hal_buffer buffer_type;
 	int extra_idx = 0;
-	int64_t time_usec = 0;
+	u64 time_nsec = 0;
 	struct vb2_v4l2_buffer *vbuf = NULL;
 
 	if (!response) {
@@ -2057,11 +2063,11 @@
 				vb->planes[0].length);
 		if (!(fill_buf_done->flags1 &
 			HAL_BUFFERFLAG_TIMESTAMPINVALID)) {
-			time_usec = fill_buf_done->timestamp_hi;
-			time_usec = (time_usec << 32) |
+			time_nsec = fill_buf_done->timestamp_hi;
+			time_nsec = (time_nsec << 32) |
 				fill_buf_done->timestamp_lo;
 		} else {
-			time_usec = 0;
+			time_nsec = 0;
 			dprintk(VIDC_DBG,
 					"Set zero timestamp for buffer %pa, filled: %d, (hi:%u, lo:%u)\n",
 					&fill_buf_done->packet_buffer1,
@@ -2070,8 +2076,8 @@
 					fill_buf_done->timestamp_lo);
 		}
 		vbuf->flags = 0;
-//		vb->timestamp = (u64)
-//			ns_to_timeval(time_usec * NSEC_PER_USEC);
+		vb->timestamp = time_nsec;
+
 		extra_idx =
 			EXTRADATA_IDX(inst->fmts[CAPTURE_PORT].num_planes);
 		if (extra_idx && extra_idx < VIDEO_MAX_PLANES) {
@@ -2135,7 +2141,7 @@
 		dprintk(VIDC_DBG,
 		"Got fbd from hal: device_addr: %pa, alloc: %d, filled: %d, offset: %d, ts: %lld, flags: %#x, crop: %d %d %d %d, pic_type: %#x, mark_data: %#x\n",
 		&fill_buf_done->packet_buffer1, fill_buf_done->alloc_len1,
-		fill_buf_done->filled_len1, fill_buf_done->offset1, time_usec,
+		fill_buf_done->filled_len1, fill_buf_done->offset1, time_nsec,
 		fill_buf_done->flags1, fill_buf_done->start_x_coord,
 		fill_buf_done->start_y_coord, fill_buf_done->frame_width,
 		fill_buf_done->frame_height, fill_buf_done->picture_type,
@@ -3583,18 +3589,15 @@
 static void populate_frame_data(struct vidc_frame_data *data,
 		const struct vb2_buffer *vb, struct msm_vidc_inst *inst)
 {
-	int64_t time_usec = 0;
 	int extra_idx;
 	enum v4l2_buf_type type = vb->type;
 	enum vidc_ports port = type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE ?
 		OUTPUT_PORT : CAPTURE_PORT;
 	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
 
-	do_div(time_usec, NSEC_PER_USEC);
-
 	data->alloc_len = vb->planes[0].length;
 	data->device_addr = vb->planes[0].m.userptr;
-	data->timestamp = time_usec;
+	data->timestamp = vb->timestamp;
 	data->flags = 0;
 	data->clnt_data = data->device_addr;
 
@@ -4054,7 +4057,8 @@
 	return rc;
 }
 
-int msm_comm_release_output_buffers(struct msm_vidc_inst *inst)
+int msm_comm_release_output_buffers(struct msm_vidc_inst *inst,
+	bool force_release)
 {
 	struct msm_smem *handle;
 	struct internal_buf *buf, *dummy;
@@ -4096,6 +4100,11 @@
 			goto exit;
 		}
 
+		if ((buf->buffer_ownership == FIRMWARE) && !force_release) {
+			dprintk(VIDC_INFO, "DPB is with f/w. Can't free it\n");
+			continue;
+		}
+
 		buffer_info.buffer_size = handle->size;
 		buffer_info.buffer_type = buf->buffer_type;
 		buffer_info.num_buffers = 1;
@@ -4355,13 +4364,17 @@
 int msm_comm_set_output_buffers(struct msm_vidc_inst *inst)
 {
 	int rc = 0;
+	bool force_release = true;
 
 	if (!inst || !inst->core || !inst->core->device) {
 		dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
 		return -EINVAL;
 	}
 
-	if (msm_comm_release_output_buffers(inst))
+	if (inst->fmts[OUTPUT_PORT].defer_outputs)
+		force_release = false;
+
+	if (msm_comm_release_output_buffers(inst, force_release))
 		dprintk(VIDC_WARN, "Failed to release output buffers\n");
 
 	rc = set_output_buffers(inst, HAL_BUFFER_OUTPUT);
@@ -4369,7 +4382,7 @@
 		goto error;
 	return rc;
 error:
-	msm_comm_release_output_buffers(inst);
+	msm_comm_release_output_buffers(inst, true);
 	return rc;
 }
 
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.h b/drivers/media/platform/msm/vidc/msm_vidc_common.h
index c042fe9..7f2ab04 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.h
@@ -55,7 +55,9 @@
 int msm_comm_release_scratch_buffers(struct msm_vidc_inst *inst,
 					bool check_for_reuse);
 int msm_comm_release_persist_buffers(struct msm_vidc_inst *inst);
-int msm_comm_release_output_buffers(struct msm_vidc_inst *inst);
+int msm_comm_release_output_buffers(struct msm_vidc_inst *inst,
+	bool force_release);
+void msm_comm_validate_output_buffers(struct msm_vidc_inst *inst);
 int msm_comm_force_cleanup(struct msm_vidc_inst *inst);
 int msm_comm_suspend(int core_id);
 enum hal_extradata_id msm_comm_get_hal_extradata_index(
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_debug.h b/drivers/media/platform/msm/vidc/msm_vidc_debug.h
index 0af0220..cf5ce22 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_debug.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_debug.h
@@ -117,7 +117,7 @@
 
 #define MSM_VIDC_ERROR(value)					\
 	do {							\
-		dprintk(VIDC_WARN, "Fatal Level = %d\n", value);\
+		dprintk(VIDC_DBG, "Fatal Level = %d\n", value);\
 		BUG_ON(value);					\
 	} while (0)
 
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_internal.h b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
index b4f3cd7..fb90fdf7 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_internal.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
@@ -148,6 +148,7 @@
 	int num_planes;
 	int type;
 	u32 (*get_frame_size)(int plane, u32 height, u32 width);
+	bool defer_outputs;
 };
 
 struct msm_vidc_drv {
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi.h b/drivers/media/platform/msm/vidc/vidc_hfi.h
index 949bc47..3267999 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi.h
@@ -62,6 +62,7 @@
 #define HFI_BUFFER_EXTRADATA_OUTPUT2 (HFI_OX_BASE + 0x4)
 #define HFI_BUFFER_INTERNAL_SCRATCH_1 (HFI_OX_BASE + 0x5)
 #define HFI_BUFFER_INTERNAL_SCRATCH_2 (HFI_OX_BASE + 0x6)
+#define HFI_BUFFER_INTERNAL_RECON (HFI_OX_BASE + 0x9)
 
 #define HFI_BUFFER_MODE_DYNAMIC (HFI_OX_BASE + 0x3)
 
@@ -84,6 +85,7 @@
 #define HFI_EXTRADATA_FRAME_QP			0x0000000F
 #define HFI_EXTRADATA_FRAME_BITS_INFO		0x00000010
 #define HFI_EXTRADATA_VPX_COLORSPACE		0x00000014
+#define HFI_EXTRADATA_UBWC_CR_STAT_INFO		0x00000019
 #define HFI_EXTRADATA_MULTISLICE_INFO		0x7F100000
 #define HFI_EXTRADATA_NUM_CONCEALED_MB		0x7F100001
 #define HFI_EXTRADATA_INDEX					0x7F100002
@@ -119,6 +121,7 @@
 #define HFI_INTERLACE_INTERLEAVE_FRAME_BOTTOMFIELDFIRST	0x04
 #define HFI_INTERLACE_FRAME_TOPFIELDFIRST				0x08
 #define HFI_INTERLACE_FRAME_BOTTOMFIELDFIRST			0x10
+#define HFI_INTERLACE_FRAME_MBAFF					0x20
 
 #define HFI_PROPERTY_SYS_OX_START			\
 	(HFI_DOMAIN_BASE_COMMON + HFI_ARCH_OX_OFFSET + 0x0000)
@@ -135,9 +138,7 @@
 	(HFI_PROPERTY_PARAM_OX_START + 0x006)
 #define HFI_PROPERTY_PARAM_S3D_FRAME_PACKING_EXTRADATA	\
 	(HFI_PROPERTY_PARAM_OX_START + 0x009)
-#define HFI_PROPERTY_PARAM_ERR_DETECTION_CODE_EXTRADATA \
-	(HFI_PROPERTY_PARAM_OX_START + 0x00A)
-#define HFI_PROPERTY_PARAM_BUFFER_SIZE_MINIMUM			\
+#define  HFI_PROPERTY_PARAM_BUFFER_SIZE_MINIMUM			\
 	(HFI_PROPERTY_PARAM_OX_START + 0x00C)
 #define HFI_PROPERTY_PARAM_SYNC_BASED_INTERRUPT			\
 	(HFI_PROPERTY_PARAM_OX_START + 0x00E)
@@ -591,6 +592,21 @@
 	u32 flush_type;
 };
 
+struct hfi_ubwc_cr_stats_info_type {
+	u32 cr_stats_info0;
+	u32 cr_stats_info1;
+	u32 cr_stats_info2;
+	u32 cr_stats_info3;
+	u32 cr_stats_info4;
+	u32 cr_stats_info5;
+	u32 cr_stats_info6;
+};
+
+struct hfi_frame_cr_stats_type {
+	u32 frame_index;
+	struct hfi_ubwc_cr_stats_info_type ubwc_stats_info;
+};
+
 struct hfi_msg_session_empty_buffer_done_packet {
 	u32 size;
 	u32 packet_type;
@@ -601,6 +617,8 @@
 	u32 input_tag;
 	u32 packet_buffer;
 	u32 extra_data_buffer;
+	u32 flags;
+	struct hfi_frame_cr_stats_type ubwc_cr_stats;
 	u32 rgData[0];
 };
 
@@ -761,6 +779,11 @@
 	u32 format;
 };
 
+struct hfi_conceal_color_type {
+	u32 value_8bit;
+	u32 value_10bit;
+};
+
 struct hfi_extradata_num_concealed_mb_payload {
 	u32 num_mb_concealed;
 };
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
index 6863d5e..e9a5bb3 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
@@ -83,6 +83,7 @@
 #define HFI_VIDEO_CODEC_VP9				0x00004000
 #define HFI_VIDEO_CODEC_HEVC_HYBRID			0x80000000
 
+#define HFI_PROFILE_UNKNOWN					0x00000000
 #define HFI_H264_PROFILE_BASELINE			0x00000001
 #define HFI_H264_PROFILE_MAIN				0x00000002
 #define HFI_H264_PROFILE_HIGH				0x00000004
@@ -91,6 +92,7 @@
 #define HFI_H264_PROFILE_CONSTRAINED_BASE	0x00000020
 #define HFI_H264_PROFILE_CONSTRAINED_HIGH	0x00000040
 
+#define HFI_LEVEL_UNKNOWN					0x00000000
 #define HFI_H264_LEVEL_1					0x00000001
 #define HFI_H264_LEVEL_1b					0x00000002
 #define HFI_H264_LEVEL_11					0x00000004
@@ -249,8 +251,8 @@
 	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x003)
 #define HFI_PROPERTY_PARAM_VENC_RATE_CONTROL				\
 	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x004)
-#define  HFI_PROPERTY_PARAM_VENC_SESSION_QP_RANGE           \
-	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x008)
+#define  HFI_PROPERTY_PARAM_VENC_SESSION_QP_RANGE		\
+	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x009)
 #define  HFI_PROPERTY_PARAM_VENC_OPEN_GOP                   \
 	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x00C)
 #define HFI_PROPERTY_PARAM_VENC_INTRA_REFRESH				\
@@ -537,11 +539,13 @@
 struct hfi_quantization {
 	u32 qp_packed;
 	u32 layer_id;
+	u32 reserved[4];
 };
 
 struct hfi_quantization_range {
 	struct hfi_quantization min_qp;
 	struct hfi_quantization max_qp;
+	u32 reserved[4];
 };
 
 #define HFI_LTR_MODE_DISABLE	0x0
@@ -617,10 +621,10 @@
 #define HFI_COLOR_FORMAT_YUV444				(HFI_COMMON_BASE + 0xE)
 #define HFI_COLOR_FORMAT_RGBA8888			(HFI_COMMON_BASE + 0x10)
 
-#define HFI_COLOR_FORMAT_P010						\
-		(HFI_COLOR_FORMAT_10_BIT_BASE + HFI_COLOR_FORMAT_NV12)
 #define HFI_COLOR_FORMAT_YUV420_TP10					\
-		(HFI_COLOR_FORMAT_10_BIT_BASE + HFI_COLOR_FORMAT_NV12_4x4TILE)
+		(HFI_COLOR_FORMAT_10_BIT_BASE + HFI_COLOR_FORMAT_NV12)
+#define HFI_COLOR_FORMAT_P010					\
+		(HFI_COLOR_FORMAT_10_BIT_BASE + HFI_COLOR_FORMAT_NV12 + 0x1)
 
 #define HFI_COLOR_FORMAT_NV12_UBWC					\
 		(HFI_COLOR_FORMAT_UBWC_BASE + HFI_COLOR_FORMAT_NV12)
diff --git a/drivers/media/usb/siano/smsusb.c b/drivers/media/usb/siano/smsusb.c
index c2e2587..18b41b9 100644
--- a/drivers/media/usb/siano/smsusb.c
+++ b/drivers/media/usb/siano/smsusb.c
@@ -218,22 +218,30 @@
 static int smsusb_sendrequest(void *context, void *buffer, size_t size)
 {
 	struct smsusb_device_t *dev = (struct smsusb_device_t *) context;
-	struct sms_msg_hdr *phdr = (struct sms_msg_hdr *) buffer;
-	int dummy;
+	struct sms_msg_hdr *phdr;
+	int dummy, ret;
 
 	if (dev->state != SMSUSB_ACTIVE) {
 		pr_debug("Device not active yet\n");
 		return -ENOENT;
 	}
 
+	phdr = kmalloc(size, GFP_KERNEL);
+	if (!phdr)
+		return -ENOMEM;
+	memcpy(phdr, buffer, size);
+
 	pr_debug("sending %s(%d) size: %d\n",
 		  smscore_translate_msg(phdr->msg_type), phdr->msg_type,
 		  phdr->msg_length);
 
 	smsendian_handle_tx_message((struct sms_msg_data *) phdr);
-	smsendian_handle_message_header((struct sms_msg_hdr *)buffer);
-	return usb_bulk_msg(dev->udev, usb_sndbulkpipe(dev->udev, 2),
-			    buffer, size, &dummy, 1000);
+	smsendian_handle_message_header((struct sms_msg_hdr *)phdr);
+	ret = usb_bulk_msg(dev->udev, usb_sndbulkpipe(dev->udev, 2),
+			    phdr, size, &dummy, 1000);
+
+	kfree(phdr);
+	return ret;
 }
 
 static char *smsusb1_fw_lkup[] = {
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index df19777..f57700c 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -1690,10 +1690,10 @@
 		err = mmc_select_hs400(card);
 		if (err)
 			goto free_card;
-	} else if (mmc_card_hs(card)) {
+	} else {
 		/* Select the desired bus width optionally */
 		err = mmc_select_bus_width(card);
-		if (err > 0) {
+		if (err > 0 && mmc_card_hs(card)) {
 			err = mmc_select_hs_ddr(card);
 			if (err)
 				goto free_card;
diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_reg.h b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_reg.h
index 878950a..2cf8b1d 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_reg.h
+++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_reg.h
@@ -1007,9 +1007,7 @@
 
 static inline void dsaf_write_reg(void __iomem *base, u32 reg, u32 value)
 {
-	u8 __iomem *reg_addr = ACCESS_ONCE(base);
-
-	writel(value, reg_addr + reg);
+	writel(value, base + reg);
 }
 
 #define dsaf_write_dev(a, reg, value) \
@@ -1017,9 +1015,7 @@
 
 static inline u32 dsaf_read_reg(u8 __iomem *base, u32 reg)
 {
-	u8 __iomem *reg_addr = ACCESS_ONCE(base);
-
-	return readl(reg_addr + reg);
+	return readl(base + reg);
 }
 
 static inline void dsaf_write_syscon(struct regmap *base, u32 reg, u32 value)
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_rx.c b/drivers/net/ethernet/mellanox/mlx4/en_rx.c
index f2e8bed..4d3ddc2 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_rx.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_rx.c
@@ -507,8 +507,11 @@
 		return;
 
 	for (ring = 0; ring < priv->rx_ring_num; ring++) {
-		if (mlx4_en_is_ring_empty(priv->rx_ring[ring]))
+		if (mlx4_en_is_ring_empty(priv->rx_ring[ring])) {
+			local_bh_disable();
 			napi_reschedule(&priv->rx_cq[ring]->napi);
+			local_bh_enable();
+		}
 	}
 }
 
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h
index 71382df..81d8e3b 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h
@@ -765,7 +765,8 @@
 int mlx5e_modify_rqs_vsd(struct mlx5e_priv *priv, bool vsd);
 
 int mlx5e_redirect_rqt(struct mlx5e_priv *priv, u32 rqtn, int sz, int ix);
-void mlx5e_build_tir_ctx_hash(void *tirc, struct mlx5e_priv *priv);
+void mlx5e_build_indir_tir_ctx_hash(struct mlx5e_priv *priv, void *tirc,
+				    enum mlx5e_traffic_types tt);
 
 int mlx5e_open_locked(struct net_device *netdev);
 int mlx5e_close_locked(struct net_device *netdev);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c
index 27ff401..126cfeb 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c
@@ -975,15 +975,18 @@
 
 static void mlx5e_modify_tirs_hash(struct mlx5e_priv *priv, void *in, int inlen)
 {
-	struct mlx5_core_dev *mdev = priv->mdev;
 	void *tirc = MLX5_ADDR_OF(modify_tir_in, in, ctx);
-	int i;
+	struct mlx5_core_dev *mdev = priv->mdev;
+	int ctxlen = MLX5_ST_SZ_BYTES(tirc);
+	int tt;
 
 	MLX5_SET(modify_tir_in, in, bitmask.hash, 1);
-	mlx5e_build_tir_ctx_hash(tirc, priv);
 
-	for (i = 0; i < MLX5E_NUM_INDIR_TIRS; i++)
-		mlx5_core_modify_tir(mdev, priv->indir_tir[i].tirn, in, inlen);
+	for (tt = 0; tt < MLX5E_NUM_INDIR_TIRS; tt++) {
+		memset(tirc, 0, ctxlen);
+		mlx5e_build_indir_tir_ctx_hash(priv, tirc, tt);
+		mlx5_core_modify_tir(mdev, priv->indir_tir[tt].tirn, in, inlen);
+	}
 }
 
 static int mlx5e_set_rxfh(struct net_device *dev, const u32 *indir,
@@ -991,6 +994,7 @@
 {
 	struct mlx5e_priv *priv = netdev_priv(dev);
 	int inlen = MLX5_ST_SZ_BYTES(modify_tir_in);
+	bool hash_changed = false;
 	void *in;
 
 	if ((hfunc != ETH_RSS_HASH_NO_CHANGE) &&
@@ -1012,14 +1016,21 @@
 		mlx5e_redirect_rqt(priv, rqtn, MLX5E_INDIR_RQT_SIZE, 0);
 	}
 
-	if (key)
+	if (hfunc != ETH_RSS_HASH_NO_CHANGE &&
+	    hfunc != priv->params.rss_hfunc) {
+		priv->params.rss_hfunc = hfunc;
+		hash_changed = true;
+	}
+
+	if (key) {
 		memcpy(priv->params.toeplitz_hash_key, key,
 		       sizeof(priv->params.toeplitz_hash_key));
+		hash_changed = hash_changed ||
+			       priv->params.rss_hfunc == ETH_RSS_HASH_TOP;
+	}
 
-	if (hfunc != ETH_RSS_HASH_NO_CHANGE)
-		priv->params.rss_hfunc = hfunc;
-
-	mlx5e_modify_tirs_hash(priv, in, inlen);
+	if (hash_changed)
+		mlx5e_modify_tirs_hash(priv, in, inlen);
 
 	mutex_unlock(&priv->state_lock);
 
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
index 5dc3e24..b306713 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
@@ -1978,8 +1978,23 @@
 	MLX5_SET(tirc, tirc, lro_timeout_period_usecs, priv->params.lro_timeout);
 }
 
-void mlx5e_build_tir_ctx_hash(void *tirc, struct mlx5e_priv *priv)
+void mlx5e_build_indir_tir_ctx_hash(struct mlx5e_priv *priv, void *tirc,
+				    enum mlx5e_traffic_types tt)
 {
+	void *hfso = MLX5_ADDR_OF(tirc, tirc, rx_hash_field_selector_outer);
+
+#define MLX5_HASH_IP            (MLX5_HASH_FIELD_SEL_SRC_IP   |\
+				 MLX5_HASH_FIELD_SEL_DST_IP)
+
+#define MLX5_HASH_IP_L4PORTS    (MLX5_HASH_FIELD_SEL_SRC_IP   |\
+				 MLX5_HASH_FIELD_SEL_DST_IP   |\
+				 MLX5_HASH_FIELD_SEL_L4_SPORT |\
+				 MLX5_HASH_FIELD_SEL_L4_DPORT)
+
+#define MLX5_HASH_IP_IPSEC_SPI  (MLX5_HASH_FIELD_SEL_SRC_IP   |\
+				 MLX5_HASH_FIELD_SEL_DST_IP   |\
+				 MLX5_HASH_FIELD_SEL_IPSEC_SPI)
+
 	MLX5_SET(tirc, tirc, rx_hash_fn,
 		 mlx5e_rx_hash_fn(priv->params.rss_hfunc));
 	if (priv->params.rss_hfunc == ETH_RSS_HASH_TOP) {
@@ -1991,6 +2006,88 @@
 		MLX5_SET(tirc, tirc, rx_hash_symmetric, 1);
 		memcpy(rss_key, priv->params.toeplitz_hash_key, len);
 	}
+
+	switch (tt) {
+	case MLX5E_TT_IPV4_TCP:
+		MLX5_SET(rx_hash_field_select, hfso, l3_prot_type,
+			 MLX5_L3_PROT_TYPE_IPV4);
+		MLX5_SET(rx_hash_field_select, hfso, l4_prot_type,
+			 MLX5_L4_PROT_TYPE_TCP);
+		MLX5_SET(rx_hash_field_select, hfso, selected_fields,
+			 MLX5_HASH_IP_L4PORTS);
+		break;
+
+	case MLX5E_TT_IPV6_TCP:
+		MLX5_SET(rx_hash_field_select, hfso, l3_prot_type,
+			 MLX5_L3_PROT_TYPE_IPV6);
+		MLX5_SET(rx_hash_field_select, hfso, l4_prot_type,
+			 MLX5_L4_PROT_TYPE_TCP);
+		MLX5_SET(rx_hash_field_select, hfso, selected_fields,
+			 MLX5_HASH_IP_L4PORTS);
+		break;
+
+	case MLX5E_TT_IPV4_UDP:
+		MLX5_SET(rx_hash_field_select, hfso, l3_prot_type,
+			 MLX5_L3_PROT_TYPE_IPV4);
+		MLX5_SET(rx_hash_field_select, hfso, l4_prot_type,
+			 MLX5_L4_PROT_TYPE_UDP);
+		MLX5_SET(rx_hash_field_select, hfso, selected_fields,
+			 MLX5_HASH_IP_L4PORTS);
+		break;
+
+	case MLX5E_TT_IPV6_UDP:
+		MLX5_SET(rx_hash_field_select, hfso, l3_prot_type,
+			 MLX5_L3_PROT_TYPE_IPV6);
+		MLX5_SET(rx_hash_field_select, hfso, l4_prot_type,
+			 MLX5_L4_PROT_TYPE_UDP);
+		MLX5_SET(rx_hash_field_select, hfso, selected_fields,
+			 MLX5_HASH_IP_L4PORTS);
+		break;
+
+	case MLX5E_TT_IPV4_IPSEC_AH:
+		MLX5_SET(rx_hash_field_select, hfso, l3_prot_type,
+			 MLX5_L3_PROT_TYPE_IPV4);
+		MLX5_SET(rx_hash_field_select, hfso, selected_fields,
+			 MLX5_HASH_IP_IPSEC_SPI);
+		break;
+
+	case MLX5E_TT_IPV6_IPSEC_AH:
+		MLX5_SET(rx_hash_field_select, hfso, l3_prot_type,
+			 MLX5_L3_PROT_TYPE_IPV6);
+		MLX5_SET(rx_hash_field_select, hfso, selected_fields,
+			 MLX5_HASH_IP_IPSEC_SPI);
+		break;
+
+	case MLX5E_TT_IPV4_IPSEC_ESP:
+		MLX5_SET(rx_hash_field_select, hfso, l3_prot_type,
+			 MLX5_L3_PROT_TYPE_IPV4);
+		MLX5_SET(rx_hash_field_select, hfso, selected_fields,
+			 MLX5_HASH_IP_IPSEC_SPI);
+		break;
+
+	case MLX5E_TT_IPV6_IPSEC_ESP:
+		MLX5_SET(rx_hash_field_select, hfso, l3_prot_type,
+			 MLX5_L3_PROT_TYPE_IPV6);
+		MLX5_SET(rx_hash_field_select, hfso, selected_fields,
+			 MLX5_HASH_IP_IPSEC_SPI);
+		break;
+
+	case MLX5E_TT_IPV4:
+		MLX5_SET(rx_hash_field_select, hfso, l3_prot_type,
+			 MLX5_L3_PROT_TYPE_IPV4);
+		MLX5_SET(rx_hash_field_select, hfso, selected_fields,
+			 MLX5_HASH_IP);
+		break;
+
+	case MLX5E_TT_IPV6:
+		MLX5_SET(rx_hash_field_select, hfso, l3_prot_type,
+			 MLX5_L3_PROT_TYPE_IPV6);
+		MLX5_SET(rx_hash_field_select, hfso, selected_fields,
+			 MLX5_HASH_IP);
+		break;
+	default:
+		WARN_ONCE(true, "%s: bad traffic type!\n", __func__);
+	}
 }
 
 static int mlx5e_modify_tirs_lro(struct mlx5e_priv *priv)
@@ -2360,110 +2457,13 @@
 static void mlx5e_build_indir_tir_ctx(struct mlx5e_priv *priv, u32 *tirc,
 				      enum mlx5e_traffic_types tt)
 {
-	void *hfso = MLX5_ADDR_OF(tirc, tirc, rx_hash_field_selector_outer);
-
 	MLX5_SET(tirc, tirc, transport_domain, priv->mdev->mlx5e_res.td.tdn);
 
-#define MLX5_HASH_IP            (MLX5_HASH_FIELD_SEL_SRC_IP   |\
-				 MLX5_HASH_FIELD_SEL_DST_IP)
-
-#define MLX5_HASH_IP_L4PORTS    (MLX5_HASH_FIELD_SEL_SRC_IP   |\
-				 MLX5_HASH_FIELD_SEL_DST_IP   |\
-				 MLX5_HASH_FIELD_SEL_L4_SPORT |\
-				 MLX5_HASH_FIELD_SEL_L4_DPORT)
-
-#define MLX5_HASH_IP_IPSEC_SPI  (MLX5_HASH_FIELD_SEL_SRC_IP   |\
-				 MLX5_HASH_FIELD_SEL_DST_IP   |\
-				 MLX5_HASH_FIELD_SEL_IPSEC_SPI)
-
 	mlx5e_build_tir_ctx_lro(tirc, priv);
 
 	MLX5_SET(tirc, tirc, disp_type, MLX5_TIRC_DISP_TYPE_INDIRECT);
 	MLX5_SET(tirc, tirc, indirect_table, priv->indir_rqt.rqtn);
-	mlx5e_build_tir_ctx_hash(tirc, priv);
-
-	switch (tt) {
-	case MLX5E_TT_IPV4_TCP:
-		MLX5_SET(rx_hash_field_select, hfso, l3_prot_type,
-			 MLX5_L3_PROT_TYPE_IPV4);
-		MLX5_SET(rx_hash_field_select, hfso, l4_prot_type,
-			 MLX5_L4_PROT_TYPE_TCP);
-		MLX5_SET(rx_hash_field_select, hfso, selected_fields,
-			 MLX5_HASH_IP_L4PORTS);
-		break;
-
-	case MLX5E_TT_IPV6_TCP:
-		MLX5_SET(rx_hash_field_select, hfso, l3_prot_type,
-			 MLX5_L3_PROT_TYPE_IPV6);
-		MLX5_SET(rx_hash_field_select, hfso, l4_prot_type,
-			 MLX5_L4_PROT_TYPE_TCP);
-		MLX5_SET(rx_hash_field_select, hfso, selected_fields,
-			 MLX5_HASH_IP_L4PORTS);
-		break;
-
-	case MLX5E_TT_IPV4_UDP:
-		MLX5_SET(rx_hash_field_select, hfso, l3_prot_type,
-			 MLX5_L3_PROT_TYPE_IPV4);
-		MLX5_SET(rx_hash_field_select, hfso, l4_prot_type,
-			 MLX5_L4_PROT_TYPE_UDP);
-		MLX5_SET(rx_hash_field_select, hfso, selected_fields,
-			 MLX5_HASH_IP_L4PORTS);
-		break;
-
-	case MLX5E_TT_IPV6_UDP:
-		MLX5_SET(rx_hash_field_select, hfso, l3_prot_type,
-			 MLX5_L3_PROT_TYPE_IPV6);
-		MLX5_SET(rx_hash_field_select, hfso, l4_prot_type,
-			 MLX5_L4_PROT_TYPE_UDP);
-		MLX5_SET(rx_hash_field_select, hfso, selected_fields,
-			 MLX5_HASH_IP_L4PORTS);
-		break;
-
-	case MLX5E_TT_IPV4_IPSEC_AH:
-		MLX5_SET(rx_hash_field_select, hfso, l3_prot_type,
-			 MLX5_L3_PROT_TYPE_IPV4);
-		MLX5_SET(rx_hash_field_select, hfso, selected_fields,
-			 MLX5_HASH_IP_IPSEC_SPI);
-		break;
-
-	case MLX5E_TT_IPV6_IPSEC_AH:
-		MLX5_SET(rx_hash_field_select, hfso, l3_prot_type,
-			 MLX5_L3_PROT_TYPE_IPV6);
-		MLX5_SET(rx_hash_field_select, hfso, selected_fields,
-			 MLX5_HASH_IP_IPSEC_SPI);
-		break;
-
-	case MLX5E_TT_IPV4_IPSEC_ESP:
-		MLX5_SET(rx_hash_field_select, hfso, l3_prot_type,
-			 MLX5_L3_PROT_TYPE_IPV4);
-		MLX5_SET(rx_hash_field_select, hfso, selected_fields,
-			 MLX5_HASH_IP_IPSEC_SPI);
-		break;
-
-	case MLX5E_TT_IPV6_IPSEC_ESP:
-		MLX5_SET(rx_hash_field_select, hfso, l3_prot_type,
-			 MLX5_L3_PROT_TYPE_IPV6);
-		MLX5_SET(rx_hash_field_select, hfso, selected_fields,
-			 MLX5_HASH_IP_IPSEC_SPI);
-		break;
-
-	case MLX5E_TT_IPV4:
-		MLX5_SET(rx_hash_field_select, hfso, l3_prot_type,
-			 MLX5_L3_PROT_TYPE_IPV4);
-		MLX5_SET(rx_hash_field_select, hfso, selected_fields,
-			 MLX5_HASH_IP);
-		break;
-
-	case MLX5E_TT_IPV6:
-		MLX5_SET(rx_hash_field_select, hfso, l3_prot_type,
-			 MLX5_L3_PROT_TYPE_IPV6);
-		MLX5_SET(rx_hash_field_select, hfso, selected_fields,
-			 MLX5_HASH_IP);
-		break;
-	default:
-		WARN_ONCE(true,
-			  "mlx5e_build_indir_tir_ctx: bad traffic type!\n");
-	}
+	mlx5e_build_indir_tir_ctx_hash(priv, tirc, tt);
 }
 
 static void mlx5e_build_direct_tir_ctx(struct mlx5e_priv *priv, u32 *tirc,
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c
index 914e546..7e20e4b 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c
@@ -1110,9 +1110,8 @@
 				return rule;
 			}
 			rule = add_rule_fte(fte, fg, dest);
-			unlock_ref_node(&fte->node);
 			if (IS_ERR(rule))
-				goto unlock_fg;
+				goto unlock_fte;
 			else
 				goto add_rule;
 		}
@@ -1130,6 +1129,7 @@
 		goto unlock_fg;
 	}
 	tree_init_node(&fte->node, 0, del_fte);
+	nested_lock_ref_node(&fte->node, FS_MUTEX_CHILD);
 	rule = add_rule_fte(fte, fg, dest);
 	if (IS_ERR(rule)) {
 		kfree(fte);
@@ -1142,6 +1142,8 @@
 	list_add(&fte->node.list, prev);
 add_rule:
 	tree_add_node(&rule->node, &fte->node);
+unlock_fte:
+	unlock_ref_node(&fte->node);
 unlock_fg:
 	unlock_ref_node(&fg->node);
 	return rule;
diff --git a/drivers/net/ethernet/msm/rndis_ipa.c b/drivers/net/ethernet/msm/rndis_ipa.c
index 29596f6..b8eff5a 100644
--- a/drivers/net/ethernet/msm/rndis_ipa.c
+++ b/drivers/net/ethernet/msm/rndis_ipa.c
@@ -121,8 +121,8 @@
 };
 
 #define RNDIS_IPA_STATE_DEBUG(ctx) \
-	(RNDIS_IPA_DEBUG("Driver state: %s\n",\
-	rndis_ipa_state_string((ctx)->state)))
+	RNDIS_IPA_DEBUG("Driver state: %s\n",\
+	rndis_ipa_state_string((ctx)->state))
 
 
 /**
@@ -832,7 +832,7 @@
 	netdev_tx_t status = NETDEV_TX_BUSY;
 	struct rndis_ipa_dev *rndis_ipa_ctx = netdev_priv(net);
 
-	net->trans_start = jiffies;
+	netif_trans_update(net);
 
 	RNDIS_IPA_DEBUG
 		("Tx, len=%d, skb->protocol=%d, outstanding=%d\n",
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c
index 7df4ff1..7d19029 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c
@@ -305,8 +305,12 @@
 {
 	void __iomem *ioaddr = hw->pcsr;
 	u32 intr_status = readl(ioaddr + GMAC_INT_STATUS);
+	u32 intr_mask = readl(ioaddr + GMAC_INT_MASK);
 	int ret = 0;
 
+	/* Discard masked bits */
+	intr_status &= ~intr_mask;
+
 	/* Not used events (e.g. MMC interrupts) are not handled. */
 	if ((intr_status & GMAC_INT_STATUS_MMCTIS))
 		x->mmc_tx_irq_n++;
diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c
index 720b5fa..c2ac39a 100644
--- a/drivers/net/hyperv/netvsc.c
+++ b/drivers/net/hyperv/netvsc.c
@@ -1288,6 +1288,9 @@
 	ndev = hv_get_drvdata(device);
 	buffer = get_per_channel_state(channel);
 
+	/* commit_rd_index() -> hv_signal_on_read() needs this. */
+	init_cached_read_index(channel);
+
 	do {
 		desc = get_next_pkt_raw(channel);
 		if (desc != NULL) {
@@ -1340,6 +1343,9 @@
 
 			bufferlen = bytes_recvd;
 		}
+
+		init_cached_read_index(channel);
+
 	} while (1);
 
 	if (bufferlen > NETVSC_PACKET_SIZE)
diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c
index 6255973..1b65f0f 100644
--- a/drivers/net/loopback.c
+++ b/drivers/net/loopback.c
@@ -164,6 +164,7 @@
 {
 	dev->mtu		= 64 * 1024;
 	dev->hard_header_len	= ETH_HLEN;	/* 14	*/
+	dev->min_header_len	= ETH_HLEN;	/* 14	*/
 	dev->addr_len		= ETH_ALEN;	/* 6	*/
 	dev->type		= ARPHRD_LOOPBACK;	/* 0x0001*/
 	dev->flags		= IFF_LOOPBACK;
diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c
index 6f38daf..adea6f5 100644
--- a/drivers/net/macvtap.c
+++ b/drivers/net/macvtap.c
@@ -682,7 +682,7 @@
 	ssize_t n;
 
 	if (q->flags & IFF_VNET_HDR) {
-		vnet_hdr_len = q->vnet_hdr_sz;
+		vnet_hdr_len = READ_ONCE(q->vnet_hdr_sz);
 
 		err = -EINVAL;
 		if (len < vnet_hdr_len)
@@ -822,7 +822,7 @@
 
 	if (q->flags & IFF_VNET_HDR) {
 		struct virtio_net_hdr vnet_hdr;
-		vnet_hdr_len = q->vnet_hdr_sz;
+		vnet_hdr_len = READ_ONCE(q->vnet_hdr_sz);
 		if (iov_iter_count(iter) < vnet_hdr_len)
 			return -EINVAL;
 
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index e5d9041..e686b70 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -1187,9 +1187,11 @@
 	}
 
 	if (tun->flags & IFF_VNET_HDR) {
-		if (len < tun->vnet_hdr_sz)
+		int vnet_hdr_sz = READ_ONCE(tun->vnet_hdr_sz);
+
+		if (len < vnet_hdr_sz)
 			return -EINVAL;
-		len -= tun->vnet_hdr_sz;
+		len -= vnet_hdr_sz;
 
 		n = copy_from_iter(&gso, sizeof(gso), from);
 		if (n != sizeof(gso))
@@ -1201,7 +1203,7 @@
 
 		if (tun16_to_cpu(tun, gso.hdr_len) > len)
 			return -EINVAL;
-		iov_iter_advance(from, tun->vnet_hdr_sz - sizeof(gso));
+		iov_iter_advance(from, vnet_hdr_sz - sizeof(gso));
 	}
 
 	if ((tun->flags & TUN_TYPE_MASK) == IFF_TAP) {
@@ -1348,7 +1350,7 @@
 		vlan_hlen = VLAN_HLEN;
 
 	if (tun->flags & IFF_VNET_HDR)
-		vnet_hdr_sz = tun->vnet_hdr_sz;
+		vnet_hdr_sz = READ_ONCE(tun->vnet_hdr_sz);
 
 	total = skb->len + vlan_hlen + vnet_hdr_sz;
 
diff --git a/drivers/net/usb/catc.c b/drivers/net/usb/catc.c
index d9ca05d..4086415 100644
--- a/drivers/net/usb/catc.c
+++ b/drivers/net/usb/catc.c
@@ -777,7 +777,7 @@
 	struct net_device *netdev;
 	struct catc *catc;
 	u8 broadcast[ETH_ALEN];
-	int i, pktsz;
+	int pktsz, ret;
 
 	if (usb_set_interface(usbdev,
 			intf->altsetting->desc.bInterfaceNumber, 1)) {
@@ -812,12 +812,8 @@
 	if ((!catc->ctrl_urb) || (!catc->tx_urb) || 
 	    (!catc->rx_urb) || (!catc->irq_urb)) {
 		dev_err(&intf->dev, "No free urbs available.\n");
-		usb_free_urb(catc->ctrl_urb);
-		usb_free_urb(catc->tx_urb);
-		usb_free_urb(catc->rx_urb);
-		usb_free_urb(catc->irq_urb);
-		free_netdev(netdev);
-		return -ENOMEM;
+		ret = -ENOMEM;
+		goto fail_free;
 	}
 
 	/* The F5U011 has the same vendor/product as the netmate but a device version of 0x130 */
@@ -845,15 +841,24 @@
                 catc->irq_buf, 2, catc_irq_done, catc, 1);
 
 	if (!catc->is_f5u011) {
+		u32 *buf;
+		int i;
+
 		dev_dbg(dev, "Checking memory size\n");
 
-		i = 0x12345678;
-		catc_write_mem(catc, 0x7a80, &i, 4);
-		i = 0x87654321;	
-		catc_write_mem(catc, 0xfa80, &i, 4);
-		catc_read_mem(catc, 0x7a80, &i, 4);
+		buf = kmalloc(4, GFP_KERNEL);
+		if (!buf) {
+			ret = -ENOMEM;
+			goto fail_free;
+		}
+
+		*buf = 0x12345678;
+		catc_write_mem(catc, 0x7a80, buf, 4);
+		*buf = 0x87654321;
+		catc_write_mem(catc, 0xfa80, buf, 4);
+		catc_read_mem(catc, 0x7a80, buf, 4);
 	  
-		switch (i) {
+		switch (*buf) {
 		case 0x12345678:
 			catc_set_reg(catc, TxBufCount, 8);
 			catc_set_reg(catc, RxBufCount, 32);
@@ -868,6 +873,8 @@
 			dev_dbg(dev, "32k Memory\n");
 			break;
 		}
+
+		kfree(buf);
 	  
 		dev_dbg(dev, "Getting MAC from SEEROM.\n");
 	  
@@ -914,16 +921,21 @@
 	usb_set_intfdata(intf, catc);
 
 	SET_NETDEV_DEV(netdev, &intf->dev);
-	if (register_netdev(netdev) != 0) {
-		usb_set_intfdata(intf, NULL);
-		usb_free_urb(catc->ctrl_urb);
-		usb_free_urb(catc->tx_urb);
-		usb_free_urb(catc->rx_urb);
-		usb_free_urb(catc->irq_urb);
-		free_netdev(netdev);
-		return -EIO;
-	}
+	ret = register_netdev(netdev);
+	if (ret)
+		goto fail_clear_intfdata;
+
 	return 0;
+
+fail_clear_intfdata:
+	usb_set_intfdata(intf, NULL);
+fail_free:
+	usb_free_urb(catc->ctrl_urb);
+	usb_free_urb(catc->tx_urb);
+	usb_free_urb(catc->rx_urb);
+	usb_free_urb(catc->irq_urb);
+	free_netdev(netdev);
+	return ret;
 }
 
 static void catc_disconnect(struct usb_interface *intf)
diff --git a/drivers/net/usb/pegasus.c b/drivers/net/usb/pegasus.c
index 1434e5d..ee40ac2 100644
--- a/drivers/net/usb/pegasus.c
+++ b/drivers/net/usb/pegasus.c
@@ -126,40 +126,61 @@
 
 static int get_registers(pegasus_t *pegasus, __u16 indx, __u16 size, void *data)
 {
+	u8 *buf;
 	int ret;
 
+	buf = kmalloc(size, GFP_NOIO);
+	if (!buf)
+		return -ENOMEM;
+
 	ret = usb_control_msg(pegasus->usb, usb_rcvctrlpipe(pegasus->usb, 0),
 			      PEGASUS_REQ_GET_REGS, PEGASUS_REQT_READ, 0,
-			      indx, data, size, 1000);
+			      indx, buf, size, 1000);
 	if (ret < 0)
 		netif_dbg(pegasus, drv, pegasus->net,
 			  "%s returned %d\n", __func__, ret);
+	else if (ret <= size)
+		memcpy(data, buf, ret);
+	kfree(buf);
 	return ret;
 }
 
-static int set_registers(pegasus_t *pegasus, __u16 indx, __u16 size, void *data)
+static int set_registers(pegasus_t *pegasus, __u16 indx, __u16 size,
+			 const void *data)
 {
+	u8 *buf;
 	int ret;
 
+	buf = kmemdup(data, size, GFP_NOIO);
+	if (!buf)
+		return -ENOMEM;
+
 	ret = usb_control_msg(pegasus->usb, usb_sndctrlpipe(pegasus->usb, 0),
 			      PEGASUS_REQ_SET_REGS, PEGASUS_REQT_WRITE, 0,
-			      indx, data, size, 100);
+			      indx, buf, size, 100);
 	if (ret < 0)
 		netif_dbg(pegasus, drv, pegasus->net,
 			  "%s returned %d\n", __func__, ret);
+	kfree(buf);
 	return ret;
 }
 
 static int set_register(pegasus_t *pegasus, __u16 indx, __u8 data)
 {
+	u8 *buf;
 	int ret;
 
+	buf = kmemdup(&data, 1, GFP_NOIO);
+	if (!buf)
+		return -ENOMEM;
+
 	ret = usb_control_msg(pegasus->usb, usb_sndctrlpipe(pegasus->usb, 0),
 			      PEGASUS_REQ_SET_REG, PEGASUS_REQT_WRITE, data,
-			      indx, &data, 1, 1000);
+			      indx, buf, 1, 1000);
 	if (ret < 0)
 		netif_dbg(pegasus, drv, pegasus->net,
 			  "%s returned %d\n", __func__, ret);
+	kfree(buf);
 	return ret;
 }
 
diff --git a/drivers/net/usb/rtl8150.c b/drivers/net/usb/rtl8150.c
index 7c72bfa..dc4f7ea 100644
--- a/drivers/net/usb/rtl8150.c
+++ b/drivers/net/usb/rtl8150.c
@@ -155,16 +155,36 @@
 */
 static int get_registers(rtl8150_t * dev, u16 indx, u16 size, void *data)
 {
-	return usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0),
-			       RTL8150_REQ_GET_REGS, RTL8150_REQT_READ,
-			       indx, 0, data, size, 500);
+	void *buf;
+	int ret;
+
+	buf = kmalloc(size, GFP_NOIO);
+	if (!buf)
+		return -ENOMEM;
+
+	ret = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0),
+			      RTL8150_REQ_GET_REGS, RTL8150_REQT_READ,
+			      indx, 0, buf, size, 500);
+	if (ret > 0 && ret <= size)
+		memcpy(data, buf, ret);
+	kfree(buf);
+	return ret;
 }
 
-static int set_registers(rtl8150_t * dev, u16 indx, u16 size, void *data)
+static int set_registers(rtl8150_t * dev, u16 indx, u16 size, const void *data)
 {
-	return usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0),
-			       RTL8150_REQ_SET_REGS, RTL8150_REQT_WRITE,
-			       indx, 0, data, size, 500);
+	void *buf;
+	int ret;
+
+	buf = kmemdup(data, size, GFP_NOIO);
+	if (!buf)
+		return -ENOMEM;
+
+	ret = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0),
+			      RTL8150_REQ_SET_REGS, RTL8150_REQT_WRITE,
+			      indx, 0, buf, size, 500);
+	kfree(buf);
+	return ret;
 }
 
 static void async_set_reg_cb(struct urb *urb)
diff --git a/drivers/net/wireless/ath/wil6210/Kconfig b/drivers/net/wireless/ath/wil6210/Kconfig
index 6dfedc8..8f0bde5 100644
--- a/drivers/net/wireless/ath/wil6210/Kconfig
+++ b/drivers/net/wireless/ath/wil6210/Kconfig
@@ -40,3 +40,23 @@
 	  option if you are interested in debugging the driver.
 
 	  If unsure, say Y to make it easier to debug problems.
+
+config WIL6210_WRITE_IOCTL
+	bool "wil6210 write ioctl to the device"
+	depends on WIL6210
+	default n
+	---help---
+	  Say Y here to allow write-access from user-space to
+	  the device memory through ioctl. This is useful for
+	  debugging purposes only.
+
+	  If unsure, say N.
+
+config WIL6210_PLATFORM_MSM
+	bool "wil6210 MSM platform specific support"
+	depends on WIL6210
+	depends on ARCH_QCOM
+	default y
+	---help---
+	  Say Y here to enable wil6210 driver support for MSM
+	  platform specific features
diff --git a/drivers/net/wireless/ath/wil6210/Makefile b/drivers/net/wireless/ath/wil6210/Makefile
index 11b544b..a0f7658 100644
--- a/drivers/net/wireless/ath/wil6210/Makefile
+++ b/drivers/net/wireless/ath/wil6210/Makefile
@@ -19,8 +19,12 @@
 wil6210-y += ethtool.o
 wil6210-y += wil_crash_dump.o
 wil6210-y += p2p.o
+wil6210-y += ftm.o
 
 # for tracing framework to find trace.h
 CFLAGS_trace.o := -I$(src)
 
 subdir-ccflags-y += -D__CHECK_ENDIAN__
+
+MSM_11AD_PATH = drivers/platform/msm/msm_11ad
+CFLAGS_wil_platform.o := -I$(MSM_11AD_PATH)
diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c
index d117240..6c68fd9 100644
--- a/drivers/net/wireless/ath/wil6210/cfg80211.c
+++ b/drivers/net/wireless/ath/wil6210/cfg80211.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2016 Qualcomm Atheros, Inc.
+ * Copyright (c) 2012-2017 Qualcomm Atheros, Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -17,9 +17,14 @@
 #include <linux/etherdevice.h>
 #include "wil6210.h"
 #include "wmi.h"
+#include "ftm.h"
 
 #define WIL_MAX_ROC_DURATION_MS 5000
 
+bool disable_ap_sme;
+module_param(disable_ap_sme, bool, 0444);
+MODULE_PARM_DESC(disable_ap_sme, " let user space handle AP mode SME");
+
 #define CHAN60G(_channel, _flags) {				\
 	.band			= NL80211_BAND_60GHZ,		\
 	.center_freq		= 56160 + (2160 * (_channel)),	\
@@ -36,6 +41,90 @@
 /* channel 4 not supported yet */
 };
 
+/* Vendor id to be used in vendor specific command and events
+ * to user space.
+ * NOTE: The authoritative place for definition of QCA_NL80211_VENDOR_ID,
+ * vendor subcmd definitions prefixed with QCA_NL80211_VENDOR_SUBCMD, and
+ * qca_wlan_vendor_attr is open source file src/common/qca-vendor.h in
+ * git://w1.fi/srv/git/hostap.git; the values here are just a copy of that
+ */
+
+#define QCA_NL80211_VENDOR_ID	0x001374
+
+enum qca_nl80211_vendor_subcmds {
+	QCA_NL80211_VENDOR_SUBCMD_LOC_GET_CAPA = 128,
+	QCA_NL80211_VENDOR_SUBCMD_FTM_START_SESSION = 129,
+	QCA_NL80211_VENDOR_SUBCMD_FTM_ABORT_SESSION = 130,
+	QCA_NL80211_VENDOR_SUBCMD_FTM_MEAS_RESULT = 131,
+	QCA_NL80211_VENDOR_SUBCMD_FTM_SESSION_DONE = 132,
+	QCA_NL80211_VENDOR_SUBCMD_FTM_CFG_RESPONDER = 133,
+	QCA_NL80211_VENDOR_SUBCMD_AOA_MEAS = 134,
+	QCA_NL80211_VENDOR_SUBCMD_AOA_ABORT_MEAS = 135,
+	QCA_NL80211_VENDOR_SUBCMD_AOA_MEAS_RESULT = 136,
+};
+
+/* vendor specific commands */
+static const struct wiphy_vendor_command wil_nl80211_vendor_commands[] = {
+	{
+		.info.vendor_id = QCA_NL80211_VENDOR_ID,
+		.info.subcmd = QCA_NL80211_VENDOR_SUBCMD_LOC_GET_CAPA,
+		.flags = WIPHY_VENDOR_CMD_NEED_WDEV |
+			 WIPHY_VENDOR_CMD_NEED_RUNNING,
+		.doit = wil_ftm_get_capabilities
+	},
+	{
+		.info.vendor_id = QCA_NL80211_VENDOR_ID,
+		.info.subcmd = QCA_NL80211_VENDOR_SUBCMD_FTM_START_SESSION,
+		.flags = WIPHY_VENDOR_CMD_NEED_WDEV |
+			 WIPHY_VENDOR_CMD_NEED_RUNNING,
+		.doit = wil_ftm_start_session
+	},
+	{
+		.info.vendor_id = QCA_NL80211_VENDOR_ID,
+		.info.subcmd = QCA_NL80211_VENDOR_SUBCMD_FTM_ABORT_SESSION,
+		.flags = WIPHY_VENDOR_CMD_NEED_WDEV |
+			 WIPHY_VENDOR_CMD_NEED_RUNNING,
+		.doit = wil_ftm_abort_session
+	},
+	{
+		.info.vendor_id = QCA_NL80211_VENDOR_ID,
+		.info.subcmd = QCA_NL80211_VENDOR_SUBCMD_FTM_CFG_RESPONDER,
+		.flags = WIPHY_VENDOR_CMD_NEED_WDEV |
+			 WIPHY_VENDOR_CMD_NEED_RUNNING,
+		.doit = wil_ftm_configure_responder
+	},
+	{
+		.info.vendor_id = QCA_NL80211_VENDOR_ID,
+		.info.subcmd = QCA_NL80211_VENDOR_SUBCMD_AOA_MEAS,
+		.flags = WIPHY_VENDOR_CMD_NEED_WDEV |
+			 WIPHY_VENDOR_CMD_NEED_RUNNING,
+		.doit = wil_aoa_start_measurement
+	},
+	{
+		.info.vendor_id = QCA_NL80211_VENDOR_ID,
+		.info.subcmd = QCA_NL80211_VENDOR_SUBCMD_AOA_ABORT_MEAS,
+		.flags = WIPHY_VENDOR_CMD_NEED_WDEV |
+			 WIPHY_VENDOR_CMD_NEED_RUNNING,
+		.doit = wil_aoa_abort_measurement
+	},
+};
+
+/* vendor specific events */
+static const struct nl80211_vendor_cmd_info wil_nl80211_vendor_events[] = {
+	[QCA_NL80211_VENDOR_EVENT_FTM_MEAS_RESULT_INDEX] = {
+			.vendor_id = QCA_NL80211_VENDOR_ID,
+			.subcmd = QCA_NL80211_VENDOR_SUBCMD_FTM_MEAS_RESULT
+	},
+	[QCA_NL80211_VENDOR_EVENT_FTM_SESSION_DONE_INDEX] = {
+			.vendor_id = QCA_NL80211_VENDOR_ID,
+			.subcmd = QCA_NL80211_VENDOR_SUBCMD_FTM_SESSION_DONE
+	},
+	[QCA_NL80211_VENDOR_EVENT_AOA_MEAS_RESULT_INDEX] = {
+			.vendor_id = QCA_NL80211_VENDOR_ID,
+			.subcmd = QCA_NL80211_VENDOR_SUBCMD_AOA_MEAS_RESULT
+	},
+};
+
 static struct ieee80211_supported_band wil_band_60ghz = {
 	.channels = wil_60ghz_channels,
 	.n_channels = ARRAY_SIZE(wil_60ghz_channels),
@@ -62,9 +151,16 @@
 	},
 	[NL80211_IFTYPE_AP] = {
 		.tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
-		BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
+		BIT(IEEE80211_STYPE_PROBE_RESP >> 4) |
+		BIT(IEEE80211_STYPE_ASSOC_RESP >> 4) |
+		BIT(IEEE80211_STYPE_DISASSOC >> 4),
 		.rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
-		BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
+		BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
+		BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
+		BIT(IEEE80211_STYPE_DISASSOC >> 4) |
+		BIT(IEEE80211_STYPE_AUTH >> 4) |
+		BIT(IEEE80211_STYPE_DEAUTH >> 4) |
+		BIT(IEEE80211_STYPE_REASSOC_REQ >> 4)
 	},
 	[NL80211_IFTYPE_P2P_CLIENT] = {
 		.tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
@@ -194,7 +290,7 @@
 
 	int cid = wil_find_cid(wil, mac);
 
-	wil_dbg_misc(wil, "%s(%pM) CID %d\n", __func__, mac, cid);
+	wil_dbg_misc(wil, "get_station: %pM CID %d\n", mac, cid);
 	if (cid < 0)
 		return cid;
 
@@ -233,7 +329,7 @@
 		return -ENOENT;
 
 	ether_addr_copy(mac, wil->sta[cid].addr);
-	wil_dbg_misc(wil, "%s(%pM) CID %d\n", __func__, mac, cid);
+	wil_dbg_misc(wil, "dump_station: %pM CID %d\n", mac, cid);
 
 	rc = wil_cid_fill_sinfo(wil, cid, sinfo);
 
@@ -250,16 +346,15 @@
 	struct net_device *ndev = wil_to_ndev(wil);
 	struct wireless_dev *p2p_wdev;
 
-	wil_dbg_misc(wil, "%s()\n", __func__);
+	wil_dbg_misc(wil, "add_iface\n");
 
 	if (type != NL80211_IFTYPE_P2P_DEVICE) {
-		wil_err(wil, "%s: unsupported iftype %d\n", __func__, type);
+		wil_err(wil, "unsupported iftype %d\n", type);
 		return ERR_PTR(-EINVAL);
 	}
 
 	if (wil->p2p_wdev) {
-		wil_err(wil, "%s: P2P_DEVICE interface already created\n",
-			__func__);
+		wil_err(wil, "P2P_DEVICE interface already created\n");
 		return ERR_PTR(-EINVAL);
 	}
 
@@ -282,11 +377,10 @@
 {
 	struct wil6210_priv *wil = wiphy_to_wil(wiphy);
 
-	wil_dbg_misc(wil, "%s()\n", __func__);
+	wil_dbg_misc(wil, "del_iface\n");
 
 	if (wdev != wil->p2p_wdev) {
-		wil_err(wil, "%s: delete of incorrect interface 0x%p\n",
-			__func__, wdev);
+		wil_err(wil, "delete of incorrect interface 0x%p\n", wdev);
 		return -EINVAL;
 	}
 
@@ -304,7 +398,7 @@
 	struct wireless_dev *wdev = wil_to_wdev(wil);
 	int rc;
 
-	wil_dbg_misc(wil, "%s() type=%d\n", __func__, type);
+	wil_dbg_misc(wil, "change_iface: type=%d\n", type);
 
 	if (netif_running(wil_to_ndev(wil)) && !wil_is_recovery_blocked(wil)) {
 		wil_dbg_misc(wil, "interface is up. resetting...\n");
@@ -351,16 +445,7 @@
 	uint i, n;
 	int rc;
 
-	wil_dbg_misc(wil, "%s(), wdev=0x%p iftype=%d\n",
-		     __func__, wdev, wdev->iftype);
-
-	mutex_lock(&wil->p2p_wdev_mutex);
-	if (wil->scan_request) {
-		wil_err(wil, "Already scanning\n");
-		mutex_unlock(&wil->p2p_wdev_mutex);
-		return -EAGAIN;
-	}
-	mutex_unlock(&wil->p2p_wdev_mutex);
+	wil_dbg_misc(wil, "scan: wdev=0x%p iftype=%d\n", wdev, wdev->iftype);
 
 	/* check we are client side */
 	switch (wdev->iftype) {
@@ -378,12 +463,24 @@
 		return -EBUSY;
 	}
 
+	mutex_lock(&wil->mutex);
+
+	mutex_lock(&wil->p2p_wdev_mutex);
+	if (wil->scan_request || wil->p2p.discovery_started) {
+		wil_err(wil, "Already scanning\n");
+		mutex_unlock(&wil->p2p_wdev_mutex);
+		rc = -EAGAIN;
+		goto out;
+	}
+	mutex_unlock(&wil->p2p_wdev_mutex);
+
 	/* social scan on P2P_DEVICE is handled as p2p search */
 	if (wdev->iftype == NL80211_IFTYPE_P2P_DEVICE &&
 	    wil_p2p_is_social_scan(request)) {
 		if (!wil->p2p.p2p_dev_started) {
 			wil_err(wil, "P2P search requested on stopped P2P device\n");
-			return -EIO;
+			rc = -EIO;
+			goto out;
 		}
 		wil->scan_request = request;
 		wil->radio_wdev = wdev;
@@ -392,7 +489,7 @@
 			wil->radio_wdev = wil_to_wdev(wil);
 			wil->scan_request = NULL;
 		}
-		return rc;
+		goto out;
 	}
 
 	(void)wil_p2p_stop_discovery(wil);
@@ -415,7 +512,7 @@
 
 	if (rc) {
 		wil_err(wil, "set SSID for scan request failed: %d\n", rc);
-		return rc;
+		goto out;
 	}
 
 	wil->scan_request = request;
@@ -448,7 +545,7 @@
 
 	rc = wmi_set_ie(wil, WMI_FRAME_PROBE_REQ, request->ie_len, request->ie);
 	if (rc)
-		goto out;
+		goto out_restore;
 
 	if (wil->discovery_mode && cmd.cmd.scan_type == WMI_ACTIVE_SCAN) {
 		cmd.cmd.discovery_mode = 1;
@@ -459,16 +556,45 @@
 	rc = wmi_send(wil, WMI_START_SCAN_CMDID, &cmd, sizeof(cmd.cmd) +
 			cmd.cmd.num_channels * sizeof(cmd.cmd.channel_list[0]));
 
-out:
+out_restore:
 	if (rc) {
 		del_timer_sync(&wil->scan_timer);
 		wil->radio_wdev = wil_to_wdev(wil);
 		wil->scan_request = NULL;
 	}
-
+out:
+	mutex_unlock(&wil->mutex);
 	return rc;
 }
 
+static void wil_cfg80211_abort_scan(struct wiphy *wiphy,
+				    struct wireless_dev *wdev)
+{
+	struct wil6210_priv *wil = wiphy_to_wil(wiphy);
+
+	wil_dbg_misc(wil, "wdev=0x%p iftype=%d\n", wdev, wdev->iftype);
+
+	mutex_lock(&wil->mutex);
+	mutex_lock(&wil->p2p_wdev_mutex);
+
+	if (!wil->scan_request)
+		goto out;
+
+	if (wdev != wil->scan_request->wdev) {
+		wil_dbg_misc(wil, "abort scan was called on the wrong iface\n");
+		goto out;
+	}
+
+	if (wil->radio_wdev == wil->p2p_wdev)
+		wil_p2p_stop_radio_operations(wil);
+	else
+		wil_abort_scan(wil, true);
+
+out:
+	mutex_unlock(&wil->p2p_wdev_mutex);
+	mutex_unlock(&wil->mutex);
+}
+
 static void wil_print_crypto(struct wil6210_priv *wil,
 			     struct cfg80211_crypto_settings *c)
 {
@@ -524,7 +650,7 @@
 	int rc = 0;
 	enum ieee80211_bss_type bss_type = IEEE80211_BSS_TYPE_ESS;
 
-	wil_dbg_misc(wil, "%s()\n", __func__);
+	wil_dbg_misc(wil, "connect\n");
 	wil_print_connect_params(wil, sme);
 
 	if (test_bit(wil_status_fwconnecting, wil->status) ||
@@ -560,6 +686,7 @@
 		goto out;
 	}
 	wil->privacy = sme->privacy;
+	wil->pbss = sme->pbss;
 
 	if (wil->privacy) {
 		/* For secure assoc, remove old keys */
@@ -656,12 +783,11 @@
 	int rc;
 	struct wil6210_priv *wil = wiphy_to_wil(wiphy);
 
-	wil_dbg_misc(wil, "%s(reason=%d)\n", __func__, reason_code);
+	wil_dbg_misc(wil, "disconnect: reason=%d\n", reason_code);
 
 	if (!(test_bit(wil_status_fwconnecting, wil->status) ||
 	      test_bit(wil_status_fwconnected, wil->status))) {
-		wil_err(wil, "%s: Disconnect was called while disconnected\n",
-			__func__);
+		wil_err(wil, "Disconnect was called while disconnected\n");
 		return 0;
 	}
 
@@ -669,11 +795,31 @@
 		      WMI_DISCONNECT_EVENTID, NULL, 0,
 		      WIL6210_DISCONNECT_TO_MS);
 	if (rc)
-		wil_err(wil, "%s: disconnect error %d\n", __func__, rc);
+		wil_err(wil, "disconnect error %d\n", rc);
 
 	return rc;
 }
 
+static int wil_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
+{
+	struct wil6210_priv *wil = wiphy_to_wil(wiphy);
+	int rc;
+
+	/* these parameters are explicitly not supported */
+	if (changed & (WIPHY_PARAM_RETRY_LONG |
+		       WIPHY_PARAM_FRAG_THRESHOLD |
+		       WIPHY_PARAM_RTS_THRESHOLD))
+		return -ENOTSUPP;
+
+	if (changed & WIPHY_PARAM_RETRY_SHORT) {
+		rc = wmi_set_mgmt_retry(wil, wiphy->retry_short);
+		if (rc)
+			return rc;
+	}
+
+	return 0;
+}
+
 int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
 			 struct cfg80211_mgmt_tx_params *params,
 			 u64 *cookie)
@@ -697,7 +843,7 @@
 	 * different from currently "listened" channel and fail if it is.
 	 */
 
-	wil_dbg_misc(wil, "%s()\n", __func__);
+	wil_dbg_misc(wil, "mgmt_tx\n");
 	print_hex_dump_bytes("mgmt tx frame ", DUMP_PREFIX_OFFSET, buf, len);
 
 	cmd = kmalloc(sizeof(*cmd) + len, GFP_KERNEL);
@@ -758,7 +904,7 @@
 			break;
 		}
 	}
-	wil_dbg_misc(wil, "%s() -> %s\n", __func__, key_usage_str[rc]);
+	wil_dbg_misc(wil, "detect_key_usage: -> %s\n", key_usage_str[rc]);
 
 	return rc;
 }
@@ -863,13 +1009,13 @@
 		return -EINVAL;
 	}
 
-	wil_dbg_misc(wil, "%s(%pM %s[%d] PN %*phN)\n", __func__,
+	wil_dbg_misc(wil, "add_key: %pM %s[%d] PN %*phN\n",
 		     mac_addr, key_usage_str[key_usage], key_index,
 		     params->seq_len, params->seq);
 
 	if (IS_ERR(cs)) {
-		wil_err(wil, "Not connected, %s(%pM %s[%d] PN %*phN)\n",
-			__func__, mac_addr, key_usage_str[key_usage], key_index,
+		wil_err(wil, "Not connected, %pM %s[%d] PN %*phN\n",
+			mac_addr, key_usage_str[key_usage], key_index,
 			params->seq_len, params->seq);
 		return -EINVAL;
 	}
@@ -878,8 +1024,8 @@
 
 	if (params->seq && params->seq_len != IEEE80211_GCMP_PN_LEN) {
 		wil_err(wil,
-			"Wrong PN len %d, %s(%pM %s[%d] PN %*phN)\n",
-			params->seq_len, __func__, mac_addr,
+			"Wrong PN len %d, %pM %s[%d] PN %*phN\n",
+			params->seq_len, mac_addr,
 			key_usage_str[key_usage], key_index,
 			params->seq_len, params->seq);
 		return -EINVAL;
@@ -903,11 +1049,11 @@
 	struct wil_sta_info *cs = wil_find_sta_by_key_usage(wil, key_usage,
 							    mac_addr);
 
-	wil_dbg_misc(wil, "%s(%pM %s[%d])\n", __func__, mac_addr,
+	wil_dbg_misc(wil, "del_key: %pM %s[%d]\n", mac_addr,
 		     key_usage_str[key_usage], key_index);
 
 	if (IS_ERR(cs))
-		wil_info(wil, "Not connected, %s(%pM %s[%d])\n", __func__,
+		wil_info(wil, "Not connected, %pM %s[%d]\n",
 			 mac_addr, key_usage_str[key_usage], key_index);
 
 	if (!IS_ERR_OR_NULL(cs))
@@ -924,7 +1070,7 @@
 {
 	struct wil6210_priv *wil = wiphy_to_wil(wiphy);
 
-	wil_dbg_misc(wil, "%s: entered\n", __func__);
+	wil_dbg_misc(wil, "set_default_key: entered\n");
 	return 0;
 }
 
@@ -937,19 +1083,12 @@
 	struct wil6210_priv *wil = wiphy_to_wil(wiphy);
 	int rc;
 
-	wil_dbg_misc(wil, "%s() center_freq=%d, duration=%d iftype=%d\n",
-		     __func__, chan->center_freq, duration, wdev->iftype);
+	wil_dbg_misc(wil,
+		     "remain_on_channel: center_freq=%d, duration=%d iftype=%d\n",
+		     chan->center_freq, duration, wdev->iftype);
 
-	rc = wil_p2p_listen(wil, duration, chan, cookie);
-	if (rc)
-		return rc;
-
-	wil->radio_wdev = wdev;
-
-	cfg80211_ready_on_channel(wdev, *cookie, chan, duration,
-				  GFP_KERNEL);
-
-	return 0;
+	rc = wil_p2p_listen(wil, wdev, duration, chan, cookie);
+	return rc;
 }
 
 static int wil_cancel_remain_on_channel(struct wiphy *wiphy,
@@ -958,7 +1097,7 @@
 {
 	struct wil6210_priv *wil = wiphy_to_wil(wiphy);
 
-	wil_dbg_misc(wil, "%s()\n", __func__);
+	wil_dbg_misc(wil, "cancel_remain_on_channel\n");
 
 	return wil_p2p_cancel_listen(wil, cookie);
 }
@@ -1114,9 +1253,9 @@
 	if (pbss)
 		wmi_nettype = WMI_NETTYPE_P2P;
 
-	wil_dbg_misc(wil, "%s: is_go=%d\n", __func__, is_go);
+	wil_dbg_misc(wil, "start_ap: is_go=%d\n", is_go);
 	if (is_go && !pbss) {
-		wil_err(wil, "%s: P2P GO must be in PBSS\n", __func__);
+		wil_err(wil, "P2P GO must be in PBSS\n");
 		return -ENOTSUPP;
 	}
 
@@ -1171,7 +1310,7 @@
 	int rc;
 	u32 privacy = 0;
 
-	wil_dbg_misc(wil, "%s()\n", __func__);
+	wil_dbg_misc(wil, "change_beacon\n");
 	wil_print_bcon_data(bcon);
 
 	if (bcon->tail &&
@@ -1210,7 +1349,7 @@
 	struct cfg80211_crypto_settings *crypto = &info->crypto;
 	u8 hidden_ssid;
 
-	wil_dbg_misc(wil, "%s()\n", __func__);
+	wil_dbg_misc(wil, "start_ap\n");
 
 	if (!channel) {
 		wil_err(wil, "AP: No channel???\n");
@@ -1261,7 +1400,7 @@
 {
 	struct wil6210_priv *wil = wiphy_to_wil(wiphy);
 
-	wil_dbg_misc(wil, "%s()\n", __func__);
+	wil_dbg_misc(wil, "stop_ap\n");
 
 	netif_carrier_off(ndev);
 	wil_set_recovery_state(wil, fw_recovery_idle);
@@ -1277,13 +1416,35 @@
 	return 0;
 }
 
+static int wil_cfg80211_add_station(struct wiphy *wiphy,
+				    struct net_device *dev,
+				    const u8 *mac,
+				    struct station_parameters *params)
+{
+	struct wil6210_priv *wil = wiphy_to_wil(wiphy);
+
+	wil_dbg_misc(wil, "add station %pM aid %d\n", mac, params->aid);
+
+	if (!disable_ap_sme) {
+		wil_err(wil, "not supported with AP SME enabled\n");
+		return -EOPNOTSUPP;
+	}
+
+	if (params->aid > WIL_MAX_DMG_AID) {
+		wil_err(wil, "invalid aid\n");
+		return -EINVAL;
+	}
+
+	return wmi_new_sta(wil, mac, params->aid);
+}
+
 static int wil_cfg80211_del_station(struct wiphy *wiphy,
 				    struct net_device *dev,
 				    struct station_del_parameters *params)
 {
 	struct wil6210_priv *wil = wiphy_to_wil(wiphy);
 
-	wil_dbg_misc(wil, "%s(%pM, reason=%d)\n", __func__, params->mac,
+	wil_dbg_misc(wil, "del_station: %pM, reason=%d\n", params->mac,
 		     params->reason_code);
 
 	mutex_lock(&wil->mutex);
@@ -1293,6 +1454,52 @@
 	return 0;
 }
 
+static int wil_cfg80211_change_station(struct wiphy *wiphy,
+				       struct net_device *dev,
+				       const u8 *mac,
+				       struct station_parameters *params)
+{
+	struct wil6210_priv *wil = wiphy_to_wil(wiphy);
+	int authorize;
+	int cid, i;
+	struct vring_tx_data *txdata = NULL;
+
+	wil_dbg_misc(wil, "change station %pM mask 0x%x set 0x%x\n", mac,
+		     params->sta_flags_mask, params->sta_flags_set);
+
+	if (!disable_ap_sme) {
+		wil_dbg_misc(wil, "not supported with AP SME enabled\n");
+		return -EOPNOTSUPP;
+	}
+
+	if (!(params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED)))
+		return 0;
+
+	cid = wil_find_cid(wil, mac);
+	if (cid < 0) {
+		wil_err(wil, "station not found\n");
+		return -ENOLINK;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(wil->vring2cid_tid); i++)
+		if (wil->vring2cid_tid[i][0] == cid) {
+			txdata = &wil->vring_tx_data[i];
+			break;
+		}
+
+	if (!txdata) {
+		wil_err(wil, "vring data not found\n");
+		return -ENOLINK;
+	}
+
+	authorize = params->sta_flags_set & BIT(NL80211_STA_FLAG_AUTHORIZED);
+	txdata->dot1x_open = authorize ? 1 : 0;
+	wil_dbg_misc(wil, "cid %d vring %d authorize %d\n", cid, i,
+		     txdata->dot1x_open);
+
+	return 0;
+}
+
 /* probe_client handling */
 static void wil_probe_client_handle(struct wil6210_priv *wil,
 				    struct wil_probe_client_req *req)
@@ -1342,7 +1549,7 @@
 {
 	struct wil_probe_client_req *req, *t;
 
-	wil_dbg_misc(wil, "%s()\n", __func__);
+	wil_dbg_misc(wil, "probe_client_flush\n");
 
 	mutex_lock(&wil->probe_client_mutex);
 
@@ -1362,7 +1569,7 @@
 	struct wil_probe_client_req *req;
 	int cid = wil_find_cid(wil, peer);
 
-	wil_dbg_misc(wil, "%s(%pM => CID %d)\n", __func__, peer, cid);
+	wil_dbg_misc(wil, "probe_client: %pM => CID %d\n", peer, cid);
 
 	if (cid < 0)
 		return -ENOLINK;
@@ -1390,7 +1597,7 @@
 	struct wil6210_priv *wil = wiphy_to_wil(wiphy);
 
 	if (params->ap_isolate >= 0) {
-		wil_dbg_misc(wil, "%s(ap_isolate %d => %d)\n", __func__,
+		wil_dbg_misc(wil, "change_bss: ap_isolate %d => %d\n",
 			     wil->ap_isolate, params->ap_isolate);
 		wil->ap_isolate = params->ap_isolate;
 	}
@@ -1403,7 +1610,7 @@
 {
 	struct wil6210_priv *wil = wiphy_to_wil(wiphy);
 
-	wil_dbg_misc(wil, "%s: entered\n", __func__);
+	wil_dbg_misc(wil, "start_p2p_device: entered\n");
 	wil->p2p.p2p_dev_started = 1;
 	return 0;
 }
@@ -1417,19 +1624,51 @@
 	if (!p2p->p2p_dev_started)
 		return;
 
-	wil_dbg_misc(wil, "%s: entered\n", __func__);
+	wil_dbg_misc(wil, "stop_p2p_device: entered\n");
 	mutex_lock(&wil->mutex);
+	mutex_lock(&wil->p2p_wdev_mutex);
 	wil_p2p_stop_radio_operations(wil);
 	p2p->p2p_dev_started = 0;
+	mutex_unlock(&wil->p2p_wdev_mutex);
 	mutex_unlock(&wil->mutex);
 }
 
+static int wil_cfg80211_set_power_mgmt(struct wiphy *wiphy,
+				       struct net_device *dev,
+				       bool enabled, int timeout)
+{
+	struct wil6210_priv *wil = wiphy_to_wil(wiphy);
+	enum wmi_ps_profile_type ps_profile;
+	int rc;
+
+	if (!test_bit(WMI_FW_CAPABILITY_PS_CONFIG, wil->fw_capabilities)) {
+		wil_err(wil, "set_power_mgmt not supported\n");
+		return -EOPNOTSUPP;
+	}
+
+	wil_dbg_misc(wil, "enabled=%d, timeout=%d\n",
+		     enabled, timeout);
+
+	if (enabled)
+		ps_profile = WMI_PS_PROFILE_TYPE_DEFAULT;
+	else
+		ps_profile = WMI_PS_PROFILE_TYPE_PS_DISABLED;
+
+	rc  = wmi_ps_dev_profile_cfg(wil, ps_profile);
+	if (rc)
+		wil_err(wil, "wmi_ps_dev_profile_cfg failed (%d)\n", rc);
+
+	return rc;
+}
+
 static struct cfg80211_ops wil_cfg80211_ops = {
 	.add_virtual_intf = wil_cfg80211_add_iface,
 	.del_virtual_intf = wil_cfg80211_del_iface,
 	.scan = wil_cfg80211_scan,
+	.abort_scan = wil_cfg80211_abort_scan,
 	.connect = wil_cfg80211_connect,
 	.disconnect = wil_cfg80211_disconnect,
+	.set_wiphy_params = wil_cfg80211_set_wiphy_params,
 	.change_virtual_intf = wil_cfg80211_change_iface,
 	.get_station = wil_cfg80211_get_station,
 	.dump_station = wil_cfg80211_dump_station,
@@ -1444,12 +1683,15 @@
 	.change_beacon = wil_cfg80211_change_beacon,
 	.start_ap = wil_cfg80211_start_ap,
 	.stop_ap = wil_cfg80211_stop_ap,
+	.add_station = wil_cfg80211_add_station,
 	.del_station = wil_cfg80211_del_station,
+	.change_station = wil_cfg80211_change_station,
 	.probe_client = wil_cfg80211_probe_client,
 	.change_bss = wil_cfg80211_change_bss,
 	/* P2P device */
 	.start_p2p_device = wil_cfg80211_start_p2p_device,
 	.stop_p2p_device = wil_cfg80211_stop_p2p_device,
+	.set_power_mgmt = wil_cfg80211_set_power_mgmt,
 };
 
 static void wil_wiphy_init(struct wiphy *wiphy)
@@ -1464,9 +1706,11 @@
 				 BIT(NL80211_IFTYPE_P2P_GO) |
 				 BIT(NL80211_IFTYPE_P2P_DEVICE) |
 				 BIT(NL80211_IFTYPE_MONITOR);
-	wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME |
-			WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL |
-			WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD;
+	wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL |
+			WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD |
+			WIPHY_FLAG_PS_ON_BY_DEFAULT;
+	if (!disable_ap_sme)
+		wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME;
 	dev_dbg(wiphy_dev(wiphy), "%s : flags = 0x%08x\n",
 		__func__, wiphy->flags);
 	wiphy->probe_resp_offload =
@@ -1483,6 +1727,11 @@
 	wiphy->n_cipher_suites = ARRAY_SIZE(wil_cipher_suites);
 	wiphy->mgmt_stypes = wil_mgmt_stypes;
 	wiphy->features |= NL80211_FEATURE_SK_TX_STATUS;
+
+	wiphy->n_vendor_commands = ARRAY_SIZE(wil_nl80211_vendor_commands);
+	wiphy->vendor_commands = wil_nl80211_vendor_commands;
+	wiphy->vendor_events = wil_nl80211_vendor_events;
+	wiphy->n_vendor_events = ARRAY_SIZE(wil_nl80211_vendor_events);
 }
 
 struct wireless_dev *wil_cfg80211_init(struct device *dev)
diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c
index 5e4058a..3e8cdf1 100644
--- a/drivers/net/wireless/ath/wil6210/debugfs.c
+++ b/drivers/net/wireless/ath/wil6210/debugfs.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2016 Qualcomm Atheros, Inc.
+ * Copyright (c) 2012-2017 Qualcomm Atheros, Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -364,13 +364,13 @@
 }
 
 static const struct dbg_off isr_off[] = {
-	{"ICC", S_IRUGO | S_IWUSR, offsetof(struct RGF_ICR, ICC), doff_io32},
-	{"ICR", S_IRUGO | S_IWUSR, offsetof(struct RGF_ICR, ICR), doff_io32},
-	{"ICM", S_IRUGO | S_IWUSR, offsetof(struct RGF_ICR, ICM), doff_io32},
-	{"ICS",		  S_IWUSR, offsetof(struct RGF_ICR, ICS), doff_io32},
-	{"IMV", S_IRUGO | S_IWUSR, offsetof(struct RGF_ICR, IMV), doff_io32},
-	{"IMS",		  S_IWUSR, offsetof(struct RGF_ICR, IMS), doff_io32},
-	{"IMC",		  S_IWUSR, offsetof(struct RGF_ICR, IMC), doff_io32},
+	{"ICC", 0644, offsetof(struct RGF_ICR, ICC), doff_io32},
+	{"ICR", 0644, offsetof(struct RGF_ICR, ICR), doff_io32},
+	{"ICM", 0644, offsetof(struct RGF_ICR, ICM), doff_io32},
+	{"ICS",	0244, offsetof(struct RGF_ICR, ICS), doff_io32},
+	{"IMV", 0644, offsetof(struct RGF_ICR, IMV), doff_io32},
+	{"IMS",	0244, offsetof(struct RGF_ICR, IMS), doff_io32},
+	{"IMC",	0244, offsetof(struct RGF_ICR, IMC), doff_io32},
 	{},
 };
 
@@ -390,9 +390,9 @@
 }
 
 static const struct dbg_off pseudo_isr_off[] = {
-	{"CAUSE",   S_IRUGO, HOSTADDR(RGF_DMA_PSEUDO_CAUSE), doff_io32},
-	{"MASK_SW", S_IRUGO, HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_SW), doff_io32},
-	{"MASK_FW", S_IRUGO, HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_FW), doff_io32},
+	{"CAUSE",   0444, HOSTADDR(RGF_DMA_PSEUDO_CAUSE), doff_io32},
+	{"MASK_SW", 0444, HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_SW), doff_io32},
+	{"MASK_FW", 0444, HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_FW), doff_io32},
 	{},
 };
 
@@ -411,40 +411,40 @@
 }
 
 static const struct dbg_off lgc_itr_cnt_off[] = {
-	{"TRSH", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_CNT_TRSH), doff_io32},
-	{"DATA", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_CNT_DATA), doff_io32},
-	{"CTL",  S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_CNT_CRL), doff_io32},
+	{"TRSH", 0644, HOSTADDR(RGF_DMA_ITR_CNT_TRSH), doff_io32},
+	{"DATA", 0644, HOSTADDR(RGF_DMA_ITR_CNT_DATA), doff_io32},
+	{"CTL",  0644, HOSTADDR(RGF_DMA_ITR_CNT_CRL), doff_io32},
 	{},
 };
 
 static const struct dbg_off tx_itr_cnt_off[] = {
-	{"TRSH", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_TX_CNT_TRSH),
+	{"TRSH", 0644, HOSTADDR(RGF_DMA_ITR_TX_CNT_TRSH),
 	 doff_io32},
-	{"DATA", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_TX_CNT_DATA),
+	{"DATA", 0644, HOSTADDR(RGF_DMA_ITR_TX_CNT_DATA),
 	 doff_io32},
-	{"CTL",  S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_TX_CNT_CTL),
+	{"CTL",  0644, HOSTADDR(RGF_DMA_ITR_TX_CNT_CTL),
 	 doff_io32},
-	{"IDL_TRSH", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_TX_IDL_CNT_TRSH),
+	{"IDL_TRSH", 0644, HOSTADDR(RGF_DMA_ITR_TX_IDL_CNT_TRSH),
 	 doff_io32},
-	{"IDL_DATA", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_TX_IDL_CNT_DATA),
+	{"IDL_DATA", 0644, HOSTADDR(RGF_DMA_ITR_TX_IDL_CNT_DATA),
 	 doff_io32},
-	{"IDL_CTL",  S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_TX_IDL_CNT_CTL),
+	{"IDL_CTL",  0644, HOSTADDR(RGF_DMA_ITR_TX_IDL_CNT_CTL),
 	 doff_io32},
 	{},
 };
 
 static const struct dbg_off rx_itr_cnt_off[] = {
-	{"TRSH", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_RX_CNT_TRSH),
+	{"TRSH", 0644, HOSTADDR(RGF_DMA_ITR_RX_CNT_TRSH),
 	 doff_io32},
-	{"DATA", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_RX_CNT_DATA),
+	{"DATA", 0644, HOSTADDR(RGF_DMA_ITR_RX_CNT_DATA),
 	 doff_io32},
-	{"CTL",  S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_RX_CNT_CTL),
+	{"CTL",  0644, HOSTADDR(RGF_DMA_ITR_RX_CNT_CTL),
 	 doff_io32},
-	{"IDL_TRSH", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_RX_IDL_CNT_TRSH),
+	{"IDL_TRSH", 0644, HOSTADDR(RGF_DMA_ITR_RX_IDL_CNT_TRSH),
 	 doff_io32},
-	{"IDL_DATA", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_RX_IDL_CNT_DATA),
+	{"IDL_DATA", 0644, HOSTADDR(RGF_DMA_ITR_RX_IDL_CNT_DATA),
 	 doff_io32},
-	{"IDL_CTL",  S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_RX_IDL_CNT_CTL),
+	{"IDL_CTL",  0644, HOSTADDR(RGF_DMA_ITR_RX_IDL_CNT_CTL),
 	 doff_io32},
 	{},
 };
@@ -813,7 +813,7 @@
 	rc = wil_cfg80211_mgmt_tx(wiphy, wdev, &params, NULL);
 
 	kfree(frame);
-	wil_info(wil, "%s() -> %d\n", __func__, rc);
+	wil_info(wil, "-> %d\n", rc);
 
 	return len;
 }
@@ -855,7 +855,7 @@
 	rc1 = wmi_send(wil, cmdid, cmd, cmdlen);
 	kfree(wmi);
 
-	wil_info(wil, "%s(0x%04x[%d]) -> %d\n", __func__, cmdid, cmdlen, rc1);
+	wil_info(wil, "0x%04x[%d] -> %d\n", cmdid, cmdlen, rc1);
 
 	return rc;
 }
@@ -1379,6 +1379,7 @@
 	for (i = 0; i < ARRAY_SIZE(wil->sta); i++) {
 		struct wil_sta_info *p = &wil->sta[i];
 		char *status = "unknown";
+		u8 aid = 0;
 
 		switch (p->status) {
 		case wil_sta_unused:
@@ -1389,9 +1390,10 @@
 			break;
 		case wil_sta_connected:
 			status = "connected";
+			aid = p->aid;
 			break;
 		}
-		seq_printf(s, "[%d] %pM %s\n", i, p->addr, status);
+		seq_printf(s, "[%d] %pM %s AID %d\n", i, p->addr, status, aid);
 
 		if (p->status == wil_sta_connected) {
 			spin_lock_bh(&p->tid_rx_lock);
@@ -1622,7 +1624,7 @@
 		blob->data = (void * __force)wil->csr + HOSTADDR(map->host);
 		blob->size = map->to - map->from;
 		snprintf(name, sizeof(name), "blob_%s", map->name);
-		wil_debugfs_create_ioblob(name, S_IRUGO, dbg, wil_blob);
+		wil_debugfs_create_ioblob(name, 0444, dbg, wil_blob);
 	}
 }
 
@@ -1632,29 +1634,29 @@
 	umode_t mode;
 	const struct file_operations *fops;
 } dbg_files[] = {
-	{"mbox",	S_IRUGO,		&fops_mbox},
-	{"vrings",	S_IRUGO,		&fops_vring},
-	{"stations",	S_IRUGO,		&fops_sta},
-	{"desc",	S_IRUGO,		&fops_txdesc},
-	{"bf",		S_IRUGO,		&fops_bf},
-	{"ssid",	S_IRUGO | S_IWUSR,	&fops_ssid},
-	{"mem_val",	S_IRUGO,		&fops_memread},
-	{"reset",		  S_IWUSR,	&fops_reset},
-	{"rxon",		  S_IWUSR,	&fops_rxon},
-	{"tx_mgmt",		  S_IWUSR,	&fops_txmgmt},
-	{"wmi_send",		  S_IWUSR,	&fops_wmi},
-	{"back",	S_IRUGO | S_IWUSR,	&fops_back},
-	{"pmccfg",	S_IRUGO | S_IWUSR,	&fops_pmccfg},
-	{"pmcdata",	S_IRUGO,		&fops_pmcdata},
-	{"temp",	S_IRUGO,		&fops_temp},
-	{"freq",	S_IRUGO,		&fops_freq},
-	{"link",	S_IRUGO,		&fops_link},
-	{"info",	S_IRUGO,		&fops_info},
-	{"recovery",	S_IRUGO | S_IWUSR,	&fops_recovery},
-	{"led_cfg",	S_IRUGO | S_IWUSR,	&fops_led_cfg},
-	{"led_blink_time",	S_IRUGO | S_IWUSR,	&fops_led_blink_time},
-	{"fw_capabilities",	S_IRUGO,	&fops_fw_capabilities},
-	{"fw_version",	S_IRUGO,		&fops_fw_version},
+	{"mbox",	0444,		&fops_mbox},
+	{"vrings",	0444,		&fops_vring},
+	{"stations", 0444,		&fops_sta},
+	{"desc",	0444,		&fops_txdesc},
+	{"bf",		0444,		&fops_bf},
+	{"ssid",	0644,		&fops_ssid},
+	{"mem_val",	0644,		&fops_memread},
+	{"reset",	0244,		&fops_reset},
+	{"rxon",	0244,		&fops_rxon},
+	{"tx_mgmt",	0244,		&fops_txmgmt},
+	{"wmi_send", 0244,		&fops_wmi},
+	{"back",	0644,		&fops_back},
+	{"pmccfg",	0644,		&fops_pmccfg},
+	{"pmcdata",	0444,		&fops_pmcdata},
+	{"temp",	0444,		&fops_temp},
+	{"freq",	0444,		&fops_freq},
+	{"link",	0444,		&fops_link},
+	{"info",	0444,		&fops_info},
+	{"recovery", 0644,		&fops_recovery},
+	{"led_cfg",	0644,		&fops_led_cfg},
+	{"led_blink_time",	0644,	&fops_led_blink_time},
+	{"fw_capabilities",	0444,	&fops_fw_capabilities},
+	{"fw_version",	0444,		&fops_fw_version},
 };
 
 static void wil6210_debugfs_init_files(struct wil6210_priv *wil,
@@ -1693,30 +1695,32 @@
 
 /* fields in struct wil6210_priv */
 static const struct dbg_off dbg_wil_off[] = {
-	WIL_FIELD(privacy,	S_IRUGO,		doff_u32),
-	WIL_FIELD(status[0],	S_IRUGO | S_IWUSR,	doff_ulong),
-	WIL_FIELD(hw_version,	S_IRUGO,		doff_x32),
-	WIL_FIELD(recovery_count, S_IRUGO,		doff_u32),
-	WIL_FIELD(ap_isolate,	S_IRUGO,		doff_u32),
-	WIL_FIELD(discovery_mode, S_IRUGO | S_IWUSR,	doff_u8),
+	WIL_FIELD(privacy,	0444,		doff_u32),
+	WIL_FIELD(status[0],	0644,	doff_ulong),
+	WIL_FIELD(hw_version,	0444,	doff_x32),
+	WIL_FIELD(recovery_count, 0444,	doff_u32),
+	WIL_FIELD(ap_isolate,	0444,	doff_u32),
+	WIL_FIELD(discovery_mode, 0644,	doff_u8),
+	WIL_FIELD(chip_revision, 0444,	doff_u8),
+	WIL_FIELD(abft_len, 0644,		doff_u8),
 	{},
 };
 
 static const struct dbg_off dbg_wil_regs[] = {
-	{"RGF_MAC_MTRL_COUNTER_0", S_IRUGO, HOSTADDR(RGF_MAC_MTRL_COUNTER_0),
+	{"RGF_MAC_MTRL_COUNTER_0", 0444, HOSTADDR(RGF_MAC_MTRL_COUNTER_0),
 		doff_io32},
-	{"RGF_USER_USAGE_1", S_IRUGO, HOSTADDR(RGF_USER_USAGE_1), doff_io32},
+	{"RGF_USER_USAGE_1", 0444, HOSTADDR(RGF_USER_USAGE_1), doff_io32},
 	{},
 };
 
 /* static parameters */
 static const struct dbg_off dbg_statics[] = {
-	{"desc_index",	S_IRUGO | S_IWUSR, (ulong)&dbg_txdesc_index, doff_u32},
-	{"vring_index",	S_IRUGO | S_IWUSR, (ulong)&dbg_vring_index, doff_u32},
-	{"mem_addr",	S_IRUGO | S_IWUSR, (ulong)&mem_addr, doff_u32},
-	{"vring_idle_trsh", S_IRUGO | S_IWUSR, (ulong)&vring_idle_trsh,
+	{"desc_index",	0644, (ulong)&dbg_txdesc_index, doff_u32},
+	{"vring_index",	0644, (ulong)&dbg_vring_index, doff_u32},
+	{"mem_addr",	0644, (ulong)&mem_addr, doff_u32},
+	{"vring_idle_trsh", 0644, (ulong)&vring_idle_trsh,
 	 doff_u32},
-	{"led_polarity", S_IRUGO | S_IWUSR, (ulong)&led_polarity, doff_u8},
+	{"led_polarity", 0644, (ulong)&led_polarity, doff_u8},
 	{},
 };
 
diff --git a/drivers/net/wireless/ath/wil6210/ethtool.c b/drivers/net/wireless/ath/wil6210/ethtool.c
index 7053b62..adcfef4 100644
--- a/drivers/net/wireless/ath/wil6210/ethtool.c
+++ b/drivers/net/wireless/ath/wil6210/ethtool.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014 Qualcomm Atheros, Inc.
+ * Copyright (c) 2014,2017 Qualcomm Atheros, Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -27,7 +27,7 @@
 
 	mutex_lock(&wil->mutex);
 
-	wil_dbg_misc(wil, "%s()\n", __func__);
+	wil_dbg_misc(wil, "ethtoolops_begin\n");
 
 	return 0;
 }
@@ -36,7 +36,7 @@
 {
 	struct wil6210_priv *wil = ndev_to_wil(ndev);
 
-	wil_dbg_misc(wil, "%s()\n", __func__);
+	wil_dbg_misc(wil, "ethtoolops_complete\n");
 
 	mutex_unlock(&wil->mutex);
 }
@@ -48,7 +48,7 @@
 	u32 tx_itr_en, tx_itr_val = 0;
 	u32 rx_itr_en, rx_itr_val = 0;
 
-	wil_dbg_misc(wil, "%s()\n", __func__);
+	wil_dbg_misc(wil, "ethtoolops_get_coalesce\n");
 
 	tx_itr_en = wil_r(wil, RGF_DMA_ITR_TX_CNT_CTL);
 	if (tx_itr_en & BIT_DMA_ITR_TX_CNT_CTL_EN)
@@ -68,7 +68,7 @@
 {
 	struct wil6210_priv *wil = ndev_to_wil(ndev);
 
-	wil_dbg_misc(wil, "%s(rx %d usec, tx %d usec)\n", __func__,
+	wil_dbg_misc(wil, "ethtoolops_set_coalesce: rx %d usec, tx %d usec\n",
 		     cp->rx_coalesce_usecs, cp->tx_coalesce_usecs);
 
 	if (wil->wdev->iftype == NL80211_IFTYPE_MONITOR) {
diff --git a/drivers/net/wireless/ath/wil6210/ftm.c b/drivers/net/wireless/ath/wil6210/ftm.c
new file mode 100644
index 0000000..f94c894
--- /dev/null
+++ b/drivers/net/wireless/ath/wil6210/ftm.c
@@ -0,0 +1,929 @@
+/*
+ * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <linux/etherdevice.h>
+#include <net/netlink.h>
+#include "wil6210.h"
+#include "ftm.h"
+#include "wmi.h"
+
+/* FTM session ID we use with FW */
+#define WIL_FTM_FW_SESSION_ID		1
+
+/* fixed spare allocation we reserve in NL messages we allocate */
+#define WIL_FTM_NL_EXTRA_ALLOC		32
+
+/* approx maximum length for FTM_MEAS_RESULT NL80211 event */
+#define WIL_FTM_MEAS_RESULT_MAX_LENGTH	2048
+
+/* timeout for waiting for standalone AOA measurement, milliseconds */
+#define WIL_AOA_MEASUREMENT_TIMEOUT	1000
+
+/* maximum number of allowed FTM measurements per burst */
+#define WIL_FTM_MAX_MEAS_PER_BURST	31
+
+/* initial token to use on non-secure FTM measurement */
+#define WIL_TOF_FTM_DEFAULT_INITIAL_TOKEN	2
+
+#define WIL_TOF_FTM_MAX_LCI_LENGTH		(240)
+#define WIL_TOF_FTM_MAX_LCR_LENGTH		(240)
+
+static const struct
+nla_policy wil_nl80211_loc_policy[QCA_WLAN_VENDOR_ATTR_LOC_MAX + 1] = {
+	[QCA_WLAN_VENDOR_ATTR_FTM_SESSION_COOKIE] = { .type = NLA_U64 },
+	[QCA_WLAN_VENDOR_ATTR_LOC_CAPA] = { .type = NLA_NESTED },
+	[QCA_WLAN_VENDOR_ATTR_FTM_MEAS_PEERS] = { .type = NLA_NESTED },
+	[QCA_WLAN_VENDOR_ATTR_FTM_MEAS_PEER_RESULTS] = { .type = NLA_NESTED },
+	[QCA_WLAN_VENDOR_ATTR_FTM_RESPONDER_ENABLE] = { .type = NLA_FLAG },
+	[QCA_WLAN_VENDOR_ATTR_LOC_SESSION_STATUS] = { .type = NLA_U32 },
+	[QCA_WLAN_VENDOR_ATTR_FTM_INITIAL_TOKEN] = { .type = NLA_U8 },
+	[QCA_WLAN_VENDOR_ATTR_AOA_TYPE] = { .type = NLA_U32 },
+	[QCA_WLAN_VENDOR_ATTR_LOC_ANTENNA_ARRAY_MASK] = { .type = NLA_U32 },
+	[QCA_WLAN_VENDOR_ATTR_FREQ] = { .type = NLA_U32 },
+};
+
+static const struct
+nla_policy wil_nl80211_ftm_peer_policy[
+	QCA_WLAN_VENDOR_ATTR_FTM_PEER_MAX + 1] = {
+	[QCA_WLAN_VENDOR_ATTR_FTM_PEER_MAC_ADDR] = { .len = ETH_ALEN },
+	[QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_FLAGS] = { .type = NLA_U32 },
+	[QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_PARAMS] = { .type = NLA_NESTED },
+	[QCA_WLAN_VENDOR_ATTR_FTM_PEER_SECURE_TOKEN_ID] = { .type = NLA_U8 },
+	[QCA_WLAN_VENDOR_ATTR_FTM_PEER_FREQ] = { .type = NLA_U32 },
+};
+
+static const struct
+nla_policy wil_nl80211_ftm_meas_param_policy[
+	QCA_WLAN_VENDOR_ATTR_FTM_PARAM_MAX + 1] = {
+	[QCA_WLAN_VENDOR_ATTR_FTM_PARAM_MEAS_PER_BURST] = { .type = NLA_U8 },
+	[QCA_WLAN_VENDOR_ATTR_FTM_PARAM_NUM_BURSTS_EXP] = { .type = NLA_U8 },
+	[QCA_WLAN_VENDOR_ATTR_FTM_PARAM_BURST_DURATION] = { .type = NLA_U8 },
+	[QCA_WLAN_VENDOR_ATTR_FTM_PARAM_BURST_PERIOD] = { .type = NLA_U16 },
+};
+
+static u8 wil_ftm_get_channel(struct wil6210_priv *wil,
+			      const u8 *mac_addr, u32 freq)
+{
+	struct wiphy *wiphy = wil_to_wiphy(wil);
+	struct cfg80211_bss *bss;
+	struct ieee80211_channel *chan;
+	u8 channel;
+
+	if (freq) {
+		chan = ieee80211_get_channel(wiphy, freq);
+		if (!chan) {
+			wil_err(wil, "invalid freq: %d\n", freq);
+			return 0;
+		}
+		channel = chan->hw_value;
+	} else {
+		bss = cfg80211_get_bss(wiphy, NULL, mac_addr,
+				       NULL, 0, IEEE80211_BSS_TYPE_ANY,
+				       IEEE80211_PRIVACY_ANY);
+		if (!bss) {
+			wil_err(wil, "Unable to find BSS\n");
+			return 0;
+		}
+		channel = bss->channel->hw_value;
+		cfg80211_put_bss(wiphy, bss);
+	}
+
+	wil_dbg_misc(wil, "target %pM at channel %d\n", mac_addr, channel);
+	return channel;
+}
+
+static int wil_ftm_parse_meas_params(struct wil6210_priv *wil,
+				     struct nlattr *attr,
+				     struct wil_ftm_meas_params *params)
+{
+	struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_FTM_PARAM_MAX + 1];
+	int rc;
+
+	if (!attr) {
+		/* temporary defaults for one-shot measurement */
+		params->meas_per_burst = 1;
+		params->burst_period = 5; /* 500 milliseconds */
+		return 0;
+	}
+	rc = nla_parse_nested(tb, QCA_WLAN_VENDOR_ATTR_FTM_PARAM_MAX,
+			      attr, wil_nl80211_ftm_meas_param_policy);
+	if (rc) {
+		wil_err(wil, "invalid measurement params\n");
+		return rc;
+	}
+	if (tb[QCA_WLAN_VENDOR_ATTR_FTM_PARAM_MEAS_PER_BURST])
+		params->meas_per_burst = nla_get_u8(
+			tb[QCA_WLAN_VENDOR_ATTR_FTM_PARAM_MEAS_PER_BURST]);
+	if (tb[QCA_WLAN_VENDOR_ATTR_FTM_PARAM_NUM_BURSTS_EXP])
+		params->num_of_bursts_exp = nla_get_u8(
+			tb[QCA_WLAN_VENDOR_ATTR_FTM_PARAM_NUM_BURSTS_EXP]);
+	if (tb[QCA_WLAN_VENDOR_ATTR_FTM_PARAM_BURST_DURATION])
+		params->burst_duration = nla_get_u8(
+			tb[QCA_WLAN_VENDOR_ATTR_FTM_PARAM_BURST_DURATION]);
+	if (tb[QCA_WLAN_VENDOR_ATTR_FTM_PARAM_BURST_PERIOD])
+		params->burst_period = nla_get_u16(
+			tb[QCA_WLAN_VENDOR_ATTR_FTM_PARAM_BURST_PERIOD]);
+	return 0;
+}
+
+static int wil_ftm_validate_meas_params(struct wil6210_priv *wil,
+					struct wil_ftm_meas_params *params)
+{
+	/* temporary allow only single-burst */
+	if (params->meas_per_burst > WIL_FTM_MAX_MEAS_PER_BURST ||
+	    params->num_of_bursts_exp != 0) {
+		wil_err(wil, "invalid measurement params\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int wil_ftm_append_meas_params(struct wil6210_priv *wil,
+				      struct sk_buff *msg,
+				      struct wil_ftm_meas_params *params)
+{
+	struct nlattr *nl_p;
+
+	nl_p = nla_nest_start(
+		msg, QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_MEAS_PARAMS);
+	if (!nl_p)
+		goto out_put_failure;
+	if (nla_put_u8(msg, QCA_WLAN_VENDOR_ATTR_FTM_PARAM_MEAS_PER_BURST,
+		       params->meas_per_burst) ||
+	    nla_put_u8(msg, QCA_WLAN_VENDOR_ATTR_FTM_PARAM_NUM_BURSTS_EXP,
+		       params->num_of_bursts_exp) ||
+	    nla_put_u8(msg, QCA_WLAN_VENDOR_ATTR_FTM_PARAM_BURST_DURATION,
+		       params->burst_duration) ||
+	    nla_put_u16(msg, QCA_WLAN_VENDOR_ATTR_FTM_PARAM_BURST_PERIOD,
+			params->burst_period))
+		goto out_put_failure;
+	nla_nest_end(msg, nl_p);
+	return 0;
+out_put_failure:
+	return -ENOBUFS;
+}
+
+static int wil_ftm_append_peer_meas_res(struct wil6210_priv *wil,
+					struct sk_buff *msg,
+					struct wil_ftm_peer_meas_res *res)
+{
+	struct nlattr *nl_mres, *nl_f;
+	int i;
+
+	if (nla_put(msg, QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_MAC_ADDR,
+		    ETH_ALEN, res->mac_addr) ||
+	    nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_FLAGS,
+			res->flags) ||
+	    nla_put_u8(msg, QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_STATUS,
+		       res->status))
+		goto out_put_failure;
+	if (res->status == QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_STATUS_FAILED &&
+	    nla_put_u8(msg,
+		       QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_VALUE_SECONDS,
+		       res->value_seconds))
+		goto out_put_failure;
+	if (res->has_params &&
+	    wil_ftm_append_meas_params(wil, msg, &res->params))
+		goto out_put_failure;
+	nl_mres = nla_nest_start(msg, QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_MEAS);
+	if (!nl_mres)
+		goto out_put_failure;
+	for (i = 0; i < res->n_meas; i++) {
+		nl_f = nla_nest_start(msg, i);
+		if (!nl_f)
+			goto out_put_failure;
+		if (nla_put_u64_64bit(msg, QCA_WLAN_VENDOR_ATTR_FTM_MEAS_T1,
+				      res->meas[i].t1,
+				      QCA_WLAN_VENDOR_ATTR_FTM_MEAS_PAD) ||
+		    nla_put_u64_64bit(msg, QCA_WLAN_VENDOR_ATTR_FTM_MEAS_T2,
+				      res->meas[i].t2,
+				      QCA_WLAN_VENDOR_ATTR_FTM_MEAS_PAD) ||
+		    nla_put_u64_64bit(msg, QCA_WLAN_VENDOR_ATTR_FTM_MEAS_T3,
+				      res->meas[i].t3,
+				      QCA_WLAN_VENDOR_ATTR_FTM_MEAS_PAD) ||
+		    nla_put_u64_64bit(msg, QCA_WLAN_VENDOR_ATTR_FTM_MEAS_T4,
+				      res->meas[i].t4,
+				      QCA_WLAN_VENDOR_ATTR_FTM_MEAS_PAD))
+			goto out_put_failure;
+		nla_nest_end(msg, nl_f);
+	}
+	nla_nest_end(msg, nl_mres);
+	return 0;
+out_put_failure:
+	wil_err(wil, "fail to append peer result\n");
+	return -ENOBUFS;
+}
+
+static void wil_ftm_send_meas_result(struct wil6210_priv *wil,
+				     struct wil_ftm_peer_meas_res *res)
+{
+	struct sk_buff *vendor_event = NULL;
+	struct nlattr *nl_res;
+	int rc = 0;
+
+	wil_dbg_misc(wil, "sending %d results for peer %pM\n",
+		     res->n_meas, res->mac_addr);
+
+	vendor_event = cfg80211_vendor_event_alloc(
+				wil_to_wiphy(wil),
+				wil->wdev,
+				WIL_FTM_MEAS_RESULT_MAX_LENGTH,
+				QCA_NL80211_VENDOR_EVENT_FTM_MEAS_RESULT_INDEX,
+				GFP_KERNEL);
+	if (!vendor_event) {
+		wil_err(wil, "fail to allocate measurement result\n");
+		rc = -ENOMEM;
+		goto out;
+	}
+
+	if (nla_put_u64_64bit(
+		vendor_event, QCA_WLAN_VENDOR_ATTR_FTM_SESSION_COOKIE,
+		wil->ftm.session_cookie, QCA_WLAN_VENDOR_ATTR_PAD)) {
+		rc = -ENOBUFS;
+		goto out;
+	}
+
+	nl_res = nla_nest_start(vendor_event,
+				QCA_WLAN_VENDOR_ATTR_FTM_MEAS_PEER_RESULTS);
+	if (!nl_res) {
+		rc = -ENOBUFS;
+		goto out;
+	}
+
+	rc = wil_ftm_append_peer_meas_res(wil, vendor_event, res);
+	if (rc)
+		goto out;
+
+	nla_nest_end(vendor_event, nl_res);
+	cfg80211_vendor_event(vendor_event, GFP_KERNEL);
+	vendor_event = NULL;
+out:
+	if (vendor_event)
+		kfree_skb(vendor_event);
+	if (rc)
+		wil_err(wil, "send peer result failed, err %d\n", rc);
+}
+
+static void wil_ftm_send_peer_res(struct wil6210_priv *wil)
+{
+	if (!wil->ftm.has_ftm_res || !wil->ftm.ftm_res)
+		return;
+
+	wil_ftm_send_meas_result(wil, wil->ftm.ftm_res);
+	wil->ftm.has_ftm_res = 0;
+	wil->ftm.ftm_res->n_meas = 0;
+}
+
+static void wil_aoa_measurement_timeout(struct work_struct *work)
+{
+	struct wil_ftm_priv *ftm = container_of(work, struct wil_ftm_priv,
+						aoa_timeout_work);
+	struct wil6210_priv *wil = container_of(ftm, struct wil6210_priv, ftm);
+	struct wil_aoa_meas_result res;
+
+	wil_dbg_misc(wil, "AOA measurement timeout\n");
+
+	memset(&res, 0, sizeof(res));
+	ether_addr_copy(res.mac_addr, wil->ftm.aoa_peer_mac_addr);
+	res.type = wil->ftm.aoa_type;
+	res.status = QCA_WLAN_VENDOR_ATTR_LOC_SESSION_STATUS_ABORTED;
+	wil_aoa_cfg80211_meas_result(wil, &res);
+}
+
+static int
+wil_ftm_cfg80211_start_session(struct wil6210_priv *wil,
+			       struct wil_ftm_session_request *request)
+{
+	int rc = 0;
+	bool has_lci = false, has_lcr = false;
+	u8 max_meas = 0, channel, *ptr;
+	u32 i, cmd_len;
+	struct wmi_tof_session_start_cmd *cmd;
+
+	mutex_lock(&wil->ftm.lock);
+	if (wil->ftm.session_started) {
+		wil_err(wil, "FTM session already running\n");
+		rc = -EAGAIN;
+		goto out;
+	}
+
+	for (i = 0; i < request->n_peers; i++) {
+		if (request->peers[i].flags &
+		    QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_FLAG_LCI)
+			has_lci = true;
+		if (request->peers[i].flags &
+		    QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_FLAG_LCR)
+			has_lcr = true;
+		max_meas = max(max_meas,
+			       request->peers[i].params.meas_per_burst);
+	}
+
+	wil->ftm.ftm_res = kzalloc(sizeof(*wil->ftm.ftm_res) +
+		      max_meas * sizeof(struct wil_ftm_peer_meas) +
+		      (has_lci ? WIL_TOF_FTM_MAX_LCI_LENGTH : 0) +
+		      (has_lcr ? WIL_TOF_FTM_MAX_LCR_LENGTH : 0), GFP_KERNEL);
+	if (!wil->ftm.ftm_res) {
+		rc = -ENOMEM;
+		goto out;
+	}
+	ptr = (u8 *)wil->ftm.ftm_res;
+	ptr += sizeof(struct wil_ftm_peer_meas_res) +
+	       max_meas * sizeof(struct wil_ftm_peer_meas);
+	if (has_lci) {
+		wil->ftm.ftm_res->lci = ptr;
+		ptr += WIL_TOF_FTM_MAX_LCI_LENGTH;
+	}
+	if (has_lcr)
+		wil->ftm.ftm_res->lcr = ptr;
+	wil->ftm.max_ftm_meas = max_meas;
+
+	cmd_len = sizeof(struct wmi_tof_session_start_cmd) +
+		  request->n_peers * sizeof(struct wmi_ftm_dest_info);
+	cmd = kzalloc(cmd_len, GFP_KERNEL);
+	if (!cmd) {
+		rc = -ENOMEM;
+		goto out_ftm_res;
+	}
+
+	cmd->session_id = cpu_to_le32(WIL_FTM_FW_SESSION_ID);
+	cmd->num_of_dest = cpu_to_le16(request->n_peers);
+	for (i = 0; i < request->n_peers; i++) {
+		ether_addr_copy(cmd->ftm_dest_info[i].dst_mac,
+				request->peers[i].mac_addr);
+		channel = wil_ftm_get_channel(wil, request->peers[i].mac_addr,
+					      request->peers[i].freq);
+		if (!channel) {
+			wil_err(wil, "can't find FTM target at index %d\n", i);
+			rc = -EINVAL;
+			goto out_cmd;
+		}
+		cmd->ftm_dest_info[i].channel = channel - 1;
+		if (request->peers[i].flags &
+		    QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_FLAG_SECURE) {
+			cmd->ftm_dest_info[i].flags |=
+				WMI_TOF_SESSION_START_FLAG_SECURED;
+			cmd->ftm_dest_info[i].initial_token =
+				request->peers[i].secure_token_id;
+		} else {
+			cmd->ftm_dest_info[i].initial_token =
+				WIL_TOF_FTM_DEFAULT_INITIAL_TOKEN;
+		}
+		if (request->peers[i].flags &
+		    QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_FLAG_ASAP)
+			cmd->ftm_dest_info[i].flags |=
+				WMI_TOF_SESSION_START_FLAG_ASAP;
+		if (request->peers[i].flags &
+		    QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_FLAG_LCI)
+			cmd->ftm_dest_info[i].flags |=
+				WMI_TOF_SESSION_START_FLAG_LCI_REQ;
+		if (request->peers[i].flags &
+		    QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_FLAG_LCR)
+			cmd->ftm_dest_info[i].flags |=
+				WMI_TOF_SESSION_START_FLAG_LCR_REQ;
+		cmd->ftm_dest_info[i].num_of_ftm_per_burst =
+			request->peers[i].params.meas_per_burst;
+		cmd->ftm_dest_info[i].num_of_bursts_exp =
+			request->peers[i].params.num_of_bursts_exp;
+		cmd->ftm_dest_info[i].burst_duration =
+			request->peers[i].params.burst_duration;
+		cmd->ftm_dest_info[i].burst_period =
+			cpu_to_le16(request->peers[i].params.burst_period);
+	}
+
+	rc = wmi_send(wil, WMI_TOF_SESSION_START_CMDID, cmd, cmd_len);
+
+	if (!rc) {
+		wil->ftm.session_cookie = request->session_cookie;
+		wil->ftm.session_started = 1;
+	}
+out_cmd:
+	kfree(cmd);
+out_ftm_res:
+	if (rc) {
+		kfree(wil->ftm.ftm_res);
+		wil->ftm.ftm_res = NULL;
+	}
+out:
+	mutex_unlock(&wil->ftm.lock);
+	return rc;
+}
+
+static void
+wil_ftm_cfg80211_session_ended(struct wil6210_priv *wil, u32 status)
+{
+	struct sk_buff *vendor_event = NULL;
+
+	mutex_lock(&wil->ftm.lock);
+
+	if (!wil->ftm.session_started) {
+		wil_dbg_misc(wil, "FTM session not started, ignoring event\n");
+		goto out;
+	}
+
+	/* finish the session */
+	wil_dbg_misc(wil, "finishing FTM session\n");
+
+	/* send left-over results if any */
+	wil_ftm_send_peer_res(wil);
+
+	wil->ftm.session_started = 0;
+	kfree(wil->ftm.ftm_res);
+	wil->ftm.ftm_res = NULL;
+
+	vendor_event = cfg80211_vendor_event_alloc(
+		wil_to_wiphy(wil),
+		wil->wdev,
+		WIL_FTM_NL_EXTRA_ALLOC,
+		QCA_NL80211_VENDOR_EVENT_FTM_SESSION_DONE_INDEX,
+		GFP_KERNEL);
+	if (!vendor_event)
+		goto out;
+
+	if (nla_put_u64_64bit(vendor_event,
+			      QCA_WLAN_VENDOR_ATTR_FTM_SESSION_COOKIE,
+			      wil->ftm.session_cookie,
+			      QCA_WLAN_VENDOR_ATTR_PAD) ||
+	    nla_put_u32(vendor_event,
+			QCA_WLAN_VENDOR_ATTR_LOC_SESSION_STATUS, status)) {
+		wil_err(wil, "failed to fill session done event\n");
+		goto out;
+	}
+	cfg80211_vendor_event(vendor_event, GFP_KERNEL);
+	vendor_event = NULL;
+out:
+	kfree_skb(vendor_event);
+	mutex_unlock(&wil->ftm.lock);
+}
+
+static void wil_aoa_timer_fn(ulong x)
+{
+	struct wil6210_priv *wil = (void *)x;
+
+	wil_dbg_misc(wil, "AOA timer\n");
+	schedule_work(&wil->ftm.aoa_timeout_work);
+}
+
+static int
+wil_aoa_cfg80211_start_measurement(struct wil6210_priv *wil,
+				   struct wil_aoa_meas_request *request)
+{
+	int rc = 0;
+	struct wmi_aoa_meas_cmd cmd;
+	u8 channel;
+
+	mutex_lock(&wil->ftm.lock);
+
+	if (wil->ftm.aoa_started) {
+		wil_err(wil, "AOA measurement already running\n");
+		rc = -EAGAIN;
+		goto out;
+	}
+	if (request->type >= QCA_WLAN_VENDOR_ATTR_AOA_TYPE_MAX) {
+		wil_err(wil, "invalid AOA type: %d\n", request->type);
+		rc = -EINVAL;
+		goto out;
+	}
+
+	channel = wil_ftm_get_channel(wil, request->mac_addr, request->freq);
+	if (!channel) {
+		rc = -EINVAL;
+		goto out;
+	}
+
+	memset(&cmd, 0, sizeof(cmd));
+	ether_addr_copy(cmd.mac_addr, request->mac_addr);
+	cmd.channel = channel - 1;
+	cmd.aoa_meas_type = request->type;
+
+	rc = wmi_send(wil, WMI_AOA_MEAS_CMDID, &cmd, sizeof(cmd));
+	if (rc)
+		goto out;
+
+	ether_addr_copy(wil->ftm.aoa_peer_mac_addr, request->mac_addr);
+	mod_timer(&wil->ftm.aoa_timer,
+		  jiffies + msecs_to_jiffies(WIL_AOA_MEASUREMENT_TIMEOUT));
+	wil->ftm.aoa_started = 1;
+out:
+	mutex_unlock(&wil->ftm.lock);
+	return rc;
+}
+
+void wil_aoa_cfg80211_meas_result(struct wil6210_priv *wil,
+				  struct wil_aoa_meas_result *result)
+{
+	struct sk_buff *vendor_event = NULL;
+
+	mutex_lock(&wil->ftm.lock);
+
+	if (!wil->ftm.aoa_started) {
+		wil_info(wil, "AOA not started, not sending result\n");
+		goto out;
+	}
+
+	wil_dbg_misc(wil, "sending AOA measurement result\n");
+
+	vendor_event = cfg80211_vendor_event_alloc(
+				wil_to_wiphy(wil),
+				wil->wdev,
+				result->length + WIL_FTM_NL_EXTRA_ALLOC,
+				QCA_NL80211_VENDOR_EVENT_AOA_MEAS_RESULT_INDEX,
+				GFP_KERNEL);
+	if (!vendor_event) {
+		wil_err(wil, "fail to allocate measurement result\n");
+		goto out;
+	}
+
+	if (nla_put(vendor_event, QCA_WLAN_VENDOR_ATTR_MAC_ADDR,
+		    ETH_ALEN, result->mac_addr) ||
+	    nla_put_u32(vendor_event, QCA_WLAN_VENDOR_ATTR_AOA_TYPE,
+			result->type) ||
+	    nla_put_u32(vendor_event, QCA_WLAN_VENDOR_ATTR_LOC_SESSION_STATUS,
+			result->status) ||
+	    nla_put_u32(vendor_event,
+			QCA_WLAN_VENDOR_ATTR_LOC_ANTENNA_ARRAY_MASK,
+			result->antenna_array_mask)) {
+		wil_err(wil, "failed to fill vendor event\n");
+		goto out;
+	}
+
+	if (result->length > 0 &&
+	    nla_put(vendor_event, QCA_WLAN_VENDOR_ATTR_AOA_MEAS_RESULT,
+		    result->length, result->data)) {
+		wil_err(wil, "failed to fill vendor event with AOA data\n");
+		goto out;
+	}
+
+	cfg80211_vendor_event(vendor_event, GFP_KERNEL);
+
+	del_timer_sync(&wil->ftm.aoa_timer);
+	wil->ftm.aoa_started = 0;
+out:
+	mutex_unlock(&wil->ftm.lock);
+}
+
+void wil_ftm_evt_session_ended(struct wil6210_priv *wil,
+			       struct wmi_tof_session_end_event *evt)
+{
+	u32 status;
+
+	switch (evt->status) {
+	case WMI_TOF_SESSION_END_NO_ERROR:
+		status = QCA_WLAN_VENDOR_ATTR_LOC_SESSION_STATUS_OK;
+		break;
+	case WMI_TOF_SESSION_END_PARAMS_ERROR:
+		status = QCA_WLAN_VENDOR_ATTR_LOC_SESSION_STATUS_INVALID;
+		break;
+	case WMI_TOF_SESSION_END_FAIL:
+		status = QCA_WLAN_VENDOR_ATTR_LOC_SESSION_STATUS_FAILED;
+		break;
+	case WMI_TOF_SESSION_END_ABORTED:
+		status = QCA_WLAN_VENDOR_ATTR_LOC_SESSION_STATUS_ABORTED;
+		break;
+	default:
+		status = QCA_WLAN_VENDOR_ATTR_LOC_SESSION_STATUS_FAILED;
+		break;
+	}
+
+	wil_ftm_cfg80211_session_ended(wil, status);
+}
+
+void wil_ftm_evt_per_dest_res(struct wil6210_priv *wil,
+			      struct wmi_tof_ftm_per_dest_res_event *evt)
+{
+	u32 i, index;
+	__le64 tmp = 0;
+	u8 n_meas;
+
+	mutex_lock(&wil->ftm.lock);
+
+	if (!wil->ftm.session_started || !wil->ftm.ftm_res) {
+		wil_dbg_misc(wil, "Session not running, ignoring res event\n");
+		goto out;
+	}
+	if (wil->ftm.has_ftm_res &&
+	    !ether_addr_equal(evt->dst_mac, wil->ftm.ftm_res->mac_addr)) {
+		wil_dbg_misc(wil,
+			     "Results for previous peer not properly terminated\n");
+		wil_ftm_send_peer_res(wil);
+	}
+
+	if (!wil->ftm.has_ftm_res) {
+		ether_addr_copy(wil->ftm.ftm_res->mac_addr, evt->dst_mac);
+		wil->ftm.has_ftm_res = 1;
+	}
+
+	n_meas = evt->actual_ftm_per_burst;
+	switch (evt->status) {
+	case WMI_PER_DEST_RES_NO_ERROR:
+		wil->ftm.ftm_res->status =
+			QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_STATUS_OK;
+		break;
+	case WMI_PER_DEST_RES_TX_RX_FAIL:
+		/* FW reports corrupted results here, discard. */
+		n_meas = 0;
+		wil->ftm.ftm_res->status =
+			QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_STATUS_OK;
+		break;
+	case WMI_PER_DEST_RES_PARAM_DONT_MATCH:
+		wil->ftm.ftm_res->status =
+			QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_STATUS_INVALID;
+		break;
+	default:
+		wil_err(wil, "unexpected status %d\n", evt->status);
+		wil->ftm.ftm_res->status =
+			QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_STATUS_INVALID;
+		break;
+	}
+
+	for (i = 0; i < n_meas; i++) {
+		index = wil->ftm.ftm_res->n_meas;
+		if (index >= wil->ftm.max_ftm_meas) {
+			wil_dbg_misc(wil, "Too many measurements, some lost\n");
+			break;
+		}
+		memcpy(&tmp, evt->responder_ftm_res[i].t1,
+		       sizeof(evt->responder_ftm_res[i].t1));
+		wil->ftm.ftm_res->meas[index].t1 = le64_to_cpu(tmp);
+		memcpy(&tmp, evt->responder_ftm_res[i].t2,
+		       sizeof(evt->responder_ftm_res[i].t2));
+		wil->ftm.ftm_res->meas[index].t2 = le64_to_cpu(tmp);
+		memcpy(&tmp, evt->responder_ftm_res[i].t3,
+		       sizeof(evt->responder_ftm_res[i].t3));
+		wil->ftm.ftm_res->meas[index].t3 = le64_to_cpu(tmp);
+		memcpy(&tmp, evt->responder_ftm_res[i].t4,
+		       sizeof(evt->responder_ftm_res[i].t4));
+		wil->ftm.ftm_res->meas[index].t4 = le64_to_cpu(tmp);
+		wil->ftm.ftm_res->n_meas++;
+	}
+
+	if (evt->flags & WMI_PER_DEST_RES_BURST_REPORT_END)
+		wil_ftm_send_peer_res(wil);
+out:
+	mutex_unlock(&wil->ftm.lock);
+}
+
+void wil_aoa_evt_meas(struct wil6210_priv *wil,
+		      struct wmi_aoa_meas_event *evt,
+		      int len)
+{
+	int data_len = len - offsetof(struct wmi_aoa_meas_event, meas_data);
+	struct wil_aoa_meas_result *res;
+
+	data_len = min_t(int, le16_to_cpu(evt->length), data_len);
+
+	res = kmalloc(sizeof(*res) + data_len, GFP_KERNEL);
+	if (!res)
+		return;
+
+	ether_addr_copy(res->mac_addr, evt->mac_addr);
+	res->type = evt->aoa_meas_type;
+	res->antenna_array_mask = le32_to_cpu(evt->meas_rf_mask);
+	res->status = evt->meas_status;
+	res->length = data_len;
+	memcpy(res->data, evt->meas_data, data_len);
+
+	wil_dbg_misc(wil, "AOA result status %d type %d mask %d length %d\n",
+		     res->status, res->type,
+		     res->antenna_array_mask, res->length);
+
+	wil_aoa_cfg80211_meas_result(wil, res);
+	kfree(res);
+}
+
+int wil_ftm_get_capabilities(struct wiphy *wiphy, struct wireless_dev *wdev,
+			     const void *data, int data_len)
+{
+	struct wil6210_priv *wil = wiphy_to_wil(wiphy);
+	struct sk_buff *skb;
+	struct nlattr *attr;
+
+	if (!test_bit(WMI_FW_CAPABILITY_FTM, wil->fw_capabilities))
+		return -ENOTSUPP;
+
+	/* we should get the capabilities from the FW. for now,
+	 * report dummy capabilities for one shot measurement
+	 */
+	skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, 128);
+	if (!skb)
+		return -ENOMEM;
+	attr = nla_nest_start(skb, QCA_WLAN_VENDOR_ATTR_LOC_CAPA);
+	if (!attr ||
+	    nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LOC_CAPA_FLAGS,
+			QCA_WLAN_VENDOR_ATTR_LOC_CAPA_FLAG_FTM_RESPONDER |
+			QCA_WLAN_VENDOR_ATTR_LOC_CAPA_FLAG_FTM_INITIATOR |
+			QCA_WLAN_VENDOR_ATTR_LOC_CAPA_FLAG_ASAP |
+			QCA_WLAN_VENDOR_ATTR_LOC_CAPA_FLAG_AOA) ||
+	    nla_put_u16(skb, QCA_WLAN_VENDOR_ATTR_FTM_CAPA_MAX_NUM_SESSIONS,
+			1) ||
+	    nla_put_u16(skb, QCA_WLAN_VENDOR_ATTR_FTM_CAPA_MAX_NUM_PEERS, 1) ||
+	    nla_put_u8(skb, QCA_WLAN_VENDOR_ATTR_FTM_CAPA_MAX_NUM_BURSTS_EXP,
+		       0) ||
+	    nla_put_u8(skb, QCA_WLAN_VENDOR_ATTR_FTM_CAPA_MAX_MEAS_PER_BURST,
+		       4) ||
+	    nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_AOA_CAPA_SUPPORTED_TYPES,
+			BIT(QCA_WLAN_VENDOR_ATTR_AOA_TYPE_TOP_CIR_PHASE))) {
+		wil_err(wil, "fail to fill get_capabilities reply\n");
+		kfree_skb(skb);
+		return -ENOMEM;
+	}
+	nla_nest_end(skb, attr);
+
+	return cfg80211_vendor_cmd_reply(skb);
+}
+
+int wil_ftm_start_session(struct wiphy *wiphy, struct wireless_dev *wdev,
+			  const void *data, int data_len)
+{
+	struct wil6210_priv *wil = wiphy_to_wil(wiphy);
+	struct wil_ftm_session_request *request;
+	struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_LOC_MAX + 1];
+	struct nlattr *tb2[QCA_WLAN_VENDOR_ATTR_FTM_PEER_MAX + 1];
+	struct nlattr *peer;
+	int rc, n_peers = 0, index = 0, tmp;
+
+	if (!test_bit(WMI_FW_CAPABILITY_FTM, wil->fw_capabilities))
+		return -ENOTSUPP;
+
+	rc = nla_parse(tb, QCA_WLAN_VENDOR_ATTR_LOC_MAX, data, data_len,
+		       wil_nl80211_loc_policy);
+	if (rc) {
+		wil_err(wil, "Invalid ATTR\n");
+		return rc;
+	}
+
+	if (!tb[QCA_WLAN_VENDOR_ATTR_FTM_MEAS_PEERS]) {
+		wil_err(wil, "no peers specified\n");
+		return -EINVAL;
+	}
+
+	if (!tb[QCA_WLAN_VENDOR_ATTR_FTM_SESSION_COOKIE]) {
+		wil_err(wil, "session cookie not specified\n");
+		return -EINVAL;
+	}
+
+	nla_for_each_nested(peer, tb[QCA_WLAN_VENDOR_ATTR_FTM_MEAS_PEERS],
+			    tmp)
+		n_peers++;
+
+	if (!n_peers) {
+		wil_err(wil, "empty peer list\n");
+		return -EINVAL;
+	}
+
+	/* for now only allow measurement for a single peer */
+	if (n_peers != 1) {
+		wil_err(wil, "only single peer allowed\n");
+		return -EINVAL;
+	}
+
+	request = kzalloc(sizeof(*request) +
+			  n_peers * sizeof(struct wil_ftm_meas_peer_info),
+			  GFP_KERNEL);
+	if (!request)
+		return -ENOMEM;
+
+	request->session_cookie =
+		nla_get_u64(tb[QCA_WLAN_VENDOR_ATTR_FTM_SESSION_COOKIE]);
+	request->n_peers = n_peers;
+	nla_for_each_nested(peer, tb[QCA_WLAN_VENDOR_ATTR_FTM_MEAS_PEERS],
+			    tmp) {
+		rc = nla_parse_nested(tb2, QCA_WLAN_VENDOR_ATTR_FTM_PEER_MAX,
+				      peer, wil_nl80211_ftm_peer_policy);
+		if (rc) {
+			wil_err(wil, "Invalid peer ATTR\n");
+			goto out;
+		}
+		if (!tb2[QCA_WLAN_VENDOR_ATTR_FTM_PEER_MAC_ADDR] ||
+		    nla_len(tb2[QCA_WLAN_VENDOR_ATTR_FTM_PEER_MAC_ADDR])
+			    != ETH_ALEN) {
+			wil_err(wil, "Peer MAC address missing or invalid\n");
+			rc = -EINVAL;
+			goto out;
+		}
+		memcpy(request->peers[index].mac_addr,
+		       nla_data(tb2[QCA_WLAN_VENDOR_ATTR_FTM_PEER_MAC_ADDR]),
+		       ETH_ALEN);
+		if (tb2[QCA_WLAN_VENDOR_ATTR_FTM_PEER_FREQ])
+			request->peers[index].freq = nla_get_u32(
+				tb2[QCA_WLAN_VENDOR_ATTR_FTM_PEER_FREQ]);
+		if (tb2[QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_FLAGS])
+			request->peers[index].flags = nla_get_u32(
+				tb2[QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_FLAGS]);
+		if (tb2[QCA_WLAN_VENDOR_ATTR_FTM_PEER_SECURE_TOKEN_ID])
+			request->peers[index].secure_token_id = nla_get_u8(
+			   tb2[QCA_WLAN_VENDOR_ATTR_FTM_PEER_SECURE_TOKEN_ID]);
+		rc = wil_ftm_parse_meas_params(
+			wil,
+			tb2[QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_PARAMS],
+			&request->peers[index].params);
+		if (!rc)
+			rc = wil_ftm_validate_meas_params(
+				wil, &request->peers[index].params);
+		if (rc)
+			goto out;
+		index++;
+	}
+
+	rc = wil_ftm_cfg80211_start_session(wil, request);
+out:
+	kfree(request);
+	return rc;
+}
+
+int wil_ftm_abort_session(struct wiphy *wiphy, struct wireless_dev *wdev,
+			  const void *data, int data_len)
+{
+	struct wil6210_priv *wil = wiphy_to_wil(wiphy);
+
+	wil_dbg_misc(wil, "stub\n");
+	return -ENOTSUPP;
+}
+
+int wil_ftm_configure_responder(struct wiphy *wiphy, struct wireless_dev *wdev,
+				const void *data, int data_len)
+{
+	struct wil6210_priv *wil = wiphy_to_wil(wiphy);
+
+	wil_dbg_misc(wil, "stub\n");
+	return -ENOTSUPP;
+}
+
+int wil_aoa_start_measurement(struct wiphy *wiphy, struct wireless_dev *wdev,
+			      const void *data, int data_len)
+{
+	struct wil6210_priv *wil = wiphy_to_wil(wiphy);
+	struct wil_aoa_meas_request request;
+	struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_LOC_MAX + 1];
+	int rc;
+
+	if (!test_bit(WMI_FW_CAPABILITY_FTM, wil->fw_capabilities))
+		return -ENOTSUPP;
+
+	wil_dbg_misc(wil, "AOA start measurement\n");
+
+	rc = nla_parse(tb, QCA_WLAN_VENDOR_ATTR_LOC_MAX, data, data_len,
+		       wil_nl80211_loc_policy);
+	if (rc) {
+		wil_err(wil, "Invalid ATTR\n");
+		return rc;
+	}
+
+	if (!tb[QCA_WLAN_VENDOR_ATTR_MAC_ADDR] ||
+	    !tb[QCA_WLAN_VENDOR_ATTR_AOA_TYPE]) {
+		wil_err(wil, "Must specify MAC address and type\n");
+		return -EINVAL;
+	}
+
+	memset(&request, 0, sizeof(request));
+	ether_addr_copy(request.mac_addr,
+			nla_data(tb[QCA_WLAN_VENDOR_ATTR_MAC_ADDR]));
+	request.type = nla_get_u32(tb[QCA_WLAN_VENDOR_ATTR_AOA_TYPE]);
+	if (tb[QCA_WLAN_VENDOR_ATTR_FREQ])
+		request.freq = nla_get_u32(tb[QCA_WLAN_VENDOR_ATTR_FREQ]);
+
+	rc = wil_aoa_cfg80211_start_measurement(wil, &request);
+	return rc;
+}
+
+int wil_aoa_abort_measurement(struct wiphy *wiphy, struct wireless_dev *wdev,
+			      const void *data, int data_len)
+{
+	struct wil6210_priv *wil = wiphy_to_wil(wiphy);
+
+	wil_dbg_misc(wil, "stub\n");
+	return -ENOTSUPP;
+}
+
+void wil_ftm_init(struct wil6210_priv *wil)
+{
+	mutex_init(&wil->ftm.lock);
+	setup_timer(&wil->ftm.aoa_timer, wil_aoa_timer_fn, (ulong)wil);
+	INIT_WORK(&wil->ftm.aoa_timeout_work, wil_aoa_measurement_timeout);
+}
+
+void wil_ftm_deinit(struct wil6210_priv *wil)
+{
+	del_timer_sync(&wil->ftm.aoa_timer);
+	cancel_work_sync(&wil->ftm.aoa_timeout_work);
+	kfree(wil->ftm.ftm_res);
+}
+
+void wil_ftm_stop_operations(struct wil6210_priv *wil)
+{
+	wil_ftm_cfg80211_session_ended(
+		wil, QCA_WLAN_VENDOR_ATTR_LOC_SESSION_STATUS_ABORTED);
+}
diff --git a/drivers/net/wireless/ath/wil6210/ftm.h b/drivers/net/wireless/ath/wil6210/ftm.h
new file mode 100644
index 0000000..8efa292
--- /dev/null
+++ b/drivers/net/wireless/ath/wil6210/ftm.h
@@ -0,0 +1,520 @@
+/*
+ * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef __WIL6210_FTM_H__
+#define __WIL6210_FTM_H__
+
+/**
+ * NOTE: The authoritative place for definition of QCA_NL80211_VENDOR_ID,
+ * vendor subcmd definitions prefixed with QCA_NL80211_VENDOR_SUBCMD, and
+ * qca_wlan_vendor_attr is open source file src/common/qca-vendor.h in
+ * git://w1.fi/srv/git/hostap.git; the values here are just a copy of that
+ */
+
+/**
+ * enum qca_vendor_attr_loc - attributes for FTM and AOA commands
+ *
+ * @QCA_WLAN_VENDOR_ATTR_FTM_SESSION_COOKIE: Session cookie, specified in
+ *  %QCA_NL80211_VENDOR_SUBCMD_FTM_START_SESSION. It will be provided by driver
+ *  events and can be used to identify events targeted for this session.
+ * @QCA_WLAN_VENDOR_ATTR_LOC_CAPA: Nested attribute containing extra
+ *  FTM/AOA capabilities, returned by %QCA_NL80211_VENDOR_SUBCMD_LOC_GET_CAPA.
+ *  see %enum qca_wlan_vendor_attr_loc_capa.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_MEAS_PEERS: array of nested attributes
+ *  containing information about each peer in measurement session
+ *  request. See %enum qca_wlan_vendor_attr_peer_info for supported
+ *  attributes for each peer
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_RESULTS: nested attribute containing
+ *  measurement results for a peer. reported by the
+ *  %QCA_NL80211_VENDOR_SUBCMD_FTM_MEAS_RESULT event.
+ *  See %enum qca_wlan_vendor_attr_peer_result for list of supported
+ *  attributes.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_RESPONDER_ENABLE: flag attribute for
+ *  enabling or disabling responder functionality.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_LCI: used in the
+ *  %QCA_NL80211_VENDOR_SUBCMD_FTM_CFG_RESPONDER command in order to
+ *  specify the LCI report that will be sent by the responder during
+ *  a measurement exchange. The format is defined in IEEE P802.11-REVmc/D5.0,
+ *  9.4.2.22.10
+ * @QCA_WLAN_VENDOR_ATTR_FTM_LCR: provided with the
+ *  %QCA_NL80211_VENDOR_SUBCMD_FTM_CFG_RESPONDER command in order to
+ *  specify the location civic report that will be sent by the responder during
+ *  a measurement exchange. The format is defined in IEEE P802.11-REVmc/D5.0,
+ *  9.4.2.22.13
+ * @QCA_WLAN_VENDOR_ATTR_LOC_SESSION_STATUS: session/measurement completion
+ *  status code, reported in %QCA_NL80211_VENDOR_SUBCMD_FTM_SESSION_DONE
+ *  and %QCA_NL80211_VENDOR_SUBCMD_AOA_MEAS_RESULT
+ * @QCA_WLAN_VENDOR_ATTR_FTM_INITIAL_TOKEN: initial dialog token used
+ *  by responder (0 if not specified)
+ * @QCA_WLAN_VENDOR_ATTR_AOA_TYPE: AOA measurement type. Requested in
+ *  %QCA_NL80211_VENDOR_SUBCMD_AOA_MEAS and optionally in
+ *  %QCA_NL80211_VENDOR_SUBCMD_FTM_START_SESSION if AOA measurements
+ *  are needed as part of an FTM session.
+ *  Reported by QCA_NL80211_VENDOR_SUBCMD_AOA_MEAS_RESULT.
+ *  See enum qca_wlan_vendor_attr_aoa_type.
+ * @QCA_WLAN_VENDOR_ATTR_LOC_ANTENNA_ARRAY_MASK: bit mask indicating
+ *  which antenna arrays were used in location measurement.
+ *  Reported in %QCA_NL80211_VENDOR_SUBCMD_FTM_MEAS_RESULT and
+ *  %QCA_NL80211_VENDOR_SUBCMD_AOA_MEAS_RESULT
+ * @QCA_WLAN_VENDOR_ATTR_AOA_MEAS_RESULT: AOA measurement data.
+ *  Its contents depends on the AOA type and antenna array mask:
+ *  %QCA_WLAN_VENDOR_ATTR_AOA_TYPE_TOP_CIR_PHASE: array of U16 values,
+ *  phase of the strongest CIR path for each antenna in the measured
+ *  array(s).
+ *  %QCA_WLAN_VENDOR_ATTR_AOA_TYPE_TOP_CIR_PHASE_AMP: array of 2 U16
+ *  values, phase and amplitude of the strongest CIR path for each
+ *  antenna in the measured array(s)
+ * @QCA_WLAN_VENDOR_ATTR_FREQ: Frequency where peer is listening, in MHz.
+ *  Unsigned 32 bit value.
+ */
+enum qca_wlan_vendor_attr_loc {
+	/* we reuse these attributes */
+	QCA_WLAN_VENDOR_ATTR_MAC_ADDR = 6,
+	QCA_WLAN_VENDOR_ATTR_PAD = 13,
+	QCA_WLAN_VENDOR_ATTR_FTM_SESSION_COOKIE = 14,
+	QCA_WLAN_VENDOR_ATTR_LOC_CAPA = 15,
+	QCA_WLAN_VENDOR_ATTR_FTM_MEAS_PEERS = 16,
+	QCA_WLAN_VENDOR_ATTR_FTM_MEAS_PEER_RESULTS = 17,
+	QCA_WLAN_VENDOR_ATTR_FTM_RESPONDER_ENABLE = 18,
+	QCA_WLAN_VENDOR_ATTR_FTM_LCI = 19,
+	QCA_WLAN_VENDOR_ATTR_FTM_LCR = 20,
+	QCA_WLAN_VENDOR_ATTR_LOC_SESSION_STATUS = 21,
+	QCA_WLAN_VENDOR_ATTR_FTM_INITIAL_TOKEN = 22,
+	QCA_WLAN_VENDOR_ATTR_AOA_TYPE = 23,
+	QCA_WLAN_VENDOR_ATTR_LOC_ANTENNA_ARRAY_MASK = 24,
+	QCA_WLAN_VENDOR_ATTR_AOA_MEAS_RESULT = 25,
+	QCA_WLAN_VENDOR_ATTR_FREQ = 28,
+	/* keep last */
+	QCA_WLAN_VENDOR_ATTR_LOC_AFTER_LAST,
+	QCA_WLAN_VENDOR_ATTR_LOC_MAX = QCA_WLAN_VENDOR_ATTR_LOC_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_loc_capa - indoor location capabilities
+ *
+ * @QCA_WLAN_VENDOR_ATTR_LOC_CAPA_FLAGS: various flags. See
+ *  %enum qca_wlan_vendor_attr_loc_capa_flags
+ * @QCA_WLAN_VENDOR_ATTR_FTM_CAPA_MAX_NUM_SESSIONS: Maximum number
+ *  of measurement sessions that can run concurrently.
+ *  Default is one session (no session concurrency)
+ * @QCA_WLAN_VENDOR_ATTR_FTM_CAPA_MAX_NUM_PEERS: The total number of unique
+ *  peers that are supported in running sessions. For example,
+ *  if the value is 8 and maximum number of sessions is 2, you can
+ *  have one session with 8 unique peers, or 2 sessions with 4 unique
+ *  peers each, and so on.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_CAPA_MAX_NUM_BURSTS_EXP: Maximum number
+ *  of bursts per peer, as an exponent (2^value). Default is 0,
+ *  meaning no multi-burst support.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_CAPA_MAX_MEAS_PER_BURST: Maximum number
+ *  of measurement exchanges allowed in a single burst
+ * @QCA_WLAN_VENDOR_ATTR_AOA_CAPA_SUPPORTED_TYPES: Supported AOA measurement
+ *  types. A bit mask (unsigned 32 bit value), each bit corresponds
+ *  to an AOA type as defined by %enum qca_vendor_attr_aoa_type.
+ */
+enum qca_wlan_vendor_attr_loc_capa {
+	QCA_WLAN_VENDOR_ATTR_LOC_CAPA_INVALID,
+	QCA_WLAN_VENDOR_ATTR_LOC_CAPA_FLAGS,
+	QCA_WLAN_VENDOR_ATTR_FTM_CAPA_MAX_NUM_SESSIONS,
+	QCA_WLAN_VENDOR_ATTR_FTM_CAPA_MAX_NUM_PEERS,
+	QCA_WLAN_VENDOR_ATTR_FTM_CAPA_MAX_NUM_BURSTS_EXP,
+	QCA_WLAN_VENDOR_ATTR_FTM_CAPA_MAX_MEAS_PER_BURST,
+	QCA_WLAN_VENDOR_ATTR_AOA_CAPA_SUPPORTED_TYPES,
+	/* keep last */
+	QCA_WLAN_VENDOR_ATTR_LOC_CAPA_AFTER_LAST,
+	QCA_WLAN_VENDOR_ATTR_LOC_CAPA_MAX =
+		QCA_WLAN_VENDOR_ATTR_LOC_CAPA_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_loc_capa_flags: Indoor location capability flags
+ *
+ * @QCA_WLAN_VENDOR_ATTR_LOC_CAPA_FLAG_FTM_RESPONDER: Set if driver
+ *  can be configured as an FTM responder (for example, an AP that
+ *  services FTM requests). %QCA_NL80211_VENDOR_SUBCMD_FTM_CFG_RESPONDER
+ *  will be supported if set.
+ * @QCA_WLAN_VENDOR_ATTR_LOC_CAPA_FLAG_FTM_INITIATOR: Set if driver
+ *  can run FTM sessions. %QCA_NL80211_VENDOR_SUBCMD_FTM_START_SESSION
+ *  will be supported if set.
+ * @QCA_WLAN_VENDOR_ATTR_LOC_CAPA_FLAG_ASAP: Set if FTM responder
+ *  supports immediate (ASAP) response.
+ * @QCA_WLAN_VENDOR_ATTR_LOC_CAPA_FLAG_AOA: Set if driver supports standalone
+ *  AOA measurement using %QCA_NL80211_VENDOR_SUBCMD_AOA_MEAS
+ * @QCA_WLAN_VENDOR_ATTR_LOC_CAPA_FLAG_AOA_IN_FTM: Set if driver supports
+ *  requesting AOA measurements as part of an FTM session.
+ */
+enum qca_wlan_vendor_attr_loc_capa_flags {
+	QCA_WLAN_VENDOR_ATTR_LOC_CAPA_FLAG_FTM_RESPONDER = 1 << 0,
+	QCA_WLAN_VENDOR_ATTR_LOC_CAPA_FLAG_FTM_INITIATOR = 1 << 1,
+	QCA_WLAN_VENDOR_ATTR_LOC_CAPA_FLAG_ASAP = 1 << 2,
+	QCA_WLAN_VENDOR_ATTR_LOC_CAPA_FLAG_AOA = 1 << 3,
+	QCA_WLAN_VENDOR_ATTR_LOC_CAPA_FLAG_AOA_IN_FTM = 1 << 4,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_peer_info: information about
+ *  a single peer in a measurement session.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_MAC_ADDR: The MAC address of the peer.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_FLAGS: Various flags related
+ *  to measurement. See %enum qca_wlan_vendor_attr_ftm_peer_meas_flags.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_PARAMS: Nested attribute of
+ *  FTM measurement parameters, as specified by IEEE P802.11-REVmc/D7.0,
+ *  9.4.2.167. See %enum qca_wlan_vendor_attr_ftm_meas_param for
+ *  list of supported attributes.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_SECURE_TOKEN_ID: Initial token ID for
+ *  secure measurement
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_AOA_BURST_PERIOD: Request AOA
+ *  measurement every _value_ bursts. If 0 or not specified,
+ *  AOA measurements will be disabled for this peer.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_FREQ: Frequency in MHz where
+ *  peer is listening. Optional; if not specified, use the
+ *  entry from the kernel scan results cache.
+ */
+enum qca_wlan_vendor_attr_ftm_peer_info {
+	QCA_WLAN_VENDOR_ATTR_FTM_PEER_INVALID,
+	QCA_WLAN_VENDOR_ATTR_FTM_PEER_MAC_ADDR,
+	QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_FLAGS,
+	QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_PARAMS,
+	QCA_WLAN_VENDOR_ATTR_FTM_PEER_SECURE_TOKEN_ID,
+	QCA_WLAN_VENDOR_ATTR_FTM_PEER_AOA_BURST_PERIOD,
+	QCA_WLAN_VENDOR_ATTR_FTM_PEER_FREQ,
+	/* keep last */
+	QCA_WLAN_VENDOR_ATTR_FTM_PEER_AFTER_LAST,
+	QCA_WLAN_VENDOR_ATTR_FTM_PEER_MAX =
+		QCA_WLAN_VENDOR_ATTR_FTM_PEER_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_ftm_peer_meas_flags: Measurement request flags,
+ *  per-peer
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_FLAG_ASAP: If set, request
+ *  immediate (ASAP) response from peer
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_FLAG_LCI: If set, request
+ *  LCI report from peer. The LCI report includes the absolute
+ *  location of the peer in "official" coordinates (similar to GPS).
+ *  See IEEE P802.11-REVmc/D7.0, 11.24.6.7 for more information.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_FLAG_LCR: If set, request
+ *  Location civic report from peer. The LCR includes the location
+ *  of the peer in free-form format. See IEEE P802.11-REVmc/D7.0,
+ *  11.24.6.7 for more information.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_FLAG_SECURE: If set,
+ *  request a secure measurement.
+ *  %QCA_WLAN_VENDOR_ATTR_FTM_PEER_SECURE_TOKEN_ID must also be provided.
+ */
+enum qca_wlan_vendor_attr_ftm_peer_meas_flags {
+	QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_FLAG_ASAP	= 1 << 0,
+	QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_FLAG_LCI	= 1 << 1,
+	QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_FLAG_LCR	= 1 << 2,
+	QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_FLAG_SECURE  = 1 << 3,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_ftm_meas_param: Measurement parameters
+ *
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PARAM_MEAS_PER_BURST: Number of measurements
+ *  to perform in a single burst.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PARAM_NUM_BURSTS_EXP: Number of bursts to
+ *  perform, specified as an exponent (2^value)
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PARAM_BURST_DURATION: Duration of burst
+ *  instance, as specified in IEEE P802.11-REVmc/D7.0, 9.4.2.167
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PARAM_BURST_PERIOD: Time between bursts,
+ *  as specified in IEEE P802.11-REVmc/D7.0, 9.4.2.167. Must
+ *  be larger than %QCA_WLAN_VENDOR_ATTR_FTM_PARAM_BURST_DURATION
+ */
+enum qca_wlan_vendor_attr_ftm_meas_param {
+	QCA_WLAN_VENDOR_ATTR_FTM_PARAM_INVALID,
+	QCA_WLAN_VENDOR_ATTR_FTM_PARAM_MEAS_PER_BURST,
+	QCA_WLAN_VENDOR_ATTR_FTM_PARAM_NUM_BURSTS_EXP,
+	QCA_WLAN_VENDOR_ATTR_FTM_PARAM_BURST_DURATION,
+	QCA_WLAN_VENDOR_ATTR_FTM_PARAM_BURST_PERIOD,
+	/* keep last */
+	QCA_WLAN_VENDOR_ATTR_FTM_PARAM_AFTER_LAST,
+	QCA_WLAN_VENDOR_ATTR_FTM_PARAM_MAX =
+		QCA_WLAN_VENDOR_ATTR_FTM_PARAM_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_ftm_peer_result: Per-peer results
+ *
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_MAC_ADDR: MAC address of the reported
+ *  peer
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_STATUS: Status of measurement
+ *  request for this peer.
+ *  See %enum qca_wlan_vendor_attr_ftm_peer_result_status
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_FLAGS: Various flags related
+ *  to measurement results for this peer.
+ *  See %enum qca_wlan_vendor_attr_ftm_peer_result_flags
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_VALUE_SECONDS: Specified when
+ *  request failed and peer requested not to send an additional request
+ *  for this number of seconds.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_LCI: LCI report when received
+ *  from peer. In the format specified by IEEE P802.11-REVmc/D7.0,
+ *  9.4.2.22.10
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_LCR: Location civic report when
+ *  received from peer.In the format specified by IEEE P802.11-REVmc/D7.0,
+ *  9.4.2.22.13
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_MEAS_PARAMS: Reported when peer
+ *  overridden some measurement request parameters. See
+ *  enum qca_wlan_vendor_attr_ftm_meas_param.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_AOA_MEAS: AOA measurement
+ *  for this peer. Same contents as %QCA_WLAN_VENDOR_ATTR_AOA_MEAS_RESULT
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_MEAS: Array of measurement
+ *  results. Each entry is a nested attribute defined
+ *  by enum qca_wlan_vendor_attr_ftm_meas.
+ */
+enum qca_wlan_vendor_attr_ftm_peer_result {
+	QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_INVALID,
+	QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_MAC_ADDR,
+	QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_STATUS,
+	QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_FLAGS,
+	QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_VALUE_SECONDS,
+	QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_LCI,
+	QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_LCR,
+	QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_MEAS_PARAMS,
+	QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_AOA_MEAS,
+	QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_MEAS,
+	/* keep last */
+	QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_AFTER_LAST,
+	QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_MAX =
+		QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_ftm_peer_result_status
+ *
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_STATUS_OK: Request sent ok and results
+ *  will be provided. Peer may have overridden some measurement parameters,
+ *  in which case overridden parameters will be report by
+ *  %QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_MEAS_PARAMS attribute
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_STATUS_INCAPABLE: Peer is incapable
+ *  of performing the measurement request. No more results will be sent
+ *  for this peer in this session.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_STATUS_FAILED: Peer reported request
+ *  failed, and requested not to send an additional request for number
+ *  of seconds specified by %QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_VALUE_SECONDS
+ *  attribute.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_STATUS_INVALID: Request validation
+ *  failed. Request was not sent over the air.
+ */
+enum qca_wlan_vendor_attr_ftm_peer_result_status {
+	QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_STATUS_OK,
+	QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_STATUS_INCAPABLE,
+	QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_STATUS_FAILED,
+	QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_STATUS_INVALID,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_ftm_peer_result_flags : Various flags
+ *  for measurement result, per-peer
+ *
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_FLAG_DONE: If set,
+ *  measurement completed for this peer. No more results will be reported
+ *  for this peer in this session.
+ */
+enum qca_wlan_vendor_attr_ftm_peer_result_flags {
+	QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_FLAG_DONE = 1 << 0,
+};
+
+/**
+ * enum qca_vendor_attr_loc_session_status: Session completion status code
+ *
+ * @QCA_WLAN_VENDOR_ATTR_LOC_SESSION_STATUS_OK: Session completed
+ *  successfully.
+ * @QCA_WLAN_VENDOR_ATTR_LOC_SESSION_STATUS_ABORTED: Session aborted
+ *  by request
+ * @QCA_WLAN_VENDOR_ATTR_LOC_SESSION_STATUS_INVALID: Session request
+ *  was invalid and was not started
+ * @QCA_WLAN_VENDOR_ATTR_LOC_SESSION_STATUS_FAILED: Session had an error
+ *  and did not complete normally (for example out of resources)
+ *
+ */
+enum qca_vendor_attr_loc_session_status {
+	QCA_WLAN_VENDOR_ATTR_LOC_SESSION_STATUS_OK,
+	QCA_WLAN_VENDOR_ATTR_LOC_SESSION_STATUS_ABORTED,
+	QCA_WLAN_VENDOR_ATTR_LOC_SESSION_STATUS_INVALID,
+	QCA_WLAN_VENDOR_ATTR_LOC_SESSION_STATUS_FAILED,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_ftm_meas: Single measurement data
+ *
+ * @QCA_WLAN_VENDOR_ATTR_FTM_MEAS_T1: Time of departure(TOD) of FTM packet as
+ *  recorded by responder, in picoseconds.
+ *  See IEEE P802.11-REVmc/D7.0, 11.24.6.4 for more information.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_MEAS_T2: Time of arrival(TOA) of FTM packet at
+ *  initiator, in picoseconds.
+ *  See IEEE P802.11-REVmc/D7.0, 11.24.6.4 for more information.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_MEAS_T3: TOD of ACK packet as recorded by
+ *  initiator, in picoseconds.
+ *  See IEEE P802.11-REVmc/D7.0, 11.24.6.4 for more information.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_MEAS_T4: TOA of ACK packet at
+ *  responder, in picoseconds.
+ *  See IEEE P802.11-REVmc/D7.0, 11.24.6.4 for more information.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_MEAS_RSSI: RSSI (signal level) as recorded
+ *  during this measurement exchange. Optional and will be provided if
+ *  the hardware can measure it.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_MEAS_TOD_ERR: TOD error reported by
+ *  responder. Not always provided.
+ *  See IEEE P802.11-REVmc/D7.0, 9.6.8.33 for more information.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_MEAS_TOA_ERR: TOA error reported by
+ *  responder. Not always provided.
+ *  See IEEE P802.11-REVmc/D7.0, 9.6.8.33 for more information.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_MEAS_INITIATOR_TOD_ERR: TOD error measured by
+ *  initiator. Not always provided.
+ *  See IEEE P802.11-REVmc/D7.0, 9.6.8.33 for more information.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_MEAS_INITIATOR_TOA_ERR: TOA error measured by
+ *  initiator. Not always provided.
+ *  See IEEE P802.11-REVmc/D7.0, 9.6.8.33 for more information.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_MEAS_PAD: Dummy attribute for padding.
+ */
+enum qca_wlan_vendor_attr_ftm_meas {
+	QCA_WLAN_VENDOR_ATTR_FTM_MEAS_INVALID,
+	QCA_WLAN_VENDOR_ATTR_FTM_MEAS_T1,
+	QCA_WLAN_VENDOR_ATTR_FTM_MEAS_T2,
+	QCA_WLAN_VENDOR_ATTR_FTM_MEAS_T3,
+	QCA_WLAN_VENDOR_ATTR_FTM_MEAS_T4,
+	QCA_WLAN_VENDOR_ATTR_FTM_MEAS_RSSI,
+	QCA_WLAN_VENDOR_ATTR_FTM_MEAS_TOD_ERR,
+	QCA_WLAN_VENDOR_ATTR_FTM_MEAS_TOA_ERR,
+	QCA_WLAN_VENDOR_ATTR_FTM_MEAS_INITIATOR_TOD_ERR,
+	QCA_WLAN_VENDOR_ATTR_FTM_MEAS_INITIATOR_TOA_ERR,
+	QCA_WLAN_VENDOR_ATTR_FTM_MEAS_PAD,
+	/* keep last */
+	QCA_WLAN_VENDOR_ATTR_FTM_MEAS_AFTER_LAST,
+	QCA_WLAN_VENDOR_ATTR_FTM_MEAS_MAX =
+		QCA_WLAN_VENDOR_ATTR_FTM_MEAS_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_aoa_type: AOA measurement type
+ *
+ * @QCA_WLAN_VENDOR_ATTR_AOA_TYPE_TOP_CIR_PHASE: Phase of the strongest
+ *  CIR (channel impulse response) path for each antenna.
+ * @QCA_WLAN_VENDOR_ATTR_AOA_TYPE_TOP_CIR_PHASE_AMP: Phase and amplitude
+ *  of the strongest CIR path for each antenna.
+ */
+enum qca_wlan_vendor_attr_aoa_type {
+	QCA_WLAN_VENDOR_ATTR_AOA_TYPE_TOP_CIR_PHASE,
+	QCA_WLAN_VENDOR_ATTR_AOA_TYPE_TOP_CIR_PHASE_AMP,
+	QCA_WLAN_VENDOR_ATTR_AOA_TYPE_MAX,
+};
+
+/* vendor event indices, used from both cfg80211.c and ftm.c */
+enum qca_nl80211_vendor_events_index {
+	QCA_NL80211_VENDOR_EVENT_FTM_MEAS_RESULT_INDEX,
+	QCA_NL80211_VENDOR_EVENT_FTM_SESSION_DONE_INDEX,
+	QCA_NL80211_VENDOR_EVENT_AOA_MEAS_RESULT_INDEX,
+};
+
+/* measurement parameters. Specified for each peer as part
+ * of measurement request, or provided with measurement
+ * results for peer in case peer overridden parameters
+ */
+struct wil_ftm_meas_params {
+	u8 meas_per_burst;
+	u8 num_of_bursts_exp;
+	u8 burst_duration;
+	u16 burst_period;
+};
+
+/* measurement request for a single peer */
+struct wil_ftm_meas_peer_info {
+	u8 mac_addr[ETH_ALEN];
+	u32 freq;
+	u32 flags; /* enum qca_wlan_vendor_attr_ftm_peer_meas_flags */
+	struct wil_ftm_meas_params params;
+	u8 secure_token_id;
+};
+
+/* session request, passed to wil_ftm_cfg80211_start_session */
+struct wil_ftm_session_request {
+	u64 session_cookie;
+	u32 n_peers;
+	/* keep last, variable size according to n_peers */
+	struct wil_ftm_meas_peer_info peers[0];
+};
+
+/* single measurement for a peer */
+struct wil_ftm_peer_meas {
+	u64 t1, t2, t3, t4;
+};
+
+/* measurement results for a single peer */
+struct wil_ftm_peer_meas_res {
+	u8 mac_addr[ETH_ALEN];
+	u32 flags; /* enum qca_wlan_vendor_attr_ftm_peer_result_flags */
+	u8 status; /* enum qca_wlan_vendor_attr_ftm_peer_result_status */
+	u8 value_seconds;
+	bool has_params; /* true if params is valid */
+	struct wil_ftm_meas_params params; /* peer overridden params */
+	u8 *lci;
+	u8 lci_length;
+	u8 *lcr;
+	u8 lcr_length;
+	u32 n_meas;
+	/* keep last, variable size according to n_meas */
+	struct wil_ftm_peer_meas meas[0];
+};
+
+/* standalone AOA measurement request */
+struct wil_aoa_meas_request {
+	u8 mac_addr[ETH_ALEN];
+	u32 freq;
+	u32 type;
+};
+
+/* AOA measurement result */
+struct wil_aoa_meas_result {
+	u8 mac_addr[ETH_ALEN];
+	u32 type;
+	u32 antenna_array_mask;
+	u32 status;
+	u32 length;
+	/* keep last, variable size according to length */
+	u8 data[0];
+};
+
+/* private data related to FTM. Part of the wil6210_priv structure */
+struct wil_ftm_priv {
+	struct mutex lock; /* protects the FTM data */
+	u8 session_started;
+	u64 session_cookie;
+	struct wil_ftm_peer_meas_res *ftm_res;
+	u8 has_ftm_res;
+	u32 max_ftm_meas;
+
+	/* standalone AOA measurement */
+	u8 aoa_started;
+	u8 aoa_peer_mac_addr[ETH_ALEN];
+	u32 aoa_type;
+	struct timer_list aoa_timer;
+	struct work_struct aoa_timeout_work;
+};
+
+int wil_ftm_get_capabilities(struct wiphy *wiphy, struct wireless_dev *wdev,
+			     const void *data, int data_len);
+int wil_ftm_start_session(struct wiphy *wiphy, struct wireless_dev *wdev,
+			  const void *data, int data_len);
+int wil_ftm_abort_session(struct wiphy *wiphy, struct wireless_dev *wdev,
+			  const void *data, int data_len);
+int wil_ftm_configure_responder(struct wiphy *wiphy, struct wireless_dev *wdev,
+				const void *data, int data_len);
+int wil_aoa_start_measurement(struct wiphy *wiphy, struct wireless_dev *wdev,
+			      const void *data, int data_len);
+int wil_aoa_abort_measurement(struct wiphy *wiphy, struct wireless_dev *wdev,
+			      const void *data, int data_len);
+
+#endif /* __WIL6210_FTM_H__ */
diff --git a/drivers/net/wireless/ath/wil6210/fw.c b/drivers/net/wireless/ath/wil6210/fw.c
index 82aae2d..540fc20 100644
--- a/drivers/net/wireless/ath/wil6210/fw.c
+++ b/drivers/net/wireless/ath/wil6210/fw.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2015 Qualcomm Atheros, Inc.
+ * Copyright (c) 2014-2015,2017 Qualcomm Atheros, Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -19,8 +19,9 @@
 #include "wil6210.h"
 #include "fw.h"
 
-MODULE_FIRMWARE(WIL_FW_NAME);
-MODULE_FIRMWARE(WIL_FW2_NAME);
+MODULE_FIRMWARE(WIL_FW_NAME_DEFAULT);
+MODULE_FIRMWARE(WIL_FW_NAME_SPARROW_PLUS);
+MODULE_FIRMWARE(WIL_BOARD_FILE_NAME);
 
 static
 void wil_memset_toio_32(volatile void __iomem *dst, u32 val,
diff --git a/drivers/net/wireless/ath/wil6210/fw_inc.c b/drivers/net/wireless/ath/wil6210/fw_inc.c
index 8f40eb3..f490158 100644
--- a/drivers/net/wireless/ath/wil6210/fw_inc.c
+++ b/drivers/net/wireless/ath/wil6210/fw_inc.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2016 Qualcomm Atheros, Inc.
+ * Copyright (c) 2014-2017 Qualcomm Atheros, Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -537,3 +537,22 @@
 	release_firmware(fw);
 	return rc;
 }
+
+/**
+ * wil_fw_verify_file_exists - checks if firmware file exist
+ *
+ * @wil: driver context
+ * @name: firmware file name
+ *
+ * return value - boolean, true for success, false for failure
+ */
+bool wil_fw_verify_file_exists(struct wil6210_priv *wil, const char *name)
+{
+	const struct firmware *fw;
+	int rc;
+
+	rc = request_firmware(&fw, name, wil_to_dev(wil));
+	if (!rc)
+		release_firmware(fw);
+	return rc != -ENOENT;
+}
diff --git a/drivers/net/wireless/ath/wil6210/interrupt.c b/drivers/net/wireless/ath/wil6210/interrupt.c
index 64046e0..cab1e5c 100644
--- a/drivers/net/wireless/ath/wil6210/interrupt.c
+++ b/drivers/net/wireless/ath/wil6210/interrupt.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2016 Qualcomm Atheros, Inc.
+ * Copyright (c) 2012-2017 Qualcomm Atheros, Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -94,7 +94,7 @@
 
 static void wil6210_mask_irq_misc(struct wil6210_priv *wil, bool mask_halp)
 {
-	wil_dbg_irq(wil, "%s: mask_halp(%s)\n", __func__,
+	wil_dbg_irq(wil, "mask_irq_misc: mask_halp(%s)\n",
 		    mask_halp ? "true" : "false");
 
 	wil_w(wil, RGF_DMA_EP_MISC_ICR + offsetof(struct RGF_ICR, IMS),
@@ -103,7 +103,7 @@
 
 void wil6210_mask_halp(struct wil6210_priv *wil)
 {
-	wil_dbg_irq(wil, "%s()\n", __func__);
+	wil_dbg_irq(wil, "mask_halp\n");
 
 	wil_w(wil, RGF_DMA_EP_MISC_ICR + offsetof(struct RGF_ICR, IMS),
 	      BIT_DMA_EP_MISC_ICR_HALP);
@@ -111,7 +111,7 @@
 
 static void wil6210_mask_irq_pseudo(struct wil6210_priv *wil)
 {
-	wil_dbg_irq(wil, "%s()\n", __func__);
+	wil_dbg_irq(wil, "mask_irq_pseudo\n");
 
 	wil_w(wil, RGF_DMA_PSEUDO_CAUSE_MASK_SW, WIL6210_IRQ_DISABLE);
 
@@ -134,7 +134,7 @@
 
 static void wil6210_unmask_irq_misc(struct wil6210_priv *wil, bool unmask_halp)
 {
-	wil_dbg_irq(wil, "%s: unmask_halp(%s)\n", __func__,
+	wil_dbg_irq(wil, "unmask_irq_misc: unmask_halp(%s)\n",
 		    unmask_halp ? "true" : "false");
 
 	wil_w(wil, RGF_DMA_EP_MISC_ICR + offsetof(struct RGF_ICR, IMC),
@@ -143,7 +143,7 @@
 
 static void wil6210_unmask_halp(struct wil6210_priv *wil)
 {
-	wil_dbg_irq(wil, "%s()\n", __func__);
+	wil_dbg_irq(wil, "unmask_halp\n");
 
 	wil_w(wil, RGF_DMA_EP_MISC_ICR + offsetof(struct RGF_ICR, IMC),
 	      BIT_DMA_EP_MISC_ICR_HALP);
@@ -151,7 +151,7 @@
 
 static void wil6210_unmask_irq_pseudo(struct wil6210_priv *wil)
 {
-	wil_dbg_irq(wil, "%s()\n", __func__);
+	wil_dbg_irq(wil, "unmask_irq_pseudo\n");
 
 	set_bit(wil_status_irqen, wil->status);
 
@@ -160,7 +160,7 @@
 
 void wil_mask_irq(struct wil6210_priv *wil)
 {
-	wil_dbg_irq(wil, "%s()\n", __func__);
+	wil_dbg_irq(wil, "mask_irq\n");
 
 	wil6210_mask_irq_tx(wil);
 	wil6210_mask_irq_rx(wil);
@@ -170,7 +170,7 @@
 
 void wil_unmask_irq(struct wil6210_priv *wil)
 {
-	wil_dbg_irq(wil, "%s()\n", __func__);
+	wil_dbg_irq(wil, "unmask_irq\n");
 
 	wil_w(wil, RGF_DMA_EP_RX_ICR + offsetof(struct RGF_ICR, ICC),
 	      WIL_ICR_ICC_VALUE);
@@ -187,7 +187,7 @@
 
 void wil_configure_interrupt_moderation(struct wil6210_priv *wil)
 {
-	wil_dbg_irq(wil, "%s()\n", __func__);
+	wil_dbg_irq(wil, "configure_interrupt_moderation\n");
 
 	/* disable interrupt moderation for monitor
 	 * to get better timestamp precision
@@ -400,7 +400,7 @@
 	}
 
 	if (isr & BIT_DMA_EP_MISC_ICR_HALP) {
-		wil_dbg_irq(wil, "%s: HALP IRQ invoked\n", __func__);
+		wil_dbg_irq(wil, "irq_misc: HALP IRQ invoked\n");
 		wil6210_mask_halp(wil);
 		isr &= ~BIT_DMA_EP_MISC_ICR_HALP;
 		complete(&wil->halp.comp);
@@ -599,7 +599,7 @@
 
 void wil6210_set_halp(struct wil6210_priv *wil)
 {
-	wil_dbg_irq(wil, "%s()\n", __func__);
+	wil_dbg_irq(wil, "set_halp\n");
 
 	wil_w(wil, RGF_DMA_EP_MISC_ICR + offsetof(struct RGF_ICR, ICS),
 	      BIT_DMA_EP_MISC_ICR_HALP);
@@ -607,7 +607,7 @@
 
 void wil6210_clear_halp(struct wil6210_priv *wil)
 {
-	wil_dbg_irq(wil, "%s()\n", __func__);
+	wil_dbg_irq(wil, "clear_halp\n");
 
 	wil_w(wil, RGF_DMA_EP_MISC_ICR + offsetof(struct RGF_ICR, ICR),
 	      BIT_DMA_EP_MISC_ICR_HALP);
@@ -618,7 +618,7 @@
 {
 	int rc;
 
-	wil_dbg_misc(wil, "%s(%s)\n", __func__, use_msi ? "MSI" : "INTx");
+	wil_dbg_misc(wil, "init_irq: %s\n", use_msi ? "MSI" : "INTx");
 
 	rc = request_threaded_irq(irq, wil6210_hardirq,
 				  wil6210_thread_irq,
@@ -629,7 +629,7 @@
 
 void wil6210_fini_irq(struct wil6210_priv *wil, int irq)
 {
-	wil_dbg_misc(wil, "%s()\n", __func__);
+	wil_dbg_misc(wil, "fini_irq:\n");
 
 	wil_mask_irq(wil);
 	free_irq(irq, wil);
diff --git a/drivers/net/wireless/ath/wil6210/ioctl.c b/drivers/net/wireless/ath/wil6210/ioctl.c
index 6303800..bbdd232 100644
--- a/drivers/net/wireless/ath/wil6210/ioctl.c
+++ b/drivers/net/wireless/ath/wil6210/ioctl.c
@@ -24,6 +24,14 @@
 			     DUMP_PREFIX_OFFSET, 16, 1, buf, len, true)
 #define wil_dbg_ioctl(wil, fmt, arg...) wil_dbg(wil, "DBG[IOC ]" fmt, ##arg)
 
+#define WIL_PRIV_DATA_MAX_LEN	8192
+#define CMD_SET_AP_WPS_P2P_IE	"SET_AP_WPS_P2P_IE"
+
+struct wil_android_priv_data {
+	char *buf;
+	int used_len;
+	int total_len;
+};
 static void __iomem *wil_ioc_addr(struct wil6210_priv *wil, uint32_t addr,
 				  uint32_t size, enum wil_memio_op op)
 {
@@ -79,10 +87,12 @@
 		io.val = readl(a);
 		need_copy = true;
 		break;
+#if defined(CONFIG_WIL6210_WRITE_IOCTL)
 	case wil_mmio_write:
 		writel(io.val, a);
 		wmb(); /* make sure write propagated to HW */
 		break;
+#endif
 	default:
 		wil_err(wil, "Unsupported operation, op = 0x%08x\n", io.op);
 		return -EINVAL;
@@ -139,6 +149,7 @@
 			goto out_free;
 		}
 		break;
+#if defined(CONFIG_WIL6210_WRITE_IOCTL)
 	case wil_mmio_write:
 		if (copy_from_user(block, io.block, io.size)) {
 			rc = -EFAULT;
@@ -148,6 +159,7 @@
 		wmb(); /* make sure write propagated to HW */
 		wil_hex_dump_ioctl("Write ", block, io.size);
 		break;
+#endif
 	default:
 		wil_err(wil, "Unsupported operation, op = 0x%08x\n", io.op);
 		rc = -EINVAL;
@@ -159,6 +171,52 @@
 	return rc;
 }
 
+static int wil_ioc_android(struct wil6210_priv *wil, void __user *data)
+{
+	int rc = 0;
+	char *command;
+	struct wil_android_priv_data priv_data;
+
+	wil_dbg_ioctl(wil, "%s()\n", __func__);
+
+	if (copy_from_user(&priv_data, data, sizeof(priv_data)))
+		return -EFAULT;
+
+	if (priv_data.total_len <= 0 ||
+	    priv_data.total_len >= WIL_PRIV_DATA_MAX_LEN) {
+		wil_err(wil, "%s: invalid data len %d\n",
+			__func__, priv_data.total_len);
+		return -EINVAL;
+	}
+
+	command = kmalloc(priv_data.total_len + 1, GFP_KERNEL);
+	if (!command)
+		return -ENOMEM;
+
+	if (copy_from_user(command, priv_data.buf, priv_data.total_len)) {
+		rc = -EFAULT;
+		goto out_free;
+	}
+
+	/* Make sure the command is NUL-terminated */
+	command[priv_data.total_len] = '\0';
+
+	wil_dbg_ioctl(wil, "%s(command = %s)\n", __func__, command);
+
+	/* P2P not supported, but WPS is (in AP mode).
+	 * Ignore those in order not to block WPS functionality
+	 * in non-P2P mode.
+	 */
+	if (strncasecmp(command, CMD_SET_AP_WPS_P2P_IE,
+			strlen(CMD_SET_AP_WPS_P2P_IE)) == 0)
+		rc = 0;
+	else
+		rc = -ENOIOCTLCMD;
+
+out_free:
+	kfree(command);
+	return rc;
+}
 int wil_ioctl(struct wil6210_priv *wil, void __user *data, int cmd)
 {
 	int ret;
@@ -170,6 +228,9 @@
 	case WIL_IOCTL_MEMIO_BLOCK:
 		ret = wil_ioc_memio_block(wil, data);
 		break;
+	case (SIOCDEVPRIVATE + 1):
+		ret = wil_ioc_android(wil, data);
+		break;
 	default:
 		wil_dbg_ioctl(wil, "Unsupported IOCTL 0x%04x\n", cmd);
 		return -ENOIOCTLCMD;
diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c
index e7130b5..133f6b5 100644
--- a/drivers/net/wireless/ath/wil6210/main.c
+++ b/drivers/net/wireless/ath/wil6210/main.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2016 Qualcomm Atheros, Inc.
+ * Copyright (c) 2012-2017 Qualcomm Atheros, Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -24,25 +24,26 @@
 #include "boot_loader.h"
 
 #define WAIT_FOR_HALP_VOTE_MS 100
+#define WAIT_FOR_SCAN_ABORT_MS 1000
 
 bool debug_fw; /* = false; */
-module_param(debug_fw, bool, S_IRUGO);
+module_param(debug_fw, bool, 0444);
 MODULE_PARM_DESC(debug_fw, " do not perform card reset. For FW debug");
 
 static bool oob_mode;
-module_param(oob_mode, bool, S_IRUGO);
+module_param(oob_mode, bool, 0444);
 MODULE_PARM_DESC(oob_mode,
 		 " enable out of the box (OOB) mode in FW, for diagnostics and certification");
 
 bool no_fw_recovery;
-module_param(no_fw_recovery, bool, S_IRUGO | S_IWUSR);
+module_param(no_fw_recovery, bool, 0644);
 MODULE_PARM_DESC(no_fw_recovery, " disable automatic FW error recovery");
 
 /* if not set via modparam, will be set to default value of 1/8 of
  * rx ring size during init flow
  */
 unsigned short rx_ring_overflow_thrsh = WIL6210_RX_HIGH_TRSH_INIT;
-module_param(rx_ring_overflow_thrsh, ushort, S_IRUGO);
+module_param(rx_ring_overflow_thrsh, ushort, 0444);
 MODULE_PARM_DESC(rx_ring_overflow_thrsh,
 		 " RX ring overflow threshold in descriptors.");
 
@@ -72,7 +73,7 @@
 	.get = param_get_uint,
 };
 
-module_param_cb(mtu_max, &mtu_max_ops, &mtu_max, S_IRUGO);
+module_param_cb(mtu_max, &mtu_max_ops, &mtu_max, 0444);
 MODULE_PARM_DESC(mtu_max, " Max MTU value.");
 
 static uint rx_ring_order = WIL_RX_RING_SIZE_ORDER_DEFAULT;
@@ -101,11 +102,11 @@
 	.get = param_get_uint,
 };
 
-module_param_cb(rx_ring_order, &ring_order_ops, &rx_ring_order, S_IRUGO);
+module_param_cb(rx_ring_order, &ring_order_ops, &rx_ring_order, 0444);
 MODULE_PARM_DESC(rx_ring_order, " Rx ring order; size = 1 << order");
-module_param_cb(tx_ring_order, &ring_order_ops, &tx_ring_order, S_IRUGO);
+module_param_cb(tx_ring_order, &ring_order_ops, &tx_ring_order, 0444);
 MODULE_PARM_DESC(tx_ring_order, " Tx ring order; size = 1 << order");
-module_param_cb(bcast_ring_order, &ring_order_ops, &bcast_ring_order, S_IRUGO);
+module_param_cb(bcast_ring_order, &ring_order_ops, &bcast_ring_order, 0444);
 MODULE_PARM_DESC(bcast_ring_order, " Bcast ring order; size = 1 << order");
 
 #define RST_DELAY (20) /* msec, for loop in @wil_target_reset */
@@ -171,12 +172,16 @@
 	struct wil_sta_info *sta = &wil->sta[cid];
 
 	might_sleep();
-	wil_dbg_misc(wil, "%s(CID %d, status %d)\n", __func__, cid,
-		     sta->status);
+	wil_dbg_misc(wil, "disconnect_cid: CID %d, status %d\n",
+		     cid, sta->status);
 	/* inform upper/lower layers */
 	if (sta->status != wil_sta_unused) {
-		if (!from_event)
-			wmi_disconnect_sta(wil, sta->addr, reason_code, true);
+		if (!from_event) {
+			bool del_sta = (wdev->iftype == NL80211_IFTYPE_AP) ?
+						disable_ap_sme : false;
+			wmi_disconnect_sta(wil, sta->addr, reason_code,
+					   true, del_sta);
+		}
 
 		switch (wdev->iftype) {
 		case NL80211_IFTYPE_AP:
@@ -213,7 +218,7 @@
 	memset(&sta->stats, 0, sizeof(sta->stats));
 }
 
-static bool wil_ap_is_connected(struct wil6210_priv *wil)
+static bool wil_is_connected(struct wil6210_priv *wil)
 {
 	int i;
 
@@ -236,7 +241,7 @@
 		return;
 
 	might_sleep();
-	wil_info(wil, "%s(bssid=%pM, reason=%d, ev%s)\n", __func__, bssid,
+	wil_info(wil, "bssid=%pM, reason=%d, ev%s\n", bssid,
 		 reason_code, from_event ? "+" : "-");
 
 	/* Cases are:
@@ -267,7 +272,7 @@
 	case NL80211_IFTYPE_STATION:
 	case NL80211_IFTYPE_P2P_CLIENT:
 		wil_bcast_fini(wil);
-		netif_tx_stop_all_queues(ndev);
+		wil_update_net_queues_bh(wil, NULL, true);
 		netif_carrier_off(ndev);
 
 		if (test_bit(wil_status_fwconnected, wil->status)) {
@@ -283,8 +288,12 @@
 		break;
 	case NL80211_IFTYPE_AP:
 	case NL80211_IFTYPE_P2P_GO:
-		if (!wil_ap_is_connected(wil))
+		if (!wil_is_connected(wil)) {
+			wil_update_net_queues_bh(wil, NULL, true);
 			clear_bit(wil_status_fwconnected, wil->status);
+		} else {
+			wil_update_net_queues_bh(wil, NULL, false);
+		}
 		break;
 	default:
 		break;
@@ -342,7 +351,7 @@
 
 void wil_set_recovery_state(struct wil6210_priv *wil, int state)
 {
-	wil_dbg_misc(wil, "%s(%d -> %d)\n", __func__,
+	wil_dbg_misc(wil, "set_recovery_state: %d -> %d\n",
 		     wil->recovery_state, state);
 
 	wil->recovery_state = state;
@@ -384,18 +393,19 @@
 
 	wil->last_fw_recovery = jiffies;
 
+	wil_info(wil, "fw error recovery requested (try %d)...\n",
+		 wil->recovery_count);
+	if (!no_fw_recovery)
+		wil->recovery_state = fw_recovery_running;
+	if (wil_wait_for_recovery(wil) != 0)
+		return;
+
 	mutex_lock(&wil->mutex);
 	switch (wdev->iftype) {
 	case NL80211_IFTYPE_STATION:
 	case NL80211_IFTYPE_P2P_CLIENT:
 	case NL80211_IFTYPE_MONITOR:
-		wil_info(wil, "fw error recovery requested (try %d)...\n",
-			 wil->recovery_count);
-		if (!no_fw_recovery)
-			wil->recovery_state = fw_recovery_running;
-		if (0 != wil_wait_for_recovery(wil))
-			break;
-
+		/* silent recovery, upper layers will see disconnect */
 		__wil_down(wil);
 		__wil_up(wil);
 		break;
@@ -483,7 +493,7 @@
 {
 	uint i;
 
-	wil_dbg_misc(wil, "%s()\n", __func__);
+	wil_dbg_misc(wil, "priv_init\n");
 
 	memset(wil->sta, 0, sizeof(wil->sta));
 	for (i = 0; i < WIL6210_MAX_CID; i++)
@@ -512,12 +522,17 @@
 	INIT_WORK(&wil->wmi_event_worker, wmi_event_worker);
 	INIT_WORK(&wil->fw_error_worker, wil_fw_error_worker);
 	INIT_WORK(&wil->probe_client_worker, wil_probe_client_worker);
+	INIT_WORK(&wil->p2p.delayed_listen_work, wil_p2p_delayed_listen_work);
 
 	INIT_LIST_HEAD(&wil->pending_wmi_ev);
 	INIT_LIST_HEAD(&wil->probe_client_pending);
 	spin_lock_init(&wil->wmi_ev_lock);
+	spin_lock_init(&wil->net_queue_lock);
+	wil->net_queue_stopped = 1;
 	init_waitqueue_head(&wil->wq);
 
+	wil_ftm_init(wil);
+
 	wil->wmi_wq = create_singlethread_workqueue(WIL_NAME "_wmi");
 	if (!wil->wmi_wq)
 		return -EAGAIN;
@@ -555,7 +570,7 @@
 void wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid,
 			u16 reason_code, bool from_event)
 {
-	wil_dbg_misc(wil, "%s()\n", __func__);
+	wil_dbg_misc(wil, "disconnect\n");
 
 	del_timer_sync(&wil->connect_timer);
 	_wil6210_disconnect(wil, bssid, reason_code, from_event);
@@ -563,14 +578,16 @@
 
 void wil_priv_deinit(struct wil6210_priv *wil)
 {
-	wil_dbg_misc(wil, "%s()\n", __func__);
+	wil_dbg_misc(wil, "priv_deinit\n");
 
+	wil_ftm_deinit(wil);
 	wil_set_recovery_state(wil, fw_recovery_idle);
 	del_timer_sync(&wil->scan_timer);
 	del_timer_sync(&wil->p2p.discovery_timer);
 	cancel_work_sync(&wil->disconnect_worker);
 	cancel_work_sync(&wil->fw_error_worker);
 	cancel_work_sync(&wil->p2p.discovery_expired_work);
+	cancel_work_sync(&wil->p2p.delayed_listen_work);
 	mutex_lock(&wil->mutex);
 	wil6210_disconnect(wil, NULL, WLAN_REASON_DEAUTH_LEAVING, false);
 	mutex_unlock(&wil->mutex);
@@ -595,7 +612,7 @@
 
 static void wil_set_oob_mode(struct wil6210_priv *wil, bool enable)
 {
-	wil_info(wil, "%s: enable=%d\n", __func__, enable);
+	wil_info(wil, "enable=%d\n", enable);
 	if (enable)
 		wil_s(wil, RGF_USER_USAGE_6, BIT_USER_OOB_MODE);
 	else
@@ -685,6 +702,19 @@
 	return 0;
 }
 
+static void wil_collect_fw_info(struct wil6210_priv *wil)
+{
+	struct wiphy *wiphy = wil_to_wiphy(wil);
+	u8 retry_short;
+	int rc;
+
+	rc = wmi_get_mgmt_retry(wil, &retry_short);
+	if (!rc) {
+		wiphy->retry_short = retry_short;
+		wil_dbg_misc(wil, "FW retry_short: %d\n", retry_short);
+	}
+}
+
 void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r)
 {
 	le32_to_cpus(&r->base);
@@ -801,6 +831,34 @@
 	return 0;
 }
 
+void wil_abort_scan(struct wil6210_priv *wil, bool sync)
+{
+	int rc;
+	struct cfg80211_scan_info info = {
+		.aborted = true,
+	};
+
+	lockdep_assert_held(&wil->p2p_wdev_mutex);
+
+	if (!wil->scan_request)
+		return;
+
+	wil_dbg_misc(wil, "Abort scan_request 0x%p\n", wil->scan_request);
+	del_timer_sync(&wil->scan_timer);
+	mutex_unlock(&wil->p2p_wdev_mutex);
+	rc = wmi_abort_scan(wil);
+	if (!rc && sync)
+		wait_event_interruptible_timeout(wil->wq, !wil->scan_request,
+						 msecs_to_jiffies(
+						 WAIT_FOR_SCAN_ABORT_MS));
+
+	mutex_lock(&wil->p2p_wdev_mutex);
+	if (wil->scan_request) {
+		cfg80211_scan_done(wil->scan_request, &info);
+		wil->scan_request = NULL;
+	}
+}
+
 /*
  * We reset all the structures, and we reset the UMAC.
  * After calling this routine, you're expected to reload
@@ -810,7 +868,7 @@
 {
 	int rc;
 
-	wil_dbg_misc(wil, "%s()\n", __func__);
+	wil_dbg_misc(wil, "reset\n");
 
 	WARN_ON(!mutex_is_locked(&wil->mutex));
 	WARN_ON(test_bit(wil_status_napi_en, wil->status));
@@ -833,9 +891,8 @@
 		rc = wil->platform_ops.notify(wil->platform_handle,
 					      WIL_PLATFORM_EVT_PRE_RESET);
 		if (rc)
-			wil_err(wil,
-				"%s: PRE_RESET platform notify failed, rc %d\n",
-				__func__, rc);
+			wil_err(wil, "PRE_RESET platform notify failed, rc %d\n",
+				rc);
 	}
 
 	set_bit(wil_status_resetting, wil->status);
@@ -853,17 +910,7 @@
 	mutex_unlock(&wil->wmi_mutex);
 
 	mutex_lock(&wil->p2p_wdev_mutex);
-	if (wil->scan_request) {
-		struct cfg80211_scan_info info = {
-			.aborted = true,
-		};
-
-		wil_dbg_misc(wil, "Abort scan_request 0x%p\n",
-			     wil->scan_request);
-		del_timer_sync(&wil->scan_timer);
-		cfg80211_scan_done(wil->scan_request, &info);
-		wil->scan_request = NULL;
-	}
+	wil_abort_scan(wil, false);
 	mutex_unlock(&wil->p2p_wdev_mutex);
 
 	wil_mask_irq(wil);
@@ -874,7 +921,10 @@
 	flush_workqueue(wil->wmi_wq);
 
 	wil_bl_crash_info(wil, false);
+	wil_disable_irq(wil);
 	rc = wil_target_reset(wil);
+	wil6210_clear_irq(wil);
+	wil_enable_irq(wil);
 	wil_rx_fini(wil);
 	if (rc) {
 		wil_bl_crash_info(wil, true);
@@ -889,16 +939,16 @@
 
 	wil_set_oob_mode(wil, oob_mode);
 	if (load_fw) {
-		wil_info(wil, "Use firmware <%s> + board <%s>\n", WIL_FW_NAME,
-			 WIL_FW2_NAME);
+		wil_info(wil, "Use firmware <%s> + board <%s>\n",
+			 wil->wil_fw_name, WIL_BOARD_FILE_NAME);
 
 		wil_halt_cpu(wil);
 		memset(wil->fw_version, 0, sizeof(wil->fw_version));
 		/* Loading f/w from the file */
-		rc = wil_request_firmware(wil, WIL_FW_NAME, true);
+		rc = wil_request_firmware(wil, wil->wil_fw_name, true);
 		if (rc)
 			return rc;
-		rc = wil_request_firmware(wil, WIL_FW2_NAME, true);
+		rc = wil_request_firmware(wil, WIL_BOARD_FILE_NAME, true);
 		if (rc)
 			return rc;
 
@@ -935,18 +985,18 @@
 		/* check FW is responsive */
 		rc = wmi_echo(wil);
 		if (rc) {
-			wil_err(wil, "%s: wmi_echo failed, rc %d\n",
-				__func__, rc);
+			wil_err(wil, "wmi_echo failed, rc %d\n", rc);
 			return rc;
 		}
 
+		wil_collect_fw_info(wil);
+
 		if (wil->platform_ops.notify) {
 			rc = wil->platform_ops.notify(wil->platform_handle,
 						      WIL_PLATFORM_EVT_FW_RDY);
 			if (rc) {
-				wil_err(wil,
-					"%s: FW_RDY notify failed, rc %d\n",
-					__func__, rc);
+				wil_err(wil, "FW_RDY notify failed, rc %d\n",
+					rc);
 				rc = 0;
 			}
 		}
@@ -1030,7 +1080,7 @@
 {
 	int rc;
 
-	wil_dbg_misc(wil, "%s()\n", __func__);
+	wil_dbg_misc(wil, "up\n");
 
 	mutex_lock(&wil->mutex);
 	rc = __wil_up(wil);
@@ -1056,20 +1106,11 @@
 	}
 	wil_enable_irq(wil);
 
-	wil_p2p_stop_radio_operations(wil);
+	wil_ftm_stop_operations(wil);
 
 	mutex_lock(&wil->p2p_wdev_mutex);
-	if (wil->scan_request) {
-		struct cfg80211_scan_info info = {
-			.aborted = true,
-		};
-
-		wil_dbg_misc(wil, "Abort scan_request 0x%p\n",
-			     wil->scan_request);
-		del_timer_sync(&wil->scan_timer);
-		cfg80211_scan_done(wil->scan_request, &info);
-		wil->scan_request = NULL;
-	}
+	wil_p2p_stop_radio_operations(wil);
+	wil_abort_scan(wil, false);
 	mutex_unlock(&wil->p2p_wdev_mutex);
 
 	wil_reset(wil, false);
@@ -1081,7 +1122,7 @@
 {
 	int rc;
 
-	wil_dbg_misc(wil, "%s()\n", __func__);
+	wil_dbg_misc(wil, "down\n");
 
 	wil_set_recovery_state(wil, fw_recovery_idle);
 	mutex_lock(&wil->mutex);
@@ -1114,25 +1155,24 @@
 
 	mutex_lock(&wil->halp.lock);
 
-	wil_dbg_irq(wil, "%s: start, HALP ref_cnt (%d)\n", __func__,
+	wil_dbg_irq(wil, "halp_vote: start, HALP ref_cnt (%d)\n",
 		    wil->halp.ref_cnt);
 
 	if (++wil->halp.ref_cnt == 1) {
 		wil6210_set_halp(wil);
 		rc = wait_for_completion_timeout(&wil->halp.comp, to_jiffies);
 		if (!rc) {
-			wil_err(wil, "%s: HALP vote timed out\n", __func__);
+			wil_err(wil, "HALP vote timed out\n");
 			/* Mask HALP as done in case the interrupt is raised */
 			wil6210_mask_halp(wil);
 		} else {
 			wil_dbg_irq(wil,
-				    "%s: HALP vote completed after %d ms\n",
-				    __func__,
+				    "halp_vote: HALP vote completed after %d ms\n",
 				    jiffies_to_msecs(to_jiffies - rc));
 		}
 	}
 
-	wil_dbg_irq(wil, "%s: end, HALP ref_cnt (%d)\n", __func__,
+	wil_dbg_irq(wil, "halp_vote: end, HALP ref_cnt (%d)\n",
 		    wil->halp.ref_cnt);
 
 	mutex_unlock(&wil->halp.lock);
@@ -1144,15 +1184,15 @@
 
 	mutex_lock(&wil->halp.lock);
 
-	wil_dbg_irq(wil, "%s: start, HALP ref_cnt (%d)\n", __func__,
+	wil_dbg_irq(wil, "halp_unvote: start, HALP ref_cnt (%d)\n",
 		    wil->halp.ref_cnt);
 
 	if (--wil->halp.ref_cnt == 0) {
 		wil6210_clear_halp(wil);
-		wil_dbg_irq(wil, "%s: HALP unvote\n", __func__);
+		wil_dbg_irq(wil, "HALP unvote\n");
 	}
 
-	wil_dbg_irq(wil, "%s: end, HALP ref_cnt (%d)\n", __func__,
+	wil_dbg_irq(wil, "halp_unvote:end, HALP ref_cnt (%d)\n",
 		    wil->halp.ref_cnt);
 
 	mutex_unlock(&wil->halp.lock);
diff --git a/drivers/net/wireless/ath/wil6210/netdev.c b/drivers/net/wireless/ath/wil6210/netdev.c
index 61de5e9..1a65d07 100644
--- a/drivers/net/wireless/ath/wil6210/netdev.c
+++ b/drivers/net/wireless/ath/wil6210/netdev.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2016 Qualcomm Atheros, Inc.
+ * Copyright (c) 2012-2017 Qualcomm Atheros, Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -14,18 +14,24 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
+#include <linux/moduleparam.h>
 #include <linux/etherdevice.h>
 #include "wil6210.h"
 #include "txrx.h"
 
+static bool alt_ifname; /* = false; */
+module_param(alt_ifname, bool, 0444);
+MODULE_PARM_DESC(alt_ifname, " use an alternate interface name wigigN instead of wlanN");
+
 static int wil_open(struct net_device *ndev)
 {
 	struct wil6210_priv *wil = ndev_to_wil(ndev);
 
-	wil_dbg_misc(wil, "%s()\n", __func__);
+	wil_dbg_misc(wil, "open\n");
 
-	if (debug_fw) {
-		wil_err(wil, "%s() while in debug_fw mode\n", __func__);
+	if (debug_fw ||
+	    test_bit(WMI_FW_CAPABILITY_WMI_ONLY, wil->fw_capabilities)) {
+		wil_err(wil, "while in debug_fw or wmi_only mode\n");
 		return -EINVAL;
 	}
 
@@ -36,7 +42,7 @@
 {
 	struct wil6210_priv *wil = ndev_to_wil(ndev);
 
-	wil_dbg_misc(wil, "%s()\n", __func__);
+	wil_dbg_misc(wil, "stop\n");
 
 	return wil_down(wil);
 }
@@ -136,6 +142,7 @@
 	struct wil6210_priv *wil;
 	struct ieee80211_channel *ch;
 	int rc = 0;
+	const char *ifname = alt_ifname ? "wigig%d" : "wlan%d";
 
 	wdev = wil_cfg80211_init(dev);
 	if (IS_ERR(wdev)) {
@@ -147,7 +154,7 @@
 	wil->wdev = wdev;
 	wil->radio_wdev = wdev;
 
-	wil_dbg_misc(wil, "%s()\n", __func__);
+	wil_dbg_misc(wil, "if_alloc\n");
 
 	rc = wil_priv_init(wil);
 	if (rc) {
@@ -160,7 +167,7 @@
 	ch = wdev->wiphy->bands[NL80211_BAND_60GHZ]->channels;
 	cfg80211_chandef_create(&wdev->preset_chandef, ch, NL80211_CHAN_NO_HT);
 
-	ndev = alloc_netdev(0, "wlan%d", NET_NAME_UNKNOWN, wil_dev_setup);
+	ndev = alloc_netdev(0, ifname, NET_NAME_UNKNOWN, wil_dev_setup);
 	if (!ndev) {
 		dev_err(dev, "alloc_netdev_mqs failed\n");
 		rc = -ENOMEM;
@@ -194,7 +201,7 @@
 {
 	struct net_device *ndev = wil_to_ndev(wil);
 
-	wil_dbg_misc(wil, "%s()\n", __func__);
+	wil_dbg_misc(wil, "if_free\n");
 
 	if (!ndev)
 		return;
@@ -229,7 +236,7 @@
 	netif_tx_napi_add(ndev, &wil->napi_tx, wil6210_netdev_poll_tx,
 			  WIL6210_NAPI_BUDGET);
 
-	netif_tx_stop_all_queues(ndev);
+	wil_update_net_queues_bh(wil, NULL, true);
 
 	rc = register_netdev(ndev);
 	if (rc < 0) {
@@ -249,7 +256,7 @@
 	struct net_device *ndev = wil_to_ndev(wil);
 	struct wireless_dev *wdev = wil_to_wdev(wil);
 
-	wil_dbg_misc(wil, "%s()\n", __func__);
+	wil_dbg_misc(wil, "if_remove\n");
 
 	unregister_netdev(ndev);
 	wiphy_unregister(wdev->wiphy);
diff --git a/drivers/net/wireless/ath/wil6210/p2p.c b/drivers/net/wireless/ath/wil6210/p2p.c
index 4087785..7924847 100644
--- a/drivers/net/wireless/ath/wil6210/p2p.c
+++ b/drivers/net/wireless/ath/wil6210/p2p.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2016 Qualcomm Atheros, Inc.
+ * Copyright (c) 2014-2017 Qualcomm Atheros, Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -22,6 +22,43 @@
 #define P2P_SEARCH_DURATION_MS 500
 #define P2P_DEFAULT_BI 100
 
+static int wil_p2p_start_listen(struct wil6210_priv *wil)
+{
+	struct wil_p2p_info *p2p = &wil->p2p;
+	u8 channel = p2p->listen_chan.hw_value;
+	int rc;
+
+	lockdep_assert_held(&wil->mutex);
+
+	rc = wmi_p2p_cfg(wil, channel, P2P_DEFAULT_BI);
+	if (rc) {
+		wil_err(wil, "wmi_p2p_cfg failed\n");
+		goto out;
+	}
+
+	rc = wmi_set_ssid(wil, strlen(P2P_WILDCARD_SSID), P2P_WILDCARD_SSID);
+	if (rc) {
+		wil_err(wil, "wmi_set_ssid failed\n");
+		goto out_stop;
+	}
+
+	rc = wmi_start_listen(wil);
+	if (rc) {
+		wil_err(wil, "wmi_start_listen failed\n");
+		goto out_stop;
+	}
+
+	INIT_WORK(&p2p->discovery_expired_work, wil_p2p_listen_expired);
+	mod_timer(&p2p->discovery_timer,
+		  jiffies + msecs_to_jiffies(p2p->listen_duration));
+out_stop:
+	if (rc)
+		wmi_stop_discovery(wil);
+
+out:
+	return rc;
+}
+
 bool wil_p2p_is_social_scan(struct cfg80211_scan_request *request)
 {
 	return (request->n_channels == 1) &&
@@ -32,7 +69,7 @@
 {
 	struct wil6210_priv *wil = (void *)x;
 
-	wil_dbg_misc(wil, "%s\n", __func__);
+	wil_dbg_misc(wil, "p2p_discovery_timer_fn\n");
 
 	schedule_work(&wil->p2p.discovery_expired_work);
 }
@@ -43,27 +80,25 @@
 	int rc;
 	struct wil_p2p_info *p2p = &wil->p2p;
 
-	wil_dbg_misc(wil, "%s: channel %d\n",
-		     __func__, P2P_DMG_SOCIAL_CHANNEL);
+	wil_dbg_misc(wil, "p2p_search: channel %d\n", P2P_DMG_SOCIAL_CHANNEL);
 
-	mutex_lock(&wil->mutex);
+	lockdep_assert_held(&wil->mutex);
 
 	if (p2p->discovery_started) {
-		wil_err(wil, "%s: search failed. discovery already ongoing\n",
-			__func__);
+		wil_err(wil, "search failed. discovery already ongoing\n");
 		rc = -EBUSY;
 		goto out;
 	}
 
 	rc = wmi_p2p_cfg(wil, P2P_DMG_SOCIAL_CHANNEL, P2P_DEFAULT_BI);
 	if (rc) {
-		wil_err(wil, "%s: wmi_p2p_cfg failed\n", __func__);
+		wil_err(wil, "wmi_p2p_cfg failed\n");
 		goto out;
 	}
 
 	rc = wmi_set_ssid(wil, strlen(P2P_WILDCARD_SSID), P2P_WILDCARD_SSID);
 	if (rc) {
-		wil_err(wil, "%s: wmi_set_ssid failed\n", __func__);
+		wil_err(wil, "wmi_set_ssid failed\n");
 		goto out_stop;
 	}
 
@@ -71,8 +106,7 @@
 	rc = wmi_set_ie(wil, WMI_FRAME_PROBE_REQ,
 			request->ie_len, request->ie);
 	if (rc) {
-		wil_err(wil, "%s: wmi_set_ie(WMI_FRAME_PROBE_REQ) failed\n",
-			__func__);
+		wil_err(wil, "wmi_set_ie(WMI_FRAME_PROBE_REQ) failed\n");
 		goto out_stop;
 	}
 
@@ -82,14 +116,13 @@
 	rc = wmi_set_ie(wil, WMI_FRAME_PROBE_RESP,
 			request->ie_len, request->ie);
 	if (rc) {
-		wil_err(wil, "%s: wmi_set_ie(WMI_FRAME_PROBE_RESP) failed\n",
-			__func__);
+		wil_err(wil, "wmi_set_ie(WMI_FRAME_PROBE_RESP) failed\n");
 		goto out_stop;
 	}
 
 	rc = wmi_start_search(wil);
 	if (rc) {
-		wil_err(wil, "%s: wmi_start_search failed\n", __func__);
+		wil_err(wil, "wmi_start_search failed\n");
 		goto out_stop;
 	}
 
@@ -103,61 +136,53 @@
 		wmi_stop_discovery(wil);
 
 out:
-	mutex_unlock(&wil->mutex);
 	return rc;
 }
 
-int wil_p2p_listen(struct wil6210_priv *wil, unsigned int duration,
-		   struct ieee80211_channel *chan, u64 *cookie)
+int wil_p2p_listen(struct wil6210_priv *wil, struct wireless_dev *wdev,
+		   unsigned int duration, struct ieee80211_channel *chan,
+		   u64 *cookie)
 {
 	struct wil_p2p_info *p2p = &wil->p2p;
-	u8 channel = P2P_DMG_SOCIAL_CHANNEL;
 	int rc;
 
 	if (!chan)
 		return -EINVAL;
 
-	channel = chan->hw_value;
-
-	wil_dbg_misc(wil, "%s: duration %d\n", __func__, duration);
+	wil_dbg_misc(wil, "p2p_listen: duration %d\n", duration);
 
 	mutex_lock(&wil->mutex);
 
 	if (p2p->discovery_started) {
-		wil_err(wil, "%s: discovery already ongoing\n", __func__);
+		wil_err(wil, "discovery already ongoing\n");
 		rc = -EBUSY;
 		goto out;
 	}
 
-	rc = wmi_p2p_cfg(wil, channel, P2P_DEFAULT_BI);
-	if (rc) {
-		wil_err(wil, "%s: wmi_p2p_cfg failed\n", __func__);
-		goto out;
-	}
-
-	rc = wmi_set_ssid(wil, strlen(P2P_WILDCARD_SSID), P2P_WILDCARD_SSID);
-	if (rc) {
-		wil_err(wil, "%s: wmi_set_ssid failed\n", __func__);
-		goto out_stop;
-	}
-
-	rc = wmi_start_listen(wil);
-	if (rc) {
-		wil_err(wil, "%s: wmi_start_listen failed\n", __func__);
-		goto out_stop;
-	}
-
 	memcpy(&p2p->listen_chan, chan, sizeof(*chan));
 	*cookie = ++p2p->cookie;
+	p2p->listen_duration = duration;
+
+	mutex_lock(&wil->p2p_wdev_mutex);
+	if (wil->scan_request) {
+		wil_dbg_misc(wil, "Delaying p2p listen until scan done\n");
+		p2p->pending_listen_wdev = wdev;
+		p2p->discovery_started = 1;
+		rc = 0;
+		mutex_unlock(&wil->p2p_wdev_mutex);
+		goto out;
+	}
+	mutex_unlock(&wil->p2p_wdev_mutex);
+
+	rc = wil_p2p_start_listen(wil);
+	if (rc)
+		goto out;
 
 	p2p->discovery_started = 1;
-	INIT_WORK(&p2p->discovery_expired_work, wil_p2p_listen_expired);
-	mod_timer(&p2p->discovery_timer,
-		  jiffies + msecs_to_jiffies(duration));
+	wil->radio_wdev = wdev;
 
-out_stop:
-	if (rc)
-		wmi_stop_discovery(wil);
+	cfg80211_ready_on_channel(wdev, *cookie, chan, duration,
+				  GFP_KERNEL);
 
 out:
 	mutex_unlock(&wil->mutex);
@@ -170,9 +195,14 @@
 	u8 started = p2p->discovery_started;
 
 	if (p2p->discovery_started) {
-		del_timer_sync(&p2p->discovery_timer);
+		if (p2p->pending_listen_wdev) {
+			/* discovery not really started, only pending */
+			p2p->pending_listen_wdev = NULL;
+		} else {
+			del_timer_sync(&p2p->discovery_timer);
+			wmi_stop_discovery(wil);
+		}
 		p2p->discovery_started = 0;
-		wmi_stop_discovery(wil);
 	}
 
 	return started;
@@ -186,8 +216,8 @@
 	mutex_lock(&wil->mutex);
 
 	if (cookie != p2p->cookie) {
-		wil_info(wil, "%s: Cookie mismatch: 0x%016llx vs. 0x%016llx\n",
-			 __func__, p2p->cookie, cookie);
+		wil_info(wil, "Cookie mismatch: 0x%016llx vs. 0x%016llx\n",
+			 p2p->cookie, cookie);
 		mutex_unlock(&wil->mutex);
 		return -ENOENT;
 	}
@@ -197,7 +227,7 @@
 	mutex_unlock(&wil->mutex);
 
 	if (!started) {
-		wil_err(wil, "%s: listen not started\n", __func__);
+		wil_err(wil, "listen not started\n");
 		return -ENOENT;
 	}
 
@@ -219,7 +249,7 @@
 			struct wil6210_priv, p2p);
 	u8 started;
 
-	wil_dbg_misc(wil, "%s()\n", __func__);
+	wil_dbg_misc(wil, "p2p_listen_expired\n");
 
 	mutex_lock(&wil->mutex);
 	started = wil_p2p_stop_discovery(wil);
@@ -245,7 +275,7 @@
 			struct wil6210_priv, p2p);
 	u8 started;
 
-	wil_dbg_misc(wil, "%s()\n", __func__);
+	wil_dbg_misc(wil, "p2p_search_expired\n");
 
 	mutex_lock(&wil->mutex);
 	started = wil_p2p_stop_discovery(wil);
@@ -257,13 +287,59 @@
 		};
 
 		mutex_lock(&wil->p2p_wdev_mutex);
-		cfg80211_scan_done(wil->scan_request, &info);
-		wil->scan_request = NULL;
-		wil->radio_wdev = wil->wdev;
+		if (wil->scan_request) {
+			cfg80211_scan_done(wil->scan_request, &info);
+			wil->scan_request = NULL;
+			wil->radio_wdev = wil->wdev;
+		}
 		mutex_unlock(&wil->p2p_wdev_mutex);
 	}
 }
 
+void wil_p2p_delayed_listen_work(struct work_struct *work)
+{
+	struct wil_p2p_info *p2p = container_of(work,
+			struct wil_p2p_info, delayed_listen_work);
+	struct wil6210_priv *wil = container_of(p2p,
+			struct wil6210_priv, p2p);
+	int rc;
+
+	mutex_lock(&wil->mutex);
+
+	wil_dbg_misc(wil, "Checking delayed p2p listen\n");
+	if (!p2p->discovery_started || !p2p->pending_listen_wdev)
+		goto out;
+
+	mutex_lock(&wil->p2p_wdev_mutex);
+	if (wil->scan_request) {
+		/* another scan started, wait again... */
+		mutex_unlock(&wil->p2p_wdev_mutex);
+		goto out;
+	}
+	mutex_unlock(&wil->p2p_wdev_mutex);
+
+	rc = wil_p2p_start_listen(wil);
+
+	mutex_lock(&wil->p2p_wdev_mutex);
+	if (rc) {
+		cfg80211_remain_on_channel_expired(p2p->pending_listen_wdev,
+						   p2p->cookie,
+						   &p2p->listen_chan,
+						   GFP_KERNEL);
+		wil->radio_wdev = wil->wdev;
+	} else {
+		cfg80211_ready_on_channel(p2p->pending_listen_wdev, p2p->cookie,
+					  &p2p->listen_chan,
+					  p2p->listen_duration, GFP_KERNEL);
+		wil->radio_wdev = p2p->pending_listen_wdev;
+	}
+	p2p->pending_listen_wdev = NULL;
+	mutex_unlock(&wil->p2p_wdev_mutex);
+
+out:
+	mutex_unlock(&wil->mutex);
+}
+
 void wil_p2p_stop_radio_operations(struct wil6210_priv *wil)
 {
 	struct wil_p2p_info *p2p = &wil->p2p;
@@ -272,8 +348,7 @@
 	};
 
 	lockdep_assert_held(&wil->mutex);
-
-	mutex_lock(&wil->p2p_wdev_mutex);
+	lockdep_assert_held(&wil->p2p_wdev_mutex);
 
 	if (wil->radio_wdev != wil->p2p_wdev)
 		goto out;
@@ -281,10 +356,8 @@
 	if (!p2p->discovery_started) {
 		/* Regular scan on the p2p device */
 		if (wil->scan_request &&
-		    wil->scan_request->wdev == wil->p2p_wdev) {
-			cfg80211_scan_done(wil->scan_request, &info);
-			wil->scan_request = NULL;
-		}
+		    wil->scan_request->wdev == wil->p2p_wdev)
+			wil_abort_scan(wil, true);
 		goto out;
 	}
 
@@ -307,5 +380,4 @@
 
 out:
 	wil->radio_wdev = wil->wdev;
-	mutex_unlock(&wil->p2p_wdev_mutex);
 }
diff --git a/drivers/net/wireless/ath/wil6210/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c
index 44746ca..31b4591 100644
--- a/drivers/net/wireless/ath/wil6210/pcie_bus.c
+++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c
@@ -23,7 +23,7 @@
 #include <linux/rtnetlink.h>
 
 static bool use_msi = true;
-module_param(use_msi, bool, S_IRUGO);
+module_param(use_msi, bool, 0444);
 MODULE_PARM_DESC(use_msi, " Use MSI interrupt, default - true");
 
 #ifdef CONFIG_PM
@@ -36,18 +36,38 @@
 static
 void wil_set_capabilities(struct wil6210_priv *wil)
 {
-	u32 rev_id = wil_r(wil, RGF_USER_JTAG_DEV_ID);
+	u32 jtag_id = wil_r(wil, RGF_USER_JTAG_DEV_ID);
+	u8 chip_revision = (wil_r(wil, RGF_USER_REVISION_ID) &
+			    RGF_USER_REVISION_ID_MASK);
 
 	bitmap_zero(wil->hw_capabilities, hw_capability_last);
 	bitmap_zero(wil->fw_capabilities, WMI_FW_CAPABILITY_MAX);
+	wil->wil_fw_name = WIL_FW_NAME_DEFAULT;
+	wil->chip_revision = chip_revision;
 
-	switch (rev_id) {
-	case JTAG_DEV_ID_SPARROW_B0:
-		wil->hw_name = "Sparrow B0";
-		wil->hw_version = HW_VER_SPARROW_B0;
+	switch (jtag_id) {
+	case JTAG_DEV_ID_SPARROW:
+		switch (chip_revision) {
+		case REVISION_ID_SPARROW_D0:
+			wil->hw_name = "Sparrow D0";
+			wil->hw_version = HW_VER_SPARROW_D0;
+			if (wil_fw_verify_file_exists(wil,
+						      WIL_FW_NAME_SPARROW_PLUS))
+				wil->wil_fw_name = WIL_FW_NAME_SPARROW_PLUS;
+			break;
+		case REVISION_ID_SPARROW_B0:
+			wil->hw_name = "Sparrow B0";
+			wil->hw_version = HW_VER_SPARROW_B0;
+			break;
+		default:
+			wil->hw_name = "Unknown";
+			wil->hw_version = HW_VER_UNKNOWN;
+			break;
+		}
 		break;
 	default:
-		wil_err(wil, "Unknown board hardware 0x%08x\n", rev_id);
+		wil_err(wil, "Unknown board hardware, chip_id 0x%08x, chip_revision 0x%08x\n",
+			jtag_id, chip_revision);
 		wil->hw_name = "Unknown";
 		wil->hw_version = HW_VER_UNKNOWN;
 	}
@@ -55,7 +75,7 @@
 	wil_info(wil, "Board hardware is %s\n", wil->hw_name);
 
 	/* extract FW capabilities from file without loading the FW */
-	wil_request_firmware(wil, WIL_FW_NAME, false);
+	wil_request_firmware(wil, wil->wil_fw_name, false);
 }
 
 void wil_disable_irq(struct wil6210_priv *wil)
@@ -79,8 +99,10 @@
 	 */
 	int msi_only = pdev->msi_enabled;
 	bool _use_msi = use_msi;
+	bool wmi_only = test_bit(WMI_FW_CAPABILITY_WMI_ONLY,
+				 wil->fw_capabilities);
 
-	wil_dbg_misc(wil, "%s()\n", __func__);
+	wil_dbg_misc(wil, "if_pcie_enable, wmi_only %d\n", wmi_only);
 
 	pdev->msi_enabled = 0;
 
@@ -103,9 +125,11 @@
 	if (rc)
 		goto stop_master;
 
-	/* need reset here to obtain MAC */
+	/* need reset here to obtain MAC or in case of WMI-only FW, full reset
+	 * and fw loading takes place
+	 */
 	mutex_lock(&wil->mutex);
-	rc = wil_reset(wil, false);
+	rc = wil_reset(wil, wmi_only);
 	mutex_unlock(&wil->mutex);
 	if (rc)
 		goto release_irq;
@@ -125,7 +149,7 @@
 {
 	struct pci_dev *pdev = wil->pdev;
 
-	wil_dbg_misc(wil, "%s()\n", __func__);
+	wil_dbg_misc(wil, "if_pcie_disable\n");
 
 	pci_clear_master(pdev);
 	/* disable and release IRQ */
@@ -187,6 +211,22 @@
 		dev_err(dev, "wil_if_alloc failed: %d\n", rc);
 		return rc;
 	}
+
+	/* device supports 48 bit addresses */
+	rc = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(48));
+	if (rc) {
+		dev_err(dev, "dma_set_mask_and_coherent(48) failed: %d\n", rc);
+		rc = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32));
+		if (rc) {
+			dev_err(dev,
+				"dma_set_mask_and_coherent(32) failed: %d\n",
+				rc);
+			goto if_free;
+		}
+	} else {
+		wil->use_extended_dma_addr = 1;
+	}
+
 	wil->pdev = pdev;
 	pci_set_drvdata(pdev, wil);
 	/* rollback to if_free */
@@ -289,7 +329,7 @@
 	struct wil6210_priv *wil = pci_get_drvdata(pdev);
 	void __iomem *csr = wil->csr;
 
-	wil_dbg_misc(wil, "%s()\n", __func__);
+	wil_dbg_misc(wil, "pcie_remove\n");
 
 #ifdef CONFIG_PM
 #ifdef CONFIG_PM_SLEEP
@@ -327,8 +367,7 @@
 	struct pci_dev *pdev = to_pci_dev(dev);
 	struct wil6210_priv *wil = pci_get_drvdata(pdev);
 
-	wil_dbg_pm(wil, "%s(%s)\n", __func__,
-		   is_runtime ? "runtime" : "system");
+	wil_dbg_pm(wil, "suspend: %s\n", is_runtime ? "runtime" : "system");
 
 	rc = wil_can_suspend(wil, is_runtime);
 	if (rc)
@@ -354,8 +393,7 @@
 	struct pci_dev *pdev = to_pci_dev(dev);
 	struct wil6210_priv *wil = pci_get_drvdata(pdev);
 
-	wil_dbg_pm(wil, "%s(%s)\n", __func__,
-		   is_runtime ? "runtime" : "system");
+	wil_dbg_pm(wil, "resume: %s\n", is_runtime ? "runtime" : "system");
 
 	/* allow master */
 	pci_set_master(pdev);
@@ -375,7 +413,7 @@
 	int rc = 0;
 	enum wil_platform_event evt;
 
-	wil_dbg_pm(wil, "%s: mode (%ld)\n", __func__, mode);
+	wil_dbg_pm(wil, "pm_notify: mode (%ld)\n", mode);
 
 	switch (mode) {
 	case PM_HIBERNATION_PREPARE:
diff --git a/drivers/net/wireless/ath/wil6210/pm.c b/drivers/net/wireless/ath/wil6210/pm.c
index 11ee24d..a0acb2d 100644
--- a/drivers/net/wireless/ath/wil6210/pm.c
+++ b/drivers/net/wireless/ath/wil6210/pm.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014,2016 Qualcomm Atheros, Inc.
+ * Copyright (c) 2014,2017 Qualcomm Atheros, Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -21,8 +21,7 @@
 	int rc = 0;
 	struct wireless_dev *wdev = wil->wdev;
 
-	wil_dbg_pm(wil, "%s(%s)\n", __func__,
-		   is_runtime ? "runtime" : "system");
+	wil_dbg_pm(wil, "can_suspend: %s\n", is_runtime ? "runtime" : "system");
 
 	if (!netif_running(wil_to_ndev(wil))) {
 		/* can always sleep when down */
@@ -59,7 +58,7 @@
 	}
 
 out:
-	wil_dbg_pm(wil, "%s(%s) => %s (%d)\n", __func__,
+	wil_dbg_pm(wil, "can_suspend: %s => %s (%d)\n",
 		   is_runtime ? "runtime" : "system", rc ? "No" : "Yes", rc);
 
 	return rc;
@@ -70,8 +69,7 @@
 	int rc = 0;
 	struct net_device *ndev = wil_to_ndev(wil);
 
-	wil_dbg_pm(wil, "%s(%s)\n", __func__,
-		   is_runtime ? "runtime" : "system");
+	wil_dbg_pm(wil, "suspend: %s\n", is_runtime ? "runtime" : "system");
 
 	/* if netif up, hardware is alive, shut it down */
 	if (ndev->flags & IFF_UP) {
@@ -86,7 +84,7 @@
 		rc = wil->platform_ops.suspend(wil->platform_handle);
 
 out:
-	wil_dbg_pm(wil, "%s(%s) => %d\n", __func__,
+	wil_dbg_pm(wil, "suspend: %s => %d\n",
 		   is_runtime ? "runtime" : "system", rc);
 	return rc;
 }
@@ -96,8 +94,7 @@
 	int rc = 0;
 	struct net_device *ndev = wil_to_ndev(wil);
 
-	wil_dbg_pm(wil, "%s(%s)\n", __func__,
-		   is_runtime ? "runtime" : "system");
+	wil_dbg_pm(wil, "resume: %s\n", is_runtime ? "runtime" : "system");
 
 	if (wil->platform_ops.resume) {
 		rc = wil->platform_ops.resume(wil->platform_handle);
@@ -115,7 +112,7 @@
 		rc = wil_up(wil);
 
 out:
-	wil_dbg_pm(wil, "%s(%s) => %d\n", __func__,
+	wil_dbg_pm(wil, "resume: %s => %d\n",
 		   is_runtime ? "runtime" : "system", rc);
 	return rc;
 }
diff --git a/drivers/net/wireless/ath/wil6210/pmc.c b/drivers/net/wireless/ath/wil6210/pmc.c
index 5ca0307..b067fdf 100644
--- a/drivers/net/wireless/ath/wil6210/pmc.c
+++ b/drivers/net/wireless/ath/wil6210/pmc.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2015 Qualcomm Atheros, Inc.
+ * Copyright (c) 2012-2015,2017 Qualcomm Atheros, Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -54,53 +54,90 @@
 	struct pmc_ctx *pmc = &wil->pmc;
 	struct device *dev = wil_to_dev(wil);
 	struct wmi_pmc_cmd pmc_cmd = {0};
+	int last_cmd_err = -ENOMEM;
 
 	mutex_lock(&pmc->lock);
 
 	if (wil_is_pmc_allocated(pmc)) {
 		/* sanity check */
-		wil_err(wil, "%s: ERROR pmc is already allocated\n", __func__);
+		wil_err(wil, "ERROR pmc is already allocated\n");
+		goto no_release_err;
+	}
+	if ((num_descriptors <= 0) || (descriptor_size <= 0)) {
+		wil_err(wil,
+			"Invalid params num_descriptors(%d), descriptor_size(%d)\n",
+			num_descriptors, descriptor_size);
+		last_cmd_err = -EINVAL;
+		goto no_release_err;
+	}
+
+	if (num_descriptors > (1 << WIL_RING_SIZE_ORDER_MAX)) {
+		wil_err(wil,
+			"num_descriptors(%d) exceeds max ring size %d\n",
+			num_descriptors, 1 << WIL_RING_SIZE_ORDER_MAX);
+		last_cmd_err = -EINVAL;
+		goto no_release_err;
+	}
+
+	if (num_descriptors > INT_MAX / descriptor_size) {
+		wil_err(wil,
+			"Overflow in num_descriptors(%d)*descriptor_size(%d)\n",
+			num_descriptors, descriptor_size);
+		last_cmd_err = -EINVAL;
 		goto no_release_err;
 	}
 
 	pmc->num_descriptors = num_descriptors;
 	pmc->descriptor_size = descriptor_size;
 
-	wil_dbg_misc(wil, "%s: %d descriptors x %d bytes each\n",
-		     __func__, num_descriptors, descriptor_size);
+	wil_dbg_misc(wil, "pmc_alloc: %d descriptors x %d bytes each\n",
+		     num_descriptors, descriptor_size);
 
 	/* allocate descriptors info list in pmc context*/
 	pmc->descriptors = kcalloc(num_descriptors,
 				  sizeof(struct desc_alloc_info),
 				  GFP_KERNEL);
 	if (!pmc->descriptors) {
-		wil_err(wil, "%s: ERROR allocating pmc skb list\n", __func__);
+		wil_err(wil, "ERROR allocating pmc skb list\n");
 		goto no_release_err;
 	}
 
-	wil_dbg_misc(wil,
-		     "%s: allocated descriptors info list %p\n",
-		     __func__, pmc->descriptors);
+	wil_dbg_misc(wil, "pmc_alloc: allocated descriptors info list %p\n",
+		     pmc->descriptors);
 
 	/* Allocate pring buffer and descriptors.
 	 * vring->va should be aligned on its size rounded up to power of 2
-	 * This is granted by the dma_alloc_coherent
+	 * This is granted by the dma_alloc_coherent.
+	 *
+	 * HW has limitation that all vrings addresses must share the same
+	 * upper 16 msb bits part of 48 bits address. To workaround that,
+	 * if we are using 48 bit addresses switch to 32 bit allocation
+	 * before allocating vring memory.
+	 *
+	 * There's no check for the return value of dma_set_mask_and_coherent,
+	 * since we assume if we were able to set the mask during
+	 * initialization in this system it will not fail if we set it again
 	 */
+	if (wil->use_extended_dma_addr)
+		dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32));
+
 	pmc->pring_va = dma_alloc_coherent(dev,
 			sizeof(struct vring_tx_desc) * num_descriptors,
 			&pmc->pring_pa,
 			GFP_KERNEL);
 
+	if (wil->use_extended_dma_addr)
+		dma_set_mask_and_coherent(dev, DMA_BIT_MASK(48));
+
 	wil_dbg_misc(wil,
-		     "%s: allocated pring %p => %pad. %zd x %d = total %zd bytes\n",
-		     __func__,
+		     "pmc_alloc: allocated pring %p => %pad. %zd x %d = total %zd bytes\n",
 		     pmc->pring_va, &pmc->pring_pa,
 		     sizeof(struct vring_tx_desc),
 		     num_descriptors,
 		     sizeof(struct vring_tx_desc) * num_descriptors);
 
 	if (!pmc->pring_va) {
-		wil_err(wil, "%s: ERROR allocating pmc pring\n", __func__);
+		wil_err(wil, "ERROR allocating pmc pring\n");
 		goto release_pmc_skb_list;
 	}
 
@@ -119,9 +156,7 @@
 			GFP_KERNEL);
 
 		if (unlikely(!pmc->descriptors[i].va)) {
-			wil_err(wil,
-				"%s: ERROR allocating pmc descriptor %d",
-				__func__, i);
+			wil_err(wil, "ERROR allocating pmc descriptor %d", i);
 			goto release_pmc_skbs;
 		}
 
@@ -141,21 +176,21 @@
 		*_d = *d;
 	}
 
-	wil_dbg_misc(wil, "%s: allocated successfully\n", __func__);
+	wil_dbg_misc(wil, "pmc_alloc: allocated successfully\n");
 
 	pmc_cmd.op = WMI_PMC_ALLOCATE;
 	pmc_cmd.ring_size = cpu_to_le16(pmc->num_descriptors);
 	pmc_cmd.mem_base = cpu_to_le64(pmc->pring_pa);
 
-	wil_dbg_misc(wil, "%s: send WMI_PMC_CMD with ALLOCATE op\n", __func__);
+	wil_dbg_misc(wil, "pmc_alloc: send WMI_PMC_CMD with ALLOCATE op\n");
 	pmc->last_cmd_status = wmi_send(wil,
 					WMI_PMC_CMDID,
 					&pmc_cmd,
 					sizeof(pmc_cmd));
 	if (pmc->last_cmd_status) {
 		wil_err(wil,
-			"%s: WMI_PMC_CMD with ALLOCATE op failed with status %d",
-			__func__, pmc->last_cmd_status);
+			"WMI_PMC_CMD with ALLOCATE op failed with status %d",
+			pmc->last_cmd_status);
 		goto release_pmc_skbs;
 	}
 
@@ -164,7 +199,7 @@
 	return;
 
 release_pmc_skbs:
-	wil_err(wil, "%s: exit on error: Releasing skbs...\n", __func__);
+	wil_err(wil, "exit on error: Releasing skbs...\n");
 	for (i = 0; pmc->descriptors[i].va && i < num_descriptors; i++) {
 		dma_free_coherent(dev,
 				  descriptor_size,
@@ -173,7 +208,7 @@
 
 		pmc->descriptors[i].va = NULL;
 	}
-	wil_err(wil, "%s: exit on error: Releasing pring...\n", __func__);
+	wil_err(wil, "exit on error: Releasing pring...\n");
 
 	dma_free_coherent(dev,
 			  sizeof(struct vring_tx_desc) * num_descriptors,
@@ -183,13 +218,12 @@
 	pmc->pring_va = NULL;
 
 release_pmc_skb_list:
-	wil_err(wil, "%s: exit on error: Releasing descriptors info list...\n",
-		__func__);
+	wil_err(wil, "exit on error: Releasing descriptors info list...\n");
 	kfree(pmc->descriptors);
 	pmc->descriptors = NULL;
 
 no_release_err:
-	pmc->last_cmd_status = -ENOMEM;
+	pmc->last_cmd_status = last_cmd_err;
 	mutex_unlock(&pmc->lock);
 }
 
@@ -208,24 +242,23 @@
 	pmc->last_cmd_status = 0;
 
 	if (!wil_is_pmc_allocated(pmc)) {
-		wil_dbg_misc(wil, "%s: Error, can't free - not allocated\n",
-			     __func__);
+		wil_dbg_misc(wil,
+			     "pmc_free: Error, can't free - not allocated\n");
 		pmc->last_cmd_status = -EPERM;
 		mutex_unlock(&pmc->lock);
 		return;
 	}
 
 	if (send_pmc_cmd) {
-		wil_dbg_misc(wil, "%s: send WMI_PMC_CMD with RELEASE op\n",
-			     __func__);
+		wil_dbg_misc(wil, "send WMI_PMC_CMD with RELEASE op\n");
 		pmc_cmd.op = WMI_PMC_RELEASE;
 		pmc->last_cmd_status =
 				wmi_send(wil, WMI_PMC_CMDID, &pmc_cmd,
 					 sizeof(pmc_cmd));
 		if (pmc->last_cmd_status) {
 			wil_err(wil,
-				"%s WMI_PMC_CMD with RELEASE op failed, status %d",
-				__func__, pmc->last_cmd_status);
+				"WMI_PMC_CMD with RELEASE op failed, status %d",
+				pmc->last_cmd_status);
 			/* There's nothing we can do with this error.
 			 * Normally, it should never occur.
 			 * Continue to freeing all memory allocated for pmc.
@@ -237,8 +270,8 @@
 		size_t buf_size = sizeof(struct vring_tx_desc) *
 				  pmc->num_descriptors;
 
-		wil_dbg_misc(wil, "%s: free pring va %p\n",
-			     __func__, pmc->pring_va);
+		wil_dbg_misc(wil, "pmc_free: free pring va %p\n",
+			     pmc->pring_va);
 		dma_free_coherent(dev, buf_size, pmc->pring_va, pmc->pring_pa);
 
 		pmc->pring_va = NULL;
@@ -257,11 +290,11 @@
 					  pmc->descriptors[i].pa);
 			pmc->descriptors[i].va = NULL;
 		}
-		wil_dbg_misc(wil, "%s: free descriptor info %d/%d\n",
-			     __func__, i, pmc->num_descriptors);
+		wil_dbg_misc(wil, "pmc_free: free descriptor info %d/%d\n", i,
+			     pmc->num_descriptors);
 		wil_dbg_misc(wil,
-			     "%s: free pmc descriptors info list %p\n",
-			     __func__, pmc->descriptors);
+			     "pmc_free: free pmc descriptors info list %p\n",
+			     pmc->descriptors);
 		kfree(pmc->descriptors);
 		pmc->descriptors = NULL;
 	} else {
@@ -277,7 +310,7 @@
  */
 int wil_pmc_last_cmd_status(struct wil6210_priv *wil)
 {
-	wil_dbg_misc(wil, "%s: status %d\n", __func__,
+	wil_dbg_misc(wil, "pmc_last_cmd_status: status %d\n",
 		     wil->pmc.last_cmd_status);
 
 	return wil->pmc.last_cmd_status;
@@ -295,20 +328,22 @@
 	size_t retval = 0;
 	unsigned long long idx;
 	loff_t offset;
-	size_t pmc_size = pmc->descriptor_size * pmc->num_descriptors;
+	size_t pmc_size;
 
 	mutex_lock(&pmc->lock);
 
 	if (!wil_is_pmc_allocated(pmc)) {
-		wil_err(wil, "%s: error, pmc is not allocated!\n", __func__);
+		wil_err(wil, "error, pmc is not allocated!\n");
 		pmc->last_cmd_status = -EPERM;
 		mutex_unlock(&pmc->lock);
 		return -EPERM;
 	}
 
+	pmc_size = pmc->descriptor_size * pmc->num_descriptors;
+
 	wil_dbg_misc(wil,
-		     "%s: size %u, pos %lld\n",
-		     __func__, (unsigned)count, *f_pos);
+		     "pmc_read: size %u, pos %lld\n",
+		     (u32)count, *f_pos);
 
 	pmc->last_cmd_status = 0;
 
@@ -317,15 +352,16 @@
 	offset = *f_pos - (idx * pmc->descriptor_size);
 
 	if (*f_pos >= pmc_size) {
-		wil_dbg_misc(wil, "%s: reached end of pmc buf: %lld >= %u\n",
-			     __func__, *f_pos, (unsigned)pmc_size);
+		wil_dbg_misc(wil,
+			     "pmc_read: reached end of pmc buf: %lld >= %u\n",
+			     *f_pos, (u32)pmc_size);
 		pmc->last_cmd_status = -ERANGE;
 		goto out;
 	}
 
 	wil_dbg_misc(wil,
-		     "%s: read from pos %lld (descriptor %llu, offset %llu) %zu bytes\n",
-		     __func__, *f_pos, idx, offset, count);
+		     "pmc_read: read from pos %lld (descriptor %llu, offset %llu) %zu bytes\n",
+		     *f_pos, idx, offset, count);
 
 	/* if no errors, return the copied byte count */
 	retval = simple_read_from_buffer(buf,
@@ -345,7 +381,18 @@
 	loff_t newpos;
 	struct wil6210_priv *wil = filp->private_data;
 	struct pmc_ctx *pmc = &wil->pmc;
-	size_t pmc_size = pmc->descriptor_size * pmc->num_descriptors;
+	size_t pmc_size;
+
+	mutex_lock(&pmc->lock);
+
+	if (!wil_is_pmc_allocated(pmc)) {
+		wil_err(wil, "error, pmc is not allocated!\n");
+		pmc->last_cmd_status = -EPERM;
+		mutex_unlock(&pmc->lock);
+		return -EPERM;
+	}
+
+	pmc_size = pmc->descriptor_size * pmc->num_descriptors;
 
 	switch (whence) {
 	case 0: /* SEEK_SET */
@@ -361,15 +408,21 @@
 		break;
 
 	default: /* can't happen */
-		return -EINVAL;
+		newpos = -EINVAL;
+		goto out;
 	}
 
-	if (newpos < 0)
-		return -EINVAL;
+	if (newpos < 0) {
+		newpos = -EINVAL;
+		goto out;
+	}
 	if (newpos > pmc_size)
 		newpos = pmc_size;
 
 	filp->f_pos = newpos;
 
+out:
+	mutex_unlock(&pmc->lock);
+
 	return newpos;
 }
diff --git a/drivers/net/wireless/ath/wil6210/rx_reorder.c b/drivers/net/wireless/ath/wil6210/rx_reorder.c
index 19ed127..7404b6f 100644
--- a/drivers/net/wireless/ath/wil6210/rx_reorder.c
+++ b/drivers/net/wireless/ath/wil6210/rx_reorder.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2016 Qualcomm Atheros, Inc.
+ * Copyright (c) 2014-2017 Qualcomm Atheros, Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -349,8 +349,8 @@
 	rc = wmi_addba_rx_resp(wil, cid, tid, dialog_token, status,
 			       agg_amsdu, agg_wsize, agg_timeout);
 	if (rc || (status != WLAN_STATUS_SUCCESS)) {
-		wil_err(wil, "%s: do not apply ba, rc(%d), status(%d)\n",
-			__func__, rc, status);
+		wil_err(wil, "do not apply ba, rc(%d), status(%d)\n", rc,
+			status);
 		goto out;
 	}
 
@@ -387,7 +387,7 @@
 	txdata->addba_in_progress = true;
 	rc = wmi_addba(wil, ringid, agg_wsize, agg_timeout);
 	if (rc) {
-		wil_err(wil, "%s: wmi_addba failed, rc (%d)", __func__, rc);
+		wil_err(wil, "wmi_addba failed, rc (%d)", rc);
 		txdata->addba_in_progress = false;
 	}
 
diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c
index 4c38520..8b5411e 100644
--- a/drivers/net/wireless/ath/wil6210/txrx.c
+++ b/drivers/net/wireless/ath/wil6210/txrx.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2016 Qualcomm Atheros, Inc.
+ * Copyright (c) 2012-2017 Qualcomm Atheros, Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -29,12 +29,12 @@
 #include "trace.h"
 
 static bool rtap_include_phy_info;
-module_param(rtap_include_phy_info, bool, S_IRUGO);
+module_param(rtap_include_phy_info, bool, 0444);
 MODULE_PARM_DESC(rtap_include_phy_info,
 		 " Include PHY info in the radiotap header, default - no");
 
 bool rx_align_2;
-module_param(rx_align_2, bool, S_IRUGO);
+module_param(rx_align_2, bool, 0444);
 MODULE_PARM_DESC(rx_align_2, " align Rx buffers on 4*n+2, default - no");
 
 static inline uint wil_rx_snaplen(void)
@@ -88,6 +88,18 @@
 	return vring->size/4;
 }
 
+/* returns true if num avail descriptors is lower than wmark_low */
+static inline int wil_vring_avail_low(struct vring *vring)
+{
+	return wil_vring_avail_tx(vring) < wil_vring_wmark_low(vring);
+}
+
+/* returns true if num avail descriptors is higher than wmark_high */
+static inline int wil_vring_avail_high(struct vring *vring)
+{
+	return wil_vring_avail_tx(vring) > wil_vring_wmark_high(vring);
+}
+
 /* wil_val_in_range - check if value in [min,max) */
 static inline bool wil_val_in_range(int val, int min, int max)
 {
@@ -100,7 +112,7 @@
 	size_t sz = vring->size * sizeof(vring->va[0]);
 	uint i;
 
-	wil_dbg_misc(wil, "%s()\n", __func__);
+	wil_dbg_misc(wil, "vring_alloc:\n");
 
 	BUILD_BUG_ON(sizeof(vring->va[0]) != 32);
 
@@ -111,15 +123,32 @@
 		vring->va = NULL;
 		return -ENOMEM;
 	}
+
 	/* vring->va should be aligned on its size rounded up to power of 2
-	 * This is granted by the dma_alloc_coherent
+	 * This is granted by the dma_alloc_coherent.
+	 *
+	 * HW has limitation that all vrings addresses must share the same
+	 * upper 16 msb bits part of 48 bits address. To workaround that,
+	 * if we are using 48 bit addresses switch to 32 bit allocation
+	 * before allocating vring memory.
+	 *
+	 * There's no check for the return value of dma_set_mask_and_coherent,
+	 * since we assume if we were able to set the mask during
+	 * initialization in this system it will not fail if we set it again
 	 */
+	if (wil->use_extended_dma_addr)
+		dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32));
+
 	vring->va = dma_alloc_coherent(dev, sz, &vring->pa, GFP_KERNEL);
 	if (!vring->va) {
 		kfree(vring->ctx);
 		vring->ctx = NULL;
 		return -ENOMEM;
 	}
+
+	if (wil->use_extended_dma_addr)
+		dma_set_mask_and_coherent(dev, DMA_BIT_MASK(48));
+
 	/* initially, all descriptors are SW owned
 	 * For Tx and Rx, ownership bit is at the same location, thus
 	 * we can use any
@@ -733,7 +762,7 @@
 		wil_err(wil, "Rx IRQ while Rx not yet initialized\n");
 		return;
 	}
-	wil_dbg_txrx(wil, "%s()\n", __func__);
+	wil_dbg_txrx(wil, "rx_handle\n");
 	while ((*quota > 0) && (NULL != (skb = wil_vring_reap_rx(wil, v)))) {
 		(*quota)--;
 
@@ -756,7 +785,7 @@
 	struct vring *vring = &wil->vring_rx;
 	int rc;
 
-	wil_dbg_misc(wil, "%s()\n", __func__);
+	wil_dbg_misc(wil, "rx_init\n");
 
 	if (vring->va) {
 		wil_err(wil, "Rx ring already allocated\n");
@@ -787,7 +816,7 @@
 {
 	struct vring *vring = &wil->vring_rx;
 
-	wil_dbg_misc(wil, "%s()\n", __func__);
+	wil_dbg_misc(wil, "rx_fini\n");
 
 	if (vring->va)
 		wil_vring_free(wil, vring, 0);
@@ -839,7 +868,7 @@
 	struct vring *vring = &wil->vring_tx[id];
 	struct vring_tx_data *txdata = &wil->vring_tx_data[id];
 
-	wil_dbg_misc(wil, "%s() max_mpdu_size %d\n", __func__,
+	wil_dbg_misc(wil, "vring_init_tx: max_mpdu_size %d\n",
 		     cmd.vring_cfg.tx_sw_ring.max_mpdu_size);
 	lockdep_assert_held(&wil->mutex);
 
@@ -919,7 +948,7 @@
 	struct vring *vring = &wil->vring_tx[id];
 	struct vring_tx_data *txdata = &wil->vring_tx_data[id];
 
-	wil_dbg_misc(wil, "%s() max_mpdu_size %d\n", __func__,
+	wil_dbg_misc(wil, "vring_init_bcast: max_mpdu_size %d\n",
 		     cmd.vring_cfg.tx_sw_ring.max_mpdu_size);
 	lockdep_assert_held(&wil->mutex);
 
@@ -981,7 +1010,7 @@
 	if (!vring->va)
 		return;
 
-	wil_dbg_misc(wil, "%s() id=%d\n", __func__, id);
+	wil_dbg_misc(wil, "vring_fini_tx: id=%d\n", id);
 
 	spin_lock_bh(&txdata->lock);
 	txdata->dot1x_open = false;
@@ -1020,12 +1049,14 @@
 			struct vring *v = &wil->vring_tx[i];
 			struct vring_tx_data *txdata = &wil->vring_tx_data[i];
 
-			wil_dbg_txrx(wil, "%s(%pM) -> [%d]\n",
-				     __func__, eth->h_dest, i);
+			wil_dbg_txrx(wil, "find_tx_ucast: (%pM) -> [%d]\n",
+				     eth->h_dest, i);
 			if (v->va && txdata->enabled) {
 				return v;
 			} else {
-				wil_dbg_txrx(wil, "vring[%d] not valid\n", i);
+				wil_dbg_txrx(wil,
+					     "find_tx_ucast: vring[%d] not valid\n",
+					     i);
 				return NULL;
 			}
 		}
@@ -1181,17 +1212,6 @@
 	return v;
 }
 
-static struct vring *wil_find_tx_bcast(struct wil6210_priv *wil,
-				       struct sk_buff *skb)
-{
-	struct wireless_dev *wdev = wil->wdev;
-
-	if (wdev->iftype != NL80211_IFTYPE_AP)
-		return wil_find_tx_bcast_2(wil, skb);
-
-	return wil_find_tx_bcast_1(wil, skb);
-}
-
 static int wil_tx_desc_map(struct vring_tx_desc *d, dma_addr_t pa, u32 len,
 			   int vring_index)
 {
@@ -1361,8 +1381,8 @@
 	int gso_type;
 	int rc = -EINVAL;
 
-	wil_dbg_txrx(wil, "%s() %d bytes to vring %d\n",
-		     __func__, skb->len, vring_index);
+	wil_dbg_txrx(wil, "tx_vring_tso: %d bytes to vring %d\n", skb->len,
+		     vring_index);
 
 	if (unlikely(!txdata->enabled))
 		return -EINVAL;
@@ -1631,8 +1651,8 @@
 	bool mcast = (vring_index == wil->bcast_vring);
 	uint len = skb_headlen(skb);
 
-	wil_dbg_txrx(wil, "%s() %d bytes to vring %d\n",
-		     __func__, skb->len, vring_index);
+	wil_dbg_txrx(wil, "tx_vring: %d bytes to vring %d\n", skb->len,
+		     vring_index);
 
 	if (unlikely(!txdata->enabled))
 		return -EINVAL;
@@ -1780,6 +1800,89 @@
 	return rc;
 }
 
+/**
+ * Check status of tx vrings and stop/wake net queues if needed
+ *
+ * This function does one of two checks:
+ * In case check_stop is true, will check if net queues need to be stopped. If
+ * the conditions for stopping are met, netif_tx_stop_all_queues() is called.
+ * In case check_stop is false, will check if net queues need to be waked. If
+ * the conditions for waking are met, netif_tx_wake_all_queues() is called.
+ * vring is the vring which is currently being modified by either adding
+ * descriptors (tx) into it or removing descriptors (tx complete) from it. Can
+ * be null when irrelevant (e.g. connect/disconnect events).
+ *
+ * The implementation is to stop net queues if modified vring has low
+ * descriptor availability. Wake if all vrings are not in low descriptor
+ * availability and modified vring has high descriptor availability.
+ */
+static inline void __wil_update_net_queues(struct wil6210_priv *wil,
+					   struct vring *vring,
+					   bool check_stop)
+{
+	int i;
+
+	if (vring)
+		wil_dbg_txrx(wil, "vring %d, check_stop=%d, stopped=%d",
+			     (int)(vring - wil->vring_tx), check_stop,
+			     wil->net_queue_stopped);
+	else
+		wil_dbg_txrx(wil, "check_stop=%d, stopped=%d",
+			     check_stop, wil->net_queue_stopped);
+
+	if (check_stop == wil->net_queue_stopped)
+		/* net queues already in desired state */
+		return;
+
+	if (check_stop) {
+		if (!vring || unlikely(wil_vring_avail_low(vring))) {
+			/* not enough room in the vring */
+			netif_tx_stop_all_queues(wil_to_ndev(wil));
+			wil->net_queue_stopped = true;
+			wil_dbg_txrx(wil, "netif_tx_stop called\n");
+		}
+		return;
+	}
+
+	/* check wake */
+	for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) {
+		struct vring *cur_vring = &wil->vring_tx[i];
+		struct vring_tx_data *txdata = &wil->vring_tx_data[i];
+
+		if (!cur_vring->va || !txdata->enabled || cur_vring == vring)
+			continue;
+
+		if (wil_vring_avail_low(cur_vring)) {
+			wil_dbg_txrx(wil, "vring %d full, can't wake\n",
+				     (int)(cur_vring - wil->vring_tx));
+			return;
+		}
+	}
+
+	if (!vring || wil_vring_avail_high(vring)) {
+		/* enough room in the vring */
+		wil_dbg_txrx(wil, "calling netif_tx_wake\n");
+		netif_tx_wake_all_queues(wil_to_ndev(wil));
+		wil->net_queue_stopped = false;
+	}
+}
+
+void wil_update_net_queues(struct wil6210_priv *wil, struct vring *vring,
+			   bool check_stop)
+{
+	spin_lock(&wil->net_queue_lock);
+	__wil_update_net_queues(wil, vring, check_stop);
+	spin_unlock(&wil->net_queue_lock);
+}
+
+void wil_update_net_queues_bh(struct wil6210_priv *wil, struct vring *vring,
+			      bool check_stop)
+{
+	spin_lock_bh(&wil->net_queue_lock);
+	__wil_update_net_queues(wil, vring, check_stop);
+	spin_unlock_bh(&wil->net_queue_lock);
+}
+
 netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 {
 	struct wil6210_priv *wil = ndev_to_wil(ndev);
@@ -1789,7 +1892,7 @@
 	static bool pr_once_fw;
 	int rc;
 
-	wil_dbg_txrx(wil, "%s()\n", __func__);
+	wil_dbg_txrx(wil, "start_xmit\n");
 	if (unlikely(!test_bit(wil_status_fwready, wil->status))) {
 		if (!pr_once_fw) {
 			wil_err(wil, "FW not ready\n");
@@ -1808,12 +1911,26 @@
 	pr_once_fw = false;
 
 	/* find vring */
-	if (wil->wdev->iftype == NL80211_IFTYPE_STATION) {
-		/* in STA mode (ESS), all to same VRING */
+	if (wil->wdev->iftype == NL80211_IFTYPE_STATION && !wil->pbss) {
+		/* in STA mode (ESS), all to same VRING (to AP) */
 		vring = wil_find_tx_vring_sta(wil, skb);
-	} else { /* direct communication, find matching VRING */
-		vring = bcast ? wil_find_tx_bcast(wil, skb) :
-				wil_find_tx_ucast(wil, skb);
+	} else if (bcast) {
+		if (wil->pbss)
+			/* in pbss, no bcast VRING - duplicate skb in
+			 * all stations VRINGs
+			 */
+			vring = wil_find_tx_bcast_2(wil, skb);
+		else if (wil->wdev->iftype == NL80211_IFTYPE_AP)
+			/* AP has a dedicated bcast VRING */
+			vring = wil_find_tx_bcast_1(wil, skb);
+		else
+			/* unexpected combination, fallback to duplicating
+			 * the skb in all stations VRINGs
+			 */
+			vring = wil_find_tx_bcast_2(wil, skb);
+	} else {
+		/* unicast, find specific VRING by dest. address */
+		vring = wil_find_tx_ucast(wil, skb);
 	}
 	if (unlikely(!vring)) {
 		wil_dbg_txrx(wil, "No Tx VRING found for %pM\n", eth->h_dest);
@@ -1822,14 +1939,10 @@
 	/* set up vring entry */
 	rc = wil_tx_vring(wil, vring, skb);
 
-	/* do we still have enough room in the vring? */
-	if (unlikely(wil_vring_avail_tx(vring) < wil_vring_wmark_low(vring))) {
-		netif_tx_stop_all_queues(wil_to_ndev(wil));
-		wil_dbg_txrx(wil, "netif_tx_stop : ring full\n");
-	}
-
 	switch (rc) {
 	case 0:
+		/* shall we stop net queues? */
+		wil_update_net_queues_bh(wil, vring, true);
 		/* statistics will be updated on the tx_complete */
 		dev_kfree_skb_any(skb);
 		return NETDEV_TX_OK;
@@ -1891,7 +2004,7 @@
 		return 0;
 	}
 
-	wil_dbg_txrx(wil, "%s(%d)\n", __func__, ringid);
+	wil_dbg_txrx(wil, "tx_complete: (%d)\n", ringid);
 
 	used_before_complete = wil_vring_used_tx(vring);
 
@@ -1978,10 +2091,9 @@
 		txdata->last_idle = get_cycles();
 	}
 
-	if (wil_vring_avail_tx(vring) > wil_vring_wmark_high(vring)) {
-		wil_dbg_txrx(wil, "netif_tx_wake : ring not full\n");
-		netif_tx_wake_all_queues(wil_to_ndev(wil));
-	}
+	/* shall we wake net queues? */
+	if (done)
+		wil_update_net_queues(wil, vring, false);
 
 	return done;
 }
diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h
index a949cd6..18a8872 100644
--- a/drivers/net/wireless/ath/wil6210/wil6210.h
+++ b/drivers/net/wireless/ath/wil6210/wil6210.h
@@ -25,6 +25,7 @@
 #include <linux/types.h>
 #include "wmi.h"
 #include "wil_platform.h"
+#include "ftm.h"
 
 extern bool no_fw_recovery;
 extern unsigned int mtu_max;
@@ -33,10 +34,12 @@
 extern u32 vring_idle_trsh;
 extern bool rx_align_2;
 extern bool debug_fw;
+extern bool disable_ap_sme;
 
 #define WIL_NAME "wil6210"
-#define WIL_FW_NAME "wil6210.fw" /* code */
-#define WIL_FW2_NAME "wil6210.brd" /* board & radio parameters */
+#define WIL_FW_NAME_DEFAULT "wil6210.fw" /* code Sparrow B0 */
+#define WIL_FW_NAME_SPARROW_PLUS "wil6210_sparrow_plus.fw" /* code Sparrow D0 */
+#define WIL_BOARD_FILE_NAME "wil6210.brd" /* board & radio parameters */
 
 #define WIL_MAX_BUS_REQUEST_KBPS 800000 /* ~6.1Gbps */
 
@@ -98,6 +101,9 @@
 #define WIL6210_RX_HIGH_TRSH_INIT		(0)
 #define WIL6210_RX_HIGH_TRSH_DEFAULT \
 				(1 << (WIL_RX_RING_SIZE_ORDER_DEFAULT - 3))
+#define WIL_MAX_DMG_AID 254 /* for DMG only 1-254 allowed (see
+			     * 802.11REVmc/D5.0, section 9.4.1.8)
+			     */
 /* Hardware definitions begin */
 
 /*
@@ -249,7 +255,12 @@
 	#define BIT_CAF_OSC_DIG_XTAL_STABLE	BIT(0)
 
 #define RGF_USER_JTAG_DEV_ID	(0x880b34) /* device ID */
-	#define JTAG_DEV_ID_SPARROW_B0	(0x2632072f)
+	#define JTAG_DEV_ID_SPARROW	(0x2632072f)
+
+#define RGF_USER_REVISION_ID		(0x88afe4)
+#define RGF_USER_REVISION_ID_MASK	(3)
+	#define REVISION_ID_SPARROW_B0	(0x0)
+	#define REVISION_ID_SPARROW_D0	(0x3)
 
 /* crash codes for FW/Ucode stored here */
 #define RGF_FW_ASSERT_CODE		(0x91f020)
@@ -257,7 +268,8 @@
 
 enum {
 	HW_VER_UNKNOWN,
-	HW_VER_SPARROW_B0, /* JTAG_DEV_ID_SPARROW_B0 */
+	HW_VER_SPARROW_B0, /* REVISION_ID_SPARROW_B0 */
+	HW_VER_SPARROW_D0, /* REVISION_ID_SPARROW_D0 */
 };
 
 /* popular locations */
@@ -276,10 +288,11 @@
 	u32 to;   /* linker address - to, exclusive */
 	u32 host; /* PCI/Host address - BAR0 + 0x880000 */
 	const char *name; /* for debugfs */
+	bool fw; /* true if FW mapping, false if UCODE mapping */
 };
 
 /* array size should be in sync with actual definition in the wmi.c */
-extern const struct fw_map fw_mapping[8];
+extern const struct fw_map fw_mapping[10];
 
 /**
  * mk_cidxtid - construct @cidxtid field
@@ -461,8 +474,11 @@
 	u8 discovery_started;
 	u8 p2p_dev_started;
 	u64 cookie;
+	struct wireless_dev *pending_listen_wdev;
+	unsigned int listen_duration;
 	struct timer_list discovery_timer; /* listen/search duration */
 	struct work_struct discovery_expired_work; /* listen/search expire */
+	struct work_struct delayed_listen_work; /* listen after scan done */
 };
 
 enum wil_sta_status {
@@ -508,6 +524,7 @@
 	unsigned long tid_rx_stop_requested[BITS_TO_LONGS(WIL_STA_TID_NUM)];
 	struct wil_tid_crypto_rx tid_crypto_rx[WIL_STA_TID_NUM];
 	struct wil_tid_crypto_rx group_crypto_rx;
+	u8 aid; /* 1-254; 0 if unknown/not reported */
 };
 
 enum {
@@ -579,7 +596,9 @@
 	DECLARE_BITMAP(status, wil_status_last);
 	u8 fw_version[ETHTOOL_FWVERS_LEN];
 	u32 hw_version;
+	u8 chip_revision;
 	const char *hw_name;
+	const char *wil_fw_name;
 	DECLARE_BITMAP(hw_capabilities, hw_capability_last);
 	DECLARE_BITMAP(fw_capabilities, WMI_FW_CAPABILITY_MAX);
 	u8 n_mids; /* number of additional MIDs as reported by FW */
@@ -624,6 +643,8 @@
 	 * - consumed in thread by wmi_event_worker
 	 */
 	spinlock_t wmi_ev_lock;
+	spinlock_t net_queue_lock; /* guarding stop/wake netif queue */
+	int net_queue_stopped; /* netif_tx_stop_all_queues invoked */
 	struct napi_struct napi_rx;
 	struct napi_struct napi_tx;
 	/* keep alive */
@@ -637,6 +658,7 @@
 	u8 vring2cid_tid[WIL6210_MAX_TX_RINGS][2]; /* [0] - CID, [1] - TID */
 	struct wil_sta_info sta[WIL6210_MAX_CID];
 	int bcast_vring;
+	bool use_extended_dma_addr; /* indicates whether we are using 48 bits */
 	/* scan */
 	struct cfg80211_scan_request *scan_request;
 
@@ -647,6 +669,7 @@
 	struct dentry *debug;
 	struct wil_blob_wrapper blobs[ARRAY_SIZE(fw_mapping)];
 	u8 discovery_mode;
+	u8 abft_len;
 
 	void *platform_handle;
 	struct wil_platform_ops platform_ops;
@@ -665,6 +688,8 @@
 	/* High Access Latency Policy voting */
 	struct wil_halp halp;
 
+	struct wil_ftm_priv ftm;
+
 #ifdef CONFIG_PM
 #ifdef CONFIG_PM_SLEEP
 	struct notifier_block pm_notify;
@@ -810,13 +835,18 @@
 int wmi_rx_chain_add(struct wil6210_priv *wil, struct vring *vring);
 int wmi_rxon(struct wil6210_priv *wil, bool on);
 int wmi_get_temperature(struct wil6210_priv *wil, u32 *t_m, u32 *t_r);
-int wmi_disconnect_sta(struct wil6210_priv *wil, const u8 *mac, u16 reason,
-		       bool full_disconnect);
+int wmi_disconnect_sta(struct wil6210_priv *wil, const u8 *mac,
+		       u16 reason, bool full_disconnect, bool del_sta);
 int wmi_addba(struct wil6210_priv *wil, u8 ringid, u8 size, u16 timeout);
 int wmi_delba_tx(struct wil6210_priv *wil, u8 ringid, u16 reason);
 int wmi_delba_rx(struct wil6210_priv *wil, u8 cidxtid, u16 reason);
 int wmi_addba_rx_resp(struct wil6210_priv *wil, u8 cid, u8 tid, u8 token,
 		      u16 status, bool amsdu, u16 agg_wsize, u16 timeout);
+int wmi_ps_dev_profile_cfg(struct wil6210_priv *wil,
+			   enum wmi_ps_profile_type ps_profile);
+int wmi_set_mgmt_retry(struct wil6210_priv *wil, u8 retry_short);
+int wmi_get_mgmt_retry(struct wil6210_priv *wil, u8 *retry_short);
+int wmi_new_sta(struct wil6210_priv *wil, const u8 *mac, u8 aid);
 int wil_addba_rx_request(struct wil6210_priv *wil, u8 cidxtid,
 			 u8 dialog_token, __le16 ba_param_set,
 			 __le16 ba_timeout, __le16 ba_seq_ctrl);
@@ -837,13 +867,15 @@
 void wil_p2p_discovery_timer_fn(ulong x);
 int wil_p2p_search(struct wil6210_priv *wil,
 		   struct cfg80211_scan_request *request);
-int wil_p2p_listen(struct wil6210_priv *wil, unsigned int duration,
-		   struct ieee80211_channel *chan, u64 *cookie);
+int wil_p2p_listen(struct wil6210_priv *wil, struct wireless_dev *wdev,
+		   unsigned int duration, struct ieee80211_channel *chan,
+		   u64 *cookie);
 u8 wil_p2p_stop_discovery(struct wil6210_priv *wil);
 int wil_p2p_cancel_listen(struct wil6210_priv *wil, u64 cookie);
 void wil_p2p_listen_expired(struct work_struct *work);
 void wil_p2p_search_expired(struct work_struct *work);
 void wil_p2p_stop_radio_operations(struct wil6210_priv *wil);
+void wil_p2p_delayed_listen_work(struct work_struct *work);
 
 /* WMI for P2P */
 int wmi_p2p_cfg(struct wil6210_priv *wil, int channel, int bi);
@@ -869,6 +901,11 @@
 		  u8 chan, u8 hidden_ssid, u8 is_go);
 int wmi_pcp_stop(struct wil6210_priv *wil);
 int wmi_led_cfg(struct wil6210_priv *wil, bool enable);
+int wmi_aoa_meas(struct wil6210_priv *wil, const void *mac_addr, u8 chan,
+		 u8 type);
+int wmi_abort_scan(struct wil6210_priv *wil);
+void wil_abort_scan(struct wil6210_priv *wil, bool sync);
+
 void wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid,
 			u16 reason_code, bool from_event);
 void wil_probe_client_flush(struct wil6210_priv *wil);
@@ -886,6 +923,10 @@
 int wil_bcast_init(struct wil6210_priv *wil);
 void wil_bcast_fini(struct wil6210_priv *wil);
 
+void wil_update_net_queues(struct wil6210_priv *wil, struct vring *vring,
+			   bool should_stop);
+void wil_update_net_queues_bh(struct wil6210_priv *wil, struct vring *vring,
+			      bool check_stop);
 netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev);
 int wil_tx_complete(struct wil6210_priv *wil, int ringid);
 void wil6210_unmask_irq_tx(struct wil6210_priv *wil);
@@ -899,6 +940,7 @@
 int wil_ioctl(struct wil6210_priv *wil, void __user *data, int cmd);
 int wil_request_firmware(struct wil6210_priv *wil, const char *name,
 			 bool load);
+bool wil_fw_verify_file_exists(struct wil6210_priv *wil, const char *name);
 
 int wil_can_suspend(struct wil6210_priv *wil, bool is_runtime);
 int wil_suspend(struct wil6210_priv *wil, bool is_runtime);
@@ -912,4 +954,18 @@
 void wil6210_set_halp(struct wil6210_priv *wil);
 void wil6210_clear_halp(struct wil6210_priv *wil);
 
+void wil_ftm_init(struct wil6210_priv *wil);
+void wil_ftm_deinit(struct wil6210_priv *wil);
+void wil_ftm_stop_operations(struct wil6210_priv *wil);
+void wil_aoa_cfg80211_meas_result(struct wil6210_priv *wil,
+				  struct wil_aoa_meas_result *result);
+
+void wil_ftm_evt_session_ended(struct wil6210_priv *wil,
+			       struct wmi_tof_session_end_event *evt);
+void wil_ftm_evt_per_dest_res(struct wil6210_priv *wil,
+			      struct wmi_tof_ftm_per_dest_res_event *evt);
+void wil_aoa_evt_meas(struct wil6210_priv *wil,
+		      struct wmi_aoa_meas_event *evt,
+		      int len);
+
 #endif /* __WIL6210_H__ */
diff --git a/drivers/net/wireless/ath/wil6210/wil_crash_dump.c b/drivers/net/wireless/ath/wil6210/wil_crash_dump.c
index b57d280..e53cf0c 100644
--- a/drivers/net/wireless/ath/wil6210/wil_crash_dump.c
+++ b/drivers/net/wireless/ath/wil6210/wil_crash_dump.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015 Qualcomm Atheros, Inc.
+ * Copyright (c) 2015,2017 Qualcomm Atheros, Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -36,6 +36,9 @@
 	for (i = 1; i < ARRAY_SIZE(fw_mapping); i++) {
 		map = &fw_mapping[i];
 
+		if (!map->fw)
+			continue;
+
 		if (map->host < host_min)
 			host_min = map->host;
 
@@ -59,13 +62,13 @@
 	u32 host_min, dump_size, offset, len;
 
 	if (wil_fw_get_crash_dump_bounds(wil, &dump_size, &host_min)) {
-		wil_err(wil, "%s: fail to obtain crash dump size\n", __func__);
+		wil_err(wil, "fail to obtain crash dump size\n");
 		return -EINVAL;
 	}
 
 	if (dump_size > size) {
-		wil_err(wil, "%s: not enough space for dump. Need %d have %d\n",
-			__func__, dump_size, size);
+		wil_err(wil, "not enough space for dump. Need %d have %d\n",
+			dump_size, size);
 		return -EINVAL;
 	}
 
@@ -73,12 +76,16 @@
 	for (i = 0; i < ARRAY_SIZE(fw_mapping); i++) {
 		map = &fw_mapping[i];
 
+		if (!map->fw)
+			continue;
+
 		data = (void * __force)wil->csr + HOSTADDR(map->host);
 		len = map->to - map->from;
 		offset = map->host - host_min;
 
-		wil_dbg_misc(wil, "%s() - dump %s, size %d, offset %d\n",
-			     __func__, fw_mapping[i].name, len, offset);
+		wil_dbg_misc(wil,
+			     "fw_copy_crash_dump: - dump %s, size %d, offset %d\n",
+			     fw_mapping[i].name, len, offset);
 
 		wil_memcpy_fromio_32((void * __force)(dest + offset),
 				     (const void __iomem * __force)data, len);
@@ -93,7 +100,7 @@
 	u32 fw_dump_size;
 
 	if (wil_fw_get_crash_dump_bounds(wil, &fw_dump_size, NULL)) {
-		wil_err(wil, "%s: fail to get fw dump size\n", __func__);
+		wil_err(wil, "fail to get fw dump size\n");
 		return;
 	}
 
@@ -109,6 +116,5 @@
 	 * after 5 min
 	 */
 	dev_coredumpv(wil_to_dev(wil), fw_dump_data, fw_dump_size, GFP_KERNEL);
-	wil_info(wil, "%s: fw core dumped, size %d bytes\n", __func__,
-		 fw_dump_size);
+	wil_info(wil, "fw core dumped, size %d bytes\n", fw_dump_size);
 }
diff --git a/drivers/net/wireless/ath/wil6210/wil_platform.c b/drivers/net/wireless/ath/wil6210/wil_platform.c
index 4eed05bd..47cab37 100644
--- a/drivers/net/wireless/ath/wil6210/wil_platform.c
+++ b/drivers/net/wireless/ath/wil6210/wil_platform.c
@@ -16,14 +16,16 @@
 
 #include <linux/device.h>
 #include "wil_platform.h"
+#include "msm_11ad.h"
 
 int __init wil_platform_modinit(void)
 {
-	return 0;
+	return msm_11ad_modinit();
 }
 
 void wil_platform_modexit(void)
 {
+	msm_11ad_modexit();
 }
 
 /**
@@ -36,7 +38,7 @@
 void *wil_platform_init(struct device *dev, struct wil_platform_ops *ops,
 			const struct wil_platform_rops *rops, void *wil_handle)
 {
-	void *handle = ops; /* to return some non-NULL for 'void' impl. */
+	void *handle;
 
 	if (!ops) {
 		dev_err(dev,
@@ -44,7 +46,7 @@
 		return NULL;
 	}
 
-	/* platform specific init functions should be called here */
+	handle = msm_11ad_dev_init(dev, ops, rops, wil_handle);
 
 	return handle;
 }
diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c
index fae4f12..0ede7f7 100644
--- a/drivers/net/wireless/ath/wil6210/wmi.c
+++ b/drivers/net/wireless/ath/wil6210/wmi.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2016 Qualcomm Atheros, Inc.
+ * Copyright (c) 2012-2017 Qualcomm Atheros, Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -22,18 +22,19 @@
 #include "txrx.h"
 #include "wmi.h"
 #include "trace.h"
+#include "ftm.h"
 
 static uint max_assoc_sta = WIL6210_MAX_CID;
-module_param(max_assoc_sta, uint, S_IRUGO | S_IWUSR);
+module_param(max_assoc_sta, uint, 0644);
 MODULE_PARM_DESC(max_assoc_sta, " Max number of stations associated to the AP");
 
 int agg_wsize; /* = 0; */
-module_param(agg_wsize, int, S_IRUGO | S_IWUSR);
+module_param(agg_wsize, int, 0644);
 MODULE_PARM_DESC(agg_wsize, " Window size for Tx Block Ack after connect;"
 		 " 0 - use default; < 0 - don't auto-establish");
 
 u8 led_id = WIL_LED_INVALID_ID;
-module_param(led_id, byte, S_IRUGO);
+module_param(led_id, byte, 0444);
 MODULE_PARM_DESC(led_id,
 		 " 60G device led enablement. Set the led ID (0-2) to enable");
 
@@ -84,19 +85,29 @@
  * array size should be in sync with the declaration in the wil6210.h
  */
 const struct fw_map fw_mapping[] = {
-	{0x000000, 0x040000, 0x8c0000, "fw_code"}, /* FW code RAM      256k */
-	{0x800000, 0x808000, 0x900000, "fw_data"}, /* FW data RAM       32k */
-	{0x840000, 0x860000, 0x908000, "fw_peri"}, /* periph. data RAM 128k */
-	{0x880000, 0x88a000, 0x880000, "rgf"},     /* various RGF       40k */
-	{0x88a000, 0x88b000, 0x88a000, "AGC_tbl"}, /* AGC table          4k */
-	{0x88b000, 0x88c000, 0x88b000, "rgf_ext"}, /* Pcie_ext_rgf       4k */
-	{0x88c000, 0x88c200, 0x88c000, "mac_rgf_ext"}, /* mac_ext_rgf  512b */
-	{0x8c0000, 0x949000, 0x8c0000, "upper"},   /* upper area       548k */
-	/*
-	 * 920000..930000 ucode code RAM
-	 * 930000..932000 ucode data RAM
-	 * 932000..949000 back-door debug data
+	/* FW code RAM 256k */
+	{0x000000, 0x040000, 0x8c0000, "fw_code", true},
+	/* FW data RAM 32k */
+	{0x800000, 0x808000, 0x900000, "fw_data", true},
+	/* periph data 128k */
+	{0x840000, 0x860000, 0x908000, "fw_peri", true},
+	/* various RGF 40k */
+	{0x880000, 0x88a000, 0x880000, "rgf", true},
+	/* AGC table   4k */
+	{0x88a000, 0x88b000, 0x88a000, "AGC_tbl", true},
+	/* Pcie_ext_rgf 4k */
+	{0x88b000, 0x88c000, 0x88b000, "rgf_ext", true},
+	/* mac_ext_rgf 512b */
+	{0x88c000, 0x88c200, 0x88c000, "mac_rgf_ext", true},
+	/* upper area 548k */
+	{0x8c0000, 0x949000, 0x8c0000, "upper", true},
+	/* UCODE areas - accessible by debugfs blobs but not by
+	 * wmi_addr_remap. UCODE areas MUST be added AFTER FW areas!
 	 */
+	/* ucode code RAM 128k */
+	{0x000000, 0x020000, 0x920000, "uc_code", false},
+	/* ucode data RAM 16k */
+	{0x800000, 0x804000, 0x940000, "uc_data", false},
 };
 
 struct blink_on_off_time led_blink_time[] = {
@@ -108,7 +119,7 @@
 u8 led_polarity = LED_POLARITY_LOW_ACTIVE;
 
 /**
- * return AHB address for given firmware/ucode internal (linker) address
+ * return AHB address for given firmware internal (linker) address
  * @x - internal address
  * If address have no valid AHB mapping, return 0
  */
@@ -117,7 +128,8 @@
 	uint i;
 
 	for (i = 0; i < ARRAY_SIZE(fw_mapping); i++) {
-		if ((x >= fw_mapping[i].from) && (x < fw_mapping[i].to))
+		if (fw_mapping[i].fw &&
+		    ((x >= fw_mapping[i].from) && (x < fw_mapping[i].to)))
 			return x + fw_mapping[i].host - fw_mapping[i].from;
 	}
 
@@ -427,18 +439,24 @@
 	mutex_lock(&wil->p2p_wdev_mutex);
 	if (wil->scan_request) {
 		struct wmi_scan_complete_event *data = d;
+		int status = le32_to_cpu(data->status);
 		struct cfg80211_scan_info info = {
-			.aborted = (data->status != WMI_SCAN_SUCCESS),
+			.aborted = ((status != WMI_SCAN_SUCCESS) &&
+				(status != WMI_SCAN_ABORT_REJECTED)),
 		};
 
-		wil_dbg_wmi(wil, "SCAN_COMPLETE(0x%08x)\n", data->status);
+		wil_dbg_wmi(wil, "SCAN_COMPLETE(0x%08x)\n", status);
 		wil_dbg_misc(wil, "Complete scan_request 0x%p aborted %d\n",
 			     wil->scan_request, info.aborted);
-
 		del_timer_sync(&wil->scan_timer);
 		cfg80211_scan_done(wil->scan_request, &info);
 		wil->radio_wdev = wil->wdev;
 		wil->scan_request = NULL;
+		wake_up_interruptible(&wil->wq);
+		if (wil->p2p.pending_listen_wdev) {
+			wil_dbg_misc(wil, "Scheduling delayed listen\n");
+			schedule_work(&wil->p2p.delayed_listen_work);
+		}
 	} else {
 		wil_err(wil, "SCAN_COMPLETE while not scanning\n");
 	}
@@ -478,8 +496,8 @@
 	}
 
 	ch = evt->channel + 1;
-	wil_info(wil, "Connect %pM channel [%d] cid %d\n",
-		 evt->bssid, ch, evt->cid);
+	wil_info(wil, "Connect %pM channel [%d] cid %d aid %d\n",
+		 evt->bssid, ch, evt->cid, evt->aid);
 	wil_hex_dump_wmi("connect AI : ", DUMP_PREFIX_OFFSET, 16, 1,
 			 evt->assoc_info, len - sizeof(*evt), true);
 
@@ -522,8 +540,8 @@
 	} else if ((wdev->iftype == NL80211_IFTYPE_AP) ||
 		   (wdev->iftype == NL80211_IFTYPE_P2P_GO)) {
 		if (wil->sta[evt->cid].status != wil_sta_unused) {
-			wil_err(wil, "%s: AP: Invalid status %d for CID %d\n",
-				__func__, wil->sta[evt->cid].status, evt->cid);
+			wil_err(wil, "AP: Invalid status %d for CID %d\n",
+				wil->sta[evt->cid].status, evt->cid);
 			mutex_unlock(&wil->mutex);
 			return;
 		}
@@ -536,23 +554,19 @@
 
 	rc = wil_tx_init(wil, evt->cid);
 	if (rc) {
-		wil_err(wil, "%s: config tx vring failed for CID %d, rc (%d)\n",
-			__func__, evt->cid, rc);
+		wil_err(wil, "config tx vring failed for CID %d, rc (%d)\n",
+			evt->cid, rc);
 		wmi_disconnect_sta(wil, wil->sta[evt->cid].addr,
-				   WLAN_REASON_UNSPECIFIED, false);
+				   WLAN_REASON_UNSPECIFIED, false, false);
 	} else {
-		wil_info(wil, "%s: successful connection to CID %d\n",
-			 __func__, evt->cid);
+		wil_info(wil, "successful connection to CID %d\n", evt->cid);
 	}
 
 	if ((wdev->iftype == NL80211_IFTYPE_STATION) ||
 	    (wdev->iftype == NL80211_IFTYPE_P2P_CLIENT)) {
 		if (rc) {
-			netif_tx_stop_all_queues(ndev);
 			netif_carrier_off(ndev);
-			wil_err(wil,
-				"%s: cfg80211_connect_result with failure\n",
-				__func__);
+			wil_err(wil, "cfg80211_connect_result with failure\n");
 			cfg80211_connect_result(ndev, evt->bssid, NULL, 0,
 						NULL, 0,
 						WLAN_STATUS_UNSPECIFIED_FAILURE,
@@ -567,8 +581,12 @@
 		}
 	} else if ((wdev->iftype == NL80211_IFTYPE_AP) ||
 		   (wdev->iftype == NL80211_IFTYPE_P2P_GO)) {
-		if (rc)
+		if (rc) {
+			if (disable_ap_sme)
+				/* notify new_sta has failed */
+				cfg80211_del_sta(ndev, evt->bssid, GFP_KERNEL);
 			goto out;
+		}
 
 		memset(&sinfo, 0, sizeof(sinfo));
 
@@ -581,14 +599,15 @@
 
 		cfg80211_new_sta(ndev, evt->bssid, &sinfo, GFP_KERNEL);
 	} else {
-		wil_err(wil, "%s: unhandled iftype %d for CID %d\n",
-			__func__, wdev->iftype, evt->cid);
+		wil_err(wil, "unhandled iftype %d for CID %d\n", wdev->iftype,
+			evt->cid);
 		goto out;
 	}
 
 	wil->sta[evt->cid].status = wil_sta_connected;
+	wil->sta[evt->cid].aid = evt->aid;
 	set_bit(wil_status_fwconnected, wil->status);
-	netif_tx_wake_all_queues(ndev);
+	wil_update_net_queues_bh(wil, NULL, false);
 
 out:
 	if (rc)
@@ -671,6 +690,7 @@
 {
 	struct wmi_vring_en_event *evt = d;
 	u8 vri = evt->vring_index;
+	struct wireless_dev *wdev = wil_to_wdev(wil);
 
 	wil_dbg_wmi(wil, "Enable vring %d\n", vri);
 
@@ -678,7 +698,12 @@
 		wil_err(wil, "Enable for invalid vring %d\n", vri);
 		return;
 	}
-	wil->vring_tx_data[vri].dot1x_open = true;
+
+	if (wdev->iftype != NL80211_IFTYPE_AP || !disable_ap_sme)
+		/* in AP mode with disable_ap_sme, this is done by
+		 * wil_cfg80211_change_station()
+		 */
+		wil->vring_tx_data[vri].dot1x_open = true;
 	if (vri == wil->bcast_vring) /* no BA for bcast */
 		return;
 	if (agg_wsize >= 0)
@@ -774,6 +799,30 @@
 	spin_unlock_bh(&sta->tid_rx_lock);
 }
 
+static void wmi_evt_aoa_meas(struct wil6210_priv *wil, int id,
+			     void *d, int len)
+{
+	struct wmi_aoa_meas_event *evt = d;
+
+	wil_aoa_evt_meas(wil, evt, len);
+}
+
+static void wmi_evt_ftm_session_ended(struct wil6210_priv *wil, int id,
+				      void *d, int len)
+{
+	struct wmi_tof_session_end_event *evt = d;
+
+	wil_ftm_evt_session_ended(wil, evt);
+}
+
+static void wmi_evt_per_dest_res(struct wil6210_priv *wil, int id,
+				 void *d, int len)
+{
+	struct wmi_tof_ftm_per_dest_res_event *evt = d;
+
+	wil_ftm_evt_per_dest_res(wil, evt);
+}
+
 /**
  * Some events are ignored for purpose; and need not be interpreted as
  * "unhandled events"
@@ -801,6 +850,13 @@
 	{WMI_DELBA_EVENTID,		wmi_evt_delba},
 	{WMI_VRING_EN_EVENTID,		wmi_evt_vring_en},
 	{WMI_DATA_PORT_OPEN_EVENTID,		wmi_evt_ignore},
+	{WMI_AOA_MEAS_EVENTID,			wmi_evt_aoa_meas},
+	{WMI_TOF_SESSION_END_EVENTID,		wmi_evt_ftm_session_ended},
+	{WMI_TOF_GET_CAPABILITIES_EVENTID,	wmi_evt_ignore},
+	{WMI_TOF_SET_LCR_EVENTID,		wmi_evt_ignore},
+	{WMI_TOF_SET_LCI_EVENTID,		wmi_evt_ignore},
+	{WMI_TOF_FTM_PER_DEST_RES_EVENTID,	wmi_evt_per_dest_res},
+	{WMI_TOF_CHANNEL_INFO_EVENTID,		wmi_evt_ignore},
 };
 
 /*
@@ -903,8 +959,8 @@
 		      offsetof(struct wil6210_mbox_ctl, rx.tail), r->tail);
 
 		if (immed_reply) {
-			wil_dbg_wmi(wil, "%s: Complete WMI 0x%04x\n",
-				    __func__, wil->reply_id);
+			wil_dbg_wmi(wil, "recv_cmd: Complete WMI 0x%04x\n",
+				    wil->reply_id);
 			kfree(evt);
 			num_immed_reply++;
 			complete(&wil->wmi_call);
@@ -918,7 +974,7 @@
 		}
 	}
 	/* normally, 1 event per IRQ should be processed */
-	wil_dbg_wmi(wil, "%s -> %d events queued, %d completed\n", __func__,
+	wil_dbg_wmi(wil, "recv_cmd: -> %d events queued, %d completed\n",
 		    n - num_immed_reply, num_immed_reply);
 }
 
@@ -934,6 +990,7 @@
 	wil->reply_id = reply_id;
 	wil->reply_buf = reply;
 	wil->reply_size = reply_size;
+	reinit_completion(&wil->wmi_call);
 	spin_unlock(&wil->wmi_ev_lock);
 
 	rc = __wmi_send(wil, cmdid, buf, len);
@@ -1053,6 +1110,8 @@
 		.pcp_max_assoc_sta = max_assoc_sta,
 		.hidden_ssid = hidden_ssid,
 		.is_go = is_go,
+		.disable_ap_sme = disable_ap_sme,
+		.abft_len = wil->abft_len,
 	};
 	struct {
 		struct wmi_cmd_hdr wmi;
@@ -1070,6 +1129,13 @@
 		cmd.pcp_max_assoc_sta = WIL6210_MAX_CID;
 	}
 
+	if (disable_ap_sme &&
+	    !test_bit(WMI_FW_CAPABILITY_DISABLE_AP_SME,
+		      wil->fw_capabilities)) {
+		wil_err(wil, "disable_ap_sme not supported by FW\n");
+		return -EOPNOTSUPP;
+	}
+
 	/*
 	 * Processing time may be huge, in case of secure AP it takes about
 	 * 3500ms for FW to start AP
@@ -1336,7 +1402,7 @@
 		struct wmi_listen_started_event evt;
 	} __packed reply;
 
-	wil_info(wil, "%s(%s)\n", __func__, on ? "on" : "off");
+	wil_info(wil, "(%s)\n", on ? "on" : "off");
 
 	if (on) {
 		rc = wmi_call(wil, WMI_START_LISTEN_CMDID, NULL, 0,
@@ -1440,12 +1506,15 @@
 	return 0;
 }
 
-int wmi_disconnect_sta(struct wil6210_priv *wil, const u8 *mac, u16 reason,
-		       bool full_disconnect)
+int wmi_disconnect_sta(struct wil6210_priv *wil, const u8 *mac,
+		       u16 reason, bool full_disconnect, bool del_sta)
 {
 	int rc;
 	u16 reason_code;
-	struct wmi_disconnect_sta_cmd cmd = {
+	struct wmi_disconnect_sta_cmd disc_sta_cmd = {
+		.disconnect_reason = cpu_to_le16(reason),
+	};
+	struct wmi_del_sta_cmd del_sta_cmd = {
 		.disconnect_reason = cpu_to_le16(reason),
 	};
 	struct {
@@ -1453,12 +1522,19 @@
 		struct wmi_disconnect_event evt;
 	} __packed reply;
 
-	ether_addr_copy(cmd.dst_mac, mac);
+	wil_dbg_wmi(wil, "disconnect_sta: (%pM, reason %d)\n", mac, reason);
 
-	wil_dbg_wmi(wil, "%s(%pM, reason %d)\n", __func__, mac, reason);
-
-	rc = wmi_call(wil, WMI_DISCONNECT_STA_CMDID, &cmd, sizeof(cmd),
-		      WMI_DISCONNECT_EVENTID, &reply, sizeof(reply), 1000);
+	if (del_sta) {
+		ether_addr_copy(del_sta_cmd.dst_mac, mac);
+		rc = wmi_call(wil, WMI_DEL_STA_CMDID, &del_sta_cmd,
+			      sizeof(del_sta_cmd), WMI_DISCONNECT_EVENTID,
+			      &reply, sizeof(reply), 1000);
+	} else {
+		ether_addr_copy(disc_sta_cmd.dst_mac, mac);
+		rc = wmi_call(wil, WMI_DISCONNECT_STA_CMDID, &disc_sta_cmd,
+			      sizeof(disc_sta_cmd), WMI_DISCONNECT_EVENTID,
+			      &reply, sizeof(reply), 1000);
+	}
 	/* failure to disconnect in reasonable time treated as FW error */
 	if (rc) {
 		wil_fw_error_recovery(wil);
@@ -1491,8 +1567,8 @@
 		.amsdu = 0,
 	};
 
-	wil_dbg_wmi(wil, "%s(ring %d size %d timeout %d)\n", __func__,
-		    ringid, size, timeout);
+	wil_dbg_wmi(wil, "addba: (ring %d size %d timeout %d)\n", ringid, size,
+		    timeout);
 
 	return wmi_send(wil, WMI_VRING_BA_EN_CMDID, &cmd, sizeof(cmd));
 }
@@ -1504,8 +1580,7 @@
 		.reason = cpu_to_le16(reason),
 	};
 
-	wil_dbg_wmi(wil, "%s(ring %d reason %d)\n", __func__,
-		    ringid, reason);
+	wil_dbg_wmi(wil, "delba_tx: (ring %d reason %d)\n", ringid, reason);
 
 	return wmi_send(wil, WMI_VRING_BA_DIS_CMDID, &cmd, sizeof(cmd));
 }
@@ -1517,8 +1592,8 @@
 		.reason = cpu_to_le16(reason),
 	};
 
-	wil_dbg_wmi(wil, "%s(CID %d TID %d reason %d)\n", __func__,
-		    cidxtid & 0xf, (cidxtid >> 4) & 0xf, reason);
+	wil_dbg_wmi(wil, "delba_rx: (CID %d TID %d reason %d)\n", cidxtid & 0xf,
+		    (cidxtid >> 4) & 0xf, reason);
 
 	return wmi_send(wil, WMI_RCP_DELBA_CMDID, &cmd, sizeof(cmd));
 }
@@ -1564,11 +1639,135 @@
 	return rc;
 }
 
+int wmi_ps_dev_profile_cfg(struct wil6210_priv *wil,
+			   enum wmi_ps_profile_type ps_profile)
+{
+	int rc;
+	struct wmi_ps_dev_profile_cfg_cmd cmd = {
+		.ps_profile = ps_profile,
+	};
+	struct {
+		struct wmi_cmd_hdr wmi;
+		struct wmi_ps_dev_profile_cfg_event evt;
+	} __packed reply;
+	u32 status;
+
+	wil_dbg_wmi(wil, "Setting ps dev profile %d\n", ps_profile);
+
+	reply.evt.status = cpu_to_le32(WMI_PS_CFG_CMD_STATUS_ERROR);
+
+	rc = wmi_call(wil, WMI_PS_DEV_PROFILE_CFG_CMDID, &cmd, sizeof(cmd),
+		      WMI_PS_DEV_PROFILE_CFG_EVENTID, &reply, sizeof(reply),
+		      100);
+	if (rc)
+		return rc;
+
+	status = le32_to_cpu(reply.evt.status);
+
+	if (status != WMI_PS_CFG_CMD_STATUS_SUCCESS) {
+		wil_err(wil, "ps dev profile cfg failed with status %d\n",
+			status);
+		rc = -EINVAL;
+	}
+
+	return rc;
+}
+
+int wmi_set_mgmt_retry(struct wil6210_priv *wil, u8 retry_short)
+{
+	int rc;
+	struct wmi_set_mgmt_retry_limit_cmd cmd = {
+		.mgmt_retry_limit = retry_short,
+	};
+	struct {
+		struct wmi_cmd_hdr wmi;
+		struct wmi_set_mgmt_retry_limit_event evt;
+	} __packed reply;
+
+	wil_dbg_wmi(wil, "Setting mgmt retry short %d\n", retry_short);
+
+	if (!test_bit(WMI_FW_CAPABILITY_MGMT_RETRY_LIMIT, wil->fw_capabilities))
+		return -ENOTSUPP;
+
+	reply.evt.status = WMI_FW_STATUS_FAILURE;
+
+	rc = wmi_call(wil, WMI_SET_MGMT_RETRY_LIMIT_CMDID, &cmd, sizeof(cmd),
+		      WMI_SET_MGMT_RETRY_LIMIT_EVENTID, &reply, sizeof(reply),
+		      100);
+	if (rc)
+		return rc;
+
+	if (reply.evt.status != WMI_FW_STATUS_SUCCESS) {
+		wil_err(wil, "set mgmt retry limit failed with status %d\n",
+			reply.evt.status);
+		rc = -EINVAL;
+	}
+
+	return rc;
+}
+
+int wmi_get_mgmt_retry(struct wil6210_priv *wil, u8 *retry_short)
+{
+	int rc;
+	struct {
+		struct wmi_cmd_hdr wmi;
+		struct wmi_get_mgmt_retry_limit_event evt;
+	} __packed reply;
+
+	wil_dbg_wmi(wil, "getting mgmt retry short\n");
+
+	if (!test_bit(WMI_FW_CAPABILITY_MGMT_RETRY_LIMIT, wil->fw_capabilities))
+		return -ENOTSUPP;
+
+	reply.evt.mgmt_retry_limit = 0;
+	rc = wmi_call(wil, WMI_GET_MGMT_RETRY_LIMIT_CMDID, NULL, 0,
+		      WMI_GET_MGMT_RETRY_LIMIT_EVENTID, &reply, sizeof(reply),
+		      100);
+	if (rc)
+		return rc;
+
+	if (retry_short)
+		*retry_short = reply.evt.mgmt_retry_limit;
+
+	return 0;
+}
+
+int wmi_abort_scan(struct wil6210_priv *wil)
+{
+	int rc;
+
+	wil_dbg_wmi(wil, "sending WMI_ABORT_SCAN_CMDID\n");
+
+	rc = wmi_send(wil, WMI_ABORT_SCAN_CMDID, NULL, 0);
+	if (rc)
+		wil_err(wil, "Failed to abort scan (%d)\n", rc);
+
+	return rc;
+}
+
+int wmi_new_sta(struct wil6210_priv *wil, const u8 *mac, u8 aid)
+{
+	int rc;
+	struct wmi_new_sta_cmd cmd = {
+		.aid = aid,
+	};
+
+	wil_dbg_wmi(wil, "new sta %pM, aid %d\n", mac, aid);
+
+	ether_addr_copy(cmd.dst_mac, mac);
+
+	rc = wmi_send(wil, WMI_NEW_STA_CMDID, &cmd, sizeof(cmd));
+	if (rc)
+		wil_err(wil, "Failed to send new sta (%d)\n", rc);
+
+	return rc;
+}
+
 void wmi_event_flush(struct wil6210_priv *wil)
 {
 	struct pending_wmi_event *evt, *t;
 
-	wil_dbg_wmi(wil, "%s()\n", __func__);
+	wil_dbg_wmi(wil, "event_flush\n");
 
 	list_for_each_entry_safe(evt, t, &wil->pending_wmi_ev, list) {
 		list_del(&evt->list);
@@ -1609,8 +1808,8 @@
 			WARN_ON(wil->reply_buf);
 			wmi_evt_call_handler(wil, id, evt_data,
 					     len - sizeof(*wmi));
-			wil_dbg_wmi(wil, "%s: Complete WMI 0x%04x\n",
-				    __func__, id);
+			wil_dbg_wmi(wil, "event_handle: Complete WMI 0x%04x\n",
+				    id);
 			complete(&wil->wmi_call);
 			return;
 		}
@@ -1657,11 +1856,11 @@
 	struct pending_wmi_event *evt;
 	struct list_head *lh;
 
-	wil_dbg_wmi(wil, "Start %s\n", __func__);
+	wil_dbg_wmi(wil, "event_worker: Start\n");
 	while ((lh = next_wmi_ev(wil)) != NULL) {
 		evt = list_entry(lh, struct pending_wmi_event, list);
 		wmi_event_handle(wil, &evt->event.hdr);
 		kfree(evt);
 	}
-	wil_dbg_wmi(wil, "Finished %s\n", __func__);
+	wil_dbg_wmi(wil, "event_worker: Finished\n");
 }
diff --git a/drivers/net/wireless/ath/wil6210/wmi.h b/drivers/net/wireless/ath/wil6210/wmi.h
index f430e8a..7c9fee5 100644
--- a/drivers/net/wireless/ath/wil6210/wmi.h
+++ b/drivers/net/wireless/ath/wil6210/wmi.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2016 Qualcomm Atheros, Inc.
+ * Copyright (c) 2012-2017 Qualcomm Atheros, Inc.
  * Copyright (c) 2006-2012 Wilocity
  *
  * Permission to use, copy, modify, and/or distribute this software for any
@@ -35,6 +35,7 @@
 #define WMI_MAC_LEN			(6)
 #define WMI_PROX_RANGE_NUM		(3)
 #define WMI_MAX_LOSS_DMG_BEACONS	(20)
+#define MAX_NUM_OF_SECTORS		(128)
 
 /* Mailbox interface
  * used for commands and events
@@ -51,8 +52,12 @@
  * the host
  */
 enum wmi_fw_capability {
-	WMI_FW_CAPABILITY_FTM		= 0,
-	WMI_FW_CAPABILITY_PS_CONFIG	= 1,
+	WMI_FW_CAPABILITY_FTM			= 0,
+	WMI_FW_CAPABILITY_PS_CONFIG		= 1,
+	WMI_FW_CAPABILITY_RF_SECTORS		= 2,
+	WMI_FW_CAPABILITY_MGMT_RETRY_LIMIT	= 3,
+	WMI_FW_CAPABILITY_DISABLE_AP_SME	= 4,
+	WMI_FW_CAPABILITY_WMI_ONLY		= 5,
 	WMI_FW_CAPABILITY_MAX,
 };
 
@@ -66,137 +71,152 @@
 
 /* List of Commands */
 enum wmi_command_id {
-	WMI_CONNECT_CMDID			= 0x01,
-	WMI_DISCONNECT_CMDID			= 0x03,
-	WMI_DISCONNECT_STA_CMDID		= 0x04,
-	WMI_START_SCAN_CMDID			= 0x07,
-	WMI_SET_BSS_FILTER_CMDID		= 0x09,
-	WMI_SET_PROBED_SSID_CMDID		= 0x0A,
-	WMI_SET_LISTEN_INT_CMDID		= 0x0B,
-	WMI_BCON_CTRL_CMDID			= 0x0F,
-	WMI_ADD_CIPHER_KEY_CMDID		= 0x16,
-	WMI_DELETE_CIPHER_KEY_CMDID		= 0x17,
-	WMI_PCP_CONF_CMDID			= 0x18,
-	WMI_SET_APPIE_CMDID			= 0x3F,
-	WMI_SET_WSC_STATUS_CMDID		= 0x41,
-	WMI_PXMT_RANGE_CFG_CMDID		= 0x42,
-	WMI_PXMT_SNR2_RANGE_CFG_CMDID		= 0x43,
-	WMI_MEM_READ_CMDID			= 0x800,
-	WMI_MEM_WR_CMDID			= 0x801,
-	WMI_ECHO_CMDID				= 0x803,
-	WMI_DEEP_ECHO_CMDID			= 0x804,
-	WMI_CONFIG_MAC_CMDID			= 0x805,
-	WMI_CONFIG_PHY_DEBUG_CMDID		= 0x806,
-	WMI_ADD_DEBUG_TX_PCKT_CMDID		= 0x808,
-	WMI_PHY_GET_STATISTICS_CMDID		= 0x809,
-	WMI_FS_TUNE_CMDID			= 0x80A,
-	WMI_CORR_MEASURE_CMDID			= 0x80B,
-	WMI_READ_RSSI_CMDID			= 0x80C,
-	WMI_TEMP_SENSE_CMDID			= 0x80E,
-	WMI_DC_CALIB_CMDID			= 0x80F,
-	WMI_SEND_TONE_CMDID			= 0x810,
-	WMI_IQ_TX_CALIB_CMDID			= 0x811,
-	WMI_IQ_RX_CALIB_CMDID			= 0x812,
-	WMI_SET_UCODE_IDLE_CMDID		= 0x813,
-	WMI_SET_WORK_MODE_CMDID			= 0x815,
-	WMI_LO_LEAKAGE_CALIB_CMDID		= 0x816,
-	WMI_MARLON_R_READ_CMDID			= 0x818,
-	WMI_MARLON_R_WRITE_CMDID		= 0x819,
-	WMI_MARLON_R_TXRX_SEL_CMDID		= 0x81A,
-	MAC_IO_STATIC_PARAMS_CMDID		= 0x81B,
-	MAC_IO_DYNAMIC_PARAMS_CMDID		= 0x81C,
-	WMI_SILENT_RSSI_CALIB_CMDID		= 0x81D,
-	WMI_RF_RX_TEST_CMDID			= 0x81E,
-	WMI_CFG_RX_CHAIN_CMDID			= 0x820,
-	WMI_VRING_CFG_CMDID			= 0x821,
-	WMI_BCAST_VRING_CFG_CMDID		= 0x822,
-	WMI_VRING_BA_EN_CMDID			= 0x823,
-	WMI_VRING_BA_DIS_CMDID			= 0x824,
-	WMI_RCP_ADDBA_RESP_CMDID		= 0x825,
-	WMI_RCP_DELBA_CMDID			= 0x826,
-	WMI_SET_SSID_CMDID			= 0x827,
-	WMI_GET_SSID_CMDID			= 0x828,
-	WMI_SET_PCP_CHANNEL_CMDID		= 0x829,
-	WMI_GET_PCP_CHANNEL_CMDID		= 0x82A,
-	WMI_SW_TX_REQ_CMDID			= 0x82B,
-	WMI_READ_MAC_RXQ_CMDID			= 0x830,
-	WMI_READ_MAC_TXQ_CMDID			= 0x831,
-	WMI_WRITE_MAC_RXQ_CMDID			= 0x832,
-	WMI_WRITE_MAC_TXQ_CMDID			= 0x833,
-	WMI_WRITE_MAC_XQ_FIELD_CMDID		= 0x834,
-	WMI_MLME_PUSH_CMDID			= 0x835,
-	WMI_BEAMFORMING_MGMT_CMDID		= 0x836,
-	WMI_BF_TXSS_MGMT_CMDID			= 0x837,
-	WMI_BF_SM_MGMT_CMDID			= 0x838,
-	WMI_BF_RXSS_MGMT_CMDID			= 0x839,
-	WMI_BF_TRIG_CMDID			= 0x83A,
-	WMI_LINK_MAINTAIN_CFG_WRITE_CMDID	= 0x842,
-	WMI_LINK_MAINTAIN_CFG_READ_CMDID	= 0x843,
-	WMI_SET_SECTORS_CMDID			= 0x849,
-	WMI_MAINTAIN_PAUSE_CMDID		= 0x850,
-	WMI_MAINTAIN_RESUME_CMDID		= 0x851,
-	WMI_RS_MGMT_CMDID			= 0x852,
-	WMI_RF_MGMT_CMDID			= 0x853,
-	WMI_THERMAL_THROTTLING_CTRL_CMDID	= 0x854,
-	WMI_THERMAL_THROTTLING_GET_STATUS_CMDID	= 0x855,
-	WMI_OTP_READ_CMDID			= 0x856,
-	WMI_OTP_WRITE_CMDID			= 0x857,
-	WMI_LED_CFG_CMDID			= 0x858,
+	WMI_CONNECT_CMDID				= 0x01,
+	WMI_DISCONNECT_CMDID				= 0x03,
+	WMI_DISCONNECT_STA_CMDID			= 0x04,
+	WMI_START_SCAN_CMDID				= 0x07,
+	WMI_SET_BSS_FILTER_CMDID			= 0x09,
+	WMI_SET_PROBED_SSID_CMDID			= 0x0A,
+	WMI_SET_LISTEN_INT_CMDID			= 0x0B,
+	WMI_BCON_CTRL_CMDID				= 0x0F,
+	WMI_ADD_CIPHER_KEY_CMDID			= 0x16,
+	WMI_DELETE_CIPHER_KEY_CMDID			= 0x17,
+	WMI_PCP_CONF_CMDID				= 0x18,
+	WMI_SET_APPIE_CMDID				= 0x3F,
+	WMI_SET_WSC_STATUS_CMDID			= 0x41,
+	WMI_PXMT_RANGE_CFG_CMDID			= 0x42,
+	WMI_PXMT_SNR2_RANGE_CFG_CMDID			= 0x43,
+	WMI_MEM_READ_CMDID				= 0x800,
+	WMI_MEM_WR_CMDID				= 0x801,
+	WMI_ECHO_CMDID					= 0x803,
+	WMI_DEEP_ECHO_CMDID				= 0x804,
+	WMI_CONFIG_MAC_CMDID				= 0x805,
+	WMI_CONFIG_PHY_DEBUG_CMDID			= 0x806,
+	WMI_ADD_DEBUG_TX_PCKT_CMDID			= 0x808,
+	WMI_PHY_GET_STATISTICS_CMDID			= 0x809,
+	WMI_FS_TUNE_CMDID				= 0x80A,
+	WMI_CORR_MEASURE_CMDID				= 0x80B,
+	WMI_READ_RSSI_CMDID				= 0x80C,
+	WMI_TEMP_SENSE_CMDID				= 0x80E,
+	WMI_DC_CALIB_CMDID				= 0x80F,
+	WMI_SEND_TONE_CMDID				= 0x810,
+	WMI_IQ_TX_CALIB_CMDID				= 0x811,
+	WMI_IQ_RX_CALIB_CMDID				= 0x812,
+	WMI_SET_UCODE_IDLE_CMDID			= 0x813,
+	WMI_SET_WORK_MODE_CMDID				= 0x815,
+	WMI_LO_LEAKAGE_CALIB_CMDID			= 0x816,
+	WMI_MARLON_R_READ_CMDID				= 0x818,
+	WMI_MARLON_R_WRITE_CMDID			= 0x819,
+	WMI_MARLON_R_TXRX_SEL_CMDID			= 0x81A,
+	MAC_IO_STATIC_PARAMS_CMDID			= 0x81B,
+	MAC_IO_DYNAMIC_PARAMS_CMDID			= 0x81C,
+	WMI_SILENT_RSSI_CALIB_CMDID			= 0x81D,
+	WMI_RF_RX_TEST_CMDID				= 0x81E,
+	WMI_CFG_RX_CHAIN_CMDID				= 0x820,
+	WMI_VRING_CFG_CMDID				= 0x821,
+	WMI_BCAST_VRING_CFG_CMDID			= 0x822,
+	WMI_VRING_BA_EN_CMDID				= 0x823,
+	WMI_VRING_BA_DIS_CMDID				= 0x824,
+	WMI_RCP_ADDBA_RESP_CMDID			= 0x825,
+	WMI_RCP_DELBA_CMDID				= 0x826,
+	WMI_SET_SSID_CMDID				= 0x827,
+	WMI_GET_SSID_CMDID				= 0x828,
+	WMI_SET_PCP_CHANNEL_CMDID			= 0x829,
+	WMI_GET_PCP_CHANNEL_CMDID			= 0x82A,
+	WMI_SW_TX_REQ_CMDID				= 0x82B,
+	WMI_READ_MAC_RXQ_CMDID				= 0x830,
+	WMI_READ_MAC_TXQ_CMDID				= 0x831,
+	WMI_WRITE_MAC_RXQ_CMDID				= 0x832,
+	WMI_WRITE_MAC_TXQ_CMDID				= 0x833,
+	WMI_WRITE_MAC_XQ_FIELD_CMDID			= 0x834,
+	WMI_MLME_PUSH_CMDID				= 0x835,
+	WMI_BEAMFORMING_MGMT_CMDID			= 0x836,
+	WMI_BF_TXSS_MGMT_CMDID				= 0x837,
+	WMI_BF_SM_MGMT_CMDID				= 0x838,
+	WMI_BF_RXSS_MGMT_CMDID				= 0x839,
+	WMI_BF_TRIG_CMDID				= 0x83A,
+	WMI_LINK_MAINTAIN_CFG_WRITE_CMDID		= 0x842,
+	WMI_LINK_MAINTAIN_CFG_READ_CMDID		= 0x843,
+	WMI_SET_SECTORS_CMDID				= 0x849,
+	WMI_MAINTAIN_PAUSE_CMDID			= 0x850,
+	WMI_MAINTAIN_RESUME_CMDID			= 0x851,
+	WMI_RS_MGMT_CMDID				= 0x852,
+	WMI_RF_MGMT_CMDID				= 0x853,
+	WMI_THERMAL_THROTTLING_CTRL_CMDID		= 0x854,
+	WMI_THERMAL_THROTTLING_GET_STATUS_CMDID		= 0x855,
+	WMI_OTP_READ_CMDID				= 0x856,
+	WMI_OTP_WRITE_CMDID				= 0x857,
+	WMI_LED_CFG_CMDID				= 0x858,
 	/* Performance monitoring commands */
-	WMI_BF_CTRL_CMDID			= 0x862,
-	WMI_NOTIFY_REQ_CMDID			= 0x863,
-	WMI_GET_STATUS_CMDID			= 0x864,
-	WMI_GET_RF_STATUS_CMDID			= 0x866,
-	WMI_GET_BASEBAND_TYPE_CMDID		= 0x867,
-	WMI_UNIT_TEST_CMDID			= 0x900,
-	WMI_HICCUP_CMDID			= 0x901,
-	WMI_FLASH_READ_CMDID			= 0x902,
-	WMI_FLASH_WRITE_CMDID			= 0x903,
+	WMI_BF_CTRL_CMDID				= 0x862,
+	WMI_NOTIFY_REQ_CMDID				= 0x863,
+	WMI_GET_STATUS_CMDID				= 0x864,
+	WMI_GET_RF_STATUS_CMDID				= 0x866,
+	WMI_GET_BASEBAND_TYPE_CMDID			= 0x867,
+	WMI_UNIT_TEST_CMDID				= 0x900,
+	WMI_HICCUP_CMDID				= 0x901,
+	WMI_FLASH_READ_CMDID				= 0x902,
+	WMI_FLASH_WRITE_CMDID				= 0x903,
 	/* Power management */
-	WMI_TRAFFIC_DEFERRAL_CMDID		= 0x904,
-	WMI_TRAFFIC_RESUME_CMDID		= 0x905,
+	WMI_TRAFFIC_DEFERRAL_CMDID			= 0x904,
+	WMI_TRAFFIC_RESUME_CMDID			= 0x905,
 	/* P2P */
-	WMI_P2P_CFG_CMDID			= 0x910,
-	WMI_PORT_ALLOCATE_CMDID			= 0x911,
-	WMI_PORT_DELETE_CMDID			= 0x912,
-	WMI_POWER_MGMT_CFG_CMDID		= 0x913,
-	WMI_START_LISTEN_CMDID			= 0x914,
-	WMI_START_SEARCH_CMDID			= 0x915,
-	WMI_DISCOVERY_START_CMDID		= 0x916,
-	WMI_DISCOVERY_STOP_CMDID		= 0x917,
-	WMI_PCP_START_CMDID			= 0x918,
-	WMI_PCP_STOP_CMDID			= 0x919,
-	WMI_GET_PCP_FACTOR_CMDID		= 0x91B,
+	WMI_P2P_CFG_CMDID				= 0x910,
+	WMI_PORT_ALLOCATE_CMDID				= 0x911,
+	WMI_PORT_DELETE_CMDID				= 0x912,
+	WMI_POWER_MGMT_CFG_CMDID			= 0x913,
+	WMI_START_LISTEN_CMDID				= 0x914,
+	WMI_START_SEARCH_CMDID				= 0x915,
+	WMI_DISCOVERY_START_CMDID			= 0x916,
+	WMI_DISCOVERY_STOP_CMDID			= 0x917,
+	WMI_PCP_START_CMDID				= 0x918,
+	WMI_PCP_STOP_CMDID				= 0x919,
+	WMI_GET_PCP_FACTOR_CMDID			= 0x91B,
 	/* Power Save Configuration Commands */
-	WMI_PS_DEV_PROFILE_CFG_CMDID		= 0x91C,
+	WMI_PS_DEV_PROFILE_CFG_CMDID			= 0x91C,
 	/* Not supported yet */
-	WMI_PS_DEV_CFG_CMDID			= 0x91D,
+	WMI_PS_DEV_CFG_CMDID				= 0x91D,
 	/* Not supported yet */
-	WMI_PS_DEV_CFG_READ_CMDID		= 0x91E,
+	WMI_PS_DEV_CFG_READ_CMDID			= 0x91E,
 	/* Per MAC Power Save Configuration commands
 	 * Not supported yet
 	 */
-	WMI_PS_MID_CFG_CMDID			= 0x91F,
+	WMI_PS_MID_CFG_CMDID				= 0x91F,
 	/* Not supported yet */
-	WMI_PS_MID_CFG_READ_CMDID		= 0x920,
-	WMI_RS_CFG_CMDID			= 0x921,
-	WMI_GET_DETAILED_RS_RES_CMDID		= 0x922,
-	WMI_AOA_MEAS_CMDID			= 0x923,
-	WMI_TOF_SESSION_START_CMDID		= 0x991,
-	WMI_TOF_GET_CAPABILITIES_CMDID		= 0x992,
-	WMI_TOF_SET_LCR_CMDID			= 0x993,
-	WMI_TOF_SET_LCI_CMDID			= 0x994,
-	WMI_TOF_CHANNEL_INFO_CMDID		= 0x995,
-	WMI_SET_MAC_ADDRESS_CMDID		= 0xF003,
-	WMI_ABORT_SCAN_CMDID			= 0xF007,
-	WMI_SET_PROMISCUOUS_MODE_CMDID		= 0xF041,
-	WMI_GET_PMK_CMDID			= 0xF048,
-	WMI_SET_PASSPHRASE_CMDID		= 0xF049,
-	WMI_SEND_ASSOC_RES_CMDID		= 0xF04A,
-	WMI_SET_ASSOC_REQ_RELAY_CMDID		= 0xF04B,
-	WMI_MAC_ADDR_REQ_CMDID			= 0xF04D,
-	WMI_FW_VER_CMDID			= 0xF04E,
-	WMI_PMC_CMDID				= 0xF04F,
+	WMI_PS_MID_CFG_READ_CMDID			= 0x920,
+	WMI_RS_CFG_CMDID				= 0x921,
+	WMI_GET_DETAILED_RS_RES_CMDID			= 0x922,
+	WMI_AOA_MEAS_CMDID				= 0x923,
+	WMI_BRP_SET_ANT_LIMIT_CMDID			= 0x924,
+	WMI_SET_MGMT_RETRY_LIMIT_CMDID			= 0x930,
+	WMI_GET_MGMT_RETRY_LIMIT_CMDID			= 0x931,
+	WMI_NEW_STA_CMDID				= 0x935,
+	WMI_DEL_STA_CMDID				= 0x936,
+	WMI_TOF_SESSION_START_CMDID			= 0x991,
+	WMI_TOF_GET_CAPABILITIES_CMDID			= 0x992,
+	WMI_TOF_SET_LCR_CMDID				= 0x993,
+	WMI_TOF_SET_LCI_CMDID				= 0x994,
+	WMI_TOF_CHANNEL_INFO_CMDID			= 0x995,
+	WMI_TOF_SET_TX_RX_OFFSET_CMDID			= 0x997,
+	WMI_TOF_GET_TX_RX_OFFSET_CMDID			= 0x998,
+	WMI_GET_RF_SECTOR_PARAMS_CMDID			= 0x9A0,
+	WMI_SET_RF_SECTOR_PARAMS_CMDID			= 0x9A1,
+	WMI_GET_SELECTED_RF_SECTOR_INDEX_CMDID		= 0x9A2,
+	WMI_SET_SELECTED_RF_SECTOR_INDEX_CMDID		= 0x9A3,
+	WMI_SET_RF_SECTOR_ON_CMDID			= 0x9A4,
+	WMI_PRIO_TX_SECTORS_ORDER_CMDID			= 0x9A5,
+	WMI_PRIO_TX_SECTORS_NUMBER_CMDID		= 0x9A6,
+	WMI_PRIO_TX_SECTORS_SET_DEFAULT_CFG_CMDID	= 0x9A7,
+	WMI_SET_MAC_ADDRESS_CMDID			= 0xF003,
+	WMI_ABORT_SCAN_CMDID				= 0xF007,
+	WMI_SET_PROMISCUOUS_MODE_CMDID			= 0xF041,
+	WMI_GET_PMK_CMDID				= 0xF048,
+	WMI_SET_PASSPHRASE_CMDID			= 0xF049,
+	WMI_SEND_ASSOC_RES_CMDID			= 0xF04A,
+	WMI_SET_ASSOC_REQ_RELAY_CMDID			= 0xF04B,
+	WMI_MAC_ADDR_REQ_CMDID				= 0xF04D,
+	WMI_FW_VER_CMDID				= 0xF04E,
+	WMI_PMC_CMDID					= 0xF04F,
 };
 
 /* WMI_CONNECT_CMDID */
@@ -528,7 +548,10 @@
 	u8 pcp_max_assoc_sta;
 	u8 hidden_ssid;
 	u8 is_go;
-	u8 reserved0[7];
+	u8 reserved0[5];
+	/* abft_len override if non-0 */
+	u8 abft_len;
+	u8 disable_ap_sme;
 	u8 network_type;
 	u8 channel;
 	u8 disable_sec_offload;
@@ -879,6 +902,26 @@
 	__le32 meas_rf_mask;
 } __packed;
 
+/* WMI_SET_MGMT_RETRY_LIMIT_CMDID */
+struct wmi_set_mgmt_retry_limit_cmd {
+	/* MAC retransmit limit for mgmt frames */
+	u8 mgmt_retry_limit;
+	/* alignment to 32b */
+	u8 reserved[3];
+} __packed;
+
+/* WMI_NEW_STA_CMDID */
+struct wmi_new_sta_cmd {
+	u8 dst_mac[WMI_MAC_LEN];
+	u8 aid;
+} __packed;
+
+/* WMI_DEL_STA_CMDID */
+struct wmi_del_sta_cmd {
+	u8 dst_mac[WMI_MAC_LEN];
+	__le16 disconnect_reason;
+} __packed;
+
 enum wmi_tof_burst_duration {
 	WMI_TOF_BURST_DURATION_250_USEC		= 2,
 	WMI_TOF_BURST_DURATION_500_USEC		= 3,
@@ -942,6 +985,15 @@
 	__le32 channel_info_report_request;
 } __packed;
 
+/* WMI_TOF_SET_TX_RX_OFFSET_CMDID */
+struct wmi_tof_set_tx_rx_offset_cmd {
+	/* TX delay offset */
+	__le32 tx_offset;
+	/* RX delay offset */
+	__le32 rx_offset;
+	__le32 reserved[2];
+} __packed;
+
 /* WMI Events
  * List of Events (target to host)
  */
@@ -1035,12 +1087,25 @@
 	WMI_RS_CFG_DONE_EVENTID				= 0x1921,
 	WMI_GET_DETAILED_RS_RES_EVENTID			= 0x1922,
 	WMI_AOA_MEAS_EVENTID				= 0x1923,
+	WMI_BRP_SET_ANT_LIMIT_EVENTID			= 0x1924,
+	WMI_SET_MGMT_RETRY_LIMIT_EVENTID		= 0x1930,
+	WMI_GET_MGMT_RETRY_LIMIT_EVENTID		= 0x1931,
 	WMI_TOF_SESSION_END_EVENTID			= 0x1991,
 	WMI_TOF_GET_CAPABILITIES_EVENTID		= 0x1992,
 	WMI_TOF_SET_LCR_EVENTID				= 0x1993,
 	WMI_TOF_SET_LCI_EVENTID				= 0x1994,
 	WMI_TOF_FTM_PER_DEST_RES_EVENTID		= 0x1995,
 	WMI_TOF_CHANNEL_INFO_EVENTID			= 0x1996,
+	WMI_TOF_SET_TX_RX_OFFSET_EVENTID		= 0x1997,
+	WMI_TOF_GET_TX_RX_OFFSET_EVENTID		= 0x1998,
+	WMI_GET_RF_SECTOR_PARAMS_DONE_EVENTID		= 0x19A0,
+	WMI_SET_RF_SECTOR_PARAMS_DONE_EVENTID		= 0x19A1,
+	WMI_GET_SELECTED_RF_SECTOR_INDEX_DONE_EVENTID	= 0x19A2,
+	WMI_SET_SELECTED_RF_SECTOR_INDEX_DONE_EVENTID	= 0x19A3,
+	WMI_SET_RF_SECTOR_ON_DONE_EVENTID		= 0x19A4,
+	WMI_PRIO_TX_SECTORS_ORDER_EVENTID		= 0x19A5,
+	WMI_PRIO_TX_SECTORS_NUMBER_EVENTID		= 0x19A6,
+	WMI_PRIO_TX_SECTORS_SET_DEFAULT_CFG_EVENTID	= 0x19A7,
 	WMI_SET_CHANNEL_EVENTID				= 0x9000,
 	WMI_ASSOC_REQ_EVENTID				= 0x9001,
 	WMI_EAPOL_RX_EVENTID				= 0x9002,
@@ -1166,6 +1231,7 @@
 	BASEBAND_SPARROW_M_B0	= 0x05,
 	BASEBAND_SPARROW_M_C0	= 0x06,
 	BASEBAND_SPARROW_M_D0	= 0x07,
+	BASEBAND_TALYN_M_A0	= 0x08,
 };
 
 /* WMI_GET_BASEBAND_TYPE_EVENTID */
@@ -1242,12 +1308,13 @@
 	u8 assoc_req_len;
 	u8 assoc_resp_len;
 	u8 cid;
-	u8 reserved2[3];
+	u8 aid;
+	u8 reserved2[2];
 	/* not in use */
 	u8 assoc_info[0];
 } __packed;
 
-/* WMI_DISCONNECT_EVENTID */
+/* disconnect_reason */
 enum wmi_disconnect_reason {
 	WMI_DIS_REASON_NO_NETWORK_AVAIL		= 0x01,
 	/* bmiss */
@@ -1265,6 +1332,7 @@
 	WMI_DIS_REASON_IBSS_MERGE		= 0x0E,
 };
 
+/* WMI_DISCONNECT_EVENTID */
 struct wmi_disconnect_event {
 	/* reason code, see 802.11 spec. */
 	__le16 protocol_reason_status;
@@ -1714,6 +1782,42 @@
 	u8 reserved[3];
 } __packed;
 
+/* BRP antenna limit mode */
+enum wmi_brp_ant_limit_mode {
+	/* Disable BRP force antenna limit */
+	WMI_BRP_ANT_LIMIT_MODE_DISABLE		= 0x00,
+	/* Define maximal antennas limit. Only effective antennas will be
+	 * actually used
+	 */
+	WMI_BRP_ANT_LIMIT_MODE_EFFECTIVE	= 0x01,
+	/* Force a specific number of antennas */
+	WMI_BRP_ANT_LIMIT_MODE_FORCE		= 0x02,
+	/* number of BRP antenna limit modes */
+	WMI_BRP_ANT_LIMIT_MODES_NUM		= 0x03,
+};
+
+/* WMI_BRP_SET_ANT_LIMIT_CMDID */
+struct wmi_brp_set_ant_limit_cmd {
+	/* connection id */
+	u8 cid;
+	/* enum wmi_brp_ant_limit_mode */
+	u8 limit_mode;
+	/* antenna limit count, 1-27
+	 * disable_mode - ignored
+	 * effective_mode - upper limit to number of antennas to be used
+	 * force_mode - exact number of antennas to be used
+	 */
+	u8 ant_limit;
+	u8 reserved;
+} __packed;
+
+/* WMI_BRP_SET_ANT_LIMIT_EVENTID */
+struct wmi_brp_set_ant_limit_event {
+	/* wmi_fw_status */
+	u8 status;
+	u8 reserved[3];
+} __packed;
+
 /* broadcast connection ID */
 #define WMI_LINK_MAINTAIN_CFG_CID_BROADCAST	(0xFFFFFFFF)
 
@@ -2070,6 +2174,22 @@
 	u8 meas_data[WMI_AOA_MAX_DATA_SIZE];
 } __packed;
 
+/* WMI_SET_MGMT_RETRY_LIMIT_EVENTID */
+struct wmi_set_mgmt_retry_limit_event {
+	/* enum wmi_fw_status */
+	u8 status;
+	/* alignment to 32b */
+	u8 reserved[3];
+} __packed;
+
+/* WMI_GET_MGMT_RETRY_LIMIT_EVENTID */
+struct wmi_get_mgmt_retry_limit_event {
+	/* MAC retransmit limit for mgmt frames */
+	u8 mgmt_retry_limit;
+	/* alignment to 32b */
+	u8 reserved[3];
+} __packed;
+
 /* WMI_TOF_GET_CAPABILITIES_EVENTID */
 struct wmi_tof_get_capabilities_event {
 	u8 ftm_capability;
@@ -2184,4 +2304,283 @@
 	u8 report[0];
 } __packed;
 
+/* WMI_TOF_SET_TX_RX_OFFSET_EVENTID */
+struct wmi_tof_set_tx_rx_offset_event {
+	/* enum wmi_fw_status */
+	u8 status;
+	u8 reserved[3];
+} __packed;
+
+/* WMI_TOF_GET_TX_RX_OFFSET_EVENTID */
+struct wmi_tof_get_tx_rx_offset_event {
+	/* enum wmi_fw_status */
+	u8 status;
+	u8 reserved1[3];
+	/* TX delay offset */
+	__le32 tx_offset;
+	/* RX delay offset */
+	__le32 rx_offset;
+	__le32 reserved2[2];
+} __packed;
+
+/* Result status codes for WMI commands */
+enum wmi_rf_sector_status {
+	WMI_RF_SECTOR_STATUS_SUCCESS			= 0x00,
+	WMI_RF_SECTOR_STATUS_BAD_PARAMETERS_ERROR	= 0x01,
+	WMI_RF_SECTOR_STATUS_BUSY_ERROR			= 0x02,
+	WMI_RF_SECTOR_STATUS_NOT_SUPPORTED_ERROR	= 0x03,
+};
+
+/* Types of the RF sector (TX,RX) */
+enum wmi_rf_sector_type {
+	WMI_RF_SECTOR_TYPE_RX	= 0x00,
+	WMI_RF_SECTOR_TYPE_TX	= 0x01,
+};
+
+/* Content of RF Sector (six 32-bits registers) */
+struct wmi_rf_sector_info {
+	/* Phase values for RF Chains[15-0] (2bits per RF chain) */
+	__le32 psh_hi;
+	/* Phase values for RF Chains[31-16] (2bits per RF chain) */
+	__le32 psh_lo;
+	/* ETYPE Bit0 for all RF chains[31-0] - bit0 of Edge amplifier gain
+	 * index
+	 */
+	__le32 etype0;
+	/* ETYPE Bit1 for all RF chains[31-0] - bit1 of Edge amplifier gain
+	 * index
+	 */
+	__le32 etype1;
+	/* ETYPE Bit2 for all RF chains[31-0] - bit2 of Edge amplifier gain
+	 * index
+	 */
+	__le32 etype2;
+	/* D-Type values (3bits each) for 8 Distribution amplifiers + X16
+	 * switch bits
+	 */
+	__le32 dtype_swch_off;
+} __packed;
+
+#define WMI_INVALID_RF_SECTOR_INDEX	(0xFFFF)
+#define WMI_MAX_RF_MODULES_NUM		(8)
+
+/* WMI_GET_RF_SECTOR_PARAMS_CMD */
+struct wmi_get_rf_sector_params_cmd {
+	/* Sector number to be retrieved */
+	__le16 sector_idx;
+	/* enum wmi_rf_sector_type - type of requested RF sector */
+	u8 sector_type;
+	/* bitmask vector specifying destination RF modules */
+	u8 rf_modules_vec;
+} __packed;
+
+/* \WMI_GET_RF_SECTOR_PARAMS_DONE_EVENT */
+struct wmi_get_rf_sector_params_done_event {
+	/* result status of WMI_GET_RF_SECTOR_PARAMS_CMD (enum
+	 * wmi_rf_sector_status)
+	 */
+	u8 status;
+	/* align next field to U64 boundary */
+	u8 reserved[7];
+	/* TSF timestamp when RF sectors where retrieved */
+	__le64 tsf;
+	/* Content of RF sector retrieved from each RF module */
+	struct wmi_rf_sector_info sectors_info[WMI_MAX_RF_MODULES_NUM];
+} __packed;
+
+/* WMI_SET_RF_SECTOR_PARAMS_CMD */
+struct wmi_set_rf_sector_params_cmd {
+	/* Sector number to be retrieved */
+	__le16 sector_idx;
+	/* enum wmi_rf_sector_type - type of requested RF sector */
+	u8 sector_type;
+	/* bitmask vector specifying destination RF modules */
+	u8 rf_modules_vec;
+	/* Content of RF sector to be written to each RF module */
+	struct wmi_rf_sector_info sectors_info[WMI_MAX_RF_MODULES_NUM];
+} __packed;
+
+/* \WMI_SET_RF_SECTOR_PARAMS_DONE_EVENT */
+struct wmi_set_rf_sector_params_done_event {
+	/* result status of WMI_SET_RF_SECTOR_PARAMS_CMD (enum
+	 * wmi_rf_sector_status)
+	 */
+	u8 status;
+} __packed;
+
+/* WMI_GET_SELECTED_RF_SECTOR_INDEX_CMD - Get RF sector index selected by
+ * TXSS/BRP for communication with specified CID
+ */
+struct wmi_get_selected_rf_sector_index_cmd {
+	/* Connection/Station ID in [0:7] range */
+	u8 cid;
+	/* type of requested RF sector (enum wmi_rf_sector_type) */
+	u8 sector_type;
+	/* align to U32 boundary */
+	u8 reserved[2];
+} __packed;
+
+/* \WMI_GET_SELECTED_RF_SECTOR_INDEX_DONE_EVENT - Returns retrieved RF sector
+ * index selected by TXSS/BRP for communication with specified CID
+ */
+struct wmi_get_selected_rf_sector_index_done_event {
+	/* Retrieved sector index selected in TXSS (for TX sector request) or
+	 * BRP (for RX sector request)
+	 */
+	__le16 sector_idx;
+	/* result status of WMI_GET_SELECTED_RF_SECTOR_INDEX_CMD (enum
+	 * wmi_rf_sector_status)
+	 */
+	u8 status;
+	/* align next field to U64 boundary */
+	u8 reserved[5];
+	/* TSF timestamp when result was retrieved */
+	__le64 tsf;
+} __packed;
+
+/* WMI_SET_SELECTED_RF_SECTOR_INDEX_CMD - Force RF sector index for
+ * communication with specified CID. Assumes that TXSS/BRP is disabled by
+ * other command
+ */
+struct wmi_set_selected_rf_sector_index_cmd {
+	/* Connection/Station ID in [0:7] range */
+	u8 cid;
+	/* type of requested RF sector (enum wmi_rf_sector_type) */
+	u8 sector_type;
+	/* Forced sector index */
+	__le16 sector_idx;
+} __packed;
+
+/* \WMI_SET_SELECTED_RF_SECTOR_INDEX_DONE_EVENT - Success/Fail status for
+ * WMI_SET_SELECTED_RF_SECTOR_INDEX_CMD
+ */
+struct wmi_set_selected_rf_sector_index_done_event {
+	/* result status of WMI_SET_SELECTED_RF_SECTOR_INDEX_CMD (enum
+	 * wmi_rf_sector_status)
+	 */
+	u8 status;
+	/* align to U32 boundary */
+	u8 reserved[3];
+} __packed;
+
+/* WMI_SET_RF_SECTOR_ON_CMD - Activates specified sector for specified rf
+ * modules
+ */
+struct wmi_set_rf_sector_on_cmd {
+	/* Sector index to be activated */
+	__le16 sector_idx;
+	/* type of requested RF sector (enum wmi_rf_sector_type) */
+	u8 sector_type;
+	/* bitmask vector specifying destination RF modules */
+	u8 rf_modules_vec;
+} __packed;
+
+/* \WMI_SET_RF_SECTOR_ON_DONE_EVENT - Success/Fail status for
+ * WMI_SET_RF_SECTOR_ON_CMD
+ */
+struct wmi_set_rf_sector_on_done_event {
+	/* result status of WMI_SET_RF_SECTOR_ON_CMD (enum
+	 * wmi_rf_sector_status)
+	 */
+	u8 status;
+	/* align to U32 boundary */
+	u8 reserved[3];
+} __packed;
+
+enum wmi_sector_sweep_type {
+	WMI_SECTOR_SWEEP_TYPE_TXSS		= 0x00,
+	WMI_SECTOR_SWEEP_TYPE_BCON		= 0x01,
+	WMI_SECTOR_SWEEP_TYPE_TXSS_AND_BCON	= 0x02,
+	WMI_SECTOR_SWEEP_TYPE_NUM		= 0x03,
+};
+
+/* WMI_PRIO_TX_SECTORS_ORDER_CMDID
+ *
+ * Set the order of TX sectors in TXSS and/or Beacon(AP).
+ *
+ * Returned event:
+ * - WMI_PRIO_TX_SECTORS_ORDER_EVENTID
+ */
+struct wmi_prio_tx_sectors_order_cmd {
+	/* tx sectors order to be applied, 0xFF for end of array */
+	u8 tx_sectors_priority_array[MAX_NUM_OF_SECTORS];
+	/* enum wmi_sector_sweep_type, TXSS and/or Beacon */
+	u8 sector_sweep_type;
+	/* needed only for TXSS configuration */
+	u8 cid;
+	/* alignment to 32b */
+	u8 reserved[2];
+} __packed;
+
+/* completion status codes */
+enum wmi_prio_tx_sectors_cmd_status {
+	WMI_PRIO_TX_SECT_CMD_STATUS_SUCCESS	= 0x00,
+	WMI_PRIO_TX_SECT_CMD_STATUS_BAD_PARAM	= 0x01,
+	/* other error */
+	WMI_PRIO_TX_SECT_CMD_STATUS_ERROR	= 0x02,
+};
+
+/* WMI_PRIO_TX_SECTORS_ORDER_EVENTID */
+struct wmi_prio_tx_sectors_order_event {
+	/* enum wmi_prio_tx_sectors_cmd_status */
+	u8 status;
+	/* alignment to 32b */
+	u8 reserved[3];
+} __packed;
+
+struct wmi_prio_tx_sectors_num_cmd {
+	/* [0-128], 0 = No changes */
+	u8 beacon_number_of_sectors;
+	/* [0-128], 0 = No changes */
+	u8 txss_number_of_sectors;
+	/* [0-8] needed only for TXSS configuration */
+	u8 cid;
+} __packed;
+
+/* WMI_PRIO_TX_SECTORS_NUMBER_CMDID
+ *
+ * Set the number of active sectors in TXSS and/or Beacon.
+ *
+ * Returned event:
+ * - WMI_PRIO_TX_SECTORS_NUMBER_EVENTID
+ */
+struct wmi_prio_tx_sectors_number_cmd {
+	struct wmi_prio_tx_sectors_num_cmd active_sectors_num;
+	/* alignment to 32b */
+	u8 reserved;
+} __packed;
+
+/* WMI_PRIO_TX_SECTORS_NUMBER_EVENTID */
+struct wmi_prio_tx_sectors_number_event {
+	/* enum wmi_prio_tx_sectors_cmd_status */
+	u8 status;
+	/* alignment to 32b */
+	u8 reserved[3];
+} __packed;
+
+/* WMI_PRIO_TX_SECTORS_SET_DEFAULT_CFG_CMDID
+ *
+ * Set default sectors order and number (hard coded in board file)
+ * in TXSS and/or Beacon.
+ *
+ * Returned event:
+ * - WMI_PRIO_TX_SECTORS_SET_DEFAULT_CFG_EVENTID
+ */
+struct wmi_prio_tx_sectors_set_default_cfg_cmd {
+	/* enum wmi_sector_sweep_type, TXSS and/or Beacon */
+	u8 sector_sweep_type;
+	/* needed only for TXSS configuration */
+	u8 cid;
+	/* alignment to 32b */
+	u8 reserved[2];
+} __packed;
+
+/* WMI_PRIO_TX_SECTORS_SET_DEFAULT_CFG_EVENTID */
+struct wmi_prio_tx_sectors_set_default_cfg_event {
+	/* enum wmi_prio_tx_sectors_cmd_status */
+	u8 status;
+	/* alignment to 32b */
+	u8 reserved[3];
+} __packed;
+
 #endif /* __WILOCITY_WMI_H__ */
diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/sw.c
index 8b6e37c..20bfb37 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/sw.c
+++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/sw.c
@@ -96,7 +96,7 @@
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
-	char *fw_name = "rtlwifi/rtl8192cfwU.bin";
+	char *fw_name;
 
 	rtl8192ce_bt_reg_init(hw);
 
@@ -168,8 +168,13 @@
 	}
 
 	/* request fw */
-	if (IS_81XXC_VENDOR_UMC_B_CUT(rtlhal->version))
+	if (IS_VENDOR_UMC_A_CUT(rtlhal->version) &&
+	    !IS_92C_SERIAL(rtlhal->version))
+		fw_name = "rtlwifi/rtl8192cfwU.bin";
+	else if (IS_81XXC_VENDOR_UMC_B_CUT(rtlhal->version))
 		fw_name = "rtlwifi/rtl8192cfwU_B.bin";
+	else
+		fw_name = "rtlwifi/rtl8192cfw.bin";
 
 	rtlpriv->max_fw_size = 0x4000;
 	pr_info("Using firmware %s\n", fw_name);
diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c
index bf2744e..0cdcb21 100644
--- a/drivers/net/xen-netfront.c
+++ b/drivers/net/xen-netfront.c
@@ -1397,6 +1397,8 @@
 	for (i = 0; i < num_queues && info->queues; ++i) {
 		struct netfront_queue *queue = &info->queues[i];
 
+		del_timer_sync(&queue->rx_refill_timer);
+
 		if (queue->tx_irq && (queue->tx_irq == queue->rx_irq))
 			unbind_from_irqhandler(queue->tx_irq, queue);
 		if (queue->tx_irq && (queue->tx_irq != queue->rx_irq)) {
@@ -1751,7 +1753,6 @@
 
 		if (netif_running(info->netdev))
 			napi_disable(&queue->napi);
-		del_timer_sync(&queue->rx_refill_timer);
 		netif_napi_del(&queue->napi);
 	}
 
diff --git a/drivers/ntb/ntb_transport.c b/drivers/ntb/ntb_transport.c
index 4eb8adb..c234ee43 100644
--- a/drivers/ntb/ntb_transport.c
+++ b/drivers/ntb/ntb_transport.c
@@ -1799,7 +1799,7 @@
 
 	node = dev_to_node(&ndev->dev);
 
-	free_queue = ffs(nt->qp_bitmap);
+	free_queue = ffs(nt->qp_bitmap_free);
 	if (!free_queue)
 		goto err;
 
@@ -2270,9 +2270,8 @@
 
 static void __exit ntb_transport_exit(void)
 {
-	debugfs_remove_recursive(nt_debugfs_dir);
-
 	ntb_unregister_client(&ntb_transport_client);
 	bus_unregister(&ntb_transport_bus);
+	debugfs_remove_recursive(nt_debugfs_dir);
 }
 module_exit(ntb_transport_exit);
diff --git a/drivers/ntb/test/ntb_perf.c b/drivers/ntb/test/ntb_perf.c
index e75d4fd..434e1d4 100644
--- a/drivers/ntb/test/ntb_perf.c
+++ b/drivers/ntb/test/ntb_perf.c
@@ -265,6 +265,8 @@
 	if (dma_submit_error(cookie))
 		goto err_set_unmap;
 
+	dmaengine_unmap_put(unmap);
+
 	atomic_inc(&pctx->dma_sync);
 	dma_async_issue_pending(chan);
 
diff --git a/drivers/nvdimm/namespace_devs.c b/drivers/nvdimm/namespace_devs.c
index 1480734..aefca64 100644
--- a/drivers/nvdimm/namespace_devs.c
+++ b/drivers/nvdimm/namespace_devs.c
@@ -962,8 +962,8 @@
 	struct nvdimm_drvdata *ndd;
 	struct nd_label_id label_id;
 	u32 flags = 0, remainder;
+	int rc, i, id = -1;
 	u8 *uuid = NULL;
-	int rc, i;
 
 	if (dev->driver || ndns->claim)
 		return -EBUSY;
@@ -972,11 +972,13 @@
 		struct nd_namespace_pmem *nspm = to_nd_namespace_pmem(dev);
 
 		uuid = nspm->uuid;
+		id = nspm->id;
 	} else if (is_namespace_blk(dev)) {
 		struct nd_namespace_blk *nsblk = to_nd_namespace_blk(dev);
 
 		uuid = nsblk->uuid;
 		flags = NSLABEL_FLAG_LOCAL;
+		id = nsblk->id;
 	}
 
 	/*
@@ -1039,10 +1041,11 @@
 
 	/*
 	 * Try to delete the namespace if we deleted all of its
-	 * allocation, this is not the seed device for the region, and
-	 * it is not actively claimed by a btt instance.
+	 * allocation, this is not the seed or 0th device for the
+	 * region, and it is not actively claimed by a btt, pfn, or dax
+	 * instance.
 	 */
-	if (val == 0 && nd_region->ns_seed != dev && !ndns->claim)
+	if (val == 0 && id != 0 && nd_region->ns_seed != dev && !ndns->claim)
 		nd_device_unregister(dev, ND_ASYNC);
 
 	return rc;
diff --git a/drivers/nvdimm/pfn_devs.c b/drivers/nvdimm/pfn_devs.c
index a2ac9e6..6c033c9 100644
--- a/drivers/nvdimm/pfn_devs.c
+++ b/drivers/nvdimm/pfn_devs.c
@@ -627,15 +627,12 @@
 	size = resource_size(&nsio->res);
 	npfns = (size - start_pad - end_trunc - SZ_8K) / SZ_4K;
 	if (nd_pfn->mode == PFN_MODE_PMEM) {
-		unsigned long memmap_size;
-
 		/*
 		 * vmemmap_populate_hugepages() allocates the memmap array in
 		 * HPAGE_SIZE chunks.
 		 */
-		memmap_size = ALIGN(64 * npfns, HPAGE_SIZE);
-		offset = ALIGN(start + SZ_8K + memmap_size + dax_label_reserve,
-				nd_pfn->align) - start;
+		offset = ALIGN(start + SZ_8K + 64 * npfns + dax_label_reserve,
+				max(nd_pfn->align, HPAGE_SIZE)) - start;
 	} else if (nd_pfn->mode == PFN_MODE_RAM)
 		offset = ALIGN(start + SZ_8K + dax_label_reserve,
 				nd_pfn->align) - start;
diff --git a/drivers/pci/pcie/pme.c b/drivers/pci/pcie/pme.c
index 884bad5..4b70349 100644
--- a/drivers/pci/pcie/pme.c
+++ b/drivers/pci/pcie/pme.c
@@ -448,6 +448,17 @@
 	return 0;
 }
 
+/**
+ * pcie_pme_remove - Prepare PCIe PME service device for removal.
+ * @srv - PCIe service device to remove.
+ */
+static void pcie_pme_remove(struct pcie_device *srv)
+{
+	pcie_pme_suspend(srv);
+	free_irq(srv->irq, srv);
+	kfree(get_service_data(srv));
+}
+
 static struct pcie_port_service_driver pcie_pme_driver = {
 	.name		= "pcie_pme",
 	.port_type	= PCI_EXP_TYPE_ROOT_PORT,
@@ -456,6 +467,7 @@
 	.probe		= pcie_pme_probe,
 	.suspend	= pcie_pme_suspend,
 	.resume		= pcie_pme_resume,
+	.remove		= pcie_pme_remove,
 };
 
 /**
diff --git a/drivers/platform/msm/Kconfig b/drivers/platform/msm/Kconfig
index 6265515..54a9cb2 100644
--- a/drivers/platform/msm/Kconfig
+++ b/drivers/platform/msm/Kconfig
@@ -113,6 +113,7 @@
 	  numbers in the kernel log along with the PMIC option status. The PMIC
 	  type is mapped to a QTI chip part number and logged as well.
 
+
 config MSM_MHI_DEV
         tristate "Modem Device Interface Driver"
 	depends on EP_PCIE && IPA
@@ -130,4 +131,17 @@
 	  Enabling this option adds USB BAM Driver.
 	  USB BAM driver was added to supports SPS Peripheral-to-Peripheral
 	  transfers between the USB and other peripheral.
+
+config MSM_11AD
+	tristate "Platform driver for 11ad chip"
+	depends on PCI
+	depends on PCI_MSM
+	default n
+	---help---
+	  This module adds required platform support for wireless adapter based on
+	  Qualcomm Technologies, Inc. 11ad chip, integrated into MSM platform
+
+	  If you choose to build it as a module, it will be called
+	  msm_11ad_proxy.
+
 endmenu
diff --git a/drivers/platform/msm/Makefile b/drivers/platform/msm/Makefile
index fe7ae10..0bf87f4 100644
--- a/drivers/platform/msm/Makefile
+++ b/drivers/platform/msm/Makefile
@@ -9,3 +9,4 @@
 obj-$(CONFIG_QPNP_REVID) += qpnp-revid.o
 obj-$(CONFIG_MSM_MHI_DEV) += mhi_dev/
 obj-$(CONFIG_USB_BAM) += usb_bam.o
+obj-$(CONFIG_MSM_11AD) += msm_11ad/
\ No newline at end of file
diff --git a/drivers/platform/msm/gsi/gsi.c b/drivers/platform/msm/gsi/gsi.c
index 188388b..f48182c 100644
--- a/drivers/platform/msm/gsi/gsi.c
+++ b/drivers/platform/msm/gsi/gsi.c
@@ -22,7 +22,7 @@
 #include "gsi_reg.h"
 
 #define GSI_CMD_TIMEOUT (5*HZ)
-#define GSI_STOP_CMD_TIMEOUT_MS 1
+#define GSI_STOP_CMD_TIMEOUT_MS 10
 #define GSI_MAX_CH_LOW_WEIGHT 15
 #define GSI_MHI_ER_START 10
 #define GSI_MHI_ER_END 16
@@ -264,6 +264,11 @@
 	}
 }
 
+static void gsi_handle_gp_int1(void)
+{
+	complete(&gsi_ctx->gen_ee_cmd_compl);
+}
+
 static void gsi_handle_glob_ee(int ee)
 {
 	uint32_t val;
@@ -288,8 +293,7 @@
 	}
 
 	if (val & GSI_EE_n_CNTXT_GLOB_IRQ_EN_GP_INT1_BMSK) {
-		notify.evt_id = GSI_PER_EVT_GLOB_GP1;
-		gsi_ctx->per.notify_cb(&notify);
+		gsi_handle_gp_int1();
 	}
 
 	if (val & GSI_EE_n_CNTXT_GLOB_IRQ_EN_GP_INT2_BMSK) {
@@ -2745,6 +2749,67 @@
 }
 EXPORT_SYMBOL(gsi_get_inst_ram_offset_and_size);
 
+int gsi_halt_channel_ee(unsigned int chan_idx, unsigned int ee, int *code)
+{
+	enum gsi_generic_ee_cmd_opcode op = GSI_GEN_EE_CMD_HALT_CHANNEL;
+	uint32_t val;
+	int res;
+
+	if (!gsi_ctx) {
+		pr_err("%s:%d gsi context not allocated\n", __func__, __LINE__);
+		return -GSI_STATUS_NODEV;
+	}
+
+	if (chan_idx >= gsi_ctx->max_ch || !code) {
+		GSIERR("bad params chan_idx=%d\n", chan_idx);
+		return -GSI_STATUS_INVALID_PARAMS;
+	}
+
+	mutex_lock(&gsi_ctx->mlock);
+	reinit_completion(&gsi_ctx->gen_ee_cmd_compl);
+
+	/* invalidate the response */
+	gsi_ctx->scratch.word0.val = gsi_readl(gsi_ctx->base +
+			GSI_EE_n_CNTXT_SCRATCH_0_OFFS(gsi_ctx->per.ee));
+	gsi_ctx->scratch.word0.s.generic_ee_cmd_return_code = 0;
+	gsi_writel(gsi_ctx->scratch.word0.val, gsi_ctx->base +
+			GSI_EE_n_CNTXT_SCRATCH_0_OFFS(gsi_ctx->per.ee));
+
+	gsi_ctx->gen_ee_cmd_dbg.halt_channel++;
+	val = (((op << GSI_EE_n_GSI_EE_GENERIC_CMD_OPCODE_SHFT) &
+		GSI_EE_n_GSI_EE_GENERIC_CMD_OPCODE_BMSK) |
+		((chan_idx << GSI_EE_n_GSI_EE_GENERIC_CMD_VIRT_CHAN_IDX_SHFT) &
+			GSI_EE_n_GSI_EE_GENERIC_CMD_VIRT_CHAN_IDX_BMSK) |
+		((ee << GSI_EE_n_GSI_EE_GENERIC_CMD_EE_SHFT) &
+			GSI_EE_n_GSI_EE_GENERIC_CMD_EE_BMSK));
+	gsi_writel(val, gsi_ctx->base +
+		GSI_EE_n_GSI_EE_GENERIC_CMD_OFFS(gsi_ctx->per.ee));
+
+	res = wait_for_completion_timeout(&gsi_ctx->gen_ee_cmd_compl,
+		msecs_to_jiffies(GSI_CMD_TIMEOUT));
+	if (res == 0) {
+		GSIERR("chan_idx=%u ee=%u timed out\n", chan_idx, ee);
+		res = -GSI_STATUS_TIMED_OUT;
+		goto free_lock;
+	}
+
+	gsi_ctx->scratch.word0.val = gsi_readl(gsi_ctx->base +
+		GSI_EE_n_CNTXT_SCRATCH_0_OFFS(gsi_ctx->per.ee));
+	if (gsi_ctx->scratch.word0.s.generic_ee_cmd_return_code == 0) {
+		GSIERR("No response received\n");
+		res = -GSI_STATUS_ERROR;
+		goto free_lock;
+	}
+
+	res = GSI_STATUS_SUCCESS;
+	*code = gsi_ctx->scratch.word0.s.generic_ee_cmd_return_code;
+free_lock:
+	mutex_unlock(&gsi_ctx->mlock);
+
+	return res;
+}
+EXPORT_SYMBOL(gsi_halt_channel_ee);
+
 static int msm_gsi_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
@@ -2757,6 +2822,7 @@
 	}
 
 	gsi_ctx->dev = dev;
+	init_completion(&gsi_ctx->gen_ee_cmd_compl);
 	gsi_debugfs_init();
 
 	return 0;
diff --git a/drivers/platform/msm/gsi/gsi.h b/drivers/platform/msm/gsi/gsi.h
index 750ae2b..d0eb162 100644
--- a/drivers/platform/msm/gsi/gsi.h
+++ b/drivers/platform/msm/gsi/gsi.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -115,9 +115,12 @@
 struct gsi_ee_scratch {
 	union __packed {
 		struct {
-			uint32_t resvd1:15;
+			uint32_t inter_ee_cmd_return_code:3;
+			uint32_t resvd1:2;
+			uint32_t generic_ee_cmd_return_code:3;
+			uint32_t resvd2:7;
 			uint32_t max_usb_pkt_size:1;
-			uint32_t resvd2:8;
+			uint32_t resvd3:8;
 			uint32_t mhi_base_chan_idx:8;
 		} s;
 		uint32_t val;
@@ -135,6 +138,10 @@
 	unsigned long cmd_completed;
 };
 
+struct gsi_generic_ee_cmd_debug_stats {
+	unsigned long halt_channel;
+};
+
 struct gsi_ctx {
 	void __iomem *base;
 	struct device *dev;
@@ -143,6 +150,7 @@
 	struct gsi_chan_ctx chan[GSI_CHAN_MAX];
 	struct ch_debug_stats ch_dbg[GSI_CHAN_MAX];
 	struct gsi_evt_ctx evtr[GSI_EVT_RING_MAX];
+	struct gsi_generic_ee_cmd_debug_stats gen_ee_cmd_dbg;
 	struct mutex mlock;
 	spinlock_t slock;
 	unsigned long evt_bmap;
@@ -154,6 +162,7 @@
 	struct workqueue_struct *dp_stat_wq;
 	u32 max_ch;
 	u32 max_ev;
+	struct completion gen_ee_cmd_compl;
 };
 
 enum gsi_re_type {
@@ -227,6 +236,18 @@
 	GSI_EVT_DE_ALLOC = 0xa,
 };
 
+enum gsi_generic_ee_cmd_opcode {
+	GSI_GEN_EE_CMD_HALT_CHANNEL = 0x1,
+};
+
+enum gsi_generic_ee_cmd_return_code {
+	GSI_GEN_EE_CMD_RETURN_CODE_SUCCESS = 0x1,
+	GSI_GEN_EE_CMD_RETURN_CODE_CHANNEL_NOT_RUNNING = 0x2,
+	GSI_GEN_EE_CMD_RETURN_CODE_INCORRECT_DIRECTION = 0x3,
+	GSI_GEN_EE_CMD_RETURN_CODE_INCORRECT_CHANNEL_TYPE = 0x4,
+	GSI_GEN_EE_CMD_RETURN_CODE_INCORRECT_CHANNEL_INDEX = 0x5,
+};
+
 extern struct gsi_ctx *gsi_ctx;
 void gsi_debugfs_init(void);
 uint16_t gsi_find_idx_from_addr(struct gsi_ring_ctx *ctx, uint64_t addr);
diff --git a/drivers/platform/msm/gsi/gsi_reg.h b/drivers/platform/msm/gsi/gsi_reg.h
index 1acaf74..d0462aa 100644
--- a/drivers/platform/msm/gsi/gsi_reg.h
+++ b/drivers/platform/msm/gsi/gsi_reg.h
@@ -1365,8 +1365,12 @@
 	(GSI_GSI_REG_BASE_OFFS + 0x0001f018 + 0x4000 * (n))
 #define GSI_EE_n_GSI_EE_GENERIC_CMD_RMSK 0xffffffff
 #define GSI_EE_n_GSI_EE_GENERIC_CMD_MAXn 3
-#define GSI_EE_n_GSI_EE_GENERIC_CMD_OPCODE_BMSK 0xffffffff
+#define GSI_EE_n_GSI_EE_GENERIC_CMD_OPCODE_BMSK 0x1f
 #define GSI_EE_n_GSI_EE_GENERIC_CMD_OPCODE_SHFT 0x0
+#define GSI_EE_n_GSI_EE_GENERIC_CMD_VIRT_CHAN_IDX_BMSK 0x3e0
+#define GSI_EE_n_GSI_EE_GENERIC_CMD_VIRT_CHAN_IDX_SHFT 0x5
+#define GSI_EE_n_GSI_EE_GENERIC_CMD_EE_BMSK 0x3c00
+#define GSI_EE_n_GSI_EE_GENERIC_CMD_EE_SHFT 0xa
 
 /* v1.0 */
 #define GSI_V1_0_EE_n_GSI_HW_PARAM_OFFS(n) \
diff --git a/drivers/platform/msm/ipa/ipa_api.c b/drivers/platform/msm/ipa/ipa_api.c
index 06881d3..aa81bdc 100644
--- a/drivers/platform/msm/ipa/ipa_api.c
+++ b/drivers/platform/msm/ipa/ipa_api.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -2510,15 +2510,15 @@
 
 /**
  * ipa_get_gsi_ep_info() - provide gsi ep information
- * @ipa_ep_idx: IPA endpoint index
+ * @client: IPA client type
  *
  * Return value: pointer to ipa_gsi_ep_info
  */
-struct ipa_gsi_ep_config *ipa_get_gsi_ep_info(int ipa_ep_idx)
+const struct ipa_gsi_ep_config *ipa_get_gsi_ep_info(enum ipa_client_type client)
 {
 	if (!ipa_api_ctrl || !ipa_api_ctrl->ipa_get_gsi_ep_info)
 		return NULL;
-	return ipa_api_ctrl->ipa_get_gsi_ep_info(ipa_ep_idx);
+	return ipa_api_ctrl->ipa_get_gsi_ep_info(client);
 }
 EXPORT_SYMBOL(ipa_get_gsi_ep_info);
 
diff --git a/drivers/platform/msm/ipa/ipa_api.h b/drivers/platform/msm/ipa/ipa_api.h
index 171c9fb..1b8e3d6 100644
--- a/drivers/platform/msm/ipa/ipa_api.h
+++ b/drivers/platform/msm/ipa/ipa_api.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -331,7 +331,8 @@
 	int (*ipa_create_wdi_mapping)(u32 num_buffers,
 		struct ipa_wdi_buffer_info *info);
 
-	struct ipa_gsi_ep_config *(*ipa_get_gsi_ep_info)(int ipa_ep_idx);
+	const struct ipa_gsi_ep_config *(*ipa_get_gsi_ep_info)
+		(enum ipa_client_type client);
 
 	int (*ipa_register_ipa_ready_cb)(void (*ipa_ready_cb)(void *user_data),
 		void *user_data);
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa.c b/drivers/platform/msm/ipa/ipa_v2/ipa.c
index feec2aa..4d735df 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa.c
@@ -1827,7 +1827,7 @@
 	u32 max_cmds = ipa_get_max_flt_rt_cmds(ipa_ctx->ipa_num_pipes);
 
 	mem.base = dma_alloc_coherent(ipa_ctx->pdev, 4, &mem.phys_base,
-		GFP_KERNEL);
+		GFP_ATOMIC);
 	if (!mem.base) {
 		IPAERR("failed to alloc DMA buff of size 4\n");
 		return -ENOMEM;
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_flt.c b/drivers/platform/msm/ipa/ipa_v2/ipa_flt.c
index 12eaae8..ad5b799 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_flt.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_flt.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -235,7 +235,7 @@
  * @ip: the ip address family type
  * @hdr_sz: header size
  *
- * Returns:	0 on success, negative on failure
+ * Returns:	size on success, negative on failure
  *
  * caller needs to hold any needed locks to ensure integrity
  *
@@ -373,7 +373,12 @@
 					((long)body &
 					IPA_FLT_ENTRY_MEMORY_ALLIGNMENT));
 		} else {
-			WARN_ON(tbl->sz == 0);
+			if (tbl->sz == 0) {
+				IPAERR("tbl size is 0\n");
+				WARN_ON(1);
+				goto proc_err;
+			}
+
 			/* allocate memory for the flt tbl */
 			flt_tbl_mem.size = tbl->sz;
 			flt_tbl_mem.base =
@@ -460,7 +465,12 @@
 						((long)body &
 					IPA_FLT_ENTRY_MEMORY_ALLIGNMENT));
 			} else {
-				WARN_ON(tbl->sz == 0);
+				if (tbl->sz == 0) {
+					IPAERR("tbl size is 0\n");
+					WARN_ON(1);
+					goto proc_err;
+				}
+
 				/* allocate memory for the flt tbl */
 				flt_tbl_mem.size = tbl->sz;
 				flt_tbl_mem.base =
@@ -534,8 +544,15 @@
 	u8 *hdr;
 	u8 *body;
 	u8 *base;
+	int res;
 
-	mem->size = ipa_get_flt_hw_tbl_size(ip, &hdr_sz);
+	res = ipa_get_flt_hw_tbl_size(ip, &hdr_sz);
+	if (res < 0) {
+		IPAERR("ipa_get_flt_hw_tbl_size failed %d\n", res);
+		return res;
+	}
+
+	mem->size = res;
 	mem->size = IPA_HW_TABLE_ALIGNMENT(mem->size);
 
 	if (mem->size == 0) {
@@ -720,6 +737,7 @@
 	u32 *entr;
 	u32 body_start_offset;
 	u32 hdr_top;
+	int res;
 
 	if (ip == IPA_IP_v4)
 		body_start_offset = IPA_MEM_PART(apps_v4_flt_ofst) -
@@ -756,7 +774,13 @@
 		entr++;
 	}
 
-	mem->size = ipa_get_flt_hw_tbl_size(ip, &hdr_sz);
+	res = ipa_get_flt_hw_tbl_size(ip, &hdr_sz);
+	if (res < 0) {
+		IPAERR("ipa_get_flt_hw_tbl_size failed %d\n", res);
+		goto body_err;
+	}
+
+	mem->size = res;
 	mem->size -= hdr_sz;
 	mem->size = IPA_HW_TABLE_ALIGNMENT(mem->size);
 
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_i.h b/drivers/platform/msm/ipa/ipa_v2/ipa_i.h
index 299a431..586598a 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_i.h
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_i.h
@@ -139,7 +139,7 @@
 
 #define IPA_HW_TABLE_ALIGNMENT(start_ofst) \
 	(((start_ofst) + 127) & ~127)
-#define IPA_RT_FLT_HW_RULE_BUF_SIZE	(128)
+#define IPA_RT_FLT_HW_RULE_BUF_SIZE	(256)
 
 #define IPA_HDR_PROC_CTX_TABLE_ALIGNMENT_BYTE 8
 #define IPA_HDR_PROC_CTX_TABLE_ALIGNMENT(start_ofst) \
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_nat.c b/drivers/platform/msm/ipa/ipa_v2/ipa_nat.c
index 9b97f57..96e0125 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_nat.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_nat.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -25,6 +25,16 @@
 #define IPA_NAT_SHARED_MEMORY  1
 #define IPA_NAT_TEMP_MEM_SIZE 128
 
+enum nat_table_type {
+	IPA_NAT_BASE_TBL = 0,
+	IPA_NAT_EXPN_TBL = 1,
+	IPA_NAT_INDX_TBL = 2,
+	IPA_NAT_INDEX_EXPN_TBL = 3,
+};
+
+#define NAT_TABLE_ENTRY_SIZE_BYTE 32
+#define NAT_INTEX_TABLE_ENTRY_SIZE_BYTE 4
+
 static int ipa_nat_vma_fault_remap(
 	 struct vm_area_struct *vma, struct vm_fault *vmf)
 {
@@ -572,6 +582,71 @@
 		goto bail;
 	}
 
+	for (cnt = 0; cnt < dma->entries; cnt++) {
+		if (dma->dma[cnt].table_index >= 1) {
+			IPAERR("Invalid table index %d\n",
+				dma->dma[cnt].table_index);
+			ret = -EPERM;
+			goto bail;
+		}
+
+		switch (dma->dma[cnt].base_addr) {
+		case IPA_NAT_BASE_TBL:
+			if (dma->dma[cnt].offset >=
+				(ipa_ctx->nat_mem.size_base_tables + 1) *
+				NAT_TABLE_ENTRY_SIZE_BYTE) {
+				IPAERR("Invalid offset %d\n",
+					dma->dma[cnt].offset);
+				ret = -EPERM;
+				goto bail;
+			}
+
+			break;
+
+		case IPA_NAT_EXPN_TBL:
+			if (dma->dma[cnt].offset >=
+				ipa_ctx->nat_mem.size_expansion_tables *
+				NAT_TABLE_ENTRY_SIZE_BYTE) {
+				IPAERR("Invalid offset %d\n",
+					dma->dma[cnt].offset);
+				ret = -EPERM;
+				goto bail;
+			}
+
+			break;
+
+		case IPA_NAT_INDX_TBL:
+			if (dma->dma[cnt].offset >=
+				(ipa_ctx->nat_mem.size_base_tables + 1) *
+				NAT_INTEX_TABLE_ENTRY_SIZE_BYTE) {
+				IPAERR("Invalid offset %d\n",
+					dma->dma[cnt].offset);
+				ret = -EPERM;
+				goto bail;
+			}
+
+			break;
+
+		case IPA_NAT_INDEX_EXPN_TBL:
+			if (dma->dma[cnt].offset >=
+				ipa_ctx->nat_mem.size_expansion_tables *
+				NAT_INTEX_TABLE_ENTRY_SIZE_BYTE) {
+				IPAERR("Invalid offset %d\n",
+					dma->dma[cnt].offset);
+				ret = -EPERM;
+				goto bail;
+			}
+
+			break;
+
+		default:
+			IPAERR("Invalid base_addr %d\n",
+				dma->dma[cnt].base_addr);
+			ret = -EPERM;
+			goto bail;
+		}
+	}
+
 	size = sizeof(struct ipa_desc) * NUM_OF_DESC;
 	desc = kzalloc(size, GFP_KERNEL);
 	if (desc == NULL) {
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_rt.c b/drivers/platform/msm/ipa/ipa_v2/ipa_rt.c
index 164e94b..c1ed842 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_rt.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_rt.c
@@ -227,7 +227,7 @@
  * @hdr_sz: header size
  * @max_rt_idx: maximal index
  *
- * Returns:	0 on success, negative on failure
+ * Returns:	size on success, negative on failure
  *
  * caller needs to hold any needed locks to ensure integrity
  *
@@ -356,7 +356,11 @@
 					      ((long)body &
 					      IPA_RT_ENTRY_MEMORY_ALLIGNMENT));
 		} else {
-			WARN_ON(tbl->sz == 0);
+			if (tbl->sz == 0) {
+				IPAERR("cannot generate 0 size table\n");
+				goto proc_err;
+			}
+
 			/* allocate memory for the RT tbl */
 			rt_tbl_mem.size = tbl->sz;
 			rt_tbl_mem.base =
@@ -429,8 +433,15 @@
 	u8 *base;
 	int max_rt_idx;
 	int i;
+	int res;
 
-	mem->size = ipa_get_rt_hw_tbl_size(ip, &hdr_sz, &max_rt_idx);
+	res = ipa_get_rt_hw_tbl_size(ip, &hdr_sz, &max_rt_idx);
+	if (res < 0) {
+		IPAERR("ipa_get_rt_hw_tbl_size failed %d\n", res);
+		goto error;
+	}
+
+	mem->size = res;
 	mem->size = (mem->size + IPA_RT_TABLE_MEMORY_ALLIGNMENT) &
 				~IPA_RT_TABLE_MEMORY_ALLIGNMENT;
 
@@ -603,6 +614,7 @@
 	int num_index;
 	u32 body_start_offset;
 	u32 apps_start_idx;
+	int res;
 
 	if (ip == IPA_IP_v4) {
 		num_index = IPA_MEM_PART(v4_apps_rt_index_hi) -
@@ -632,7 +644,13 @@
 		entr++;
 	}
 
-	mem->size = ipa_get_rt_hw_tbl_size(ip, &hdr_sz, &max_rt_idx);
+	res = ipa_get_rt_hw_tbl_size(ip, &hdr_sz, &max_rt_idx);
+	if (res < 0) {
+		IPAERR("ipa_get_rt_hw_tbl_size failed %d\n", res);
+		goto base_err;
+	}
+
+	mem->size = res;
 	mem->size -= hdr_sz;
 	mem->size = (mem->size + IPA_RT_TABLE_MEMORY_ALLIGNMENT) &
 				~IPA_RT_TABLE_MEMORY_ALLIGNMENT;
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c
index 4fdd84b..dd12169 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c
@@ -4929,7 +4929,8 @@
 	return res;
 }
 
-static struct ipa_gsi_ep_config *ipa2_get_gsi_ep_info(int ipa_ep_idx)
+static const struct ipa_gsi_ep_config *ipa2_get_gsi_ep_info
+	(enum ipa_client_type client)
 {
 	IPAERR("Not supported for IPA 2.x\n");
 	return NULL;
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c
index e9e3c15..acc597b 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c
@@ -227,19 +227,11 @@
 static void ipa3_start_tag_process(struct work_struct *work);
 static DECLARE_WORK(ipa3_tag_work, ipa3_start_tag_process);
 
-static void ipa3_sps_release_resource(struct work_struct *work);
-static DECLARE_DELAYED_WORK(ipa3_sps_release_resource_work,
-	ipa3_sps_release_resource);
+static void ipa3_transport_release_resource(struct work_struct *work);
+static DECLARE_DELAYED_WORK(ipa3_transport_release_resource_work,
+	ipa3_transport_release_resource);
 static void ipa_gsi_notify_cb(struct gsi_per_notify *notify);
 
-static void ipa_gsi_request_resource(struct work_struct *work);
-static DECLARE_WORK(ipa_gsi_request_resource_work,
-	ipa_gsi_request_resource);
-
-static void ipa_gsi_release_resource(struct work_struct *work);
-static DECLARE_DELAYED_WORK(ipa_gsi_release_resource_work,
-	ipa_gsi_release_resource);
-
 static struct ipa3_plat_drv_res ipa3_res = {0, };
 struct msm_bus_scale_pdata *ipa3_bus_scale_table;
 
@@ -1878,6 +1870,45 @@
 	}
 }
 
+static void ipa3_halt_q6_cons_gsi_channels(void)
+{
+	int ep_idx;
+	int client_idx;
+	const struct ipa_gsi_ep_config *gsi_ep_cfg;
+	int ret;
+	int code = 0;
+
+	for (client_idx = 0; client_idx < IPA_CLIENT_MAX; client_idx++) {
+		if (IPA_CLIENT_IS_Q6_CONS(client_idx)) {
+			ep_idx = ipa3_get_ep_mapping(client_idx);
+			if (ep_idx == -1)
+				continue;
+
+			gsi_ep_cfg = ipa3_get_gsi_ep_info(ep_idx);
+			if (!gsi_ep_cfg) {
+				IPAERR("failed to get GSI config\n");
+				ipa_assert();
+				return;
+			}
+
+			ret = gsi_halt_channel_ee(
+				gsi_ep_cfg->ipa_gsi_chan_num, gsi_ep_cfg->ee,
+				&code);
+			if (ret == GSI_STATUS_SUCCESS)
+				IPADBG("halted gsi ch %d ee %d with code %d\n",
+				gsi_ep_cfg->ipa_gsi_chan_num,
+				gsi_ep_cfg->ee,
+				code);
+			else
+				IPAERR("failed to halt ch %d ee %d code %d\n",
+				gsi_ep_cfg->ipa_gsi_chan_num,
+				gsi_ep_cfg->ee,
+				code);
+		}
+	}
+}
+
+
 static int ipa3_q6_clean_q6_flt_tbls(enum ipa_ip_type ip,
 	enum ipa_rule_type rlt)
 {
@@ -1935,7 +1966,7 @@
 	}
 
 	retval = ipahal_flt_generate_empty_img(1, lcl_hdr_sz, lcl_hdr_sz,
-		0, &mem);
+		0, &mem, true);
 	if (retval) {
 		IPAERR("failed to generate flt single tbl empty img\n");
 		goto free_cmd_pyld;
@@ -2042,7 +2073,7 @@
 
 	retval = ipahal_rt_generate_empty_img(
 		modem_rt_index_hi - modem_rt_index_lo + 1,
-		lcl_hdr_sz, lcl_hdr_sz, &mem);
+		lcl_hdr_sz, lcl_hdr_sz, &mem, true);
 	if (retval) {
 		IPAERR("fail generate empty rt img\n");
 		return -ENOMEM;
@@ -2302,13 +2333,18 @@
 	int client_idx;
 
 	IPADBG_LOW("ENTER\n");
-	IPA_ACTIVE_CLIENTS_INC_SIMPLE();
 
 	if (!ipa3_ctx->uc_ctx.uc_loaded) {
 		IPAERR("uC is not loaded. Skipping\n");
 		return;
 	}
 
+	IPA_ACTIVE_CLIENTS_INC_SIMPLE();
+
+	/* Handle the issue where SUSPEND was removed for some reason */
+	ipa3_q6_avoid_holb();
+	ipa3_halt_q6_cons_gsi_channels();
+
 	for (client_idx = 0; client_idx < IPA_CLIENT_MAX; client_idx++)
 		if (IPA_CLIENT_IS_Q6_PROD(client_idx)) {
 			if (ipa3_uc_is_gsi_channel_empty(client_idx)) {
@@ -2510,7 +2546,7 @@
 
 	rc = ipahal_rt_generate_empty_img(IPA_MEM_PART(v4_rt_num_index),
 		IPA_MEM_PART(v4_rt_hash_size), IPA_MEM_PART(v4_rt_nhash_size),
-		&mem);
+		&mem, false);
 	if (rc) {
 		IPAERR("fail generate empty v4 rt img\n");
 		return rc;
@@ -2577,7 +2613,7 @@
 
 	rc = ipahal_rt_generate_empty_img(IPA_MEM_PART(v6_rt_num_index),
 		IPA_MEM_PART(v6_rt_hash_size), IPA_MEM_PART(v6_rt_nhash_size),
-		&mem);
+		&mem, false);
 	if (rc) {
 		IPAERR("fail generate empty v6 rt img\n");
 		return rc;
@@ -2638,7 +2674,7 @@
 	rc = ipahal_flt_generate_empty_img(ipa3_ctx->ep_flt_num,
 		IPA_MEM_PART(v4_flt_hash_size),
 		IPA_MEM_PART(v4_flt_nhash_size), ipa3_ctx->ep_flt_bitmap,
-		&mem);
+		&mem, false);
 	if (rc) {
 		IPAERR("fail generate empty v4 flt img\n");
 		return rc;
@@ -2698,7 +2734,7 @@
 	rc = ipahal_flt_generate_empty_img(ipa3_ctx->ep_flt_num,
 		IPA_MEM_PART(v6_flt_hash_size),
 		IPA_MEM_PART(v6_flt_nhash_size), ipa3_ctx->ep_flt_bitmap,
-		&mem);
+		&mem, false);
 	if (rc) {
 		IPAERR("fail generate empty v6 flt img\n");
 		return rc;
@@ -3194,8 +3230,8 @@
  *
  * This function is called prior to clock gating when active client counter
  * is 1. TAG process ensures that there are no packets inside IPA HW that
- * were not submitted to peer's BAM. During TAG process all aggregation frames
- * are (force) closed.
+ * were not submitted to the IPA client via the transport. During TAG process
+ * all aggregation frames are (force) closed.
  *
  * Return codes:
  * None
@@ -3501,10 +3537,10 @@
 	return 0;
 }
 
-static void ipa3_sps_process_irq_schedule_rel(void)
+static void ipa3_process_irq_schedule_rel(void)
 {
 	queue_delayed_work(ipa3_ctx->transport_power_mgmt_wq,
-		&ipa3_sps_release_resource_work,
+		&ipa3_transport_release_resource_work,
 		msecs_to_jiffies(IPA_TRANSPORT_PROD_TIMEOUT_MSEC));
 }
 
@@ -3549,7 +3585,7 @@
 					atomic_set(
 					&ipa3_ctx->transport_pm.dec_clients,
 					1);
-					ipa3_sps_process_irq_schedule_rel();
+					ipa3_process_irq_schedule_rel();
 				}
 			} else {
 				resource = ipa3_get_rm_resource_from_ep(i);
@@ -3611,17 +3647,17 @@
 	return 0;
 }
 
-static void ipa3_sps_release_resource(struct work_struct *work)
+static void ipa3_transport_release_resource(struct work_struct *work)
 {
 	mutex_lock(&ipa3_ctx->transport_pm.transport_pm_mutex);
 	/* check whether still need to decrease client usage */
 	if (atomic_read(&ipa3_ctx->transport_pm.dec_clients)) {
 		if (atomic_read(&ipa3_ctx->transport_pm.eot_activity)) {
 			IPADBG("EOT pending Re-scheduling\n");
-			ipa3_sps_process_irq_schedule_rel();
+			ipa3_process_irq_schedule_rel();
 		} else {
 			atomic_set(&ipa3_ctx->transport_pm.dec_clients, 0);
-			IPA_ACTIVE_CLIENTS_DEC_SPECIAL("SPS_RESOURCE");
+			IPA_ACTIVE_CLIENTS_DEC_SPECIAL("TRANSPORT_RESOURCE");
 		}
 	}
 	atomic_set(&ipa3_ctx->transport_pm.eot_activity, 0);
@@ -3847,13 +3883,13 @@
 /**
  * ipa3_post_init() - Initialize the IPA Driver (Part II).
  * This part contains all initialization which requires interaction with
- * IPA HW (via SPS BAM or GSI).
+ * IPA HW (via GSI).
  *
  * @resource_p:	contain platform specific values from DST file
  * @pdev:	The platform device structure representing the IPA driver
  *
  * Function initialization process:
- * - Register BAM/SPS or GSI
+ * - Register GSI
  * - Setup APPS pipes
  * - Initialize tethering bridge
  * - Initialize IPA debugfs
@@ -3868,57 +3904,28 @@
 			  struct device *ipa_dev)
 {
 	int result;
-	struct sps_bam_props bam_props = { 0 };
 	struct gsi_per_props gsi_props;
 	struct ipa3_uc_hdlrs uc_hdlrs = { 0 };
 
-	if (ipa3_ctx->transport_prototype == IPA_TRANSPORT_TYPE_GSI) {
-		memset(&gsi_props, 0, sizeof(gsi_props));
-		gsi_props.ver = ipa3_get_gsi_ver(resource_p->ipa_hw_type);
-		gsi_props.ee = resource_p->ee;
-		gsi_props.intr = GSI_INTR_IRQ;
-		gsi_props.irq = resource_p->transport_irq;
-		gsi_props.phys_addr = resource_p->transport_mem_base;
-		gsi_props.size = resource_p->transport_mem_size;
-		gsi_props.notify_cb = ipa_gsi_notify_cb;
-		gsi_props.req_clk_cb = NULL;
-		gsi_props.rel_clk_cb = NULL;
+	memset(&gsi_props, 0, sizeof(gsi_props));
+	gsi_props.ver = ipa3_get_gsi_ver(resource_p->ipa_hw_type);
+	gsi_props.ee = resource_p->ee;
+	gsi_props.intr = GSI_INTR_IRQ;
+	gsi_props.irq = resource_p->transport_irq;
+	gsi_props.phys_addr = resource_p->transport_mem_base;
+	gsi_props.size = resource_p->transport_mem_size;
+	gsi_props.notify_cb = ipa_gsi_notify_cb;
+	gsi_props.req_clk_cb = NULL;
+	gsi_props.rel_clk_cb = NULL;
 
-		result = gsi_register_device(&gsi_props,
-			&ipa3_ctx->gsi_dev_hdl);
-		if (result != GSI_STATUS_SUCCESS) {
-			IPAERR(":gsi register error - %d\n", result);
-			result = -ENODEV;
-			goto fail_register_device;
-		}
-		IPADBG("IPA gsi is registered\n");
-	} else {
-		/* register IPA with SPS driver */
-		bam_props.phys_addr = resource_p->transport_mem_base;
-		bam_props.virt_size = resource_p->transport_mem_size;
-		bam_props.irq = resource_p->transport_irq;
-		bam_props.num_pipes = ipa3_ctx->ipa_num_pipes;
-		bam_props.summing_threshold = IPA_SUMMING_THRESHOLD;
-		bam_props.event_threshold = IPA_EVENT_THRESHOLD;
-		bam_props.options |= SPS_BAM_NO_LOCAL_CLK_GATING;
-		if (ipa3_ctx->ipa3_hw_mode != IPA_HW_MODE_VIRTUAL)
-			bam_props.options |= SPS_BAM_OPT_IRQ_WAKEUP;
-		if (ipa3_ctx->ipa_bam_remote_mode == true)
-			bam_props.manage |= SPS_BAM_MGR_DEVICE_REMOTE;
-		if (!ipa3_ctx->smmu_s1_bypass)
-			bam_props.options |= SPS_BAM_SMMU_EN;
-		bam_props.ee = resource_p->ee;
-		bam_props.ipc_loglevel = 3;
-
-		result = sps_register_bam_device(&bam_props,
-			&ipa3_ctx->bam_handle);
-		if (result) {
-			IPAERR(":bam register error - %d\n", result);
-			result = -EPROBE_DEFER;
-			goto fail_register_device;
-		}
-		IPADBG("IPA BAM is registered\n");
+	result = gsi_register_device(&gsi_props,
+		&ipa3_ctx->gsi_dev_hdl);
+	if (result != GSI_STATUS_SUCCESS) {
+		IPAERR(":gsi register error - %d\n", result);
+		result = -ENODEV;
+		goto fail_register_device;
 	}
+	IPADBG("IPA gsi is registered\n");
 
 	/* setup the AP-IPA pipes */
 	if (ipa3_setup_apps_pipes()) {
@@ -3926,7 +3933,7 @@
 		result = -ENODEV;
 		goto fail_setup_apps_pipes;
 	}
-	IPADBG("IPA System2Bam pipes were connected\n");
+	IPADBG("IPA GPI pipes were connected\n");
 
 	if (ipa3_ctx->use_ipa_teth_bridge) {
 		/* Initialize the tethering bridge driver */
@@ -3979,18 +3986,13 @@
 fail_teth_bridge_driver_init:
 	ipa3_teardown_apps_pipes();
 fail_setup_apps_pipes:
-	if (ipa3_ctx->transport_prototype == IPA_TRANSPORT_TYPE_GSI)
-		gsi_deregister_device(ipa3_ctx->gsi_dev_hdl, false);
-	else
-		sps_deregister_bam_device(ipa3_ctx->bam_handle);
+	gsi_deregister_device(ipa3_ctx->gsi_dev_hdl, false);
 fail_register_device:
 	ipa_rm_delete_resource(IPA_RM_RESOURCE_APPS_CONS);
 	ipa_rm_exit();
 	cdev_del(&ipa3_ctx->cdev);
 	device_destroy(ipa3_ctx->class, ipa3_ctx->dev_num);
 	unregister_chrdev_region(ipa3_ctx->dev_num, 1);
-	if (ipa3_ctx->pipe_mem_pool)
-		gen_pool_destroy(ipa3_ctx->pipe_mem_pool);
 	ipa3_destroy_flt_tbl_idrs();
 	idr_destroy(&ipa3_ctx->ipa_idr);
 	kmem_cache_destroy(ipa3_ctx->rx_pkt_wrapper_cache);
@@ -4095,27 +4097,22 @@
 	if (ipa3_is_ready())
 		return count;
 
-	/*
-	 * We will trigger the process only if we're in GSI mode, otherwise,
-	 * we just ignore the write.
-	 */
-	if (ipa3_ctx->transport_prototype == IPA_TRANSPORT_TYPE_GSI) {
-		IPA_ACTIVE_CLIENTS_INC_SIMPLE();
+	IPA_ACTIVE_CLIENTS_INC_SIMPLE();
 
-		if (ipa3_is_msm_device())
-			result = ipa3_trigger_fw_loading_msms();
-		else
-			result = ipa3_trigger_fw_loading_mdms();
-		/* No IPAv3.x chipsets that don't support FW loading */
+	if (ipa3_is_msm_device())
+		result = ipa3_trigger_fw_loading_msms();
+	else
+		result = ipa3_trigger_fw_loading_mdms();
+	/* No IPAv3.x chipsets that don't support FW loading */
 
-		IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
+	IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
 
-		if (result) {
-			IPAERR("FW loading process has failed\n");
+	if (result) {
+		IPAERR("FW loading process has failed\n");
 			return result;
-		} else
-			ipa3_post_init(&ipa3_res, ipa3_ctx->dev);
-	}
+	} else
+		ipa3_post_init(&ipa3_res, ipa3_ctx->dev);
+
 	return count;
 }
 
@@ -4182,7 +4179,6 @@
 *    3)read HW values(such as core memory size)
 * - Map IPA core registers to CPU memory
 * - Restart IPA core(HW reset)
-* - Set configuration for IPA BAM via BAM_CNFG_BITS
 * - Initialize the look-aside caches(kmem_cache/slab) for filter,
 *   routing and IPA-tree
 * - Create memory pool with 4 objects for DMA operations(each object
@@ -4195,7 +4191,6 @@
 *   routing table ,filtering rule
 * - Initialize the filter block by committing IPV4 and IPV6 default rules
 * - Create empty routing table in system memory(no committing)
-* - Initialize pipes memory pool with ipa3_pipe_mem_init for supported platforms
 * - Create a char-device for IPA
 * - Initialize IPA RM (resource manager)
 * - Configure GSI registers (in GSI case)
@@ -4237,7 +4232,6 @@
 	ipa3_ctx->ipa_hw_type = resource_p->ipa_hw_type;
 	ipa3_ctx->ipa3_hw_mode = resource_p->ipa3_hw_mode;
 	ipa3_ctx->use_ipa_teth_bridge = resource_p->use_ipa_teth_bridge;
-	ipa3_ctx->ipa_bam_remote_mode = resource_p->ipa_bam_remote_mode;
 	ipa3_ctx->modem_cfg_emb_pipe_flt = resource_p->modem_cfg_emb_pipe_flt;
 	ipa3_ctx->ipa_wdi2 = resource_p->ipa_wdi2;
 	ipa3_ctx->use_64_bit_dma_mask = resource_p->use_64_bit_dma_mask;
@@ -4245,7 +4239,6 @@
 	ipa3_ctx->lan_rx_ring_size = resource_p->lan_rx_ring_size;
 	ipa3_ctx->skip_uc_pipe_reset = resource_p->skip_uc_pipe_reset;
 	ipa3_ctx->tethered_flow_control = resource_p->tethered_flow_control;
-	ipa3_ctx->transport_prototype = resource_p->transport_prototype;
 	ipa3_ctx->ee = resource_p->ee;
 	ipa3_ctx->apply_rg10_wa = resource_p->apply_rg10_wa;
 	ipa3_ctx->gsi_ch20_wa = resource_p->gsi_ch20_wa;
@@ -4424,11 +4417,7 @@
 		goto fail_create_transport_wq;
 	}
 
-	/* Initialize the SPS PM lock. */
 	mutex_init(&ipa3_ctx->transport_pm.transport_pm_mutex);
-	spin_lock_init(&ipa3_ctx->transport_pm.lock);
-	ipa3_ctx->transport_pm.res_granted = false;
-	ipa3_ctx->transport_pm.res_rel_in_prog = false;
 
 	/* init the lookaside cache */
 	ipa3_ctx->flt_rule_cache = kmem_cache_create("IPA_FLT",
@@ -4499,16 +4488,6 @@
 		goto fail_rx_pkt_wrapper_cache;
 	}
 
-	/* Setup DMA pool */
-	ipa3_ctx->dma_pool = dma_pool_create("ipa_tx", ipa3_ctx->pdev,
-		IPA_NUM_DESC_PER_SW_TX * sizeof(struct sps_iovec),
-		0, 0);
-	if (!ipa3_ctx->dma_pool) {
-		IPAERR("cannot alloc DMA pool.\n");
-		result = -ENOMEM;
-		goto fail_dma_pool;
-	}
-
 	/* init the various list heads */
 	INIT_LIST_HEAD(&ipa3_ctx->hdr_tbl.head_hdr_entry_list);
 	for (i = 0; i < IPA_HDR_BIN_MAX; i++) {
@@ -4567,11 +4546,6 @@
 	spin_lock_init(&ipa3_ctx->wc_memb.ipa_tx_mul_spinlock);
 	INIT_LIST_HEAD(&ipa3_ctx->wc_memb.wlan_comm_desc_list);
 
-	/* setup the IPA pipe mem pool */
-	if (resource_p->ipa_pipe_mem_size)
-		ipa3_pipe_mem_init(resource_p->ipa_pipe_mem_start_ofst,
-				resource_p->ipa_pipe_mem_size);
-
 	ipa3_ctx->class = class_create(THIS_MODULE, DRV_NAME);
 
 	result = alloc_chrdev_region(&ipa3_ctx->dev_num, 0, 1, DRV_NAME);
@@ -4649,26 +4623,20 @@
 	init_completion(&ipa3_ctx->uc_loaded_completion_obj);
 
 	/*
-	 * For GSI, we can't register the GSI driver yet, as it expects
+	 * We can't register the GSI driver yet, as it expects
 	 * the GSI FW to be up and running before the registration.
+	 *
+	 * For IPA3.0, the GSI configuration is done by the GSI driver.
+	 * For IPA3.1 (and on), the GSI configuration is done by TZ.
 	 */
-	if (ipa3_ctx->transport_prototype == IPA_TRANSPORT_TYPE_GSI) {
-		/*
-		 * For IPA3.0, the GSI configuration is done by the GSI driver.
-		 * For IPA3.1 (and on), the GSI configuration is done by TZ.
-		 */
-		if (ipa3_ctx->ipa_hw_type == IPA_HW_v3_0) {
-			result = ipa3_gsi_pre_fw_load_init();
-			if (result) {
-				IPAERR("gsi pre FW loading config failed\n");
-				result = -ENODEV;
-				goto fail_ipa_init_interrupts;
-			}
+	if (ipa3_ctx->ipa_hw_type == IPA_HW_v3_0) {
+		result = ipa3_gsi_pre_fw_load_init();
+		if (result) {
+			IPAERR("gsi pre FW loading config failed\n");
+			result = -ENODEV;
+			goto fail_ipa_init_interrupts;
 		}
 	}
-	/* For BAM (No other mode), we can just carry on with initialization */
-	else
-		return ipa3_post_init(resource_p, ipa_dev);
 
 	return 0;
 
@@ -4684,11 +4652,8 @@
 fail_device_create:
 	unregister_chrdev_region(ipa3_ctx->dev_num, 1);
 fail_alloc_chrdev_region:
-	if (ipa3_ctx->pipe_mem_pool)
-		gen_pool_destroy(ipa3_ctx->pipe_mem_pool);
 	ipa3_destroy_flt_tbl_idrs();
 	idr_destroy(&ipa3_ctx->ipa_idr);
-fail_dma_pool:
 	kmem_cache_destroy(ipa3_ctx->rx_pkt_wrapper_cache);
 fail_rx_pkt_wrapper_cache:
 	kmem_cache_destroy(ipa3_ctx->tx_pkt_wrapper_cache);
@@ -4748,7 +4713,6 @@
 	ipa_drv_res->ipa_pipe_mem_size = IPA_PIPE_MEM_SIZE;
 	ipa_drv_res->ipa_hw_type = 0;
 	ipa_drv_res->ipa3_hw_mode = 0;
-	ipa_drv_res->ipa_bam_remote_mode = false;
 	ipa_drv_res->modem_cfg_emb_pipe_flt = false;
 	ipa_drv_res->ipa_wdi2 = false;
 	ipa_drv_res->use_64_bit_dma_mask = false;
@@ -4810,13 +4774,6 @@
 		ipa_drv_res->use_ipa_teth_bridge
 		? "True" : "False");
 
-	ipa_drv_res->ipa_bam_remote_mode =
-			of_property_read_bool(pdev->dev.of_node,
-			"qcom,ipa-bam-remote-mode");
-	IPADBG(": ipa bam remote mode = %s\n",
-			ipa_drv_res->ipa_bam_remote_mode
-			? "True" : "False");
-
 	ipa_drv_res->modem_cfg_emb_pipe_flt =
 			of_property_read_bool(pdev->dev.of_node,
 			"qcom,modem-cfg-emb-pipe-flt");
@@ -4852,16 +4809,6 @@
 		ipa_drv_res->tethered_flow_control
 		? "True" : "False");
 
-	if (of_property_read_bool(pdev->dev.of_node,
-		"qcom,use-gsi"))
-		ipa_drv_res->transport_prototype = IPA_TRANSPORT_TYPE_GSI;
-	else
-		ipa_drv_res->transport_prototype = IPA_TRANSPORT_TYPE_SPS;
-
-	IPADBG(": transport type = %s\n",
-		ipa_drv_res->transport_prototype == IPA_TRANSPORT_TYPE_SPS
-		? "SPS" : "GSI");
-
 	/* Get IPA wrapper address */
 	resource = platform_get_resource_byname(pdev, IORESOURCE_MEM,
 			"ipa-base");
@@ -4878,53 +4825,28 @@
 	smmu_info.ipa_base = ipa_drv_res->ipa_mem_base;
 	smmu_info.ipa_size = ipa_drv_res->ipa_mem_size;
 
-	if (ipa_drv_res->transport_prototype == IPA_TRANSPORT_TYPE_SPS) {
-		/* Get IPA BAM address */
-		resource = platform_get_resource_byname(pdev, IORESOURCE_MEM,
-				"bam-base");
-		if (!resource) {
-			IPAERR(":get resource failed for bam-base!\n");
-			return -ENODEV;
-		}
-		ipa_drv_res->transport_mem_base = resource->start;
-		ipa_drv_res->transport_mem_size = resource_size(resource);
-		IPADBG(": bam-base = 0x%x, size = 0x%x\n",
-				ipa_drv_res->transport_mem_base,
-				ipa_drv_res->transport_mem_size);
-
-		/* Get IPA BAM IRQ number */
-		resource = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
-				"bam-irq");
-		if (!resource) {
-			IPAERR(":get resource failed for bam-irq!\n");
-			return -ENODEV;
-		}
-		ipa_drv_res->transport_irq = resource->start;
-		IPADBG(": bam-irq = %d\n", ipa_drv_res->transport_irq);
-	} else {
-		/* Get IPA GSI address */
-		resource = platform_get_resource_byname(pdev, IORESOURCE_MEM,
-				"gsi-base");
-		if (!resource) {
-			IPAERR(":get resource failed for gsi-base!\n");
-			return -ENODEV;
-		}
-		ipa_drv_res->transport_mem_base = resource->start;
-		ipa_drv_res->transport_mem_size = resource_size(resource);
-		IPADBG(": gsi-base = 0x%x, size = 0x%x\n",
-				ipa_drv_res->transport_mem_base,
-				ipa_drv_res->transport_mem_size);
-
-		/* Get IPA GSI IRQ number */
-		resource = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
-				"gsi-irq");
-		if (!resource) {
-			IPAERR(":get resource failed for gsi-irq!\n");
-			return -ENODEV;
-		}
-		ipa_drv_res->transport_irq = resource->start;
-		IPADBG(": gsi-irq = %d\n", ipa_drv_res->transport_irq);
+	/* Get IPA GSI address */
+	resource = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+			"gsi-base");
+	if (!resource) {
+		IPAERR(":get resource failed for gsi-base!\n");
+		return -ENODEV;
 	}
+	ipa_drv_res->transport_mem_base = resource->start;
+	ipa_drv_res->transport_mem_size = resource_size(resource);
+	IPADBG(": gsi-base = 0x%x, size = 0x%x\n",
+			ipa_drv_res->transport_mem_base,
+			ipa_drv_res->transport_mem_size);
+
+	/* Get IPA GSI IRQ number */
+	resource = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
+			"gsi-irq");
+	if (!resource) {
+		IPAERR(":get resource failed for gsi-irq!\n");
+		return -ENODEV;
+	}
+	ipa_drv_res->transport_irq = resource->start;
+	IPADBG(": gsi-irq = %d\n", ipa_drv_res->transport_irq);
 
 	/* Get IPA pipe mem start ofst */
 	resource = platform_get_resource_byname(pdev, IORESOURCE_MEM,
@@ -5541,9 +5463,11 @@
 		}
 	}
 
-	/* release SPS IPA resource without waiting for inactivity timer */
+	/*
+	 * Release transport IPA resource without waiting for inactivity timer
+	 */
 	atomic_set(&ipa3_ctx->transport_pm.eot_activity, 0);
-	ipa3_sps_release_resource(NULL);
+	ipa3_transport_release_resource(NULL);
 	IPADBG("Exit\n");
 
 	return 0;
@@ -5568,85 +5492,6 @@
 	return ipa3_ctx;
 }
 
-static void ipa_gsi_request_resource(struct work_struct *work)
-{
-	unsigned long flags;
-	int ret;
-
-	/* request IPA clocks */
-	IPA_ACTIVE_CLIENTS_INC_SIMPLE();
-
-	/* mark transport resource as granted */
-	spin_lock_irqsave(&ipa3_ctx->transport_pm.lock, flags);
-	ipa3_ctx->transport_pm.res_granted = true;
-
-	IPADBG("IPA is ON, calling gsi driver\n");
-	ret = gsi_complete_clk_grant(ipa3_ctx->gsi_dev_hdl);
-	if (ret != GSI_STATUS_SUCCESS)
-		IPAERR("gsi_complete_clk_grant failed %d\n", ret);
-
-	spin_unlock_irqrestore(&ipa3_ctx->transport_pm.lock, flags);
-}
-
-void ipa_gsi_req_res_cb(void *user_data, bool *granted)
-{
-	unsigned long flags;
-	struct ipa_active_client_logging_info log_info;
-
-	spin_lock_irqsave(&ipa3_ctx->transport_pm.lock, flags);
-
-	/* make sure no release will happen */
-	cancel_delayed_work(&ipa_gsi_release_resource_work);
-	ipa3_ctx->transport_pm.res_rel_in_prog = false;
-
-	if (ipa3_ctx->transport_pm.res_granted) {
-		*granted = true;
-	} else {
-		IPA_ACTIVE_CLIENTS_PREP_SPECIAL(log_info, "GSI_RESOURCE");
-		if (ipa3_inc_client_enable_clks_no_block(&log_info) == 0) {
-			ipa3_ctx->transport_pm.res_granted = true;
-			*granted = true;
-		} else {
-			queue_work(ipa3_ctx->transport_power_mgmt_wq,
-				   &ipa_gsi_request_resource_work);
-			*granted = false;
-		}
-	}
-	spin_unlock_irqrestore(&ipa3_ctx->transport_pm.lock, flags);
-}
-
-static void ipa_gsi_release_resource(struct work_struct *work)
-{
-	unsigned long flags;
-	bool dec_clients = false;
-
-	spin_lock_irqsave(&ipa3_ctx->transport_pm.lock, flags);
-	/* check whether still need to decrease client usage */
-	if (ipa3_ctx->transport_pm.res_rel_in_prog) {
-		dec_clients = true;
-		ipa3_ctx->transport_pm.res_rel_in_prog = false;
-		ipa3_ctx->transport_pm.res_granted = false;
-	}
-	spin_unlock_irqrestore(&ipa3_ctx->transport_pm.lock, flags);
-	if (dec_clients)
-		IPA_ACTIVE_CLIENTS_DEC_SPECIAL("GSI_RESOURCE");
-}
-
-int ipa_gsi_rel_res_cb(void *user_data)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&ipa3_ctx->transport_pm.lock, flags);
-
-	ipa3_ctx->transport_pm.res_rel_in_prog = true;
-	queue_delayed_work(ipa3_ctx->transport_power_mgmt_wq,
-			   &ipa_gsi_release_resource_work,
-			   msecs_to_jiffies(IPA_TRANSPORT_PROD_TIMEOUT_MSEC));
-
-	spin_unlock_irqrestore(&ipa3_ctx->transport_pm.lock, flags);
-	return 0;
-}
-
 static void ipa_gsi_notify_cb(struct gsi_per_notify *notify)
 {
 	switch (notify->evt_id) {
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_client.c b/drivers/platform/msm/ipa/ipa_v3/ipa_client.c
index 75b2824..796103f 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_client.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_client.c
@@ -130,623 +130,6 @@
 	return res;
 }
 
-static int ipa3_smmu_map_peer_bam(unsigned long dev)
-{
-	phys_addr_t base;
-	u32 size;
-	struct iommu_domain *smmu_domain;
-	struct ipa_smmu_cb_ctx *cb = ipa3_get_smmu_ctx();
-
-	if (!ipa3_ctx->smmu_s1_bypass) {
-		if (ipa3_ctx->peer_bam_map_cnt == 0) {
-			if (sps_get_bam_addr(dev, &base, &size)) {
-				IPAERR("Fail to get addr\n");
-				return -EINVAL;
-			}
-			smmu_domain = ipa3_get_smmu_domain();
-			if (smmu_domain != NULL) {
-				if (ipa3_iommu_map(smmu_domain,
-					cb->va_end,
-					rounddown(base, PAGE_SIZE),
-					roundup(size + base -
-					rounddown(base, PAGE_SIZE), PAGE_SIZE),
-					IOMMU_READ | IOMMU_WRITE |
-					IOMMU_MMIO)) {
-					IPAERR("Fail to ipa3_iommu_map\n");
-					return -EINVAL;
-				}
-			}
-
-			ipa3_ctx->peer_bam_iova = cb->va_end;
-			ipa3_ctx->peer_bam_pa = base;
-			ipa3_ctx->peer_bam_map_size = size;
-			ipa3_ctx->peer_bam_dev = dev;
-
-			IPADBG("Peer bam %lu mapped\n", dev);
-		} else {
-			WARN_ON(dev != ipa3_ctx->peer_bam_dev);
-		}
-
-		ipa3_ctx->peer_bam_map_cnt++;
-	}
-
-	return 0;
-}
-
-static int ipa3_connect_configure_sps(const struct ipa_connect_params *in,
-				     struct ipa3_ep_context *ep, int ipa_ep_idx)
-{
-	int result = -EFAULT;
-
-	/* Default Config */
-	ep->ep_hdl = sps_alloc_endpoint();
-
-	if (ipa3_smmu_map_peer_bam(in->client_bam_hdl)) {
-		IPAERR("fail to iommu map peer BAM.\n");
-		return -EFAULT;
-	}
-
-	if (ep->ep_hdl == NULL) {
-		IPAERR("SPS EP alloc failed EP.\n");
-		return -EFAULT;
-	}
-
-	result = sps_get_config(ep->ep_hdl,
-		&ep->connect);
-	if (result) {
-		IPAERR("fail to get config.\n");
-		return -EFAULT;
-	}
-
-	/* Specific Config */
-	if (IPA_CLIENT_IS_CONS(in->client)) {
-		ep->connect.mode = SPS_MODE_SRC;
-		ep->connect.destination =
-			in->client_bam_hdl;
-		ep->connect.dest_iova = ipa3_ctx->peer_bam_iova;
-		ep->connect.source = ipa3_ctx->bam_handle;
-		ep->connect.dest_pipe_index =
-			in->client_ep_idx;
-		ep->connect.src_pipe_index = ipa_ep_idx;
-	} else {
-		ep->connect.mode = SPS_MODE_DEST;
-		ep->connect.source = in->client_bam_hdl;
-		ep->connect.source_iova = ipa3_ctx->peer_bam_iova;
-		ep->connect.destination = ipa3_ctx->bam_handle;
-		ep->connect.src_pipe_index = in->client_ep_idx;
-		ep->connect.dest_pipe_index = ipa_ep_idx;
-	}
-
-	return 0;
-}
-
-static int ipa3_connect_allocate_fifo(const struct ipa_connect_params *in,
-				     struct sps_mem_buffer *mem_buff_ptr,
-				     bool *fifo_in_pipe_mem_ptr,
-				     u32 *fifo_pipe_mem_ofst_ptr,
-				     u32 fifo_size, int ipa_ep_idx)
-{
-	dma_addr_t dma_addr;
-	u32 ofst;
-	int result = -EFAULT;
-	struct iommu_domain *smmu_domain;
-
-	mem_buff_ptr->size = fifo_size;
-	if (in->pipe_mem_preferred) {
-		if (ipa3_pipe_mem_alloc(&ofst, fifo_size)) {
-			IPAERR("FIFO pipe mem alloc fail ep %u\n",
-				ipa_ep_idx);
-			mem_buff_ptr->base =
-				dma_alloc_coherent(ipa3_ctx->pdev,
-				mem_buff_ptr->size,
-				&dma_addr, GFP_KERNEL);
-		} else {
-			memset(mem_buff_ptr, 0, sizeof(struct sps_mem_buffer));
-			result = sps_setup_bam2bam_fifo(mem_buff_ptr, ofst,
-				fifo_size, 1);
-			WARN_ON(result);
-			*fifo_in_pipe_mem_ptr = 1;
-			dma_addr = mem_buff_ptr->phys_base;
-			*fifo_pipe_mem_ofst_ptr = ofst;
-		}
-	} else {
-		mem_buff_ptr->base =
-			dma_alloc_coherent(ipa3_ctx->pdev, mem_buff_ptr->size,
-			&dma_addr, GFP_KERNEL);
-	}
-	if (ipa3_ctx->smmu_s1_bypass) {
-		mem_buff_ptr->phys_base = dma_addr;
-	} else {
-		mem_buff_ptr->iova = dma_addr;
-		smmu_domain = ipa_get_smmu_domain();
-		if (smmu_domain != NULL) {
-			mem_buff_ptr->phys_base =
-				iommu_iova_to_phys(smmu_domain, dma_addr);
-		}
-	}
-	if (mem_buff_ptr->base == NULL) {
-		IPAERR("fail to get DMA memory.\n");
-		return -EFAULT;
-	}
-
-	return 0;
-}
-
-/**
- * ipa3_connect() - low-level IPA client connect
- * @in:	[in] input parameters from client
- * @sps:	[out] sps output from IPA needed by client for sps_connect
- * @clnt_hdl:	[out] opaque client handle assigned by IPA to client
- *
- * Should be called by the driver of the peripheral that wants to connect to
- * IPA in BAM-BAM mode. these peripherals are USB and HSIC. this api
- * expects caller to take responsibility to add any needed headers, routing
- * and filtering tables and rules as needed.
- *
- * Returns:	0 on success, negative on failure
- *
- * Note:	Should not be called from atomic context
- */
-int ipa3_connect(const struct ipa_connect_params *in,
-		struct ipa_sps_params *sps,
-		u32 *clnt_hdl)
-{
-	int ipa_ep_idx;
-	int result = -EFAULT;
-	struct ipa3_ep_context *ep;
-	struct ipahal_reg_ep_cfg_status ep_status;
-	unsigned long base;
-	struct iommu_domain *smmu_domain;
-
-	IPADBG("connecting client\n");
-
-	if (in == NULL || sps == NULL || clnt_hdl == NULL ||
-	    in->client >= IPA_CLIENT_MAX ||
-	    in->desc_fifo_sz == 0 || in->data_fifo_sz == 0) {
-		IPAERR("bad parm.\n");
-		return -EINVAL;
-	}
-
-	ipa_ep_idx = ipa3_get_ep_mapping(in->client);
-	if (ipa_ep_idx == -1) {
-		IPAERR("fail to alloc EP.\n");
-		goto fail;
-	}
-
-	ep = &ipa3_ctx->ep[ipa_ep_idx];
-
-	if (ep->valid) {
-		IPAERR("EP already allocated.\n");
-		goto fail;
-	}
-
-	memset(&ipa3_ctx->ep[ipa_ep_idx], 0, sizeof(struct ipa3_ep_context));
-	IPA_ACTIVE_CLIENTS_INC_EP(in->client);
-
-	ep->skip_ep_cfg = in->skip_ep_cfg;
-	ep->valid = 1;
-	ep->client = in->client;
-	ep->client_notify = in->notify;
-	ep->priv = in->priv;
-	ep->keep_ipa_awake = in->keep_ipa_awake;
-
-	result = ipa3_enable_data_path(ipa_ep_idx);
-	if (result) {
-		IPAERR("enable data path failed res=%d clnt=%d.\n", result,
-				ipa_ep_idx);
-		goto ipa_cfg_ep_fail;
-	}
-
-	if (!ep->skip_ep_cfg) {
-		if (ipa3_cfg_ep(ipa_ep_idx, &in->ipa_ep_cfg)) {
-			IPAERR("fail to configure EP.\n");
-			goto ipa_cfg_ep_fail;
-		}
-		/* Setting EP status 0 */
-		memset(&ep_status, 0, sizeof(ep_status));
-		if (ipa3_cfg_ep_status(ipa_ep_idx, &ep_status)) {
-			IPAERR("fail to configure status of EP.\n");
-			goto ipa_cfg_ep_fail;
-		}
-		IPADBG("ep configuration successful\n");
-	} else {
-		IPADBG("Skipping endpoint configuration.\n");
-	}
-
-	result = ipa3_connect_configure_sps(in, ep, ipa_ep_idx);
-	if (result) {
-		IPAERR("fail to configure SPS.\n");
-		goto ipa_cfg_ep_fail;
-	}
-
-	if (!ipa3_ctx->smmu_s1_bypass &&
-			(in->desc.base == NULL ||
-			 in->data.base == NULL)) {
-		IPAERR(" allocate FIFOs data_fifo=0x%p desc_fifo=0x%p.\n",
-				in->data.base, in->desc.base);
-		goto desc_mem_alloc_fail;
-	}
-
-	if (in->desc.base == NULL) {
-		result = ipa3_connect_allocate_fifo(in, &ep->connect.desc,
-						  &ep->desc_fifo_in_pipe_mem,
-						  &ep->desc_fifo_pipe_mem_ofst,
-						  in->desc_fifo_sz, ipa_ep_idx);
-		if (result) {
-			IPAERR("fail to allocate DESC FIFO.\n");
-			goto desc_mem_alloc_fail;
-		}
-	} else {
-		IPADBG("client allocated DESC FIFO\n");
-		ep->connect.desc = in->desc;
-		ep->desc_fifo_client_allocated = 1;
-	}
-	IPADBG("Descriptor FIFO pa=%pa, size=%d\n", &ep->connect.desc.phys_base,
-	       ep->connect.desc.size);
-
-	if (in->data.base == NULL) {
-		result = ipa3_connect_allocate_fifo(in, &ep->connect.data,
-						&ep->data_fifo_in_pipe_mem,
-						&ep->data_fifo_pipe_mem_ofst,
-						in->data_fifo_sz, ipa_ep_idx);
-		if (result) {
-			IPAERR("fail to allocate DATA FIFO.\n");
-			goto data_mem_alloc_fail;
-		}
-	} else {
-		IPADBG("client allocated DATA FIFO\n");
-		ep->connect.data = in->data;
-		ep->data_fifo_client_allocated = 1;
-	}
-	IPADBG("Data FIFO pa=%pa, size=%d\n", &ep->connect.data.phys_base,
-	       ep->connect.data.size);
-
-	if (!ipa3_ctx->smmu_s1_bypass) {
-		ep->connect.data.iova = ep->connect.data.phys_base;
-		base = ep->connect.data.iova;
-		smmu_domain = ipa_get_smmu_domain();
-		if (smmu_domain != NULL) {
-			if (ipa3_iommu_map(smmu_domain,
-				rounddown(base, PAGE_SIZE),
-				rounddown(base, PAGE_SIZE),
-				roundup(ep->connect.data.size + base -
-					rounddown(base, PAGE_SIZE), PAGE_SIZE),
-				IOMMU_READ | IOMMU_WRITE)) {
-				IPAERR("Fail to ipa3_iommu_map data FIFO\n");
-				goto iommu_map_data_fail;
-			}
-		}
-		ep->connect.desc.iova = ep->connect.desc.phys_base;
-		base = ep->connect.desc.iova;
-		if (smmu_domain != NULL) {
-			if (ipa3_iommu_map(smmu_domain,
-				rounddown(base, PAGE_SIZE),
-				rounddown(base, PAGE_SIZE),
-				roundup(ep->connect.desc.size + base -
-					rounddown(base, PAGE_SIZE), PAGE_SIZE),
-				IOMMU_READ | IOMMU_WRITE)) {
-				IPAERR("Fail to ipa3_iommu_map desc FIFO\n");
-				goto iommu_map_desc_fail;
-			}
-		}
-	}
-
-	if (IPA_CLIENT_IS_USB_CONS(in->client))
-		ep->connect.event_thresh = IPA_USB_EVENT_THRESHOLD;
-	else
-		ep->connect.event_thresh = IPA_EVENT_THRESHOLD;
-	ep->connect.options = SPS_O_AUTO_ENABLE;    /* BAM-to-BAM */
-
-	result = ipa3_sps_connect_safe(ep->ep_hdl, &ep->connect, in->client);
-	if (result) {
-		IPAERR("sps_connect fails.\n");
-		goto sps_connect_fail;
-	}
-
-	sps->ipa_bam_hdl = ipa3_ctx->bam_handle;
-	sps->ipa_ep_idx = ipa_ep_idx;
-	*clnt_hdl = ipa_ep_idx;
-	memcpy(&sps->desc, &ep->connect.desc, sizeof(struct sps_mem_buffer));
-	memcpy(&sps->data, &ep->connect.data, sizeof(struct sps_mem_buffer));
-
-	ipa3_ctx->skip_ep_cfg_shadow[ipa_ep_idx] = ep->skip_ep_cfg;
-	if (!ep->skip_ep_cfg && IPA_CLIENT_IS_PROD(in->client))
-		ipa3_install_dflt_flt_rules(ipa_ep_idx);
-
-	if (!ep->keep_ipa_awake)
-		IPA_ACTIVE_CLIENTS_DEC_EP(in->client);
-
-	IPADBG("client %d (ep: %d) connected\n", in->client, ipa_ep_idx);
-
-	return 0;
-
-sps_connect_fail:
-	if (!ipa3_ctx->smmu_s1_bypass) {
-		base = ep->connect.desc.iova;
-		smmu_domain = ipa_get_smmu_domain();
-		if (smmu_domain != NULL) {
-			iommu_unmap(smmu_domain,
-				rounddown(base, PAGE_SIZE),
-				roundup(ep->connect.desc.size + base -
-					rounddown(base, PAGE_SIZE), PAGE_SIZE));
-		}
-	}
-iommu_map_desc_fail:
-	if (!ipa3_ctx->smmu_s1_bypass) {
-		base = ep->connect.data.iova;
-		smmu_domain = ipa_get_smmu_domain();
-		if (smmu_domain != NULL) {
-			iommu_unmap(smmu_domain,
-				rounddown(base, PAGE_SIZE),
-				roundup(ep->connect.data.size + base -
-					rounddown(base, PAGE_SIZE), PAGE_SIZE));
-		}
-	}
-iommu_map_data_fail:
-	if (!ep->data_fifo_client_allocated) {
-		if (!ep->data_fifo_in_pipe_mem)
-			dma_free_coherent(ipa3_ctx->pdev,
-				  ep->connect.data.size,
-				  ep->connect.data.base,
-				  ep->connect.data.phys_base);
-		else
-			ipa3_pipe_mem_free(ep->data_fifo_pipe_mem_ofst,
-				  ep->connect.data.size);
-	}
-data_mem_alloc_fail:
-	if (!ep->desc_fifo_client_allocated) {
-		if (!ep->desc_fifo_in_pipe_mem)
-			dma_free_coherent(ipa3_ctx->pdev,
-				  ep->connect.desc.size,
-				  ep->connect.desc.base,
-				  ep->connect.desc.phys_base);
-		else
-			ipa3_pipe_mem_free(ep->desc_fifo_pipe_mem_ofst,
-				  ep->connect.desc.size);
-	}
-desc_mem_alloc_fail:
-	sps_free_endpoint(ep->ep_hdl);
-ipa_cfg_ep_fail:
-	memset(&ipa3_ctx->ep[ipa_ep_idx], 0, sizeof(struct ipa3_ep_context));
-	IPA_ACTIVE_CLIENTS_DEC_EP(in->client);
-fail:
-	return result;
-}
-
-static int ipa3_smmu_unmap_peer_bam(unsigned long dev)
-{
-	size_t len;
-	struct iommu_domain *smmu_domain;
-	struct ipa_smmu_cb_ctx *cb = ipa3_get_smmu_ctx();
-
-	if (!ipa3_ctx->smmu_s1_bypass) {
-		WARN_ON(dev != ipa3_ctx->peer_bam_dev);
-		ipa3_ctx->peer_bam_map_cnt--;
-		if (ipa3_ctx->peer_bam_map_cnt == 0) {
-			len = roundup(ipa3_ctx->peer_bam_map_size +
-					ipa3_ctx->peer_bam_pa -
-					rounddown(ipa3_ctx->peer_bam_pa,
-						PAGE_SIZE), PAGE_SIZE);
-			smmu_domain = ipa3_get_smmu_domain();
-			if (smmu_domain != NULL) {
-				if (iommu_unmap(smmu_domain,
-					cb->va_end, len) != len) {
-					IPAERR("Fail to iommu_unmap\n");
-					return -EINVAL;
-				}
-				IPADBG("Peer bam %lu unmapped\n", dev);
-			}
-		}
-	}
-
-	return 0;
-}
-
-/**
- * ipa3_disconnect() - low-level IPA client disconnect
- * @clnt_hdl:	[in] opaque client handle assigned by IPA to client
- *
- * Should be called by the driver of the peripheral that wants to disconnect
- * from IPA in BAM-BAM mode. this api expects caller to take responsibility to
- * free any needed headers, routing and filtering tables and rules as needed.
- *
- * Returns:	0 on success, negative on failure
- *
- * Note:	Should not be called from atomic context
- */
-int ipa3_disconnect(u32 clnt_hdl)
-{
-	int result;
-	struct ipa3_ep_context *ep;
-	unsigned long peer_bam;
-	unsigned long base;
-	struct iommu_domain *smmu_domain;
-	struct ipa_disable_force_clear_datapath_req_msg_v01 req = {0};
-	int res;
-	enum ipa_client_type client_type;
-
-	if (clnt_hdl >= ipa3_ctx->ipa_num_pipes ||
-		ipa3_ctx->ep[clnt_hdl].valid == 0) {
-		IPAERR("bad parm.\n");
-		return -EINVAL;
-	}
-
-	ep = &ipa3_ctx->ep[clnt_hdl];
-	client_type = ipa3_get_client_mapping(clnt_hdl);
-	if (!ep->keep_ipa_awake)
-		IPA_ACTIVE_CLIENTS_INC_EP(client_type);
-
-	/* Set Disconnect in Progress flag. */
-	spin_lock(&ipa3_ctx->disconnect_lock);
-	ep->disconnect_in_progress = true;
-	spin_unlock(&ipa3_ctx->disconnect_lock);
-
-	result = ipa3_disable_data_path(clnt_hdl);
-	if (result) {
-		IPAERR("disable data path failed res=%d clnt=%d.\n", result,
-				clnt_hdl);
-		return -EPERM;
-	}
-
-	result = sps_disconnect(ep->ep_hdl);
-	if (result) {
-		IPAERR("SPS disconnect failed.\n");
-		return -EPERM;
-	}
-
-	if (IPA_CLIENT_IS_CONS(ep->client))
-		peer_bam = ep->connect.destination;
-	else
-		peer_bam = ep->connect.source;
-
-	if (ipa3_smmu_unmap_peer_bam(peer_bam)) {
-		IPAERR("fail to iommu unmap peer BAM.\n");
-		return -EPERM;
-	}
-
-	if (!ep->desc_fifo_client_allocated &&
-	     ep->connect.desc.base) {
-		if (!ep->desc_fifo_in_pipe_mem)
-			dma_free_coherent(ipa3_ctx->pdev,
-					  ep->connect.desc.size,
-					  ep->connect.desc.base,
-					  ep->connect.desc.phys_base);
-		else
-			ipa3_pipe_mem_free(ep->desc_fifo_pipe_mem_ofst,
-					  ep->connect.desc.size);
-	}
-
-	if (!ep->data_fifo_client_allocated &&
-	     ep->connect.data.base) {
-		if (!ep->data_fifo_in_pipe_mem)
-			dma_free_coherent(ipa3_ctx->pdev,
-					  ep->connect.data.size,
-					  ep->connect.data.base,
-					  ep->connect.data.phys_base);
-		else
-			ipa3_pipe_mem_free(ep->data_fifo_pipe_mem_ofst,
-					  ep->connect.data.size);
-	}
-
-	if (!ipa3_ctx->smmu_s1_bypass) {
-		base = ep->connect.desc.iova;
-		smmu_domain = ipa_get_smmu_domain();
-		if (smmu_domain != NULL) {
-			iommu_unmap(smmu_domain,
-				rounddown(base, PAGE_SIZE),
-				roundup(ep->connect.desc.size + base -
-					rounddown(base, PAGE_SIZE), PAGE_SIZE));
-		}
-	}
-
-	if (!ipa3_ctx->smmu_s1_bypass) {
-		base = ep->connect.data.iova;
-		smmu_domain = ipa_get_smmu_domain();
-		if (smmu_domain != NULL) {
-			iommu_unmap(smmu_domain,
-				rounddown(base, PAGE_SIZE),
-				roundup(ep->connect.data.size + base -
-					rounddown(base, PAGE_SIZE), PAGE_SIZE));
-		}
-	}
-
-	result = sps_free_endpoint(ep->ep_hdl);
-	if (result) {
-		IPAERR("SPS de-alloc EP failed.\n");
-		return -EPERM;
-	}
-
-	ipa3_delete_dflt_flt_rules(clnt_hdl);
-
-	/* If APPS flow control is not enabled, send a message to modem to
-	 * enable flow control honoring.
-	 */
-	if (!ipa3_ctx->tethered_flow_control && ep->qmi_request_sent) {
-		/* Send a message to modem to disable flow control honoring. */
-		req.request_id = clnt_hdl;
-		res = ipa3_qmi_disable_force_clear_datapath_send(&req);
-		if (res) {
-			IPADBG("disable_force_clear_datapath failed %d\n",
-				res);
-		}
-	}
-
-	spin_lock(&ipa3_ctx->disconnect_lock);
-	memset(&ipa3_ctx->ep[clnt_hdl], 0, sizeof(struct ipa3_ep_context));
-	spin_unlock(&ipa3_ctx->disconnect_lock);
-	IPA_ACTIVE_CLIENTS_DEC_EP(client_type);
-
-	IPADBG("client (ep: %d) disconnected\n", clnt_hdl);
-
-	return 0;
-}
-
-/**
-* ipa3_reset_endpoint() - reset an endpoint from BAM perspective
-* @clnt_hdl: [in] IPA client handle
-*
-* Returns:	0 on success, negative on failure
-*
-* Note:	Should not be called from atomic context
-*/
-int ipa3_reset_endpoint(u32 clnt_hdl)
-{
-	int res;
-	struct ipa3_ep_context *ep;
-
-	if (clnt_hdl >= ipa3_ctx->ipa_num_pipes) {
-		IPAERR("Bad parameters.\n");
-		return -EFAULT;
-	}
-	ep = &ipa3_ctx->ep[clnt_hdl];
-	IPA_ACTIVE_CLIENTS_INC_EP(ipa3_get_client_mapping(clnt_hdl));
-	res = sps_disconnect(ep->ep_hdl);
-	if (res) {
-		IPAERR("sps_disconnect() failed, res=%d.\n", res);
-		goto bail;
-	} else {
-		res = ipa3_sps_connect_safe(ep->ep_hdl, &ep->connect,
-			ep->client);
-		if (res) {
-			IPAERR("sps_connect() failed, res=%d.\n", res);
-			goto bail;
-		}
-	}
-
-bail:
-	IPA_ACTIVE_CLIENTS_DEC_EP(ipa3_get_client_mapping(clnt_hdl));
-	return res;
-}
-
-/**
- * ipa3_sps_connect_safe() - connect endpoint from BAM prespective
- * @h: [in] sps pipe handle
- * @connect: [in] sps connect parameters
- * @ipa_client: [in] ipa client handle representing the pipe
- *
- * This function connects a BAM pipe using SPS driver sps_connect() API
- * and by requesting uC interface to reset the pipe, avoids an IPA HW
- * limitation that does not allow resetting a BAM pipe during traffic in
- * IPA TX command queue.
- *
- * Returns:	0 on success, negative on failure
- */
-int ipa3_sps_connect_safe(struct sps_pipe *h, struct sps_connect *connect,
-			 enum ipa_client_type ipa_client)
-{
-	int res;
-
-	if (ipa3_ctx->ipa_hw_type > IPA_HW_v2_5 ||
-			ipa3_ctx->skip_uc_pipe_reset) {
-		IPADBG("uC pipe reset is not required\n");
-	} else {
-		res = ipa3_uc_reset_pipe(ipa_client);
-		if (res)
-			return res;
-	}
-	return sps_connect(h, connect);
-}
-
 static void ipa_chan_err_cb(struct gsi_chan_err_notify *notify)
 {
 	if (notify) {
@@ -1152,8 +535,7 @@
 	struct ipahal_reg_ep_cfg_status ep_status;
 	unsigned long gsi_dev_hdl;
 	enum gsi_status gsi_res;
-	struct ipa_gsi_ep_config gsi_ep_cfg;
-	struct ipa_gsi_ep_config *gsi_ep_cfg_ptr = &gsi_ep_cfg;
+	const struct ipa_gsi_ep_config *gsi_ep_cfg_ptr;
 
 	IPADBG("entry\n");
 	if (params == NULL || out_params == NULL ||
@@ -1227,8 +609,7 @@
 		goto write_evt_scratch_fail;
 	}
 
-	memset(gsi_ep_cfg_ptr, 0, sizeof(struct ipa_gsi_ep_config));
-	gsi_ep_cfg_ptr = ipa_get_gsi_ep_info(ipa_ep_idx);
+	gsi_ep_cfg_ptr = ipa3_get_gsi_ep_info(ep->client);
 	params->chan_params.evt_ring_hdl = ep->gsi_evt_ring_hdl;
 	params->chan_params.ch_id = gsi_ep_cfg_ptr->ipa_gsi_chan_num;
 	gsi_res = gsi_alloc_channel(&params->chan_params, gsi_dev_hdl,
@@ -1978,7 +1359,7 @@
  * @clnt_hdl:	[in] opaque client handle assigned by IPA to client
  *
  * Should be called by the driver of the peripheral that wants to remove
- * ep delay on IPA consumer ipe before disconnect in BAM-BAM mode. this api
+ * ep delay on IPA consumer ipe before disconnect in non GPI mode. this api
  * expects caller to take responsibility to free any needed headers, routing
  * and filtering tables and rules as needed.
  *
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_dma.c b/drivers/platform/msm/ipa/ipa_v3/ipa_dma.c
index 961ce13..f6bd162 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_dma.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_dma.c
@@ -25,10 +25,6 @@
 #define IPA_DMA_POLLING_MAX_SLEEP_RX 1050
 #define IPA_DMA_SYS_DESC_MAX_FIFO_SZ 0x7FF8
 #define IPA_DMA_MAX_PKT_SZ 0xFFFF
-#define IPA_DMA_MAX_PENDING_SYNC (IPA_SYS_DESC_FIFO_SZ / \
-	sizeof(struct sps_iovec) - 1)
-#define IPA_DMA_MAX_PENDING_ASYNC (IPA_DMA_SYS_DESC_MAX_FIFO_SZ / \
-	sizeof(struct sps_iovec) - 1)
 
 #define IPADMA_DRV_NAME "ipa_dma"
 
@@ -361,7 +357,7 @@
  *		-EINVAL: invalid params
  *		-EPERM: operation not permitted as ipa_dma isn't enable or
  *			initialized
- *		-SPS_ERROR: on sps faliures
+ *		-gsi_status : on GSI failures
  *		-EFAULT: other
  */
 int ipa3_dma_sync_memcpy(u64 dest, u64 src, int len)
@@ -371,7 +367,6 @@
 	int i = 0;
 	struct ipa3_sys_context *cons_sys;
 	struct ipa3_sys_context *prod_sys;
-	struct sps_iovec iov;
 	struct ipa3_dma_xfer_wrapper *xfer_descr = NULL;
 	struct ipa3_dma_xfer_wrapper *head_descr = NULL;
 	struct gsi_xfer_elem xfer_elem;
@@ -394,12 +389,6 @@
 		IPADMA_ERR("invalid len, %d\n", len);
 		return	-EINVAL;
 	}
-	if (ipa3_ctx->transport_prototype != IPA_TRANSPORT_TYPE_GSI) {
-		if (((u32)src != src) || ((u32)dest != dest)) {
-			IPADMA_ERR("Bad addr, only 32b addr supported for BAM");
-			return -EINVAL;
-		}
-	}
 	spin_lock_irqsave(&ipa3_dma_ctx->pending_lock, flags);
 	if (!ipa3_dma_ctx->is_enabled) {
 		IPADMA_ERR("can't memcpy, IPADMA isn't enabled\n");
@@ -408,14 +397,6 @@
 	}
 	atomic_inc(&ipa3_dma_ctx->sync_memcpy_pending_cnt);
 	spin_unlock_irqrestore(&ipa3_dma_ctx->pending_lock, flags);
-	if (ipa3_ctx->transport_prototype == IPA_TRANSPORT_TYPE_SPS) {
-		if (atomic_read(&ipa3_dma_ctx->sync_memcpy_pending_cnt) >=
-				IPA_DMA_MAX_PENDING_SYNC) {
-			atomic_dec(&ipa3_dma_ctx->sync_memcpy_pending_cnt);
-			IPADMA_ERR("Reached pending requests limit\n");
-			return -EFAULT;
-		}
-	}
 
 	ep_idx = ipa3_get_ep_mapping(IPA_CLIENT_MEMCPY_DMA_SYNC_CONS);
 	if (-1 == ep_idx) {
@@ -448,46 +429,31 @@
 	mutex_lock(&ipa3_dma_ctx->sync_lock);
 	list_add_tail(&xfer_descr->link, &cons_sys->head_desc_list);
 	cons_sys->len++;
-	if (ipa3_ctx->transport_prototype == IPA_TRANSPORT_TYPE_GSI) {
-		xfer_elem.addr = dest;
-		xfer_elem.len = len;
-		xfer_elem.type = GSI_XFER_ELEM_DATA;
-		xfer_elem.flags = GSI_XFER_FLAG_EOT;
-		xfer_elem.xfer_user_data = xfer_descr;
-		res = gsi_queue_xfer(cons_sys->ep->gsi_chan_hdl, 1,
-				&xfer_elem, true);
-		if (res) {
-			IPADMA_ERR(
-				"Failed: gsi_queue_xfer dest descr res:%d\n",
-				res);
-			goto fail_send;
-		}
-		xfer_elem.addr = src;
-		xfer_elem.len = len;
-		xfer_elem.type = GSI_XFER_ELEM_DATA;
-		xfer_elem.flags = GSI_XFER_FLAG_EOT;
-		xfer_elem.xfer_user_data = NULL;
-		res = gsi_queue_xfer(prod_sys->ep->gsi_chan_hdl, 1,
-				&xfer_elem, true);
-		if (res) {
-			IPADMA_ERR(
-				"Failed: gsi_queue_xfer src descr res:%d\n",
-				 res);
-			BUG();
-		}
-	} else {
-		res = sps_transfer_one(cons_sys->ep->ep_hdl, dest, len,
-			NULL, 0);
-		if (res) {
-			IPADMA_ERR("Failed: sps_transfer_one on dest descr\n");
-			goto fail_send;
-		}
-		res = sps_transfer_one(prod_sys->ep->ep_hdl, src, len,
-			NULL, SPS_IOVEC_FLAG_EOT);
-		if (res) {
-			IPADMA_ERR("Failed: sps_transfer_one on src descr\n");
-			BUG();
-		}
+	xfer_elem.addr = dest;
+	xfer_elem.len = len;
+	xfer_elem.type = GSI_XFER_ELEM_DATA;
+	xfer_elem.flags = GSI_XFER_FLAG_EOT;
+	xfer_elem.xfer_user_data = xfer_descr;
+	res = gsi_queue_xfer(cons_sys->ep->gsi_chan_hdl, 1,
+			&xfer_elem, true);
+	if (res) {
+		IPADMA_ERR(
+			"Failed: gsi_queue_xfer dest descr res:%d\n",
+			res);
+		goto fail_send;
+	}
+	xfer_elem.addr = src;
+	xfer_elem.len = len;
+	xfer_elem.type = GSI_XFER_ELEM_DATA;
+	xfer_elem.flags = GSI_XFER_FLAG_EOT;
+	xfer_elem.xfer_user_data = NULL;
+	res = gsi_queue_xfer(prod_sys->ep->gsi_chan_hdl, 1,
+			&xfer_elem, true);
+	if (res) {
+		IPADMA_ERR(
+			"Failed: gsi_queue_xfer src descr res:%d\n",
+			 res);
+		ipa_assert();
 	}
 	head_descr = list_first_entry(&cons_sys->head_desc_list,
 				struct ipa3_dma_xfer_wrapper, link);
@@ -505,37 +471,22 @@
 
 	do {
 		/* wait for transfer to complete */
-		if (ipa3_ctx->transport_prototype == IPA_TRANSPORT_TYPE_GSI) {
-			res = gsi_poll_channel(cons_sys->ep->gsi_chan_hdl,
-				&gsi_notify);
-			if (res == GSI_STATUS_SUCCESS)
-				stop_polling = true;
-			else if (res != GSI_STATUS_POLL_EMPTY)
-				IPADMA_ERR(
-					"Failed: gsi_poll_chanel, returned %d loop#:%d\n",
-					res, i);
-		} else {
-			res = sps_get_iovec(cons_sys->ep->ep_hdl, &iov);
-			if (res)
-				IPADMA_ERR(
-					"Failed: get_iovec, returned %d loop#:%d\n",
-					res, i);
-			if (iov.addr != 0)
-				stop_polling = true;
-		}
+		res = gsi_poll_channel(cons_sys->ep->gsi_chan_hdl,
+			&gsi_notify);
+		if (res == GSI_STATUS_SUCCESS)
+			stop_polling = true;
+		else if (res != GSI_STATUS_POLL_EMPTY)
+			IPADMA_ERR(
+				"Failed: gsi_poll_chanel, returned %d loop#:%d\n",
+				res, i);
 		usleep_range(IPA_DMA_POLLING_MIN_SLEEP_RX,
 			IPA_DMA_POLLING_MAX_SLEEP_RX);
 		i++;
 	} while (!stop_polling);
 
-	if (ipa3_ctx->transport_prototype == IPA_TRANSPORT_TYPE_GSI) {
-		BUG_ON(len != gsi_notify.bytes_xfered);
-		BUG_ON(dest != ((struct ipa3_dma_xfer_wrapper *)
-				(gsi_notify.xfer_user_data))->phys_addr_dest);
-	} else {
-		BUG_ON(dest != iov.addr);
-		BUG_ON(len != iov.size);
-	}
+	ipa_assert_on(len != gsi_notify.bytes_xfered);
+	ipa_assert_on(dest != ((struct ipa3_dma_xfer_wrapper *)
+			(gsi_notify.xfer_user_data))->phys_addr_dest);
 
 	mutex_lock(&ipa3_dma_ctx->sync_lock);
 	list_del(&head_descr->link);
@@ -582,7 +533,7 @@
  *		-EINVAL: invalid params
  *		-EPERM: operation not permitted as ipa_dma isn't enable or
  *			initialized
- *		-SPS_ERROR: on sps faliures
+ *		-gsi_status : on GSI failures
  *		-EFAULT: descr fifo is full.
  */
 int ipa3_dma_async_memcpy(u64 dest, u64 src, int len,
@@ -611,13 +562,6 @@
 		IPADMA_ERR("invalid len, %d\n", len);
 		return	-EINVAL;
 	}
-	if (ipa3_ctx->transport_prototype != IPA_TRANSPORT_TYPE_GSI) {
-		if (((u32)src != src) || ((u32)dest != dest)) {
-			IPADMA_ERR(
-				"Bad addr - only 32b addr supported for BAM");
-			return -EINVAL;
-		}
-	}
 	if (!user_cb) {
 		IPADMA_ERR("null pointer: user_cb\n");
 		return -EINVAL;
@@ -630,14 +574,6 @@
 	}
 	atomic_inc(&ipa3_dma_ctx->async_memcpy_pending_cnt);
 	spin_unlock_irqrestore(&ipa3_dma_ctx->pending_lock, flags);
-	if (ipa3_ctx->transport_prototype == IPA_TRANSPORT_TYPE_SPS) {
-		if (atomic_read(&ipa3_dma_ctx->async_memcpy_pending_cnt) >=
-				IPA_DMA_MAX_PENDING_ASYNC) {
-			atomic_dec(&ipa3_dma_ctx->async_memcpy_pending_cnt);
-			IPADMA_ERR("Reached pending requests limit\n");
-			return -EFAULT;
-		}
-	}
 
 	ep_idx = ipa3_get_ep_mapping(IPA_CLIENT_MEMCPY_DMA_ASYNC_CONS);
 	if (-1 == ep_idx) {
@@ -671,48 +607,32 @@
 	spin_lock_irqsave(&ipa3_dma_ctx->async_lock, flags);
 	list_add_tail(&xfer_descr->link, &cons_sys->head_desc_list);
 	cons_sys->len++;
-	if (ipa3_ctx->transport_prototype == IPA_TRANSPORT_TYPE_GSI) {
-		xfer_elem_cons.addr = dest;
-		xfer_elem_cons.len = len;
-		xfer_elem_cons.type = GSI_XFER_ELEM_DATA;
-		xfer_elem_cons.flags = GSI_XFER_FLAG_EOT;
-		xfer_elem_cons.xfer_user_data = xfer_descr;
-		xfer_elem_prod.addr = src;
-		xfer_elem_prod.len = len;
-		xfer_elem_prod.type = GSI_XFER_ELEM_DATA;
-		xfer_elem_prod.flags = GSI_XFER_FLAG_EOT;
-		xfer_elem_prod.xfer_user_data = NULL;
-		res = gsi_queue_xfer(cons_sys->ep->gsi_chan_hdl, 1,
-				&xfer_elem_cons, true);
-		if (res) {
-			IPADMA_ERR(
-				"Failed: gsi_queue_xfer on dest descr res: %d\n",
-				res);
-			goto fail_send;
-		}
-		res = gsi_queue_xfer(prod_sys->ep->gsi_chan_hdl, 1,
-				&xfer_elem_prod, true);
-		if (res) {
-			IPADMA_ERR(
-				"Failed: gsi_queue_xfer on src descr res: %d\n",
-				res);
-			BUG();
-			goto fail_send;
-		}
-	} else {
-		res = sps_transfer_one(cons_sys->ep->ep_hdl, dest, len,
-			xfer_descr, 0);
-		if (res) {
-			IPADMA_ERR("Failed: sps_transfer_one on dest descr\n");
-			goto fail_send;
-		}
-		res = sps_transfer_one(prod_sys->ep->ep_hdl, src, len,
-			NULL, SPS_IOVEC_FLAG_EOT);
-		if (res) {
-			IPADMA_ERR("Failed: sps_transfer_one on src descr\n");
-			BUG();
-			goto fail_send;
-		}
+	xfer_elem_cons.addr = dest;
+	xfer_elem_cons.len = len;
+	xfer_elem_cons.type = GSI_XFER_ELEM_DATA;
+	xfer_elem_cons.flags = GSI_XFER_FLAG_EOT;
+	xfer_elem_cons.xfer_user_data = xfer_descr;
+	xfer_elem_prod.addr = src;
+	xfer_elem_prod.len = len;
+	xfer_elem_prod.type = GSI_XFER_ELEM_DATA;
+	xfer_elem_prod.flags = GSI_XFER_FLAG_EOT;
+	xfer_elem_prod.xfer_user_data = NULL;
+	res = gsi_queue_xfer(cons_sys->ep->gsi_chan_hdl, 1,
+			&xfer_elem_cons, true);
+	if (res) {
+		IPADMA_ERR(
+			"Failed: gsi_queue_xfer on dest descr res: %d\n",
+			res);
+		goto fail_send;
+	}
+	res = gsi_queue_xfer(prod_sys->ep->gsi_chan_hdl, 1,
+			&xfer_elem_prod, true);
+	if (res) {
+		IPADMA_ERR(
+			"Failed: gsi_queue_xfer on src descr res: %d\n",
+			res);
+		ipa_assert();
+		goto fail_send;
 	}
 	spin_unlock_irqrestore(&ipa3_dma_ctx->async_lock, flags);
 	IPADMA_FUNC_EXIT();
@@ -832,9 +752,9 @@
 }
 
 /**
- * ipa3_dma_async_memcpy_notify_cb() -Callback function which will be called by
- * IPA driver after getting notify from SPS driver or poll mode on Rx operation
- * is completed (data was written to dest descriptor on async_cons ep).
+ * ipa3_dma_async_memcpy_notify_cb() - Callback function which will be called
+ * by IPA driver after getting notify on Rx operation is completed (data was
+ * written to dest descriptor on async_cons ep).
  *
  * @priv -not in use.
  * @evt - event name - IPA_RECIVE.
@@ -865,11 +785,6 @@
 	list_del(&xfer_descr_expected->link);
 	sys->len--;
 	spin_unlock_irqrestore(&ipa3_dma_ctx->async_lock, flags);
-	if (ipa3_ctx->transport_prototype != IPA_TRANSPORT_TYPE_GSI) {
-		BUG_ON(xfer_descr_expected->phys_addr_dest !=
-				mem_info->phys_base);
-		BUG_ON(xfer_descr_expected->len != mem_info->size);
-	}
 	atomic_inc(&ipa3_dma_ctx->total_async_memcpy);
 	atomic_dec(&ipa3_dma_ctx->async_memcpy_pending_cnt);
 	xfer_descr_expected->callback(xfer_descr_expected->user1);
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
index 34c7227..85cd468 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
@@ -70,13 +70,18 @@
 
 #define IPA_DEFAULT_SYS_YELLOW_WM 32
 
+/*
+ * The transport descriptor size was changed to GSI_CHAN_RE_SIZE_16B, but
+ * IPA users still use sps_iovec size as FIFO element size.
+ */
+#define IPA_FIFO_ELEMENT_SIZE 8
+
 static struct sk_buff *ipa3_get_skb_ipa_rx(unsigned int len, gfp_t flags);
 static void ipa3_replenish_wlan_rx_cache(struct ipa3_sys_context *sys);
 static void ipa3_replenish_rx_cache(struct ipa3_sys_context *sys);
 static void ipa3_replenish_rx_work_func(struct work_struct *work);
 static void ipa3_fast_replenish_rx_cache(struct ipa3_sys_context *sys);
 static void ipa3_wq_handle_rx(struct work_struct *work);
-static void ipa3_wq_handle_tx(struct work_struct *work);
 static void ipa3_wq_rx_common(struct ipa3_sys_context *sys, u32 size);
 static void ipa3_wlan_wq_rx_common(struct ipa3_sys_context *sys,
 				u32 size);
@@ -94,10 +99,8 @@
 static int ipa_populate_tag_field(struct ipa3_desc *desc,
 		struct ipa3_tx_pkt_wrapper *tx_pkt,
 		struct ipahal_imm_cmd_pyld **tag_pyld_ret);
-static int ipa_handle_rx_core_gsi(struct ipa3_sys_context *sys,
-	bool process_all, bool in_poll_state);
-static int ipa_handle_rx_core_sps(struct ipa3_sys_context *sys,
-	bool process_all, bool in_poll_state);
+static int ipa_poll_gsi_pkt(struct ipa3_sys_context *sys,
+	struct ipa_mem_buffer *mem_info);
 static unsigned long tag_to_pointer_wa(uint64_t tag);
 static uint64_t pointer_to_tag_wa(struct ipa3_tx_pkt_wrapper *tx_pkt);
 
@@ -142,22 +145,6 @@
 		if (tx_pkt->callback)
 			tx_pkt->callback(tx_pkt->user1, tx_pkt->user2);
 
-		if (ipa3_ctx->transport_prototype == IPA_TRANSPORT_TYPE_SPS
-			&& tx_pkt->cnt > 1
-			&& tx_pkt->cnt != IPA_LAST_DESC_CNT) {
-			if (tx_pkt->cnt == IPA_NUM_DESC_PER_SW_TX) {
-				dma_pool_free(ipa3_ctx->dma_pool,
-					tx_pkt->mult.base,
-					tx_pkt->mult.phys_base);
-			} else {
-				dma_unmap_single(ipa3_ctx->pdev,
-					tx_pkt->mult.phys_base,
-					tx_pkt->mult.size,
-					DMA_TO_DEVICE);
-				kfree(tx_pkt->mult.base);
-			}
-		}
-
 		kmem_cache_free(ipa3_ctx->tx_pkt_wrapper_cache, tx_pkt);
 		tx_pkt = next_pkt;
 	}
@@ -191,7 +178,6 @@
  *   the order for sent packet is the same as expected
  * - delete all the tx packet descriptors from the system
  *   pipe context (not needed anymore)
- * - return the tx buffer back to dma_pool
  */
 static void ipa3_wq_write_done(struct work_struct *work)
 {
@@ -204,118 +190,6 @@
 	ipa3_wq_write_done_common(sys, tx_pkt);
 }
 
-static int ipa3_handle_tx_core(struct ipa3_sys_context *sys, bool process_all,
-		bool in_poll_state)
-{
-	struct sps_iovec iov;
-	struct ipa3_tx_pkt_wrapper *tx_pkt_expected;
-	int ret;
-	int cnt = 0;
-
-	while ((in_poll_state ? atomic_read(&sys->curr_polling_state) :
-				!atomic_read(&sys->curr_polling_state))) {
-		if (cnt && !process_all)
-			break;
-		ret = sps_get_iovec(sys->ep->ep_hdl, &iov);
-		if (ret) {
-			IPAERR("sps_get_iovec failed %d\n", ret);
-			break;
-		}
-
-		if (iov.addr == 0)
-			break;
-
-		tx_pkt_expected = list_first_entry(&sys->head_desc_list,
-						   struct ipa3_tx_pkt_wrapper,
-						   link);
-		ipa3_wq_write_done_common(sys, tx_pkt_expected);
-		cnt++;
-	};
-
-	return cnt;
-}
-
-/**
- * ipa3_tx_switch_to_intr_mode() - Operate the Tx data path in interrupt mode
- */
-static void ipa3_tx_switch_to_intr_mode(struct ipa3_sys_context *sys)
-{
-	int ret;
-
-	if (!atomic_read(&sys->curr_polling_state)) {
-		IPAERR("already in intr mode\n");
-		goto fail;
-	}
-
-	if (ipa3_ctx->transport_prototype == IPA_TRANSPORT_TYPE_GSI) {
-		atomic_set(&sys->curr_polling_state, 0);
-		ipa3_dec_release_wakelock();
-		ret = gsi_config_channel_mode(sys->ep->gsi_chan_hdl,
-			GSI_CHAN_MODE_CALLBACK);
-		if (ret != GSI_STATUS_SUCCESS) {
-			IPAERR("Failed to switch to intr mode.\n");
-			goto fail;
-		}
-	} else {
-		ret = sps_get_config(sys->ep->ep_hdl, &sys->ep->connect);
-		if (ret) {
-			IPAERR("sps_get_config() failed %d\n", ret);
-			goto fail;
-		}
-		sys->event.options = SPS_O_EOT;
-		ret = sps_register_event(sys->ep->ep_hdl, &sys->event);
-		if (ret) {
-			IPAERR("sps_register_event() failed %d\n", ret);
-			goto fail;
-		}
-		sys->ep->connect.options =
-			SPS_O_AUTO_ENABLE | SPS_O_ACK_TRANSFERS | SPS_O_EOT;
-		ret = sps_set_config(sys->ep->ep_hdl, &sys->ep->connect);
-		if (ret) {
-			IPAERR("sps_set_config() failed %d\n", ret);
-			goto fail;
-		}
-		atomic_set(&sys->curr_polling_state, 0);
-		ipa3_handle_tx_core(sys, true, false);
-		ipa3_dec_release_wakelock();
-	}
-	return;
-
-fail:
-	queue_delayed_work(sys->wq, &sys->switch_to_intr_work,
-			msecs_to_jiffies(1));
-}
-
-static void ipa3_handle_tx(struct ipa3_sys_context *sys)
-{
-	int inactive_cycles = 0;
-	int cnt;
-
-	IPA_ACTIVE_CLIENTS_INC_SIMPLE();
-	do {
-		cnt = ipa3_handle_tx_core(sys, true, true);
-		if (cnt == 0) {
-			inactive_cycles++;
-			usleep_range(POLLING_MIN_SLEEP_TX,
-					POLLING_MAX_SLEEP_TX);
-		} else {
-			inactive_cycles = 0;
-		}
-	} while (inactive_cycles <= POLLING_INACTIVITY_TX);
-
-	ipa3_tx_switch_to_intr_mode(sys);
-	IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
-}
-
-static void ipa3_wq_handle_tx(struct work_struct *work)
-{
-	struct ipa3_sys_context *sys;
-
-	sys = container_of(work, struct ipa3_sys_context, work);
-
-	ipa3_handle_tx(sys);
-}
-
 /**
  * ipa3_send_one() - Send a single descriptor
  * @sys:	system pipe context
@@ -324,8 +198,8 @@
  *
  * - Allocate tx_packet wrapper
  * - transfer data to the IPA
- * - after the transfer was done the SPS will
- *   notify the sending user via ipa_sps_irq_comp_tx()
+ * - after the transfer was done the user will be notified via provided
+ *   callback
  *
  * Return codes: 0: success, -EFAULT: failure
  */
@@ -335,9 +209,7 @@
 	struct ipa3_tx_pkt_wrapper *tx_pkt;
 	struct gsi_xfer_elem gsi_xfer;
 	int result;
-	u16 sps_flags = SPS_IOVEC_FLAG_EOT;
 	dma_addr_t dma_address;
-	u16 len = 0;
 	u32 mem_flag = GFP_ATOMIC;
 
 	if (unlikely(!in_atomic))
@@ -373,32 +245,16 @@
 	tx_pkt->user1 = desc->user1;
 	tx_pkt->user2 = desc->user2;
 
-	if (ipa3_ctx->transport_prototype == IPA_TRANSPORT_TYPE_GSI) {
-		memset(&gsi_xfer, 0, sizeof(gsi_xfer));
-		gsi_xfer.addr = dma_address;
-		gsi_xfer.flags |= GSI_XFER_FLAG_EOT;
-		gsi_xfer.xfer_user_data = tx_pkt;
-		if (desc->type == IPA_IMM_CMD_DESC) {
-			gsi_xfer.len = desc->opcode;
-			gsi_xfer.type = GSI_XFER_ELEM_IMME_CMD;
-		} else {
-			gsi_xfer.len = desc->len;
-			gsi_xfer.type = GSI_XFER_ELEM_DATA;
-		}
+	memset(&gsi_xfer, 0, sizeof(gsi_xfer));
+	gsi_xfer.addr = dma_address;
+	gsi_xfer.flags |= GSI_XFER_FLAG_EOT;
+	gsi_xfer.xfer_user_data = tx_pkt;
+	if (desc->type == IPA_IMM_CMD_DESC) {
+		gsi_xfer.len = desc->opcode;
+		gsi_xfer.type = GSI_XFER_ELEM_IMME_CMD;
 	} else {
-		/*
-		 * Special treatment for immediate commands, where the
-		 * structure of the descriptor is different
-		 */
-		if (desc->type == IPA_IMM_CMD_DESC) {
-			sps_flags |= SPS_IOVEC_FLAG_IMME;
-			len = desc->opcode;
-			IPADBG_LOW("sending cmd=%d pyld_len=%d sps_flags=%x\n",
-					desc->opcode, desc->len, sps_flags);
-			IPA_DUMP_BUFF(desc->pyld, dma_address, desc->len);
-		} else {
-			len = desc->len;
-		}
+		gsi_xfer.len = desc->len;
+		gsi_xfer.type = GSI_XFER_ELEM_DATA;
 	}
 
 	INIT_WORK(&tx_pkt->work, ipa3_wq_write_done);
@@ -406,20 +262,11 @@
 	spin_lock_bh(&sys->spinlock);
 	list_add_tail(&tx_pkt->link, &sys->head_desc_list);
 
-	if (ipa3_ctx->transport_prototype == IPA_TRANSPORT_TYPE_GSI) {
-		result = gsi_queue_xfer(sys->ep->gsi_chan_hdl, 1,
-					&gsi_xfer, true);
-		if (result != GSI_STATUS_SUCCESS) {
-			IPAERR("GSI xfer failed.\n");
-			goto fail_transport_send;
-		}
-	} else {
-		result = sps_transfer_one(sys->ep->ep_hdl, dma_address,
-					len, tx_pkt, sps_flags);
-		if (result) {
-			IPAERR("sps_transfer_one failed rc=%d\n", result);
-			goto fail_transport_send;
-		}
+	result = gsi_queue_xfer(sys->ep->gsi_chan_hdl, 1,
+				&gsi_xfer, true);
+	if (result != GSI_STATUS_SUCCESS) {
+		IPAERR("GSI xfer failed.\n");
+		goto fail_transport_send;
 	}
 
 	spin_unlock_bh(&sys->spinlock);
@@ -443,14 +290,11 @@
  * @desc: packets to send (may be immediate command or data)
  * @in_atomic:  whether caller is in atomic context
  *
- * This function is used for system-to-bam connection.
- * - SPS driver expect struct sps_transfer which will contain all the data
- *   for a transaction
+ * This function is used for GPI connection.
  * - ipa3_tx_pkt_wrapper will be used for each ipa
  *   descriptor (allocated from wrappers cache)
  * - The wrapper struct will be configured for each ipa-desc payload and will
  *   contain information which will be later used by the user callbacks
- * - each transfer will be made by calling to sps_transfer()
  * - Each packet (command or data) that will be sent will also be saved in
  *   ipa3_sys_context for later check that all data was sent
  *
@@ -464,77 +308,36 @@
 	struct ipa3_tx_pkt_wrapper *tx_pkt, *tx_pkt_first;
 	struct ipahal_imm_cmd_pyld *tag_pyld_ret = NULL;
 	struct ipa3_tx_pkt_wrapper *next_pkt;
-	struct sps_transfer transfer = { 0 };
-	struct sps_iovec *iovec;
 	struct gsi_xfer_elem *gsi_xfer_elem_array = NULL;
-	dma_addr_t dma_addr;
 	int i = 0;
 	int j;
 	int result;
 	int fail_dma_wrap = 0;
-	uint size;
 	u32 mem_flag = GFP_ATOMIC;
-	int ipa_ep_idx;
-	struct ipa_gsi_ep_config *gsi_ep_cfg;
+	const struct ipa_gsi_ep_config *gsi_ep_cfg;
 
 	if (unlikely(!in_atomic))
 		mem_flag = GFP_KERNEL;
 
-	size = num_desc * sizeof(struct sps_iovec);
+	gsi_ep_cfg = ipa3_get_gsi_ep_info(sys->ep->client);
+	if (unlikely(!gsi_ep_cfg)) {
+		IPAERR("failed to get gsi EP config for client=%d\n",
+			sys->ep->client);
+		return -EFAULT;
+	}
+	if (unlikely(num_desc > gsi_ep_cfg->ipa_if_tlv)) {
+		IPAERR("Too many chained descriptors need=%d max=%d\n",
+			num_desc, gsi_ep_cfg->ipa_if_tlv);
+		WARN_ON(1);
+		return -EPERM;
+	}
 
-	if (ipa3_ctx->transport_prototype == IPA_TRANSPORT_TYPE_GSI) {
-		ipa_ep_idx = ipa3_get_ep_mapping(sys->ep->client);
-		if (unlikely(ipa_ep_idx < 0)) {
-			IPAERR("invalid ep_index of client = %d\n",
-				sys->ep->client);
-			return -EFAULT;
-		}
-		gsi_ep_cfg = ipa3_get_gsi_ep_info(ipa_ep_idx);
-		if (unlikely(!gsi_ep_cfg)) {
-			IPAERR("failed to get gsi EP config of ep_idx=%d\n",
-				ipa_ep_idx);
-			return -EFAULT;
-		}
-		if (unlikely(num_desc > gsi_ep_cfg->ipa_if_tlv)) {
-			IPAERR("Too many chained descriptors need=%d max=%d\n",
-				num_desc, gsi_ep_cfg->ipa_if_tlv);
-			WARN_ON(1);
-			return -EPERM;
-		}
-
-		gsi_xfer_elem_array =
-			kzalloc(num_desc * sizeof(struct gsi_xfer_elem),
-			mem_flag);
-		if (!gsi_xfer_elem_array) {
-			IPAERR("Failed to alloc mem for gsi xfer array.\n");
-			return -EFAULT;
-		}
-	} else {
-		if (num_desc == IPA_NUM_DESC_PER_SW_TX) {
-			transfer.iovec = dma_pool_alloc(ipa3_ctx->dma_pool,
-					mem_flag, &dma_addr);
-			if (!transfer.iovec) {
-				IPAERR("fail to alloc dma mem\n");
-				return -EFAULT;
-			}
-		} else {
-			transfer.iovec = kmalloc(size, mem_flag);
-			if (!transfer.iovec) {
-				IPAERR("fail to alloc mem for sps xfr buff ");
-				IPAERR("num_desc = %d size = %d\n",
-						num_desc, size);
-				return -EFAULT;
-			}
-			dma_addr  = dma_map_single(ipa3_ctx->pdev,
-					transfer.iovec, size, DMA_TO_DEVICE);
-			if (!dma_addr) {
-				IPAERR("dma_map_single failed\n");
-				kfree(transfer.iovec);
-				return -EFAULT;
-			}
-		}
-		transfer.iovec_phys = dma_addr;
-		transfer.iovec_count = num_desc;
+	gsi_xfer_elem_array =
+		kzalloc(num_desc * sizeof(struct gsi_xfer_elem),
+		mem_flag);
+	if (!gsi_xfer_elem_array) {
+		IPAERR("Failed to alloc mem for gsi xfer array.\n");
+		return -EFAULT;
 	}
 
 	spin_lock_bh(&sys->spinlock);
@@ -617,87 +420,41 @@
 
 		list_add_tail(&tx_pkt->link, &sys->head_desc_list);
 
-		if (ipa3_ctx->transport_prototype == IPA_TRANSPORT_TYPE_GSI) {
-			gsi_xfer_elem_array[i].addr = tx_pkt->mem.phys_base;
+		gsi_xfer_elem_array[i].addr = tx_pkt->mem.phys_base;
 
-			/*
-			 * Special treatment for immediate commands, where
-			 * the structure of the descriptor is different
-			 */
-			if (desc[i].type == IPA_IMM_CMD_DESC) {
-				gsi_xfer_elem_array[i].len = desc[i].opcode;
-				gsi_xfer_elem_array[i].type =
-					GSI_XFER_ELEM_IMME_CMD;
-			} else {
-				gsi_xfer_elem_array[i].len = desc[i].len;
-				gsi_xfer_elem_array[i].type =
-					GSI_XFER_ELEM_DATA;
-			}
-
-			if (i == (num_desc - 1)) {
-				gsi_xfer_elem_array[i].flags |=
-					GSI_XFER_FLAG_EOT;
-				gsi_xfer_elem_array[i].xfer_user_data =
-					tx_pkt_first;
-				/* "mark" the last desc */
-				tx_pkt->cnt = IPA_LAST_DESC_CNT;
-			} else
-				gsi_xfer_elem_array[i].flags |=
-					GSI_XFER_FLAG_CHAIN;
+		/*
+		 * Special treatment for immediate commands, where
+		 * the structure of the descriptor is different
+		 */
+		if (desc[i].type == IPA_IMM_CMD_DESC) {
+			gsi_xfer_elem_array[i].len = desc[i].opcode;
+			gsi_xfer_elem_array[i].type =
+				GSI_XFER_ELEM_IMME_CMD;
 		} else {
-			/*
-			 * first desc of set is "special" as it
-			 * holds the count and other info
-			 */
-			if (i == 0) {
-				transfer.user = tx_pkt;
-				tx_pkt->mult.phys_base = dma_addr;
-				tx_pkt->mult.base = transfer.iovec;
-				tx_pkt->mult.size = size;
-			}
-
-			iovec = &transfer.iovec[i];
-			iovec->flags = 0;
-			/*
-			 * Point the iovec to the buffer and
-			 */
-			iovec->addr = tx_pkt->mem.phys_base;
-			/*
-			 * Special treatment for immediate commands, where
-			 * the structure of the descriptor is different
-			 */
-			if (desc[i].type == IPA_IMM_CMD_DESC) {
-				iovec->size = desc[i].opcode;
-				iovec->flags |= SPS_IOVEC_FLAG_IMME;
-				IPA_DUMP_BUFF(desc[i].pyld,
-					tx_pkt->mem.phys_base, desc[i].len);
-			} else {
-				iovec->size = desc[i].len;
-			}
-
-			if (i == (num_desc - 1)) {
-				iovec->flags |= SPS_IOVEC_FLAG_EOT;
-				/* "mark" the last desc */
-				tx_pkt->cnt = IPA_LAST_DESC_CNT;
-			}
+			gsi_xfer_elem_array[i].len = desc[i].len;
+			gsi_xfer_elem_array[i].type =
+				GSI_XFER_ELEM_DATA;
 		}
+
+		if (i == (num_desc - 1)) {
+			gsi_xfer_elem_array[i].flags |=
+				GSI_XFER_FLAG_EOT;
+			gsi_xfer_elem_array[i].xfer_user_data =
+				tx_pkt_first;
+			/* "mark" the last desc */
+			tx_pkt->cnt = IPA_LAST_DESC_CNT;
+		} else
+			gsi_xfer_elem_array[i].flags |=
+				GSI_XFER_FLAG_CHAIN;
 	}
 
-	if (ipa3_ctx->transport_prototype == IPA_TRANSPORT_TYPE_GSI) {
-		result = gsi_queue_xfer(sys->ep->gsi_chan_hdl, num_desc,
-				gsi_xfer_elem_array, true);
-		if (result != GSI_STATUS_SUCCESS) {
-			IPAERR("GSI xfer failed.\n");
-			goto failure;
-		}
-		kfree(gsi_xfer_elem_array);
-	} else {
-		result = sps_transfer(sys->ep->ep_hdl, &transfer);
-		if (result) {
-			IPAERR("sps_transfer failed rc=%d\n", result);
-			goto failure;
-		}
+	result = gsi_queue_xfer(sys->ep->gsi_chan_hdl, num_desc,
+			gsi_xfer_elem_array, true);
+	if (result != GSI_STATUS_SUCCESS) {
+		IPAERR("GSI xfer failed.\n");
+		goto failure;
 	}
+	kfree(gsi_xfer_elem_array);
 
 	spin_unlock_bh(&sys->spinlock);
 	return 0;
@@ -725,28 +482,15 @@
 		if (fail_dma_wrap)
 			kmem_cache_free(ipa3_ctx->tx_pkt_wrapper_cache, tx_pkt);
 
-	if (ipa3_ctx->transport_prototype == IPA_TRANSPORT_TYPE_GSI) {
-		kfree(gsi_xfer_elem_array);
-	} else {
-		if (transfer.iovec_phys) {
-			if (num_desc == IPA_NUM_DESC_PER_SW_TX) {
-				dma_pool_free(ipa3_ctx->dma_pool,
-					transfer.iovec, transfer.iovec_phys);
-			} else {
-				dma_unmap_single(ipa3_ctx->pdev,
-					transfer.iovec_phys, size,
-					DMA_TO_DEVICE);
-				kfree(transfer.iovec);
-			}
-		}
-	}
+	kfree(gsi_xfer_elem_array);
+
 	spin_unlock_bh(&sys->spinlock);
 	return -EFAULT;
 }
 
 /**
  * ipa3_transport_irq_cmd_ack - callback function which will be called by
- * SPS/GSI driver after an immediate command is complete.
+ * the transport driver after an immediate command is complete.
  * @user1:	pointer to the descriptor of the transfer
  * @user2:
  *
@@ -768,7 +512,7 @@
 
 /**
  * ipa3_transport_irq_cmd_ack_free - callback function which will be
- * called by SPS/GSI driver after an immediate command is complete.
+ * called by the transport driver after an immediate command is complete.
  * This function will also free the completion object once it is done.
  * @tag_comp: pointer to the completion object
  * @ignored: parameter not used
@@ -942,77 +686,6 @@
 }
 
 /**
- * ipa3_sps_irq_tx_notify() - Callback function which will be called by
- * the SPS driver to start a Tx poll operation.
- * Called in an interrupt context.
- * @notify:	SPS driver supplied notification struct
- *
- * This function defer the work for this event to the tx workqueue.
- */
-static void ipa3_sps_irq_tx_notify(struct sps_event_notify *notify)
-{
-	struct ipa3_sys_context *sys = (struct ipa3_sys_context *)notify->user;
-	int ret;
-
-	IPADBG_LOW("event %d notified\n", notify->event_id);
-
-	switch (notify->event_id) {
-	case SPS_EVENT_EOT:
-		if (IPA_CLIENT_IS_APPS_CONS(sys->ep->client))
-			atomic_set(&ipa3_ctx->transport_pm.eot_activity, 1);
-		if (!atomic_read(&sys->curr_polling_state)) {
-			ret = sps_get_config(sys->ep->ep_hdl,
-					&sys->ep->connect);
-			if (ret) {
-				IPAERR("sps_get_config() failed %d\n", ret);
-				break;
-			}
-			sys->ep->connect.options = SPS_O_AUTO_ENABLE |
-				SPS_O_ACK_TRANSFERS | SPS_O_POLL;
-			ret = sps_set_config(sys->ep->ep_hdl,
-					&sys->ep->connect);
-			if (ret) {
-				IPAERR("sps_set_config() failed %d\n", ret);
-				break;
-			}
-			ipa3_inc_acquire_wakelock();
-			atomic_set(&sys->curr_polling_state, 1);
-			queue_work(sys->wq, &sys->work);
-		}
-		break;
-	default:
-		IPAERR("received unexpected event id %d\n", notify->event_id);
-	}
-}
-
-/**
- * ipa3_sps_irq_tx_no_aggr_notify() - Callback function which will be called by
- * the SPS driver after a Tx operation is complete.
- * Called in an interrupt context.
- * @notify:	SPS driver supplied notification struct
- *
- * This function defer the work for this event to the tx workqueue.
- * This event will be later handled by ipa_write_done.
- */
-static void ipa3_sps_irq_tx_no_aggr_notify(struct sps_event_notify *notify)
-{
-	struct ipa3_tx_pkt_wrapper *tx_pkt;
-
-	IPADBG_LOW("event %d notified\n", notify->event_id);
-
-	switch (notify->event_id) {
-	case SPS_EVENT_EOT:
-		tx_pkt = notify->data.transfer.user;
-		if (IPA_CLIENT_IS_APPS_CONS(tx_pkt->sys->ep->client))
-			atomic_set(&ipa3_ctx->transport_pm.eot_activity, 1);
-		queue_work(tx_pkt->sys->wq, &tx_pkt->work);
-		break;
-	default:
-		IPAERR("received unexpected event id %d\n", notify->event_id);
-	}
-}
-
-/**
  * ipa3_handle_rx_core() - The core functionality of packet reception. This
  * function is read from multiple code paths.
  *
@@ -1029,13 +702,28 @@
 static int ipa3_handle_rx_core(struct ipa3_sys_context *sys, bool process_all,
 		bool in_poll_state)
 {
-	int cnt;
+	int ret;
+	int cnt = 0;
+	struct ipa_mem_buffer mem_info = { 0 };
 
-	if (ipa3_ctx->transport_prototype == IPA_TRANSPORT_TYPE_GSI)
-		cnt = ipa_handle_rx_core_gsi(sys, process_all, in_poll_state);
-	else
-		cnt = ipa_handle_rx_core_sps(sys, process_all, in_poll_state);
+	while ((in_poll_state ? atomic_read(&sys->curr_polling_state) :
+		!atomic_read(&sys->curr_polling_state))) {
+		if (cnt && !process_all)
+			break;
 
+		ret = ipa_poll_gsi_pkt(sys, &mem_info);
+		if (ret)
+			break;
+
+		if (IPA_CLIENT_IS_MEMCPY_DMA_CONS(sys->ep->client))
+			ipa3_dma_memcpy_notify(sys, &mem_info);
+		else if (IPA_CLIENT_IS_WLAN_CONS(sys->ep->client))
+			ipa3_wlan_wq_rx_common(sys, mem_info.size);
+		else
+			ipa3_wq_rx_common(sys, mem_info.size);
+
+		++cnt;
+	}
 	return cnt;
 }
 
@@ -1046,50 +734,17 @@
 {
 	int ret;
 
-	if (ipa3_ctx->transport_prototype == IPA_TRANSPORT_TYPE_GSI) {
-		if (!atomic_read(&sys->curr_polling_state)) {
-			IPAERR("already in intr mode\n");
-			goto fail;
-		}
-		atomic_set(&sys->curr_polling_state, 0);
-		ipa3_dec_release_wakelock();
-		ret = gsi_config_channel_mode(sys->ep->gsi_chan_hdl,
-			GSI_CHAN_MODE_CALLBACK);
-		if (ret != GSI_STATUS_SUCCESS) {
-			IPAERR("Failed to switch to intr mode.\n");
-			goto fail;
-		}
-	} else {
-		ret = sps_get_config(sys->ep->ep_hdl, &sys->ep->connect);
-		if (ret) {
-			IPAERR("sps_get_config() failed %d\n", ret);
-			goto fail;
-		}
-		if (!atomic_read(&sys->curr_polling_state) &&
-			((sys->ep->connect.options & SPS_O_EOT) == SPS_O_EOT)) {
-			IPADBG("already in intr mode\n");
-			return;
-		}
-		if (!atomic_read(&sys->curr_polling_state)) {
-			IPAERR("already in intr mode\n");
-			goto fail;
-		}
-		sys->event.options = SPS_O_EOT;
-		ret = sps_register_event(sys->ep->ep_hdl, &sys->event);
-		if (ret) {
-			IPAERR("sps_register_event() failed %d\n", ret);
-			goto fail;
-		}
-		sys->ep->connect.options =
-			SPS_O_AUTO_ENABLE | SPS_O_ACK_TRANSFERS | SPS_O_EOT;
-		ret = sps_set_config(sys->ep->ep_hdl, &sys->ep->connect);
-		if (ret) {
-			IPAERR("sps_set_config() failed %d\n", ret);
-			goto fail;
-		}
-		atomic_set(&sys->curr_polling_state, 0);
-		ipa3_handle_rx_core(sys, true, false);
-		ipa3_dec_release_wakelock();
+	if (!atomic_read(&sys->curr_polling_state)) {
+		IPAERR("already in intr mode\n");
+		goto fail;
+	}
+	atomic_set(&sys->curr_polling_state, 0);
+	ipa3_dec_release_wakelock();
+	ret = gsi_config_channel_mode(sys->ep->gsi_chan_hdl,
+		GSI_CHAN_MODE_CALLBACK);
+	if (ret != GSI_STATUS_SUCCESS) {
+		IPAERR("Failed to switch to intr mode.\n");
+		goto fail;
 	}
 	return;
 
@@ -1099,74 +754,6 @@
 }
 
 /**
- * ipa_rx_notify() - Callback function which is called by the SPS driver when a
- * a packet is received
- * @notify:	SPS driver supplied notification information
- *
- * Called in an interrupt context, therefore the majority of the work is
- * deffered using a work queue.
- *
- * After receiving a packet, the driver goes to polling mode and keeps pulling
- * packets until the rx buffer is empty, then it goes back to interrupt mode.
- * This comes to prevent the CPU from handling too many interrupts when the
- * throughput is high.
- */
-static void ipa3_sps_irq_rx_notify(struct sps_event_notify *notify)
-{
-	struct ipa3_sys_context *sys = (struct ipa3_sys_context *)notify->user;
-	int ret;
-
-	IPADBG_LOW("event %d notified\n", notify->event_id);
-
-	switch (notify->event_id) {
-	case SPS_EVENT_EOT:
-		if (IPA_CLIENT_IS_APPS_CONS(sys->ep->client))
-			atomic_set(&ipa3_ctx->transport_pm.eot_activity, 1);
-		if (!atomic_read(&sys->curr_polling_state)) {
-			sys->ep->eot_in_poll_err++;
-			break;
-		}
-
-		ret = sps_get_config(sys->ep->ep_hdl,
-							 &sys->ep->connect);
-		if (ret) {
-			IPAERR("sps_get_config() failed %d\n", ret);
-			break;
-		}
-		sys->ep->connect.options = SPS_O_AUTO_ENABLE |
-			  SPS_O_ACK_TRANSFERS | SPS_O_POLL;
-		ret = sps_set_config(sys->ep->ep_hdl,
-							 &sys->ep->connect);
-		if (ret) {
-			IPAERR("sps_set_config() failed %d\n", ret);
-			break;
-		}
-		ipa3_inc_acquire_wakelock();
-		atomic_set(&sys->curr_polling_state, 1);
-		trace_intr_to_poll3(sys->ep->client);
-		queue_work(sys->wq, &sys->work);
-		break;
-	default:
-		IPAERR("received unexpected event id %d\n", notify->event_id);
-	}
-}
-
-/**
- * switch_to_intr_tx_work_func() - Wrapper function to move from polling
- *	to interrupt mode
- * @work: work struct
- */
-void ipa3_switch_to_intr_tx_work_func(struct work_struct *work)
-{
-	struct delayed_work *dwork;
-	struct ipa3_sys_context *sys;
-
-	dwork = container_of(work, struct delayed_work, work);
-	sys = container_of(dwork, struct ipa3_sys_context, switch_to_intr_work);
-	ipa3_handle_tx(sys);
-}
-
-/**
  * ipa3_handle_rx() - handle packet reception. This function is executed in the
  * context of a work queue.
  * @work: work struct needed by the work queue
@@ -1220,18 +807,15 @@
 }
 
 /**
- * ipa3_setup_sys_pipe() - Setup an IPA end-point in system-BAM mode and perform
+ * ipa3_setup_sys_pipe() - Setup an IPA GPI pipe and perform
  * IPA EP configuration
- * @sys_in:	[in] input needed to setup BAM pipe and configure EP
+ * @sys_in:	[in] input needed to setup the pipe and configure EP
  * @clnt_hdl:	[out] client handle
  *
  *  - configure the end-point registers with the supplied
  *    parameters from the user.
- *  - call SPS APIs to create a system-to-bam connection with IPA.
+ *  - Creates a GPI connection with IPA.
  *  - allocate descriptor FIFO
- *  - register callback function(ipa3_sps_irq_rx_notify or
- *    ipa3_sps_irq_tx_notify - depends on client type) in case the driver is
- *    not configured to pulling mode
  *
  * Returns:	0 on success, negative on failure
  */
@@ -1240,9 +824,7 @@
 	struct ipa3_ep_context *ep;
 	int ipa_ep_idx;
 	int result = -EINVAL;
-	dma_addr_t dma_addr;
 	char buff[IPA_RESOURCE_NAME_MAX];
-	struct iommu_domain *smmu_domain;
 
 	if (sys_in == NULL || clnt_hdl == NULL) {
 		IPAERR("NULL args\n");
@@ -1348,7 +930,7 @@
 	ep->priv = sys_in->priv;
 	ep->keep_ipa_awake = sys_in->keep_ipa_awake;
 	atomic_set(&ep->avail_fifo_desc,
-		((sys_in->desc_fifo_sz/sizeof(struct sps_iovec))-1));
+		((sys_in->desc_fifo_sz / IPA_FIFO_ELEMENT_SIZE) - 1));
 
 	if (ep->status.status_en && IPA_CLIENT_IS_CONS(ep->client) &&
 	    ep->sys->status_stat == NULL) {
@@ -1374,88 +956,11 @@
 		IPADBG("skipping ep configuration\n");
 	}
 
-	if (ipa3_ctx->transport_prototype == IPA_TRANSPORT_TYPE_GSI) {
-		result = ipa_gsi_setup_channel(sys_in, ep);
-		if (result) {
-			IPAERR("Failed to setup GSI channel\n");
-			goto fail_gen2;
-		}
-	} else {
-		/* Default Config */
-		ep->ep_hdl = sps_alloc_endpoint();
-		if (ep->ep_hdl == NULL) {
-			IPAERR("SPS EP allocation failed.\n");
-			goto fail_gen2;
-		}
-
-		result = sps_get_config(ep->ep_hdl, &ep->connect);
-		if (result) {
-			IPAERR("fail to get config.\n");
-			goto fail_sps_cfg;
-		}
-
-		/* Specific Config */
-		if (IPA_CLIENT_IS_CONS(sys_in->client)) {
-			ep->connect.mode = SPS_MODE_SRC;
-			ep->connect.destination = SPS_DEV_HANDLE_MEM;
-			ep->connect.source = ipa3_ctx->bam_handle;
-			ep->connect.dest_pipe_index = ipa3_ctx->a5_pipe_index++;
-			ep->connect.src_pipe_index = ipa_ep_idx;
-		} else {
-			ep->connect.mode = SPS_MODE_DEST;
-			ep->connect.source = SPS_DEV_HANDLE_MEM;
-			ep->connect.destination = ipa3_ctx->bam_handle;
-			ep->connect.src_pipe_index = ipa3_ctx->a5_pipe_index++;
-			ep->connect.dest_pipe_index = ipa_ep_idx;
-		}
-
-		IPADBG("client:%d ep:%d",
-			sys_in->client, ipa_ep_idx);
-
-		IPADBG("dest_pipe_index:%d src_pipe_index:%d\n",
-			ep->connect.dest_pipe_index,
-			ep->connect.src_pipe_index);
-
-		ep->connect.options = ep->sys->sps_option;
-		ep->connect.desc.size = sys_in->desc_fifo_sz;
-		ep->connect.desc.base = dma_alloc_coherent(ipa3_ctx->pdev,
-				ep->connect.desc.size, &dma_addr, 0);
-		if (ipa3_ctx->smmu_s1_bypass) {
-			ep->connect.desc.phys_base = dma_addr;
-		} else {
-			ep->connect.desc.iova = dma_addr;
-			smmu_domain = ipa3_get_smmu_domain();
-			if (smmu_domain != NULL) {
-				ep->connect.desc.phys_base =
-					iommu_iova_to_phys(smmu_domain,
-							dma_addr);
-			}
-		}
-		if (ep->connect.desc.base == NULL) {
-			IPAERR("fail to get DMA desc memory.\n");
-			goto fail_sps_cfg;
-		}
-
-		ep->connect.event_thresh = IPA_EVENT_THRESHOLD;
-
-		result = ipa3_sps_connect_safe(ep->ep_hdl,
-				&ep->connect, sys_in->client);
-		if (result) {
-			IPAERR("sps_connect fails.\n");
-			goto fail_sps_connect;
-		}
-
-		ep->sys->event.options = SPS_O_EOT;
-		ep->sys->event.mode = SPS_TRIGGER_CALLBACK;
-		ep->sys->event.xfer_done = NULL;
-		ep->sys->event.user = ep->sys;
-		ep->sys->event.callback = ep->sys->sps_callback;
-		result = sps_register_event(ep->ep_hdl, &ep->sys->event);
-		if (result < 0) {
-			IPAERR("register event error %d\n", result);
-			goto fail_register_event;
-		}
-	}	/* end of sps config */
+	result = ipa_gsi_setup_channel(sys_in, ep);
+	if (result) {
+		IPAERR("Failed to setup GSI channel\n");
+		goto fail_gen2;
+	}
 
 	*clnt_hdl = ipa_ep_idx;
 
@@ -1506,14 +1011,6 @@
 
 	return 0;
 
-fail_register_event:
-	sps_disconnect(ep->ep_hdl);
-fail_sps_connect:
-	dma_free_coherent(ipa3_ctx->pdev, ep->connect.desc.size,
-			  ep->connect.desc.base,
-			  ep->connect.desc.phys_base);
-fail_sps_cfg:
-	sps_free_endpoint(ep->ep_hdl);
 fail_gen2:
 	destroy_workqueue(ep->sys->repl_wq);
 fail_wq2:
@@ -1528,7 +1025,7 @@
 }
 
 /**
- * ipa3_teardown_sys_pipe() - Teardown the system-BAM pipe and cleanup IPA EP
+ * ipa3_teardown_sys_pipe() - Teardown the GPI pipe and cleanup IPA EP
  * @clnt_hdl:	[in] the handle obtained from ipa3_setup_sys_pipe
  *
  * Returns:	0 on success, negative on failure
@@ -1573,57 +1070,49 @@
 	if (IPA_CLIENT_IS_CONS(ep->client))
 		cancel_delayed_work_sync(&ep->sys->replenish_rx_work);
 	flush_workqueue(ep->sys->wq);
-	if (ipa3_ctx->transport_prototype == IPA_TRANSPORT_TYPE_GSI) {
-		result = ipa3_stop_gsi_channel(clnt_hdl);
+	result = ipa3_stop_gsi_channel(clnt_hdl);
+	if (result != GSI_STATUS_SUCCESS) {
+		IPAERR("GSI stop chan err: %d.\n", result);
+		ipa_assert();
+		return result;
+	}
+	result = gsi_reset_channel(ep->gsi_chan_hdl);
+	if (result != GSI_STATUS_SUCCESS) {
+		IPAERR("Failed to reset chan: %d.\n", result);
+		ipa_assert();
+		return result;
+	}
+	dma_free_coherent(ipa3_ctx->pdev,
+		ep->gsi_mem_info.chan_ring_len,
+		ep->gsi_mem_info.chan_ring_base_vaddr,
+		ep->gsi_mem_info.chan_ring_base_addr);
+	result = gsi_dealloc_channel(ep->gsi_chan_hdl);
+	if (result != GSI_STATUS_SUCCESS) {
+		IPAERR("Failed to dealloc chan: %d.\n", result);
+		ipa_assert();
+		return result;
+	}
+
+	/* free event ring only when it is present */
+	if (ep->gsi_evt_ring_hdl != ~0) {
+		result = gsi_reset_evt_ring(ep->gsi_evt_ring_hdl);
 		if (result != GSI_STATUS_SUCCESS) {
-			IPAERR("GSI stop chan err: %d.\n", result);
-			BUG();
-			return result;
-		}
-		result = gsi_reset_channel(ep->gsi_chan_hdl);
-		if (result != GSI_STATUS_SUCCESS) {
-			IPAERR("Failed to reset chan: %d.\n", result);
+			IPAERR("Failed to reset evt ring: %d.\n",
+					result);
 			BUG();
 			return result;
 		}
 		dma_free_coherent(ipa3_ctx->pdev,
-			ep->gsi_mem_info.chan_ring_len,
-			ep->gsi_mem_info.chan_ring_base_vaddr,
-			ep->gsi_mem_info.chan_ring_base_addr);
-		result = gsi_dealloc_channel(ep->gsi_chan_hdl);
+			ep->gsi_mem_info.evt_ring_len,
+			ep->gsi_mem_info.evt_ring_base_vaddr,
+			ep->gsi_mem_info.evt_ring_base_addr);
+		result = gsi_dealloc_evt_ring(ep->gsi_evt_ring_hdl);
 		if (result != GSI_STATUS_SUCCESS) {
-			IPAERR("Failed to dealloc chan: %d.\n", result);
+			IPAERR("Failed to dealloc evt ring: %d.\n",
+					result);
 			BUG();
 			return result;
 		}
-
-		/* free event ring only when it is present */
-		if (ep->gsi_evt_ring_hdl != ~0) {
-			result = gsi_reset_evt_ring(ep->gsi_evt_ring_hdl);
-			if (result != GSI_STATUS_SUCCESS) {
-				IPAERR("Failed to reset evt ring: %d.\n",
-						result);
-				BUG();
-				return result;
-			}
-			dma_free_coherent(ipa3_ctx->pdev,
-				ep->gsi_mem_info.evt_ring_len,
-				ep->gsi_mem_info.evt_ring_base_vaddr,
-				ep->gsi_mem_info.evt_ring_base_addr);
-			result = gsi_dealloc_evt_ring(ep->gsi_evt_ring_hdl);
-			if (result != GSI_STATUS_SUCCESS) {
-				IPAERR("Failed to dealloc evt ring: %d.\n",
-						result);
-				BUG();
-				return result;
-			}
-		}
-	} else {
-		sps_disconnect(ep->ep_hdl);
-		dma_free_coherent(ipa3_ctx->pdev, ep->connect.desc.size,
-				  ep->connect.desc.base,
-				  ep->connect.desc.phys_base);
-		sps_free_endpoint(ep->ep_hdl);
 	}
 	if (ep->sys->repl_wq)
 		flush_workqueue(ep->sys->repl_wq);
@@ -1662,7 +1151,6 @@
  * @user2
  *
  * This notified callback is for the destination client.
- * This function is supplied in ipa3_connect.
  */
 static void ipa3_tx_comp_usr_notify_release(void *user1, int user2)
 {
@@ -1704,11 +1192,8 @@
  * (for A5_WLAN_AMPDU_PROD only one desciprtor will be sent),
  * the first descriptor will be used to inform the IPA hardware that
  * apps need to push data into the IPA (IP_PACKET_INIT immediate command).
- * Once this send was done from SPS point-of-view the IPA driver will
- * get notified by the supplied callback - ipa_sps_irq_tx_comp()
- *
- * ipa_sps_irq_tx_comp will call to the user supplied
- * callback (from ipa3_connect)
+ * Once this send was done from transport point-of-view the IPA driver will
+ * get notified by the supplied callback.
  *
  * Returns:	0 on success, negative on failure
  */
@@ -1723,7 +1208,7 @@
 	struct ipa3_sys_context *sys;
 	int src_ep_idx;
 	int num_frags, f;
-	struct ipa_gsi_ep_config *gsi_ep;
+	const struct ipa_gsi_ep_config *gsi_ep;
 
 	if (unlikely(!ipa3_ctx)) {
 		IPAERR("IPA3 driver was not initialized\n");
@@ -1777,7 +1262,7 @@
 	 * 2 descriptors are needed for IP_PACKET_INIT and TAG_STATUS.
 	 * 1 descriptor needed for the linear portion of skb.
 	 */
-	gsi_ep = ipa3_get_gsi_ep_info(src_ep_idx);
+	gsi_ep = ipa3_get_gsi_ep_info(ipa3_ctx->ep[src_ep_idx].client);
 	if (gsi_ep && (num_frags + 3 > gsi_ep->ipa_if_tlv)) {
 		if (skb_linearize(skb)) {
 			IPAERR("Failed to linear skb with %d frags\n",
@@ -2032,24 +1517,17 @@
 			rx_pkt->sys = sys;
 
 			list_add_tail(&rx_pkt->link, &sys->head_desc_list);
-			if (ipa3_ctx->transport_prototype ==
-					IPA_TRANSPORT_TYPE_GSI) {
-				memset(&gsi_xfer_elem_one, 0,
-					sizeof(gsi_xfer_elem_one));
-				gsi_xfer_elem_one.addr = rx_pkt->data.dma_addr;
-				gsi_xfer_elem_one.len = IPA_WLAN_RX_BUFF_SZ;
-				gsi_xfer_elem_one.flags |= GSI_XFER_FLAG_EOT;
-				gsi_xfer_elem_one.flags |= GSI_XFER_FLAG_EOB;
-				gsi_xfer_elem_one.type = GSI_XFER_ELEM_DATA;
-				gsi_xfer_elem_one.xfer_user_data = rx_pkt;
+			memset(&gsi_xfer_elem_one, 0,
+				sizeof(gsi_xfer_elem_one));
+			gsi_xfer_elem_one.addr = rx_pkt->data.dma_addr;
+			gsi_xfer_elem_one.len = IPA_WLAN_RX_BUFF_SZ;
+			gsi_xfer_elem_one.flags |= GSI_XFER_FLAG_EOT;
+			gsi_xfer_elem_one.flags |= GSI_XFER_FLAG_EOB;
+			gsi_xfer_elem_one.type = GSI_XFER_ELEM_DATA;
+			gsi_xfer_elem_one.xfer_user_data = rx_pkt;
 
-				ret = gsi_queue_xfer(sys->ep->gsi_chan_hdl, 1,
-					&gsi_xfer_elem_one, true);
-			} else {
-				ret = sps_transfer_one(sys->ep->ep_hdl,
-					rx_pkt->data.dma_addr,
-					IPA_WLAN_RX_BUFF_SZ, rx_pkt, 0);
-			}
+			ret = gsi_queue_xfer(sys->ep->gsi_chan_hdl, 1,
+				&gsi_xfer_elem_one, true);
 
 			if (ret) {
 				IPAERR("failed to provide buffer: %d\n", ret);
@@ -2176,7 +1654,6 @@
  *   - Fill the packets skb with data
  *   - Make the packet DMAable
  *   - Add the packet to the system pipe linked list
- *   - Initiate a SPS transfer so that SPS driver will use this packet later.
  */
 static void ipa3_replenish_rx_cache(struct ipa3_sys_context *sys)
 {
@@ -2220,33 +1697,21 @@
 		list_add_tail(&rx_pkt->link, &sys->head_desc_list);
 		rx_len_cached = ++sys->len;
 
-		if (ipa3_ctx->transport_prototype ==
-				IPA_TRANSPORT_TYPE_GSI) {
-			memset(&gsi_xfer_elem_one, 0,
-				sizeof(gsi_xfer_elem_one));
-			gsi_xfer_elem_one.addr = rx_pkt->data.dma_addr;
-			gsi_xfer_elem_one.len = sys->rx_buff_sz;
-			gsi_xfer_elem_one.flags |= GSI_XFER_FLAG_EOT;
-			gsi_xfer_elem_one.flags |= GSI_XFER_FLAG_EOB;
-			gsi_xfer_elem_one.type = GSI_XFER_ELEM_DATA;
-			gsi_xfer_elem_one.xfer_user_data = rx_pkt;
+		memset(&gsi_xfer_elem_one, 0,
+			sizeof(gsi_xfer_elem_one));
+		gsi_xfer_elem_one.addr = rx_pkt->data.dma_addr;
+		gsi_xfer_elem_one.len = sys->rx_buff_sz;
+		gsi_xfer_elem_one.flags |= GSI_XFER_FLAG_EOT;
+		gsi_xfer_elem_one.flags |= GSI_XFER_FLAG_EOB;
+		gsi_xfer_elem_one.type = GSI_XFER_ELEM_DATA;
+		gsi_xfer_elem_one.xfer_user_data = rx_pkt;
 
-			ret = gsi_queue_xfer(sys->ep->gsi_chan_hdl,
-					1, &gsi_xfer_elem_one, true);
-			if (ret != GSI_STATUS_SUCCESS) {
-				IPAERR("failed to provide buffer: %d\n",
-					ret);
-				goto fail_provide_rx_buffer;
-			}
-		} else {
-			ret = sps_transfer_one(sys->ep->ep_hdl,
-				rx_pkt->data.dma_addr, sys->rx_buff_sz,
-				rx_pkt, 0);
-
-			if (ret) {
-				IPAERR("sps_transfer_one failed %d\n", ret);
-				goto fail_provide_rx_buffer;
-			}
+		ret = gsi_queue_xfer(sys->ep->gsi_chan_hdl,
+				1, &gsi_xfer_elem_one, true);
+		if (ret != GSI_STATUS_SUCCESS) {
+			IPAERR("failed to provide buffer: %d\n",
+				ret);
+			goto fail_provide_rx_buffer;
 		}
 	}
 
@@ -2327,33 +1792,21 @@
 
 		list_add_tail(&rx_pkt->link, &sys->head_desc_list);
 		rx_len_cached = ++sys->len;
-		if (ipa3_ctx->transport_prototype ==
-				IPA_TRANSPORT_TYPE_GSI) {
-			memset(&gsi_xfer_elem_one, 0,
-				sizeof(gsi_xfer_elem_one));
-			gsi_xfer_elem_one.addr = rx_pkt->data.dma_addr;
-			gsi_xfer_elem_one.len = sys->rx_buff_sz;
-			gsi_xfer_elem_one.flags |= GSI_XFER_FLAG_EOT;
-			gsi_xfer_elem_one.flags |= GSI_XFER_FLAG_EOB;
-			gsi_xfer_elem_one.type = GSI_XFER_ELEM_DATA;
-			gsi_xfer_elem_one.xfer_user_data = rx_pkt;
+		memset(&gsi_xfer_elem_one, 0,
+			sizeof(gsi_xfer_elem_one));
+		gsi_xfer_elem_one.addr = rx_pkt->data.dma_addr;
+		gsi_xfer_elem_one.len = sys->rx_buff_sz;
+		gsi_xfer_elem_one.flags |= GSI_XFER_FLAG_EOT;
+		gsi_xfer_elem_one.flags |= GSI_XFER_FLAG_EOB;
+		gsi_xfer_elem_one.type = GSI_XFER_ELEM_DATA;
+		gsi_xfer_elem_one.xfer_user_data = rx_pkt;
 
-			ret = gsi_queue_xfer(sys->ep->gsi_chan_hdl,
-					1, &gsi_xfer_elem_one, true);
-			if (ret != GSI_STATUS_SUCCESS) {
-				IPAERR("failed to provide buffer: %d\n",
-					ret);
-				goto fail_provide_rx_buffer;
-			}
-		} else {
-			ret = sps_transfer_one(sys->ep->ep_hdl,
-				rx_pkt->data.dma_addr, sys->rx_buff_sz,
-				rx_pkt, 0);
-
-			if (ret) {
-				IPAERR("sps_transfer_one failed %d\n", ret);
-				goto fail_provide_rx_buffer;
-			}
+		ret = gsi_queue_xfer(sys->ep->gsi_chan_hdl,
+				1, &gsi_xfer_elem_one, true);
+		if (ret != GSI_STATUS_SUCCESS) {
+			IPAERR("failed to provide buffer: %d\n",
+				ret);
+			goto fail_provide_rx_buffer;
 		}
 	}
 
@@ -2393,34 +1846,21 @@
 		rx_pkt = sys->repl.cache[curr];
 		list_add_tail(&rx_pkt->link, &sys->head_desc_list);
 
-		if (ipa3_ctx->transport_prototype ==
-				IPA_TRANSPORT_TYPE_GSI) {
-			memset(&gsi_xfer_elem_one, 0,
-				sizeof(gsi_xfer_elem_one));
-			gsi_xfer_elem_one.addr = rx_pkt->data.dma_addr;
-			gsi_xfer_elem_one.len = sys->rx_buff_sz;
-			gsi_xfer_elem_one.flags |= GSI_XFER_FLAG_EOT;
-			gsi_xfer_elem_one.flags |= GSI_XFER_FLAG_EOB;
-			gsi_xfer_elem_one.type = GSI_XFER_ELEM_DATA;
-			gsi_xfer_elem_one.xfer_user_data = rx_pkt;
+		memset(&gsi_xfer_elem_one, 0,
+			sizeof(gsi_xfer_elem_one));
+		gsi_xfer_elem_one.addr = rx_pkt->data.dma_addr;
+		gsi_xfer_elem_one.len = sys->rx_buff_sz;
+		gsi_xfer_elem_one.flags |= GSI_XFER_FLAG_EOT;
+		gsi_xfer_elem_one.flags |= GSI_XFER_FLAG_EOB;
+		gsi_xfer_elem_one.type = GSI_XFER_ELEM_DATA;
+		gsi_xfer_elem_one.xfer_user_data = rx_pkt;
 
-			ret = gsi_queue_xfer(sys->ep->gsi_chan_hdl, 1,
-				&gsi_xfer_elem_one, true);
-			if (ret != GSI_STATUS_SUCCESS) {
-				IPAERR("failed to provide buffer: %d\n",
-					ret);
-				break;
-			}
-		} else {
-			ret = sps_transfer_one(sys->ep->ep_hdl,
-				rx_pkt->data.dma_addr, sys->rx_buff_sz,
-				rx_pkt, 0);
-
-			if (ret) {
-				IPAERR("sps_transfer_one failed %d\n", ret);
-				list_del(&rx_pkt->link);
-				break;
-			}
+		ret = gsi_queue_xfer(sys->ep->gsi_chan_hdl, 1,
+			&gsi_xfer_elem_one, true);
+		if (ret != GSI_STATUS_SUCCESS) {
+			IPAERR("failed to provide buffer: %d\n",
+				ret);
+			break;
 		}
 		rx_len_cached = ++sys->len;
 		curr = (curr + 1) % sys->repl.capacity;
@@ -3184,35 +2624,6 @@
 	ipa3_wq_rx_common(sys, 0);
 }
 
-/**
- * ipa3_sps_irq_rx_no_aggr_notify() - Callback function which will be called by
- * the SPS driver after a Rx operation is complete.
- * Called in an interrupt context.
- * @notify:	SPS driver supplied notification struct
- *
- * This function defer the work for this event to a workqueue.
- */
-void ipa3_sps_irq_rx_no_aggr_notify(struct sps_event_notify *notify)
-{
-	struct ipa3_rx_pkt_wrapper *rx_pkt;
-
-	switch (notify->event_id) {
-	case SPS_EVENT_EOT:
-		rx_pkt = notify->data.transfer.user;
-		if (IPA_CLIENT_IS_APPS_CONS(rx_pkt->sys->ep->client))
-			atomic_set(&ipa3_ctx->transport_pm.eot_activity, 1);
-		rx_pkt->len = notify->data.transfer.iovec.size;
-		IPADBG_LOW("event %d notified sys=%p len=%u\n",
-				notify->event_id,
-				notify->user, rx_pkt->len);
-		queue_work(rx_pkt->sys->wq, &rx_pkt->work);
-		break;
-	default:
-		IPAERR("received unexpected event id %d sys=%p\n",
-				notify->event_id, notify->user);
-	}
-}
-
 static int ipa3_odu_rx_pyld_hdlr(struct sk_buff *rx_skb,
 	struct ipa3_sys_context *sys)
 {
@@ -3237,32 +2648,20 @@
 {
 	if (in->client == IPA_CLIENT_APPS_CMD_PROD) {
 		sys->policy = IPA_POLICY_INTR_MODE;
-		sys->sps_option = (SPS_O_AUTO_ENABLE | SPS_O_EOT);
-		sys->sps_callback = ipa3_sps_irq_tx_no_aggr_notify;
 		return 0;
 	}
 
 	if (IPA_CLIENT_IS_MEMCPY_DMA_PROD(in->client)) {
 		sys->policy = IPA_POLICY_NOINTR_MODE;
-		sys->sps_option = SPS_O_AUTO_ENABLE;
-		sys->sps_callback = NULL;
 		return 0;
 	}
 
 	if (IPA_CLIENT_IS_PROD(in->client)) {
 		if (sys->ep->skip_ep_cfg) {
 			sys->policy = IPA_POLICY_INTR_POLL_MODE;
-			sys->sps_option = (SPS_O_AUTO_ENABLE|
-				SPS_O_EOT | SPS_O_ACK_TRANSFERS);
-			sys->sps_callback = ipa3_sps_irq_tx_notify;
-			INIT_WORK(&sys->work, ipa3_wq_handle_tx);
-			INIT_DELAYED_WORK(&sys->switch_to_intr_work,
-				ipa3_switch_to_intr_tx_work_func);
 			atomic_set(&sys->curr_polling_state, 0);
 		} else {
 			sys->policy = IPA_POLICY_NOINTR_MODE;
-			sys->sps_option = SPS_O_AUTO_ENABLE;
-			sys->sps_callback = NULL;
 			sys->ep->status.status_en = true;
 			sys->ep->status.status_ep = ipa3_get_ep_mapping(
 					IPA_CLIENT_APPS_LAN_CONS);
@@ -3272,9 +2671,6 @@
 		    in->client == IPA_CLIENT_APPS_WAN_CONS) {
 			sys->ep->status.status_en = true;
 			sys->policy = IPA_POLICY_INTR_POLL_MODE;
-			sys->sps_option = (SPS_O_AUTO_ENABLE | SPS_O_EOT
-					| SPS_O_ACK_TRANSFERS);
-			sys->sps_callback = ipa3_sps_irq_rx_notify;
 			INIT_WORK(&sys->work, ipa3_wq_handle_rx);
 			INIT_DELAYED_WORK(&sys->switch_to_intr_work,
 				ipa3_switch_to_intr_rx_work_func);
@@ -3370,9 +2766,6 @@
 				in->client);
 
 			sys->policy = IPA_POLICY_INTR_POLL_MODE;
-			sys->sps_option = (SPS_O_AUTO_ENABLE | SPS_O_EOT
-				| SPS_O_ACK_TRANSFERS);
-			sys->sps_callback = ipa3_sps_irq_rx_notify;
 			INIT_WORK(&sys->work, ipa3_wq_handle_rx);
 			INIT_DELAYED_WORK(&sys->switch_to_intr_work,
 				ipa3_switch_to_intr_rx_work_func);
@@ -3380,8 +2773,8 @@
 				ipa3_replenish_rx_work_func);
 			atomic_set(&sys->curr_polling_state, 0);
 			sys->rx_buff_sz = IPA_WLAN_RX_BUFF_SZ;
-			sys->rx_pool_sz = in->desc_fifo_sz/
-				sizeof(struct sps_iovec) - 1;
+			sys->rx_pool_sz = in->desc_fifo_sz /
+				IPA_FIFO_ELEMENT_SIZE - 1;
 			if (sys->rx_pool_sz > IPA_WLAN_RX_POOL_SZ)
 				sys->rx_pool_sz = IPA_WLAN_RX_POOL_SZ;
 			sys->pyld_hdlr = NULL;
@@ -3395,18 +2788,15 @@
 				in->client);
 
 			sys->policy = IPA_POLICY_INTR_POLL_MODE;
-			sys->sps_option = (SPS_O_AUTO_ENABLE | SPS_O_EOT
-				| SPS_O_ACK_TRANSFERS);
-			sys->sps_callback = ipa3_sps_irq_rx_notify;
 			INIT_WORK(&sys->work, ipa3_wq_handle_rx);
 			INIT_DELAYED_WORK(&sys->switch_to_intr_work,
-			ipa3_switch_to_intr_rx_work_func);
+				ipa3_switch_to_intr_rx_work_func);
 			INIT_DELAYED_WORK(&sys->replenish_rx_work,
 				ipa3_replenish_rx_work_func);
 			atomic_set(&sys->curr_polling_state, 0);
 			sys->rx_buff_sz = IPA_ODU_RX_BUFF_SZ;
 			sys->rx_pool_sz = in->desc_fifo_sz /
-				sizeof(struct sps_iovec) - 1;
+				IPA_FIFO_ELEMENT_SIZE - 1;
 			if (sys->rx_pool_sz > IPA_ODU_RX_POOL_SZ)
 				sys->rx_pool_sz = IPA_ODU_RX_POOL_SZ;
 			sys->pyld_hdlr = ipa3_odu_rx_pyld_hdlr;
@@ -3420,9 +2810,6 @@
 				in->client);
 
 			sys->policy = IPA_POLICY_INTR_POLL_MODE;
-			sys->sps_option = (SPS_O_AUTO_ENABLE | SPS_O_EOT
-					| SPS_O_ACK_TRANSFERS);
-			sys->sps_callback = ipa3_sps_irq_rx_notify;
 			INIT_WORK(&sys->work, ipa3_wq_handle_rx);
 			INIT_DELAYED_WORK(&sys->switch_to_intr_work,
 				ipa3_switch_to_intr_rx_work_func);
@@ -3432,8 +2819,6 @@
 				in->client);
 
 			sys->policy = IPA_POLICY_NOINTR_MODE;
-			sys->sps_option = SPS_O_AUTO_ENABLE |
-			SPS_O_ACK_TRANSFERS | SPS_O_POLL;
 		} else {
 			IPAERR("Need to install a RX pipe hdlr\n");
 			WARN_ON(1);
@@ -3507,13 +2892,11 @@
  * from WLAN1_PROD pipe to IPA HW
  *
  * The function will send data descriptors from WLAN1_PROD (one
- * at a time) using sps_transfer_one. Will set EOT flag for last
- * descriptor Once this send was done from SPS point-of-view the
- * IPA driver will get notified by the supplied callback -
- * ipa3_sps_irq_tx_no_aggr_notify()
+ * at a time). Will set EOT flag for last descriptor Once this send was done
+ * from transport point-of-view the IPA driver will get notified by the
+ * supplied callback - ipa_gsi_irq_tx_notify_cb()
  *
- * ipa3_sps_irq_tx_no_aggr_notify will call to the user supplied
- * callback (from ipa3_connect)
+ * ipa_gsi_irq_tx_notify_cb will call to the user supplied callback
  *
  * Returns:	0 on success, negative on failure
  */
@@ -3638,7 +3021,7 @@
 /* Functions added to support kernel tests */
 
 int ipa3_sys_setup(struct ipa_sys_connect_params *sys_in,
-			unsigned long *ipa_bam_or_gsi_hdl,
+			unsigned long *ipa_transport_hdl,
 			u32 *ipa_pipe_num, u32 *clnt_hdl, bool en_status)
 {
 	struct ipa3_ep_context *ep;
@@ -3650,7 +3033,7 @@
 		goto fail_gen;
 	}
 
-	if (ipa_bam_or_gsi_hdl == NULL || ipa_pipe_num == NULL) {
+	if (ipa_transport_hdl == NULL || ipa_pipe_num == NULL) {
 		IPAERR("NULL args\n");
 		goto fail_gen;
 	}
@@ -3735,10 +3118,7 @@
 	*clnt_hdl = ipa_ep_idx;
 
 	*ipa_pipe_num = ipa_ep_idx;
-	if (ipa3_ctx->transport_prototype == IPA_TRANSPORT_TYPE_GSI)
-		*ipa_bam_or_gsi_hdl = ipa3_ctx->gsi_dev_hdl;
-	else
-		*ipa_bam_or_gsi_hdl = ipa3_ctx->bam_handle;
+	*ipa_transport_hdl = ipa3_ctx->gsi_dev_hdl;
 
 	if (!ep->keep_ipa_awake)
 		IPA_ACTIVE_CLIENTS_DEC_EP(sys_in->client);
@@ -3958,7 +3338,7 @@
 	struct gsi_evt_ring_props gsi_evt_ring_props;
 	struct gsi_chan_props gsi_channel_props;
 	union __packed gsi_channel_scratch ch_scratch;
-	struct ipa_gsi_ep_config *gsi_ep_info;
+	const struct ipa_gsi_ep_config *gsi_ep_info;
 	dma_addr_t dma_addr;
 	dma_addr_t evt_dma_addr;
 	int result;
@@ -4021,9 +3401,10 @@
 		gsi_channel_props.max_re_expected = ep->sys->rx_pool_sz;
 	}
 
-	gsi_ep_info = ipa3_get_gsi_ep_info(ipa3_get_ep_mapping(ep->client));
+	gsi_ep_info = ipa3_get_gsi_ep_info(ep->client);
 	if (!gsi_ep_info) {
-		IPAERR("Invalid ep number\n");
+		IPAERR("Failed getting GSI EP info for client=%d\n",
+		       ep->client);
 		result = -EINVAL;
 		goto fail_get_gsi_ep_info;
 	} else
@@ -4181,83 +3562,6 @@
 	return ret;
 }
 
-static int ipa_handle_rx_core_gsi(struct ipa3_sys_context *sys,
-	bool process_all, bool in_poll_state)
-{
-	int ret;
-	int cnt = 0;
-	struct ipa_mem_buffer mem_info = {0};
-
-	while ((in_poll_state ? atomic_read(&sys->curr_polling_state) :
-			!atomic_read(&sys->curr_polling_state))) {
-		if (cnt && !process_all)
-			break;
-
-		ret = ipa_poll_gsi_pkt(sys, &mem_info);
-		if (ret)
-			break;
-
-		if (IPA_CLIENT_IS_MEMCPY_DMA_CONS(sys->ep->client))
-			ipa3_dma_memcpy_notify(sys, &mem_info);
-		else if (IPA_CLIENT_IS_WLAN_CONS(sys->ep->client))
-			ipa3_wlan_wq_rx_common(sys, mem_info.size);
-		else
-			ipa3_wq_rx_common(sys, mem_info.size);
-
-		cnt++;
-	}
-	return cnt;
-}
-
-static int ipa_poll_sps_pkt(struct ipa3_sys_context *sys,
-		struct ipa_mem_buffer *mem_info)
-{
-	int ret;
-	struct sps_iovec iov;
-
-	ret = sps_get_iovec(sys->ep->ep_hdl, &iov);
-	if (ret) {
-		IPAERR("sps_get_iovec failed %d\n", ret);
-		return ret;
-	}
-
-	if (iov.addr == 0)
-		return -EIO;
-
-	mem_info->phys_base = iov.addr;
-	mem_info->size = iov.size;
-	return 0;
-}
-
-static int ipa_handle_rx_core_sps(struct ipa3_sys_context *sys,
-	bool process_all, bool in_poll_state)
-{
-	int ret;
-	int cnt = 0;
-	struct ipa_mem_buffer mem_info = {0};
-
-	while ((in_poll_state ? atomic_read(&sys->curr_polling_state) :
-			!atomic_read(&sys->curr_polling_state))) {
-		if (cnt && !process_all)
-			break;
-
-		ret = ipa_poll_sps_pkt(sys, &mem_info);
-		if (ret)
-			break;
-
-		if (IPA_CLIENT_IS_MEMCPY_DMA_CONS(sys->ep->client))
-			ipa3_dma_memcpy_notify(sys, &mem_info);
-		else if (IPA_CLIENT_IS_WLAN_CONS(sys->ep->client))
-			ipa3_wlan_wq_rx_common(sys, mem_info.size);
-		else
-			ipa3_wq_rx_common(sys, mem_info.size);
-
-		cnt++;
-	}
-
-	return cnt;
-}
-
 /**
  * ipa3_rx_poll() - Poll the rx packets from IPA HW. This
  * function is exectued in the softirq context
@@ -4287,11 +3591,7 @@
 	while (cnt < weight &&
 		   atomic_read(&ep->sys->curr_polling_state)) {
 
-		if (ipa3_ctx->transport_prototype == IPA_TRANSPORT_TYPE_GSI)
-			ret = ipa_poll_gsi_pkt(ep->sys, &mem_info);
-		else
-			ret = ipa_poll_sps_pkt(ep->sys, &mem_info);
-
+		ret = ipa_poll_gsi_pkt(ep->sys, &mem_info);
 		if (ret)
 			break;
 
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
index acad448..9e72f67 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
@@ -23,7 +23,6 @@
 #include <linux/slab.h>
 #include <linux/ipa.h>
 #include <linux/ipa_usb.h>
-#include <linux/msm-sps.h>
 #include <asm/dma-iommu.h>
 #include <linux/iommu.h>
 #include <linux/platform_device.h>
@@ -129,15 +128,6 @@
 #define IPA_HDR_PROC_CTX_BIN1 1
 #define IPA_HDR_PROC_CTX_BIN_MAX 2
 
-#define IPA_EVENT_THRESHOLD 0x10
-
-/*
- * Due to ZLT issue with USB 3.0 core, IPA BAM threashold need to be set
- * to max packet size + 1. After setting the threshold, USB core
- * will not be notified on ZLTs
- */
-#define IPA_USB_EVENT_THRESHOLD 0x4001
-
 #define IPA_RX_POOL_CEIL 32
 #define IPA_RX_SKB_SIZE 1792
 
@@ -148,9 +138,6 @@
 #define IPA_CLIENT_IS_PROD(x) (x >= IPA_CLIENT_PROD && x < IPA_CLIENT_CONS)
 #define IPA_CLIENT_IS_CONS(x) (x >= IPA_CLIENT_CONS && x < IPA_CLIENT_MAX)
 
-#define IPA_PIPE_MEM_START_OFST_ALIGNMENT(start_ofst) \
-	(((start_ofst) + 127) & ~127)
-
 #define IPA_HDR_PROC_CTX_TABLE_ALIGNMENT_BYTE 8
 #define IPA_HDR_PROC_CTX_TABLE_ALIGNMENT(start_ofst) \
 	(((start_ofst) + IPA_HDR_PROC_CTX_TABLE_ALIGNMENT_BYTE - 1) & \
@@ -493,7 +480,6 @@
  * struct ipa3_ep_context - IPA end point context
  * @valid: flag indicating id EP context is valid
  * @client: EP client type
- * @ep_hdl: EP's client SPS handle
  * @gsi_chan_hdl: EP's GSI channel handle
  * @gsi_evt_ring_hdl: EP's GSI channel event ring handle
  * @gsi_mem_info: EP's GSI channel rings info
@@ -501,17 +487,10 @@
  * @cfg: EP cionfiguration
  * @dst_pipe_index: destination pipe index
  * @rt_tbl_idx: routing table index
- * @connect: SPS connect
  * @priv: user provided information which will forwarded once the user is
  *        notified for new data avail
  * @client_notify: user provided CB for EP events notification, the event is
  *                 data revived.
- * @desc_fifo_in_pipe_mem: flag indicating if descriptors FIFO uses pipe memory
- * @data_fifo_in_pipe_mem: flag indicating if data FIFO uses pipe memory
- * @desc_fifo_pipe_mem_ofst: descriptors FIFO pipe memory offset
- * @data_fifo_pipe_mem_ofst: data FIFO pipe memory offset
- * @desc_fifo_client_allocated: if descriptors FIFO was allocated by a client
- * @data_fifo_client_allocated: if data FIFO was allocated by a client
  * @skip_ep_cfg: boolean field that determines if EP should be configured
  *  by IPA driver
  * @keep_ipa_awake: when true, IPA will not be clock gated
@@ -523,7 +502,6 @@
 struct ipa3_ep_context {
 	int valid;
 	enum ipa_client_type client;
-	struct sps_pipe *ep_hdl;
 	unsigned long gsi_chan_hdl;
 	unsigned long gsi_evt_ring_hdl;
 	struct ipa_gsi_ep_mem_info gsi_mem_info;
@@ -536,16 +514,9 @@
 	struct ipahal_reg_ep_cfg_status status;
 	u32 dst_pipe_index;
 	u32 rt_tbl_idx;
-	struct sps_connect connect;
 	void *priv;
 	void (*client_notify)(void *priv, enum ipa_dp_evt_type evt,
 		       unsigned long data);
-	bool desc_fifo_in_pipe_mem;
-	bool data_fifo_in_pipe_mem;
-	u32 desc_fifo_pipe_mem_ofst;
-	u32 data_fifo_pipe_mem_ofst;
-	bool desc_fifo_client_allocated;
-	bool data_fifo_client_allocated;
 	atomic_t avail_fifo_desc;
 	u32 dflt_flt4_rule_hdl;
 	u32 dflt_flt6_rule_hdl;
@@ -610,18 +581,16 @@
 };
 
 /**
- * struct ipa3_sys_context - IPA endpoint context for system to BAM pipes
+ * struct ipa3_sys_context - IPA GPI pipes context
  * @head_desc_list: header descriptors list
  * @len: the size of the above list
  * @spinlock: protects the list and its size
- * @event: used to request CALLBACK mode from SPS driver
  * @ep: IPA EP context
  *
- * IPA context specific to the system-bam pipes a.k.a LAN IN/OUT and WAN
+ * IPA context specific to the GPI pipes a.k.a LAN IN/OUT and WAN
  */
 struct ipa3_sys_context {
 	u32 len;
-	struct sps_register_event event;
 	atomic_t curr_polling_state;
 	struct delayed_work switch_to_intr_work;
 	enum ipa3_sys_pipe_policy policy;
@@ -637,8 +606,6 @@
 	unsigned int len_partial;
 	bool drop_packet;
 	struct work_struct work;
-	void (*sps_callback)(struct sps_event_notify *notify);
-	enum sps_option sps_option;
 	struct delayed_work replenish_rx_work;
 	struct work_struct repl_work;
 	void (*repl_hdlr)(struct ipa3_sys_context *sys);
@@ -677,8 +644,6 @@
  * @user1: cookie1 for above callback
  * @user2: cookie2 for above callback
  * @sys: corresponding IPA sys context
- * @mult: valid only for first of a "multiple" transfer,
- * holds info for the "sps_transfer" buffer
  * @cnt: 1 for single transfers,
  * >1 and <0xFFFF for first of a "multiple" transfer,
  * 0xFFFF for last desc, 0 for rest of "multiple' transfer
@@ -696,7 +661,6 @@
 	void *user1;
 	int user2;
 	struct ipa3_sys_context *sys;
-	struct ipa_mem_buffer mult;
 	u32 cnt;
 	void *bounce;
 	bool no_unmap_dma;
@@ -977,15 +941,9 @@
 
 /**
  * struct ipa3_transport_pm - transport power management related members
- * @lock: lock for ensuring atomic operations
- * @res_granted: true if SPS requested IPA resource and IPA granted it
- * @res_rel_in_prog: true if releasing IPA resource is in progress
  * @transport_pm_mutex: Mutex to protect the transport_pm functionality.
  */
 struct ipa3_transport_pm {
-	spinlock_t lock;
-	bool res_granted;
-	bool res_rel_in_prog;
 	atomic_t dec_clients;
 	atomic_t eot_activity;
 	struct mutex transport_pm_mutex;
@@ -1034,13 +992,12 @@
  * @dev_num: device number
  * @dev: the dev_t of the device
  * @cdev: cdev of the device
- * @bam_handle: IPA driver's BAM handle
  * @ep: list of all end points
  * @skip_ep_cfg_shadow: state to update filter table correctly across
   power-save
  * @ep_flt_bitmap: End-points supporting filtering bitmap
  * @ep_flt_num: End-points supporting filtering number
- * @resume_on_connect: resume ep on ipa3_connect
+ * @resume_on_connect: resume ep on ipa connect
  * @flt_tbl: list of all IPA filter tables
  * @mode: IPA operating mode
  * @mmio: iomem
@@ -1084,13 +1041,10 @@
  *  gating IPA clocks
  * @transport_pm: transport power management related information
  * @disconnect_lock: protects LAN_CONS packet receive notification CB
- * @pipe_mem_pool: pipe memory pool
- * @dma_pool: special purpose DMA pool
  * @ipa3_active_clients: structure for reference counting connected IPA clients
  * @ipa_hw_type: type of IPA HW type (e.g. IPA 1.0, IPA 1.1 etc')
  * @ipa3_hw_mode: mode of IPA HW mode (e.g. Normal, Virtual or over PCIe)
  * @use_ipa_teth_bridge: use tethering bridge driver
- * @ipa_bam_remote_mode: ipa bam is in remote mode
  * @modem_cfg_emb_pipe_flt: modem configure embedded pipe filtering rules
  * @logbuf: ipc log buffer for high priority messages
  * @logbuf_low: ipc log buffer for low priority messages
@@ -1123,7 +1077,6 @@
 	dev_t dev_num;
 	struct device *dev;
 	struct cdev cdev;
-	unsigned long bam_handle;
 	struct ipa3_ep_context ep[IPA3_MAX_NUM_PIPES];
 	bool skip_ep_cfg_shadow[IPA3_MAX_NUM_PIPES];
 	u32 ep_flt_bitmap;
@@ -1170,8 +1123,6 @@
 	bool ip4_flt_tbl_nhash_lcl;
 	bool ip6_flt_tbl_hash_lcl;
 	bool ip6_flt_tbl_nhash_lcl;
-	struct gen_pool *pipe_mem_pool;
-	struct dma_pool *dma_pool;
 	struct ipa3_active_clients ipa3_active_clients;
 	struct ipa3_active_clients_log_ctx ipa3_active_clients_logging;
 	struct workqueue_struct *power_mgmt_wq;
@@ -1191,7 +1142,6 @@
 	enum ipa_hw_type ipa_hw_type;
 	enum ipa3_hw_mode ipa3_hw_mode;
 	bool use_ipa_teth_bridge;
-	bool ipa_bam_remote_mode;
 	bool modem_cfg_emb_pipe_flt;
 	bool ipa_wdi2;
 	bool use_64_bit_dma_mask;
@@ -1220,18 +1170,12 @@
 	u32 wan_rx_ring_size;
 	u32 lan_rx_ring_size;
 	bool skip_uc_pipe_reset;
-	enum ipa_transport_type transport_prototype;
 	unsigned long gsi_dev_hdl;
 	u32 ee;
 	bool apply_rg10_wa;
 	bool gsi_ch20_wa;
 	bool smmu_present;
 	bool smmu_s1_bypass;
-	unsigned long peer_bam_iova;
-	phys_addr_t peer_bam_pa;
-	u32 peer_bam_map_size;
-	unsigned long peer_bam_dev;
-	u32 peer_bam_map_cnt;
 	u32 wdi_map_cnt;
 	struct wakeup_source w_lock;
 	struct ipa3_wakelock_ref_cnt wakelock_ref_cnt;
@@ -1249,18 +1193,6 @@
 	struct ipa_tz_unlock_reg_info *ipa_tz_unlock_reg;
 };
 
-/**
- * enum ipa3_pipe_mem_type - IPA pipe memory type
- * @IPA_SPS_PIPE_MEM: Default, SPS dedicated pipe memory
- * @IPA_PRIVATE_MEM: IPA's private memory
- * @IPA_SYSTEM_MEM: System RAM, requires allocation
- */
-enum ipa3_pipe_mem_type {
-	IPA_SPS_PIPE_MEM = 0,
-	IPA_PRIVATE_MEM  = 1,
-	IPA_SYSTEM_MEM   = 2,
-};
-
 struct ipa3_plat_drv_res {
 	bool use_ipa_teth_bridge;
 	u32 ipa_mem_base;
@@ -1274,14 +1206,12 @@
 	enum ipa_hw_type ipa_hw_type;
 	enum ipa3_hw_mode ipa3_hw_mode;
 	u32 ee;
-	bool ipa_bam_remote_mode;
 	bool modem_cfg_emb_pipe_flt;
 	bool ipa_wdi2;
 	bool use_64_bit_dma_mask;
 	u32 wan_rx_ring_size;
 	u32 lan_rx_ring_size;
 	bool skip_uc_pipe_reset;
-	enum ipa_transport_type transport_prototype;
 	bool apply_rg10_wa;
 	bool gsi_ch20_wa;
 	bool tethered_flow_control;
@@ -1468,14 +1398,6 @@
 extern struct ipa3_context *ipa3_ctx;
 
 /* public APIs */
-/*
- * Connect / Disconnect
- */
-int ipa3_connect(const struct ipa_connect_params *in,
-		struct ipa_sps_params *sps,
-		u32 *clnt_hdl);
-int ipa3_disconnect(u32 clnt_hdl);
-
 /* Generic GSI channels functions */
 int ipa3_request_gsi_channel(struct ipa_request_gsi_channel_params *params,
 			     struct ipa_req_chan_out_params *out_params);
@@ -1506,11 +1428,6 @@
 int ipa3_xdci_resume(u32 ul_clnt_hdl, u32 dl_clnt_hdl, bool is_dpl);
 
 /*
- * Resume / Suspend
- */
-int ipa3_reset_endpoint(u32 clnt_hdl);
-
-/*
  * Remove ep delay
  */
 int ipa3_clear_endpoint_delay(u32 clnt_hdl);
@@ -1675,7 +1592,7 @@
 int ipa3_teardown_sys_pipe(u32 clnt_hdl);
 
 int ipa3_sys_setup(struct ipa_sys_connect_params *sys_in,
-	unsigned long *ipa_bam_hdl,
+	unsigned long *ipa_transport_hdl,
 	u32 *ipa_pipe_num, u32 *clnt_hdl, bool en_status);
 
 int ipa3_sys_teardown(u32 clnt_hdl);
@@ -1794,8 +1711,6 @@
 /*
  * Miscellaneous
  */
-void ipa3_bam_reg_dump(void);
-
 int ipa3_get_ep_mapping(enum ipa_client_type client);
 
 bool ipa3_is_ready(void);
@@ -1857,9 +1772,6 @@
 int ipa3_send_cmd_timeout(u16 num_desc, struct ipa3_desc *descr, u32 timeout);
 int ipa3_send_cmd(u16 num_desc, struct ipa3_desc *descr);
 int ipa3_cfg_filter(u32 disable);
-int ipa3_pipe_mem_init(u32 start_ofst, u32 size);
-int ipa3_pipe_mem_alloc(u32 *ofst, u32 size);
-int ipa3_pipe_mem_free(u32 ofst, u32 size);
 int ipa3_straddle_boundary(u32 start, u32 end, u32 boundary);
 struct ipa3_context *ipa3_get_ctx(void);
 void ipa3_enable_clks(void);
@@ -1956,15 +1868,11 @@
 void ipa3_q6_post_shutdown_cleanup(void);
 int ipa3_init_q6_smem(void);
 
-int ipa3_sps_connect_safe(struct sps_pipe *h, struct sps_connect *connect,
-			 enum ipa_client_type ipa_client);
-
 int ipa3_mhi_handle_ipa_config_req(struct ipa_config_req_msg_v01 *config_req);
 int ipa3_mhi_query_ch_info(enum ipa_client_type client,
 		struct gsi_chan_info *ch_info);
 
 int ipa3_uc_interface_init(void);
-int ipa3_uc_reset_pipe(enum ipa_client_type ipa_client);
 int ipa3_uc_is_gsi_channel_empty(enum ipa_client_type ipa_client);
 int ipa3_uc_state_check(void);
 int ipa3_uc_loaded_check(void);
@@ -1995,7 +1903,8 @@
 int ipa3_uc_mhi_print_stats(char *dbg_buff, int size);
 int ipa3_uc_memcpy(phys_addr_t dest, phys_addr_t src, int len);
 void ipa3_tag_destroy_imm(void *user1, int user2);
-struct ipa_gsi_ep_config *ipa3_get_gsi_ep_info(int ipa_ep_idx);
+const struct ipa_gsi_ep_config *ipa3_get_gsi_ep_info
+	(enum ipa_client_type client);
 void ipa3_uc_rg10_write_reg(enum ipahal_reg_name reg, u32 n, u32 val);
 
 u32 ipa3_get_num_pipes(void);
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_interrupts.c b/drivers/platform/msm/ipa/ipa_v3/ipa_interrupts.c
index 75711c0..e7f8acd 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_interrupts.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_interrupts.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -61,7 +61,7 @@
 	[IPA_PROC_ERR_IRQ]			= 13,
 	[IPA_TX_SUSPEND_IRQ]			= 14,
 	[IPA_TX_HOLB_DROP_IRQ]			= 15,
-	[IPA_BAM_GSI_IDLE_IRQ]			= 16,
+	[IPA_GSI_IDLE_IRQ]			= 16,
 };
 
 static void ipa3_interrupt_defer(struct work_struct *work);
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_mhi.c b/drivers/platform/msm/ipa/ipa_v3/ipa_mhi.c
index 9e2ffe7..f66e3a3 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_mhi.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_mhi.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015, 2017 The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2017 The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -197,14 +197,14 @@
 	struct gsi_chan_props ch_props;
 	union __packed gsi_channel_scratch ch_scratch;
 	struct ipa3_ep_context *ep;
-	struct ipa_gsi_ep_config *ep_cfg;
+	const struct ipa_gsi_ep_config *ep_cfg;
 
 	IPA_MHI_FUNC_ENTRY();
 
 	ep = &ipa3_ctx->ep[ipa_ep_idx];
 
 	msi = params->msi;
-	ep_cfg = ipa_get_gsi_ep_info(ipa_ep_idx);
+	ep_cfg = ipa3_get_gsi_ep_info(client);
 	if (!ep_cfg) {
 		IPA_MHI_ERR("Wrong parameter, ep_cfg is NULL\n");
 		return -EPERM;
@@ -332,7 +332,7 @@
 {
 	int res;
 	struct gsi_device_scratch gsi_scratch;
-	struct ipa_gsi_ep_config *gsi_ep_info;
+	const struct ipa_gsi_ep_config *gsi_ep_info;
 
 	IPA_MHI_FUNC_ENTRY();
 
@@ -342,8 +342,7 @@
 	}
 
 	/* Initialize IPA MHI engine */
-	gsi_ep_info = ipa_get_gsi_ep_info(
-		ipa_get_ep_mapping(IPA_CLIENT_MHI_PROD));
+	gsi_ep_info = ipa3_get_gsi_ep_info(IPA_CLIENT_MHI_PROD);
 	if (!gsi_ep_info) {
 		IPAERR("MHI PROD has no ep allocated\n");
 		ipa_assert();
@@ -497,12 +496,10 @@
 
 	ep = &ipa3_ctx->ep[clnt_hdl];
 
-	if (ipa3_ctx->transport_prototype == IPA_TRANSPORT_TYPE_GSI) {
-		res = gsi_dealloc_channel(ep->gsi_chan_hdl);
-		if (res) {
-			IPAERR("gsi_dealloc_channel failed %d\n", res);
-			goto fail_reset_channel;
-		}
+	res = gsi_dealloc_channel(ep->gsi_chan_hdl);
+	if (res) {
+		IPAERR("gsi_dealloc_channel failed %d\n", res);
+		goto fail_reset_channel;
 	}
 
 	ep->valid = 0;
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_nat.c b/drivers/platform/msm/ipa/ipa_v3/ipa_nat.c
index 4b22203..d98e6b4 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_nat.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_nat.c
@@ -24,6 +24,17 @@
 
 #define IPA_NAT_TEMP_MEM_SIZE 128
 
+enum nat_table_type {
+	IPA_NAT_BASE_TBL = 0,
+	IPA_NAT_EXPN_TBL = 1,
+	IPA_NAT_INDX_TBL = 2,
+	IPA_NAT_INDEX_EXPN_TBL = 3,
+};
+
+#define NAT_TABLE_ENTRY_SIZE_BYTE 32
+#define NAT_INTEX_TABLE_ENTRY_SIZE_BYTE 4
+
+
 static int ipa3_nat_vma_fault_remap(
 	 struct vm_area_struct *vma, struct vm_fault *vmf)
 {
@@ -575,6 +586,71 @@
 		goto bail;
 	}
 
+	for (cnt = 0; cnt < dma->entries; cnt++) {
+		if (dma->dma[cnt].table_index >= 1) {
+			IPAERR("Invalid table index %d\n",
+				dma->dma[cnt].table_index);
+			ret = -EPERM;
+			goto bail;
+		}
+
+		switch (dma->dma[cnt].base_addr) {
+		case IPA_NAT_BASE_TBL:
+			if (dma->dma[cnt].offset >=
+				(ipa3_ctx->nat_mem.size_base_tables + 1) *
+				NAT_TABLE_ENTRY_SIZE_BYTE) {
+				IPAERR("Invalid offset %d\n",
+					dma->dma[cnt].offset);
+				ret = -EPERM;
+				goto bail;
+			}
+
+			break;
+
+		case IPA_NAT_EXPN_TBL:
+			if (dma->dma[cnt].offset >=
+				ipa3_ctx->nat_mem.size_expansion_tables *
+				NAT_TABLE_ENTRY_SIZE_BYTE) {
+				IPAERR("Invalid offset %d\n",
+					dma->dma[cnt].offset);
+				ret = -EPERM;
+				goto bail;
+			}
+
+			break;
+
+		case IPA_NAT_INDX_TBL:
+			if (dma->dma[cnt].offset >=
+				(ipa3_ctx->nat_mem.size_base_tables + 1) *
+				NAT_INTEX_TABLE_ENTRY_SIZE_BYTE) {
+				IPAERR("Invalid offset %d\n",
+					dma->dma[cnt].offset);
+				ret = -EPERM;
+				goto bail;
+			}
+
+			break;
+
+		case IPA_NAT_INDEX_EXPN_TBL:
+			if (dma->dma[cnt].offset >=
+				ipa3_ctx->nat_mem.size_expansion_tables *
+				NAT_INTEX_TABLE_ENTRY_SIZE_BYTE) {
+				IPAERR("Invalid offset %d\n",
+					dma->dma[cnt].offset);
+				ret = -EPERM;
+				goto bail;
+			}
+
+			break;
+
+		default:
+			IPAERR("Invalid base_addr %d\n",
+				dma->dma[cnt].base_addr);
+			ret = -EPERM;
+			goto bail;
+		}
+	}
+
 	size = sizeof(struct ipa3_desc) * NUM_OF_DESC;
 	desc = kzalloc(size, GFP_KERNEL);
 	if (desc == NULL) {
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_uc.c b/drivers/platform/msm/ipa/ipa_v3/ipa_uc.c
index 6167301..f5ef141 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_uc.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_uc.c
@@ -89,7 +89,7 @@
 };
 
 /**
- * struct IpaHwResetPipeCmdData_t - Structure holding the parameters
+ * struct IpaHwMemCopyData_t - Structure holding the parameters
  * for IPA_CPU_2_HW_CMD_MEMCPY command.
  *
  * The parameters are passed as immediate params in the shared memory
@@ -102,24 +102,6 @@
 };
 
 /**
- * union IpaHwResetPipeCmdData_t - Structure holding the parameters
- * for IPA_CPU_2_HW_CMD_RESET_PIPE command.
- * @pipeNum : Pipe number to be reset
- * @direction : 1 - IPA Producer, 0 - IPA Consumer
- * @reserved_02_03 : Reserved
- *
- * The parameters are passed as immediate params in the shared memory
- */
-union IpaHwResetPipeCmdData_t {
-	struct IpaHwResetPipeCmdParams_t {
-		u8     pipeNum;
-		u8     direction;
-		u32    reserved_02_03;
-	} __packed params;
-	u32 raw32b;
-} __packed;
-
-/**
  * struct IpaHwRegWriteCmdData_t - holds the parameters for
  * IPA_CPU_2_HW_CMD_REG_WRITE command. Parameters are
  * sent as 64b immediate parameters.
@@ -790,67 +772,16 @@
 	IPADBG("uC handlers registered for feature %u\n", feature);
 }
 
-/**
- * ipa3_uc_reset_pipe() - reset a BAM pipe using the uC interface
- * @ipa_client: [in] ipa client handle representing the pipe
- *
- * The function uses the uC interface in order to issue a BAM
- * PIPE reset request. The uC makes sure there's no traffic in
- * the TX command queue before issuing the reset.
- *
- * Returns:	0 on success, negative on failure
- */
-int ipa3_uc_reset_pipe(enum ipa_client_type ipa_client)
-{
-	union IpaHwResetPipeCmdData_t cmd;
-	int ep_idx;
-	int ret;
-
-	ep_idx = ipa3_get_ep_mapping(ipa_client);
-	if (ep_idx == -1) {
-		IPAERR("Invalid IPA client\n");
-		return 0;
-	}
-
-	/*
-	 * If the uC interface has not been initialized yet,
-	 * continue with the sequence without resetting the
-	 * pipe.
-	 */
-	if (ipa3_uc_state_check()) {
-		IPADBG("uC interface will not be used to reset %s pipe %d\n",
-		       IPA_CLIENT_IS_PROD(ipa_client) ? "CONS" : "PROD",
-		       ep_idx);
-		return 0;
-	}
-
-	/*
-	 * IPA consumer = 0, IPA producer = 1.
-	 * IPA driver concept of PROD/CONS is the opposite of the
-	 * IPA HW concept. Therefore, IPA AP CLIENT PRODUCER = IPA CONSUMER,
-	 * and vice-versa.
-	 */
-	cmd.params.direction = (u8)(IPA_CLIENT_IS_PROD(ipa_client) ? 0 : 1);
-	cmd.params.pipeNum = (u8)ep_idx;
-
-	IPADBG("uC pipe reset on IPA %s pipe %d\n",
-	       IPA_CLIENT_IS_PROD(ipa_client) ? "CONS" : "PROD", ep_idx);
-
-	ret = ipa3_uc_send_cmd(cmd.raw32b, IPA_CPU_2_HW_CMD_RESET_PIPE, 0,
-			      false, 10*HZ);
-
-	return ret;
-}
-
 int ipa3_uc_is_gsi_channel_empty(enum ipa_client_type ipa_client)
 {
-	struct ipa_gsi_ep_config *gsi_ep_info;
+	const struct ipa_gsi_ep_config *gsi_ep_info;
 	union IpaHwChkChEmptyCmdData_t cmd;
 	int ret;
 
-	gsi_ep_info = ipa3_get_gsi_ep_info(ipa3_get_ep_mapping(ipa_client));
+	gsi_ep_info = ipa3_get_gsi_ep_info(ipa_client);
 	if (!gsi_ep_info) {
-		IPAERR("Invalid IPA ep index\n");
+		IPAERR("Failed getting GSI EP info for client=%d\n",
+		       ipa_client);
 		return 0;
 	}
 
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_uc_mhi.c b/drivers/platform/msm/ipa/ipa_v3/ipa_uc_mhi.c
index 7949d91..ac5f421 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_uc_mhi.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_uc_mhi.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015, 2016 The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2017 The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -68,7 +68,7 @@
  * Values that represent MHI related HW event to be sent to CPU.
  * @IPA_HW_2_CPU_EVENT_MHI_CHANNEL_ERROR: Event specify the device detected an
  *	error in an element from the transfer ring associated with the channel
- * @IPA_HW_2_CPU_EVENT_MHI_CHANNEL_WAKE_UP_REQUEST: Event specify a bam
+ * @IPA_HW_2_CPU_EVENT_MHI_CHANNEL_WAKE_UP_REQUEST: Event specify a transport
  *	interrupt was asserted when MHI engine is suspended
  */
 enum ipa_hw_2_cpu_mhi_events {
@@ -187,7 +187,7 @@
  *	value is within the range 0 to IPA_HW_MAX_CHANNEL_HANDLE
  * @contexArrayIndex: Unique index for channels, between 0 and 255. The index is
  *	used as an index in channel context array structures.
- * @bamPipeId: The BAM pipe number for pipe dedicated for this channel
+ * @bamPipeId: The IPA pipe number for pipe dedicated for this channel
  * @channelDirection: The direction of the channel as defined in the channel
  *	type field (CHTYPE) in the channel context data structure.
  * @reserved: reserved.
@@ -264,8 +264,8 @@
  * @state: The new channel state. In case state is not as requested this is
  *	error indication for the last command
  * @channelHandle: The channel identifier
- * @additonalParams: For stop: the number of pending bam descriptors currently
- *	queued
+ * @additonalParams: For stop: the number of pending transport descriptors
+ * currently queued
 */
 union IpaHwMhiChangeChannelStateResponseData_t {
 	struct IpaHwMhiChangeChannelStateResponseParams_t {
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c b/drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c
index d2c9ae1..8f87baf 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c
@@ -1345,33 +1345,6 @@
 	return result;
 }
 
-static int ipa3_wait_for_prod_empty(void)
-{
-	int i;
-	u32 rx_door_bell_value;
-
-	for (i = 0; i < IPA_UC_FINISH_MAX; i++) {
-		rx_door_bell_value = ipahal_read_reg_mn(
-			IPA_UC_MAILBOX_m_n,
-			IPA_HW_WDI_RX_MBOX_START_INDEX / 32,
-			IPA_HW_WDI_RX_MBOX_START_INDEX % 32);
-		IPADBG("(%d)rx_DB(%u)rp(%u),comp_wp(%u)\n",
-			i,
-			rx_door_bell_value,
-			*ipa3_ctx->uc_ctx.rdy_ring_rp_va,
-			*ipa3_ctx->uc_ctx.rdy_comp_ring_wp_va);
-		if (*ipa3_ctx->uc_ctx.rdy_ring_rp_va !=
-			*ipa3_ctx->uc_ctx.rdy_comp_ring_wp_va) {
-			usleep_range(IPA_UC_WAIT_MIN_SLEEP,
-				IPA_UC_WAII_MAX_SLEEP);
-		} else {
-			return 0;
-		}
-	}
-
-	return -ETIME;
-}
-
 /**
  * ipa3_disable_wdi_pipe() - WDI client disable
  * @clnt_hdl:	[in] opaque client handle assigned by IPA to client
@@ -1388,9 +1361,6 @@
 	struct ipa_ep_cfg_ctrl ep_cfg_ctrl;
 	u32 prod_hdl;
 
-	u32 source_pipe_bitmask = 0;
-	bool disable_force_clear = false;
-
 	if (clnt_hdl >= ipa3_ctx->ipa_num_pipes ||
 	    ipa3_ctx->ep[clnt_hdl].valid == 0) {
 		IPAERR("bad parm, %d\n", clnt_hdl);
@@ -1445,40 +1415,6 @@
 		usleep_range(IPA_UC_POLL_SLEEP_USEC * IPA_UC_POLL_SLEEP_USEC,
 			IPA_UC_POLL_SLEEP_USEC * IPA_UC_POLL_SLEEP_USEC);
 
-		/*
-		 * checking rdy_ring_rp_pa matches the
-		 * rdy_comp_ring_wp_pa on WDI2.0
-		 */
-		if (ipa3_ctx->ipa_wdi2) {
-			result = ipa3_wait_for_prod_empty();
-			if (result) {
-				IPADBG("prod not empty\n");
-				/*
-				 * In case ipa_uc still haven't processed all
-				 * pending descriptors, ask modem to drain
-				 */
-				source_pipe_bitmask = 1 <<
-					ipa3_get_ep_mapping(ep->client);
-				result = ipa3_enable_force_clear(clnt_hdl,
-					false, source_pipe_bitmask);
-				if (result) {
-					IPAERR("failed to force clear %d\n",
-						result);
-				} else {
-					disable_force_clear = true;
-				}
-
-				/*
-				 * In case ipa_uc still haven't processed all
-				 * pending descriptors, we have to assert
-				 */
-				result = ipa3_wait_for_prod_empty();
-				if (result) {
-					IPAERR("prod still not empty\n");
-					ipa_assert();
-				}
-			}
-		}
 	}
 
 	disable.params.ipa_pipe_number = clnt_hdl;
@@ -1497,8 +1433,6 @@
 		memset(&ep_cfg_ctrl, 0, sizeof(struct ipa_ep_cfg_ctrl));
 		ep_cfg_ctrl.ipa_ep_delay = true;
 		ipa3_cfg_ep_ctrl(clnt_hdl, &ep_cfg_ctrl);
-		if (disable_force_clear)
-			ipa3_disable_force_clear(clnt_hdl);
 	}
 	IPA_ACTIVE_CLIENTS_DEC_EP(ipa3_get_client_mapping(clnt_hdl));
 	ep->uc_offload_state &= ~IPA_WDI_ENABLED;
@@ -1584,6 +1518,9 @@
 	struct ipa3_ep_context *ep;
 	union IpaHwWdiCommonChCmdData_t suspend;
 	struct ipa_ep_cfg_ctrl ep_cfg_ctrl;
+	u32 source_pipe_bitmask = 0;
+	bool disable_force_clear = false;
+	struct ipahal_ep_cfg_ctrl_scnd ep_ctrl_scnd = { 0 };
 
 	if (clnt_hdl >= ipa3_ctx->ipa_num_pipes ||
 	    ipa3_ctx->ep[clnt_hdl].valid == 0) {
@@ -1608,6 +1545,31 @@
 	suspend.params.ipa_pipe_number = clnt_hdl;
 
 	if (IPA_CLIENT_IS_PROD(ep->client)) {
+		/*
+		 * For WDI 2.0 need to ensure pipe will be empty before suspend
+		 * as IPA uC will fail to suspend the pipe otherwise.
+		 */
+		if (ipa3_ctx->ipa_wdi2) {
+			source_pipe_bitmask = 1 <<
+					ipa3_get_ep_mapping(ep->client);
+			result = ipa3_enable_force_clear(clnt_hdl,
+				false, source_pipe_bitmask);
+			if (result) {
+				/*
+				 * assuming here modem SSR, AP can remove
+				 * the delay in this case
+				 */
+				IPAERR("failed to force clear %d\n", result);
+				IPAERR("remove delay from SCND reg\n");
+				ep_ctrl_scnd.endp_delay = false;
+				ipahal_write_reg_n_fields(
+					IPA_ENDP_INIT_CTRL_SCND_n, clnt_hdl,
+					&ep_ctrl_scnd);
+			} else {
+				disable_force_clear = true;
+			}
+		}
+
 		IPADBG("Post suspend event first for IPA Producer\n");
 		IPADBG("Client: %d clnt_hdl: %d\n", ep->client, clnt_hdl);
 		result = ipa3_uc_send_cmd(suspend.raw32b,
@@ -1652,6 +1614,9 @@
 		}
 	}
 
+	if (disable_force_clear)
+		ipa3_disable_force_clear(clnt_hdl);
+
 	ipa3_ctx->tag_process_before_gating = true;
 	IPA_ACTIVE_CLIENTS_DEC_EP(ipa3_get_client_mapping(clnt_hdl));
 	ep->uc_offload_state &= ~IPA_WDI_RESUMED;
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
index 4c1f2b35..ab9bbed 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
@@ -95,8 +95,9 @@
 #define QMB_MASTER_SELECT_PCIE (1)
 
 #define IPA_CLIENT_NOT_USED \
-	{IPA_EP_NOT_ALLOCATED, IPA_EP_NOT_ALLOCATED, false, \
-		IPA_DPS_HPS_SEQ_TYPE_INVALID, QMB_MASTER_SELECT_DDR}
+	{ IPA_EP_NOT_ALLOCATED, IPA_EP_NOT_ALLOCATED, false, \
+	IPA_DPS_HPS_SEQ_TYPE_INVALID, QMB_MASTER_SELECT_DDR, \
+		{ -1, -1, -1, -1, -1 } }
 
 /* Resource Group index*/
 #define IPA_v3_0_GROUP_UL		(0)
@@ -111,12 +112,12 @@
 #define IPA_v3_0_GROUP_Q6ZIP_ENGINE	IPA_v3_0_GROUP_UC_RX_Q
 #define IPA_v3_0_GROUP_MAX		(6)
 
-#define IPA_v3_5_1_GROUP_LWA_DL	(0)
-#define IPA_v3_5_1_GROUP_UL_DL		(1)
-#define IPA_v3_5_1_GROUP_DMA		(2)
-#define IPA_v3_5_1_GROUP_UC_RX_Q	(3)
-#define IPA_v3_5_1_SRC_GROUP_MAX	(4)
-#define IPA_v3_5_1_DST_GROUP_MAX	(3)
+#define IPA_v3_5_GROUP_LWA_DL		(0)
+#define IPA_v3_5_GROUP_UL_DL		(1)
+#define IPA_v3_5_GROUP_DMA		(2)
+#define IPA_v3_5_GROUP_UC_RX_Q		(3)
+#define IPA_v3_5_SRC_GROUP_MAX		(4)
+#define IPA_v3_5_DST_GROUP_MAX		(3)
 
 #define IPA_GROUP_MAX IPA_v3_0_GROUP_MAX
 
@@ -131,12 +132,12 @@
 	IPA_v3_0_RSRC_GRP_TYPE_SRC_ACK_ENTRIES,
 	IPA_v3_0_RSRC_GRP_TYPE_SRC_MAX,
 
-	IPA_v3_5_1_RSRC_GRP_TYPE_SRC_PKT_CONTEXTS = 0,
-	IPA_v3_5_1_RSRC_GRP_TYPE_SRS_DESCRIPTOR_LISTS,
-	IPA_v3_5_1_RSRC_GRP_TYPE_SRC_DESCRIPTOR_BUFF,
-	IPA_v3_5_1_RSRC_GRP_TYPE_SRC_HPS_DMARS,
-	IPA_v3_5_1_RSRC_GRP_TYPE_SRC_ACK_ENTRIES,
-	IPA_v3_5_1_RSRC_GRP_TYPE_SRC_MAX
+	IPA_v3_5_RSRC_GRP_TYPE_SRC_PKT_CONTEXTS = 0,
+	IPA_v3_5_RSRC_GRP_TYPE_SRS_DESCRIPTOR_LISTS,
+	IPA_v3_5_RSRC_GRP_TYPE_SRC_DESCRIPTOR_BUFF,
+	IPA_v3_5_RSRC_GRP_TYPE_SRC_HPS_DMARS,
+	IPA_v3_5_RSRC_GRP_TYPE_SRC_ACK_ENTRIES,
+	IPA_v3_5_RSRC_GRP_TYPE_SRC_MAX
 };
 
 #define IPA_RSRC_GRP_TYPE_SRC_MAX IPA_v3_0_RSRC_GRP_TYPE_SRC_MAX
@@ -147,9 +148,9 @@
 	IPA_v3_0_RSRC_GRP_TYPE_DST_DPS_DMARS,
 	IPA_v3_0_RSRC_GRP_TYPE_DST_MAX,
 
-	IPA_v3_5_1_RSRC_GRP_TYPE_DST_DATA_SECTORS = 0,
-	IPA_v3_5_1_RSRC_GRP_TYPE_DST_DPS_DMARS,
-	IPA_v3_5_1_RSRC_GRP_TYPE_DST_MAX,
+	IPA_v3_5_RSRC_GRP_TYPE_DST_DATA_SECTORS = 0,
+	IPA_v3_5_RSRC_GRP_TYPE_DST_DPS_DMARS,
+	IPA_v3_5_RSRC_GRP_TYPE_DST_MAX,
 };
 #define IPA_RSRC_GRP_TYPE_DST_MAX IPA_v3_0_RSRC_GRP_TYPE_DST_MAX
 
@@ -192,15 +193,15 @@
 	},
 	[IPA_3_5_1] = {
 		/* LWA_DL  UL_DL    not used  UC_RX_Q, other are invalid */
-		[IPA_v3_5_1_RSRC_GRP_TYPE_SRC_PKT_CONTEXTS] = {
+		[IPA_v3_5_RSRC_GRP_TYPE_SRC_PKT_CONTEXTS] = {
 		{1, 255}, {1, 255}, {0, 0}, {1, 255}, {0, 0}, {0, 0} },
-		[IPA_v3_5_1_RSRC_GRP_TYPE_SRS_DESCRIPTOR_LISTS] = {
+		[IPA_v3_5_RSRC_GRP_TYPE_SRS_DESCRIPTOR_LISTS] = {
 		{10, 10}, {10, 10}, {0, 0}, {8, 8}, {0, 0}, {0, 0} },
-		[IPA_v3_5_1_RSRC_GRP_TYPE_SRC_DESCRIPTOR_BUFF] = {
+		[IPA_v3_5_RSRC_GRP_TYPE_SRC_DESCRIPTOR_BUFF] = {
 		{12, 12}, {14, 14}, {0, 0}, {8, 8}, {0, 0}, {0, 0} },
-		[IPA_v3_5_1_RSRC_GRP_TYPE_SRC_HPS_DMARS] = {
+		[IPA_v3_5_RSRC_GRP_TYPE_SRC_HPS_DMARS] = {
 		{0, 255}, {0, 255}, {0, 255}, {0, 255},  {0, 0}, {0, 0} },
-		[IPA_v3_5_1_RSRC_GRP_TYPE_SRC_ACK_ENTRIES] = {
+		[IPA_v3_5_RSRC_GRP_TYPE_SRC_ACK_ENTRIES] = {
 		{14, 14}, {20, 20}, {0, 0}, {14, 14}, {0, 0}, {0, 0} },
 	}
 };
@@ -218,9 +219,9 @@
 	},
 	[IPA_3_5_1] = {
 			/*LWA_DL UL/DL/DPL not used, other are invalid */
-		[IPA_v3_5_1_RSRC_GRP_TYPE_DST_DATA_SECTORS] = {
+		[IPA_v3_5_RSRC_GRP_TYPE_DST_DATA_SECTORS] = {
 		{4, 4}, {4, 4}, {3, 3}, {0, 0}, {0, 0}, {0, 0} },
-		[IPA_v3_5_1_RSRC_GRP_TYPE_DST_DPS_DMARS] = {
+		[IPA_v3_5_RSRC_GRP_TYPE_DST_DPS_DMARS] = {
 		{2, 255}, {1, 255}, {1, 2}, {0, 0}, {0, 0}, {0, 0} },
 	}
 };
@@ -238,12 +239,19 @@
 		},
 };
 
+enum ipa_ees {
+	IPA_EE_AP = 0,
+	IPA_EE_Q6 = 1,
+	IPA_EE_UC = 3,
+};
+
 struct ipa_ep_configuration {
 	int pipe_num;
 	int group_num;
 	bool support_flt;
 	int sequencer_type;
 	u8 qmb_master_sel;
+	struct ipa_gsi_ep_config ipa_gsi_ep_info;
 };
 
 static const struct ipa_ep_configuration ipa3_ep_mapping
@@ -252,7 +260,8 @@
 	[IPA_3_0][IPA_CLIENT_WLAN1_PROD]          = {
 			10, IPA_v3_0_GROUP_UL, true,
 			IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP,
-			QMB_MASTER_SELECT_DDR},
+			QMB_MASTER_SELECT_DDR,
+			{ 10, 1, 8, 16, IPA_EE_UC } },
 	[IPA_3_0][IPA_CLIENT_HSIC2_PROD]          = IPA_CLIENT_NOT_USED,
 	[IPA_3_0][IPA_CLIENT_USB2_PROD]           = IPA_CLIENT_NOT_USED,
 	[IPA_3_0][IPA_CLIENT_HSIC3_PROD]          = IPA_CLIENT_NOT_USED,
@@ -263,188 +272,227 @@
 	[IPA_3_0][IPA_CLIENT_USB_PROD]            = {
 			1, IPA_v3_0_GROUP_UL, true,
 			IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP,
-			QMB_MASTER_SELECT_DDR},
-	[IPA_3_0][IPA_CLIENT_UC_USB_PROD]         = {
-			2, IPA_v3_0_GROUP_UL, true,
-			IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP,
-			QMB_MASTER_SELECT_DDR},
+			QMB_MASTER_SELECT_DDR,
+			{ 1, 3, 8, 16, IPA_EE_AP } },
+	[IPA_3_0][IPA_CLIENT_UC_USB_PROD]         = IPA_CLIENT_NOT_USED,
 	[IPA_3_0][IPA_CLIENT_A5_WLAN_AMPDU_PROD]  = IPA_CLIENT_NOT_USED,
 	[IPA_3_0][IPA_CLIENT_A2_EMBEDDED_PROD]    = IPA_CLIENT_NOT_USED,
 	[IPA_3_0][IPA_CLIENT_A2_TETHERED_PROD]    = IPA_CLIENT_NOT_USED,
 	[IPA_3_0][IPA_CLIENT_APPS_LAN_WAN_PROD]   = {
 			14, IPA_v3_0_GROUP_UL, true,
 			IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP,
-			QMB_MASTER_SELECT_DDR},
-	[IPA_3_0][IPA_CLIENT_APPS_CMD_PROD]
-			= {22, IPA_v3_0_GROUP_IMM_CMD, false,
+			QMB_MASTER_SELECT_DDR,
+			{ 14, 11, 8, 16, IPA_EE_AP } },
+	[IPA_3_0][IPA_CLIENT_APPS_CMD_PROD]	  = {
+			22, IPA_v3_0_GROUP_IMM_CMD, false,
 			IPA_DPS_HPS_SEQ_TYPE_DMA_ONLY,
-			QMB_MASTER_SELECT_DDR},
+			QMB_MASTER_SELECT_DDR,
+			{ 22, 6, 18, 28, IPA_EE_AP } },
 	[IPA_3_0][IPA_CLIENT_ODU_PROD]            = {
 			12, IPA_v3_0_GROUP_UL, true,
 			IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP,
-			QMB_MASTER_SELECT_DDR},
+			QMB_MASTER_SELECT_DDR,
+			{ 12, 9, 8, 16, IPA_EE_AP } },
 	[IPA_3_0][IPA_CLIENT_MHI_PROD]            = {
 			0, IPA_v3_0_GROUP_UL, true,
 			IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP,
-			QMB_MASTER_SELECT_PCIE},
+			QMB_MASTER_SELECT_PCIE,
+			{ 0, 0, 8, 16, IPA_EE_AP } },
 	[IPA_3_0][IPA_CLIENT_Q6_LAN_PROD]         = {
 			9, IPA_v3_0_GROUP_UL, false,
 			IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP,
-			QMB_MASTER_SELECT_DDR},
+			QMB_MASTER_SELECT_DDR,
+			{ 9, 4, 8, 12, IPA_EE_Q6 } },
 	[IPA_3_0][IPA_CLIENT_Q6_WAN_PROD]         = {
-			5, IPA_v3_0_GROUP_DL,
-			true, IPA_DPS_HPS_SEQ_TYPE_PKT_PROCESS_NO_DEC_UCP,
-			QMB_MASTER_SELECT_DDR},
-	[IPA_3_0][IPA_CLIENT_Q6_CMD_PROD]
-			= {6, IPA_v3_0_GROUP_IMM_CMD, false,
+			5, IPA_v3_0_GROUP_DL, true,
 			IPA_DPS_HPS_SEQ_TYPE_PKT_PROCESS_NO_DEC_UCP,
-			QMB_MASTER_SELECT_DDR},
-	[IPA_3_0][IPA_CLIENT_Q6_DECOMP_PROD]      = {7, IPA_v3_0_GROUP_Q6ZIP,
+			QMB_MASTER_SELECT_DDR,
+			{ 5, 0, 16, 32, IPA_EE_Q6 } },
+	[IPA_3_0][IPA_CLIENT_Q6_CMD_PROD] = {
+			6, IPA_v3_0_GROUP_IMM_CMD, false,
+			IPA_DPS_HPS_SEQ_TYPE_PKT_PROCESS_NO_DEC_UCP,
+			QMB_MASTER_SELECT_DDR,
+			{ 6, 1, 18, 28, IPA_EE_Q6 } },
+	[IPA_3_0][IPA_CLIENT_Q6_DECOMP_PROD]      = {
+			7, IPA_v3_0_GROUP_Q6ZIP,
 			false, IPA_DPS_HPS_SEQ_TYPE_PKT_PROCESS_NO_DEC_UCP,
-			QMB_MASTER_SELECT_DDR},
-	[IPA_3_0][IPA_CLIENT_Q6_DECOMP2_PROD]     = {8, IPA_v3_0_GROUP_Q6ZIP,
+			QMB_MASTER_SELECT_DDR,
+			{ 7, 2, 0, 0, IPA_EE_Q6 } },
+	[IPA_3_0][IPA_CLIENT_Q6_DECOMP2_PROD]     = {
+			8, IPA_v3_0_GROUP_Q6ZIP,
 			false, IPA_DPS_HPS_SEQ_TYPE_PKT_PROCESS_NO_DEC_UCP,
-			QMB_MASTER_SELECT_DDR},
-	[IPA_3_0][IPA_CLIENT_MEMCPY_DMA_SYNC_PROD]
-			= {12, IPA_v3_0_GROUP_DMA, false,
+			QMB_MASTER_SELECT_DDR,
+			{ 8, 3, 0, 0, IPA_EE_Q6 } },
+	[IPA_3_0][IPA_CLIENT_MEMCPY_DMA_SYNC_PROD] = {
+			12, IPA_v3_0_GROUP_DMA, false,
 			IPA_DPS_HPS_SEQ_TYPE_DMA_ONLY,
-			QMB_MASTER_SELECT_PCIE},
-	[IPA_3_0][IPA_CLIENT_MEMCPY_DMA_ASYNC_PROD]
-			= {13, IPA_v3_0_GROUP_DMA, false,
+			QMB_MASTER_SELECT_PCIE,
+			{ 12, 9, 8, 16, IPA_EE_AP } },
+	[IPA_3_0][IPA_CLIENT_MEMCPY_DMA_ASYNC_PROD] = {
+			13, IPA_v3_0_GROUP_DMA, false,
 			IPA_DPS_HPS_SEQ_TYPE_DMA_ONLY,
-			QMB_MASTER_SELECT_PCIE},
+			QMB_MASTER_SELECT_PCIE,
+			{ 13, 10, 8, 16, IPA_EE_AP } },
 	/* Only for test purpose */
 	[IPA_3_0][IPA_CLIENT_TEST_PROD]           = {
 			1, IPA_v3_0_GROUP_UL, true,
 			IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP,
-			QMB_MASTER_SELECT_DDR},
+			QMB_MASTER_SELECT_DDR,
+			{ 1, 3, 8, 16, IPA_EE_AP } },
 	[IPA_3_0][IPA_CLIENT_TEST1_PROD]          = {
 			1, IPA_v3_0_GROUP_UL, true,
 			IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP,
-			QMB_MASTER_SELECT_DDR},
+			QMB_MASTER_SELECT_DDR,
+			{ 1, 3, 8, 16, IPA_EE_AP } },
 	[IPA_3_0][IPA_CLIENT_TEST2_PROD]          = {
 			3, IPA_v3_0_GROUP_UL, true,
 			IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP,
-			QMB_MASTER_SELECT_DDR},
+			QMB_MASTER_SELECT_DDR,
+			{ 3, 5, 16, 32, IPA_EE_AP } },
 	[IPA_3_0][IPA_CLIENT_TEST3_PROD]          = {
 			12, IPA_v3_0_GROUP_UL, true,
 			IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP,
-			QMB_MASTER_SELECT_DDR},
+			QMB_MASTER_SELECT_DDR,
+			{ 12, 9, 8, 16, IPA_EE_AP } },
 	[IPA_3_0][IPA_CLIENT_TEST4_PROD]          = {
 			13, IPA_v3_0_GROUP_UL, true,
 			IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP,
-			QMB_MASTER_SELECT_DDR},
+			QMB_MASTER_SELECT_DDR,
+			{ 13, 10, 8, 16, IPA_EE_AP } },
 
 	[IPA_3_0][IPA_CLIENT_HSIC1_CONS]          = IPA_CLIENT_NOT_USED,
 	[IPA_3_0][IPA_CLIENT_WLAN1_CONS]          = {
 			25, IPA_v3_0_GROUP_DL, false,
 			IPA_DPS_HPS_SEQ_TYPE_INVALID,
-			QMB_MASTER_SELECT_DDR},
+			QMB_MASTER_SELECT_DDR,
+			{ 25, 4, 8, 8, IPA_EE_UC } },
 	[IPA_3_0][IPA_CLIENT_HSIC2_CONS]          = IPA_CLIENT_NOT_USED,
 	[IPA_3_0][IPA_CLIENT_USB2_CONS]           = IPA_CLIENT_NOT_USED,
 	[IPA_3_0][IPA_CLIENT_WLAN2_CONS]          = {
 			27, IPA_v3_0_GROUP_DL, false,
 			IPA_DPS_HPS_SEQ_TYPE_INVALID,
-			QMB_MASTER_SELECT_DDR},
+			QMB_MASTER_SELECT_DDR,
+			{ 27, 4, 8, 8, IPA_EE_AP } },
 	[IPA_3_0][IPA_CLIENT_HSIC3_CONS]          = IPA_CLIENT_NOT_USED,
 	[IPA_3_0][IPA_CLIENT_USB3_CONS]           = IPA_CLIENT_NOT_USED,
 	[IPA_3_0][IPA_CLIENT_WLAN3_CONS]          = {
 			28, IPA_v3_0_GROUP_DL, false,
 			IPA_DPS_HPS_SEQ_TYPE_INVALID,
-			QMB_MASTER_SELECT_DDR},
+			QMB_MASTER_SELECT_DDR,
+			{ 28, 13, 8, 8, IPA_EE_AP } },
 	[IPA_3_0][IPA_CLIENT_HSIC4_CONS]          = IPA_CLIENT_NOT_USED,
 	[IPA_3_0][IPA_CLIENT_USB4_CONS]           = IPA_CLIENT_NOT_USED,
 	[IPA_3_0][IPA_CLIENT_WLAN4_CONS]          = {
 			29, IPA_v3_0_GROUP_DL, false,
-			IPA_DPS_HPS_SEQ_TYPE_PKT_PROCESS_NO_DEC_UCP,
-			QMB_MASTER_SELECT_DDR},
+			IPA_DPS_HPS_SEQ_TYPE_INVALID,
+			QMB_MASTER_SELECT_DDR,
+			{ 29, 14, 8, 8, IPA_EE_AP } },
 	[IPA_3_0][IPA_CLIENT_HSIC5_CONS]          = IPA_CLIENT_NOT_USED,
 	[IPA_3_0][IPA_CLIENT_USB_CONS]            = {
 			26, IPA_v3_0_GROUP_DL, false,
 			IPA_DPS_HPS_SEQ_TYPE_INVALID,
-			QMB_MASTER_SELECT_DDR},
+			QMB_MASTER_SELECT_DDR,
+			{ 26, 12, 8, 8, IPA_EE_AP } },
 	[IPA_3_0][IPA_CLIENT_USB_DPL_CONS]        = {
 			17, IPA_v3_0_GROUP_DPL, false,
 			IPA_DPS_HPS_SEQ_TYPE_INVALID,
-			QMB_MASTER_SELECT_DDR},
+			QMB_MASTER_SELECT_DDR,
+			{ 17, 2, 8, 12, IPA_EE_AP } },
 	[IPA_3_0][IPA_CLIENT_A2_EMBEDDED_CONS]    = IPA_CLIENT_NOT_USED,
 	[IPA_3_0][IPA_CLIENT_A2_TETHERED_CONS]    = IPA_CLIENT_NOT_USED,
 	[IPA_3_0][IPA_CLIENT_A5_LAN_WAN_CONS]     = IPA_CLIENT_NOT_USED,
 	[IPA_3_0][IPA_CLIENT_APPS_LAN_CONS]       = {
 			15, IPA_v3_0_GROUP_UL, false,
 			IPA_DPS_HPS_SEQ_TYPE_INVALID,
-			QMB_MASTER_SELECT_DDR},
+			QMB_MASTER_SELECT_DDR,
+			{ 15, 7, 8, 12, IPA_EE_AP } },
 	[IPA_3_0][IPA_CLIENT_APPS_WAN_CONS]       = {
 			16, IPA_v3_0_GROUP_DL, false,
 			IPA_DPS_HPS_SEQ_TYPE_INVALID,
-			QMB_MASTER_SELECT_DDR},
+			QMB_MASTER_SELECT_DDR,
+			{ 16, 8, 8, 12, IPA_EE_AP } },
 	[IPA_3_0][IPA_CLIENT_ODU_EMB_CONS]        = {
 			23, IPA_v3_0_GROUP_DL, false,
 			IPA_DPS_HPS_SEQ_TYPE_INVALID,
-			QMB_MASTER_SELECT_DDR},
+			QMB_MASTER_SELECT_DDR,
+			{ 23, 1, 8, 8, IPA_EE_AP } },
 	[IPA_3_0][IPA_CLIENT_ODU_TETH_CONS]       = IPA_CLIENT_NOT_USED,
 	[IPA_3_0][IPA_CLIENT_MHI_CONS]            = {
 			23, IPA_v3_0_GROUP_DL, false,
 			IPA_DPS_HPS_SEQ_TYPE_INVALID,
-			QMB_MASTER_SELECT_PCIE},
+			QMB_MASTER_SELECT_PCIE,
+			{ 23, 1, 8, 8, IPA_EE_AP } },
 	[IPA_3_0][IPA_CLIENT_Q6_LAN_CONS]         = {
 			19, IPA_v3_0_GROUP_DL, false,
 			IPA_DPS_HPS_SEQ_TYPE_INVALID,
-			QMB_MASTER_SELECT_DDR},
+			QMB_MASTER_SELECT_DDR,
+			{ 19, 6, 8, 12, IPA_EE_Q6 } },
 	[IPA_3_0][IPA_CLIENT_Q6_WAN_CONS]         = {
 			18, IPA_v3_0_GROUP_UL, false,
 			IPA_DPS_HPS_SEQ_TYPE_INVALID,
-			QMB_MASTER_SELECT_DDR},
+			QMB_MASTER_SELECT_DDR,
+			{ 18, 5, 8, 12, IPA_EE_Q6 } },
 	[IPA_3_0][IPA_CLIENT_Q6_DUN_CONS]         = {
-			30, IPA_v3_0_GROUP_DIAG,
-			false, IPA_DPS_HPS_SEQ_TYPE_INVALID,
-			QMB_MASTER_SELECT_DDR},
-	[IPA_3_0][IPA_CLIENT_Q6_DECOMP_CONS]
-			= {21, IPA_v3_0_GROUP_Q6ZIP, false,
+			30, IPA_v3_0_GROUP_DIAG, false,
 			IPA_DPS_HPS_SEQ_TYPE_INVALID,
-			QMB_MASTER_SELECT_DDR},
-	[IPA_3_0][IPA_CLIENT_Q6_DECOMP2_CONS]
-			= {4, IPA_v3_0_GROUP_Q6ZIP, false,
+			QMB_MASTER_SELECT_DDR,
+			{ 30, 7, 4, 4, IPA_EE_Q6 } },
+	[IPA_3_0][IPA_CLIENT_Q6_DECOMP_CONS] = {
+			21, IPA_v3_0_GROUP_Q6ZIP, false,
 			IPA_DPS_HPS_SEQ_TYPE_INVALID,
-			QMB_MASTER_SELECT_DDR},
-	[IPA_3_0][IPA_CLIENT_MEMCPY_DMA_SYNC_CONS]
-			= {28, IPA_v3_0_GROUP_DMA, false,
+			QMB_MASTER_SELECT_DDR,
+			{ 21, 8, 4, 4, IPA_EE_Q6 } },
+	[IPA_3_0][IPA_CLIENT_Q6_DECOMP2_CONS] = {
+			4, IPA_v3_0_GROUP_Q6ZIP, false,
 			IPA_DPS_HPS_SEQ_TYPE_INVALID,
-			QMB_MASTER_SELECT_PCIE},
-	[IPA_3_0][IPA_CLIENT_MEMCPY_DMA_ASYNC_CONS]
-			= {29, IPA_v3_0_GROUP_DMA, false,
+			QMB_MASTER_SELECT_DDR,
+			{ 4, 9, 4, 4, IPA_EE_Q6 } },
+	[IPA_3_0][IPA_CLIENT_MEMCPY_DMA_SYNC_CONS] = {
+			28, IPA_v3_0_GROUP_DMA, false,
 			IPA_DPS_HPS_SEQ_TYPE_INVALID,
-			QMB_MASTER_SELECT_PCIE},
+			QMB_MASTER_SELECT_PCIE,
+			{ 28, 13, 8, 8, IPA_EE_AP } },
+	[IPA_3_0][IPA_CLIENT_MEMCPY_DMA_ASYNC_CONS] = {
+			29, IPA_v3_0_GROUP_DMA, false,
+			IPA_DPS_HPS_SEQ_TYPE_INVALID,
+			QMB_MASTER_SELECT_PCIE,
+			{ 29, 14, 8, 8, IPA_EE_AP } },
 	[IPA_3_0][IPA_CLIENT_Q6_LTE_WIFI_AGGR_CONS]     = IPA_CLIENT_NOT_USED,
 	/* Only for test purpose */
 	[IPA_3_0][IPA_CLIENT_TEST_CONS]           = {
 			26, IPA_v3_0_GROUP_DL, false,
 			IPA_DPS_HPS_SEQ_TYPE_INVALID,
-			QMB_MASTER_SELECT_DDR},
+			QMB_MASTER_SELECT_DDR,
+			{ 26, 12, 8, 8, IPA_EE_AP } },
 	[IPA_3_0][IPA_CLIENT_TEST1_CONS]          = {
 			26, IPA_v3_0_GROUP_DL, false,
 			IPA_DPS_HPS_SEQ_TYPE_INVALID,
-			QMB_MASTER_SELECT_DDR},
+			QMB_MASTER_SELECT_DDR,
+			{ 26, 12, 8, 8, IPA_EE_AP } },
 	[IPA_3_0][IPA_CLIENT_TEST2_CONS]          = {
 			27, IPA_v3_0_GROUP_DL, false,
 			IPA_DPS_HPS_SEQ_TYPE_INVALID,
-			QMB_MASTER_SELECT_DDR},
+			QMB_MASTER_SELECT_DDR,
+			{ 27, 4, 8, 8, IPA_EE_AP } },
 	[IPA_3_0][IPA_CLIENT_TEST3_CONS]          = {
 			28, IPA_v3_0_GROUP_DL, false,
 			IPA_DPS_HPS_SEQ_TYPE_INVALID,
-			QMB_MASTER_SELECT_DDR},
+			QMB_MASTER_SELECT_DDR,
+			{ 28, 13, 8, 8, IPA_EE_AP } },
 	[IPA_3_0][IPA_CLIENT_TEST4_CONS]          = {
 			29, IPA_v3_0_GROUP_DL, false,
 			IPA_DPS_HPS_SEQ_TYPE_INVALID,
-			QMB_MASTER_SELECT_DDR},
+			QMB_MASTER_SELECT_DDR,
+			{ 29, 14, 8, 8, IPA_EE_AP } },
+
 
 	/* IPA_3_5_1 */
 	[IPA_3_5_1][IPA_CLIENT_HSIC1_PROD]          = IPA_CLIENT_NOT_USED,
 	[IPA_3_5_1][IPA_CLIENT_WLAN1_PROD]          = {
-			7, IPA_v3_5_1_GROUP_UL_DL,
-			true,
+			7, IPA_v3_5_GROUP_UL_DL, true,
 			IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP,
-			QMB_MASTER_SELECT_DDR},
+			QMB_MASTER_SELECT_DDR,
+			{ 7, 1, 8, 16, IPA_EE_UC } },
 	[IPA_3_5_1][IPA_CLIENT_HSIC2_PROD]          = IPA_CLIENT_NOT_USED,
 	[IPA_3_5_1][IPA_CLIENT_USB2_PROD]           = IPA_CLIENT_NOT_USED,
 	[IPA_3_5_1][IPA_CLIENT_HSIC3_PROD]          = IPA_CLIENT_NOT_USED,
@@ -453,244 +501,169 @@
 	[IPA_3_5_1][IPA_CLIENT_USB4_PROD]           = IPA_CLIENT_NOT_USED,
 	[IPA_3_5_1][IPA_CLIENT_HSIC5_PROD]          = IPA_CLIENT_NOT_USED,
 	[IPA_3_5_1][IPA_CLIENT_USB_PROD]            = {
-			0, IPA_v3_5_1_GROUP_UL_DL,
-			true,
+			0, IPA_v3_5_GROUP_UL_DL, true,
 			IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP,
-			QMB_MASTER_SELECT_DDR},
+			QMB_MASTER_SELECT_DDR,
+			{ 0, 0, 8, 16, IPA_EE_AP } },
 	[IPA_3_5_1][IPA_CLIENT_UC_USB_PROD]         = IPA_CLIENT_NOT_USED,
 	[IPA_3_5_1][IPA_CLIENT_A5_WLAN_AMPDU_PROD]  = IPA_CLIENT_NOT_USED,
 	[IPA_3_5_1][IPA_CLIENT_A2_EMBEDDED_PROD]    = IPA_CLIENT_NOT_USED,
 	[IPA_3_5_1][IPA_CLIENT_A2_TETHERED_PROD]    = IPA_CLIENT_NOT_USED,
 	[IPA_3_5_1][IPA_CLIENT_APPS_LAN_WAN_PROD]   = {
-			8, IPA_v3_5_1_GROUP_UL_DL,
-			true,
+			8, IPA_v3_5_GROUP_UL_DL, true,
 			IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP,
-			QMB_MASTER_SELECT_DDR},
+			QMB_MASTER_SELECT_DDR,
+			{ 8, 7, 8, 16, IPA_EE_AP } },
 	[IPA_3_5_1][IPA_CLIENT_APPS_CMD_PROD]		= {
-			5, IPA_v3_5_1_GROUP_UL_DL,
-			false,
+			5, IPA_v3_5_GROUP_UL_DL, false,
 			IPA_DPS_HPS_SEQ_TYPE_DMA_ONLY,
-			QMB_MASTER_SELECT_DDR},
+			QMB_MASTER_SELECT_DDR,
+			{ 5, 4, 20, 23, IPA_EE_AP } },
 	[IPA_3_5_1][IPA_CLIENT_ODU_PROD]            = IPA_CLIENT_NOT_USED,
 	[IPA_3_5_1][IPA_CLIENT_MHI_PROD]            = IPA_CLIENT_NOT_USED,
 	[IPA_3_5_1][IPA_CLIENT_Q6_LAN_PROD]         = {
-			3, IPA_v3_5_1_GROUP_UL_DL,
-			true, IPA_DPS_HPS_SEQ_TYPE_PKT_PROCESS_NO_DEC_UCP,
-			QMB_MASTER_SELECT_DDR },
-	[IPA_3_5_1][IPA_CLIENT_Q6_WAN_PROD]         = {
-			6, IPA_v3_5_1_GROUP_UL_DL,
-			true, IPA_DPS_HPS_SEQ_TYPE_PKT_PROCESS_NO_DEC_UCP,
-			QMB_MASTER_SELECT_DDR},
-	[IPA_3_5_1][IPA_CLIENT_Q6_CMD_PROD]
-			= {4, IPA_v3_5_1_GROUP_UL_DL, false,
+			3, IPA_v3_5_GROUP_UL_DL, true,
 			IPA_DPS_HPS_SEQ_TYPE_PKT_PROCESS_NO_DEC_UCP,
-			QMB_MASTER_SELECT_DDR},
+			QMB_MASTER_SELECT_DDR,
+			{ 3, 0, 16, 32, IPA_EE_Q6 } },
+	[IPA_3_5_1][IPA_CLIENT_Q6_WAN_PROD]         = {
+			6, IPA_v3_5_GROUP_UL_DL, true,
+			IPA_DPS_HPS_SEQ_TYPE_PKT_PROCESS_NO_DEC_UCP,
+			QMB_MASTER_SELECT_DDR,
+			{ 6, 4, 12, 30, IPA_EE_Q6 } },
+	[IPA_3_5_1][IPA_CLIENT_Q6_CMD_PROD]	    = {
+			4, IPA_v3_5_GROUP_UL_DL, false,
+			IPA_DPS_HPS_SEQ_TYPE_PKT_PROCESS_NO_DEC_UCP,
+			QMB_MASTER_SELECT_DDR,
+			{ 4, 1, 20, 23, IPA_EE_Q6 } },
 	[IPA_3_5_1][IPA_CLIENT_Q6_DECOMP_PROD]      = IPA_CLIENT_NOT_USED,
 	[IPA_3_5_1][IPA_CLIENT_Q6_DECOMP2_PROD]     = IPA_CLIENT_NOT_USED,
 	[IPA_3_5_1][IPA_CLIENT_MEMCPY_DMA_SYNC_PROD] = IPA_CLIENT_NOT_USED,
 	[IPA_3_5_1][IPA_CLIENT_MEMCPY_DMA_ASYNC_PROD] = IPA_CLIENT_NOT_USED,
 	/* Only for test purpose */
 	[IPA_3_5_1][IPA_CLIENT_TEST_PROD]           = {
-			0, IPA_v3_5_1_GROUP_UL_DL, true,
+			0, IPA_v3_5_GROUP_UL_DL, true,
 			IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP,
-			QMB_MASTER_SELECT_DDR},
+			QMB_MASTER_SELECT_DDR,
+			{ 0, 0, 8, 16, IPA_EE_AP } },
 	[IPA_3_5_1][IPA_CLIENT_TEST1_PROD]          = {
-			0, IPA_v3_5_1_GROUP_UL_DL, true,
+			0, IPA_v3_5_GROUP_UL_DL, true,
 			IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP,
-			QMB_MASTER_SELECT_DDR},
+			QMB_MASTER_SELECT_DDR,
+			{ 0, 0, 8, 16, IPA_EE_AP } },
 	[IPA_3_5_1][IPA_CLIENT_TEST2_PROD]          = {
-			2, IPA_v3_5_1_GROUP_UL_DL, true,
+			2, IPA_v3_5_GROUP_UL_DL, true,
 			IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP,
-			QMB_MASTER_SELECT_DDR},
+			QMB_MASTER_SELECT_DDR,
+			{ 2, 3, 16, 32, IPA_EE_AP } },
 	[IPA_3_5_1][IPA_CLIENT_TEST3_PROD]          = {
-			4, IPA_v3_5_1_GROUP_UL_DL, true,
+			4, IPA_v3_5_GROUP_UL_DL, true,
 			IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP,
-			QMB_MASTER_SELECT_DDR},
+			QMB_MASTER_SELECT_DDR,
+			{ 4, 1, 20, 23, IPA_EE_Q6 } },
 	[IPA_3_5_1][IPA_CLIENT_TEST4_PROD]          = {
-			1, IPA_v3_5_1_GROUP_UL_DL, true,
+			1, IPA_v3_5_GROUP_UL_DL, true,
 			IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP,
-			QMB_MASTER_SELECT_DDR},
+			QMB_MASTER_SELECT_DDR,
+			{ 1, 0, 8, 16, IPA_EE_UC } },
 
 	[IPA_3_5_1][IPA_CLIENT_HSIC1_CONS]          = IPA_CLIENT_NOT_USED,
 	[IPA_3_5_1][IPA_CLIENT_WLAN1_CONS]          = {
-			16, IPA_v3_5_1_GROUP_UL_DL,
-			false,
+			16, IPA_v3_5_GROUP_UL_DL, false,
 			IPA_DPS_HPS_SEQ_TYPE_INVALID,
-			QMB_MASTER_SELECT_DDR},
+			QMB_MASTER_SELECT_DDR,
+			{ 16, 3, 8, 8, IPA_EE_UC } },
 	[IPA_3_5_1][IPA_CLIENT_HSIC2_CONS]          = IPA_CLIENT_NOT_USED,
 	[IPA_3_5_1][IPA_CLIENT_USB2_CONS]           = IPA_CLIENT_NOT_USED,
 	[IPA_3_5_1][IPA_CLIENT_WLAN2_CONS]          =  {
-			18, IPA_v3_5_1_GROUP_UL_DL, false,
+			18, IPA_v3_5_GROUP_UL_DL, false,
 			IPA_DPS_HPS_SEQ_TYPE_INVALID,
-			QMB_MASTER_SELECT_DDR},
+			QMB_MASTER_SELECT_DDR,
+			{ 18, 9, 8, 8, IPA_EE_AP } },
 	[IPA_3_5_1][IPA_CLIENT_HSIC3_CONS]          = IPA_CLIENT_NOT_USED,
 	[IPA_3_5_1][IPA_CLIENT_USB3_CONS]           = IPA_CLIENT_NOT_USED,
 	[IPA_3_5_1][IPA_CLIENT_WLAN3_CONS]          =  {
-			19, IPA_v3_5_1_GROUP_UL_DL, false,
+			19, IPA_v3_5_GROUP_UL_DL, false,
 			IPA_DPS_HPS_SEQ_TYPE_INVALID,
-			QMB_MASTER_SELECT_DDR},
+			QMB_MASTER_SELECT_DDR,
+			{ 19, 10, 8, 8, IPA_EE_AP } },
 	[IPA_3_5_1][IPA_CLIENT_HSIC4_CONS]          = IPA_CLIENT_NOT_USED,
 	[IPA_3_5_1][IPA_CLIENT_USB4_CONS]           = IPA_CLIENT_NOT_USED,
 	[IPA_3_5_1][IPA_CLIENT_WLAN4_CONS]          = IPA_CLIENT_NOT_USED,
 	[IPA_3_5_1][IPA_CLIENT_HSIC5_CONS]          = IPA_CLIENT_NOT_USED,
 	[IPA_3_5_1][IPA_CLIENT_USB_CONS]            = {
-			17, IPA_v3_5_1_GROUP_UL_DL,
-			false,
+			17, IPA_v3_5_GROUP_UL_DL, false,
 			IPA_DPS_HPS_SEQ_TYPE_INVALID,
-			QMB_MASTER_SELECT_DDR},
+			QMB_MASTER_SELECT_DDR,
+			{ 17, 8, 8, 8, IPA_EE_AP } },
 	[IPA_3_5_1][IPA_CLIENT_USB_DPL_CONS]        = {
-			11, IPA_v3_5_1_GROUP_UL_DL,
-			false,
+			11, IPA_v3_5_GROUP_UL_DL, false,
 			IPA_DPS_HPS_SEQ_TYPE_INVALID,
-			QMB_MASTER_SELECT_DDR},
+			QMB_MASTER_SELECT_DDR,
+			{ 11, 2, 4, 6, IPA_EE_AP } },
 	[IPA_3_5_1][IPA_CLIENT_A2_EMBEDDED_CONS]    = IPA_CLIENT_NOT_USED,
 	[IPA_3_5_1][IPA_CLIENT_A2_TETHERED_CONS]    = IPA_CLIENT_NOT_USED,
 	[IPA_3_5_1][IPA_CLIENT_A5_LAN_WAN_CONS]     = IPA_CLIENT_NOT_USED,
 	[IPA_3_5_1][IPA_CLIENT_APPS_LAN_CONS]       = {
-			9, IPA_v3_5_1_GROUP_UL_DL,
-			false,
+			9, IPA_v3_5_GROUP_UL_DL, false,
 			IPA_DPS_HPS_SEQ_TYPE_INVALID,
-			QMB_MASTER_SELECT_DDR},
+			QMB_MASTER_SELECT_DDR,
+			{ 9, 5, 8, 12, IPA_EE_AP } },
 	[IPA_3_5_1][IPA_CLIENT_APPS_WAN_CONS]       = {
-			10, IPA_v3_5_1_GROUP_UL_DL,
-			false,
+			10, IPA_v3_5_GROUP_UL_DL, false,
 			IPA_DPS_HPS_SEQ_TYPE_INVALID,
-			QMB_MASTER_SELECT_DDR},
+			QMB_MASTER_SELECT_DDR,
+			{ 10, 6, 8, 12, IPA_EE_AP } },
 	[IPA_3_5_1][IPA_CLIENT_ODU_EMB_CONS]        = IPA_CLIENT_NOT_USED,
 	[IPA_3_5_1][IPA_CLIENT_ODU_TETH_CONS]       = IPA_CLIENT_NOT_USED,
 	[IPA_3_5_1][IPA_CLIENT_MHI_CONS]            = IPA_CLIENT_NOT_USED,
 	[IPA_3_5_1][IPA_CLIENT_Q6_LAN_CONS]         = {
-			13, IPA_v3_5_1_GROUP_UL_DL,
-			false,
+			13, IPA_v3_5_GROUP_UL_DL, false,
 			IPA_DPS_HPS_SEQ_TYPE_INVALID,
-			QMB_MASTER_SELECT_DDR},
+			QMB_MASTER_SELECT_DDR,
+			{ 13, 3, 8, 12, IPA_EE_Q6 } },
 	[IPA_3_5_1][IPA_CLIENT_Q6_WAN_CONS]         = {
-			12, IPA_v3_5_1_GROUP_UL_DL,
-			false,
+			12, IPA_v3_5_GROUP_UL_DL, false,
 			IPA_DPS_HPS_SEQ_TYPE_INVALID,
-			QMB_MASTER_SELECT_DDR},
-	[IPA_3_5_1][IPA_CLIENT_Q6_DUN_CONS]         = IPA_CLIENT_NOT_USED,
-	[IPA_3_5_1][IPA_CLIENT_Q6_DECOMP_CONS]		= IPA_CLIENT_NOT_USED,
-	[IPA_3_5_1][IPA_CLIENT_Q6_DECOMP2_CONS]		= IPA_CLIENT_NOT_USED,
-	[IPA_3_5_1][IPA_CLIENT_MEMCPY_DMA_SYNC_CONS] = IPA_CLIENT_NOT_USED,
+			QMB_MASTER_SELECT_DDR,
+			{ 12, 2, 8, 12, IPA_EE_Q6 } },
+	[IPA_3_5_1][IPA_CLIENT_Q6_DUN_CONS]           = IPA_CLIENT_NOT_USED,
+	[IPA_3_5_1][IPA_CLIENT_Q6_DECOMP_CONS]	      = IPA_CLIENT_NOT_USED,
+	[IPA_3_5_1][IPA_CLIENT_Q6_DECOMP2_CONS]	      = IPA_CLIENT_NOT_USED,
+	[IPA_3_5_1][IPA_CLIENT_MEMCPY_DMA_SYNC_CONS]  = IPA_CLIENT_NOT_USED,
 	[IPA_3_5_1][IPA_CLIENT_MEMCPY_DMA_ASYNC_CONS] = IPA_CLIENT_NOT_USED,
 	[IPA_3_5_1][IPA_CLIENT_Q6_LTE_WIFI_AGGR_CONS] = IPA_CLIENT_NOT_USED,
 	/* Only for test purpose */
 	[IPA_3_5_1][IPA_CLIENT_TEST_CONS]           = {
-			17, IPA_v3_5_1_GROUP_UL_DL,
+			17, IPA_v3_5_GROUP_UL_DL,
 			false,
 			IPA_DPS_HPS_SEQ_TYPE_INVALID,
-			QMB_MASTER_SELECT_DDR},
+			QMB_MASTER_SELECT_DDR,
+			{ 17, 8, 8, 8, IPA_EE_AP } },
 	[IPA_3_5_1][IPA_CLIENT_TEST1_CONS]          = {
-			17, IPA_v3_5_1_GROUP_UL_DL,
+			17, IPA_v3_5_GROUP_UL_DL,
 			false,
 			IPA_DPS_HPS_SEQ_TYPE_INVALID,
-			QMB_MASTER_SELECT_DDR},
+			QMB_MASTER_SELECT_DDR,
+			{ 17, 8, 8, 8, IPA_EE_AP } },
 	[IPA_3_5_1][IPA_CLIENT_TEST2_CONS]          = {
-			18, IPA_v3_5_1_GROUP_UL_DL,
+			18, IPA_v3_5_GROUP_UL_DL,
 			false,
 			IPA_DPS_HPS_SEQ_TYPE_INVALID,
-			QMB_MASTER_SELECT_DDR},
+			QMB_MASTER_SELECT_DDR,
+			{ 18, 9, 8, 8, IPA_EE_AP } },
 	[IPA_3_5_1][IPA_CLIENT_TEST3_CONS]          = {
-			19, IPA_v3_5_1_GROUP_UL_DL,
+			19, IPA_v3_5_GROUP_UL_DL,
 			false,
 			IPA_DPS_HPS_SEQ_TYPE_INVALID,
-			QMB_MASTER_SELECT_DDR},
+			QMB_MASTER_SELECT_DDR,
+			{ 19, 10, 8, 8, IPA_EE_AP } },
 	[IPA_3_5_1][IPA_CLIENT_TEST4_CONS]          = {
-			11, IPA_v3_5_1_GROUP_UL_DL,
+			11, IPA_v3_5_GROUP_UL_DL,
 			false,
 			IPA_DPS_HPS_SEQ_TYPE_INVALID,
-			QMB_MASTER_SELECT_DDR},
-};
-
-enum ipa_ees {
-	IPA_EE_AP = 0,
-	IPA_EE_Q6 = 1,
-	IPA_EE_UC = 3,
-};
-
-static struct ipa_gsi_ep_config
-	ipa_gsi_ep_info[IPA_VER_MAX][IPA3_MAX_NUM_PIPES] = {
-		/* IPA_3_0 - valid also for IPAv3.1 */
-	[IPA_3_0] = {
-	/* {ipa_ep_num, ipa_gsi_chan_num, ipa_if_tlv, ipa_if_aos, ee} */
-		{0, 0, 8, 16, IPA_EE_AP},
-		{1, 3, 8, 16, IPA_EE_AP},
-		{3, 5, 16, 32, IPA_EE_AP},
-		{4, 9, 4, 4, IPA_EE_Q6},
-		{5, 0, 16, 32, IPA_EE_Q6},
-		{6, 1, 18, 28, IPA_EE_Q6},
-		{7, 2, 0, 0, IPA_EE_Q6},
-		{8, 3, 0, 0, IPA_EE_Q6},
-		{9, 4, 8, 12, IPA_EE_Q6},
-		{10, 1, 8, 16, IPA_EE_UC},
-		{12, 9, 8, 16, IPA_EE_AP},
-		{13, 10, 8, 16, IPA_EE_AP},
-		{14, 11, 8, 16, IPA_EE_AP},
-		{15, 7, 8, 12, IPA_EE_AP},
-		{16, 8, 8, 12, IPA_EE_AP},
-		{17, 2, 8, 12, IPA_EE_AP},
-		{18, 5, 8, 12, IPA_EE_Q6},
-		{19, 6, 8, 12, IPA_EE_Q6},
-		{21, 8, 4, 4, IPA_EE_Q6},
-		{22, 6, 18, 28, IPA_EE_AP},
-		{23, 1, 8, 8, IPA_EE_AP},
-		{25, 4, 8, 8, IPA_EE_UC},
-		{26, 12, 8, 8, IPA_EE_AP},
-		{27, 4, 8, 8, IPA_EE_AP},
-		{28, 13, 8, 8, IPA_EE_AP},
-		{29, 14, 8, 8, IPA_EE_AP},
-		{30, 7, 4, 4, IPA_EE_Q6},
-		{-1, -1, -1, -1, -1}
-	},
-	[IPA_3_5] = {
-	/* {ipa_ep_num, ipa_gsi_chan_num, ipa_if_tlv, ipa_if_aos, ee} */
-		{0, 7, 8, 16, IPA_EE_AP},
-		{1, 0, 8, 16, IPA_EE_UC},
-		{2, 3, 16, 32, IPA_EE_AP},
-		{3, 0, 16, 32, IPA_EE_Q6},
-		{4, 1, 20, 23, IPA_EE_Q6},
-		{5, 4, 20, 23, IPA_EE_AP},
-		{6, 4, 12, 30, IPA_EE_Q6},
-		{7, 1, 8, 16, IPA_EE_UC},
-		{8, 9, 8, 16, IPA_EE_AP},
-		{9, 5, 8, 12, IPA_EE_AP},
-		{10, 6, 8, 12, IPA_EE_AP},
-		{11, 2, 4, 6, IPA_EE_AP},
-		{12, 2, 8, 12, IPA_EE_Q6},
-		{13, 3, 8, 12, IPA_EE_Q6},
-		{14, 10, 4, 6, IPA_EE_AP},
-		{15, 2, 8, 8, IPA_EE_UC},
-		{16, 3, 8, 8, IPA_EE_UC},
-		{17, 11, 8, 8, IPA_EE_AP},
-		{18, 12, 8, 8, IPA_EE_AP},
-		{19, 13, 8, 8, IPA_EE_AP},
-		{-1, -1, -1, -1, -1}
-	},
-	[IPA_3_5_1] = {
-	/* {ipa_ep_num, ipa_gsi_chan_num, ipa_if_tlv, ipa_if_aos, ee} */
-		{0, 0, 8, 16, IPA_EE_AP},
-		{1, 0, 8, 16, IPA_EE_UC},
-		{2, 3, 16, 32, IPA_EE_AP},
-		{3, 0, 16, 32, IPA_EE_Q6},
-		{4, 1, 20, 23, IPA_EE_Q6},
-		{5, 4, 20, 23, IPA_EE_AP},
-		{6, 4, 12, 30, IPA_EE_Q6},
-		{7, 1, 8, 16, IPA_EE_UC},
-		{8, 7, 8, 16, IPA_EE_AP},
-		{9, 5, 8, 12, IPA_EE_AP},
-		{10, 6, 8, 12, IPA_EE_AP},
-		{11, 2, 4, 6, IPA_EE_AP},
-		{12, 2, 8, 12, IPA_EE_Q6},
-		{13, 3, 8, 12, IPA_EE_Q6},
-		{14, 5, 8, 8, IPA_EE_Q6},
-		{15, 2, 8, 8, IPA_EE_UC},
-		{16, 3, 8, 8, IPA_EE_UC},
-		{17, 8, 8, 8, IPA_EE_AP},
-		{18, 9, 8, 8, IPA_EE_AP},
-		{19, 10, 8, 8, IPA_EE_AP},
-		{-1, -1, -1, -1, -1}
-	},
+			QMB_MASTER_SELECT_DDR,
+			{ 11, 2, 4, 6, IPA_EE_AP } },
 };
 
 static struct msm_bus_vectors ipa_init_vectors_v3_0[]  = {
@@ -1253,27 +1226,20 @@
 
 /**
  * ipa3_get_gsi_ep_info() - provide gsi ep information
- * @ipa_ep_idx: IPA endpoint index
+ * @client: IPA client value
  *
  * Return value: pointer to ipa_gsi_ep_info
  */
-struct ipa_gsi_ep_config *ipa3_get_gsi_ep_info(int ipa_ep_idx)
+const struct ipa_gsi_ep_config *ipa3_get_gsi_ep_info
+	(enum ipa_client_type client)
 {
-	int i;
-	u8 hw_index;
-
-	hw_index = ipa3_get_hw_type_index();
-
-	for (i = 0; ; i++) {
-		if (ipa_gsi_ep_info[hw_index][i].ipa_ep_num < 0)
-			break;
-
-		if (ipa_gsi_ep_info[hw_index][i].ipa_ep_num ==
-			ipa_ep_idx)
-			return &(ipa_gsi_ep_info[hw_index][i]);
+	if (client >= IPA_CLIENT_MAX || client < 0) {
+		IPAERR("Bad client number! client =%d\n", client);
+		return NULL;
 	}
 
-	return NULL;
+	return &(ipa3_ep_mapping[ipa3_get_hw_type_index()]
+		[client].ipa_gsi_ep_info);
 }
 
 /**
@@ -2339,103 +2305,6 @@
 }
 
 /**
- * ipa3_pipe_mem_init() - initialize the pipe memory
- * @start_ofst: start offset
- * @size: size
- *
- * Return value:
- * 0: success
- * -ENOMEM: no memory
- */
-int ipa3_pipe_mem_init(u32 start_ofst, u32 size)
-{
-	int res;
-	u32 aligned_start_ofst;
-	u32 aligned_size;
-	struct gen_pool *pool;
-
-	if (!size) {
-		IPAERR("no IPA pipe memory allocated\n");
-		goto fail;
-	}
-
-	aligned_start_ofst = IPA_PIPE_MEM_START_OFST_ALIGNMENT(start_ofst);
-	aligned_size = size - (aligned_start_ofst - start_ofst);
-
-	IPADBG("start_ofst=%u aligned_start_ofst=%u size=%u aligned_size=%u\n",
-	       start_ofst, aligned_start_ofst, size, aligned_size);
-
-	/* allocation order of 8 i.e. 128 bytes, global pool */
-	pool = gen_pool_create(8, -1);
-	if (!pool) {
-		IPAERR("Failed to create a new memory pool.\n");
-		goto fail;
-	}
-
-	res = gen_pool_add(pool, aligned_start_ofst, aligned_size, -1);
-	if (res) {
-		IPAERR("Failed to add memory to IPA pipe pool\n");
-		goto err_pool_add;
-	}
-
-	ipa3_ctx->pipe_mem_pool = pool;
-	return 0;
-
-err_pool_add:
-	gen_pool_destroy(pool);
-fail:
-	return -ENOMEM;
-}
-
-/**
- * ipa3_pipe_mem_alloc() - allocate pipe memory
- * @ofst: offset
- * @size: size
- *
- * Return value:
- * 0: success
- */
-int ipa3_pipe_mem_alloc(u32 *ofst, u32 size)
-{
-	u32 vaddr;
-	int res = -1;
-
-	if (!ipa3_ctx->pipe_mem_pool || !size) {
-		IPAERR("failed size=%u pipe_mem_pool=%p\n", size,
-				ipa3_ctx->pipe_mem_pool);
-		return res;
-	}
-
-	vaddr = gen_pool_alloc(ipa3_ctx->pipe_mem_pool, size);
-
-	if (vaddr) {
-		*ofst = vaddr;
-		res = 0;
-		IPADBG("size=%u ofst=%u\n", size, vaddr);
-	} else {
-		IPAERR("size=%u failed\n", size);
-	}
-
-	return res;
-}
-
-/**
- * ipa3_pipe_mem_free() - free pipe memory
- * @ofst: offset
- * @size: size
- *
- * Return value:
- * 0: success
- */
-int ipa3_pipe_mem_free(u32 ofst, u32 size)
-{
-	IPADBG("size=%u ofst=%u\n", size, ofst);
-	if (ipa3_ctx->pipe_mem_pool && size)
-		gen_pool_free(ipa3_ctx->pipe_mem_pool, ofst, size);
-	return 0;
-}
-
-/**
  * ipa3_set_aggr_mode() - Set the aggregation mode which is a global setting
  * @mode:	[in] the desired aggregation mode for e.g. straight MBIM, QCNCM,
  * etc
@@ -2534,28 +2403,6 @@
 }
 
 /**
- * ipa3_bam_reg_dump() - Dump selected BAM registers for IPA.
- * The API is right now used only to dump IPA registers towards USB.
- *
- * Function is rate limited to avoid flooding kernel log buffer
- */
-void ipa3_bam_reg_dump(void)
-{
-	static DEFINE_RATELIMIT_STATE(_rs, 500*HZ, 1);
-
-	if (__ratelimit(&_rs)) {
-		IPA_ACTIVE_CLIENTS_INC_SIMPLE();
-		pr_err("IPA BAM START\n");
-		sps_get_bam_debug_info(ipa3_ctx->bam_handle, 93,
-			(SPS_BAM_PIPE(ipa3_get_ep_mapping(IPA_CLIENT_USB_CONS))
-			|
-			SPS_BAM_PIPE(ipa3_get_ep_mapping(IPA_CLIENT_USB_PROD))),
-			0, 2);
-		IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
-	}
-}
-
-/**
  * ipa3_init_mem_partition() - Reads IPA memory map from DTS, performs alignment
  * checks and logs the fetched values.
  *
@@ -3058,7 +2905,10 @@
 	if (atomic_dec_return(&comp->cnt) == 0)
 		kfree(comp);
 
-	/* sleep for short period to ensure IPA wrote all packets to BAM */
+	/*
+	 * sleep for short period to ensure IPA wrote all packets to
+	 * the transport
+	 */
 	usleep_range(IPA_TAG_SLEEP_MIN_USEC, IPA_TAG_SLEEP_MAX_USEC);
 
 	return 0;
@@ -3294,16 +3144,12 @@
 }
 
 /**
- * ipa3_get_transport_type()- Return ipa3_ctx->transport_prototype
+ * ipa3_get_transport_type()
  *
  * Return value: enum ipa_transport_type
  */
 enum ipa_transport_type ipa3_get_transport_type(void)
 {
-	if (ipa3_ctx)
-		return ipa3_ctx->transport_prototype;
-
-	IPAERR("IPA driver has not been initialized\n");
 	return IPA_TRANSPORT_TYPE_GSI;
 }
 
@@ -3379,9 +3225,9 @@
 		return -EPERM;
 	}
 
-	api_ctrl->ipa_connect = ipa3_connect;
-	api_ctrl->ipa_disconnect = ipa3_disconnect;
-	api_ctrl->ipa_reset_endpoint = ipa3_reset_endpoint;
+	api_ctrl->ipa_connect = NULL;
+	api_ctrl->ipa_disconnect = NULL;
+	api_ctrl->ipa_reset_endpoint = NULL;
 	api_ctrl->ipa_clear_endpoint_delay = ipa3_clear_endpoint_delay;
 	api_ctrl->ipa_disable_endpoint = NULL;
 	api_ctrl->ipa_cfg_ep = ipa3_cfg_ep;
@@ -3497,7 +3343,7 @@
 	api_ctrl->ipa_add_interrupt_handler = ipa3_add_interrupt_handler;
 	api_ctrl->ipa_remove_interrupt_handler = ipa3_remove_interrupt_handler;
 	api_ctrl->ipa_restore_suspend_handler = ipa3_restore_suspend_handler;
-	api_ctrl->ipa_bam_reg_dump = ipa3_bam_reg_dump;
+	api_ctrl->ipa_bam_reg_dump = NULL;
 	api_ctrl->ipa_get_ep_mapping = ipa3_get_ep_mapping;
 	api_ctrl->ipa_is_ready = ipa3_is_ready;
 	api_ctrl->ipa_proxy_clk_vote = ipa3_proxy_clk_vote;
@@ -3633,14 +3479,14 @@
 	case IPA_3_5_1:
 		if (src) {
 			switch (group_index) {
-			case IPA_v3_5_1_GROUP_LWA_DL:
-			case IPA_v3_5_1_GROUP_UL_DL:
+			case IPA_v3_5_GROUP_LWA_DL:
+			case IPA_v3_5_GROUP_UL_DL:
 				ipahal_write_reg_n_fields(
 					IPA_SRC_RSRC_GRP_01_RSRC_TYPE_n,
 					n, val);
 				break;
-			case IPA_v3_5_1_GROUP_DMA:
-			case IPA_v3_5_1_GROUP_UC_RX_Q:
+			case IPA_v3_5_GROUP_DMA:
+			case IPA_v3_5_GROUP_UC_RX_Q:
 				ipahal_write_reg_n_fields(
 					IPA_SRC_RSRC_GRP_23_RSRC_TYPE_n,
 					n, val);
@@ -3653,13 +3499,13 @@
 			}
 		} else {
 			switch (group_index) {
-			case IPA_v3_5_1_GROUP_LWA_DL:
-			case IPA_v3_5_1_GROUP_UL_DL:
+			case IPA_v3_5_GROUP_LWA_DL:
+			case IPA_v3_5_GROUP_UL_DL:
 				ipahal_write_reg_n_fields(
 					IPA_DST_RSRC_GRP_01_RSRC_TYPE_n,
 					n, val);
 				break;
-			case IPA_v3_5_1_GROUP_DMA:
+			case IPA_v3_5_GROUP_DMA:
 				ipahal_write_reg_n_fields(
 					IPA_DST_RSRC_GRP_23_RSRC_TYPE_n,
 					n, val);
@@ -3739,10 +3585,10 @@
 		dst_grp_idx_max = IPA_v3_0_GROUP_MAX;
 		break;
 	case IPA_3_5_1:
-		src_rsrc_type_max = IPA_v3_5_1_RSRC_GRP_TYPE_SRC_MAX;
-		dst_rsrc_type_max = IPA_v3_5_1_RSRC_GRP_TYPE_DST_MAX;
-		src_grp_idx_max = IPA_v3_5_1_SRC_GROUP_MAX;
-		dst_grp_idx_max = IPA_v3_5_1_DST_GROUP_MAX;
+		src_rsrc_type_max = IPA_v3_5_RSRC_GRP_TYPE_SRC_MAX;
+		dst_rsrc_type_max = IPA_v3_5_RSRC_GRP_TYPE_DST_MAX;
+		src_grp_idx_max = IPA_v3_5_SRC_GROUP_MAX;
+		dst_grp_idx_max = IPA_v3_5_DST_GROUP_MAX;
 		break;
 	default:
 		IPAERR("invalid hw type index\n");
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_fltrt.c b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_fltrt.c
index 67b3cb3..053a581 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_fltrt.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_fltrt.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -2553,16 +2553,19 @@
  * @hash_hdr_size: SRAM buf size of the hash tbls hdr. Used for space check
  * @nhash_hdr_size: SRAM buf size of the nhash tbls hdr. Used for space check
  * @mem: mem object that points to DMA mem representing the hdr structure
+ * @atomic: should DMA allocation be executed with atomic flag
  */
 int ipahal_rt_generate_empty_img(u32 tbls_num, u32 hash_hdr_size,
-	u32 nhash_hdr_size, struct ipa_mem_buffer *mem)
+	u32 nhash_hdr_size, struct ipa_mem_buffer *mem, bool atomic)
 {
 	int i;
 	u64 addr;
 	struct ipahal_fltrt_obj *obj;
+	int flag;
 
 	IPAHAL_DBG("Entry\n");
 
+	flag = atomic ? GFP_ATOMIC : GFP_KERNEL;
 	obj = &ipahal_fltrt_objs[ipahal_ctx->hw_type];
 
 	if (!tbls_num || !nhash_hdr_size || !mem) {
@@ -2589,7 +2592,7 @@
 
 	mem->size = tbls_num * obj->tbl_hdr_width;
 	mem->base = dma_alloc_coherent(ipahal_ctx->ipa_pdev, mem->size,
-		&mem->phys_base, GFP_KERNEL);
+		&mem->phys_base, flag);
 	if (!mem->base) {
 		IPAHAL_ERR("fail to alloc DMA buff of size %d\n", mem->size);
 		return -ENOMEM;
@@ -2615,18 +2618,22 @@
  *  should be: bit0->EP0, bit1->EP1
  *  If bitmap is zero -> create tbl without bitmap entry
  * @mem: mem object that points to DMA mem representing the hdr structure
+ * @atomic: should DMA allocation be executed with atomic flag
  */
 int ipahal_flt_generate_empty_img(u32 tbls_num, u32 hash_hdr_size,
-	u32 nhash_hdr_size, u64 ep_bitmap, struct ipa_mem_buffer *mem)
+	u32 nhash_hdr_size, u64 ep_bitmap, struct ipa_mem_buffer *mem,
+	bool atomic)
 {
 	int flt_spc;
 	u64 flt_bitmap;
 	int i;
 	u64 addr;
 	struct ipahal_fltrt_obj *obj;
+	int flag;
 
 	IPAHAL_DBG("Entry - ep_bitmap 0x%llx\n", ep_bitmap);
 
+	flag = atomic ? GFP_ATOMIC : GFP_KERNEL;
 	obj = &ipahal_fltrt_objs[ipahal_ctx->hw_type];
 
 	if (!tbls_num || !nhash_hdr_size || !mem) {
@@ -2667,7 +2674,7 @@
 	if (ep_bitmap)
 		mem->size += obj->tbl_hdr_width;
 	mem->base = dma_alloc_coherent(ipahal_ctx->ipa_pdev, mem->size,
-		&mem->phys_base, GFP_KERNEL);
+		&mem->phys_base, flag);
 	if (!mem->base) {
 		IPAHAL_ERR("fail to alloc DMA buff of size %d\n", mem->size);
 		return -ENOMEM;
@@ -2721,7 +2728,7 @@
 	params->nhash_hdr.base = dma_alloc_coherent(ipahal_ctx->ipa_pdev,
 		params->nhash_hdr.size,
 		&params->nhash_hdr.phys_base, GFP_KERNEL);
-	if (!params->nhash_hdr.size) {
+	if (!params->nhash_hdr.base) {
 		IPAHAL_ERR("fail to alloc DMA buff of size %d\n",
 			params->nhash_hdr.size);
 		goto nhash_alloc_fail;
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_fltrt.h b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_fltrt.h
index ee2704d6..3ee883b 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_fltrt.h
+++ b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_fltrt.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -171,9 +171,10 @@
  * @hash_hdr_size: SRAM buf size of the hash tbls hdr. Used for space check
  * @nhash_hdr_size: SRAM buf size of the nhash tbls hdr. Used for space check
  * @mem: mem object that points to DMA mem representing the hdr structure
+ * @atomic: should DMA allocation be executed with atomic flag
  */
 int ipahal_rt_generate_empty_img(u32 tbls_num, u32 hash_hdr_size,
-	u32 nhash_hdr_size, struct ipa_mem_buffer *mem);
+	u32 nhash_hdr_size, struct ipa_mem_buffer *mem, bool atomic);
 
 /*
  * ipahal_flt_generate_empty_img() - Generate empty filter image
@@ -185,9 +186,11 @@
  * @ep_bitmap: Bitmap representing the EP that has flt tables. The format
  *  should be: bit0->EP0, bit1->EP1
  * @mem: mem object that points to DMA mem representing the hdr structure
+ * @atomic: should DMA allocation be executed with atomic flag
  */
 int ipahal_flt_generate_empty_img(u32 tbls_num, u32 hash_hdr_size,
-	u32 nhash_hdr_size, u64 ep_bitmap, struct ipa_mem_buffer *mem);
+	u32 nhash_hdr_size, u64 ep_bitmap, struct ipa_mem_buffer *mem,
+	bool atomic);
 
 /*
  * ipahal_fltrt_allocate_hw_tbl_imgs() - Allocate tbl images DMA structures
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.c b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.c
index 30fd737..2a780b6 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.c
@@ -44,6 +44,7 @@
 	__stringify(IPA_ENDP_INIT_MODE_n),
 	__stringify(IPA_ENDP_INIT_NAT_n),
 	__stringify(IPA_ENDP_INIT_CTRL_n),
+	__stringify(IPA_ENDP_INIT_CTRL_SCND_n),
 	__stringify(IPA_ENDP_INIT_HOL_BLOCK_EN_n),
 	__stringify(IPA_ENDP_INIT_HOL_BLOCK_TIMER_n),
 	__stringify(IPA_ENDP_INIT_DEAGGR_n),
@@ -645,6 +646,17 @@
 		IPA_ENDP_INIT_CTRL_n_ENDP_DELAY_BMSK);
 }
 
+static void ipareg_construct_endp_init_ctrl_scnd_n(enum ipahal_reg_name reg,
+	const void *fields, u32 *val)
+{
+	struct ipahal_ep_cfg_ctrl_scnd *ep_ctrl_scnd =
+		(struct ipahal_ep_cfg_ctrl_scnd *)fields;
+
+	IPA_SETFIELD_IN_REG(*val, ep_ctrl_scnd->endp_delay,
+		IPA_ENDP_INIT_CTRL_SCND_n_ENDP_DELAY_SHFT,
+		IPA_ENDP_INIT_CTRL_SCND_n_ENDP_DELAY_BMSK);
+}
+
 static void ipareg_construct_endp_init_nat_n(enum ipahal_reg_name reg,
 		const void *fields, u32 *val)
 {
@@ -1026,6 +1038,9 @@
 	[IPA_HW_v3_0][IPA_ENDP_INIT_CTRL_n] = {
 		ipareg_construct_endp_init_ctrl_n, ipareg_parse_dummy,
 		0x00000800, 0x70},
+	[IPA_HW_v3_0][IPA_ENDP_INIT_CTRL_SCND_n] = {
+		ipareg_construct_endp_init_ctrl_scnd_n, ipareg_parse_dummy,
+		0x00000804, 0x70 },
 	[IPA_HW_v3_0][IPA_ENDP_INIT_HOL_BLOCK_EN_n] = {
 		ipareg_construct_endp_init_hol_block_en_n,
 		ipareg_parse_dummy,
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.h b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.h
index 8b6ed39..4490103 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.h
+++ b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.h
@@ -47,6 +47,7 @@
 	IPA_ENDP_INIT_MODE_n,
 	IPA_ENDP_INIT_NAT_n,
 	IPA_ENDP_INIT_CTRL_n,
+	IPA_ENDP_INIT_CTRL_SCND_n,
 	IPA_ENDP_INIT_HOL_BLOCK_EN_n,
 	IPA_ENDP_INIT_HOL_BLOCK_TIMER_n,
 	IPA_ENDP_INIT_DEAGGR_n,
@@ -343,6 +344,14 @@
 };
 
 /*
+ * struct ipa_ep_cfg_ctrl_scnd - PA_ENDP_INIT_CTRL_SCND_n register
+ * @endp_delay: delay endpoint
+ */
+struct ipahal_ep_cfg_ctrl_scnd {
+	bool endp_delay;
+};
+
+/*
  * ipahal_reg_name_str() - returns string that represent the register
  * @reg_name: [in] register name
  */
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg_i.h b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg_i.h
index 342803f..6d69b15 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg_i.h
+++ b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg_i.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -122,6 +122,10 @@
 #define IPA_ENDP_INIT_CTRL_n_ENDP_DELAY_BMSK 0x2
 #define IPA_ENDP_INIT_CTRL_n_ENDP_DELAY_SHFT 0x1
 
+/* IPA_ENDP_INIT_CTRL_SCND_n register */
+#define IPA_ENDP_INIT_CTRL_SCND_n_ENDP_DELAY_BMSK 0x2
+#define IPA_ENDP_INIT_CTRL_SCND_n_ENDP_DELAY_SHFT 0x1
+
 /* IPA_ENDP_INIT_HOL_BLOCK_EN_n register */
 #define IPA_ENDP_INIT_HOL_BLOCK_EN_n_RMSK 0x1
 #define IPA_ENDP_INIT_HOL_BLOCK_EN_n_MAX 19
diff --git a/drivers/platform/msm/ipa/ipa_v3/teth_bridge.c b/drivers/platform/msm/ipa/ipa_v3/teth_bridge.c
index 3ed3e44..297f932 100644
--- a/drivers/platform/msm/ipa/ipa_v3/teth_bridge.c
+++ b/drivers/platform/msm/ipa/ipa_v3/teth_bridge.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -87,8 +87,7 @@
 *  definition for more info)
 *
 * USB driver gets a pointer to a callback function (usb_notify_cb) and an
-* associated data. USB driver installs this callback function in the call to
-* ipa3_connect().
+* associated data.
 *
 * Builds IPA resource manager dependency graph.
 *
diff --git a/drivers/platform/msm/ipa/test/Makefile b/drivers/platform/msm/ipa/test/Makefile
index e1686e6..c20fd2b 100644
--- a/drivers/platform/msm/ipa/test/Makefile
+++ b/drivers/platform/msm/ipa/test/Makefile
@@ -1,2 +1,2 @@
 obj-$(CONFIG_IPA_UT) += ipa_ut_mod.o
-ipa_ut_mod-y := ipa_ut_framework.o ipa_test_example.o ipa_test_mhi.o
+ipa_ut_mod-y := ipa_ut_framework.o ipa_test_example.o ipa_test_mhi.o ipa_test_dma.o
diff --git a/drivers/platform/msm/ipa/test/ipa_test_dma.c b/drivers/platform/msm/ipa/test/ipa_test_dma.c
new file mode 100644
index 0000000..07be1c3
--- /dev/null
+++ b/drivers/platform/msm/ipa/test/ipa_test_dma.c
@@ -0,0 +1,1050 @@
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/ipa.h>
+#include "../ipa_v3/ipa_i.h"
+#include "ipa_ut_framework.h"
+
+#define IPA_TEST_DMA_WQ_NAME_BUFF_SZ		64
+#define IPA_TEST_DMA_MT_TEST_NUM_WQ		400
+#define IPA_TEST_DMA_MEMCPY_BUFF_SIZE		16384
+#define IPA_TEST_DMA_MAX_PKT_SIZE		0xFF00
+#define IPA_DMA_TEST_LOOP_NUM			1000
+#define IPA_DMA_TEST_INT_LOOP_NUM		50
+#define IPA_DMA_TEST_ASYNC_PARALLEL_LOOP_NUM	128
+#define IPA_DMA_RUN_TEST_UNIT_IN_LOOP(test_unit, iters, rc, args...)	\
+	do {								\
+		int __i;						\
+		for (__i = 0; __i < iters; __i++) {	\
+			IPA_UT_LOG(#test_unit " START iter %d\n", __i);	\
+			rc = test_unit(args);				\
+			if (!rc)					\
+				continue;				\
+			IPA_UT_LOG(#test_unit " failed %d\n", rc);	\
+			break;						\
+		}							\
+	} while (0)
+
+/**
+ * struct ipa_test_dma_async_user_data - user_data structure for async memcpy
+ * @src_mem: source memory buffer
+ * @dest_mem: destination memory buffer
+ * @call_serial_number: Id of the caller
+ * @copy_done: Completion object
+ */
+struct ipa_test_dma_async_user_data {
+	struct ipa_mem_buffer src_mem;
+	struct ipa_mem_buffer dest_mem;
+	int call_serial_number;
+	struct completion copy_done;
+};
+
+/**
+ * ipa_test_dma_setup() - Suite setup function
+ */
+static int ipa_test_dma_setup(void **ppriv)
+{
+	int rc;
+
+	IPA_UT_DBG("Start Setup\n");
+
+	if (!ipa3_ctx) {
+		IPA_UT_ERR("No IPA ctx\n");
+		return -EINVAL;
+	}
+
+	rc = ipa_dma_init();
+	if (rc)
+		IPA_UT_ERR("Fail to init ipa_dma - return code %d\n", rc);
+	else
+		IPA_UT_DBG("ipa_dma_init() Completed successfully!\n");
+
+	*ppriv = NULL;
+
+	return rc;
+}
+
+/**
+ * ipa_test_dma_teardown() - Suite teardown function
+ */
+static int ipa_test_dma_teardown(void *priv)
+{
+	IPA_UT_DBG("Start Teardown\n");
+	ipa_dma_destroy();
+	return 0;
+}
+
+static int ipa_test_dma_alloc_buffs(struct ipa_mem_buffer *src,
+				struct ipa_mem_buffer *dest,
+				int size)
+{
+	int i;
+	static int val = 1;
+	int rc;
+
+	val++;
+	src->size = size;
+	src->base = dma_alloc_coherent(ipa3_ctx->pdev, src->size,
+				       &src->phys_base, GFP_KERNEL);
+	if (!src->base) {
+		IPA_UT_LOG("fail to alloc dma mem %d bytes\n", size);
+		IPA_UT_TEST_FAIL_REPORT("fail to alloc dma mem");
+		return -ENOMEM;
+	}
+
+	dest->size = size;
+	dest->base = dma_alloc_coherent(ipa3_ctx->pdev, dest->size,
+					&dest->phys_base, GFP_KERNEL);
+	if (!dest->base) {
+		IPA_UT_LOG("fail to alloc dma mem %d bytes\n", size);
+		IPA_UT_TEST_FAIL_REPORT("fail to alloc dma mem");
+		rc = -ENOMEM;
+		goto fail_alloc_dest;
+	}
+
+	memset(dest->base, 0, dest->size);
+	for (i = 0; i < src->size; i++)
+		memset(src->base + i, (val + i) & 0xFF, 1);
+	rc = memcmp(dest->base, src->base, dest->size);
+	if (rc == 0) {
+		IPA_UT_LOG("dest & src buffers are equal\n");
+		IPA_UT_TEST_FAIL_REPORT("dest & src buffers are equal");
+		rc = -EFAULT;
+		goto fail_buf_cmp;
+	}
+
+	return 0;
+
+fail_buf_cmp:
+	dma_free_coherent(ipa3_ctx->pdev, dest->size, dest->base,
+		dest->phys_base);
+fail_alloc_dest:
+	dma_free_coherent(ipa3_ctx->pdev, src->size, src->base,
+		src->phys_base);
+	return rc;
+}
+
+static void ipa_test_dma_destroy_buffs(struct ipa_mem_buffer *src,
+				struct ipa_mem_buffer *dest)
+{
+	dma_free_coherent(ipa3_ctx->pdev, src->size, src->base,
+		src->phys_base);
+	dma_free_coherent(ipa3_ctx->pdev, dest->size, dest->base,
+		dest->phys_base);
+}
+
+/**
+ * ipa_test_dma_memcpy_sync() - memcpy in sync mode
+ *
+ * @size: buffer size
+ * @expect_fail: test expects the memcpy to fail
+ *
+ * To be run during tests
+ * 1. Alloc src and dst buffers
+ * 2. sync memcpy src to dst via dma
+ * 3. compare src and dts if memcpy succeeded as expected
+ */
+static int ipa_test_dma_memcpy_sync(int size, bool expect_fail)
+{
+	int rc = 0;
+	int i;
+	struct ipa_mem_buffer src_mem;
+	struct ipa_mem_buffer dest_mem;
+	u8 *src;
+	u8 *dest;
+
+	rc = ipa_test_dma_alloc_buffs(&src_mem, &dest_mem, size);
+	if (rc) {
+		IPA_UT_LOG("fail to alloc buffers\n");
+		IPA_UT_TEST_FAIL_REPORT("fail to alloc buffers");
+		return rc;
+	}
+
+	rc = ipa_dma_sync_memcpy(dest_mem.phys_base, src_mem.phys_base, size);
+	if (!expect_fail && rc) {
+		IPA_UT_LOG("fail to sync memcpy - rc = %d\n", rc);
+		IPA_UT_TEST_FAIL_REPORT("sync memcpy failed");
+		goto free_buffs;
+	}
+	if (expect_fail && !rc) {
+		IPA_UT_LOG("sync memcpy succeeded while expected to fail\n");
+		IPA_UT_TEST_FAIL_REPORT(
+			"sync memcpy succeeded while expected to fail");
+		rc = -EFAULT;
+		goto free_buffs;
+	}
+
+	if (!rc) {
+		/* if memcpy succeeded, compare the buffers */
+		rc = memcmp(dest_mem.base, src_mem.base, size);
+		if (rc) {
+			IPA_UT_LOG("BAD memcpy - buffs are not equals\n");
+			IPA_UT_TEST_FAIL_REPORT(
+				"BAD memcpy - buffs are not equals");
+			src = src_mem.base;
+			dest = dest_mem.base;
+			for (i = 0; i < size; i++)  {
+				if (*(src + i) != *(dest + i)) {
+					IPA_UT_LOG("byte: %d 0x%x != 0x%x\n",
+						i, *(src + i), *(dest + i));
+				}
+			}
+		}
+	} else {
+		/* if memcpy failed as expected, update the rc */
+		rc = 0;
+	}
+
+free_buffs:
+	ipa_test_dma_destroy_buffs(&src_mem, &dest_mem);
+	return rc;
+}
+
+static void ipa_test_dma_async_memcpy_cb(void *comp_obj)
+{
+	struct completion *xfer_done;
+
+	if (!comp_obj) {
+		IPA_UT_ERR("Invalid Input\n");
+		return;
+	}
+	xfer_done = (struct completion *)comp_obj;
+	complete(xfer_done);
+}
+
+static void ipa_test_dma_async_memcpy_cb_user_data(void *user_param)
+{
+	int rc;
+	int i;
+	u8 *src;
+	u8 *dest;
+	struct ipa_test_dma_async_user_data *udata =
+		(struct ipa_test_dma_async_user_data *)user_param;
+
+	if (!udata) {
+		IPA_UT_ERR("Invalid user param\n");
+		return;
+	}
+
+	rc = memcmp(udata->dest_mem.base, udata->src_mem.base,
+		udata->src_mem.size);
+	if (rc) {
+		IPA_UT_LOG("BAD memcpy - buffs are not equal sn=%d\n",
+			udata->call_serial_number);
+		IPA_UT_TEST_FAIL_REPORT(
+			"BAD memcpy - buffs are not equal");
+		src = udata->src_mem.base;
+		dest = udata->dest_mem.base;
+		for (i = 0; i < udata->src_mem.size; i++)  {
+			if (*(src + i) != *(dest + i)) {
+				IPA_UT_ERR("byte: %d 0x%x != 0x%x\n", i,
+					   *(src + i), *(dest + i));
+			}
+		}
+		return;
+	}
+
+	IPA_UT_LOG("Notify on async memcopy sn=%d\n",
+		udata->call_serial_number);
+	complete(&(udata->copy_done));
+}
+
+/**
+ * ipa_test_dma_memcpy_async() - memcpy in async mode
+ *
+ * @size: buffer size
+ * @expect_fail: test expected the memcpy to fail
+ *
+ * To be run during tests
+ * 1. Alloc src and dst buffers
+ * 2. async memcpy src to dst via dma and wait for completion
+ * 3. compare src and dts if memcpy succeeded as expected
+ */
+static int ipa_test_dma_memcpy_async(int size, bool expect_fail)
+{
+	int rc = 0;
+	int i;
+	struct ipa_mem_buffer src_mem;
+	struct ipa_mem_buffer dest_mem;
+	u8 *src;
+	u8 *dest;
+	struct completion xfer_done;
+
+	rc = ipa_test_dma_alloc_buffs(&src_mem, &dest_mem, size);
+	if (rc) {
+		IPA_UT_LOG("fail to alloc buffers\n");
+		IPA_UT_TEST_FAIL_REPORT("fail to alloc buffers");
+		return rc;
+	}
+
+	init_completion(&xfer_done);
+	rc = ipa_dma_async_memcpy(dest_mem.phys_base, src_mem.phys_base, size,
+		ipa_test_dma_async_memcpy_cb, &xfer_done);
+	if (!expect_fail && rc) {
+		IPA_UT_LOG("fail to initiate async memcpy - rc=%d\n",
+			rc);
+		IPA_UT_TEST_FAIL_REPORT("async memcpy initiate failed");
+		goto free_buffs;
+	}
+	if (expect_fail && !rc) {
+		IPA_UT_LOG("async memcpy succeeded while expected to fail\n");
+		IPA_UT_TEST_FAIL_REPORT(
+			"async memcpy succeeded while expected to fail");
+		rc = -EFAULT;
+		goto free_buffs;
+	}
+
+	if (!rc) {
+		/* if memcpy succeeded, compare the buffers */
+		wait_for_completion(&xfer_done);
+		rc = memcmp(dest_mem.base, src_mem.base, size);
+		if (rc) {
+			IPA_UT_LOG("BAD memcpy - buffs are not equals\n");
+			IPA_UT_TEST_FAIL_REPORT(
+				"BAD memcpy - buffs are not equals");
+			src = src_mem.base;
+			dest = dest_mem.base;
+			for (i = 0; i < size; i++)  {
+				if (*(src + i) != *(dest + i)) {
+					IPA_UT_LOG("byte: %d 0x%x != 0x%x\n",
+						i, *(src + i), *(dest + i));
+				}
+			}
+		}
+	} else {
+		/* if memcpy failed as expected, update the rc */
+		rc = 0;
+	}
+
+free_buffs:
+	ipa_test_dma_destroy_buffs(&src_mem, &dest_mem);
+	return rc;
+}
+
+/**
+ * ipa_test_dma_sync_async_memcpy() - memcpy in sync and then async mode
+ *
+ * @size: buffer size
+ *
+ * To be run during tests
+ * 1. several sync memcopy in row
+ * 2. several async memcopy -
+ *	back-to-back (next async try initiated after prev is completed)
+ */
+static int ipa_test_dma_sync_async_memcpy(int size)
+{
+	int rc;
+
+	IPA_DMA_RUN_TEST_UNIT_IN_LOOP(ipa_test_dma_memcpy_sync,
+		IPA_DMA_TEST_INT_LOOP_NUM, rc, size, false);
+	if (rc) {
+		IPA_UT_LOG("sync memcopy fail rc=%d\n", rc);
+		IPA_UT_TEST_FAIL_REPORT("sync memcopy fail");
+		return rc;
+	}
+
+	IPA_DMA_RUN_TEST_UNIT_IN_LOOP(ipa_test_dma_memcpy_async,
+		IPA_DMA_TEST_INT_LOOP_NUM, rc, size, false);
+	if (rc) {
+		IPA_UT_LOG("async memcopy fail rc=%d\n", rc);
+		IPA_UT_TEST_FAIL_REPORT("async memcopy fail");
+		return rc;
+	}
+
+	return 0;
+}
+
+/**
+ * TEST: test control API - enable/disable dma
+ *	1. enable dma
+ *	2. disable dma
+ */
+static int ipa_test_dma_control_api(void *priv)
+{
+	int rc;
+
+	IPA_UT_LOG("Test Start\n");
+
+	rc = ipa_dma_enable();
+	if (rc) {
+		IPA_UT_LOG("DMA enable failed rc=%d\n", rc);
+		IPA_UT_TEST_FAIL_REPORT("fail enable dma");
+		return rc;
+	}
+
+	rc = ipa_dma_disable();
+	if (rc) {
+		IPA_UT_LOG("DMA disable failed rc=%d\n", rc);
+		IPA_UT_TEST_FAIL_REPORT("fail disable dma");
+		return rc;
+	}
+
+	return 0;
+}
+
+/**
+ * TEST: memcpy before dma enable
+ *
+ *	1. sync memcpy - should fail
+ *	2. async memcpy - should fail
+ */
+static int ipa_test_dma_memcpy_before_enable(void *priv)
+{
+	int rc;
+
+	IPA_UT_LOG("Test Start\n");
+
+	rc = ipa_test_dma_memcpy_sync(IPA_TEST_DMA_MEMCPY_BUFF_SIZE, true);
+	if (rc) {
+		IPA_UT_LOG("sync memcpy succeeded unexpectedly rc=%d\n", rc);
+		IPA_UT_TEST_FAIL_REPORT("sync memcpy succeeded unexpectedly");
+		return rc;
+	}
+
+	rc = ipa_test_dma_memcpy_async(IPA_TEST_DMA_MEMCPY_BUFF_SIZE, true);
+	if (rc) {
+		IPA_UT_LOG("async memcpy succeeded unexpectedly rc=%d\n", rc);
+		IPA_UT_TEST_FAIL_REPORT("sync memcpy succeeded unexpectedly");
+		return rc;
+	}
+
+	return 0;
+}
+
+/**
+ * TEST: Sync memory copy
+ *
+ *	1. dma enable
+ *	2. sync memcpy
+ *	3. dma disable
+ */
+static int ipa_test_dma_sync_memcpy(void *priv)
+{
+	int rc;
+
+	IPA_UT_LOG("Test Start\n");
+
+	rc = ipa_dma_enable();
+	if (rc) {
+		IPA_UT_LOG("DMA enable failed rc=%d\n", rc);
+		IPA_UT_TEST_FAIL_REPORT("fail enable dma");
+		return rc;
+	}
+
+	rc = ipa_test_dma_memcpy_sync(IPA_TEST_DMA_MEMCPY_BUFF_SIZE, false);
+	if (rc) {
+		IPA_UT_LOG("sync memcpy failed rc=%d\n", rc);
+		IPA_UT_TEST_FAIL_REPORT("sync memcpy failed");
+		(void)ipa_dma_disable();
+		return rc;
+	}
+
+	rc = ipa_dma_disable();
+	if (rc) {
+		IPA_UT_LOG("DMA disable failed rc=%d\n", rc);
+		IPA_UT_TEST_FAIL_REPORT("fail disable dma");
+		return rc;
+	}
+
+	return 0;
+}
+
+/**
+* TEST: Small sync memory copy
+*
+*	1. dma enable
+*	2. small sync memcpy
+*	3. small sync memcpy
+*	4. dma disable
+*/
+static int ipa_test_dma_sync_memcpy_small(void *priv)
+{
+	int rc;
+
+	IPA_UT_LOG("Test Start\n");
+
+	rc = ipa_dma_enable();
+	if (rc) {
+		IPA_UT_LOG("DMA enable failed rc=%d\n", rc);
+		IPA_UT_TEST_FAIL_REPORT("fail enable dma");
+		return rc;
+	}
+
+	rc = ipa_test_dma_memcpy_sync(4, false);
+	if (rc) {
+		IPA_UT_LOG("sync memcpy failed rc=%d\n", rc);
+		IPA_UT_TEST_FAIL_REPORT("sync memcpy failed");
+		(void)ipa_dma_disable();
+		return rc;
+	}
+
+	rc = ipa_test_dma_memcpy_sync(7, false);
+	if (rc) {
+		IPA_UT_LOG("sync memcpy failed rc=%d\n", rc);
+		IPA_UT_TEST_FAIL_REPORT("sync memcpy failed");
+		(void)ipa_dma_disable();
+		return rc;
+	}
+
+	rc = ipa_dma_disable();
+	if (rc) {
+		IPA_UT_LOG("DMA disable failed rc=%d\n", rc);
+		IPA_UT_TEST_FAIL_REPORT("fail disable dma");
+		return rc;
+	}
+
+	return 0;
+}
+
+/**
+ * TEST: Async memory copy
+ *
+ *	1. dma enable
+ *	2. async memcpy
+ *	3. dma disable
+ */
+static int ipa_test_dma_async_memcpy(void *priv)
+{
+	int rc;
+
+	IPA_UT_LOG("Test Start\n");
+
+	rc = ipa_dma_enable();
+	if (rc) {
+		IPA_UT_LOG("DMA enable failed rc=%d\n", rc);
+		IPA_UT_TEST_FAIL_REPORT("fail enable dma");
+		return rc;
+	}
+
+	rc = ipa_test_dma_memcpy_async(IPA_TEST_DMA_MEMCPY_BUFF_SIZE, false);
+	if (rc) {
+		IPA_UT_LOG("async memcpy failed rc=%d\n", rc);
+		IPA_UT_TEST_FAIL_REPORT("async memcpy failed");
+		(void)ipa_dma_disable();
+		return rc;
+	}
+
+	rc = ipa_dma_disable();
+	if (rc) {
+		IPA_UT_LOG("DMA disable failed rc=%d\n", rc);
+		IPA_UT_TEST_FAIL_REPORT("fail disable dma");
+		return rc;
+	}
+
+	return 0;
+}
+
+/**
+ * TEST: Small async memory copy
+ *
+ *	1. dma enable
+ *	2. async memcpy
+ *	3. async memcpy
+ *	4. dma disable
+ */
+static int ipa_test_dma_async_memcpy_small(void *priv)
+{
+	int rc;
+
+	IPA_UT_LOG("Test Start\n");
+
+	rc = ipa_dma_enable();
+	if (rc) {
+		IPA_UT_LOG("DMA enable failed rc=%d\n", rc);
+		IPA_UT_TEST_FAIL_REPORT("fail enable dma");
+		return rc;
+	}
+
+	rc = ipa_test_dma_memcpy_async(4, false);
+	if (rc) {
+		IPA_UT_LOG("async memcpy failed rc=%d\n", rc);
+		IPA_UT_TEST_FAIL_REPORT("async memcpy failed");
+		(void)ipa_dma_disable();
+		return rc;
+	}
+
+	rc = ipa_test_dma_memcpy_async(7, false);
+	if (rc) {
+		IPA_UT_LOG("async memcpy failed rc=%d\n", rc);
+		IPA_UT_TEST_FAIL_REPORT("async memcpy failed");
+		(void)ipa_dma_disable();
+		return rc;
+	}
+
+	rc = ipa_dma_disable();
+	if (rc) {
+		IPA_UT_LOG("DMA disable failed rc=%d\n", rc);
+		IPA_UT_TEST_FAIL_REPORT("fail disable dma");
+		return rc;
+	}
+
+	return 0;
+}
+
+/**
+ * TEST: Iteration of sync memory copy
+ *
+ *	1. dma enable
+ *	2. sync memcpy in loop - in row
+ *	3. dma disable
+ */
+static int ipa_test_dma_sync_memcpy_in_loop(void *priv)
+{
+	int rc;
+
+	IPA_UT_LOG("Test Start\n");
+
+	rc = ipa_dma_enable();
+	if (rc) {
+		IPA_UT_LOG("DMA enable failed rc=%d\n", rc);
+		IPA_UT_TEST_FAIL_REPORT("fail enable dma");
+		return rc;
+	}
+
+	IPA_DMA_RUN_TEST_UNIT_IN_LOOP(ipa_test_dma_memcpy_sync,
+		IPA_DMA_TEST_LOOP_NUM, rc,
+		IPA_TEST_DMA_MEMCPY_BUFF_SIZE, false);
+	if (rc) {
+		IPA_UT_LOG("Iterations of sync memcpy failed rc=%d\n", rc);
+		IPA_UT_TEST_FAIL_REPORT("Iterations of sync memcpy failed");
+		(void)ipa_dma_disable();
+		return rc;
+	}
+
+	rc = ipa_dma_disable();
+	if (rc) {
+		IPA_UT_LOG("DMA disable failed rc=%d\n", rc);
+		IPA_UT_TEST_FAIL_REPORT("fail disable dma");
+		return rc;
+	}
+
+	return 0;
+}
+
+/**
+ * TEST: Iteration of async memory copy
+ *
+ *	1. dma enable
+ *	2. async memcpy in loop - back-to-back
+ *		next async copy is initiated once previous one completed
+ *	3. dma disable
+ */
+static int ipa_test_dma_async_memcpy_in_loop(void *priv)
+{
+	int rc;
+
+	IPA_UT_LOG("Test Start\n");
+
+	rc = ipa_dma_enable();
+	if (rc) {
+		IPA_UT_LOG("DMA enable failed rc=%d\n", rc);
+		IPA_UT_TEST_FAIL_REPORT("fail enable dma");
+		return rc;
+	}
+
+	IPA_DMA_RUN_TEST_UNIT_IN_LOOP(ipa_test_dma_memcpy_async,
+		IPA_DMA_TEST_LOOP_NUM, rc,
+		IPA_TEST_DMA_MEMCPY_BUFF_SIZE, false);
+	if (rc) {
+		IPA_UT_LOG("Iterations of async memcpy failed rc=%d\n", rc);
+		IPA_UT_TEST_FAIL_REPORT("Iterations of async memcpy failed");
+		(void)ipa_dma_disable();
+		return rc;
+	}
+
+	rc = ipa_dma_disable();
+	if (rc) {
+		IPA_UT_LOG("DMA disable failed rc=%d\n", rc);
+		IPA_UT_TEST_FAIL_REPORT("fail disable dma");
+		return rc;
+	}
+
+	return 0;
+}
+
+/**
+ * TEST: Iteration of interleaved sync and async memory copy
+ *
+ *	1. dma enable
+ *	2. sync and async memcpy in loop - interleaved
+ *	3. dma disable
+ */
+static int ipa_test_dma_interleaved_sync_async_memcpy_in_loop(void *priv)
+{
+	int rc;
+
+	IPA_UT_LOG("Test Start\n");
+
+	rc = ipa_dma_enable();
+	if (rc) {
+		IPA_UT_LOG("DMA enable failed rc=%d\n", rc);
+		IPA_UT_TEST_FAIL_REPORT("fail enable dma");
+		return rc;
+	}
+
+	IPA_DMA_RUN_TEST_UNIT_IN_LOOP(ipa_test_dma_sync_async_memcpy,
+		IPA_DMA_TEST_INT_LOOP_NUM, rc,
+		IPA_TEST_DMA_MEMCPY_BUFF_SIZE);
+	if (rc) {
+		IPA_UT_LOG(
+			"Iterations of interleaved sync async memcpy failed rc=%d\n"
+			, rc);
+		IPA_UT_TEST_FAIL_REPORT(
+			"Iterations of interleaved sync async memcpy failed");
+		(void)ipa_dma_disable();
+		return rc;
+	}
+
+	rc = ipa_dma_disable();
+	if (rc) {
+		IPA_UT_LOG("DMA disable failed rc=%d\n", rc);
+		IPA_UT_TEST_FAIL_REPORT("fail disable dma");
+		return rc;
+	}
+
+	return 0;
+}
+
+static atomic_t ipa_test_dma_mt_test_pass;
+
+struct one_memcpy_work {
+	struct work_struct work_s;
+	int size;
+};
+
+static void ipa_test_dma_wrapper_test_one_sync(struct work_struct *work)
+{
+	int rc;
+	struct one_memcpy_work *data =
+		container_of(work, struct one_memcpy_work, work_s);
+
+	rc = ipa_test_dma_memcpy_sync(data->size, false);
+	if (rc) {
+		IPA_UT_LOG("fail sync memcpy from thread rc=%d\n", rc);
+		IPA_UT_TEST_FAIL_REPORT("fail sync memcpy from thread");
+		return;
+	}
+	atomic_inc(&ipa_test_dma_mt_test_pass);
+}
+
+static void ipa_test_dma_wrapper_test_one_async(struct work_struct *work)
+{
+	int rc;
+	struct one_memcpy_work *data =
+		container_of(work, struct one_memcpy_work, work_s);
+
+	rc = ipa_test_dma_memcpy_async(data->size, false);
+	if (rc) {
+		IPA_UT_LOG("fail async memcpy from thread rc=%d\n", rc);
+		IPA_UT_TEST_FAIL_REPORT("fail async memcpy from thread");
+		return;
+	}
+	atomic_inc(&ipa_test_dma_mt_test_pass);
+}
+
+/**
+ * TEST: Multiple threads running sync and sync mem copy
+ *
+ *	1. dma enable
+ *	2. In-loop
+ *		2.1 create wq for sync memcpy
+ *		2.2 create wq for async memcpy
+ *		2.3 queue sync memcpy work
+ *		2.4 queue async memcoy work
+ *	3. In-loop
+ *		3.1 flush and destroy wq sync
+ *		3.2 flush and destroy wq async
+ *	3. dma disable
+ */
+static int ipa_test_dma_mt_sync_async(void *priv)
+{
+	int rc;
+	int i;
+	static struct workqueue_struct *wq_sync[IPA_TEST_DMA_MT_TEST_NUM_WQ];
+	static struct workqueue_struct *wq_async[IPA_TEST_DMA_MT_TEST_NUM_WQ];
+	static struct one_memcpy_work async[IPA_TEST_DMA_MT_TEST_NUM_WQ];
+	static struct one_memcpy_work sync[IPA_TEST_DMA_MT_TEST_NUM_WQ];
+	char buff[IPA_TEST_DMA_WQ_NAME_BUFF_SZ];
+
+	memset(wq_sync, 0, sizeof(wq_sync));
+	memset(wq_sync, 0, sizeof(wq_async));
+	memset(async, 0, sizeof(async));
+	memset(sync, 0, sizeof(sync));
+
+	rc = ipa_dma_enable();
+	if (rc) {
+		IPA_UT_LOG("DMA enable failed rc=%d\n", rc);
+		IPA_UT_TEST_FAIL_REPORT("fail enable dma");
+		return rc;
+	}
+
+	atomic_set(&ipa_test_dma_mt_test_pass, 0);
+	for (i = 0; i < IPA_TEST_DMA_MT_TEST_NUM_WQ; i++) {
+		snprintf(buff, sizeof(buff), "ipa_test_dmaSwq%d", i);
+		wq_sync[i] = create_singlethread_workqueue(buff);
+		if (!wq_sync[i]) {
+			IPA_UT_ERR("failed to create sync wq#%d\n", i);
+			rc = -EFAULT;
+			goto fail_create_wq;
+		}
+		snprintf(buff, IPA_RESOURCE_NAME_MAX, "ipa_test_dmaAwq%d", i);
+		wq_async[i] = create_singlethread_workqueue(buff);
+		if (!wq_async[i]) {
+			IPA_UT_ERR("failed to create async wq#%d\n", i);
+			rc = -EFAULT;
+			goto fail_create_wq;
+		}
+
+		if (i % 2) {
+			sync[i].size = IPA_TEST_DMA_MEMCPY_BUFF_SIZE;
+			async[i].size = IPA_TEST_DMA_MEMCPY_BUFF_SIZE;
+		} else {
+			sync[i].size = 4;
+			async[i].size = 4;
+		}
+		INIT_WORK(&sync[i].work_s, ipa_test_dma_wrapper_test_one_sync);
+		queue_work(wq_sync[i], &sync[i].work_s);
+		INIT_WORK(&async[i].work_s,
+			ipa_test_dma_wrapper_test_one_async);
+		queue_work(wq_async[i], &async[i].work_s);
+	}
+
+	for (i = 0; i < IPA_TEST_DMA_MT_TEST_NUM_WQ; i++) {
+		flush_workqueue(wq_sync[i]);
+		destroy_workqueue(wq_sync[i]);
+		flush_workqueue(wq_async[i]);
+		destroy_workqueue(wq_async[i]);
+	}
+
+	rc = ipa_dma_disable();
+	if (rc) {
+		IPA_UT_LOG("DMA disable failed rc=%d\n", rc);
+		IPA_UT_TEST_FAIL_REPORT("fail disable dma");
+		return rc;
+	}
+
+	if ((2 * IPA_TEST_DMA_MT_TEST_NUM_WQ) !=
+		atomic_read(&ipa_test_dma_mt_test_pass)) {
+		IPA_UT_LOG(
+			"Multi-threaded sync/async memcopy failed passed=%d\n"
+			, atomic_read(&ipa_test_dma_mt_test_pass));
+		IPA_UT_TEST_FAIL_REPORT(
+			"Multi-threaded sync/async memcopy failed");
+		return -EFAULT;
+	}
+
+	return 0;
+
+fail_create_wq:
+	(void)ipa_dma_disable();
+	for (i = 0; i < IPA_TEST_DMA_MT_TEST_NUM_WQ; i++) {
+		if (wq_sync[i])
+			destroy_workqueue(wq_sync[i]);
+		if (wq_async[i])
+			destroy_workqueue(wq_async[i]);
+	}
+
+	return rc;
+}
+
+/**
+ * TEST: Several parallel async memory copy iterations
+ *
+ *	1. create several user_data structures - one per iteration
+ *	2. allocate buffs. Give slice for each iteration
+ *	3. iterations of async mem copy
+ *	4. wait for all to complete
+ *	5. dma disable
+ */
+static int ipa_test_dma_parallel_async_memcpy_in_loop(void *priv)
+{
+	int rc;
+	struct ipa_test_dma_async_user_data *udata;
+	struct ipa_mem_buffer all_src_mem;
+	struct ipa_mem_buffer all_dest_mem;
+	int i;
+	bool is_fail = false;
+
+	IPA_UT_LOG("Test Start\n");
+
+	rc = ipa_dma_enable();
+	if (rc) {
+		IPA_UT_LOG("DMA enable failed rc=%d\n", rc);
+		IPA_UT_TEST_FAIL_REPORT("fail enable dma");
+		return rc;
+	}
+
+	udata = kzalloc(IPA_DMA_TEST_ASYNC_PARALLEL_LOOP_NUM *
+		sizeof(struct ipa_test_dma_async_user_data), GFP_KERNEL);
+	if (!udata) {
+		IPA_UT_ERR("fail allocate user_data array\n");
+		(void)ipa_dma_disable();
+		return -ENOMEM;
+	}
+
+	rc = ipa_test_dma_alloc_buffs(&all_src_mem, &all_dest_mem,
+		IPA_TEST_DMA_MEMCPY_BUFF_SIZE);
+	if (rc) {
+		IPA_UT_LOG("fail to alloc buffers\n");
+		IPA_UT_TEST_FAIL_REPORT("fail to alloc buffers");
+		kfree(udata);
+		(void)ipa_dma_disable();
+		return rc;
+	}
+
+	for (i = 0 ; i < IPA_DMA_TEST_ASYNC_PARALLEL_LOOP_NUM ; i++) {
+		udata[i].src_mem.size =
+			IPA_TEST_DMA_MEMCPY_BUFF_SIZE /
+			IPA_DMA_TEST_ASYNC_PARALLEL_LOOP_NUM;
+		udata[i].src_mem.base = all_src_mem.base + i *
+			(IPA_TEST_DMA_MEMCPY_BUFF_SIZE /
+			IPA_DMA_TEST_ASYNC_PARALLEL_LOOP_NUM);
+		udata[i].src_mem.phys_base = all_src_mem.phys_base + i *
+			(IPA_TEST_DMA_MEMCPY_BUFF_SIZE /
+			IPA_DMA_TEST_ASYNC_PARALLEL_LOOP_NUM);
+
+		udata[i].dest_mem.size =
+			(IPA_TEST_DMA_MEMCPY_BUFF_SIZE /
+			IPA_DMA_TEST_ASYNC_PARALLEL_LOOP_NUM);
+		udata[i].dest_mem.base = all_dest_mem.base + i *
+			(IPA_TEST_DMA_MEMCPY_BUFF_SIZE /
+			IPA_DMA_TEST_ASYNC_PARALLEL_LOOP_NUM);
+		udata[i].dest_mem.phys_base = all_dest_mem.phys_base + i *
+			(IPA_TEST_DMA_MEMCPY_BUFF_SIZE /
+			IPA_DMA_TEST_ASYNC_PARALLEL_LOOP_NUM);
+
+		udata[i].call_serial_number = i + 1;
+		init_completion(&(udata[i].copy_done));
+		rc = ipa_dma_async_memcpy(udata[i].dest_mem.phys_base,
+			udata[i].src_mem.phys_base,
+			(IPA_TEST_DMA_MEMCPY_BUFF_SIZE /
+			IPA_DMA_TEST_ASYNC_PARALLEL_LOOP_NUM),
+			ipa_test_dma_async_memcpy_cb_user_data, &udata[i]);
+		if (rc) {
+			IPA_UT_LOG("async memcpy initiation fail i=%d rc=%d\n",
+				i, rc);
+			is_fail = true;
+		}
+	}
+
+	for (i = 0; i < IPA_DMA_TEST_ASYNC_PARALLEL_LOOP_NUM ; i++)
+		wait_for_completion(&udata[i].copy_done);
+
+	ipa_test_dma_destroy_buffs(&all_src_mem, &all_dest_mem);
+	kfree(udata);
+	rc = ipa_dma_disable();
+	if (rc) {
+		IPA_UT_LOG("DMA disable failed rc=%d\n", rc);
+		IPA_UT_TEST_FAIL_REPORT("fail disable dma");
+		return rc;
+	}
+
+	if (is_fail) {
+		IPA_UT_LOG("async memcopy failed\n");
+		IPA_UT_TEST_FAIL_REPORT("async memcopy failed");
+		return -EFAULT;
+	}
+
+	return 0;
+}
+
+/**
+ * TEST: Sync memory copy
+ *
+ *	1. dma enable
+ *	2. sync memcpy with max packet size
+ *	3. dma disable
+ */
+static int ipa_test_dma_sync_memcpy_max_pkt_size(void *priv)
+{
+	int rc;
+
+	IPA_UT_LOG("Test Start\n");
+
+	rc = ipa_dma_enable();
+	if (rc) {
+		IPA_UT_LOG("DMA enable failed rc=%d\n", rc);
+		IPA_UT_TEST_FAIL_REPORT("fail enable dma");
+		return rc;
+	}
+
+	rc = ipa_test_dma_memcpy_sync(IPA_TEST_DMA_MAX_PKT_SIZE, false);
+	if (rc) {
+		IPA_UT_LOG("sync memcpy failed rc=%d\n", rc);
+		IPA_UT_TEST_FAIL_REPORT("sync memcpy failed");
+		(void)ipa_dma_disable();
+		return rc;
+	}
+
+	rc = ipa_dma_disable();
+	if (rc) {
+		IPA_UT_LOG("DMA disable failed rc=%d\n", rc);
+		IPA_UT_TEST_FAIL_REPORT("fail disable dma");
+		return rc;
+	}
+
+	return 0;
+}
+
+/* Suite definition block */
+IPA_UT_DEFINE_SUITE_START(dma, "DMA for GSI",
+	ipa_test_dma_setup, ipa_test_dma_teardown)
+{
+	IPA_UT_ADD_TEST(control_api,
+		"Control API",
+		ipa_test_dma_control_api,
+		true, IPA_HW_v3_0, IPA_HW_MAX),
+	IPA_UT_ADD_TEST(memcpy_before_enable,
+		"Call memcpy before dma enable and expect it to fail",
+		ipa_test_dma_memcpy_before_enable,
+		true, IPA_HW_v3_0, IPA_HW_MAX),
+	IPA_UT_ADD_TEST(sync_memcpy,
+		"Sync memory copy",
+		ipa_test_dma_sync_memcpy,
+		true, IPA_HW_v3_0, IPA_HW_MAX),
+	IPA_UT_ADD_TEST(sync_memcpy_small,
+		"Small Sync memory copy",
+		ipa_test_dma_sync_memcpy_small,
+		true, IPA_HW_v3_5, IPA_HW_MAX),
+	IPA_UT_ADD_TEST(async_memcpy,
+		"Async memory copy",
+		ipa_test_dma_async_memcpy,
+		true, IPA_HW_v3_0, IPA_HW_MAX),
+	IPA_UT_ADD_TEST(async_memcpy_small,
+		"Small async memory copy",
+		ipa_test_dma_async_memcpy_small,
+		true, IPA_HW_v3_5, IPA_HW_MAX),
+	IPA_UT_ADD_TEST(sync_memcpy_in_loop,
+		"Several sync memory copy iterations",
+		ipa_test_dma_sync_memcpy_in_loop,
+		true, IPA_HW_v3_0, IPA_HW_MAX),
+	IPA_UT_ADD_TEST(async_memcpy_in_loop,
+		"Several async memory copy iterations",
+		ipa_test_dma_async_memcpy_in_loop,
+		true, IPA_HW_v3_0, IPA_HW_MAX),
+	IPA_UT_ADD_TEST(interleaved_sync_async_memcpy_in_loop,
+		"Several interleaved sync and async memory copy iterations",
+		ipa_test_dma_interleaved_sync_async_memcpy_in_loop,
+		true, IPA_HW_v3_0, IPA_HW_MAX),
+	IPA_UT_ADD_TEST(multi_threaded_multiple_sync_async_memcpy,
+		"Several multi-threaded sync and async memory copy iterations",
+		ipa_test_dma_mt_sync_async,
+		true, IPA_HW_v3_0, IPA_HW_MAX),
+	IPA_UT_ADD_TEST(parallel_async_memcpy_in_loop,
+		"Several parallel async memory copy iterations",
+		ipa_test_dma_parallel_async_memcpy_in_loop,
+		true, IPA_HW_v3_0, IPA_HW_MAX),
+	IPA_UT_ADD_TEST(sync_memcpy_max_pkt_size,
+		"Sync memory copy with max packet size",
+		ipa_test_dma_sync_memcpy_max_pkt_size,
+		true, IPA_HW_v3_0, IPA_HW_MAX),
+} IPA_UT_DEFINE_SUITE_END(dma);
diff --git a/drivers/platform/msm/ipa/test/ipa_ut_suite_list.h b/drivers/platform/msm/ipa/test/ipa_ut_suite_list.h
index 944800f..4a9d3b0 100644
--- a/drivers/platform/msm/ipa/test/ipa_ut_suite_list.h
+++ b/drivers/platform/msm/ipa/test/ipa_ut_suite_list.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -21,6 +21,7 @@
  * No importance for order.
  */
 IPA_UT_DECLARE_SUITE(mhi);
+IPA_UT_DECLARE_SUITE(dma);
 IPA_UT_DECLARE_SUITE(example);
 
 
@@ -31,6 +32,7 @@
 IPA_UT_DEFINE_ALL_SUITES_START
 {
 	IPA_UT_REGISTER_SUITE(mhi),
+	IPA_UT_REGISTER_SUITE(dma),
 	IPA_UT_REGISTER_SUITE(example),
 } IPA_UT_DEFINE_ALL_SUITES_END;
 
diff --git a/drivers/platform/msm/msm_11ad/Makefile b/drivers/platform/msm/msm_11ad/Makefile
new file mode 100644
index 0000000..4771045
--- /dev/null
+++ b/drivers/platform/msm/msm_11ad/Makefile
@@ -0,0 +1,9 @@
+obj-$(CONFIG_MSM_11AD) += msm_11ad_proxy.o
+
+msm_11ad_proxy-y := msm_11ad.o
+subdir-ccflags-y += -D__CHECK_ENDIAN__
+
+# need to locate wil_platform.h
+WIL_11AD_PATH = drivers/net/wireless/ath/wil6210
+subdir-ccflags-y += -I$(WIL_11AD_PATH)
+
diff --git a/drivers/platform/msm/msm_11ad/msm_11ad.c b/drivers/platform/msm/msm_11ad/msm_11ad.c
new file mode 100644
index 0000000..3330595
--- /dev/null
+++ b/drivers/platform/msm/msm_11ad/msm_11ad.c
@@ -0,0 +1,1321 @@
+/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/msm_pcie.h>
+#include <asm/dma-iommu.h>
+#include <linux/msm-bus.h>
+#include <linux/iommu.h>
+#include <linux/version.h>
+#include <linux/delay.h>
+#include <soc/qcom/subsystem_restart.h>
+#include <soc/qcom/subsystem_notif.h>
+#include <soc/qcom/ramdump.h>
+#include <soc/qcom/memory_dump.h>
+#include <linux/regulator/consumer.h>
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/cpumask.h>
+#include <linux/cpufreq.h>
+#include <linux/sched/core_ctl.h>
+#include "wil_platform.h"
+#include "msm_11ad.h"
+
+#define WIGIG_VENDOR (0x1ae9)
+#define WIGIG_DEVICE (0x0310)
+
+#define SMMU_BASE	0x10000000 /* Device address range base */
+#define SMMU_SIZE	((SZ_1G * 4ULL) - SMMU_BASE)
+
+#define WIGIG_ENABLE_DELAY	50
+#define PM_OPT_SUSPEND (MSM_PCIE_CONFIG_NO_CFG_RESTORE | \
+			MSM_PCIE_CONFIG_LINKDOWN)
+#define PM_OPT_RESUME MSM_PCIE_CONFIG_NO_CFG_RESTORE
+
+#define WIGIG_SUBSYS_NAME	"WIGIG"
+#define WIGIG_RAMDUMP_SIZE    0x200000 /* maximum ramdump size */
+#define WIGIG_DUMP_FORMAT_VER   0x1
+#define WIGIG_DUMP_MAGIC_VER_V1 0x57474947
+#define VDD_MIN_UV	1028000
+#define VDD_MAX_UV	1028000
+#define VDD_MAX_UA	575000
+#define VDDIO_MIN_UV	1950000
+#define VDDIO_MAX_UV	2040000
+#define VDDIO_MAX_UA	70300
+
+#define WIGIG_MIN_CPU_BOOST_KBPS	150000
+
+struct device;
+
+static const char * const gpio_en_name = "qcom,wigig-en";
+static const char * const sleep_clk_en_name = "qcom,sleep-clk-en";
+
+struct msm11ad_vreg {
+	const char *name;
+	struct regulator *reg;
+	int max_uA;
+	int min_uV;
+	int max_uV;
+	bool enabled;
+};
+
+struct msm11ad_clk {
+	const char *name;
+	struct clk *clk;
+	bool enabled;
+};
+
+struct msm11ad_ctx {
+	struct list_head list;
+	struct device *dev; /* for platform device */
+	int gpio_en; /* card enable */
+	int sleep_clk_en; /* sleep clock enable for low PM management */
+
+	/* pci device */
+	u32 rc_index; /* PCIE root complex index */
+	struct pci_dev *pcidev;
+	struct pci_saved_state *pristine_state;
+
+	/* SMMU */
+	bool use_smmu; /* have SMMU enabled? */
+	int smmu_bypass;
+	int smmu_fast_map;
+	struct dma_iommu_mapping *mapping;
+
+	/* bus frequency scaling */
+	struct msm_bus_scale_pdata *bus_scale;
+	u32 msm_bus_handle;
+
+	/* subsystem restart */
+	struct wil_platform_rops rops;
+	void *wil_handle;
+	struct subsys_desc subsysdesc;
+	struct subsys_device *subsys;
+	void *subsys_handle;
+	bool recovery_in_progress;
+
+	/* ramdump */
+	void *ramdump_addr;
+	struct msm_dump_data dump_data;
+	struct ramdump_device *ramdump_dev;
+
+	/* external vregs and clocks */
+	struct msm11ad_vreg vdd;
+	struct msm11ad_vreg vddio;
+	struct msm11ad_clk rf_clk3;
+	struct msm11ad_clk rf_clk3_pin;
+
+	/* cpu boost support */
+	bool use_cpu_boost;
+	bool is_cpu_boosted;
+	struct cpumask boost_cpu;
+};
+
+static LIST_HEAD(dev_list);
+
+static struct msm11ad_ctx *pcidev2ctx(struct pci_dev *pcidev)
+{
+	struct msm11ad_ctx *ctx;
+
+	list_for_each_entry(ctx, &dev_list, list) {
+		if (ctx->pcidev == pcidev)
+			return ctx;
+	}
+	return NULL;
+}
+
+static int msm_11ad_init_vreg(struct device *dev,
+			      struct msm11ad_vreg *vreg, const char *name)
+{
+	int rc = 0;
+
+	if (!vreg)
+		return 0;
+
+	vreg->name = kstrdup(name, GFP_KERNEL);
+	if (!vreg->name)
+		return -ENOMEM;
+
+	vreg->reg = devm_regulator_get(dev, name);
+	if (IS_ERR_OR_NULL(vreg->reg)) {
+		rc = PTR_ERR(vreg->reg);
+		dev_err(dev, "%s: failed to get %s, rc=%d\n",
+			__func__, name, rc);
+		kfree(vreg->name);
+		vreg->reg = NULL;
+		goto out;
+	}
+
+	dev_info(dev, "%s: %s initialized successfully\n", __func__, name);
+
+out:
+	return rc;
+}
+
+static int msm_11ad_release_vreg(struct device *dev, struct msm11ad_vreg *vreg)
+{
+	if (!vreg || !vreg->reg)
+		return 0;
+
+	dev_info(dev, "%s: %s released\n", __func__, vreg->name);
+
+	devm_regulator_put(vreg->reg);
+	vreg->reg = NULL;
+	kfree(vreg->name);
+
+	return 0;
+}
+
+static int msm_11ad_init_clk(struct device *dev, struct msm11ad_clk *clk,
+			     const char *name)
+{
+	int rc = 0;
+
+	clk->name = kstrdup(name, GFP_KERNEL);
+	if (!clk->name)
+		return -ENOMEM;
+
+	clk->clk = devm_clk_get(dev, name);
+	if (IS_ERR(clk->clk)) {
+		rc = PTR_ERR(clk->clk);
+		if (rc == -ENOENT)
+			rc = -EPROBE_DEFER;
+		dev_err(dev, "%s: failed to get %s rc %d",
+				__func__, name, rc);
+		kfree(clk->name);
+		clk->clk = NULL;
+		goto out;
+	}
+
+	dev_info(dev, "%s: %s initialized successfully\n", __func__, name);
+
+out:
+	return rc;
+}
+
+static int msm_11ad_release_clk(struct device *dev, struct msm11ad_clk *clk)
+{
+	if (!clk || !clk->clk)
+		return 0;
+
+	dev_info(dev, "%s: %s released\n", __func__, clk->name);
+
+	devm_clk_put(dev, clk->clk);
+	clk->clk = NULL;
+
+	kfree(clk->name);
+
+	return 0;
+}
+
+static int msm_11ad_init_vregs(struct msm11ad_ctx *ctx)
+{
+	int rc;
+	struct device *dev = ctx->dev;
+
+	if (!of_property_read_bool(dev->of_node, "qcom,use-ext-supply"))
+		return 0;
+
+	rc = msm_11ad_init_vreg(dev, &ctx->vdd, "vdd");
+	if (rc)
+		goto out;
+
+	ctx->vdd.max_uV = VDD_MAX_UV;
+	ctx->vdd.min_uV = VDD_MIN_UV;
+	ctx->vdd.max_uA = VDD_MAX_UA;
+
+	rc = msm_11ad_init_vreg(dev, &ctx->vddio, "vddio");
+	if (rc)
+		goto vddio_fail;
+
+	ctx->vddio.max_uV = VDDIO_MAX_UV;
+	ctx->vddio.min_uV = VDDIO_MIN_UV;
+	ctx->vddio.max_uA = VDDIO_MAX_UA;
+
+	return rc;
+
+vddio_fail:
+	msm_11ad_release_vreg(dev, &ctx->vdd);
+out:
+	return rc;
+}
+
+static void msm_11ad_release_vregs(struct msm11ad_ctx *ctx)
+{
+	msm_11ad_release_vreg(ctx->dev, &ctx->vdd);
+	msm_11ad_release_vreg(ctx->dev, &ctx->vddio);
+}
+
+static int msm_11ad_cfg_vreg(struct device *dev,
+			     struct msm11ad_vreg *vreg, bool on)
+{
+	int rc = 0;
+	int min_uV;
+	int uA_load;
+
+	if (!vreg || !vreg->reg)
+		goto out;
+
+	if (regulator_count_voltages(vreg->reg) > 0) {
+		min_uV = on ? vreg->min_uV : 0;
+		rc = regulator_set_voltage(vreg->reg, min_uV, vreg->max_uV);
+		if (rc) {
+			dev_err(dev, "%s: %s set voltage failed, err=%d\n",
+					__func__, vreg->name, rc);
+			goto out;
+		}
+		uA_load = on ? vreg->max_uA : 0;
+		rc = regulator_set_load(vreg->reg, uA_load);
+		if (rc >= 0) {
+			/*
+			 * regulator_set_load() returns new regulator
+			 * mode upon success.
+			 */
+			dev_dbg(dev,
+				  "%s: %s regulator_set_load rc(%d)\n",
+				  __func__, vreg->name, rc);
+			rc = 0;
+		} else {
+			dev_err(dev,
+				"%s: %s set load(uA_load=%d) failed, rc=%d\n",
+				__func__, vreg->name, uA_load, rc);
+			goto out;
+		}
+	}
+
+out:
+	return rc;
+}
+
+static int msm_11ad_enable_vreg(struct msm11ad_ctx *ctx,
+				struct msm11ad_vreg *vreg)
+{
+	struct device *dev = ctx->dev;
+	int rc = 0;
+
+	if (!vreg || !vreg->reg || vreg->enabled)
+		goto out;
+
+	rc = msm_11ad_cfg_vreg(dev, vreg, true);
+	if (rc)
+		goto out;
+
+	rc = regulator_enable(vreg->reg);
+	if (rc) {
+		dev_err(dev, "%s: %s enable failed, rc=%d\n",
+				__func__, vreg->name, rc);
+		goto enable_fail;
+	}
+
+	vreg->enabled = true;
+
+	dev_info(dev, "%s: %s enabled\n", __func__, vreg->name);
+
+	return rc;
+
+enable_fail:
+	msm_11ad_cfg_vreg(dev, vreg, false);
+out:
+	return rc;
+}
+
+static int msm_11ad_disable_vreg(struct msm11ad_ctx *ctx,
+				 struct msm11ad_vreg *vreg)
+{
+	struct device *dev = ctx->dev;
+	int rc = 0;
+
+	if (!vreg || !vreg->reg || !vreg->enabled)
+		goto out;
+
+	rc = regulator_disable(vreg->reg);
+	if (rc) {
+		dev_err(dev, "%s: %s disable failed, rc=%d\n",
+				__func__, vreg->name, rc);
+		goto out;
+	}
+
+	/* ignore errors on applying disable config */
+	msm_11ad_cfg_vreg(dev, vreg, false);
+	vreg->enabled = false;
+
+	dev_info(dev, "%s: %s disabled\n", __func__, vreg->name);
+
+out:
+	return rc;
+}
+
+static int msm_11ad_enable_vregs(struct msm11ad_ctx *ctx)
+{
+	int rc = 0;
+
+	rc = msm_11ad_enable_vreg(ctx, &ctx->vdd);
+	if (rc)
+		goto out;
+
+	rc = msm_11ad_enable_vreg(ctx, &ctx->vddio);
+	if (rc)
+		goto vddio_fail;
+
+	return rc;
+
+vddio_fail:
+	msm_11ad_disable_vreg(ctx, &ctx->vdd);
+out:
+	return rc;
+}
+
+static int msm_11ad_disable_vregs(struct msm11ad_ctx *ctx)
+{
+	if (!ctx->vdd.reg && !ctx->vddio.reg)
+		goto out;
+
+	/* ignore errors on disable vreg */
+	msm_11ad_disable_vreg(ctx, &ctx->vdd);
+	msm_11ad_disable_vreg(ctx, &ctx->vddio);
+
+out:
+	return 0;
+}
+
+static int msm_11ad_enable_clk(struct msm11ad_ctx *ctx,
+				struct msm11ad_clk *clk)
+{
+	struct device *dev = ctx->dev;
+	int rc = 0;
+
+	if (!clk || !clk->clk || clk->enabled)
+		goto out;
+
+	rc = clk_prepare_enable(clk->clk);
+	if (rc) {
+		dev_err(dev, "%s: failed to enable %s, rc(%d)\n",
+			__func__, clk->name, rc);
+		goto out;
+	}
+	clk->enabled = true;
+
+	dev_dbg(dev, "%s: %s enabled\n", __func__, clk->name);
+
+out:
+	return rc;
+}
+
+static void msm_11ad_disable_clk(struct msm11ad_ctx *ctx,
+				struct msm11ad_clk *clk)
+{
+	struct device *dev = ctx->dev;
+
+	if (!clk || !clk->clk || !clk->enabled)
+		goto out;
+
+	clk_disable_unprepare(clk->clk);
+	clk->enabled = false;
+
+	dev_dbg(dev, "%s: %s disabled\n", __func__, clk->name);
+
+out:
+	return;
+}
+
+static int msm_11ad_enable_clocks(struct msm11ad_ctx *ctx)
+{
+	int rc;
+
+	rc = msm_11ad_enable_clk(ctx, &ctx->rf_clk3);
+	if (rc)
+		return rc;
+
+	rc = msm_11ad_enable_clk(ctx, &ctx->rf_clk3_pin);
+	if (rc)
+		msm_11ad_disable_clk(ctx, &ctx->rf_clk3);
+
+	return rc;
+}
+
+static int msm_11ad_init_clocks(struct msm11ad_ctx *ctx)
+{
+	int rc;
+	struct device *dev = ctx->dev;
+
+	if (!of_property_read_bool(dev->of_node, "qcom,use-ext-clocks"))
+		return 0;
+
+	rc = msm_11ad_init_clk(dev, &ctx->rf_clk3, "rf_clk3_clk");
+	if (rc)
+		return rc;
+
+	rc = msm_11ad_init_clk(dev, &ctx->rf_clk3_pin, "rf_clk3_pin_clk");
+	if (rc)
+		msm_11ad_release_clk(ctx->dev, &ctx->rf_clk3);
+
+	return rc;
+}
+
+static void msm_11ad_release_clocks(struct msm11ad_ctx *ctx)
+{
+	msm_11ad_release_clk(ctx->dev, &ctx->rf_clk3_pin);
+	msm_11ad_release_clk(ctx->dev, &ctx->rf_clk3);
+}
+
+static void msm_11ad_disable_clocks(struct msm11ad_ctx *ctx)
+{
+	msm_11ad_disable_clk(ctx, &ctx->rf_clk3_pin);
+	msm_11ad_disable_clk(ctx, &ctx->rf_clk3);
+}
+
+static int ops_suspend(void *handle)
+{
+	int rc;
+	struct msm11ad_ctx *ctx = handle;
+	struct pci_dev *pcidev;
+
+	pr_info("%s(%p)\n", __func__, handle);
+	if (!ctx) {
+		pr_err("No context\n");
+		return -ENODEV;
+	}
+	pcidev = ctx->pcidev;
+	rc = pci_save_state(pcidev);
+	if (rc) {
+		dev_err(ctx->dev, "pci_save_state failed :%d\n", rc);
+		return rc;
+	}
+	rc = msm_pcie_pm_control(MSM_PCIE_SUSPEND, pcidev->bus->number,
+				 pcidev, NULL, PM_OPT_SUSPEND);
+	if (rc) {
+		dev_err(ctx->dev, "msm_pcie_pm_control(SUSPEND) failed :%d\n",
+			rc);
+		return rc;
+	}
+	if (ctx->gpio_en >= 0)
+		gpio_direction_output(ctx->gpio_en, 0);
+
+	if (ctx->sleep_clk_en >= 0)
+		gpio_direction_output(ctx->sleep_clk_en, 0);
+
+	msm_11ad_disable_clocks(ctx);
+
+	msm_11ad_disable_vregs(ctx);
+
+	return rc;
+}
+
+static int ops_resume(void *handle)
+{
+	int rc;
+	struct msm11ad_ctx *ctx = handle;
+	struct pci_dev *pcidev;
+
+	pr_info("%s(%p)\n", __func__, handle);
+	if (!ctx) {
+		pr_err("No context\n");
+		return -ENODEV;
+	}
+
+	rc = msm_11ad_enable_vregs(ctx);
+	if (rc) {
+		dev_err(ctx->dev, "msm_11ad_enable_vregs failed :%d\n",
+			rc);
+		return rc;
+	}
+
+	rc = msm_11ad_enable_clocks(ctx);
+	if (rc) {
+		dev_err(ctx->dev, "msm_11ad_enable_clocks failed :%d\n", rc);
+		goto err_disable_vregs;
+	}
+
+	if (ctx->sleep_clk_en >= 0)
+		gpio_direction_output(ctx->sleep_clk_en, 1);
+
+	pcidev = ctx->pcidev;
+	if (ctx->gpio_en >= 0) {
+		gpio_direction_output(ctx->gpio_en, 1);
+		msleep(WIGIG_ENABLE_DELAY);
+	}
+
+	rc = msm_pcie_pm_control(MSM_PCIE_RESUME, pcidev->bus->number,
+				 pcidev, NULL, PM_OPT_RESUME);
+	if (rc) {
+		dev_err(ctx->dev, "msm_pcie_pm_control(RESUME) failed :%d\n",
+			rc);
+		goto err_disable_power;
+	}
+	rc = msm_pcie_recover_config(pcidev);
+	if (rc) {
+		dev_err(ctx->dev, "msm_pcie_recover_config failed :%d\n",
+			rc);
+		goto err_suspend_rc;
+	}
+
+	return 0;
+
+err_suspend_rc:
+	msm_pcie_pm_control(MSM_PCIE_SUSPEND, pcidev->bus->number,
+			    pcidev, NULL, PM_OPT_SUSPEND);
+err_disable_power:
+	if (ctx->gpio_en >= 0)
+		gpio_direction_output(ctx->gpio_en, 0);
+
+	if (ctx->sleep_clk_en >= 0)
+		gpio_direction_output(ctx->sleep_clk_en, 0);
+
+	msm_11ad_disable_clocks(ctx);
+err_disable_vregs:
+	msm_11ad_disable_vregs(ctx);
+
+	return rc;
+}
+
+static int msm_11ad_smmu_init(struct msm11ad_ctx *ctx)
+{
+	int atomic_ctx = 1;
+	int rc;
+
+	if (!ctx->use_smmu)
+		return 0;
+
+	dev_info(ctx->dev, "Initialize SMMU, bypass = %d, fastmap = %d\n",
+		 ctx->smmu_bypass, ctx->smmu_fast_map);
+
+	ctx->mapping = arm_iommu_create_mapping(&platform_bus_type,
+						SMMU_BASE, SMMU_SIZE);
+	if (IS_ERR_OR_NULL(ctx->mapping)) {
+		rc = PTR_ERR(ctx->mapping) ?: -ENODEV;
+		dev_err(ctx->dev, "Failed to create IOMMU mapping (%d)\n", rc);
+		return rc;
+	}
+
+	rc = iommu_domain_set_attr(ctx->mapping->domain,
+				   DOMAIN_ATTR_ATOMIC,
+				   &atomic_ctx);
+	if (rc) {
+		dev_err(ctx->dev, "Set atomic attribute to SMMU failed (%d)\n",
+			rc);
+		goto release_mapping;
+	}
+
+	if (ctx->smmu_bypass) {
+		rc = iommu_domain_set_attr(ctx->mapping->domain,
+					   DOMAIN_ATTR_S1_BYPASS,
+					   &ctx->smmu_bypass);
+		if (rc) {
+			dev_err(ctx->dev, "Set bypass attribute to SMMU failed (%d)\n",
+				rc);
+			goto release_mapping;
+		}
+	} else if (ctx->smmu_fast_map) {
+		rc = iommu_domain_set_attr(ctx->mapping->domain,
+					   DOMAIN_ATTR_FAST,
+					   &ctx->smmu_fast_map);
+		if (rc) {
+			dev_err(ctx->dev, "Set fast attribute to SMMU failed (%d)\n",
+				rc);
+			goto release_mapping;
+		}
+	}
+
+	rc = arm_iommu_attach_device(&ctx->pcidev->dev, ctx->mapping);
+	if (rc) {
+		dev_err(ctx->dev, "arm_iommu_attach_device failed (%d)\n", rc);
+		goto release_mapping;
+	}
+	dev_info(ctx->dev, "attached to IOMMU\n");
+
+	return 0;
+release_mapping:
+	arm_iommu_release_mapping(ctx->mapping);
+	ctx->mapping = NULL;
+	return rc;
+}
+
+static int msm_11ad_ssr_shutdown(const struct subsys_desc *subsys,
+				 bool force_stop)
+{
+	pr_info("%s(%p,%d)\n", __func__, subsys, force_stop);
+	/* nothing is done in shutdown. We do full recovery in powerup */
+	return 0;
+}
+
+static int msm_11ad_ssr_powerup(const struct subsys_desc *subsys)
+{
+	int rc = 0;
+	struct platform_device *pdev;
+	struct msm11ad_ctx *ctx;
+
+	pr_info("%s(%p)\n", __func__, subsys);
+
+	pdev = to_platform_device(subsys->dev);
+	ctx = platform_get_drvdata(pdev);
+
+	if (!ctx)
+		return -ENODEV;
+
+	if (ctx->recovery_in_progress) {
+		if (ctx->rops.fw_recovery && ctx->wil_handle) {
+			dev_info(ctx->dev, "requesting FW recovery\n");
+			rc = ctx->rops.fw_recovery(ctx->wil_handle);
+		}
+		ctx->recovery_in_progress = false;
+	}
+
+	return rc;
+}
+
+static int msm_11ad_ssr_ramdump(int enable, const struct subsys_desc *subsys)
+{
+	int rc;
+	struct ramdump_segment segment;
+	struct platform_device *pdev;
+	struct msm11ad_ctx *ctx;
+
+	pdev = to_platform_device(subsys->dev);
+	ctx = platform_get_drvdata(pdev);
+
+	if (!ctx)
+		return -ENODEV;
+
+	if (!enable)
+		return 0;
+
+	if (ctx->rops.ramdump && ctx->wil_handle) {
+		rc = ctx->rops.ramdump(ctx->wil_handle, ctx->ramdump_addr,
+				       WIGIG_RAMDUMP_SIZE);
+		if (rc) {
+			dev_err(ctx->dev, "ramdump failed : %d\n", rc);
+			return -EINVAL;
+		}
+	}
+
+	memset(&segment, 0, sizeof(segment));
+	segment.v_address = ctx->ramdump_addr;
+	segment.size = WIGIG_RAMDUMP_SIZE;
+
+	return do_ramdump(ctx->ramdump_dev, &segment, 1);
+}
+
+static void msm_11ad_ssr_crash_shutdown(const struct subsys_desc *subsys)
+{
+	int rc;
+	struct platform_device *pdev;
+	struct msm11ad_ctx *ctx;
+
+	pdev = to_platform_device(subsys->dev);
+	ctx = platform_get_drvdata(pdev);
+
+	if (!ctx) {
+		pr_err("%s: no context\n", __func__);
+		return;
+	}
+
+	if (ctx->rops.ramdump && ctx->wil_handle) {
+		rc = ctx->rops.ramdump(ctx->wil_handle, ctx->ramdump_addr,
+				       WIGIG_RAMDUMP_SIZE);
+		if (rc)
+			dev_err(ctx->dev, "ramdump failed : %d\n", rc);
+		/* continue */
+	}
+
+	ctx->dump_data.version = WIGIG_DUMP_FORMAT_VER;
+	strlcpy(ctx->dump_data.name, WIGIG_SUBSYS_NAME,
+		sizeof(ctx->dump_data.name));
+
+	ctx->dump_data.magic = WIGIG_DUMP_MAGIC_VER_V1;
+}
+
+static void msm_11ad_ssr_deinit(struct msm11ad_ctx *ctx)
+{
+	if (ctx->ramdump_dev) {
+		destroy_ramdump_device(ctx->ramdump_dev);
+		ctx->ramdump_dev = NULL;
+	}
+
+	kfree(ctx->ramdump_addr);
+	ctx->ramdump_addr = NULL;
+
+	if (ctx->subsys_handle) {
+		subsystem_put(ctx->subsys_handle);
+		ctx->subsys_handle = NULL;
+	}
+
+	if (ctx->subsys) {
+		subsys_unregister(ctx->subsys);
+		ctx->subsys = NULL;
+	}
+}
+
+static int msm_11ad_ssr_init(struct msm11ad_ctx *ctx)
+{
+	int rc;
+	struct msm_dump_entry dump_entry;
+
+	ctx->subsysdesc.name = "WIGIG";
+	ctx->subsysdesc.owner = THIS_MODULE;
+	ctx->subsysdesc.shutdown = msm_11ad_ssr_shutdown;
+	ctx->subsysdesc.powerup = msm_11ad_ssr_powerup;
+	ctx->subsysdesc.ramdump = msm_11ad_ssr_ramdump;
+	ctx->subsysdesc.crash_shutdown = msm_11ad_ssr_crash_shutdown;
+	ctx->subsysdesc.dev = ctx->dev;
+	ctx->subsys = subsys_register(&ctx->subsysdesc);
+	if (IS_ERR(ctx->subsys)) {
+		rc = PTR_ERR(ctx->subsys);
+		dev_err(ctx->dev, "subsys_register failed :%d\n", rc);
+		goto out_rc;
+	}
+
+	/* register ramdump area */
+	ctx->ramdump_addr = kmalloc(WIGIG_RAMDUMP_SIZE, GFP_KERNEL);
+	if (!ctx->ramdump_addr) {
+		rc = -ENOMEM;
+		goto out_rc;
+	}
+
+	ctx->dump_data.addr = virt_to_phys(ctx->ramdump_addr);
+	ctx->dump_data.len = WIGIG_RAMDUMP_SIZE;
+	dump_entry.id = MSM_DUMP_DATA_WIGIG;
+	dump_entry.addr = virt_to_phys(&ctx->dump_data);
+
+	rc = msm_dump_data_register(MSM_DUMP_TABLE_APPS, &dump_entry);
+	if (rc) {
+		dev_err(ctx->dev, "Dump table setup failed: %d\n", rc);
+		goto out_rc;
+	}
+
+	ctx->ramdump_dev = create_ramdump_device(ctx->subsysdesc.name,
+						 ctx->subsysdesc.dev);
+	if (!ctx->ramdump_dev) {
+		dev_err(ctx->dev, "Create ramdump device failed: %d\n", rc);
+		rc = -ENOMEM;
+		goto out_rc;
+	}
+
+	return 0;
+
+out_rc:
+	msm_11ad_ssr_deinit(ctx);
+	return rc;
+}
+
+static void msm_11ad_init_cpu_boost(struct msm11ad_ctx *ctx)
+{
+	unsigned int minfreq = 0, maxfreq = 0, freq;
+	int i, boost_cpu;
+
+	for_each_possible_cpu(i) {
+		freq = cpufreq_quick_get_max(i);
+		if (freq > maxfreq) {
+			maxfreq = freq;
+			boost_cpu = i;
+		}
+		if (!minfreq || freq < minfreq)
+			minfreq = freq;
+	}
+
+	if (minfreq != maxfreq) {
+		/*
+		 * use first big core for boost, to be compatible with WLAN
+		 * which assigns big cores from the last index
+		 */
+		ctx->use_cpu_boost = true;
+		cpumask_clear(&ctx->boost_cpu);
+		cpumask_set_cpu(boost_cpu, &ctx->boost_cpu);
+		dev_info(ctx->dev, "CPU boost: will use core %d\n", boost_cpu);
+	} else {
+		ctx->use_cpu_boost = false;
+		dev_info(ctx->dev, "CPU boost disabled, uniform topology\n");
+	}
+}
+
+static int msm_11ad_probe(struct platform_device *pdev)
+{
+	struct msm11ad_ctx *ctx;
+	struct device *dev = &pdev->dev;
+	struct device_node *of_node = dev->of_node;
+	struct device_node *rc_node;
+	struct pci_dev *pcidev = NULL;
+	int rc;
+
+	ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
+	if (!ctx)
+		return -ENOMEM;
+
+	ctx->dev = dev;
+
+	/*== parse ==*/
+
+	/* Information pieces:
+	 * - of_node stands for "wil6210":
+	 *	wil6210: qcom,wil6210 {
+	 *	compatible = "qcom,wil6210";
+	 *	qcom,pcie-parent = <&pcie1>;
+	 *	qcom,wigig-en = <&tlmm 94 0>; (ctx->gpio_en)
+	 *	qcom,sleep-clk-en = <&pm8994_gpios 18 0>; (ctx->sleep_clk_en)
+	 *	qcom,msm-bus,name = "wil6210";
+	 *	qcom,msm-bus,num-cases = <2>;
+	 *	qcom,msm-bus,num-paths = <1>;
+	 *	qcom,msm-bus,vectors-KBps =
+	 *		<100 512 0 0>,
+	 *		<100 512 600000 800000>;
+	 *	qcom,smmu-support;
+	 *};
+	 * rc_node stands for "qcom,pcie", selected entries:
+	 * cell-index = <1>; (ctx->rc_index)
+	 * iommus = <&anoc0_smmu>;
+	 * qcom,smmu-exist;
+	 */
+
+	/* wigig-en is optional property */
+	ctx->gpio_en = of_get_named_gpio(of_node, gpio_en_name, 0);
+	if (ctx->gpio_en < 0)
+		dev_warn(ctx->dev, "GPIO <%s> not found, enable GPIO not used\n",
+			gpio_en_name);
+	ctx->sleep_clk_en = of_get_named_gpio(of_node, sleep_clk_en_name, 0);
+	if (ctx->sleep_clk_en < 0)
+		dev_warn(ctx->dev, "GPIO <%s> not found, sleep clock not used\n",
+			 sleep_clk_en_name);
+	rc_node = of_parse_phandle(of_node, "qcom,pcie-parent", 0);
+	if (!rc_node) {
+		dev_err(ctx->dev, "Parent PCIE device not found\n");
+		return -EINVAL;
+	}
+	rc = of_property_read_u32(rc_node, "cell-index", &ctx->rc_index);
+	if (rc < 0) {
+		dev_err(ctx->dev, "Parent PCIE device index not found\n");
+		return -EINVAL;
+	}
+	ctx->use_smmu = of_property_read_bool(of_node, "qcom,smmu-support");
+	ctx->bus_scale = msm_bus_cl_get_pdata(pdev);
+
+	ctx->smmu_bypass = 1;
+	ctx->smmu_fast_map = 0;
+
+	/*== execute ==*/
+	/* turn device on */
+	rc = msm_11ad_init_vregs(ctx);
+	if (rc) {
+		dev_err(ctx->dev, "msm_11ad_init_vregs failed: %d\n", rc);
+		return rc;
+	}
+	rc = msm_11ad_enable_vregs(ctx);
+	if (rc) {
+		dev_err(ctx->dev, "msm_11ad_enable_vregs failed: %d\n", rc);
+		goto out_vreg_clk;
+	}
+
+	rc = msm_11ad_init_clocks(ctx);
+	if (rc) {
+		dev_err(ctx->dev, "msm_11ad_init_clocks failed: %d\n", rc);
+		goto out_vreg_clk;
+	}
+
+	rc = msm_11ad_enable_clocks(ctx);
+	if (rc) {
+		dev_err(ctx->dev, "msm_11ad_enable_clocks failed: %d\n", rc);
+		goto out_vreg_clk;
+	}
+
+	if (ctx->gpio_en >= 0) {
+		rc = gpio_request(ctx->gpio_en, gpio_en_name);
+		if (rc < 0) {
+			dev_err(ctx->dev, "failed to request GPIO %d <%s>\n",
+				ctx->gpio_en, gpio_en_name);
+			goto out_req;
+		}
+		rc = gpio_direction_output(ctx->gpio_en, 1);
+		if (rc < 0) {
+			dev_err(ctx->dev, "failed to set GPIO %d <%s>\n",
+				ctx->gpio_en, gpio_en_name);
+			goto out_set;
+		}
+		msleep(WIGIG_ENABLE_DELAY);
+	}
+
+	/* enumerate it on PCIE */
+	rc = msm_pcie_enumerate(ctx->rc_index);
+	if (rc < 0) {
+		dev_err(ctx->dev, "Parent PCIE enumeration failed\n");
+		goto out_rc;
+	}
+	/* search for PCIE device in our domain */
+	do {
+		pcidev = pci_get_device(WIGIG_VENDOR, WIGIG_DEVICE, pcidev);
+		if (!pcidev)
+			break;
+
+		if (pci_domain_nr(pcidev->bus) == ctx->rc_index)
+			break;
+	} while (true);
+	if (!pcidev) {
+		rc = -ENODEV;
+		dev_err(ctx->dev, "Wigig device %4x:%4x not found\n",
+			WIGIG_VENDOR, WIGIG_DEVICE);
+		goto out_rc;
+	}
+	ctx->pcidev = pcidev;
+	rc = pci_save_state(pcidev);
+	if (rc) {
+		dev_err(ctx->dev, "pci_save_state failed :%d\n", rc);
+		goto out_rc;
+	}
+	ctx->pristine_state = pci_store_saved_state(pcidev);
+
+	if (ctx->sleep_clk_en >= 0) {
+		rc = gpio_request(ctx->sleep_clk_en, "msm_11ad");
+		if (rc < 0) {
+			dev_err(ctx->dev,
+				"failed to request GPIO %d <%s>, sleep clock disabled\n",
+				ctx->sleep_clk_en, sleep_clk_en_name);
+			ctx->sleep_clk_en = -EINVAL;
+		} else {
+			gpio_direction_output(ctx->sleep_clk_en, 0);
+		}
+	}
+
+	/* register for subsystem restart */
+	rc = msm_11ad_ssr_init(ctx);
+	if (rc) {
+		dev_err(ctx->dev, "msm_11ad_ssr_init failed: %d\n", rc);
+		goto out_rc;
+	}
+
+	msm_11ad_init_cpu_boost(ctx);
+
+	/* report */
+	dev_info(ctx->dev, "msm_11ad discovered. %p {\n"
+		 "  gpio_en = %d\n"
+		 "  sleep_clk_en = %d\n"
+		 "  rc_index = %d\n"
+		 "  use_smmu = %d\n"
+		 "  pcidev = %p\n"
+		 "}\n", ctx, ctx->gpio_en, ctx->sleep_clk_en, ctx->rc_index,
+		 ctx->use_smmu, ctx->pcidev);
+
+	platform_set_drvdata(pdev, ctx);
+	device_disable_async_suspend(&pcidev->dev);
+
+	list_add_tail(&ctx->list, &dev_list);
+	ops_suspend(ctx);
+
+	return 0;
+out_rc:
+	if (ctx->gpio_en >= 0)
+		gpio_direction_output(ctx->gpio_en, 0);
+out_set:
+	if (ctx->gpio_en >= 0)
+		gpio_free(ctx->gpio_en);
+out_req:
+	ctx->gpio_en = -EINVAL;
+out_vreg_clk:
+	msm_11ad_disable_clocks(ctx);
+	msm_11ad_release_clocks(ctx);
+	msm_11ad_disable_vregs(ctx);
+	msm_11ad_release_vregs(ctx);
+
+	return rc;
+}
+
+static int msm_11ad_remove(struct platform_device *pdev)
+{
+	struct msm11ad_ctx *ctx = platform_get_drvdata(pdev);
+
+	msm_11ad_ssr_deinit(ctx);
+	list_del(&ctx->list);
+	dev_info(ctx->dev, "%s: pdev %p pcidev %p\n", __func__, pdev,
+		 ctx->pcidev);
+	kfree(ctx->pristine_state);
+
+	msm_bus_cl_clear_pdata(ctx->bus_scale);
+	pci_dev_put(ctx->pcidev);
+	if (ctx->gpio_en >= 0) {
+		gpio_direction_output(ctx->gpio_en, 0);
+		gpio_free(ctx->gpio_en);
+	}
+	if (ctx->sleep_clk_en >= 0)
+		gpio_free(ctx->sleep_clk_en);
+
+	msm_11ad_disable_clocks(ctx);
+	msm_11ad_release_clocks(ctx);
+	msm_11ad_disable_vregs(ctx);
+	msm_11ad_release_vregs(ctx);
+
+	return 0;
+}
+
+static const struct of_device_id msm_11ad_of_match[] = {
+	{ .compatible = "qcom,wil6210", },
+	{},
+};
+
+static struct platform_driver msm_11ad_driver = {
+	.driver = {
+		.name = "msm_11ad",
+		.of_match_table = msm_11ad_of_match,
+	},
+	.probe = msm_11ad_probe,
+	.remove = msm_11ad_remove,
+};
+module_platform_driver(msm_11ad_driver);
+
+static void msm_11ad_set_boost_affinity(struct msm11ad_ctx *ctx)
+{
+	/*
+	 * There is a very small window where user space can change the
+	 * affinity after we changed it here and before setting the
+	 * NO_BALANCING flag. Retry this several times as a workaround.
+	 */
+	int retries = 5, rc;
+	struct irq_desc *desc;
+
+	while (retries > 0) {
+		irq_modify_status(ctx->pcidev->irq, IRQ_NO_BALANCING, 0);
+		rc = irq_set_affinity_hint(ctx->pcidev->irq, &ctx->boost_cpu);
+		if (rc)
+			dev_warn(ctx->dev,
+				"Failed set affinity, rc=%d\n", rc);
+		irq_modify_status(ctx->pcidev->irq, 0, IRQ_NO_BALANCING);
+		desc = irq_to_desc(ctx->pcidev->irq);
+		if (cpumask_equal(desc->irq_common_data.affinity,
+				  &ctx->boost_cpu))
+			break;
+		retries--;
+	}
+
+	if (!retries)
+		dev_warn(ctx->dev, "failed to set CPU boost affinity\n");
+}
+
+/* hooks for the wil6210 driver */
+static int ops_bus_request(void *handle, u32 kbps /* KBytes/Sec */)
+{
+	struct msm11ad_ctx *ctx = (struct msm11ad_ctx *)handle;
+	int rc, i;
+	int vote = 0; /* vote 0 in case requested kbps cannot be satisfied */
+	struct msm_bus_paths *usecase;
+	u32 usecase_kbps;
+	u32 min_kbps = ~0;
+
+	/* find the lowest usecase that is bigger than requested kbps */
+	for (i = 0; i < ctx->bus_scale->num_usecases; i++) {
+		usecase = &ctx->bus_scale->usecase[i];
+		/*
+		 * assume we have single path (vectors[0]). If we ever
+		 * have multiple paths, need to define the behavior
+		 */
+		usecase_kbps = div64_u64(usecase->vectors[0].ib, 1000);
+		if (usecase_kbps >= kbps && usecase_kbps < min_kbps) {
+			min_kbps = usecase_kbps;
+			vote = i;
+		}
+	}
+
+	rc = msm_bus_scale_client_update_request(ctx->msm_bus_handle, vote);
+	if (rc)
+		dev_err(ctx->dev,
+			"Failed msm_bus voting. kbps=%d vote=%d, rc=%d\n",
+			kbps, vote, rc);
+
+	if (ctx->use_cpu_boost) {
+		bool was_boosted = ctx->is_cpu_boosted;
+		bool needs_boost = (kbps >= WIGIG_MIN_CPU_BOOST_KBPS);
+
+		if (was_boosted != needs_boost) {
+			if (needs_boost) {
+				rc = core_ctl_set_boost(true);
+				if (rc) {
+					dev_err(ctx->dev,
+						"Failed enable boost rc=%d\n",
+						rc);
+					goto out;
+				}
+				msm_11ad_set_boost_affinity(ctx);
+				dev_dbg(ctx->dev, "CPU boost enabled\n");
+			} else {
+				rc = core_ctl_set_boost(false);
+				if (rc)
+					dev_err(ctx->dev,
+						"Failed disable boost rc=%d\n",
+						rc);
+				irq_modify_status(ctx->pcidev->irq,
+						  IRQ_NO_BALANCING, 0);
+				dev_dbg(ctx->dev, "CPU boost disabled\n");
+			}
+			ctx->is_cpu_boosted = needs_boost;
+		}
+	}
+out:
+	return rc;
+}
+
+static void ops_uninit(void *handle)
+{
+	struct msm11ad_ctx *ctx = (struct msm11ad_ctx *)handle;
+
+	if (ctx->msm_bus_handle) {
+		msm_bus_scale_unregister_client(ctx->msm_bus_handle);
+		ctx->msm_bus_handle = 0;
+	}
+
+	if (ctx->use_smmu) {
+		arm_iommu_detach_device(&ctx->pcidev->dev);
+		arm_iommu_release_mapping(ctx->mapping);
+		ctx->mapping = NULL;
+	}
+
+	memset(&ctx->rops, 0, sizeof(ctx->rops));
+	ctx->wil_handle = NULL;
+
+	ops_suspend(ctx);
+}
+
+static int msm_11ad_notify_crash(struct msm11ad_ctx *ctx)
+{
+	int rc;
+
+	if (ctx->subsys) {
+		dev_info(ctx->dev, "SSR requested\n");
+		ctx->recovery_in_progress = true;
+		rc = subsystem_restart_dev(ctx->subsys);
+		if (rc) {
+			dev_err(ctx->dev,
+				"subsystem_restart_dev fail: %d\n", rc);
+			ctx->recovery_in_progress = false;
+		}
+	}
+
+	return 0;
+}
+
+static int ops_notify(void *handle, enum wil_platform_event evt)
+{
+	struct msm11ad_ctx *ctx = (struct msm11ad_ctx *)handle;
+	int rc = 0;
+
+	switch (evt) {
+	case WIL_PLATFORM_EVT_FW_CRASH:
+		rc = msm_11ad_notify_crash(ctx);
+		break;
+	case WIL_PLATFORM_EVT_PRE_RESET:
+		/*
+		 * TODO: Enable rf_clk3 clock before resetting the device to
+		 * ensure stable ref clock during the device reset
+		 */
+		break;
+	case WIL_PLATFORM_EVT_FW_RDY:
+		/*
+		 * TODO: Disable rf_clk3 clock after the device is up to allow
+		 * the device to control it via its GPIO for power saving
+		 */
+		break;
+	default:
+		pr_debug("%s: Unhandled event %d\n", __func__, evt);
+		break;
+	}
+
+	return rc;
+}
+
+void *msm_11ad_dev_init(struct device *dev, struct wil_platform_ops *ops,
+			const struct wil_platform_rops *rops, void *wil_handle)
+{
+	struct pci_dev *pcidev = to_pci_dev(dev);
+	struct msm11ad_ctx *ctx = pcidev2ctx(pcidev);
+
+	if (!ctx) {
+		pr_err("Context not found for pcidev %p\n", pcidev);
+		return NULL;
+	}
+
+	/* bus scale */
+	ctx->msm_bus_handle =
+		msm_bus_scale_register_client(ctx->bus_scale);
+	if (!ctx->msm_bus_handle) {
+		dev_err(ctx->dev, "Failed msm_bus registration\n");
+		return NULL;
+	}
+	dev_info(ctx->dev, "msm_bus handle 0x%x\n", ctx->msm_bus_handle);
+	/* smmu */
+	if (msm_11ad_smmu_init(ctx)) {
+		msm_bus_scale_unregister_client(ctx->msm_bus_handle);
+		ctx->msm_bus_handle = 0;
+		return NULL;
+	}
+
+	/* subsystem restart */
+	if (rops) {
+		ctx->rops = *rops;
+		ctx->wil_handle = wil_handle;
+	}
+
+	/* fill ops */
+	memset(ops, 0, sizeof(*ops));
+	ops->bus_request = ops_bus_request;
+	ops->suspend = ops_suspend;
+	ops->resume = ops_resume;
+	ops->uninit = ops_uninit;
+	ops->notify = ops_notify;
+
+	return ctx;
+}
+EXPORT_SYMBOL(msm_11ad_dev_init);
+
+int msm_11ad_modinit(void)
+{
+	struct msm11ad_ctx *ctx = list_first_entry_or_null(&dev_list,
+							   struct msm11ad_ctx,
+							   list);
+
+	if (!ctx) {
+		pr_err("Context not found\n");
+		return -EINVAL;
+	}
+
+	if (ctx->pristine_state) {
+		/* in old kernels, pci_load_saved_state() is not exported;
+		 * so use pci_load_and_free_saved_state()
+		 * and re-allocate ctx->saved_state again
+		 */
+		pci_load_and_free_saved_state(ctx->pcidev,
+					      &ctx->pristine_state);
+		ctx->pristine_state = pci_store_saved_state(ctx->pcidev);
+	}
+
+	ctx->subsys_handle = subsystem_get(ctx->subsysdesc.name);
+
+	return ops_resume(ctx);
+}
+EXPORT_SYMBOL(msm_11ad_modinit);
+
+void msm_11ad_modexit(void)
+{
+	struct msm11ad_ctx *ctx = list_first_entry_or_null(&dev_list,
+							   struct msm11ad_ctx,
+							   list);
+
+	if (!ctx) {
+		pr_err("Context not found\n");
+		return;
+	}
+
+	if (ctx->subsys_handle) {
+		subsystem_put(ctx->subsys_handle);
+		ctx->subsys_handle = NULL;
+	}
+}
+EXPORT_SYMBOL(msm_11ad_modexit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Platform driver for Qualcomm Technologies, Inc. 11ad card");
+
diff --git a/drivers/platform/msm/msm_11ad/msm_11ad.h b/drivers/platform/msm/msm_11ad/msm_11ad.h
new file mode 100644
index 0000000..b15d512
--- /dev/null
+++ b/drivers/platform/msm/msm_11ad/msm_11ad.h
@@ -0,0 +1,40 @@
+/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef __MSM_11AD_H__
+#define __MSM_11AD_H__
+
+struct device;
+struct wil_platform_ops;
+struct wil_platform_rops;
+
+/*	msm_11ad_dev_init - call when binding to device, during probe()
+ *	@dev:	device structure of pci device
+ *	@ops:	pointer to operations supported by platform driver
+ *		Will be filled by this function call
+ *	@rops:	pointer to callback functions provided by wil device driver.
+ *		the platform driver copies the structure contents to its
+ *		internal storage. May be NULL if device driver does not
+ *		support rops.
+ *	@wil_handle:	context for wil device driver, will be provided
+ *			when platform driver invokes any of the callback
+ *			functions in rops. May be NULL if rops is also NULL
+ */
+void *msm_11ad_dev_init(struct device *dev, struct wil_platform_ops *ops,
+			const struct wil_platform_rops *rops, void *wil_handle);
+
+/* call on insmod */
+int msm_11ad_modinit(void);
+
+/* call on rmmod */
+void msm_11ad_modexit(void);
+
+#endif /* __MSM_11AD_H__ */
diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c
index 75f820ca..27ff38f 100644
--- a/drivers/s390/scsi/zfcp_fsf.c
+++ b/drivers/s390/scsi/zfcp_fsf.c
@@ -1583,7 +1583,7 @@
 int zfcp_fsf_open_wka_port(struct zfcp_fc_wka_port *wka_port)
 {
 	struct zfcp_qdio *qdio = wka_port->adapter->qdio;
-	struct zfcp_fsf_req *req = NULL;
+	struct zfcp_fsf_req *req;
 	int retval = -EIO;
 
 	spin_lock_irq(&qdio->req_q_lock);
@@ -1612,7 +1612,7 @@
 		zfcp_fsf_req_free(req);
 out:
 	spin_unlock_irq(&qdio->req_q_lock);
-	if (req && !IS_ERR(req))
+	if (!retval)
 		zfcp_dbf_rec_run_wka("fsowp_1", wka_port, req->req_id);
 	return retval;
 }
@@ -1638,7 +1638,7 @@
 int zfcp_fsf_close_wka_port(struct zfcp_fc_wka_port *wka_port)
 {
 	struct zfcp_qdio *qdio = wka_port->adapter->qdio;
-	struct zfcp_fsf_req *req = NULL;
+	struct zfcp_fsf_req *req;
 	int retval = -EIO;
 
 	spin_lock_irq(&qdio->req_q_lock);
@@ -1667,7 +1667,7 @@
 		zfcp_fsf_req_free(req);
 out:
 	spin_unlock_irq(&qdio->req_q_lock);
-	if (req && !IS_ERR(req))
+	if (!retval)
 		zfcp_dbf_rec_run_wka("fscwp_1", wka_port, req->req_id);
 	return retval;
 }
diff --git a/drivers/scsi/aacraid/comminit.c b/drivers/scsi/aacraid/comminit.c
index 341ea32..792d3e7 100644
--- a/drivers/scsi/aacraid/comminit.c
+++ b/drivers/scsi/aacraid/comminit.c
@@ -50,9 +50,13 @@
 
 static inline int aac_is_msix_mode(struct aac_dev *dev)
 {
-	u32 status;
+	u32 status = 0;
 
-	status = src_readl(dev, MUnit.OMR);
+	if (dev->pdev->device == PMC_DEVICE_S6 ||
+		dev->pdev->device == PMC_DEVICE_S7 ||
+		dev->pdev->device == PMC_DEVICE_S8) {
+		status = src_readl(dev, MUnit.OMR);
+	}
 	return (status & AAC_INT_MODE_MSIX);
 }
 
diff --git a/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c b/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c
index e3b911c..91dfd58 100644
--- a/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c
+++ b/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c
@@ -3929,6 +3929,7 @@
 static const struct target_core_fabric_ops ibmvscsis_ops = {
 	.module				= THIS_MODULE,
 	.name				= "ibmvscsis",
+	.max_data_sg_nents		= MAX_TXU / PAGE_SIZE,
 	.get_fabric_name		= ibmvscsis_get_fabric_name,
 	.tpg_get_wwn			= ibmvscsis_get_fabric_wwn,
 	.tpg_get_tag			= ibmvscsis_get_tag,
diff --git a/drivers/scsi/mpt3sas/mpt3sas_scsih.c b/drivers/scsi/mpt3sas/mpt3sas_scsih.c
index f84a608..8a7941b 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_scsih.c
+++ b/drivers/scsi/mpt3sas/mpt3sas_scsih.c
@@ -51,6 +51,7 @@
 #include <linux/workqueue.h>
 #include <linux/delay.h>
 #include <linux/pci.h>
+#include <linux/pci-aspm.h>
 #include <linux/interrupt.h>
 #include <linux/aer.h>
 #include <linux/raid_class.h>
@@ -8706,6 +8707,8 @@
 
 	switch (hba_mpi_version) {
 	case MPI2_VERSION:
+		pci_disable_link_state(pdev, PCIE_LINK_STATE_L0S |
+			PCIE_LINK_STATE_L1 | PCIE_LINK_STATE_CLKPM);
 		/* Use mpt2sas driver host template for SAS 2.0 HBA's */
 		shost = scsi_host_alloc(&mpt2sas_driver_template,
 		  sizeof(struct MPT3SAS_ADAPTER));
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index 078d797..bea819e 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -1459,7 +1459,7 @@
 				/* Don't abort commands in adapter during EEH
 				 * recovery as it's not accessible/responding.
 				 */
-				if (!ha->flags.eeh_busy) {
+				if (GET_CMD_SP(sp) && !ha->flags.eeh_busy) {
 					/* Get a reference to the sp and drop the lock.
 					 * The reference ensures this sp->done() call
 					 * - and not the call in qla2xxx_eh_abort() -
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index 935f782..9318829 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -1035,7 +1035,8 @@
 	bool is_mq = (rq->mq_ctx != NULL);
 	int error;
 
-	BUG_ON(!rq->nr_phys_segments);
+	if (WARN_ON_ONCE(!rq->nr_phys_segments))
+		return -EINVAL;
 
 	error = scsi_init_sgtable(rq, &cmd->sdb);
 	if (error)
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index 8251f6e..c05cf3b 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -1754,6 +1754,10 @@
 			return res;
 
 		iov_iter_truncate(&i, hp->dxfer_len);
+		if (!iov_iter_count(&i)) {
+			kfree(iov);
+			return -EINVAL;
+		}
 
 		res = blk_rq_map_user_iov(q, rq, md, &i, GFP_ATOMIC);
 		kfree(iov);
diff --git a/drivers/slimbus/slimbus.c b/drivers/slimbus/slimbus.c
index aa7ff12..567f290 100644
--- a/drivers/slimbus/slimbus.c
+++ b/drivers/slimbus/slimbus.c
@@ -1390,8 +1390,10 @@
 		txn.mc = SLIM_MSG_MC_CONNECT_SINK;
 	buf[0] = pn;
 	buf[1] = ctrl->chans[ch].chan;
-	if (la == SLIM_LA_MANAGER)
+	if (la == SLIM_LA_MANAGER) {
 		ctrl->ports[pn].flow = flow;
+		ctrl->ports[pn].ch = &ctrl->chans[ch].prop;
+	}
 	ret = slim_processtxn(ctrl, &txn, false);
 	if (!ret && la == SLIM_LA_MANAGER)
 		ctrl->ports[pn].state = SLIM_P_CFG;
@@ -1467,7 +1469,6 @@
 		ret = -EALREADY;
 		goto connect_src_err;
 	}
-	ctrl->ports[pn].ch = &slc->prop;
 	ret = connect_port_ch(ctrl, chan, srch, SLIM_SRC);
 
 	if (!ret)
@@ -1522,16 +1523,15 @@
 		u8 la = SLIM_HDL_TO_LA(sinkh[j]);
 		u8 pn = SLIM_HDL_TO_PORT(sinkh[j]);
 
-		if (la != SLIM_LA_MANAGER && flow != SLIM_SINK) {
+		if (la != SLIM_LA_MANAGER && flow != SLIM_SINK)
 			ret = -EINVAL;
-		} else if (la == SLIM_LA_MANAGER &&
+		else if (la == SLIM_LA_MANAGER &&
 			   (pn >= ctrl->nports ||
-			    ctrl->ports[pn].state != SLIM_P_UNCFG)) {
+			    ctrl->ports[pn].state != SLIM_P_UNCFG))
 			ret = -EINVAL;
-		} else {
-			ctrl->ports[pn].ch = &slc->prop;
+		else
 			ret = connect_port_ch(ctrl, chan, sinkh[j], SLIM_SINK);
-		}
+
 		if (ret) {
 			for (j = j - 1; j >= 0; j--)
 				disconnect_port_ch(ctrl, sinkh[j]);
@@ -2813,9 +2813,10 @@
 		struct slim_ich *slc = arr[i];
 
 		if (slc->state == SLIM_CH_ACTIVE ||
-			slc->state == SLIM_CH_SUSPENDED)
+			slc->state == SLIM_CH_SUSPENDED) {
 			slc->offset = slc->newoff;
 			slc->interval = slc->newintr;
+		}
 	}
 }
 static void slim_chan_changes(struct slim_device *sb, bool revert)
diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig
index aa51411..a072d35 100644
--- a/drivers/soc/qcom/Kconfig
+++ b/drivers/soc/qcom/Kconfig
@@ -525,6 +525,15 @@
 	  for the platforms that use APRv2.
 	  Say M if you want to enable this module.
 
+config MSM_CDSP_LOADER
+	tristate "CDSP loader support"
+	depends on MSM_GLINK
+	help
+	  Enable CDSP image loader.
+	  The CDSP loader brings CDSP out of reset
+	  for platforms that have compute DSP.
+	  Say M if you want to enable this module.
+
 config MSM_AVTIMER
 	tristate "Avtimer Driver"
 	depends on MSM_QDSP6_APRV2_GLINK || MSM_QDSP6_APRV3_GLINK
diff --git a/drivers/soc/qcom/qdsp6v2/Makefile b/drivers/soc/qcom/qdsp6v2/Makefile
index f3505ba..8c5b0d0 100644
--- a/drivers/soc/qcom/qdsp6v2/Makefile
+++ b/drivers/soc/qcom/qdsp6v2/Makefile
@@ -7,3 +7,4 @@
 obj-$(CONFIG_MSM_QDSP6_SSR) += audio_ssr.o
 obj-$(CONFIG_MSM_QDSP6_PDR) += audio_pdr.o
 obj-$(CONFIG_MSM_QDSP6_NOTIFIER) += audio_notifier.o
+obj-$(CONFIG_MSM_CDSP_LOADER) += cdsp-loader.o
diff --git a/drivers/soc/qcom/qdsp6v2/cdsp-loader.c b/drivers/soc/qcom/qdsp6v2/cdsp-loader.c
new file mode 100644
index 0000000..9bb4eb0
--- /dev/null
+++ b/drivers/soc/qcom/qdsp6v2/cdsp-loader.c
@@ -0,0 +1,271 @@
+/*
+ * Copyright (c) 2012-2014, 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/of_device.h>
+#include <linux/sysfs.h>
+#include <soc/qcom/subsystem_restart.h>
+
+#define BOOT_CMD 1
+#define IMAGE_UNLOAD_CMD 0
+
+#define CDSP_SUBSYS_DOWN 0
+#define CDSP_SUBSYS_LOADED 1
+
+static ssize_t cdsp_boot_store(struct kobject *kobj,
+	struct kobj_attribute *attr,
+	const char *buf, size_t count);
+
+struct cdsp_loader_private {
+	void *pil_h;
+	struct kobject *boot_cdsp_obj;
+	struct attribute_group *attr_group;
+};
+
+static struct kobj_attribute cdsp_boot_attribute =
+	__ATTR(boot, 0220, NULL, cdsp_boot_store);
+
+static struct attribute *attrs[] = {
+	&cdsp_boot_attribute.attr,
+	NULL,
+};
+
+static u32 cdsp_state = CDSP_SUBSYS_DOWN;
+static struct platform_device *cdsp_private;
+static void cdsp_loader_unload(struct platform_device *pdev);
+
+static int cdsp_loader_do(struct platform_device *pdev)
+{
+	struct cdsp_loader_private *priv = NULL;
+
+	int rc = 0;
+	const char *img_name;
+
+	if (!pdev) {
+		dev_err(&pdev->dev, "%s: Platform device null\n", __func__);
+		goto fail;
+	}
+
+	if (!pdev->dev.of_node) {
+		dev_err(&pdev->dev,
+			"%s: Device tree information missing\n", __func__);
+
+		goto fail;
+	}
+
+	rc = of_property_read_string(pdev->dev.of_node,
+					"qcom,proc-img-to-load",
+					&img_name);
+	if (rc)
+		goto fail;
+
+	if (!strcmp(img_name, "cdsp")) {
+		/* cdsp_state always returns "0".*/
+		if (cdsp_state == CDSP_SUBSYS_DOWN) {
+			priv = platform_get_drvdata(pdev);
+			if (!priv) {
+				dev_err(&pdev->dev,
+				" %s: Private data get failed\n", __func__);
+				goto fail;
+			}
+
+			priv->pil_h = subsystem_get("cdsp");
+			if (IS_ERR(priv->pil_h)) {
+				dev_err(&pdev->dev, "%s: pil get failed,\n",
+					__func__);
+				goto fail;
+			}
+
+			/* Set the state of the CDSP.*/
+			cdsp_state = CDSP_SUBSYS_LOADED;
+		} else if (cdsp_state == CDSP_SUBSYS_LOADED) {
+			dev_dbg(&pdev->dev,
+			"%s: CDSP state = %x\n", __func__, cdsp_state);
+		}
+
+		dev_dbg(&pdev->dev, "%s: CDSP image is loaded\n", __func__);
+		return rc;
+	}
+
+fail:
+	dev_err(&pdev->dev, "%s: CDSP image loading failed\n", __func__);
+	return rc;
+}
+
+
+static ssize_t cdsp_boot_store(struct kobject *kobj,
+	struct kobj_attribute *attr,
+	const char *buf,
+	size_t count)
+{
+	int boot = 0, ret = 0;
+
+	ret = sscanf(buf, "%du", &boot);
+
+	if (ret != 1)
+		pr_debug("%s: invalid arguments for cdsp_loader.\n", __func__);
+
+	if (boot == BOOT_CMD) {
+		pr_debug("%s: going to call cdsp_loader_do\n", __func__);
+		cdsp_loader_do(cdsp_private);
+	} else if (boot == IMAGE_UNLOAD_CMD) {
+		pr_debug("%s: going to call adsp_unloader\n", __func__);
+		cdsp_loader_unload(cdsp_private);
+	}
+	return count;
+}
+
+static void cdsp_loader_unload(struct platform_device *pdev)
+{
+	struct cdsp_loader_private *priv = NULL;
+
+	priv = platform_get_drvdata(pdev);
+
+	if (!priv)
+		return;
+
+	if (priv->pil_h) {
+		dev_dbg(&pdev->dev, "%s: calling subsystem put\n", __func__);
+		subsystem_put(priv->pil_h);
+		priv->pil_h = NULL;
+	}
+}
+
+static int cdsp_loader_init_sysfs(struct platform_device *pdev)
+{
+	int ret = -EINVAL;
+	struct cdsp_loader_private *priv = NULL;
+
+	cdsp_private = NULL;
+
+	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv) {
+		ret = -ENOMEM;
+		return ret;
+	}
+
+	platform_set_drvdata(pdev, priv);
+
+	priv->pil_h = NULL;
+	priv->boot_cdsp_obj = NULL;
+	priv->attr_group = devm_kzalloc(&pdev->dev,
+				sizeof(*(priv->attr_group)),
+				GFP_KERNEL);
+	if (!priv->attr_group) {
+		dev_err(&pdev->dev, "%s: malloc attr_group failed\n",
+						__func__);
+		ret = -ENOMEM;
+		goto error_return;
+	}
+
+	priv->attr_group->attrs = attrs;
+
+	priv->boot_cdsp_obj = kobject_create_and_add("boot_cdsp", kernel_kobj);
+	if (!priv->boot_cdsp_obj) {
+		dev_err(&pdev->dev, "%s: sysfs create and add failed\n",
+						__func__);
+		ret = -ENOMEM;
+		goto error_return;
+	}
+
+	ret = sysfs_create_group(priv->boot_cdsp_obj, priv->attr_group);
+	if (ret) {
+		dev_err(&pdev->dev, "%s: sysfs create group failed %d\n",
+							__func__, ret);
+		goto error_return;
+	}
+
+	cdsp_private = pdev;
+
+	return 0;
+
+error_return:
+
+	if (priv->boot_cdsp_obj) {
+		kobject_del(priv->boot_cdsp_obj);
+		priv->boot_cdsp_obj = NULL;
+	}
+
+	return ret;
+}
+
+static int cdsp_loader_remove(struct platform_device *pdev)
+{
+	struct cdsp_loader_private *priv = NULL;
+
+	priv = platform_get_drvdata(pdev);
+
+	if (!priv)
+		return 0;
+
+	if (priv->pil_h) {
+		subsystem_put(priv->pil_h);
+		priv->pil_h = NULL;
+	}
+
+	if (priv->boot_cdsp_obj) {
+		sysfs_remove_group(priv->boot_cdsp_obj, priv->attr_group);
+		kobject_del(priv->boot_cdsp_obj);
+		priv->boot_cdsp_obj = NULL;
+	}
+
+	return 0;
+}
+
+static int cdsp_loader_probe(struct platform_device *pdev)
+{
+	int ret = cdsp_loader_init_sysfs(pdev);
+
+	if (ret != 0) {
+		dev_err(&pdev->dev, "%s: Error in initing sysfs\n", __func__);
+		return ret;
+	}
+
+	return 0;
+}
+
+static const struct of_device_id cdsp_loader_dt_match[] = {
+	{ .compatible = "qcom,cdsp-loader" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, cdsp_loader_dt_match);
+
+static struct platform_driver cdsp_loader_driver = {
+	.driver = {
+		.name = "cdsp-loader",
+		.owner = THIS_MODULE,
+		.of_match_table = cdsp_loader_dt_match,
+	},
+	.probe = cdsp_loader_probe,
+	.remove = cdsp_loader_remove,
+};
+
+static int __init cdsp_loader_init(void)
+{
+	return platform_driver_register(&cdsp_loader_driver);
+}
+module_init(cdsp_loader_init);
+
+static void __exit cdsp_loader_exit(void)
+{
+	platform_driver_unregister(&cdsp_loader_driver);
+}
+module_exit(cdsp_loader_exit);
+
+MODULE_DESCRIPTION("CDSP Loader module");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/soc/qcom/rpmh.c b/drivers/soc/qcom/rpmh.c
index baf3e3f..6d312a0 100644
--- a/drivers/soc/qcom/rpmh.c
+++ b/drivers/soc/qcom/rpmh.c
@@ -245,16 +245,6 @@
 	int ret = 0;
 	int i;
 
-	/*
-	 * We cannot wait for completion for a sleep set, its done
-	 * outside the processor.
-	 */
-	if (rpm_msg->msg.is_complete &&
-		(state == RPMH_SLEEP_STATE || state == RPMH_WAKE_ONLY_STATE)) {
-		pr_err("Mismatch: sleep/wake set with completion.\n");
-		return -EINVAL;
-	}
-
 	/* Cache the request in our store and link the payload */
 	for (i = 0; i < rpm_msg->msg.num_payload; i++) {
 		req = cache_rpm_request(rc, state, &rpm_msg->msg.payload[i]);
@@ -638,7 +628,8 @@
 {
 	DEFINE_RPMH_MSG_ONSTACK(rc, state, NULL, NULL, rpm_msg);
 
-	rpm_msg.msg.is_complete = false;
+	/* Wake sets are always complete and sleep sets are not */
+	rpm_msg.msg.is_complete = (state == RPMH_WAKE_ONLY_STATE);
 	rpm_msg.cmd.addr = addr;
 	rpm_msg.cmd.data = data;
 
@@ -673,7 +664,7 @@
 
 	spin_lock(&rpm->lock);
 	if (!rpm->dirty) {
-		pr_info("Skipping flush, TCS has latest data.\n");
+		pr_debug("Skipping flush, TCS has latest data.\n");
 		spin_unlock(&rpm->lock);
 		return 0;
 	}
diff --git a/drivers/soc/qcom/system_pm.c b/drivers/soc/qcom/system_pm.c
index 78690d9..2855a15 100644
--- a/drivers/soc/qcom/system_pm.c
+++ b/drivers/soc/qcom/system_pm.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -16,6 +16,7 @@
 
 #include <soc/qcom/rpmh.h>
 
+#define ARCH_TIMER_HZ		(19200000UL)
 #define PDC_TIME_VALID_SHIFT	31
 #define PDC_TIME_UPPER_MASK	0xFFFFFF
 
@@ -25,9 +26,9 @@
 {
 	struct tcs_cmd cmd[3] = { { 0 } };
 
-	cmd[0].data = sleep_val & 0xFFFFFFFF;
-	cmd[1].data = (sleep_val >> 32) & PDC_TIME_UPPER_MASK;
-	cmd[1].data |= 1 << PDC_TIME_VALID_SHIFT;
+	cmd[0].data = (sleep_val >> 32) & PDC_TIME_UPPER_MASK;
+	cmd[0].data |= 1 << PDC_TIME_VALID_SHIFT;
+	cmd[1].data = sleep_val & 0xFFFFFFFF;
 
 	return rpmh_write_control(rpmh_client, cmd, ARRAY_SIZE(cmd));
 }
@@ -35,7 +36,7 @@
 /**
  * system_sleep_enter() - Activties done when entering system low power modes
  *
- * @sleep_val: The qtimer value for the next wakeup time
+ * @sleep_val: The sleep duration in us.
  *
  * Returns 0 for success or error values from writing the timer value in the
  * hardware block.
@@ -51,6 +52,14 @@
 	if (ret)
 		return ret;
 
+	/*
+	 * Set up the wake up value offset from the current time.
+	 * Convert us to ns to allow div by 19.2 Mhz tick timer.
+	 */
+	sleep_val *= NSEC_PER_USEC;
+	do_div(sleep_val, NSEC_PER_SEC/ARCH_TIMER_HZ);
+	sleep_val += arch_counter_get_cntvct();
+
 	return setup_wakeup(sleep_val);
 }
 EXPORT_SYMBOL(system_sleep_enter);
diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c
index 6b42348..ea9617c 100644
--- a/drivers/target/target_core_device.c
+++ b/drivers/target/target_core_device.c
@@ -351,7 +351,15 @@
 			kfree(new);
 			return -EINVAL;
 		}
-		BUG_ON(orig->se_lun_acl != NULL);
+		if (orig->se_lun_acl != NULL) {
+			pr_warn_ratelimited("Detected existing explicit"
+				" se_lun_acl->se_lun_group reference for %s"
+				" mapped_lun: %llu, failing\n",
+				 nacl->initiatorname, mapped_lun);
+			mutex_unlock(&nacl->lun_entry_mutex);
+			kfree(new);
+			return -EINVAL;
+		}
 
 		rcu_assign_pointer(new->se_lun, lun);
 		rcu_assign_pointer(new->se_lun_acl, lun_acl);
diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c
index 04f616b..aabd660 100644
--- a/drivers/target/target_core_sbc.c
+++ b/drivers/target/target_core_sbc.c
@@ -450,6 +450,7 @@
 					     int *post_ret)
 {
 	struct se_device *dev = cmd->se_dev;
+	sense_reason_t ret = TCM_NO_SENSE;
 
 	/*
 	 * Only set SCF_COMPARE_AND_WRITE_POST to force a response fall-through
@@ -457,9 +458,12 @@
 	 * sent to the backend driver.
 	 */
 	spin_lock_irq(&cmd->t_state_lock);
-	if ((cmd->transport_state & CMD_T_SENT) && !cmd->scsi_status) {
+	if (cmd->transport_state & CMD_T_SENT) {
 		cmd->se_cmd_flags |= SCF_COMPARE_AND_WRITE_POST;
 		*post_ret = 1;
+
+		if (cmd->scsi_status == SAM_STAT_CHECK_CONDITION)
+			ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
 	}
 	spin_unlock_irq(&cmd->t_state_lock);
 
@@ -469,7 +473,7 @@
 	 */
 	up(&dev->caw_sem);
 
-	return TCM_NO_SENSE;
+	return ret;
 }
 
 static sense_reason_t compare_and_write_callback(struct se_cmd *cmd, bool success,
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c
index 7dfefd6..767d1eb6 100644
--- a/drivers/target/target_core_transport.c
+++ b/drivers/target/target_core_transport.c
@@ -457,8 +457,20 @@
 {
 	struct se_node_acl *nacl = container_of(kref,
 				struct se_node_acl, acl_kref);
+	struct se_portal_group *se_tpg = nacl->se_tpg;
 
-	complete(&nacl->acl_free_comp);
+	if (!nacl->dynamic_stop) {
+		complete(&nacl->acl_free_comp);
+		return;
+	}
+
+	mutex_lock(&se_tpg->acl_node_mutex);
+	list_del(&nacl->acl_list);
+	mutex_unlock(&se_tpg->acl_node_mutex);
+
+	core_tpg_wait_for_nacl_pr_ref(nacl);
+	core_free_device_list_for_node(nacl, se_tpg);
+	kfree(nacl);
 }
 
 void target_put_nacl(struct se_node_acl *nacl)
@@ -499,12 +511,39 @@
 void transport_free_session(struct se_session *se_sess)
 {
 	struct se_node_acl *se_nacl = se_sess->se_node_acl;
+
 	/*
 	 * Drop the se_node_acl->nacl_kref obtained from within
 	 * core_tpg_get_initiator_node_acl().
 	 */
 	if (se_nacl) {
+		struct se_portal_group *se_tpg = se_nacl->se_tpg;
+		const struct target_core_fabric_ops *se_tfo = se_tpg->se_tpg_tfo;
+		unsigned long flags;
+
 		se_sess->se_node_acl = NULL;
+
+		/*
+		 * Also determine if we need to drop the extra ->cmd_kref if
+		 * it had been previously dynamically generated, and
+		 * the endpoint is not caching dynamic ACLs.
+		 */
+		mutex_lock(&se_tpg->acl_node_mutex);
+		if (se_nacl->dynamic_node_acl &&
+		    !se_tfo->tpg_check_demo_mode_cache(se_tpg)) {
+			spin_lock_irqsave(&se_nacl->nacl_sess_lock, flags);
+			if (list_empty(&se_nacl->acl_sess_list))
+				se_nacl->dynamic_stop = true;
+			spin_unlock_irqrestore(&se_nacl->nacl_sess_lock, flags);
+
+			if (se_nacl->dynamic_stop)
+				list_del(&se_nacl->acl_list);
+		}
+		mutex_unlock(&se_tpg->acl_node_mutex);
+
+		if (se_nacl->dynamic_stop)
+			target_put_nacl(se_nacl);
+
 		target_put_nacl(se_nacl);
 	}
 	if (se_sess->sess_cmd_map) {
@@ -518,16 +557,12 @@
 void transport_deregister_session(struct se_session *se_sess)
 {
 	struct se_portal_group *se_tpg = se_sess->se_tpg;
-	const struct target_core_fabric_ops *se_tfo;
-	struct se_node_acl *se_nacl;
 	unsigned long flags;
-	bool drop_nacl = false;
 
 	if (!se_tpg) {
 		transport_free_session(se_sess);
 		return;
 	}
-	se_tfo = se_tpg->se_tpg_tfo;
 
 	spin_lock_irqsave(&se_tpg->session_lock, flags);
 	list_del(&se_sess->sess_list);
@@ -535,33 +570,15 @@
 	se_sess->fabric_sess_ptr = NULL;
 	spin_unlock_irqrestore(&se_tpg->session_lock, flags);
 
-	/*
-	 * Determine if we need to do extra work for this initiator node's
-	 * struct se_node_acl if it had been previously dynamically generated.
-	 */
-	se_nacl = se_sess->se_node_acl;
-
-	mutex_lock(&se_tpg->acl_node_mutex);
-	if (se_nacl && se_nacl->dynamic_node_acl) {
-		if (!se_tfo->tpg_check_demo_mode_cache(se_tpg)) {
-			list_del(&se_nacl->acl_list);
-			drop_nacl = true;
-		}
-	}
-	mutex_unlock(&se_tpg->acl_node_mutex);
-
-	if (drop_nacl) {
-		core_tpg_wait_for_nacl_pr_ref(se_nacl);
-		core_free_device_list_for_node(se_nacl, se_tpg);
-		se_sess->se_node_acl = NULL;
-		kfree(se_nacl);
-	}
 	pr_debug("TARGET_CORE[%s]: Deregistered fabric_sess\n",
 		se_tpg->se_tpg_tfo->get_fabric_name());
 	/*
 	 * If last kref is dropping now for an explicit NodeACL, awake sleeping
 	 * ->acl_free_comp caller to wakeup configfs se_node_acl->acl_group
 	 * removal context from within transport_free_session() code.
+	 *
+	 * For dynamic ACL, target_put_nacl() uses target_complete_nacl()
+	 * to release all remaining generate_node_acl=1 created ACL resources.
 	 */
 
 	transport_free_session(se_sess);
@@ -3086,7 +3103,6 @@
 		spin_unlock_irqrestore(&cmd->t_state_lock, flags);
 		goto check_stop;
 	}
-	cmd->t_state = TRANSPORT_ISTATE_PROCESSING;
 	spin_unlock_irqrestore(&cmd->t_state_lock, flags);
 
 	cmd->se_tfo->queue_tm_rsp(cmd);
@@ -3099,11 +3115,25 @@
 	struct se_cmd *cmd)
 {
 	unsigned long flags;
+	bool aborted = false;
 
 	spin_lock_irqsave(&cmd->t_state_lock, flags);
-	cmd->transport_state |= CMD_T_ACTIVE;
+	if (cmd->transport_state & CMD_T_ABORTED) {
+		aborted = true;
+	} else {
+		cmd->t_state = TRANSPORT_ISTATE_PROCESSING;
+		cmd->transport_state |= CMD_T_ACTIVE;
+	}
 	spin_unlock_irqrestore(&cmd->t_state_lock, flags);
 
+	if (aborted) {
+		pr_warn_ratelimited("handle_tmr caught CMD_T_ABORTED TMR %d"
+			"ref_tag: %llu tag: %llu\n", cmd->se_tmr_req->function,
+			cmd->se_tmr_req->ref_task_tag, cmd->tag);
+		transport_cmd_check_stop_to_fabric(cmd);
+		return 0;
+	}
+
 	INIT_WORK(&cmd->work, target_tmr_work);
 	queue_work(cmd->se_dev->tmr_wq, &cmd->work);
 	return 0;
diff --git a/drivers/target/target_core_xcopy.c b/drivers/target/target_core_xcopy.c
index 094a144..18848ba 100644
--- a/drivers/target/target_core_xcopy.c
+++ b/drivers/target/target_core_xcopy.c
@@ -836,7 +836,7 @@
 			" CHECK_CONDITION -> sending response\n", rc);
 		ec_cmd->scsi_status = SAM_STAT_CHECK_CONDITION;
 	}
-	target_complete_cmd(ec_cmd, SAM_STAT_CHECK_CONDITION);
+	target_complete_cmd(ec_cmd, ec_cmd->scsi_status);
 }
 
 sense_reason_t target_do_xcopy(struct se_cmd *se_cmd)
diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c
index 079e6b1a..3c48dea 100644
--- a/drivers/usb/dwc3/dwc3-msm.c
+++ b/drivers/usb/dwc3/dwc3-msm.c
@@ -1470,6 +1470,7 @@
 		return;
 	}
 
+	dbg_event(0xFF, "RestartUSB", 0);
 	/* Reset active USB connection */
 	dwc3_resume_work(&mdwc->resume_work);
 
@@ -1480,6 +1481,8 @@
 	if (!timeout) {
 		dev_dbg(mdwc->dev,
 			"Not in LPM after disconnect, forcing suspend...\n");
+		dbg_event(0xFF, "ReStart:RT SUSP",
+			atomic_read(&mdwc->dev->power.usage_count));
 		pm_runtime_suspend(mdwc->dev);
 	}
 
@@ -1866,6 +1869,8 @@
 	}
 
 	if (!mdwc->init) {
+		dbg_event(0xFF, "dwc3 init",
+				atomic_read(&mdwc->dev->power.usage_count));
 		dwc3_core_pre_init(dwc);
 		mdwc->init = true;
 	}
@@ -2262,6 +2267,7 @@
 	 */
 	dwc3_pwr_event_handler(mdwc);
 
+	dbg_event(0xFF, "Ctl Res", atomic_read(&dwc->in_lpm));
 	return 0;
 }
 
@@ -2305,6 +2311,7 @@
 static void dwc3_resume_work(struct work_struct *w)
 {
 	struct dwc3_msm *mdwc = container_of(w, struct dwc3_msm, resume_work);
+	struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3);
 
 	dev_dbg(mdwc->dev, "%s: dwc3 resume work\n", __func__);
 
@@ -2320,9 +2327,11 @@
 		mdwc->resume_pending = false;
 	}
 
-	if (atomic_read(&mdwc->pm_suspended))
+	if (atomic_read(&mdwc->pm_suspended)) {
+		dbg_event(0xFF, "RWrk PMSus", 0);
 		/* let pm resume kick in resume work later */
 		return;
+	}
 	dwc3_ext_event_notify(mdwc);
 }
 
@@ -2394,6 +2403,7 @@
 	else
 		dwc3_pwr_event_handler(mdwc);
 
+	dbg_event(0xFF, "PWR IRQ", atomic_read(&dwc->in_lpm));
 	return IRQ_HANDLED;
 }
 
@@ -2578,7 +2588,7 @@
 		mdwc->typec_orientation =
 			cc_state ? ORIENTATION_CC2 : ORIENTATION_CC1;
 
-	dev_dbg(mdwc->dev, "cc_state:%d", mdwc->typec_orientation);
+	dbg_event(0xFF, "cc_state", mdwc->typec_orientation);
 
 	speed = extcon_get_cable_state_(edev, EXTCON_USB_SPEED);
 	dwc->maximum_speed = (speed == 0) ? USB_SPEED_HIGH : USB_SPEED_SUPER;
@@ -2587,6 +2597,7 @@
 
 	if (mdwc->id_state != id) {
 		mdwc->id_state = id;
+		dbg_event(0xFF, "id_state", mdwc->id_state);
 		queue_work(mdwc->dwc3_wq, &mdwc->resume_work);
 	}
 
@@ -2620,7 +2631,7 @@
 		mdwc->typec_orientation =
 			cc_state ? ORIENTATION_CC2 : ORIENTATION_CC1;
 
-	dev_dbg(mdwc->dev, "cc_state:%d", mdwc->typec_orientation);
+	dbg_event(0xFF, "cc_state", mdwc->typec_orientation);
 
 	speed = extcon_get_cable_state_(edev, EXTCON_USB_SPEED);
 	dwc->maximum_speed = (speed == 0) ? USB_SPEED_HIGH : USB_SPEED_SUPER;
@@ -3105,6 +3116,7 @@
 static int dwc3_msm_remove(struct platform_device *pdev)
 {
 	struct dwc3_msm	*mdwc = platform_get_drvdata(pdev);
+	struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3);
 	int ret_pm;
 
 	device_remove_file(&pdev->dev, &dev_attr_mode);
@@ -3117,6 +3129,7 @@
 	 * Hence turn ON the clocks manually.
 	 */
 	ret_pm = pm_runtime_get_sync(mdwc->dev);
+	dbg_event(0xFF, "Remov gsyn", ret_pm);
 	if (ret_pm < 0) {
 		dev_err(mdwc->dev,
 			"pm_runtime_get_sync failed with %d\n", ret_pm);
@@ -3138,6 +3151,7 @@
 	platform_device_put(mdwc->dwc3);
 	device_for_each_child(&pdev->dev, NULL, dwc3_msm_remove_children);
 
+	dbg_event(0xFF, "Remov put", 0);
 	pm_runtime_disable(mdwc->dev);
 	pm_runtime_barrier(mdwc->dev);
 	pm_runtime_put_sync(mdwc->dev);
@@ -3275,6 +3289,8 @@
 			mdwc->ss_phy->flags |= PHY_HOST_MODE;
 
 		pm_runtime_get_sync(mdwc->dev);
+		dbg_event(0xFF, "StrtHost gync",
+			atomic_read(&mdwc->dev->power.usage_count));
 		usb_phy_notify_connect(mdwc->hs_phy, USB_SPEED_HIGH);
 		if (!IS_ERR(mdwc->vbus_reg))
 			ret = regulator_enable(mdwc->vbus_reg);
@@ -3283,6 +3299,8 @@
 			mdwc->hs_phy->flags &= ~PHY_HOST_MODE;
 			mdwc->ss_phy->flags &= ~PHY_HOST_MODE;
 			pm_runtime_put_sync(mdwc->dev);
+			dbg_event(0xFF, "vregerr psync",
+				atomic_read(&mdwc->dev->power.usage_count));
 			return ret;
 		}
 
@@ -3309,6 +3327,8 @@
 			mdwc->hs_phy->flags &= ~PHY_HOST_MODE;
 			mdwc->ss_phy->flags &= ~PHY_HOST_MODE;
 			pm_runtime_put_sync(mdwc->dev);
+			dbg_event(0xFF, "pdeverr psync",
+				atomic_read(&mdwc->dev->power.usage_count));
 			usb_unregister_notify(&mdwc->host_nb);
 			return ret;
 		}
@@ -3325,6 +3345,8 @@
 		dwc3_usb3_phy_suspend(dwc, true);
 
 		/* xHCI should have incremented child count as necessary */
+		dbg_event(0xFF, "StrtHost psync",
+			atomic_read(&mdwc->dev->power.usage_count));
 		pm_runtime_mark_last_busy(mdwc->dev);
 		pm_runtime_put_sync_autosuspend(mdwc->dev);
 	} else {
@@ -3338,6 +3360,8 @@
 		}
 
 		pm_runtime_get_sync(mdwc->dev);
+		dbg_event(0xFF, "StopHost gsync",
+			atomic_read(&mdwc->dev->power.usage_count));
 		usb_phy_notify_disconnect(mdwc->hs_phy, USB_SPEED_HIGH);
 		mdwc->hs_phy->flags &= ~PHY_HOST_MODE;
 		mdwc->ss_phy->flags &= ~PHY_HOST_MODE;
@@ -3360,6 +3384,8 @@
 		dwc3_post_host_reset_core_init(dwc);
 		pm_runtime_mark_last_busy(mdwc->dev);
 		pm_runtime_put_sync_autosuspend(mdwc->dev);
+		dbg_event(0xFF, "StopHost psync",
+			atomic_read(&mdwc->dev->power.usage_count));
 	}
 
 	return 0;
@@ -3397,6 +3423,8 @@
 	struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3);
 
 	pm_runtime_get_sync(mdwc->dev);
+	dbg_event(0xFF, "StrtGdgt gsync",
+		atomic_read(&mdwc->dev->power.usage_count));
 
 	if (on) {
 		dev_dbg(mdwc->dev, "%s: turn on gadget %s\n",
@@ -3425,6 +3453,8 @@
 	}
 
 	pm_runtime_put_sync(mdwc->dev);
+	dbg_event(0xFF, "StopGdgt psync",
+		atomic_read(&mdwc->dev->power.usage_count));
 
 	return 0;
 }
@@ -3494,6 +3524,7 @@
 
 	state = usb_otg_state_string(mdwc->otg_state);
 	dev_dbg(mdwc->dev, "%s state\n", state);
+	dbg_event(0xFF, state, 0);
 
 	/* Check OTG state */
 	switch (mdwc->otg_state) {
@@ -3503,6 +3534,7 @@
 				!test_bit(B_SESS_VLD, &mdwc->inputs))
 			break;
 
+		dbg_event(0xFF, "Exit UNDEF", 0);
 		mdwc->otg_state = OTG_STATE_B_IDLE;
 		/* fall-through */
 	case OTG_STATE_B_IDLE:
@@ -3518,6 +3550,8 @@
 			 * cable disconnect or in bus suspend.
 			 */
 			pm_runtime_get_sync(mdwc->dev);
+			dbg_event(0xFF, "BIDLE gsync",
+				atomic_read(&mdwc->dev->power.usage_count));
 			dwc3_otg_start_peripheral(mdwc, 1);
 			mdwc->otg_state = OTG_STATE_B_PERIPHERAL;
 			work = 1;
@@ -3539,6 +3573,8 @@
 			 * OTG_STATE_B_IDLE state
 			 */
 			pm_runtime_put_sync(mdwc->dev);
+			dbg_event(0xFF, "!BSV psync",
+				atomic_read(&mdwc->dev->power.usage_count));
 			work = 1;
 		} else if (test_bit(B_SUSPEND, &mdwc->inputs) &&
 			test_bit(B_SESS_VLD, &mdwc->inputs)) {
@@ -3553,6 +3589,8 @@
 			 */
 			pm_runtime_mark_last_busy(mdwc->dev);
 			pm_runtime_put_autosuspend(mdwc->dev);
+			dbg_event(0xFF, "SUSP put",
+				atomic_read(&mdwc->dev->power.usage_count));
 		}
 		break;
 
@@ -3571,6 +3609,8 @@
 			 * OTG_STATE_B_PERIPHERAL state.
 			 */
 			pm_runtime_get_sync(mdwc->dev);
+			dbg_event(0xFF, "!SUSP gsync",
+				atomic_read(&mdwc->dev->power.usage_count));
 		}
 		break;
 
@@ -3612,6 +3652,7 @@
 			work = 1;
 		} else {
 			dev_dbg(mdwc->dev, "still in a_host state. Resuming root hub.\n");
+			dbg_event(0xFF, "XHCIResume", 0);
 			if (dwc)
 				pm_runtime_resume(&dwc->xhci->dev);
 		}
@@ -3637,6 +3678,7 @@
 	struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3);
 
 	dev_dbg(dev, "dwc3-msm PM suspend\n");
+	dbg_event(0xFF, "PM Sus", 0);
 
 	flush_workqueue(mdwc->dwc3_wq);
 	if (!atomic_read(&dwc->in_lpm)) {
@@ -3654,8 +3696,10 @@
 static int dwc3_msm_pm_resume(struct device *dev)
 {
 	struct dwc3_msm *mdwc = dev_get_drvdata(dev);
+	struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3);
 
 	dev_dbg(dev, "dwc3-msm PM resume\n");
+	dbg_event(0xFF, "PM Res", 0);
 
 	/* flush to avoid race in read/write of pm_suspended */
 	flush_workqueue(mdwc->dwc3_wq);
@@ -3671,7 +3715,11 @@
 #ifdef CONFIG_PM
 static int dwc3_msm_runtime_idle(struct device *dev)
 {
+	struct dwc3_msm *mdwc = dev_get_drvdata(dev);
+	struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3);
+
 	dev_dbg(dev, "DWC3-msm runtime idle\n");
+	dbg_event(0xFF, "RT Idle", 0);
 
 	return 0;
 }
@@ -3679,8 +3727,10 @@
 static int dwc3_msm_runtime_suspend(struct device *dev)
 {
 	struct dwc3_msm *mdwc = dev_get_drvdata(dev);
+	struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3);
 
 	dev_dbg(dev, "DWC3-msm runtime suspend\n");
+	dbg_event(0xFF, "RT Sus", 0);
 
 	return dwc3_msm_suspend(mdwc);
 }
@@ -3688,8 +3738,10 @@
 static int dwc3_msm_runtime_resume(struct device *dev)
 {
 	struct dwc3_msm *mdwc = dev_get_drvdata(dev);
+	struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3);
 
 	dev_dbg(dev, "DWC3-msm runtime resume\n");
+	dbg_event(0xFF, "RT Res", 0);
 
 	return dwc3_msm_resume(mdwc);
 }
diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c
index ee60147..ed218fa 100644
--- a/drivers/usb/dwc3/ep0.c
+++ b/drivers/usb/dwc3/ep0.c
@@ -288,6 +288,7 @@
 	struct dwc3_ep			*dep = to_dwc3_ep(ep);
 	struct dwc3			*dwc = dep->dwc;
 
+	dbg_event(dep->number, "EP0STAL", value);
 	dwc3_ep0_stall_and_restart(dwc);
 
 	return 0;
@@ -314,7 +315,8 @@
 	dwc3_ep0_prepare_one_trb(dwc, 0, dwc->ctrl_req_addr, 8,
 			DWC3_TRBCTL_CONTROL_SETUP, false);
 	ret = dwc3_ep0_start_trans(dwc, 0);
-	WARN_ON(ret < 0);
+	if (WARN_ON(ret < 0))
+		dbg_event(dwc->eps[0]->number, "EOUTSTART", ret);
 }
 
 static struct dwc3_ep *dwc3_wIndex_to_dep(struct dwc3 *dwc, __le16 wIndex_le)
@@ -656,7 +658,8 @@
 	/* now that we have the time, issue DGCMD Set Sel */
 	ret = dwc3_send_gadget_generic_command(dwc,
 			DWC3_DGCMD_SET_PERIODIC_PAR, param);
-	WARN_ON(ret < 0);
+	if (WARN_ON(ret < 0))
+		dbg_event(dep->number, "ESET_SELCMPL", ret);
 }
 
 static int dwc3_ep0_set_sel(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
@@ -782,6 +785,7 @@
 		dwc->ep0_next_event = DWC3_EP0_NRDY_DATA;
 	}
 
+	dbg_setup(0x00, ctrl);
 	if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD)
 		ret = dwc3_ep0_std_request(dwc, ctrl);
 	else
@@ -791,8 +795,10 @@
 		dwc->delayed_status = true;
 
 out:
-	if (ret < 0)
+	if (ret < 0) {
+		dbg_event(0x0, "ERRSTAL", ret);
 		dwc3_ep0_stall_and_restart(dwc);
+	}
 }
 
 static void dwc3_ep0_complete_data(struct dwc3 *dwc,
@@ -876,7 +882,7 @@
 
 	if ((epnum & 1) && ur->actual < ur->length) {
 		/* for some reason we did not get everything out */
-
+		dbg_event(epnum, "INDATSTAL", 0);
 		dwc3_ep0_stall_and_restart(dwc);
 	} else {
 		dwc3_gadget_giveback(ep0, r, 0);
@@ -890,7 +896,8 @@
 			dwc3_ep0_prepare_one_trb(dwc, epnum, dwc->ctrl_req_addr,
 					0, DWC3_TRBCTL_CONTROL_DATA, false);
 			ret = dwc3_ep0_start_trans(dwc, epnum);
-			WARN_ON(ret < 0);
+			if (WARN_ON(ret < 0))
+				dbg_event(epnum, "ECTRL_DATA", ret);
 		}
 	}
 }
@@ -921,6 +928,7 @@
 		if (ret < 0) {
 			dwc3_trace(trace_dwc3_ep0, "Invalid Test #%d",
 					dwc->test_mode_nr);
+			dbg_event(0x00, "INVALTEST", ret);
 			dwc3_ep0_stall_and_restart(dwc);
 			return;
 		}
@@ -932,6 +940,7 @@
 		dwc3_trace(trace_dwc3_ep0, "Setup Pending received");
 	}
 
+	dbg_print(dep->number, "DONE", status, "STATUS");
 	dwc->ep0state = EP0_SETUP_PHASE;
 	dwc3_ep0_out_start(dwc);
 }
@@ -1025,6 +1034,7 @@
 	}
 
 	WARN_ON(ret < 0);
+	dbg_queue(dep->number, &req->request, ret);
 }
 
 static int dwc3_ep0_start_control_status(struct dwc3_ep *dep)
@@ -1042,13 +1052,17 @@
 
 static void __dwc3_ep0_do_control_status(struct dwc3 *dwc, struct dwc3_ep *dep)
 {
+	int ret;
+
 	if (dwc->resize_fifos) {
 		dwc3_trace(trace_dwc3_ep0, "Resizing FIFOs");
 		dwc3_gadget_resize_tx_fifos(dwc);
 		dwc->resize_fifos = 0;
 	}
 
-	WARN_ON(dwc3_ep0_start_control_status(dep));
+	ret = dwc3_ep0_start_control_status(dep);
+	if (WARN_ON_ONCE(ret))
+		dbg_event(dep->number, "ECTRLSTATUS", ret);
 }
 
 static void dwc3_ep0_do_control_status(struct dwc3 *dwc,
@@ -1073,7 +1087,11 @@
 	cmd |= DWC3_DEPCMD_PARAM(dep->resource_index);
 	memset(&params, 0, sizeof(params));
 	ret = dwc3_send_gadget_ep_cmd(dep, cmd, &params);
-	WARN_ON_ONCE(ret);
+	if (ret) {
+		dev_dbg(dwc->dev, "%s: send ep cmd ENDTRANSFER failed",
+			dep->name);
+		dbg_event(dep->number, "EENDXFER", ret);
+	}
 	dep->resource_index = 0;
 }
 
@@ -1106,6 +1124,7 @@
 			dwc3_trace(trace_dwc3_ep0,
 					"Wrong direction for Data phase");
 			dwc3_ep0_end_control_data(dwc, dep);
+			dbg_event(epnum, "WRONGDR", 0);
 			dwc3_ep0_stall_and_restart(dwc);
 			return;
 		}
@@ -1122,7 +1141,8 @@
 		dwc->ep0state = EP0_STATUS_PHASE;
 
 		if (dwc->delayed_status) {
-			WARN_ON_ONCE(event->endpoint_number != 1);
+			if (event->endpoint_number != 1)
+				dbg_event(epnum, "EEPNUM", event->status);
 			dwc3_trace(trace_dwc3_ep0, "Delayed Status");
 			return;
 		}
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 8c41ebd..d7d929d 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -1350,6 +1350,10 @@
 		goto out;
 	}
 
+	WARN(!dep->direction && (request->length % ep->desc->wMaxPacketSize),
+		"trying to queue unaligned request (%d) with %s\n",
+		request->length, ep->name);
+
 	ret = __dwc3_gadget_ep_queue(dep, req);
 
 	/*
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index a30c8e3..da284fe 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -233,6 +233,9 @@
 config USB_F_GSI
 	tristate
 
+config USB_F_QDSS
+	tristate
+
 # this first set of drivers all depend on bulk-capable hardware.
 
 config USB_CONFIGFS
@@ -549,6 +552,13 @@
 	help
 	  Generic function driver to support h/w acceleration to IPA over GSI.
 
+config USB_CONFIGFS_F_QDSS
+        bool "USB QDSS function"
+	select USB_F_QDSS
+	depends on USB_CONFIGFS
+	help
+          USB QDSS function driver to get hwtracing related data over USB.
+
 choice
 	tristate "USB Gadget Drivers"
 	default USB_ETH
diff --git a/drivers/usb/gadget/function/Makefile b/drivers/usb/gadget/function/Makefile
index e78080c..960c2cc 100644
--- a/drivers/usb/gadget/function/Makefile
+++ b/drivers/usb/gadget/function/Makefile
@@ -62,3 +62,5 @@
 obj-$(CONFIG_USB_F_CCID)   	+= usb_f_ccid.o
 usb_f_gsi-y			:= f_gsi.o rndis.o
 obj-$(CONFIG_USB_F_GSI)         += usb_f_gsi.o
+usb_f_qdss-y			:= f_qdss.o u_qdss.o
+obj-$(CONFIG_USB_F_QDSS)        += usb_f_qdss.o
diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c
index 4a30afa..ec498d8 100644
--- a/drivers/usb/gadget/function/f_fs.c
+++ b/drivers/usb/gadget/function/f_fs.c
@@ -2054,8 +2054,8 @@
 
 	ffs->epfiles = epfiles;
 
-	ffs_log("exit: epfile name %s state %d setup_state %d flag %lu",
-		epfile->name, ffs->state, ffs->setup_state, ffs->flags);
+	ffs_log("exit: eps_count %u state %d setup_state %d flag %lu",
+		count, ffs->state, ffs->setup_state, ffs->flags);
 
 	return 0;
 }
@@ -2066,7 +2066,7 @@
 
 	ENTER();
 
-	ffs_log("enter: epfilename %s", epfile->name);
+	ffs_log("enter: count %u", count);
 
 	for (; count; --count, ++epfile) {
 		BUG_ON(mutex_is_locked(&epfile->mutex) ||
diff --git a/drivers/usb/gadget/function/f_qdss.c b/drivers/usb/gadget/function/f_qdss.c
new file mode 100644
index 0000000..7114784
--- /dev/null
+++ b/drivers/usb/gadget/function/f_qdss.c
@@ -0,0 +1,1071 @@
+/*
+ * f_qdss.c -- QDSS function Driver
+ *
+ * Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/usb/usb_qdss.h>
+#include <linux/usb/cdc.h>
+
+#include "f_qdss.h"
+
+static DEFINE_SPINLOCK(qdss_lock);
+static LIST_HEAD(usb_qdss_ch_list);
+
+static struct usb_interface_descriptor qdss_data_intf_desc = {
+	.bLength            =	sizeof(qdss_data_intf_desc),
+	.bDescriptorType    =	USB_DT_INTERFACE,
+	.bAlternateSetting  =   0,
+	.bNumEndpoints      =	1,
+	.bInterfaceClass    =	0xff,
+	.bInterfaceSubClass =	0xff,
+	.bInterfaceProtocol =	0xff,
+};
+
+static struct usb_endpoint_descriptor qdss_hs_data_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 qdss_ss_data_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 qdss_data_ep_comp_desc = {
+	.bLength              =	 sizeof(qdss_data_ep_comp_desc),
+	.bDescriptorType      =	 USB_DT_SS_ENDPOINT_COMP,
+	.bMaxBurst            =	 1,
+	.bmAttributes         =	 0,
+	.wBytesPerInterval    =	 0,
+};
+
+static struct usb_interface_descriptor qdss_ctrl_intf_desc = {
+	.bLength            =	sizeof(qdss_ctrl_intf_desc),
+	.bDescriptorType    =	USB_DT_INTERFACE,
+	.bAlternateSetting  =   0,
+	.bNumEndpoints      =	2,
+	.bInterfaceClass    =	0xff,
+	.bInterfaceSubClass =	0xff,
+	.bInterfaceProtocol =	0xff,
+};
+
+static struct usb_endpoint_descriptor qdss_hs_ctrl_in_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 qdss_ss_ctrl_in_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_endpoint_descriptor qdss_hs_ctrl_out_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 qdss_ss_ctrl_out_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 qdss_ctrl_in_ep_comp_desc = {
+	.bLength            =	sizeof(qdss_ctrl_in_ep_comp_desc),
+	.bDescriptorType    =	USB_DT_SS_ENDPOINT_COMP,
+	.bMaxBurst          =	0,
+	.bmAttributes       =	0,
+	.wBytesPerInterval  =	0,
+};
+
+static struct usb_ss_ep_comp_descriptor qdss_ctrl_out_ep_comp_desc = {
+	.bLength            =	sizeof(qdss_ctrl_out_ep_comp_desc),
+	.bDescriptorType    =	USB_DT_SS_ENDPOINT_COMP,
+	.bMaxBurst          =	0,
+	.bmAttributes       =	0,
+	.wBytesPerInterval  =	0,
+};
+
+static struct usb_descriptor_header *qdss_hs_desc[] = {
+	(struct usb_descriptor_header *) &qdss_data_intf_desc,
+	(struct usb_descriptor_header *) &qdss_hs_data_desc,
+	(struct usb_descriptor_header *) &qdss_ctrl_intf_desc,
+	(struct usb_descriptor_header *) &qdss_hs_ctrl_in_desc,
+	(struct usb_descriptor_header *) &qdss_hs_ctrl_out_desc,
+	NULL,
+};
+
+static struct usb_descriptor_header *qdss_ss_desc[] = {
+	(struct usb_descriptor_header *) &qdss_data_intf_desc,
+	(struct usb_descriptor_header *) &qdss_ss_data_desc,
+	(struct usb_descriptor_header *) &qdss_data_ep_comp_desc,
+	(struct usb_descriptor_header *) &qdss_ctrl_intf_desc,
+	(struct usb_descriptor_header *) &qdss_ss_ctrl_in_desc,
+	(struct usb_descriptor_header *) &qdss_ctrl_in_ep_comp_desc,
+	(struct usb_descriptor_header *) &qdss_ss_ctrl_out_desc,
+	(struct usb_descriptor_header *) &qdss_ctrl_out_ep_comp_desc,
+	NULL,
+};
+
+static struct usb_descriptor_header *qdss_hs_data_only_desc[] = {
+	(struct usb_descriptor_header *) &qdss_data_intf_desc,
+	(struct usb_descriptor_header *) &qdss_hs_data_desc,
+	NULL,
+};
+
+static struct usb_descriptor_header *qdss_ss_data_only_desc[] = {
+	(struct usb_descriptor_header *) &qdss_data_intf_desc,
+	(struct usb_descriptor_header *) &qdss_ss_data_desc,
+	(struct usb_descriptor_header *) &qdss_data_ep_comp_desc,
+	NULL,
+};
+
+/* string descriptors: */
+#define QDSS_DATA_IDX	0
+#define QDSS_CTRL_IDX	1
+
+static struct usb_string qdss_string_defs[] = {
+	[QDSS_DATA_IDX].s = "QDSS DATA",
+	[QDSS_CTRL_IDX].s = "QDSS CTRL",
+	{}, /* end of list */
+};
+
+static struct usb_gadget_strings qdss_string_table = {
+	.language =		0x0409,
+	.strings =		qdss_string_defs,
+};
+
+static struct usb_gadget_strings *qdss_strings[] = {
+	&qdss_string_table,
+	NULL,
+};
+
+static inline struct f_qdss *func_to_qdss(struct usb_function *f)
+{
+	return container_of(f, struct f_qdss, port.function);
+}
+
+static
+struct usb_qdss_opts *to_fi_usb_qdss_opts(struct usb_function_instance *fi)
+{
+	return container_of(fi, struct usb_qdss_opts, func_inst);
+}
+/*----------------------------------------------------------------------*/
+
+static void qdss_ctrl_write_complete(struct usb_ep *ep,
+	struct usb_request *req)
+{
+	struct f_qdss *qdss = ep->driver_data;
+	struct qdss_request *d_req = req->context;
+	unsigned long flags;
+
+	pr_debug("qdss_ctrl_write_complete\n");
+
+	if (!req->status) {
+		/* send zlp */
+		if ((req->length >= ep->maxpacket) &&
+				((req->length % ep->maxpacket) == 0)) {
+			req->length = 0;
+			d_req->actual = req->actual;
+			d_req->status = req->status;
+			if (!usb_ep_queue(qdss->port.ctrl_in, req, GFP_ATOMIC))
+				return;
+		}
+	}
+
+	spin_lock_irqsave(&qdss->lock, flags);
+	list_add_tail(&req->list, &qdss->ctrl_write_pool);
+	if (req->length != 0) {
+		d_req->actual = req->actual;
+		d_req->status = req->status;
+	}
+	spin_unlock_irqrestore(&qdss->lock, flags);
+
+	if (qdss->ch.notify)
+		qdss->ch.notify(qdss->ch.priv, USB_QDSS_CTRL_WRITE_DONE, d_req,
+			NULL);
+}
+
+static void qdss_ctrl_read_complete(struct usb_ep *ep,
+	struct usb_request *req)
+{
+	struct f_qdss *qdss = ep->driver_data;
+	struct qdss_request *d_req = req->context;
+	unsigned long flags;
+
+	pr_debug("qdss_ctrl_read_complete\n");
+
+	d_req->actual = req->actual;
+	d_req->status = req->status;
+
+	spin_lock_irqsave(&qdss->lock, flags);
+	list_add_tail(&req->list, &qdss->ctrl_read_pool);
+	spin_unlock_irqrestore(&qdss->lock, flags);
+
+	if (qdss->ch.notify)
+		qdss->ch.notify(qdss->ch.priv, USB_QDSS_CTRL_READ_DONE, d_req,
+			NULL);
+}
+
+void usb_qdss_free_req(struct usb_qdss_ch *ch)
+{
+	struct f_qdss *qdss;
+	struct usb_request *req;
+	struct list_head *act, *tmp;
+
+	pr_debug("usb_qdss_free_req\n");
+
+	qdss = ch->priv_usb;
+	if (!qdss) {
+		pr_err("usb_qdss_free_req: qdss ctx is NULL\n");
+		return;
+	}
+
+	list_for_each_safe(act, tmp, &qdss->ctrl_write_pool) {
+		req = list_entry(act, struct usb_request, list);
+		list_del(&req->list);
+		usb_ep_free_request(qdss->port.ctrl_in, req);
+	}
+
+	list_for_each_safe(act, tmp, &qdss->ctrl_read_pool) {
+		req = list_entry(act, struct usb_request, list);
+		list_del(&req->list);
+		usb_ep_free_request(qdss->port.ctrl_out, req);
+	}
+}
+EXPORT_SYMBOL(usb_qdss_free_req);
+
+int usb_qdss_alloc_req(struct usb_qdss_ch *ch, int no_write_buf,
+	int no_read_buf)
+{
+	struct f_qdss *qdss = ch->priv_usb;
+	struct usb_request *req;
+	int i;
+
+	pr_debug("usb_qdss_alloc_req\n");
+
+	if (no_write_buf <= 0 || no_read_buf <= 0 || !qdss) {
+		pr_err("usb_qdss_alloc_req: missing params\n");
+		return -ENODEV;
+	}
+
+	for (i = 0; i < no_write_buf; i++) {
+		req = usb_ep_alloc_request(qdss->port.ctrl_in, GFP_ATOMIC);
+		if (!req) {
+			pr_err("usb_qdss_alloc_req: ctrl_in allocation err\n");
+			goto fail;
+		}
+		req->complete = qdss_ctrl_write_complete;
+		list_add_tail(&req->list, &qdss->ctrl_write_pool);
+	}
+
+	for (i = 0; i < no_read_buf; i++) {
+		req = usb_ep_alloc_request(qdss->port.ctrl_out, GFP_ATOMIC);
+		if (!req) {
+			pr_err("usb_qdss_alloc_req:ctrl_out allocation err\n");
+			goto fail;
+		}
+		req->complete = qdss_ctrl_read_complete;
+		list_add_tail(&req->list, &qdss->ctrl_read_pool);
+	}
+
+	return 0;
+
+fail:
+	usb_qdss_free_req(ch);
+	return -ENOMEM;
+}
+EXPORT_SYMBOL(usb_qdss_alloc_req);
+
+static void clear_eps(struct usb_function *f)
+{
+	struct f_qdss *qdss = func_to_qdss(f);
+
+	pr_debug("clear_eps\n");
+
+	if (qdss->port.ctrl_in)
+		qdss->port.ctrl_in->driver_data = NULL;
+	if (qdss->port.ctrl_out)
+		qdss->port.ctrl_out->driver_data = NULL;
+	if (qdss->port.data)
+		qdss->port.data->driver_data = NULL;
+}
+
+static void clear_desc(struct usb_gadget *gadget, struct usb_function *f)
+{
+	pr_debug("clear_desc\n");
+
+	if (gadget_is_superspeed(gadget) && f->ss_descriptors)
+		usb_free_descriptors(f->ss_descriptors);
+
+	if (gadget_is_dualspeed(gadget) && f->hs_descriptors)
+		usb_free_descriptors(f->hs_descriptors);
+}
+
+static int qdss_bind(struct usb_configuration *c, struct usb_function *f)
+{
+	struct usb_gadget *gadget = c->cdev->gadget;
+	struct f_qdss *qdss = func_to_qdss(f);
+	struct usb_ep *ep;
+	int iface;
+
+	pr_debug("qdss_bind\n");
+
+	if (!gadget_is_dualspeed(gadget) && !gadget_is_superspeed(gadget)) {
+		pr_err("qdss_bind: full-speed is not supported\n");
+		return -ENOTSUPP;
+	}
+
+	/* Allocate data I/F */
+	iface = usb_interface_id(c, f);
+	if (iface < 0) {
+		pr_err("interface allocation error\n");
+		return iface;
+	}
+	qdss_data_intf_desc.bInterfaceNumber = iface;
+	qdss->data_iface_id = iface;
+
+	if (qdss->debug_inface_enabled) {
+		/* Allocate ctrl I/F */
+		iface = usb_interface_id(c, f);
+		if (iface < 0) {
+			pr_err("interface allocation error\n");
+			return iface;
+		}
+		qdss_ctrl_intf_desc.bInterfaceNumber = iface;
+		qdss->ctrl_iface_id = iface;
+	}
+
+	ep = usb_ep_autoconfig_ss(gadget, &qdss_ss_data_desc,
+		&qdss_data_ep_comp_desc);
+	if (!ep) {
+		pr_err("ep_autoconfig error\n");
+		goto fail;
+	}
+	qdss->port.data = ep;
+	ep->driver_data = qdss;
+
+	if (qdss->debug_inface_enabled) {
+		ep = usb_ep_autoconfig_ss(gadget, &qdss_ss_ctrl_in_desc,
+			&qdss_ctrl_in_ep_comp_desc);
+		if (!ep) {
+			pr_err("ep_autoconfig error\n");
+			goto fail;
+		}
+		qdss->port.ctrl_in = ep;
+		ep->driver_data = qdss;
+
+		ep = usb_ep_autoconfig_ss(gadget, &qdss_ss_ctrl_out_desc,
+			&qdss_ctrl_out_ep_comp_desc);
+		if (!ep) {
+			pr_err("ep_autoconfig error\n");
+			goto fail;
+		}
+		qdss->port.ctrl_out = ep;
+		ep->driver_data = qdss;
+	}
+
+	/*update descriptors*/
+	qdss_hs_data_desc.bEndpointAddress =
+		qdss_ss_data_desc.bEndpointAddress;
+	if (qdss->debug_inface_enabled) {
+		qdss_hs_ctrl_in_desc.bEndpointAddress =
+		qdss_ss_ctrl_in_desc.bEndpointAddress;
+		qdss_hs_ctrl_out_desc.bEndpointAddress =
+		qdss_ss_ctrl_out_desc.bEndpointAddress;
+		f->hs_descriptors = usb_copy_descriptors(qdss_hs_desc);
+	} else
+		f->hs_descriptors = usb_copy_descriptors(
+							qdss_hs_data_only_desc);
+	if (!f->hs_descriptors) {
+		pr_err("usb_copy_descriptors error\n");
+		goto fail;
+	}
+
+	/* update ss descriptors */
+	if (gadget_is_superspeed(gadget)) {
+		if (qdss->debug_inface_enabled)
+			f->ss_descriptors =
+			usb_copy_descriptors(qdss_ss_desc);
+		else
+			f->ss_descriptors =
+			usb_copy_descriptors(qdss_ss_data_only_desc);
+		if (!f->ss_descriptors) {
+			pr_err("usb_copy_descriptors error\n");
+			goto fail;
+		}
+	}
+
+	return 0;
+fail:
+	clear_eps(f);
+	clear_desc(gadget, f);
+	return -ENOTSUPP;
+}
+
+
+static void qdss_unbind(struct usb_configuration *c, struct usb_function *f)
+{
+	struct f_qdss  *qdss = func_to_qdss(f);
+	struct usb_gadget *gadget = c->cdev->gadget;
+
+	pr_debug("qdss_unbind\n");
+
+	flush_workqueue(qdss->wq);
+
+	clear_eps(f);
+	clear_desc(gadget, f);
+}
+
+static void qdss_eps_disable(struct usb_function *f)
+{
+	struct f_qdss  *qdss = func_to_qdss(f);
+
+	pr_debug("qdss_eps_disable\n");
+
+	if (qdss->ctrl_in_enabled) {
+		usb_ep_disable(qdss->port.ctrl_in);
+		qdss->ctrl_in_enabled = 0;
+	}
+
+	if (qdss->ctrl_out_enabled) {
+		usb_ep_disable(qdss->port.ctrl_out);
+		qdss->ctrl_out_enabled = 0;
+	}
+
+	if (qdss->data_enabled) {
+		usb_ep_disable(qdss->port.data);
+		qdss->data_enabled = 0;
+	}
+}
+
+static void usb_qdss_disconnect_work(struct work_struct *work)
+{
+	struct f_qdss *qdss;
+	int status;
+
+	qdss = container_of(work, struct f_qdss, disconnect_w);
+	pr_debug("usb_qdss_disconnect_work\n");
+
+	/*
+	 * Uninitialized init data i.e. ep specific operation.
+	 * Notify qdss to cancel all active transfers.
+	 */
+	if (qdss->ch.app_conn) {
+		status = uninit_data(qdss->port.data);
+		if (status)
+			pr_err("%s: uninit_data error\n", __func__);
+
+		if (qdss->ch.notify)
+			qdss->ch.notify(qdss->ch.priv,
+				USB_QDSS_DISCONNECT,
+				NULL,
+				NULL);
+
+		status = set_qdss_data_connection(
+				qdss->gadget,
+				qdss->port.data,
+				qdss->port.data->address,
+				0);
+		if (status)
+			pr_err("qdss_disconnect error");
+	}
+
+	/*
+	 * Decrement usage count which was incremented
+	 * before calling connect work
+	 */
+	usb_gadget_autopm_put_async(qdss->gadget);
+}
+
+static void qdss_disable(struct usb_function *f)
+{
+	struct f_qdss	*qdss = func_to_qdss(f);
+	unsigned long flags;
+
+	pr_debug("qdss_disable\n");
+	spin_lock_irqsave(&qdss->lock, flags);
+	if (!qdss->usb_connected) {
+		spin_unlock_irqrestore(&qdss->lock, flags);
+		return;
+	}
+
+	qdss->usb_connected = 0;
+	spin_unlock_irqrestore(&qdss->lock, flags);
+	/*cancell all active xfers*/
+	qdss_eps_disable(f);
+	queue_work(qdss->wq, &qdss->disconnect_w);
+}
+
+static void usb_qdss_connect_work(struct work_struct *work)
+{
+	struct f_qdss *qdss;
+	int status;
+
+	qdss = container_of(work, struct f_qdss, connect_w);
+
+	/* If cable is already removed, discard connect_work */
+	if (qdss->usb_connected == 0) {
+		pr_debug("%s: discard connect_work\n", __func__);
+		cancel_work_sync(&qdss->disconnect_w);
+		return;
+	}
+
+	pr_debug("usb_qdss_connect_work\n");
+	status = set_qdss_data_connection(
+			qdss->gadget,
+			qdss->port.data,
+			qdss->port.data->address,
+			1);
+	if (status) {
+		pr_err("set_qdss_data_connection error(%d)", status);
+		return;
+	}
+
+	if (qdss->ch.notify)
+		qdss->ch.notify(qdss->ch.priv, USB_QDSS_CONNECT,
+						NULL, &qdss->ch);
+
+	status = usb_ep_queue(qdss->port.data, qdss->endless_req, GFP_ATOMIC);
+	if (status)
+		pr_err("%s: usb_ep_queue error (%d)\n", __func__, status);
+}
+
+static int qdss_set_alt(struct usb_function *f, unsigned int intf,
+				unsigned int alt)
+{
+	struct f_qdss  *qdss = func_to_qdss(f);
+	struct usb_gadget *gadget = f->config->cdev->gadget;
+	struct usb_qdss_ch *ch = &qdss->ch;
+	int ret = 0;
+
+	pr_debug("qdss_set_alt qdss pointer = %pK\n", qdss);
+	qdss->gadget = gadget;
+
+	if (alt != 0)
+		goto fail1;
+
+	if (gadget->speed != USB_SPEED_SUPER &&
+		gadget->speed != USB_SPEED_HIGH) {
+		pr_err("qdss_st_alt: qdss supportes HS or SS only\n");
+		ret = -EINVAL;
+		goto fail1;
+	}
+
+	if (intf == qdss->data_iface_id) {
+		/* Increment usage count on connect */
+		usb_gadget_autopm_get_async(qdss->gadget);
+
+		if (config_ep_by_speed(gadget, f, qdss->port.data)) {
+			ret = -EINVAL;
+			goto fail;
+		}
+
+		ret = usb_ep_enable(qdss->port.data);
+		if (ret)
+			goto fail;
+
+		qdss->port.data->driver_data = qdss;
+		qdss->data_enabled = 1;
+
+
+	} else if ((intf == qdss->ctrl_iface_id) &&
+	(qdss->debug_inface_enabled)) {
+
+		if (config_ep_by_speed(gadget, f, qdss->port.ctrl_in)) {
+			ret = -EINVAL;
+			goto fail1;
+		}
+
+		ret = usb_ep_enable(qdss->port.ctrl_in);
+		if (ret)
+			goto fail1;
+
+		qdss->port.ctrl_in->driver_data = qdss;
+		qdss->ctrl_in_enabled = 1;
+
+		if (config_ep_by_speed(gadget, f, qdss->port.ctrl_out)) {
+			ret = -EINVAL;
+			goto fail1;
+		}
+
+
+		ret = usb_ep_enable(qdss->port.ctrl_out);
+		if (ret)
+			goto fail1;
+
+		qdss->port.ctrl_out->driver_data = qdss;
+		qdss->ctrl_out_enabled = 1;
+	}
+
+	if (qdss->debug_inface_enabled) {
+		if (qdss->ctrl_out_enabled && qdss->ctrl_in_enabled &&
+			qdss->data_enabled) {
+			qdss->usb_connected = 1;
+			pr_debug("qdss_set_alt usb_connected INTF enabled\n");
+		}
+	} else {
+		if (qdss->data_enabled) {
+			qdss->usb_connected = 1;
+			pr_debug("qdss_set_alt usb_connected INTF disabled\n");
+		}
+	}
+
+	if (qdss->usb_connected && ch->app_conn)
+		queue_work(qdss->wq, &qdss->connect_w);
+
+	return 0;
+fail:
+	/* Decrement usage count in case of failure */
+	usb_gadget_autopm_put_async(qdss->gadget);
+fail1:
+	pr_err("qdss_set_alt failed\n");
+	qdss_eps_disable(f);
+	return ret;
+}
+
+static struct f_qdss *alloc_usb_qdss(char *channel_name)
+{
+	struct f_qdss *qdss;
+	int found = 0;
+	struct usb_qdss_ch *ch;
+	unsigned long flags;
+
+	spin_lock_irqsave(&qdss_lock, flags);
+	list_for_each_entry(ch, &usb_qdss_ch_list, list) {
+		if (!strcmp(channel_name, ch->name)) {
+			found = 1;
+			break;
+		}
+	}
+
+	if (found) {
+		spin_unlock_irqrestore(&qdss_lock, flags);
+		pr_err("%s: (%s) is already available.\n",
+				__func__, channel_name);
+		return ERR_PTR(-EEXIST);
+	}
+
+	spin_unlock_irqrestore(&qdss_lock, flags);
+	qdss = kzalloc(sizeof(struct f_qdss), GFP_KERNEL);
+	if (!qdss) {
+		pr_err("%s: Unable to allocate qdss device\n", __func__);
+		return ERR_PTR(-ENOMEM);
+	}
+
+	qdss->wq = create_singlethread_workqueue(channel_name);
+	if (!qdss->wq) {
+		kfree(qdss);
+		return ERR_PTR(-ENOMEM);
+	}
+
+	spin_lock_irqsave(&qdss_lock, flags);
+	ch = &qdss->ch;
+	ch->name = channel_name;
+	list_add_tail(&ch->list, &usb_qdss_ch_list);
+	spin_unlock_irqrestore(&qdss_lock, flags);
+
+	spin_lock_init(&qdss->lock);
+	INIT_LIST_HEAD(&qdss->ctrl_read_pool);
+	INIT_LIST_HEAD(&qdss->ctrl_write_pool);
+	INIT_WORK(&qdss->connect_w, usb_qdss_connect_work);
+	INIT_WORK(&qdss->disconnect_w, usb_qdss_disconnect_work);
+
+	return qdss;
+}
+
+int usb_qdss_ctrl_read(struct usb_qdss_ch *ch, struct qdss_request *d_req)
+{
+	struct f_qdss *qdss = ch->priv_usb;
+	unsigned long flags;
+	struct usb_request *req = NULL;
+
+	pr_debug("usb_qdss_ctrl_read\n");
+
+	if (!qdss)
+		return -ENODEV;
+
+	spin_lock_irqsave(&qdss->lock, flags);
+
+	if (qdss->usb_connected == 0) {
+		spin_unlock_irqrestore(&qdss->lock, flags);
+		return -EIO;
+	}
+
+	if (list_empty(&qdss->ctrl_read_pool)) {
+		spin_unlock_irqrestore(&qdss->lock, flags);
+		pr_err("error: usb_qdss_ctrl_read list is empty\n");
+		return -EAGAIN;
+	}
+
+	req = list_first_entry(&qdss->ctrl_read_pool, struct usb_request, list);
+	list_del(&req->list);
+	spin_unlock_irqrestore(&qdss->lock, flags);
+
+	req->buf = d_req->buf;
+	req->length = d_req->length;
+	req->context = d_req;
+
+	if (usb_ep_queue(qdss->port.ctrl_out, req, GFP_ATOMIC)) {
+		/* If error add the link to linked list again*/
+		spin_lock_irqsave(&qdss->lock, flags);
+		list_add_tail(&req->list, &qdss->ctrl_read_pool);
+		spin_unlock_irqrestore(&qdss->lock, flags);
+		pr_err("qdss usb_ep_queue failed\n");
+		return -EIO;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(usb_qdss_ctrl_read);
+
+int usb_qdss_ctrl_write(struct usb_qdss_ch *ch, struct qdss_request *d_req)
+{
+	struct f_qdss *qdss = ch->priv_usb;
+	unsigned long flags;
+	struct usb_request *req = NULL;
+
+	pr_debug("usb_qdss_ctrl_write\n");
+
+	if (!qdss)
+		return -ENODEV;
+
+	spin_lock_irqsave(&qdss->lock, flags);
+
+	if (qdss->usb_connected == 0) {
+		spin_unlock_irqrestore(&qdss->lock, flags);
+		return -EIO;
+	}
+
+	if (list_empty(&qdss->ctrl_write_pool)) {
+		pr_err("error: usb_qdss_ctrl_write list is empty\n");
+		spin_unlock_irqrestore(&qdss->lock, flags);
+		return -EAGAIN;
+	}
+
+	req = list_first_entry(&qdss->ctrl_write_pool, struct usb_request,
+		list);
+	list_del(&req->list);
+	spin_unlock_irqrestore(&qdss->lock, flags);
+
+	req->buf = d_req->buf;
+	req->length = d_req->length;
+	req->context = d_req;
+	if (usb_ep_queue(qdss->port.ctrl_in, req, GFP_ATOMIC)) {
+		spin_lock_irqsave(&qdss->lock, flags);
+		list_add_tail(&req->list, &qdss->ctrl_write_pool);
+		spin_unlock_irqrestore(&qdss->lock, flags);
+		pr_err("qdss usb_ep_queue failed\n");
+		return -EIO;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(usb_qdss_ctrl_write);
+
+struct usb_qdss_ch *usb_qdss_open(const char *name, void *priv,
+	void (*notify)(void *priv, unsigned int event,
+		struct qdss_request *d_req, struct usb_qdss_ch *))
+{
+	struct usb_qdss_ch *ch;
+	struct f_qdss *qdss;
+	unsigned long flags;
+	int found = 0;
+
+	pr_debug("usb_qdss_open\n");
+
+	if (!notify) {
+		pr_err("usb_qdss_open: notification func is missing\n");
+		return NULL;
+	}
+
+	spin_lock_irqsave(&qdss_lock, flags);
+	/* Check if we already have a channel with this name */
+	list_for_each_entry(ch, &usb_qdss_ch_list, list) {
+		if (!strcmp(name, ch->name)) {
+			found = 1;
+			break;
+		}
+	}
+
+	if (!found) {
+		spin_unlock_irqrestore(&qdss_lock, flags);
+		pr_debug("usb_qdss_open failed as %s not found\n", name);
+		return NULL;
+	}
+
+	pr_debug("usb_qdss_open: qdss ctx found\n");
+	qdss = container_of(ch, struct f_qdss, ch);
+	ch->priv_usb = qdss;
+	ch->priv = priv;
+	ch->notify = notify;
+	ch->app_conn = 1;
+	spin_unlock_irqrestore(&qdss_lock, flags);
+
+	/* the case USB cabel was connected before qdss called qdss_open */
+	if (qdss->usb_connected == 1)
+		queue_work(qdss->wq, &qdss->connect_w);
+
+	return ch;
+}
+EXPORT_SYMBOL(usb_qdss_open);
+
+void usb_qdss_close(struct usb_qdss_ch *ch)
+{
+	struct f_qdss *qdss = ch->priv_usb;
+	struct usb_gadget *gadget;
+	unsigned long flags;
+	int status;
+
+	pr_debug("usb_qdss_close\n");
+
+	spin_lock_irqsave(&qdss_lock, flags);
+	if (!qdss || !qdss->usb_connected) {
+		ch->app_conn = 0;
+		spin_unlock_irqrestore(&qdss_lock, flags);
+		return;
+	}
+
+	usb_ep_dequeue(qdss->port.data, qdss->endless_req);
+	usb_ep_free_request(qdss->port.data, qdss->endless_req);
+	qdss->endless_req = NULL;
+	gadget = qdss->gadget;
+	ch->app_conn = 0;
+	spin_unlock_irqrestore(&qdss_lock, flags);
+
+	status = uninit_data(qdss->port.data);
+	if (status)
+		pr_err("%s: uninit_data error\n", __func__);
+
+	status = set_qdss_data_connection(
+				gadget,
+				qdss->port.data,
+				qdss->port.data->address,
+				0);
+	if (status)
+		pr_err("%s:qdss_disconnect error\n", __func__);
+	usb_gadget_restart(gadget);
+}
+EXPORT_SYMBOL(usb_qdss_close);
+
+static void qdss_cleanup(void)
+{
+	struct f_qdss *qdss;
+	struct list_head *act, *tmp;
+	struct usb_qdss_ch *_ch;
+	unsigned long flags;
+
+	pr_debug("qdss_cleanup\n");
+
+	list_for_each_safe(act, tmp, &usb_qdss_ch_list) {
+		_ch = list_entry(act, struct usb_qdss_ch, list);
+		qdss = container_of(_ch, struct f_qdss, ch);
+		spin_lock_irqsave(&qdss_lock, flags);
+		destroy_workqueue(qdss->wq);
+		if (!_ch->priv) {
+			list_del(&_ch->list);
+			kfree(qdss);
+		}
+		spin_unlock_irqrestore(&qdss_lock, flags);
+	}
+}
+
+static void qdss_free_func(struct usb_function *f)
+{
+	/* Do nothing as usb_qdss_alloc() doesn't alloc anything. */
+}
+
+static inline struct usb_qdss_opts *to_f_qdss_opts(struct config_item *item)
+{
+	return container_of(to_config_group(item), struct usb_qdss_opts,
+			func_inst.group);
+}
+
+static void qdss_attr_release(struct config_item *item)
+{
+	struct usb_qdss_opts *opts = to_f_qdss_opts(item);
+
+	usb_put_function_instance(&opts->func_inst);
+}
+
+static struct configfs_item_operations qdss_item_ops = {
+	.release	= qdss_attr_release,
+};
+
+static ssize_t qdss_enable_debug_inface_show(struct config_item *item,
+			char *page)
+{
+	return snprintf(page, PAGE_SIZE, "%s\n",
+		(to_f_qdss_opts(item)->usb_qdss->debug_inface_enabled == 1) ?
+		"Enabled" : "Disabled");
+}
+
+static ssize_t qdss_enable_debug_inface_store(struct config_item *item,
+			const char *page, size_t len)
+{
+	struct f_qdss *qdss = to_f_qdss_opts(item)->usb_qdss;
+	unsigned long flags;
+	u8 stats;
+
+	if (page == NULL) {
+		pr_err("Invalid buffer");
+		return len;
+	}
+
+	if (kstrtou8(page, 0, &stats) != 0 && (stats != 0 || stats != 1)) {
+		pr_err("(%u)Wrong value. enter 0 to disable or 1 to enable.\n",
+			stats);
+		return len;
+	}
+
+	spin_lock_irqsave(&qdss->lock, flags);
+	qdss->debug_inface_enabled = (stats == 1 ? "true" : "false");
+	spin_unlock_irqrestore(&qdss->lock, flags);
+	return len;
+}
+
+CONFIGFS_ATTR(qdss_, enable_debug_inface);
+static struct configfs_attribute *qdss_attrs[] = {
+	&qdss_attr_enable_debug_inface,
+	NULL,
+};
+
+static struct config_item_type qdss_func_type = {
+	.ct_item_ops	= &qdss_item_ops,
+	.ct_attrs	= qdss_attrs,
+	.ct_owner	= THIS_MODULE,
+};
+
+static void usb_qdss_free_inst(struct usb_function_instance *fi)
+{
+	struct usb_qdss_opts *opts;
+
+	opts = container_of(fi, struct usb_qdss_opts, func_inst);
+	kfree(opts->usb_qdss);
+	kfree(opts);
+}
+
+static int usb_qdss_set_inst_name(struct usb_function_instance *f,
+				const char *name)
+{
+	struct usb_qdss_opts *opts =
+		container_of(f, struct usb_qdss_opts, func_inst);
+	char *ptr;
+	size_t name_len;
+	struct f_qdss *usb_qdss;
+
+	/* get channel_name as expected input qdss.<channel_name> */
+	name_len = strlen(name) + 1;
+	if (name_len > 15)
+		return -ENAMETOOLONG;
+
+	/* get channel name */
+	ptr = kstrndup(name, name_len, GFP_KERNEL);
+	if (!ptr) {
+		pr_err("error:%ld\n", PTR_ERR(ptr));
+		return -ENOMEM;
+	}
+
+	opts->channel_name = ptr;
+	pr_debug("qdss: channel_name:%s\n", opts->channel_name);
+
+	usb_qdss = alloc_usb_qdss(opts->channel_name);
+	if (IS_ERR(usb_qdss)) {
+		pr_err("Failed to create usb_qdss port(%s)\n",
+				opts->channel_name);
+		return -ENOMEM;
+	}
+
+	opts->usb_qdss = usb_qdss;
+	return 0;
+}
+
+static struct usb_function_instance *qdss_alloc_inst(void)
+{
+	struct usb_qdss_opts *opts;
+
+	opts = kzalloc(sizeof(*opts), GFP_KERNEL);
+	if (!opts)
+		return ERR_PTR(-ENOMEM);
+
+	opts->func_inst.free_func_inst = usb_qdss_free_inst;
+	opts->func_inst.set_inst_name = usb_qdss_set_inst_name;
+
+	config_group_init_type_name(&opts->func_inst.group, "",
+				    &qdss_func_type);
+	return &opts->func_inst;
+}
+
+static struct usb_function *qdss_alloc(struct usb_function_instance *fi)
+{
+	struct usb_qdss_opts *opts = to_fi_usb_qdss_opts(fi);
+	struct f_qdss *usb_qdss = opts->usb_qdss;
+
+	usb_qdss->port.function.name = "usb_qdss";
+	usb_qdss->port.function.fs_descriptors = qdss_hs_desc;
+	usb_qdss->port.function.hs_descriptors = qdss_hs_desc;
+	usb_qdss->port.function.strings = qdss_strings;
+	usb_qdss->port.function.bind = qdss_bind;
+	usb_qdss->port.function.unbind = qdss_unbind;
+	usb_qdss->port.function.set_alt = qdss_set_alt;
+	usb_qdss->port.function.disable = qdss_disable;
+	usb_qdss->port.function.setup = NULL;
+	usb_qdss->port.function.free_func = qdss_free_func;
+
+	return &usb_qdss->port.function;
+}
+
+DECLARE_USB_FUNCTION_INIT(qdss, qdss_alloc_inst, qdss_alloc);
+static int __init usb_qdss_init(void)
+{
+	int ret;
+
+	INIT_LIST_HEAD(&usb_qdss_ch_list);
+	ret = usb_function_register(&qdssusb_func);
+	if (ret) {
+		pr_err("%s: failed to register diag %d\n", __func__, ret);
+		return ret;
+	}
+	return ret;
+}
+
+static void __exit usb_qdss_exit(void)
+{
+	usb_function_unregister(&qdssusb_func);
+	qdss_cleanup();
+}
+
+module_init(usb_qdss_init);
+module_exit(usb_qdss_exit);
+MODULE_DESCRIPTION("USB QDSS Function Driver");
diff --git a/drivers/usb/gadget/function/f_qdss.h b/drivers/usb/gadget/function/f_qdss.h
new file mode 100644
index 0000000..e673e61
--- /dev/null
+++ b/drivers/usb/gadget/function/f_qdss.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details
+ */
+
+#ifndef _F_QDSS_H
+#define _F_QDSS_H
+
+#include <linux/kernel.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <linux/usb/composite.h>
+#include <linux/usb/usb_qdss.h>
+
+enum qti_port_type {
+	QTI_PORT_RMNET,
+	QTI_PORT_DPL,
+	QTI_NUM_PORTS
+};
+
+struct usb_qdss_bam_connect_info {
+	u32 usb_bam_pipe_idx;
+	u32 peer_pipe_idx;
+	unsigned long usb_bam_handle;
+	struct sps_mem_buffer *data_fifo;
+};
+
+struct gqdss {
+	struct usb_function function;
+	struct usb_ep *ctrl_out;
+	struct usb_ep *ctrl_in;
+	struct usb_ep *data;
+	int (*send_encap_cmd)(enum qti_port_type qport, void *buf, size_t len);
+	void (*notify_modem)(void *g, enum qti_port_type qport, int cbits);
+};
+
+/* struct f_qdss - USB qdss function driver private structure */
+struct f_qdss {
+	struct gqdss port;
+	struct usb_qdss_bam_connect_info bam_info;
+	struct usb_gadget *gadget;
+	short int port_num;
+	u8 ctrl_iface_id;
+	u8 data_iface_id;
+	int usb_connected;
+	bool debug_inface_enabled;
+	struct usb_request *endless_req;
+	struct usb_qdss_ch ch;
+	struct list_head ctrl_read_pool;
+	struct list_head ctrl_write_pool;
+	struct work_struct connect_w;
+	struct work_struct disconnect_w;
+	spinlock_t lock;
+	unsigned int data_enabled:1;
+	unsigned int ctrl_in_enabled:1;
+	unsigned int ctrl_out_enabled:1;
+	struct workqueue_struct *wq;
+};
+
+struct usb_qdss_opts {
+	struct usb_function_instance func_inst;
+	struct f_qdss *usb_qdss;
+	char *channel_name;
+};
+
+int uninit_data(struct usb_ep *ep);
+int set_qdss_data_connection(struct usb_gadget *gadget,
+	struct usb_ep *data_ep, u8 data_addr, int enable);
+#endif
diff --git a/drivers/usb/gadget/function/u_qdss.c b/drivers/usb/gadget/function/u_qdss.c
new file mode 100644
index 0000000..c781d85
--- /dev/null
+++ b/drivers/usb/gadget/function/u_qdss.c
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details
+ */
+
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/usb_bam.h>
+
+#include "f_qdss.h"
+static int alloc_sps_req(struct usb_ep *data_ep)
+{
+	struct usb_request *req = NULL;
+	struct f_qdss *qdss = data_ep->driver_data;
+	u32 sps_params = 0;
+
+	pr_debug("send_sps_req\n");
+
+	req = usb_ep_alloc_request(data_ep, GFP_ATOMIC);
+	if (!req) {
+		pr_err("usb_ep_alloc_request failed\n");
+		return -ENOMEM;
+	}
+
+	req->length = 32*1024;
+	sps_params = MSM_SPS_MODE | MSM_DISABLE_WB |
+			qdss->bam_info.usb_bam_pipe_idx;
+	req->udc_priv = sps_params;
+	qdss->endless_req = req;
+
+	return 0;
+}
+
+static int init_data(struct usb_ep *ep);
+int set_qdss_data_connection(struct usb_gadget *gadget,
+	struct usb_ep *data_ep, u8 data_addr, int enable)
+{
+	enum usb_ctrl		usb_bam_type;
+	int			res = 0;
+	int			idx;
+	struct f_qdss *qdss = data_ep->driver_data;
+	struct usb_qdss_bam_connect_info bam_info = qdss->bam_info;
+
+	pr_debug("set_qdss_data_connection\n");
+
+	usb_bam_type = usb_bam_get_bam_type(gadget->name);
+
+	/* There is only one qdss pipe, so the pipe number can be set to 0 */
+	idx = usb_bam_get_connection_idx(usb_bam_type, QDSS_P_BAM,
+		PEER_PERIPHERAL_TO_USB, USB_BAM_DEVICE, 0);
+	if (idx < 0) {
+		pr_err("%s: usb_bam_get_connection_idx failed\n", __func__);
+		return idx;
+	}
+
+	if (enable) {
+		usb_bam_alloc_fifos(usb_bam_type, idx);
+		bam_info.data_fifo =
+			kzalloc(sizeof(struct sps_mem_buffer), GFP_KERNEL);
+		if (!bam_info.data_fifo) {
+			pr_err("qdss_data_connection: memory alloc failed\n");
+			return -ENOMEM;
+		}
+		get_bam2bam_connection_info(usb_bam_type, idx,
+				&bam_info.usb_bam_pipe_idx,
+				NULL, bam_info.data_fifo, NULL);
+
+		alloc_sps_req(data_ep);
+		msm_data_fifo_config(data_ep, bam_info.data_fifo->phys_base,
+					bam_info.data_fifo->size,
+					bam_info.usb_bam_pipe_idx);
+		init_data(qdss->port.data);
+
+		res = usb_bam_connect(usb_bam_type, idx,
+					&(bam_info.usb_bam_pipe_idx));
+	} else {
+		kfree(bam_info.data_fifo);
+		res = usb_bam_disconnect_pipe(usb_bam_type, idx);
+		if (res)
+			pr_err("usb_bam_disconnection error\n");
+		usb_bam_free_fifos(usb_bam_type, idx);
+	}
+
+	return res;
+}
+
+static int init_data(struct usb_ep *ep)
+{
+	int res = 0;
+
+	pr_debug("init_data\n");
+
+	res = msm_ep_config(ep);
+	if (res)
+		pr_err("msm_ep_config failed\n");
+
+	return res;
+}
+
+int uninit_data(struct usb_ep *ep)
+{
+	int res = 0;
+
+	pr_err("uninit_data\n");
+
+	res = msm_ep_unconfig(ep);
+	if (res)
+		pr_err("msm_ep_unconfig failed\n");
+
+	return res;
+}
diff --git a/drivers/video/fbdev/vfb.c b/drivers/video/fbdev/vfb.c
index da653a0..208d8f4 100644
--- a/drivers/video/fbdev/vfb.c
+++ b/drivers/video/fbdev/vfb.c
@@ -36,6 +36,8 @@
 static u_long videomemorysize = VIDEOMEMSIZE;
 module_param(videomemorysize, ulong, 0);
 MODULE_PARM_DESC(videomemorysize, "RAM available to frame buffer (in bytes)");
+static int bpp = 8;
+module_param(bpp, int, 0644);
 
 static char *mode_option = NULL;
 module_param(mode_option, charp, 0);
@@ -397,7 +399,13 @@
 		/* Test disable for backwards compatibility */
 		if (!strcmp(this_opt, "disable"))
 			vfb_enable = 0;
-		else
+		else if (!strcmp(this_opt, "bpp=")) {
+			if (kstrtoint(this_opt + 4, 0, &bpp) < 0)
+				bpp = 8;
+		} else if (!strcmp(this_opt, "memsize=")) {
+			if (kstrtoul(this_opt + 8, 0, &videomemorysize) < 0)
+				videomemorysize = VIDEOMEMSIZE;
+		} else
 			mode_option = this_opt;
 	}
 	return 1;
@@ -427,12 +435,8 @@
 	info->screen_base = (char __iomem *)videomemory;
 	info->fbops = &vfb_ops;
 
-	if (!fb_find_mode(&info->var, info, mode_option,
-			  NULL, 0, &vfb_default, 8)){
-		fb_err(info, "Unable to find usable video mode.\n");
-		retval = -EINVAL;
-		goto err1;
-	}
+	retval = fb_find_mode(&info->var, info, mode_option,
+			      NULL, 0, NULL, bpp);
 
 	vfb_fix.smem_start = (unsigned long) videomemory;
 	vfb_fix.smem_len = videomemorysize;
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index 7acbd2c..1782804 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -5648,6 +5648,10 @@
 #ifdef CONFIG_COMPAT
 long btrfs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
+	/*
+	 * These all access 32-bit values anyway so no further
+	 * handling is necessary.
+	 */
 	switch (cmd) {
 	case FS_IOC32_GETFLAGS:
 		cmd = FS_IOC_GETFLAGS;
@@ -5658,8 +5662,6 @@
 	case FS_IOC32_GETVERSION:
 		cmd = FS_IOC_GETVERSION;
 		break;
-	default:
-		return -ENOIOCTLCMD;
 	}
 
 	return btrfs_ioctl(file, cmd, (unsigned long) compat_ptr(arg));
diff --git a/fs/ext4/inline.c b/fs/ext4/inline.c
index 17a257c..dbef345 100644
--- a/fs/ext4/inline.c
+++ b/fs/ext4/inline.c
@@ -503,8 +503,16 @@
 		return -EAGAIN;
 	}
 
-	trace_android_fs_dataread_start(inode, page_offset(page), PAGE_SIZE,
-					current->pid, current->comm);
+	if (trace_android_fs_dataread_start_enabled()) {
+		char *path, pathbuf[MAX_TRACE_PATHBUF_LEN];
+
+		path = android_fstrace_get_pathname(pathbuf,
+						    MAX_TRACE_PATHBUF_LEN,
+						    inode);
+		trace_android_fs_dataread_start(inode, page_offset(page),
+						PAGE_SIZE, current->pid,
+						path, current->comm);
+	}
 
 	/*
 	 * Current inline data can only exist in the 1st page,
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index 1db9080..46912da 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -1184,8 +1184,16 @@
 	pgoff_t index;
 	unsigned from, to;
 
-	trace_android_fs_datawrite_start(inode, pos, len,
-					 current->pid, current->comm);
+	if (trace_android_fs_datawrite_start_enabled()) {
+		char *path, pathbuf[MAX_TRACE_PATHBUF_LEN];
+
+		path = android_fstrace_get_pathname(pathbuf,
+						    MAX_TRACE_PATHBUF_LEN,
+						    inode);
+		trace_android_fs_datawrite_start(inode, pos, len,
+						 current->pid, path,
+						 current->comm);
+	}
 	trace_ext4_write_begin(inode, pos, len, flags);
 	/*
 	 * Reserve one block more for addition to orphan list in case
@@ -2902,8 +2910,16 @@
 					len, flags, pagep, fsdata);
 	}
 	*fsdata = (void *)0;
-	trace_android_fs_datawrite_start(inode, pos, len,
-					 current->pid, current->comm);
+	if (trace_android_fs_datawrite_start_enabled()) {
+		char *path, pathbuf[MAX_TRACE_PATHBUF_LEN];
+
+		path = android_fstrace_get_pathname(pathbuf,
+						    MAX_TRACE_PATHBUF_LEN,
+						    inode);
+		trace_android_fs_datawrite_start(inode, pos, len,
+						 current->pid,
+						 path, current->comm);
+	}
 	trace_ext4_da_write_begin(inode, pos, len, flags);
 
 	if (ext4_test_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA)) {
@@ -3597,16 +3613,27 @@
 		return 0;
 
 	if (trace_android_fs_dataread_start_enabled() &&
-	    (rw == READ))
-		trace_android_fs_dataread_start(inode, offset, count,
-						current->pid,
-						current->comm);
-	if (trace_android_fs_datawrite_start_enabled() &&
-	    (rw == WRITE))
-		trace_android_fs_datawrite_start(inode, offset, count,
-						 current->pid,
-						 current->comm);
+	    (rw == READ)) {
+		char *path, pathbuf[MAX_TRACE_PATHBUF_LEN];
 
+		path = android_fstrace_get_pathname(pathbuf,
+						    MAX_TRACE_PATHBUF_LEN,
+						    inode);
+		trace_android_fs_dataread_start(inode, offset, count,
+						current->pid, path,
+						current->comm);
+	}
+	if (trace_android_fs_datawrite_start_enabled() &&
+	    (rw == WRITE)) {
+		char *path, pathbuf[MAX_TRACE_PATHBUF_LEN];
+
+		path = android_fstrace_get_pathname(pathbuf,
+						    MAX_TRACE_PATHBUF_LEN,
+						    inode);
+		trace_android_fs_datawrite_start(inode, offset, count,
+						 current->pid, path,
+						 current->comm);
+	}
 	trace_ext4_direct_IO_enter(inode, offset, count, iov_iter_rw(iter));
 	if (iov_iter_rw(iter) == READ)
 		ret = ext4_direct_IO_read(iocb, iter);
@@ -3839,6 +3866,11 @@
 	unsigned blocksize;
 	struct inode *inode = mapping->host;
 
+	/* If we are processing an encrypted inode during orphan list
+	 * handling */
+	if (ext4_encrypted_inode(inode) && !fscrypt_has_encryption_key(inode))
+		return 0;
+
 	blocksize = inode->i_sb->s_blocksize;
 	length = blocksize - (offset & (blocksize - 1));
 
diff --git a/fs/ext4/readpage.c b/fs/ext4/readpage.c
index 77cf54c..2531cc1 100644
--- a/fs/ext4/readpage.c
+++ b/fs/ext4/readpage.c
@@ -117,11 +117,17 @@
 		struct page *first_page = bio->bi_io_vec[0].bv_page;
 
 		if (first_page != NULL) {
+			char *path, pathbuf[MAX_TRACE_PATHBUF_LEN];
+
+			path = android_fstrace_get_pathname(pathbuf,
+						    MAX_TRACE_PATHBUF_LEN,
+						    first_page->mapping->host);
 			trace_android_fs_dataread_start(
 				first_page->mapping->host,
 				page_offset(first_page),
 				bio->bi_iter.bi_size,
 				current->pid,
+				path,
 				current->comm);
 		}
 	}
diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c
index aee4a45..2c5ae0b 100644
--- a/fs/f2fs/data.c
+++ b/fs/f2fs/data.c
@@ -1607,8 +1607,16 @@
 	block_t blkaddr = NULL_ADDR;
 	int err = 0;
 
-	trace_android_fs_datawrite_start(inode, pos, len,
-					 current->pid, current->comm);
+	if (trace_android_fs_datawrite_start_enabled()) {
+		char *path, pathbuf[MAX_TRACE_PATHBUF_LEN];
+
+		path = android_fstrace_get_pathname(pathbuf,
+						    MAX_TRACE_PATHBUF_LEN,
+						    inode);
+		trace_android_fs_datawrite_start(inode, pos, len,
+						 current->pid, path,
+						 current->comm);
+	}
 	trace_f2fs_write_begin(inode, pos, len, flags);
 
 	/*
@@ -1763,14 +1771,27 @@
 	trace_f2fs_direct_IO_enter(inode, offset, count, rw);
 
 	if (trace_android_fs_dataread_start_enabled() &&
-	    (rw == READ))
+	    (rw == READ)) {
+		char *path, pathbuf[MAX_TRACE_PATHBUF_LEN];
+
+		path = android_fstrace_get_pathname(pathbuf,
+						    MAX_TRACE_PATHBUF_LEN,
+						    inode);
 		trace_android_fs_dataread_start(inode, offset,
-						count, current->pid,
+						count, current->pid, path,
 						current->comm);
+	}
 	if (trace_android_fs_datawrite_start_enabled() &&
-	    (rw == WRITE))
+	    (rw == WRITE)) {
+		char *path, pathbuf[MAX_TRACE_PATHBUF_LEN];
+
+		path = android_fstrace_get_pathname(pathbuf,
+						    MAX_TRACE_PATHBUF_LEN,
+						    inode);
 		trace_android_fs_datawrite_start(inode, offset, count,
-						 current->pid, current->comm);
+						 current->pid, path,
+						 current->comm);
+	}
 
 	down_read(&F2FS_I(inode)->dio_rwsem[rw]);
 	err = blockdev_direct_IO(iocb, inode, iter, get_data_block_dio);
diff --git a/fs/f2fs/inline.c b/fs/f2fs/inline.c
index d534f44..1427db9 100644
--- a/fs/f2fs/inline.c
+++ b/fs/f2fs/inline.c
@@ -83,9 +83,16 @@
 {
 	struct page *ipage;
 
-	trace_android_fs_dataread_start(inode, page_offset(page),
-					PAGE_SIZE, current->pid,
-					current->comm);
+	if (trace_android_fs_dataread_start_enabled()) {
+		char *path, pathbuf[MAX_TRACE_PATHBUF_LEN];
+
+		path = android_fstrace_get_pathname(pathbuf,
+						    MAX_TRACE_PATHBUF_LEN,
+						    inode);
+		trace_android_fs_dataread_start(inode, page_offset(page),
+						PAGE_SIZE, current->pid,
+						path, current->comm);
+	}
 
 	ipage = get_node_page(F2FS_I_SB(inode), inode->i_ino);
 	if (IS_ERR(ipage)) {
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
index 3fd1e21..83511cb 100644
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -401,6 +401,10 @@
 static void queue_interrupt(struct fuse_iqueue *fiq, struct fuse_req *req)
 {
 	spin_lock(&fiq->waitq.lock);
+	if (test_bit(FR_FINISHED, &req->flags)) {
+		spin_unlock(&fiq->waitq.lock);
+		return;
+	}
 	if (list_empty(&req->intr_entry)) {
 		list_add_tail(&req->intr_entry, &fiq->interrupts);
 		wake_up_locked(&fiq->waitq);
@@ -1376,6 +1380,7 @@
 		 * code can Oops if the buffer persists after module unload.
 		 */
 		bufs[page_nr].ops = &nosteal_pipe_buf_ops;
+		bufs[page_nr].flags = 0;
 		ret = add_to_pipe(pipe, &bufs[page_nr++]);
 		if (unlikely(ret < 0))
 			break;
diff --git a/fs/mpage.c b/fs/mpage.c
index 2bb117d..802b481 100644
--- a/fs/mpage.c
+++ b/fs/mpage.c
@@ -80,11 +80,17 @@
 		struct page *first_page = bio->bi_io_vec[0].bv_page;
 
 		if (first_page != NULL) {
+			char *path, pathbuf[MAX_TRACE_PATHBUF_LEN];
+
+			path = android_fstrace_get_pathname(pathbuf,
+						    MAX_TRACE_PATHBUF_LEN,
+						    first_page->mapping->host);
 			trace_android_fs_dataread_start(
 				first_page->mapping->host,
 				page_offset(first_page),
 				bio->bi_iter.bi_size,
 				current->pid,
+				path,
 				current->comm);
 		}
 	}
diff --git a/fs/splice.c b/fs/splice.c
index 63b8f54..8dd79ec 100644
--- a/fs/splice.c
+++ b/fs/splice.c
@@ -203,6 +203,7 @@
 		buf->len = spd->partial[page_nr].len;
 		buf->private = spd->partial[page_nr].private;
 		buf->ops = spd->ops;
+		buf->flags = 0;
 
 		pipe->nrbufs++;
 		page_nr++;
diff --git a/include/linux/can/core.h b/include/linux/can/core.h
index a087500..df08a41 100644
--- a/include/linux/can/core.h
+++ b/include/linux/can/core.h
@@ -45,10 +45,9 @@
 extern int  can_proto_register(const struct can_proto *cp);
 extern void can_proto_unregister(const struct can_proto *cp);
 
-extern int  can_rx_register(struct net_device *dev, canid_t can_id,
-			    canid_t mask,
-			    void (*func)(struct sk_buff *, void *),
-			    void *data, char *ident);
+int can_rx_register(struct net_device *dev, canid_t can_id, canid_t mask,
+		    void (*func)(struct sk_buff *, void *),
+		    void *data, char *ident, struct sock *sk);
 
 extern void can_rx_unregister(struct net_device *dev, canid_t can_id,
 			      canid_t mask,
diff --git a/include/linux/clocksource.h b/include/linux/clocksource.h
index 0839818..3a4f264 100644
--- a/include/linux/clocksource.h
+++ b/include/linux/clocksource.h
@@ -186,6 +186,7 @@
 extern void clocksource_resume(void);
 extern struct clocksource * __init clocksource_default_clock(void);
 extern void clocksource_mark_unstable(struct clocksource *cs);
+extern void clocksource_select_force(void);
 
 extern u64
 clocks_calc_max_nsecs(u32 mult, u32 shift, u32 maxadj, u64 mask, u64 *max_cycles);
diff --git a/include/linux/coresight.h b/include/linux/coresight.h
index 9535e79..ec7047c 100644
--- a/include/linux/coresight.h
+++ b/include/linux/coresight.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, 2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012, 2016-2017, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -175,6 +175,7 @@
 	const struct coresight_ops *ops;
 	struct device dev;
 	atomic_t *refcnt;
+	struct coresight_path *node;
 	bool orphan;
 	bool enable;	/* true only if configured as part of a path */
 	bool activated;	/* true only if a sink is part of a path */
diff --git a/include/linux/cpumask.h b/include/linux/cpumask.h
index eec093c..b8eb25b 100644
--- a/include/linux/cpumask.h
+++ b/include/linux/cpumask.h
@@ -567,7 +567,7 @@
 static inline int cpumask_parse_user(const char __user *buf, int len,
 				     struct cpumask *dstp)
 {
-	return bitmap_parse_user(buf, len, cpumask_bits(dstp), nr_cpu_ids);
+	return bitmap_parse_user(buf, len, cpumask_bits(dstp), nr_cpumask_bits);
 }
 
 /**
@@ -582,7 +582,7 @@
 				     struct cpumask *dstp)
 {
 	return bitmap_parselist_user(buf, len, cpumask_bits(dstp),
-				     nr_cpu_ids);
+				     nr_cpumask_bits);
 }
 
 /**
@@ -597,7 +597,7 @@
 	char *nl = strchr(buf, '\n');
 	unsigned int len = nl ? (unsigned int)(nl - buf) : strlen(buf);
 
-	return bitmap_parse(buf, len, cpumask_bits(dstp), nr_cpu_ids);
+	return bitmap_parse(buf, len, cpumask_bits(dstp), nr_cpumask_bits);
 }
 
 /**
@@ -609,7 +609,7 @@
  */
 static inline int cpulist_parse(const char *buf, struct cpumask *dstp)
 {
-	return bitmap_parselist(buf, cpumask_bits(dstp), nr_cpu_ids);
+	return bitmap_parselist(buf, cpumask_bits(dstp), nr_cpumask_bits);
 }
 
 /**
diff --git a/include/linux/device.h b/include/linux/device.h
index d85101c..d469121 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -55,6 +55,8 @@
 	struct bus_attribute bus_attr_##_name = __ATTR_RW(_name)
 #define BUS_ATTR_RO(_name) \
 	struct bus_attribute bus_attr_##_name = __ATTR_RO(_name)
+#define BUS_ATTR_WO(_name) \
+	struct bus_attribute bus_attr_##_name = __ATTR_WO(_name)
 
 extern int __must_check bus_create_file(struct bus_type *,
 					struct bus_attribute *);
diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h
index cd184bd..c92a083 100644
--- a/include/linux/hyperv.h
+++ b/include/linux/hyperv.h
@@ -128,6 +128,7 @@
 	u32 ring_data_startoffset;
 	u32 priv_write_index;
 	u32 priv_read_index;
+	u32 cached_read_index;
 };
 
 /*
@@ -180,6 +181,19 @@
 	return write;
 }
 
+static inline u32 hv_get_cached_bytes_to_write(
+	const struct hv_ring_buffer_info *rbi)
+{
+	u32 read_loc, write_loc, dsize, write;
+
+	dsize = rbi->ring_datasize;
+	read_loc = rbi->cached_read_index;
+	write_loc = rbi->ring_buffer->write_index;
+
+	write = write_loc >= read_loc ? dsize - (write_loc - read_loc) :
+		read_loc - write_loc;
+	return write;
+}
 /*
  * VMBUS version is 32 bit entity broken up into
  * two 16 bit quantities: major_number. minor_number.
@@ -1447,6 +1461,7 @@
 
 void hv_process_channel_removal(struct vmbus_channel *channel, u32 relid);
 
+void vmbus_setevent(struct vmbus_channel *channel);
 /*
  * Negotiated version with the Host.
  */
@@ -1479,10 +1494,11 @@
  *    there is room for the producer to send the pending packet.
  */
 
-static inline  bool hv_need_to_signal_on_read(struct hv_ring_buffer_info *rbi)
+static inline  void hv_signal_on_read(struct vmbus_channel *channel)
 {
-	u32 cur_write_sz;
+	u32 cur_write_sz, cached_write_sz;
 	u32 pending_sz;
+	struct hv_ring_buffer_info *rbi = &channel->inbound;
 
 	/*
 	 * Issue a full memory barrier before making the signaling decision.
@@ -1500,14 +1516,26 @@
 	pending_sz = READ_ONCE(rbi->ring_buffer->pending_send_sz);
 	/* If the other end is not blocked on write don't bother. */
 	if (pending_sz == 0)
-		return false;
+		return;
 
 	cur_write_sz = hv_get_bytes_to_write(rbi);
 
-	if (cur_write_sz >= pending_sz)
-		return true;
+	if (cur_write_sz < pending_sz)
+		return;
 
-	return false;
+	cached_write_sz = hv_get_cached_bytes_to_write(rbi);
+	if (cached_write_sz < pending_sz)
+		vmbus_setevent(channel);
+
+	return;
+}
+
+static inline void
+init_cached_read_index(struct vmbus_channel *channel)
+{
+	struct hv_ring_buffer_info *rbi = &channel->inbound;
+
+	rbi->cached_read_index = rbi->ring_buffer->read_index;
 }
 
 /*
@@ -1571,6 +1599,8 @@
  * This call commits the read index and potentially signals the host.
  * Here is the pattern for using the "in-place" consumption APIs:
  *
+ * init_cached_read_index();
+ *
  * while (get_next_pkt_raw() {
  *	process the packet "in-place";
  *	put_pkt_raw();
@@ -1589,8 +1619,7 @@
 	virt_rmb();
 	ring_info->ring_buffer->read_index = ring_info->priv_read_index;
 
-	if (hv_need_to_signal_on_read(ring_info))
-		vmbus_set_event(channel);
+	hv_signal_on_read(channel);
 }
 
 
diff --git a/include/linux/ipa.h b/include/linux/ipa.h
index 5fc7dda..a83ac84 100644
--- a/include/linux/ipa.h
+++ b/include/linux/ipa.h
@@ -765,7 +765,7 @@
 	IPA_TX_SUSPEND_IRQ,
 	IPA_TX_HOLB_DROP_IRQ,
 	IPA_BAM_IDLE_IRQ,
-	IPA_BAM_GSI_IDLE_IRQ = IPA_BAM_IDLE_IRQ,
+	IPA_GSI_IDLE_IRQ = IPA_BAM_IDLE_IRQ,
 	IPA_IRQ_MAX
 };
 
@@ -1412,7 +1412,8 @@
 
 int ipa_disable_apps_wan_cons_deaggr(uint32_t agg_size, uint32_t agg_count);
 
-struct ipa_gsi_ep_config *ipa_get_gsi_ep_info(int ipa_ep_idx);
+const struct ipa_gsi_ep_config *ipa_get_gsi_ep_info
+	(enum ipa_client_type client);
 
 int ipa_stop_gsi_channel(u32 clnt_hdl);
 
@@ -2156,7 +2157,8 @@
 	return -EINVAL;
 }
 
-static inline struct ipa_gsi_ep_config *ipa_get_gsi_ep_info(int ipa_ep_idx)
+static inline const struct ipa_gsi_ep_config *ipa_get_gsi_ep_info
+	(enum ipa_client_type client)
 {
 	return NULL;
 }
diff --git a/include/linux/memblock.h b/include/linux/memblock.h
index da25f07..f7033fa 100644
--- a/include/linux/memblock.h
+++ b/include/linux/memblock.h
@@ -341,7 +341,7 @@
 int memblock_is_region_memory(phys_addr_t base, phys_addr_t size);
 bool memblock_is_reserved(phys_addr_t addr);
 bool memblock_is_region_reserved(phys_addr_t base, phys_addr_t size);
-int memblock_overlaps_memory(phys_addr_t base, phys_addr_t size);
+bool memblock_overlaps_memory(phys_addr_t base, phys_addr_t size);
 
 extern void __memblock_dump_all(void);
 
diff --git a/include/linux/msm_gsi.h b/include/linux/msm_gsi.h
index 6037fbf..d4b4cc7 100644
--- a/include/linux/msm_gsi.h
+++ b/include/linux/msm_gsi.h
@@ -1053,6 +1053,18 @@
 void gsi_get_inst_ram_offset_and_size(unsigned long *base_offset,
 		unsigned long *size);
 
+/**
+ * gsi_halt_channel_ee - Peripheral should call this function
+ * to stop other EE's channel. This is usually used in SSR clean
+ *
+ * @chan_idx: Virtual channel index
+ * @ee: EE
+ * @code: [out] response code for operation
+
+ * @Return gsi_status
+ */
+int gsi_halt_channel_ee(unsigned int chan_idx, unsigned int ee, int *code);
+
 /*
  * Here is a typical sequence of calls
  *
@@ -1250,5 +1262,11 @@
 		unsigned long *size)
 {
 }
+
+static inline int gsi_halt_channel_ee(unsigned int chan_idx, unsigned int ee,
+	 int *code)
+{
+	return -GSI_STATUS_UNSUPPORTED_OP;
+}
 #endif
 #endif
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index d213c76..a47c29e 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -1508,6 +1508,7 @@
  *	@mtu:		Interface MTU value
  *	@type:		Interface hardware type
  *	@hard_header_len: Maximum hardware header length.
+ *	@min_header_len:  Minimum hardware header length
  *
  *	@needed_headroom: Extra headroom the hardware may need, but not in all
  *			  cases can this be guaranteed
@@ -1728,6 +1729,7 @@
 	unsigned int		mtu;
 	unsigned short		type;
 	unsigned short		hard_header_len;
+	unsigned short		min_header_len;
 
 	unsigned short		needed_headroom;
 	unsigned short		needed_tailroom;
@@ -2783,6 +2785,8 @@
 {
 	if (likely(len >= dev->hard_header_len))
 		return true;
+	if (len < dev->min_header_len)
+		return false;
 
 	if (capable(CAP_SYS_RAWIO)) {
 		memset(ll_header + len, 0, dev->hard_header_len - len);
diff --git a/include/linux/nmi.h b/include/linux/nmi.h
index 780949d..dde3b13 100644
--- a/include/linux/nmi.h
+++ b/include/linux/nmi.h
@@ -9,7 +9,7 @@
 
 /**
  * touch_nmi_watchdog - restart NMI watchdog timeout.
- * 
+ *
  * If the architecture supports the NMI watchdog, touch_nmi_watchdog()
  * may be used to reset the timeout - for code which intentionally
  * disables interrupts for a long time. This call is stateless.
@@ -41,25 +41,37 @@
 #ifdef arch_trigger_cpumask_backtrace
 static inline bool trigger_all_cpu_backtrace(void)
 {
-	arch_trigger_cpumask_backtrace(cpu_online_mask, false);
+	#if defined(CONFIG_ARM64)
+		arch_trigger_all_cpu_backtrace();
+	else
+		arch_trigger_cpumask_backtrace(cpu_online_mask, false);
+	#endif
+
 	return true;
 }
 
 static inline bool trigger_allbutself_cpu_backtrace(void)
 {
-	arch_trigger_cpumask_backtrace(cpu_online_mask, true);
+	#if defined(CONFIG_ARM64)
+		arch_trigger_all_cpu_backtrace();
+	else
+		arch_trigger_cpumask_backtrace(cpu_online_mask, true);
+	#endif
+
 	return true;
 }
 
 static inline bool trigger_cpumask_backtrace(struct cpumask *mask)
 {
 	arch_trigger_cpumask_backtrace(mask, false);
+
 	return true;
 }
 
 static inline bool trigger_single_cpu_backtrace(int cpu)
 {
 	arch_trigger_cpumask_backtrace(cpumask_of(cpu), false);
+
 	return true;
 }
 
diff --git a/include/linux/timer.h b/include/linux/timer.h
index 356793e..3e354fd 100644
--- a/include/linux/timer.h
+++ b/include/linux/timer.h
@@ -244,6 +244,8 @@
 
 extern int try_to_del_timer_sync(struct timer_list *timer);
 
+extern struct timer_base timer_base_deferrable;
+
 #ifdef CONFIG_SMP
   extern int del_timer_sync(struct timer_list *timer);
 #else
diff --git a/include/linux/usb/usb_qdss.h b/include/linux/usb/usb_qdss.h
new file mode 100644
index 0000000..b58d8ee
--- /dev/null
+++ b/include/linux/usb/usb_qdss.h
@@ -0,0 +1,95 @@
+/* Copyright (c) 2012-2013, 2017 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __LINUX_USB_QDSS_H
+#define __LINUX_USB_QDSS_H
+
+#include <linux/kernel.h>
+
+struct qdss_request {
+	char *buf;
+	int length;
+	int actual;
+	int status;
+	void *context;
+};
+
+struct usb_qdss_ch {
+	const char *name;
+	struct list_head list;
+	void (*notify)(void *priv, unsigned int event,
+		struct qdss_request *d_req, struct usb_qdss_ch *ch);
+	void *priv;
+	void *priv_usb;
+	int app_conn;
+};
+
+enum qdss_state {
+	USB_QDSS_CONNECT,
+	USB_QDSS_DISCONNECT,
+	USB_QDSS_CTRL_READ_DONE,
+	USB_QDSS_DATA_WRITE_DONE,
+	USB_QDSS_CTRL_WRITE_DONE,
+};
+
+#if IS_ENABLED(CONFIG_USB_F_QDSS)
+struct usb_qdss_ch *usb_qdss_open(const char *name, void *priv,
+	void (*notify)(void *priv, unsigned int event,
+		struct qdss_request *d_req, struct usb_qdss_ch *ch));
+void usb_qdss_close(struct usb_qdss_ch *ch);
+int usb_qdss_alloc_req(struct usb_qdss_ch *ch, int n_write, int n_read);
+void usb_qdss_free_req(struct usb_qdss_ch *ch);
+int usb_qdss_read(struct usb_qdss_ch *ch, struct qdss_request *d_req);
+int usb_qdss_write(struct usb_qdss_ch *ch, struct qdss_request *d_req);
+int usb_qdss_ctrl_write(struct usb_qdss_ch *ch, struct qdss_request *d_req);
+int usb_qdss_ctrl_read(struct usb_qdss_ch *ch, struct qdss_request *d_req);
+#else
+static inline struct usb_qdss_ch *usb_qdss_open(const char *name, void *priv,
+		void (*n)(void *, unsigned int event,
+		struct qdss_request *d, struct usb_qdss_ch *c))
+{
+	return ERR_PTR(-ENODEV);
+}
+
+static inline int usb_qdss_read(struct usb_qdss_ch *c, struct qdss_request *d)
+{
+	return -ENODEV;
+}
+
+static inline int usb_qdss_write(struct usb_qdss_ch *c, struct qdss_request *d)
+{
+	return -ENODEV;
+}
+
+static inline int usb_qdss_ctrl_write(struct usb_qdss_ch *c,
+		struct qdss_request *d)
+{
+	return -ENODEV;
+}
+
+static inline int usb_qdss_ctrl_read(struct usb_qdss_ch *c,
+		struct qdss_request *d)
+{
+	return -ENODEV;
+}
+static inline int usb_qdss_alloc_req(struct usb_qdss_ch *c, int n_wr, int n_rd)
+{
+	return -ENODEV;
+}
+
+
+static inline void usb_qdss_close(struct usb_qdss_ch *ch) { }
+
+static inline void usb_qdss_free_req(struct usb_qdss_ch *ch) { }
+#endif /* CONFIG_USB_F_QDSS */
+
+#endif
diff --git a/include/net/cipso_ipv4.h b/include/net/cipso_ipv4.h
index 3ebb168..a34b141 100644
--- a/include/net/cipso_ipv4.h
+++ b/include/net/cipso_ipv4.h
@@ -309,6 +309,10 @@
 	}
 
 	for (opt_iter = 6; opt_iter < opt_len;) {
+		if (opt_iter + 1 == opt_len) {
+			err_offset = opt_iter;
+			goto out;
+		}
 		tag_len = opt[opt_iter + 1];
 		if ((tag_len == 0) || (tag_len > (opt_len - opt_iter))) {
 			err_offset = opt_iter + 1;
diff --git a/include/net/ipv6.h b/include/net/ipv6.h
index f11ca83..7f15f95 100644
--- a/include/net/ipv6.h
+++ b/include/net/ipv6.h
@@ -871,7 +871,7 @@
  *	upper-layer output functions
  */
 int ip6_xmit(const struct sock *sk, struct sk_buff *skb, struct flowi6 *fl6,
-	     struct ipv6_txoptions *opt, int tclass);
+	     __u32 mark, struct ipv6_txoptions *opt, int tclass);
 
 int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr);
 
diff --git a/include/net/lwtunnel.h b/include/net/lwtunnel.h
index fc7c0db..3f40132 100644
--- a/include/net/lwtunnel.h
+++ b/include/net/lwtunnel.h
@@ -176,7 +176,10 @@
 }
 static inline int lwtunnel_valid_encap_type_attr(struct nlattr *attr, int len)
 {
-	return -EOPNOTSUPP;
+	/* return 0 since we are not walking attr looking for
+	 * RTA_ENCAP_TYPE attribute on nexthops.
+	 */
+	return 0;
 }
 
 static inline int lwtunnel_build_state(struct net_device *dev, u16 encap_type,
diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h
index c211900..48bc1ac 100644
--- a/include/target/target_core_base.h
+++ b/include/target/target_core_base.h
@@ -538,6 +538,7 @@
 	char			initiatorname[TRANSPORT_IQN_LEN];
 	/* Used to signal demo mode created ACL, disabled by default */
 	bool			dynamic_node_acl;
+	bool			dynamic_stop;
 	u32			queue_depth;
 	u32			acl_index;
 	enum target_prot_type	saved_prot_type;
diff --git a/include/trace/events/android_fs.h b/include/trace/events/android_fs.h
index 531da43..4950953 100644
--- a/include/trace/events/android_fs.h
+++ b/include/trace/events/android_fs.h
@@ -9,8 +9,8 @@
 
 DEFINE_EVENT(android_fs_data_start_template, android_fs_dataread_start,
 	TP_PROTO(struct inode *inode, loff_t offset, int bytes,
-		 pid_t pid, char *command),
-	TP_ARGS(inode, offset, bytes, pid, command));
+		 pid_t pid, char *pathname, char *command),
+	TP_ARGS(inode, offset, bytes, pid, pathname, command));
 
 DEFINE_EVENT(android_fs_data_end_template, android_fs_dataread_end,
 	TP_PROTO(struct inode *inode, loff_t offset, int bytes),
@@ -18,14 +18,48 @@
 
 DEFINE_EVENT(android_fs_data_start_template, android_fs_datawrite_start,
 	TP_PROTO(struct inode *inode, loff_t offset, int bytes,
-		 pid_t pid, char *command),
-	TP_ARGS(inode, offset, bytes, pid, command));
+		 pid_t pid, char *pathname, char *command),
+	TP_ARGS(inode, offset, bytes, pid, pathname, command));
 
 DEFINE_EVENT(android_fs_data_end_template, android_fs_datawrite_end,
 	TP_PROTO(struct inode *inode, loff_t offset, int bytes),
-	TP_ARGS(inode, offset, bytes));
+	     TP_ARGS(inode, offset, bytes));
 
 #endif /* _TRACE_ANDROID_FS_H */
 
 /* This part must be outside protection */
 #include <trace/define_trace.h>
+
+#ifndef ANDROID_FSTRACE_GET_PATHNAME
+#define ANDROID_FSTRACE_GET_PATHNAME
+
+/* Sizes an on-stack array, so careful if sizing this up ! */
+#define MAX_TRACE_PATHBUF_LEN	256
+
+static inline char *
+android_fstrace_get_pathname(char *buf, int buflen, struct inode *inode)
+{
+	char *path;
+	struct dentry *d;
+
+	/*
+	 * d_obtain_alias() will either iput() if it locates an existing
+	 * dentry or transfer the reference to the new dentry created.
+	 * So get an extra reference here.
+	 */
+	ihold(inode);
+	d = d_obtain_alias(inode);
+	if (likely(!IS_ERR(d))) {
+		path = dentry_path_raw(d, buf, buflen);
+		if (unlikely(IS_ERR(path))) {
+			strcpy(buf, "ERROR");
+			path = buf;
+		}
+		dput(d);
+	} else {
+		strcpy(buf, "ERROR");
+		path = buf;
+	}
+	return path;
+}
+#endif
diff --git a/include/trace/events/android_fs_template.h b/include/trace/events/android_fs_template.h
index 618988b..4e61ffe 100644
--- a/include/trace/events/android_fs_template.h
+++ b/include/trace/events/android_fs_template.h
@@ -5,11 +5,10 @@
 
 DECLARE_EVENT_CLASS(android_fs_data_start_template,
 	TP_PROTO(struct inode *inode, loff_t offset, int bytes,
-		 pid_t pid, char *command),
-	TP_ARGS(inode, offset, bytes, pid, command),
+		 pid_t pid, char *pathname, char *command),
+	TP_ARGS(inode, offset, bytes, pid, pathname, command),
 	TP_STRUCT__entry(
-		__array(char, path, MAX_FILTER_STR_VAL);
-		__field(char *, pathname);
+		__string(pathbuf, pathname);
 		__field(loff_t,	offset);
 		__field(int,	bytes);
 		__field(loff_t,	i_size);
@@ -19,27 +18,7 @@
 	),
 	TP_fast_assign(
 		{
-			struct dentry *d;
-
-			/*
-			 * Grab a reference to the inode here because
-			 * d_obtain_alias() will either drop the inode
-			 * reference if it locates an existing dentry
-			 * or transfer the reference to the new dentry
-			 * created. In our case, the file is still open,
-			 * so the dentry is guaranteed to exist (connected),
-			 * so d_obtain_alias() drops the reference we
-			 * grabbed here.
-			 */
-			ihold(inode);
-			d = d_obtain_alias(inode);
-			if (!IS_ERR(d)) {
-				__entry->pathname = dentry_path(d,
-							__entry->path,
-							MAX_FILTER_STR_VAL);
-				dput(d);
-			} else
-				__entry->pathname = ERR_PTR(-EINVAL);
+			__assign_str(pathbuf, pathname);
 			__entry->offset		= offset;
 			__entry->bytes		= bytes;
 			__entry->i_size		= i_size_read(inode);
@@ -50,9 +29,8 @@
 	),
 	TP_printk("entry_name %s, offset %llu, bytes %d, cmdline %s,"
 		  " pid %d, i_size %llu, ino %lu",
-		  (IS_ERR(__entry->pathname) ? "ERROR" : __entry->pathname),
-		  __entry->offset, __entry->bytes, __get_str(cmdline),
-		  __entry->pid, __entry->i_size,
+		  __get_str(pathbuf), __entry->offset, __entry->bytes,
+		  __get_str(cmdline), __entry->pid, __entry->i_size,
 		  (unsigned long) __entry->ino)
 );
 
diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
index 6e7d325..a242e72 100644
--- a/include/uapi/linux/videodev2.h
+++ b/include/uapi/linux/videodev2.h
@@ -350,8 +350,8 @@
 	/*
 	 * The default for R'G'B' quantization is always full range, except
 	 * for the BT2020 colorspace. For Y'CbCr the quantization is always
-	 * limited range, except for COLORSPACE_JPEG, SRGB, ADOBERGB,
-	 * XV601 or XV709: those are full range.
+	 * limited range, except for COLORSPACE_JPEG, XV601 or XV709: those
+	 * are full range.
 	 */
 	V4L2_QUANTIZATION_DEFAULT     = 0,
 	V4L2_QUANTIZATION_FULL_RANGE  = 1,
@@ -366,8 +366,7 @@
 #define V4L2_MAP_QUANTIZATION_DEFAULT(is_rgb, colsp, ycbcr_enc) \
 	(((is_rgb) && (colsp) == V4L2_COLORSPACE_BT2020) ? V4L2_QUANTIZATION_LIM_RANGE : \
 	 (((is_rgb) || (ycbcr_enc) == V4L2_YCBCR_ENC_XV601 || \
-	  (ycbcr_enc) == V4L2_YCBCR_ENC_XV709 || (colsp) == V4L2_COLORSPACE_JPEG) || \
-	  (colsp) == V4L2_COLORSPACE_ADOBERGB || (colsp) == V4L2_COLORSPACE_SRGB ? \
+	  (ycbcr_enc) == V4L2_YCBCR_ENC_XV709 || (colsp) == V4L2_COLORSPACE_JPEG) ? \
 	 V4L2_QUANTIZATION_FULL_RANGE : V4L2_QUANTIZATION_LIM_RANGE))
 
 enum v4l2_priority {
diff --git a/kernel/events/core.c b/kernel/events/core.c
index 8e901de..99c91f6 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -3466,14 +3466,15 @@
 	int ret;
 };
 
-static int find_cpu_to_read(struct perf_event *event, int local_cpu)
+static int __perf_event_read_cpu(struct perf_event *event, int event_cpu)
 {
-	int event_cpu = event->oncpu;
 	u16 local_pkg, event_pkg;
 
 	if (event->group_caps & PERF_EV_CAP_READ_ACTIVE_PKG) {
-		event_pkg =  topology_physical_package_id(event_cpu);
-		local_pkg =  topology_physical_package_id(local_cpu);
+		int local_cpu = smp_processor_id();
+
+		event_pkg = topology_physical_package_id(event_cpu);
+		local_pkg = topology_physical_package_id(local_cpu);
 
 		if (event_pkg == local_pkg)
 			return local_cpu;
@@ -3603,7 +3604,7 @@
 
 static int perf_event_read(struct perf_event *event, bool group)
 {
-	int ret = 0, cpu_to_read, local_cpu;
+	int event_cpu, ret = 0;
 
 	/*
 	 * If event is enabled and currently active on a CPU, update the
@@ -3617,21 +3618,25 @@
 			.ret = 0,
 		};
 
-		local_cpu = get_cpu();
-		cpu_to_read = find_cpu_to_read(event, local_cpu);
-		put_cpu();
+		event_cpu = READ_ONCE(event->oncpu);
+		if ((unsigned)event_cpu >= nr_cpu_ids)
+			return 0;
+
+		preempt_disable();
+		event_cpu = __perf_event_read_cpu(event, event_cpu);
 
 		/*
 		 * Purposely ignore the smp_call_function_single() return
 		 * value.
 		 *
-		 * If event->oncpu isn't a valid CPU it means the event got
+		 * If event_cpu isn't a valid CPU it means the event got
 		 * scheduled out and that will have updated the event count.
 		 *
 		 * Therefore, either way, we'll have an up-to-date event count
 		 * after this.
 		 */
-		(void)smp_call_function_single(cpu_to_read, __perf_event_read, &data, 1);
+		(void)smp_call_function_single(event_cpu, __perf_event_read, &data, 1);
+		preempt_enable();
 		ret = data.ret;
 	} else if (event->state == PERF_EVENT_STATE_INACTIVE) {
 		struct perf_event_context *ctx = event->ctx;
diff --git a/kernel/futex.c b/kernel/futex.c
index 2c4be46..38b68c2 100644
--- a/kernel/futex.c
+++ b/kernel/futex.c
@@ -3323,4 +3323,4 @@
 
 	return 0;
 }
-__initcall(futex_init);
+core_initcall(futex_init);
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index b38f3fb..20fc294 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -1568,7 +1568,7 @@
 {
 	struct console *con;
 
-	trace_console(text, len);
+	trace_console_rcuidle(text, len);
 
 	if (!console_drivers)
 		return;
diff --git a/kernel/sched/Makefile b/kernel/sched/Makefile
index eed4b72..90d10e8 100644
--- a/kernel/sched/Makefile
+++ b/kernel/sched/Makefile
@@ -29,3 +29,4 @@
 obj-$(CONFIG_CPU_FREQ_GOV_SCHEDUTIL) += cpufreq_schedutil.o
 obj-$(CONFIG_SCHED_CORE_CTL) += core_ctl.o
 obj-$(CONFIG_CPU_FREQ_GOV_SCHED) += cpufreq_sched.o
+obj-$(CONFIG_CPU_FREQ_GOV_SCHEDUTIL) += cpufreq_schedutil.o
diff --git a/kernel/sched/cpufreq_schedutil.c b/kernel/sched/cpufreq_schedutil.c
new file mode 100644
index 0000000..69e0689
--- /dev/null
+++ b/kernel/sched/cpufreq_schedutil.c
@@ -0,0 +1,576 @@
+/*
+ * CPUFreq governor based on scheduler-provided CPU utilization data.
+ *
+ * Copyright (C) 2016, Intel Corporation
+ * Author: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/cpufreq.h>
+#include <linux/slab.h>
+#include <trace/events/power.h>
+
+#include "sched.h"
+
+struct sugov_tunables {
+	struct gov_attr_set attr_set;
+	unsigned int rate_limit_us;
+};
+
+struct sugov_policy {
+	struct cpufreq_policy *policy;
+
+	struct sugov_tunables *tunables;
+	struct list_head tunables_hook;
+
+	raw_spinlock_t update_lock;  /* For shared policies */
+	u64 last_freq_update_time;
+	s64 freq_update_delay_ns;
+	unsigned int next_freq;
+
+	/* The next fields are only needed if fast switch cannot be used. */
+	struct irq_work irq_work;
+	struct work_struct work;
+	struct mutex work_lock;
+	bool work_in_progress;
+
+	bool need_freq_update;
+};
+
+struct sugov_cpu {
+	struct update_util_data update_util;
+	struct sugov_policy *sg_policy;
+
+	unsigned int cached_raw_freq;
+	unsigned long iowait_boost;
+	unsigned long iowait_boost_max;
+	u64 last_update;
+
+	/* The fields below are only needed when sharing a policy. */
+	unsigned long util;
+	unsigned long max;
+	unsigned int flags;
+};
+
+static DEFINE_PER_CPU(struct sugov_cpu, sugov_cpu);
+
+/************************ Governor internals ***********************/
+
+static bool sugov_should_update_freq(struct sugov_policy *sg_policy, u64 time)
+{
+	s64 delta_ns;
+
+	if (sg_policy->work_in_progress)
+		return false;
+
+	if (unlikely(sg_policy->need_freq_update)) {
+		sg_policy->need_freq_update = false;
+		/*
+		 * This happens when limits change, so forget the previous
+		 * next_freq value and force an update.
+		 */
+		sg_policy->next_freq = UINT_MAX;
+		return true;
+	}
+
+	delta_ns = time - sg_policy->last_freq_update_time;
+	return delta_ns >= sg_policy->freq_update_delay_ns;
+}
+
+static void sugov_update_commit(struct sugov_policy *sg_policy, u64 time,
+				unsigned int next_freq)
+{
+	struct cpufreq_policy *policy = sg_policy->policy;
+
+	sg_policy->last_freq_update_time = time;
+
+	if (policy->fast_switch_enabled) {
+		if (sg_policy->next_freq == next_freq) {
+			trace_cpu_frequency(policy->cur, smp_processor_id());
+			return;
+		}
+		sg_policy->next_freq = next_freq;
+		next_freq = cpufreq_driver_fast_switch(policy, next_freq);
+		if (next_freq == CPUFREQ_ENTRY_INVALID)
+			return;
+
+		policy->cur = next_freq;
+		trace_cpu_frequency(next_freq, smp_processor_id());
+	} else if (sg_policy->next_freq != next_freq) {
+		sg_policy->next_freq = next_freq;
+		sg_policy->work_in_progress = true;
+		irq_work_queue(&sg_policy->irq_work);
+	}
+}
+
+/**
+ * get_next_freq - Compute a new frequency for a given cpufreq policy.
+ * @sg_cpu: schedutil cpu object to compute the new frequency for.
+ * @util: Current CPU utilization.
+ * @max: CPU capacity.
+ *
+ * If the utilization is frequency-invariant, choose the new frequency to be
+ * proportional to it, that is
+ *
+ * next_freq = C * max_freq * util / max
+ *
+ * Otherwise, approximate the would-be frequency-invariant utilization by
+ * util_raw * (curr_freq / max_freq) which leads to
+ *
+ * next_freq = C * curr_freq * util_raw / max
+ *
+ * Take C = 1.25 for the frequency tipping point at (util / max) = 0.8.
+ *
+ * The lowest driver-supported frequency which is equal or greater than the raw
+ * next_freq (as calculated above) is returned, subject to policy min/max and
+ * cpufreq driver limitations.
+ */
+static unsigned int get_next_freq(struct sugov_cpu *sg_cpu, unsigned long util,
+				  unsigned long max)
+{
+	struct sugov_policy *sg_policy = sg_cpu->sg_policy;
+	struct cpufreq_policy *policy = sg_policy->policy;
+	unsigned int freq = arch_scale_freq_invariant() ?
+				policy->cpuinfo.max_freq : policy->cur;
+
+	freq = (freq + (freq >> 2)) * util / max;
+
+	if (freq == sg_cpu->cached_raw_freq && sg_policy->next_freq != UINT_MAX)
+		return sg_policy->next_freq;
+	sg_cpu->cached_raw_freq = freq;
+	return cpufreq_driver_resolve_freq(policy, freq);
+}
+
+static void sugov_get_util(unsigned long *util, unsigned long *max)
+{
+	struct rq *rq = this_rq();
+	unsigned long cfs_max;
+
+	cfs_max = arch_scale_cpu_capacity(NULL, smp_processor_id());
+
+	*util = min(rq->cfs.avg.util_avg, cfs_max);
+	*max = cfs_max;
+}
+
+static void sugov_set_iowait_boost(struct sugov_cpu *sg_cpu, u64 time,
+				   unsigned int flags)
+{
+	if (flags & SCHED_CPUFREQ_IOWAIT) {
+		sg_cpu->iowait_boost = sg_cpu->iowait_boost_max;
+	} else if (sg_cpu->iowait_boost) {
+		s64 delta_ns = time - sg_cpu->last_update;
+
+		/* Clear iowait_boost if the CPU apprears to have been idle. */
+		if (delta_ns > TICK_NSEC)
+			sg_cpu->iowait_boost = 0;
+	}
+}
+
+static void sugov_iowait_boost(struct sugov_cpu *sg_cpu, unsigned long *util,
+			       unsigned long *max)
+{
+	unsigned long boost_util = sg_cpu->iowait_boost;
+	unsigned long boost_max = sg_cpu->iowait_boost_max;
+
+	if (!boost_util)
+		return;
+
+	if (*util * boost_max < *max * boost_util) {
+		*util = boost_util;
+		*max = boost_max;
+	}
+	sg_cpu->iowait_boost >>= 1;
+}
+
+static void sugov_update_single(struct update_util_data *hook, u64 time,
+				unsigned int flags)
+{
+	struct sugov_cpu *sg_cpu = container_of(hook, struct sugov_cpu, update_util);
+	struct sugov_policy *sg_policy = sg_cpu->sg_policy;
+	struct cpufreq_policy *policy = sg_policy->policy;
+	unsigned long util, max;
+	unsigned int next_f;
+
+	sugov_set_iowait_boost(sg_cpu, time, flags);
+	sg_cpu->last_update = time;
+
+	if (!sugov_should_update_freq(sg_policy, time))
+		return;
+
+	if (flags & SCHED_CPUFREQ_RT_DL) {
+		next_f = policy->cpuinfo.max_freq;
+	} else {
+		sugov_get_util(&util, &max);
+		sugov_iowait_boost(sg_cpu, &util, &max);
+		next_f = get_next_freq(sg_cpu, util, max);
+	}
+	sugov_update_commit(sg_policy, time, next_f);
+}
+
+static unsigned int sugov_next_freq_shared(struct sugov_cpu *sg_cpu,
+					   unsigned long util, unsigned long max,
+					   unsigned int flags)
+{
+	struct sugov_policy *sg_policy = sg_cpu->sg_policy;
+	struct cpufreq_policy *policy = sg_policy->policy;
+	unsigned int max_f = policy->cpuinfo.max_freq;
+	u64 last_freq_update_time = sg_policy->last_freq_update_time;
+	unsigned int j;
+
+	if (flags & SCHED_CPUFREQ_RT_DL)
+		return max_f;
+
+	sugov_iowait_boost(sg_cpu, &util, &max);
+
+	for_each_cpu(j, policy->cpus) {
+		struct sugov_cpu *j_sg_cpu;
+		unsigned long j_util, j_max;
+		s64 delta_ns;
+
+		if (j == smp_processor_id())
+			continue;
+
+		j_sg_cpu = &per_cpu(sugov_cpu, j);
+		/*
+		 * If the CPU utilization was last updated before the previous
+		 * frequency update and the time elapsed between the last update
+		 * of the CPU utilization and the last frequency update is long
+		 * enough, don't take the CPU into account as it probably is
+		 * idle now (and clear iowait_boost for it).
+		 */
+		delta_ns = last_freq_update_time - j_sg_cpu->last_update;
+		if (delta_ns > TICK_NSEC) {
+			j_sg_cpu->iowait_boost = 0;
+			continue;
+		}
+		if (j_sg_cpu->flags & SCHED_CPUFREQ_RT_DL)
+			return max_f;
+
+		j_util = j_sg_cpu->util;
+		j_max = j_sg_cpu->max;
+		if (j_util * max > j_max * util) {
+			util = j_util;
+			max = j_max;
+		}
+
+		sugov_iowait_boost(j_sg_cpu, &util, &max);
+	}
+
+	return get_next_freq(sg_cpu, util, max);
+}
+
+static void sugov_update_shared(struct update_util_data *hook, u64 time,
+				unsigned int flags)
+{
+	struct sugov_cpu *sg_cpu = container_of(hook, struct sugov_cpu, update_util);
+	struct sugov_policy *sg_policy = sg_cpu->sg_policy;
+	unsigned long util, max;
+	unsigned int next_f;
+
+	sugov_get_util(&util, &max);
+
+	raw_spin_lock(&sg_policy->update_lock);
+
+	sg_cpu->util = util;
+	sg_cpu->max = max;
+	sg_cpu->flags = flags;
+
+	sugov_set_iowait_boost(sg_cpu, time, flags);
+	sg_cpu->last_update = time;
+
+	if (sugov_should_update_freq(sg_policy, time)) {
+		next_f = sugov_next_freq_shared(sg_cpu, util, max, flags);
+		sugov_update_commit(sg_policy, time, next_f);
+	}
+
+	raw_spin_unlock(&sg_policy->update_lock);
+}
+
+static void sugov_work(struct work_struct *work)
+{
+	struct sugov_policy *sg_policy = container_of(work, struct sugov_policy, work);
+
+	mutex_lock(&sg_policy->work_lock);
+	__cpufreq_driver_target(sg_policy->policy, sg_policy->next_freq,
+				CPUFREQ_RELATION_L);
+	mutex_unlock(&sg_policy->work_lock);
+
+	sg_policy->work_in_progress = false;
+}
+
+static void sugov_irq_work(struct irq_work *irq_work)
+{
+	struct sugov_policy *sg_policy;
+
+	sg_policy = container_of(irq_work, struct sugov_policy, irq_work);
+	schedule_work_on(smp_processor_id(), &sg_policy->work);
+}
+
+/************************** sysfs interface ************************/
+
+static struct sugov_tunables *global_tunables;
+static DEFINE_MUTEX(global_tunables_lock);
+
+static inline struct sugov_tunables *to_sugov_tunables(struct gov_attr_set *attr_set)
+{
+	return container_of(attr_set, struct sugov_tunables, attr_set);
+}
+
+static ssize_t rate_limit_us_show(struct gov_attr_set *attr_set, char *buf)
+{
+	struct sugov_tunables *tunables = to_sugov_tunables(attr_set);
+
+	return sprintf(buf, "%u\n", tunables->rate_limit_us);
+}
+
+static ssize_t rate_limit_us_store(struct gov_attr_set *attr_set, const char *buf,
+				   size_t count)
+{
+	struct sugov_tunables *tunables = to_sugov_tunables(attr_set);
+	struct sugov_policy *sg_policy;
+	unsigned int rate_limit_us;
+
+	if (kstrtouint(buf, 10, &rate_limit_us))
+		return -EINVAL;
+
+	tunables->rate_limit_us = rate_limit_us;
+
+	list_for_each_entry(sg_policy, &attr_set->policy_list, tunables_hook)
+		sg_policy->freq_update_delay_ns = rate_limit_us * NSEC_PER_USEC;
+
+	return count;
+}
+
+static struct governor_attr rate_limit_us = __ATTR_RW(rate_limit_us);
+
+static struct attribute *sugov_attributes[] = {
+	&rate_limit_us.attr,
+	NULL
+};
+
+static struct kobj_type sugov_tunables_ktype = {
+	.default_attrs = sugov_attributes,
+	.sysfs_ops = &governor_sysfs_ops,
+};
+
+/********************** cpufreq governor interface *********************/
+
+static struct cpufreq_governor schedutil_gov;
+
+static struct sugov_policy *sugov_policy_alloc(struct cpufreq_policy *policy)
+{
+	struct sugov_policy *sg_policy;
+
+	sg_policy = kzalloc(sizeof(*sg_policy), GFP_KERNEL);
+	if (!sg_policy)
+		return NULL;
+
+	sg_policy->policy = policy;
+	init_irq_work(&sg_policy->irq_work, sugov_irq_work);
+	INIT_WORK(&sg_policy->work, sugov_work);
+	mutex_init(&sg_policy->work_lock);
+	raw_spin_lock_init(&sg_policy->update_lock);
+	return sg_policy;
+}
+
+static void sugov_policy_free(struct sugov_policy *sg_policy)
+{
+	mutex_destroy(&sg_policy->work_lock);
+	kfree(sg_policy);
+}
+
+static struct sugov_tunables *sugov_tunables_alloc(struct sugov_policy *sg_policy)
+{
+	struct sugov_tunables *tunables;
+
+	tunables = kzalloc(sizeof(*tunables), GFP_KERNEL);
+	if (tunables) {
+		gov_attr_set_init(&tunables->attr_set, &sg_policy->tunables_hook);
+		if (!have_governor_per_policy())
+			global_tunables = tunables;
+	}
+	return tunables;
+}
+
+static void sugov_tunables_free(struct sugov_tunables *tunables)
+{
+	if (!have_governor_per_policy())
+		global_tunables = NULL;
+
+	kfree(tunables);
+}
+
+static int sugov_init(struct cpufreq_policy *policy)
+{
+	struct sugov_policy *sg_policy;
+	struct sugov_tunables *tunables;
+	unsigned int lat;
+	int ret = 0;
+
+	/* State should be equivalent to EXIT */
+	if (policy->governor_data)
+		return -EBUSY;
+
+	sg_policy = sugov_policy_alloc(policy);
+	if (!sg_policy)
+		return -ENOMEM;
+
+	mutex_lock(&global_tunables_lock);
+
+	if (global_tunables) {
+		if (WARN_ON(have_governor_per_policy())) {
+			ret = -EINVAL;
+			goto free_sg_policy;
+		}
+		policy->governor_data = sg_policy;
+		sg_policy->tunables = global_tunables;
+
+		gov_attr_set_get(&global_tunables->attr_set, &sg_policy->tunables_hook);
+		goto out;
+	}
+
+	tunables = sugov_tunables_alloc(sg_policy);
+	if (!tunables) {
+		ret = -ENOMEM;
+		goto free_sg_policy;
+	}
+
+	tunables->rate_limit_us = LATENCY_MULTIPLIER;
+	lat = policy->cpuinfo.transition_latency / NSEC_PER_USEC;
+	if (lat)
+		tunables->rate_limit_us *= lat;
+
+	policy->governor_data = sg_policy;
+	sg_policy->tunables = tunables;
+
+	ret = kobject_init_and_add(&tunables->attr_set.kobj, &sugov_tunables_ktype,
+				   get_governor_parent_kobj(policy), "%s",
+				   schedutil_gov.name);
+	if (ret)
+		goto fail;
+
+ out:
+	mutex_unlock(&global_tunables_lock);
+
+	cpufreq_enable_fast_switch(policy);
+	return 0;
+
+ fail:
+	policy->governor_data = NULL;
+	sugov_tunables_free(tunables);
+
+ free_sg_policy:
+	mutex_unlock(&global_tunables_lock);
+
+	sugov_policy_free(sg_policy);
+	pr_err("initialization failed (error %d)\n", ret);
+	return ret;
+}
+
+static void sugov_exit(struct cpufreq_policy *policy)
+{
+	struct sugov_policy *sg_policy = policy->governor_data;
+	struct sugov_tunables *tunables = sg_policy->tunables;
+	unsigned int count;
+
+	cpufreq_disable_fast_switch(policy);
+
+	mutex_lock(&global_tunables_lock);
+
+	count = gov_attr_set_put(&tunables->attr_set, &sg_policy->tunables_hook);
+	policy->governor_data = NULL;
+	if (!count)
+		sugov_tunables_free(tunables);
+
+	mutex_unlock(&global_tunables_lock);
+
+	sugov_policy_free(sg_policy);
+}
+
+static int sugov_start(struct cpufreq_policy *policy)
+{
+	struct sugov_policy *sg_policy = policy->governor_data;
+	unsigned int cpu;
+
+	sg_policy->freq_update_delay_ns = sg_policy->tunables->rate_limit_us * NSEC_PER_USEC;
+	sg_policy->last_freq_update_time = 0;
+	sg_policy->next_freq = UINT_MAX;
+	sg_policy->work_in_progress = false;
+	sg_policy->need_freq_update = false;
+
+	for_each_cpu(cpu, policy->cpus) {
+		struct sugov_cpu *sg_cpu = &per_cpu(sugov_cpu, cpu);
+
+		sg_cpu->sg_policy = sg_policy;
+		if (policy_is_shared(policy)) {
+			sg_cpu->util = 0;
+			sg_cpu->max = 0;
+			sg_cpu->flags = SCHED_CPUFREQ_RT;
+			sg_cpu->last_update = 0;
+			sg_cpu->cached_raw_freq = 0;
+			sg_cpu->iowait_boost = 0;
+			sg_cpu->iowait_boost_max = policy->cpuinfo.max_freq;
+			cpufreq_add_update_util_hook(cpu, &sg_cpu->update_util,
+						     sugov_update_shared);
+		} else {
+			cpufreq_add_update_util_hook(cpu, &sg_cpu->update_util,
+						     sugov_update_single);
+		}
+	}
+	return 0;
+}
+
+static void sugov_stop(struct cpufreq_policy *policy)
+{
+	struct sugov_policy *sg_policy = policy->governor_data;
+	unsigned int cpu;
+
+	for_each_cpu(cpu, policy->cpus)
+		cpufreq_remove_update_util_hook(cpu);
+
+	synchronize_sched();
+
+	irq_work_sync(&sg_policy->irq_work);
+	cancel_work_sync(&sg_policy->work);
+}
+
+static void sugov_limits(struct cpufreq_policy *policy)
+{
+	struct sugov_policy *sg_policy = policy->governor_data;
+
+	if (!policy->fast_switch_enabled) {
+		mutex_lock(&sg_policy->work_lock);
+		cpufreq_policy_apply_limits(policy);
+		mutex_unlock(&sg_policy->work_lock);
+	}
+
+	sg_policy->need_freq_update = true;
+}
+
+static struct cpufreq_governor schedutil_gov = {
+	.name = "schedutil",
+	.owner = THIS_MODULE,
+	.init = sugov_init,
+	.exit = sugov_exit,
+	.start = sugov_start,
+	.stop = sugov_stop,
+	.limits = sugov_limits,
+};
+
+#ifdef CONFIG_CPU_FREQ_DEFAULT_GOV_SCHEDUTIL
+struct cpufreq_governor *cpufreq_default_governor(void)
+{
+	return &schedutil_gov;
+}
+#endif
+
+static int __init sugov_register(void)
+{
+	return cpufreq_register_governor(&schedutil_gov);
+}
+fs_initcall(sugov_register);
diff --git a/kernel/stacktrace.c b/kernel/stacktrace.c
index b6e4c16..9c15a91 100644
--- a/kernel/stacktrace.c
+++ b/kernel/stacktrace.c
@@ -18,10 +18,8 @@
 	if (WARN_ON(!trace->entries))
 		return;
 
-	for (i = 0; i < trace->nr_entries; i++) {
-		printk("%*c", 1 + spaces, ' ');
-		print_ip_sym(trace->entries[i]);
-	}
+	for (i = 0; i < trace->nr_entries; i++)
+		printk("%*c%pS\n", 1 + spaces, ' ', (void *)trace->entries[i]);
 }
 EXPORT_SYMBOL_GPL(print_stack_trace);
 
@@ -29,7 +27,6 @@
 			struct stack_trace *trace, int spaces)
 {
 	int i;
-	unsigned long ip;
 	int generated;
 	int total = 0;
 
@@ -37,9 +34,8 @@
 		return 0;
 
 	for (i = 0; i < trace->nr_entries; i++) {
-		ip = trace->entries[i];
-		generated = snprintf(buf, size, "%*c[<%p>] %pS\n",
-				1 + spaces, ' ', (void *) ip, (void *) ip);
+		generated = snprintf(buf, size, "%*c%pS\n", 1 + spaces, ' ',
+				     (void *)trace->entries[i]);
 
 		total += generated;
 
diff --git a/kernel/time/clocksource.c b/kernel/time/clocksource.c
index 7e4fad7..8a6970e 100644
--- a/kernel/time/clocksource.c
+++ b/kernel/time/clocksource.c
@@ -108,7 +108,7 @@
 
 #ifdef CONFIG_CLOCKSOURCE_WATCHDOG
 static void clocksource_watchdog_work(struct work_struct *work);
-static void clocksource_select(void);
+static void clocksource_select(bool force);
 
 static LIST_HEAD(watchdog_list);
 static struct clocksource *watchdog;
@@ -415,7 +415,7 @@
 {
 	mutex_lock(&clocksource_mutex);
 	if (__clocksource_watchdog_kthread())
-		clocksource_select();
+		clocksource_select(false);
 	mutex_unlock(&clocksource_mutex);
 	return 0;
 }
@@ -555,11 +555,12 @@
 
 #ifndef CONFIG_ARCH_USES_GETTIMEOFFSET
 
-static struct clocksource *clocksource_find_best(bool oneshot, bool skipcur)
+static struct clocksource *clocksource_find_best(bool oneshot, bool skipcur,
+						bool force)
 {
 	struct clocksource *cs;
 
-	if (!finished_booting || list_empty(&clocksource_list))
+	if ((!finished_booting && !force) || list_empty(&clocksource_list))
 		return NULL;
 
 	/*
@@ -577,13 +578,13 @@
 	return NULL;
 }
 
-static void __clocksource_select(bool skipcur)
+static void __clocksource_select(bool skipcur, bool force)
 {
 	bool oneshot = tick_oneshot_mode_active();
 	struct clocksource *best, *cs;
 
 	/* Find the best suitable clocksource */
-	best = clocksource_find_best(oneshot, skipcur);
+	best = clocksource_find_best(oneshot, skipcur, force);
 	if (!best)
 		return;
 
@@ -632,22 +633,40 @@
  * Select the clocksource with the best rating, or the clocksource,
  * which is selected by userspace override.
  */
-static void clocksource_select(void)
+static void clocksource_select(bool force)
 {
-	__clocksource_select(false);
+	return __clocksource_select(false, force);
 }
 
 static void clocksource_select_fallback(void)
 {
-	__clocksource_select(true);
+	__clocksource_select(true, false);
 }
 
 #else /* !CONFIG_ARCH_USES_GETTIMEOFFSET */
-static inline void clocksource_select(void) { }
+
+static inline void clocksource_select(bool force) { }
 static inline void clocksource_select_fallback(void) { }
 
 #endif
 
+/**
+ * clocksource_select_force - Force re-selection of the best clocksource
+ *				among registered clocksources
+ *
+ * clocksource_select() can't select the best clocksource before
+ * calling clocksource_done_booting() and since clocksource_select()
+ * should be called with clocksource_mutex held, provide a new API
+ * can be called from other files to select best clockrouce irrespective
+ * of finished_booting flag.
+ */
+void clocksource_select_force(void)
+{
+	mutex_lock(&clocksource_mutex);
+	clocksource_select(true);
+	mutex_unlock(&clocksource_mutex);
+}
+
 /*
  * clocksource_done_booting - Called near the end of core bootup
  *
@@ -664,7 +683,7 @@
 	 * Run the watchdog first to eliminate unstable clock sources
 	 */
 	__clocksource_watchdog_kthread();
-	clocksource_select();
+	clocksource_select(false);
 	mutex_unlock(&clocksource_mutex);
 	return 0;
 }
@@ -755,6 +774,7 @@
 }
 EXPORT_SYMBOL_GPL(__clocksource_update_freq_scale);
 
+
 /**
  * __clocksource_register_scale - Used to install new clocksources
  * @cs:		clocksource to be registered
@@ -776,7 +796,7 @@
 	mutex_lock(&clocksource_mutex);
 	clocksource_enqueue(cs);
 	clocksource_enqueue_watchdog(cs);
-	clocksource_select();
+	clocksource_select(false);
 	clocksource_select_watchdog(false);
 	mutex_unlock(&clocksource_mutex);
 	return 0;
@@ -799,7 +819,7 @@
 {
 	mutex_lock(&clocksource_mutex);
 	__clocksource_change_rating(cs, rating);
-	clocksource_select();
+	clocksource_select(false);
 	clocksource_select_watchdog(false);
 	mutex_unlock(&clocksource_mutex);
 }
@@ -903,7 +923,7 @@
 
 	ret = sysfs_get_uname(buf, override_name, count);
 	if (ret >= 0)
-		clocksource_select();
+		clocksource_select(false);
 
 	mutex_unlock(&clocksource_mutex);
 
diff --git a/kernel/time/timekeeping_debug.c b/kernel/time/timekeeping_debug.c
index ca9fb80..38bc4d2 100644
--- a/kernel/time/timekeeping_debug.c
+++ b/kernel/time/timekeeping_debug.c
@@ -75,7 +75,7 @@
 	int bin = min(fls(t->tv_sec), NUM_BINS-1);
 
 	sleep_time_bin[bin]++;
-	pr_info("Suspended for %lld.%03lu seconds\n", (s64)t->tv_sec,
-			t->tv_nsec / NSEC_PER_MSEC);
+	printk_deferred(KERN_INFO "Suspended for %lld.%03lu seconds\n",
+			(s64)t->tv_sec, t->tv_nsec / NSEC_PER_MSEC);
 }
 
diff --git a/kernel/time/timer.c b/kernel/time/timer.c
index f605186..400920e 100644
--- a/kernel/time/timer.c
+++ b/kernel/time/timer.c
@@ -206,6 +206,7 @@
 } ____cacheline_aligned;
 
 static DEFINE_PER_CPU(struct timer_base, timer_bases[NR_BASES]);
+struct timer_base timer_base_deferrable;
 
 #if defined(CONFIG_SMP) && defined(CONFIG_NO_HZ_COMMON)
 unsigned int sysctl_timer_migration = 1;
@@ -229,6 +230,9 @@
 		per_cpu(timer_bases[BASE_DEF].nohz_active, cpu) = true;
 		per_cpu(hrtimer_bases.nohz_active, cpu) = true;
 	}
+
+	timer_base_deferrable.migration_enabled = on;
+	timer_base_deferrable.nohz_active = true;
 }
 
 int timer_migration_handler(struct ctl_table *table, int write,
@@ -852,8 +856,11 @@
 	 * the deferrable base.
 	 */
 	if (IS_ENABLED(CONFIG_NO_HZ_COMMON) && base->nohz_active &&
-	    (tflags & TIMER_DEFERRABLE))
-		base = per_cpu_ptr(&timer_bases[BASE_DEF], cpu);
+	    (tflags & TIMER_DEFERRABLE)) {
+		base = &timer_base_deferrable;
+		if (tflags & TIMER_PINNED)
+			base = per_cpu_ptr(&timer_bases[BASE_DEF], cpu);
+	}
 	return base;
 }
 
@@ -867,7 +874,9 @@
 	 */
 	if (IS_ENABLED(CONFIG_NO_HZ_COMMON) && base->nohz_active &&
 	    (tflags & TIMER_DEFERRABLE))
-		base = this_cpu_ptr(&timer_bases[BASE_DEF]);
+		base = &timer_base_deferrable;
+		if (tflags & TIMER_PINNED)
+			base = this_cpu_ptr(&timer_bases[BASE_DEF]);
 	return base;
 }
 
@@ -1652,8 +1661,10 @@
 	struct timer_base *base = this_cpu_ptr(&timer_bases[BASE_STD]);
 
 	__run_timers(base);
-	if (IS_ENABLED(CONFIG_NO_HZ_COMMON) && base->nohz_active)
+	if (IS_ENABLED(CONFIG_NO_HZ_COMMON) && base->nohz_active) {
+		__run_timers(&timer_base_deferrable);
 		__run_timers(this_cpu_ptr(&timer_bases[BASE_DEF]));
+	}
 }
 
 /*
diff --git a/kernel/watchdog.c b/kernel/watchdog.c
index bf9885e..44ae68a 100644
--- a/kernel/watchdog.c
+++ b/kernel/watchdog.c
@@ -27,6 +27,7 @@
 #include <linux/kvm_para.h>
 #include <linux/perf_event.h>
 #include <linux/kthread.h>
+#include <soc/qcom/watchdog.h>
 
 /*
  * The run state of the lockup detectors is controlled by the content of the
@@ -364,8 +365,11 @@
 		if (per_cpu(hard_watchdog_warn, next_cpu) == true)
 			return;
 
-		if (hardlockup_panic)
-			panic("Watchdog detected hard LOCKUP on cpu %u", next_cpu);
+		if (hardlockup_panic) {
+			pr_err("Watchdog detected hard LOCKUP on cpu %u",
+					next_cpu);
+			msm_trigger_wdog_bite();
+		}
 		else
 			WARN(1, "Watchdog detected hard LOCKUP on cpu %u", next_cpu);
 
@@ -427,6 +431,9 @@
 			return;
 
 		pr_emerg("Watchdog detected hard LOCKUP on cpu %d", this_cpu);
+		if (hardlockup_panic)
+			msm_trigger_wdog_bite();
+
 		print_modules();
 		print_irqtrace_events(current);
 		if (regs)
@@ -549,6 +556,9 @@
 		pr_emerg("BUG: soft lockup - CPU#%d stuck for %us! [%s:%d]\n",
 			smp_processor_id(), duration,
 			current->comm, task_pid_nr(current));
+
+		if (softlockup_panic)
+			msm_trigger_wdog_bite();
 		__this_cpu_write(softlockup_task_ptr_saved, current);
 		print_modules();
 		print_irqtrace_events(current);
diff --git a/mm/memblock.c b/mm/memblock.c
index 166f17a..49b7c1e 100644
--- a/mm/memblock.c
+++ b/mm/memblock.c
@@ -1641,11 +1641,12 @@
 		 memblock.memory.regions[idx].size) >= end;
 }
 
-int __init_memblock memblock_overlaps_memory(phys_addr_t base, phys_addr_t size)
+bool __init_memblock memblock_overlaps_memory(phys_addr_t base,
+					      phys_addr_t size)
 {
 	memblock_cap_size(base, &size);
 
-	return memblock_overlaps_region(&memblock.memory, base, size) >= 0;
+	return memblock_overlaps_region(&memblock.memory, base, size);
 }
 
 /**
diff --git a/mm/slub.c b/mm/slub.c
index 2b3e740..7aa0e97 100644
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -1419,6 +1419,10 @@
 	int err;
 	unsigned long i, count = oo_objects(s->oo);
 
+	/* Bailout if already initialised */
+	if (s->random_seq)
+		return 0;
+
 	err = cache_random_seq_create(s, count, GFP_KERNEL);
 	if (err) {
 		pr_err("SLUB: Unable to initialize free list for %s\n",
diff --git a/net/can/af_can.c b/net/can/af_can.c
index 1108079..5488e4a 100644
--- a/net/can/af_can.c
+++ b/net/can/af_can.c
@@ -445,6 +445,7 @@
  * @func: callback function on filter match
  * @data: returned parameter for callback function
  * @ident: string for calling module identification
+ * @sk: socket pointer (might be NULL)
  *
  * Description:
  *  Invokes the callback function with the received sk_buff and the given
@@ -468,7 +469,7 @@
  */
 int can_rx_register(struct net_device *dev, canid_t can_id, canid_t mask,
 		    void (*func)(struct sk_buff *, void *), void *data,
-		    char *ident)
+		    char *ident, struct sock *sk)
 {
 	struct receiver *r;
 	struct hlist_head *rl;
@@ -496,6 +497,7 @@
 		r->func    = func;
 		r->data    = data;
 		r->ident   = ident;
+		r->sk      = sk;
 
 		hlist_add_head_rcu(&r->list, rl);
 		d->entries++;
@@ -520,8 +522,11 @@
 static void can_rx_delete_receiver(struct rcu_head *rp)
 {
 	struct receiver *r = container_of(rp, struct receiver, rcu);
+	struct sock *sk = r->sk;
 
 	kmem_cache_free(rcv_cache, r);
+	if (sk)
+		sock_put(sk);
 }
 
 /**
@@ -596,8 +601,11 @@
 	spin_unlock(&can_rcvlists_lock);
 
 	/* schedule the receiver item for deletion */
-	if (r)
+	if (r) {
+		if (r->sk)
+			sock_hold(r->sk);
 		call_rcu(&r->rcu, can_rx_delete_receiver);
+	}
 }
 EXPORT_SYMBOL(can_rx_unregister);
 
diff --git a/net/can/af_can.h b/net/can/af_can.h
index fca0fe9..b86f512 100644
--- a/net/can/af_can.h
+++ b/net/can/af_can.h
@@ -50,13 +50,14 @@
 
 struct receiver {
 	struct hlist_node list;
-	struct rcu_head rcu;
 	canid_t can_id;
 	canid_t mask;
 	unsigned long matches;
 	void (*func)(struct sk_buff *, void *);
 	void *data;
 	char *ident;
+	struct sock *sk;
+	struct rcu_head rcu;
 };
 
 #define CAN_SFF_RCV_ARRAY_SZ (1 << CAN_SFF_ID_BITS)
diff --git a/net/can/bcm.c b/net/can/bcm.c
index 5e9ed5e..e4f694d 100644
--- a/net/can/bcm.c
+++ b/net/can/bcm.c
@@ -1225,7 +1225,7 @@
 				err = can_rx_register(dev, op->can_id,
 						      REGMASK(op->can_id),
 						      bcm_rx_handler, op,
-						      "bcm");
+						      "bcm", sk);
 
 				op->rx_reg_dev = dev;
 				dev_put(dev);
@@ -1234,7 +1234,7 @@
 		} else
 			err = can_rx_register(NULL, op->can_id,
 					      REGMASK(op->can_id),
-					      bcm_rx_handler, op, "bcm");
+					      bcm_rx_handler, op, "bcm", sk);
 		if (err) {
 			/* this bcm rx op is broken -> remove it */
 			list_del(&op->list);
diff --git a/net/can/gw.c b/net/can/gw.c
index 4551687..77c8af4 100644
--- a/net/can/gw.c
+++ b/net/can/gw.c
@@ -442,7 +442,7 @@
 {
 	return can_rx_register(gwj->src.dev, gwj->ccgw.filter.can_id,
 			       gwj->ccgw.filter.can_mask, can_can_gw_rcv,
-			       gwj, "gw");
+			       gwj, "gw", NULL);
 }
 
 static inline void cgw_unregister_filter(struct cgw_job *gwj)
diff --git a/net/can/raw.c b/net/can/raw.c
index b075f02..6dc546a 100644
--- a/net/can/raw.c
+++ b/net/can/raw.c
@@ -190,7 +190,7 @@
 	for (i = 0; i < count; i++) {
 		err = can_rx_register(dev, filter[i].can_id,
 				      filter[i].can_mask,
-				      raw_rcv, sk, "raw");
+				      raw_rcv, sk, "raw", sk);
 		if (err) {
 			/* clean up successfully registered filters */
 			while (--i >= 0)
@@ -211,7 +211,7 @@
 
 	if (err_mask)
 		err = can_rx_register(dev, 0, err_mask | CAN_ERR_FLAG,
-				      raw_rcv, sk, "raw");
+				      raw_rcv, sk, "raw", sk);
 
 	return err;
 }
diff --git a/net/core/dev.c b/net/core/dev.c
index ab6dc94..555ed4b 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -1696,24 +1696,19 @@
 
 static struct static_key netstamp_needed __read_mostly;
 #ifdef HAVE_JUMP_LABEL
-/* We are not allowed to call static_key_slow_dec() from irq context
- * If net_disable_timestamp() is called from irq context, defer the
- * static_key_slow_dec() calls.
- */
 static atomic_t netstamp_needed_deferred;
+static void netstamp_clear(struct work_struct *work)
+{
+	int deferred = atomic_xchg(&netstamp_needed_deferred, 0);
+
+	while (deferred--)
+		static_key_slow_dec(&netstamp_needed);
+}
+static DECLARE_WORK(netstamp_work, netstamp_clear);
 #endif
 
 void net_enable_timestamp(void)
 {
-#ifdef HAVE_JUMP_LABEL
-	int deferred = atomic_xchg(&netstamp_needed_deferred, 0);
-
-	if (deferred) {
-		while (--deferred)
-			static_key_slow_dec(&netstamp_needed);
-		return;
-	}
-#endif
 	static_key_slow_inc(&netstamp_needed);
 }
 EXPORT_SYMBOL(net_enable_timestamp);
@@ -1721,12 +1716,12 @@
 void net_disable_timestamp(void)
 {
 #ifdef HAVE_JUMP_LABEL
-	if (in_interrupt()) {
-		atomic_inc(&netstamp_needed_deferred);
-		return;
-	}
-#endif
+	/* net_disable_timestamp() can be called from non process context */
+	atomic_inc(&netstamp_needed_deferred);
+	schedule_work(&netstamp_work);
+#else
 	static_key_slow_dec(&netstamp_needed);
+#endif
 }
 EXPORT_SYMBOL(net_disable_timestamp);
 
diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c
index 715e5d1..7506c03 100644
--- a/net/dccp/ipv6.c
+++ b/net/dccp/ipv6.c
@@ -227,7 +227,7 @@
 		opt = ireq->ipv6_opt;
 		if (!opt)
 			opt = rcu_dereference(np->opt);
-		err = ip6_xmit(sk, skb, &fl6, opt, np->tclass);
+		err = ip6_xmit(sk, skb, &fl6, sk->sk_mark, opt, np->tclass);
 		rcu_read_unlock();
 		err = net_xmit_eval(err);
 	}
@@ -281,7 +281,7 @@
 	dst = ip6_dst_lookup_flow(ctl_sk, &fl6, NULL);
 	if (!IS_ERR(dst)) {
 		skb_dst_set(skb, dst);
-		ip6_xmit(ctl_sk, skb, &fl6, NULL, 0);
+		ip6_xmit(ctl_sk, skb, &fl6, 0, NULL, 0);
 		DCCP_INC_STATS(DCCP_MIB_OUTSEGS);
 		DCCP_INC_STATS(DCCP_MIB_OUTRSTS);
 		return;
diff --git a/net/dsa/dsa2.c b/net/dsa/dsa2.c
index da38621..0f99297 100644
--- a/net/dsa/dsa2.c
+++ b/net/dsa/dsa2.c
@@ -273,6 +273,7 @@
 	if (err) {
 		dev_warn(ds->dev, "Failed to create slave %d: %d\n",
 			 index, err);
+		ds->ports[index].netdev = NULL;
 		return err;
 	}
 
diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c
index 02acfff..24d7aff 100644
--- a/net/ethernet/eth.c
+++ b/net/ethernet/eth.c
@@ -356,6 +356,7 @@
 	dev->header_ops		= &eth_header_ops;
 	dev->type		= ARPHRD_ETHER;
 	dev->hard_header_len 	= ETH_HLEN;
+	dev->min_header_len	= ETH_HLEN;
 	dev->mtu		= ETH_DATA_LEN;
 	dev->addr_len		= ETH_ALEN;
 	dev->tx_queue_len	= 1000;	/* Ethernet wants good queues */
diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c
index 72d6f05..ae20616 100644
--- a/net/ipv4/cipso_ipv4.c
+++ b/net/ipv4/cipso_ipv4.c
@@ -1587,6 +1587,10 @@
 				goto validate_return_locked;
 			}
 
+		if (opt_iter + 1 == opt_len) {
+			err_offset = opt_iter;
+			goto validate_return_locked;
+		}
 		tag_len = tag[1];
 		if (tag_len > (opt_len - opt_iter)) {
 			err_offset = opt_iter + 1;
diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c
index 32a08bc..1bc623d 100644
--- a/net/ipv4/igmp.c
+++ b/net/ipv4/igmp.c
@@ -1172,6 +1172,7 @@
 				psf->sf_crcount = im->crcount;
 		}
 		in_dev_put(pmc->interface);
+		kfree(pmc);
 	}
 	spin_unlock_bh(&im->lock);
 }
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
index d24fa20..0bd3efe 100644
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@ -1607,6 +1607,7 @@
 	sk->sk_protocol = ip_hdr(skb)->protocol;
 	sk->sk_bound_dev_if = arg->bound_dev_if;
 	sk->sk_sndbuf = sysctl_wmem_default;
+	sk->sk_mark = fl4.flowi4_mark;
 	err = ip_append_data(sk, &fl4, ip_reply_glue_bits, arg->iov->iov_base,
 			     len, 0, &ipc, &rt, MSG_DONTWAIT);
 	if (unlikely(err)) {
diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c
index f226f408..65336f3 100644
--- a/net/ipv4/ip_sockglue.c
+++ b/net/ipv4/ip_sockglue.c
@@ -1215,7 +1215,14 @@
 		pktinfo->ipi_ifindex = 0;
 		pktinfo->ipi_spec_dst.s_addr = 0;
 	}
-	skb_dst_drop(skb);
+	/* We need to keep the dst for __ip_options_echo()
+	 * We could restrict the test to opt.ts_needtime || opt.srr,
+	 * but the following is good enough as IP options are not often used.
+	 */
+	if (unlikely(IPCB(skb)->opt.optlen))
+		skb_dst_force(skb);
+	else
+		skb_dst_drop(skb);
 }
 
 int ip_setsockopt(struct sock *sk, int level,
diff --git a/net/ipv4/ping.c b/net/ipv4/ping.c
index 5b2635e..06879e6 100644
--- a/net/ipv4/ping.c
+++ b/net/ipv4/ping.c
@@ -642,6 +642,8 @@
 {
 	struct sk_buff *skb = skb_peek(&sk->sk_write_queue);
 
+	if (!skb)
+		return 0;
 	pfh->wcheck = csum_partial((char *)&pfh->icmph,
 		sizeof(struct icmphdr), pfh->wcheck);
 	pfh->icmph.checksum = csum_fold(pfh->wcheck);
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 814af89..6a90a0e 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -772,6 +772,12 @@
 				ret = -EAGAIN;
 				break;
 			}
+			/* if __tcp_splice_read() got nothing while we have
+			 * an skb in receive queue, we do not want to loop.
+			 * This might happen with URG data.
+			 */
+			if (!skb_queue_empty(&sk->sk_receive_queue))
+				break;
 			sk_wait_data(sk, &timeo, NULL);
 			if (signal_pending(current)) {
 				ret = sock_intr_errno(timeo);
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index cd8e189..0e7c05b 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -2436,9 +2436,11 @@
 	int full_space = min_t(int, tp->window_clamp, allowed_space);
 	int window;
 
-	if (mss > full_space)
+	if (unlikely(mss > full_space)) {
 		mss = full_space;
-
+		if (mss <= 0)
+			return 0;
+	}
 	if (free_space < (full_space >> 1)) {
 		icsk->icsk_ack.quick = 0;
 
diff --git a/net/ipv6/inet6_connection_sock.c b/net/ipv6/inet6_connection_sock.c
index 1c86c47..10d1deb 100644
--- a/net/ipv6/inet6_connection_sock.c
+++ b/net/ipv6/inet6_connection_sock.c
@@ -175,7 +175,7 @@
 	/* Restore final destination back after routing done */
 	fl6.daddr = sk->sk_v6_daddr;
 
-	res = ip6_xmit(sk, skb, &fl6, rcu_dereference(np->opt),
+	res = ip6_xmit(sk, skb, &fl6, sk->sk_mark, rcu_dereference(np->opt),
 		       np->tclass);
 	rcu_read_unlock();
 	return res;
diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c
index 710bc79..ffc83d4 100644
--- a/net/ipv6/ip6_gre.c
+++ b/net/ipv6/ip6_gre.c
@@ -367,35 +367,37 @@
 
 
 static void ip6gre_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
-		u8 type, u8 code, int offset, __be32 info)
+		       u8 type, u8 code, int offset, __be32 info)
 {
-	const struct ipv6hdr *ipv6h = (const struct ipv6hdr *)skb->data;
-	__be16 *p = (__be16 *)(skb->data + offset);
-	int grehlen = offset + 4;
+	const struct gre_base_hdr *greh;
+	const struct ipv6hdr *ipv6h;
+	int grehlen = sizeof(*greh);
 	struct ip6_tnl *t;
+	int key_off = 0;
 	__be16 flags;
+	__be32 key;
 
-	flags = p[0];
-	if (flags&(GRE_CSUM|GRE_KEY|GRE_SEQ|GRE_ROUTING|GRE_VERSION)) {
-		if (flags&(GRE_VERSION|GRE_ROUTING))
-			return;
-		if (flags&GRE_KEY) {
-			grehlen += 4;
-			if (flags&GRE_CSUM)
-				grehlen += 4;
-		}
+	if (!pskb_may_pull(skb, offset + grehlen))
+		return;
+	greh = (const struct gre_base_hdr *)(skb->data + offset);
+	flags = greh->flags;
+	if (flags & (GRE_VERSION | GRE_ROUTING))
+		return;
+	if (flags & GRE_CSUM)
+		grehlen += 4;
+	if (flags & GRE_KEY) {
+		key_off = grehlen + offset;
+		grehlen += 4;
 	}
 
-	/* If only 8 bytes returned, keyed message will be dropped here */
-	if (!pskb_may_pull(skb, grehlen))
+	if (!pskb_may_pull(skb, offset + grehlen))
 		return;
 	ipv6h = (const struct ipv6hdr *)skb->data;
-	p = (__be16 *)(skb->data + offset);
+	greh = (const struct gre_base_hdr *)(skb->data + offset);
+	key = key_off ? *(__be32 *)(skb->data + key_off) : 0;
 
 	t = ip6gre_tunnel_lookup(skb->dev, &ipv6h->daddr, &ipv6h->saddr,
-				flags & GRE_KEY ?
-				*(((__be32 *)p) + (grehlen / 4) - 1) : 0,
-				p[1]);
+				 key, greh->protocol);
 	if (!t)
 		return;
 
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 59eb4ed..9a87bfb 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -163,7 +163,7 @@
  * which are using proper atomic operations or spinlocks.
  */
 int ip6_xmit(const struct sock *sk, struct sk_buff *skb, struct flowi6 *fl6,
-	     struct ipv6_txoptions *opt, int tclass)
+	     __u32 mark, struct ipv6_txoptions *opt, int tclass)
 {
 	struct net *net = sock_net(sk);
 	const struct ipv6_pinfo *np = inet6_sk(sk);
@@ -230,7 +230,7 @@
 
 	skb->protocol = htons(ETH_P_IPV6);
 	skb->priority = sk->sk_priority;
-	skb->mark = sk->sk_mark;
+	skb->mark = mark;
 
 	mtu = dst_mtu(dst);
 	if ((skb->len <= mtu) || skb->ignore_df || skb_is_gso(skb)) {
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
index c1f497b..885b411 100644
--- a/net/ipv6/ip6_tunnel.c
+++ b/net/ipv6/ip6_tunnel.c
@@ -400,18 +400,19 @@
 
 __u16 ip6_tnl_parse_tlv_enc_lim(struct sk_buff *skb, __u8 *raw)
 {
-	const struct ipv6hdr *ipv6h = (const struct ipv6hdr *) raw;
-	__u8 nexthdr = ipv6h->nexthdr;
-	__u16 off = sizeof(*ipv6h);
+	const struct ipv6hdr *ipv6h = (const struct ipv6hdr *)raw;
+	unsigned int nhoff = raw - skb->data;
+	unsigned int off = nhoff + sizeof(*ipv6h);
+	u8 next, nexthdr = ipv6h->nexthdr;
 
 	while (ipv6_ext_hdr(nexthdr) && nexthdr != NEXTHDR_NONE) {
-		__u16 optlen = 0;
 		struct ipv6_opt_hdr *hdr;
-		if (raw + off + sizeof(*hdr) > skb->data &&
-		    !pskb_may_pull(skb, raw - skb->data + off + sizeof (*hdr)))
+		u16 optlen;
+
+		if (!pskb_may_pull(skb, off + sizeof(*hdr)))
 			break;
 
-		hdr = (struct ipv6_opt_hdr *) (raw + off);
+		hdr = (struct ipv6_opt_hdr *)(skb->data + off);
 		if (nexthdr == NEXTHDR_FRAGMENT) {
 			struct frag_hdr *frag_hdr = (struct frag_hdr *) hdr;
 			if (frag_hdr->frag_off)
@@ -422,20 +423,29 @@
 		} else {
 			optlen = ipv6_optlen(hdr);
 		}
+		/* cache hdr->nexthdr, since pskb_may_pull() might
+		 * invalidate hdr
+		 */
+		next = hdr->nexthdr;
 		if (nexthdr == NEXTHDR_DEST) {
-			__u16 i = off + 2;
+			u16 i = 2;
+
+			/* Remember : hdr is no longer valid at this point. */
+			if (!pskb_may_pull(skb, off + optlen))
+				break;
+
 			while (1) {
 				struct ipv6_tlv_tnl_enc_lim *tel;
 
 				/* No more room for encapsulation limit */
-				if (i + sizeof (*tel) > off + optlen)
+				if (i + sizeof(*tel) > optlen)
 					break;
 
-				tel = (struct ipv6_tlv_tnl_enc_lim *) &raw[i];
+				tel = (struct ipv6_tlv_tnl_enc_lim *)(skb->data + off + i);
 				/* return index of option if found and valid */
 				if (tel->type == IPV6_TLV_TNL_ENCAP_LIMIT &&
 				    tel->length == 1)
-					return i;
+					return i + off - nhoff;
 				/* else jump to next option */
 				if (tel->type)
 					i += tel->length + 2;
@@ -443,7 +453,7 @@
 					i++;
 			}
 		}
-		nexthdr = hdr->nexthdr;
+		nexthdr = next;
 		off += optlen;
 	}
 	return 0;
diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c
index 14a3903..1bdc703 100644
--- a/net/ipv6/mcast.c
+++ b/net/ipv6/mcast.c
@@ -81,7 +81,7 @@
 static void mld_ifc_timer_expire(unsigned long data);
 static void mld_ifc_event(struct inet6_dev *idev);
 static void mld_add_delrec(struct inet6_dev *idev, struct ifmcaddr6 *pmc);
-static void mld_del_delrec(struct inet6_dev *idev, const struct in6_addr *addr);
+static void mld_del_delrec(struct inet6_dev *idev, struct ifmcaddr6 *pmc);
 static void mld_clear_delrec(struct inet6_dev *idev);
 static bool mld_in_v1_mode(const struct inet6_dev *idev);
 static int sf_setstate(struct ifmcaddr6 *pmc);
@@ -692,9 +692,9 @@
 			dev_mc_del(dev, buf);
 	}
 
-	if (mc->mca_flags & MAF_NOREPORT)
-		goto done;
 	spin_unlock_bh(&mc->mca_lock);
+	if (mc->mca_flags & MAF_NOREPORT)
+		return;
 
 	if (!mc->idev->dead)
 		igmp6_leave_group(mc);
@@ -702,8 +702,6 @@
 	spin_lock_bh(&mc->mca_lock);
 	if (del_timer(&mc->mca_timer))
 		atomic_dec(&mc->mca_refcnt);
-done:
-	ip6_mc_clear_src(mc);
 	spin_unlock_bh(&mc->mca_lock);
 }
 
@@ -748,10 +746,11 @@
 	spin_unlock_bh(&idev->mc_lock);
 }
 
-static void mld_del_delrec(struct inet6_dev *idev, const struct in6_addr *pmca)
+static void mld_del_delrec(struct inet6_dev *idev, struct ifmcaddr6 *im)
 {
 	struct ifmcaddr6 *pmc, *pmc_prev;
-	struct ip6_sf_list *psf, *psf_next;
+	struct ip6_sf_list *psf;
+	struct in6_addr *pmca = &im->mca_addr;
 
 	spin_lock_bh(&idev->mc_lock);
 	pmc_prev = NULL;
@@ -768,14 +767,21 @@
 	}
 	spin_unlock_bh(&idev->mc_lock);
 
+	spin_lock_bh(&im->mca_lock);
 	if (pmc) {
-		for (psf = pmc->mca_tomb; psf; psf = psf_next) {
-			psf_next = psf->sf_next;
-			kfree(psf);
+		im->idev = pmc->idev;
+		im->mca_crcount = idev->mc_qrv;
+		im->mca_sfmode = pmc->mca_sfmode;
+		if (pmc->mca_sfmode == MCAST_INCLUDE) {
+			im->mca_tomb = pmc->mca_tomb;
+			im->mca_sources = pmc->mca_sources;
+			for (psf = im->mca_sources; psf; psf = psf->sf_next)
+				psf->sf_crcount = im->mca_crcount;
 		}
 		in6_dev_put(pmc->idev);
 		kfree(pmc);
 	}
+	spin_unlock_bh(&im->mca_lock);
 }
 
 static void mld_clear_delrec(struct inet6_dev *idev)
@@ -904,7 +910,7 @@
 	mca_get(mc);
 	write_unlock_bh(&idev->lock);
 
-	mld_del_delrec(idev, &mc->mca_addr);
+	mld_del_delrec(idev, mc);
 	igmp6_group_added(mc);
 	ma_put(mc);
 	return 0;
@@ -927,6 +933,7 @@
 				write_unlock_bh(&idev->lock);
 
 				igmp6_group_dropped(ma);
+				ip6_mc_clear_src(ma);
 
 				ma_put(ma);
 				return 0;
@@ -2501,15 +2508,17 @@
 	/* Withdraw multicast list */
 
 	read_lock_bh(&idev->lock);
-	mld_ifc_stop_timer(idev);
-	mld_gq_stop_timer(idev);
-	mld_dad_stop_timer(idev);
 
 	for (i = idev->mc_list; i; i = i->next)
 		igmp6_group_dropped(i);
-	read_unlock_bh(&idev->lock);
 
-	mld_clear_delrec(idev);
+	/* Should stop timer after group drop. or we will
+	 * start timer again in mld_ifc_event()
+	 */
+	mld_ifc_stop_timer(idev);
+	mld_gq_stop_timer(idev);
+	mld_dad_stop_timer(idev);
+	read_unlock_bh(&idev->lock);
 }
 
 static void ipv6_mc_reset(struct inet6_dev *idev)
@@ -2531,8 +2540,10 @@
 
 	read_lock_bh(&idev->lock);
 	ipv6_mc_reset(idev);
-	for (i = idev->mc_list; i; i = i->next)
+	for (i = idev->mc_list; i; i = i->next) {
+		mld_del_delrec(idev, i);
 		igmp6_group_added(i);
+	}
 	read_unlock_bh(&idev->lock);
 }
 
@@ -2565,6 +2576,7 @@
 
 	/* Deactivate timers */
 	ipv6_mc_down(idev);
+	mld_clear_delrec(idev);
 
 	/* Delete all-nodes address. */
 	/* We cannot call ipv6_dev_mc_dec() directly, our caller in
@@ -2579,11 +2591,9 @@
 	write_lock_bh(&idev->lock);
 	while ((i = idev->mc_list) != NULL) {
 		idev->mc_list = i->next;
+
 		write_unlock_bh(&idev->lock);
-
-		igmp6_group_dropped(i);
 		ma_put(i);
-
 		write_lock_bh(&idev->lock);
 	}
 	write_unlock_bh(&idev->lock);
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c
index b1cdf80..40d7405 100644
--- a/net/ipv6/sit.c
+++ b/net/ipv6/sit.c
@@ -1390,6 +1390,7 @@
 	err = dst_cache_init(&tunnel->dst_cache, GFP_KERNEL);
 	if (err) {
 		free_percpu(dev->tstats);
+		dev->tstats = NULL;
 		return err;
 	}
 
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index 28ec0a2..37c4b38 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -468,7 +468,7 @@
 		opt = ireq->ipv6_opt;
 		if (!opt)
 			opt = rcu_dereference(np->opt);
-		err = ip6_xmit(sk, skb, fl6, opt, np->tclass);
+		err = ip6_xmit(sk, skb, fl6, sk->sk_mark, opt, np->tclass);
 		rcu_read_unlock();
 		err = net_xmit_eval(err);
 	}
@@ -839,7 +839,7 @@
 	dst = ip6_dst_lookup_flow(ctl_sk, &fl6, NULL);
 	if (!IS_ERR(dst)) {
 		skb_dst_set(buff, dst);
-		ip6_xmit(ctl_sk, buff, &fl6, NULL, tclass);
+		ip6_xmit(ctl_sk, buff, &fl6, fl6.flowi6_mark, NULL, tclass);
 		TCP_INC_STATS(net, TCP_MIB_OUTSEGS);
 		if (rst)
 			TCP_INC_STATS(net, TCP_MIB_OUTRSTS);
@@ -989,6 +989,16 @@
 	return 0; /* don't send reset */
 }
 
+static void tcp_v6_restore_cb(struct sk_buff *skb)
+{
+	/* We need to move header back to the beginning if xfrm6_policy_check()
+	 * and tcp_v6_fill_cb() are going to be called again.
+	 * ip6_datagram_recv_specific_ctl() also expects IP6CB to be there.
+	 */
+	memmove(IP6CB(skb), &TCP_SKB_CB(skb)->header.h6,
+		sizeof(struct inet6_skb_parm));
+}
+
 static struct sock *tcp_v6_syn_recv_sock(const struct sock *sk, struct sk_buff *skb,
 					 struct request_sock *req,
 					 struct dst_entry *dst,
@@ -1180,8 +1190,10 @@
 						      sk_gfp_mask(sk, GFP_ATOMIC));
 			consume_skb(ireq->pktopts);
 			ireq->pktopts = NULL;
-			if (newnp->pktoptions)
+			if (newnp->pktoptions) {
+				tcp_v6_restore_cb(newnp->pktoptions);
 				skb_set_owner_r(newnp->pktoptions, newsk);
+			}
 		}
 	}
 
@@ -1196,16 +1208,6 @@
 	return NULL;
 }
 
-static void tcp_v6_restore_cb(struct sk_buff *skb)
-{
-	/* We need to move header back to the beginning if xfrm6_policy_check()
-	 * and tcp_v6_fill_cb() are going to be called again.
-	 * ip6_datagram_recv_specific_ctl() also expects IP6CB to be there.
-	 */
-	memmove(IP6CB(skb), &TCP_SKB_CB(skb)->header.h6,
-		sizeof(struct inet6_skb_parm));
-}
-
 /* The socket must have it's spinlock held when we get
  * here, unless it is a TCP_LISTEN socket.
  *
diff --git a/net/l2tp/l2tp_core.h b/net/l2tp/l2tp_core.h
index 2599af6..181e755c 100644
--- a/net/l2tp/l2tp_core.h
+++ b/net/l2tp/l2tp_core.h
@@ -273,6 +273,7 @@
 int l2tp_nl_register_ops(enum l2tp_pwtype pw_type,
 			 const struct l2tp_nl_cmd_ops *ops);
 void l2tp_nl_unregister_ops(enum l2tp_pwtype pw_type);
+int l2tp_ioctl(struct sock *sk, int cmd, unsigned long arg);
 
 /* Session reference counts. Incremented when code obtains a reference
  * to a session.
diff --git a/net/l2tp/l2tp_ip.c b/net/l2tp/l2tp_ip.c
index 8938b6b..c0f0750 100644
--- a/net/l2tp/l2tp_ip.c
+++ b/net/l2tp/l2tp_ip.c
@@ -11,6 +11,7 @@
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
+#include <asm/ioctls.h>
 #include <linux/icmp.h>
 #include <linux/module.h>
 #include <linux/skbuff.h>
@@ -560,6 +561,30 @@
 	return err ? err : copied;
 }
 
+int l2tp_ioctl(struct sock *sk, int cmd, unsigned long arg)
+{
+	struct sk_buff *skb;
+	int amount;
+
+	switch (cmd) {
+	case SIOCOUTQ:
+		amount = sk_wmem_alloc_get(sk);
+		break;
+	case SIOCINQ:
+		spin_lock_bh(&sk->sk_receive_queue.lock);
+		skb = skb_peek(&sk->sk_receive_queue);
+		amount = skb ? skb->len : 0;
+		spin_unlock_bh(&sk->sk_receive_queue.lock);
+		break;
+
+	default:
+		return -ENOIOCTLCMD;
+	}
+
+	return put_user(amount, (int __user *)arg);
+}
+EXPORT_SYMBOL(l2tp_ioctl);
+
 static struct proto l2tp_ip_prot = {
 	.name		   = "L2TP/IP",
 	.owner		   = THIS_MODULE,
@@ -568,7 +593,7 @@
 	.bind		   = l2tp_ip_bind,
 	.connect	   = l2tp_ip_connect,
 	.disconnect	   = l2tp_ip_disconnect,
-	.ioctl		   = udp_ioctl,
+	.ioctl		   = l2tp_ioctl,
 	.destroy	   = l2tp_ip_destroy_sock,
 	.setsockopt	   = ip_setsockopt,
 	.getsockopt	   = ip_getsockopt,
diff --git a/net/l2tp/l2tp_ip6.c b/net/l2tp/l2tp_ip6.c
index f092ac4..7095786 100644
--- a/net/l2tp/l2tp_ip6.c
+++ b/net/l2tp/l2tp_ip6.c
@@ -730,7 +730,7 @@
 	.bind		   = l2tp_ip6_bind,
 	.connect	   = l2tp_ip6_connect,
 	.disconnect	   = l2tp_ip6_disconnect,
-	.ioctl		   = udp_ioctl,
+	.ioctl		   = l2tp_ioctl,
 	.destroy	   = l2tp_ip6_destroy_sock,
 	.setsockopt	   = ipv6_setsockopt,
 	.getsockopt	   = ipv6_getsockopt,
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index 42120d9..50e1b7f 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -339,7 +339,7 @@
 	/* fast-forward to vendor IEs */
 	offset = ieee80211_ie_split_vendor(ifmsh->ie, ifmsh->ie_len, 0);
 
-	if (offset) {
+	if (offset < ifmsh->ie_len) {
 		len = ifmsh->ie_len - offset;
 		data = ifmsh->ie + offset;
 		if (skb_tailroom(skb) < len)
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index 94e4a59..458722b 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -2813,7 +2813,7 @@
 	struct virtio_net_hdr vnet_hdr = { 0 };
 	int offset = 0;
 	struct packet_sock *po = pkt_sk(sk);
-	int hlen, tlen;
+	int hlen, tlen, linear;
 	int extra_len = 0;
 
 	/*
@@ -2874,8 +2874,9 @@
 	err = -ENOBUFS;
 	hlen = LL_RESERVED_SPACE(dev);
 	tlen = dev->needed_tailroom;
-	skb = packet_alloc_skb(sk, hlen + tlen, hlen, len,
-			       __virtio16_to_cpu(vio_le(), vnet_hdr.hdr_len),
+	linear = __virtio16_to_cpu(vio_le(), vnet_hdr.hdr_len);
+	linear = max(linear, min_t(int, len, dev->hard_header_len));
+	skb = packet_alloc_skb(sk, hlen + tlen, hlen, len, linear,
 			       msg->msg_flags & MSG_DONTWAIT, &err);
 	if (skb == NULL)
 		goto out_unlock;
diff --git a/net/sched/cls_matchall.c b/net/sched/cls_matchall.c
index f935429..b12bc2a 100644
--- a/net/sched/cls_matchall.c
+++ b/net/sched/cls_matchall.c
@@ -16,16 +16,11 @@
 #include <net/sch_generic.h>
 #include <net/pkt_cls.h>
 
-struct cls_mall_filter {
+struct cls_mall_head {
 	struct tcf_exts exts;
 	struct tcf_result res;
 	u32 handle;
-	struct rcu_head	rcu;
 	u32 flags;
-};
-
-struct cls_mall_head {
-	struct cls_mall_filter *filter;
 	struct rcu_head	rcu;
 };
 
@@ -33,38 +28,29 @@
 			 struct tcf_result *res)
 {
 	struct cls_mall_head *head = rcu_dereference_bh(tp->root);
-	struct cls_mall_filter *f = head->filter;
 
-	if (tc_skip_sw(f->flags))
+	if (tc_skip_sw(head->flags))
 		return -1;
 
-	return tcf_exts_exec(skb, &f->exts, res);
+	return tcf_exts_exec(skb, &head->exts, res);
 }
 
 static int mall_init(struct tcf_proto *tp)
 {
-	struct cls_mall_head *head;
-
-	head = kzalloc(sizeof(*head), GFP_KERNEL);
-	if (!head)
-		return -ENOBUFS;
-
-	rcu_assign_pointer(tp->root, head);
-
 	return 0;
 }
 
-static void mall_destroy_filter(struct rcu_head *head)
+static void mall_destroy_rcu(struct rcu_head *rcu)
 {
-	struct cls_mall_filter *f = container_of(head, struct cls_mall_filter, rcu);
+	struct cls_mall_head *head = container_of(rcu, struct cls_mall_head,
+						  rcu);
 
-	tcf_exts_destroy(&f->exts);
-
-	kfree(f);
+	tcf_exts_destroy(&head->exts);
+	kfree(head);
 }
 
 static int mall_replace_hw_filter(struct tcf_proto *tp,
-				  struct cls_mall_filter *f,
+				  struct cls_mall_head *head,
 				  unsigned long cookie)
 {
 	struct net_device *dev = tp->q->dev_queue->dev;
@@ -74,7 +60,7 @@
 	offload.type = TC_SETUP_MATCHALL;
 	offload.cls_mall = &mall_offload;
 	offload.cls_mall->command = TC_CLSMATCHALL_REPLACE;
-	offload.cls_mall->exts = &f->exts;
+	offload.cls_mall->exts = &head->exts;
 	offload.cls_mall->cookie = cookie;
 
 	return dev->netdev_ops->ndo_setup_tc(dev, tp->q->handle, tp->protocol,
@@ -82,7 +68,7 @@
 }
 
 static void mall_destroy_hw_filter(struct tcf_proto *tp,
-				   struct cls_mall_filter *f,
+				   struct cls_mall_head *head,
 				   unsigned long cookie)
 {
 	struct net_device *dev = tp->q->dev_queue->dev;
@@ -103,29 +89,20 @@
 {
 	struct cls_mall_head *head = rtnl_dereference(tp->root);
 	struct net_device *dev = tp->q->dev_queue->dev;
-	struct cls_mall_filter *f = head->filter;
 
-	if (!force && f)
-		return false;
+	if (!head)
+		return true;
 
-	if (f) {
-		if (tc_should_offload(dev, tp, f->flags))
-			mall_destroy_hw_filter(tp, f, (unsigned long) f);
+	if (tc_should_offload(dev, tp, head->flags))
+		mall_destroy_hw_filter(tp, head, (unsigned long) head);
 
-		call_rcu(&f->rcu, mall_destroy_filter);
-	}
-	kfree_rcu(head, rcu);
+	call_rcu(&head->rcu, mall_destroy_rcu);
 	return true;
 }
 
 static unsigned long mall_get(struct tcf_proto *tp, u32 handle)
 {
-	struct cls_mall_head *head = rtnl_dereference(tp->root);
-	struct cls_mall_filter *f = head->filter;
-
-	if (f && f->handle == handle)
-		return (unsigned long) f;
-	return 0;
+	return 0UL;
 }
 
 static const struct nla_policy mall_policy[TCA_MATCHALL_MAX + 1] = {
@@ -134,7 +111,7 @@
 };
 
 static int mall_set_parms(struct net *net, struct tcf_proto *tp,
-			  struct cls_mall_filter *f,
+			  struct cls_mall_head *head,
 			  unsigned long base, struct nlattr **tb,
 			  struct nlattr *est, bool ovr)
 {
@@ -147,11 +124,11 @@
 		return err;
 
 	if (tb[TCA_MATCHALL_CLASSID]) {
-		f->res.classid = nla_get_u32(tb[TCA_MATCHALL_CLASSID]);
-		tcf_bind_filter(tp, &f->res, base);
+		head->res.classid = nla_get_u32(tb[TCA_MATCHALL_CLASSID]);
+		tcf_bind_filter(tp, &head->res, base);
 	}
 
-	tcf_exts_change(tp, &f->exts, &e);
+	tcf_exts_change(tp, &head->exts, &e);
 
 	return 0;
 }
@@ -162,21 +139,17 @@
 		       unsigned long *arg, bool ovr)
 {
 	struct cls_mall_head *head = rtnl_dereference(tp->root);
-	struct cls_mall_filter *fold = (struct cls_mall_filter *) *arg;
 	struct net_device *dev = tp->q->dev_queue->dev;
-	struct cls_mall_filter *f;
 	struct nlattr *tb[TCA_MATCHALL_MAX + 1];
+	struct cls_mall_head *new;
 	u32 flags = 0;
 	int err;
 
 	if (!tca[TCA_OPTIONS])
 		return -EINVAL;
 
-	if (head->filter)
-		return -EBUSY;
-
-	if (fold)
-		return -EINVAL;
+	if (head)
+		return -EEXIST;
 
 	err = nla_parse_nested(tb, TCA_MATCHALL_MAX,
 			       tca[TCA_OPTIONS], mall_policy);
@@ -189,23 +162,23 @@
 			return -EINVAL;
 	}
 
-	f = kzalloc(sizeof(*f), GFP_KERNEL);
-	if (!f)
+	new = kzalloc(sizeof(*new), GFP_KERNEL);
+	if (!new)
 		return -ENOBUFS;
 
-	tcf_exts_init(&f->exts, TCA_MATCHALL_ACT, 0);
+	tcf_exts_init(&new->exts, TCA_MATCHALL_ACT, 0);
 
 	if (!handle)
 		handle = 1;
-	f->handle = handle;
-	f->flags = flags;
+	new->handle = handle;
+	new->flags = flags;
 
-	err = mall_set_parms(net, tp, f, base, tb, tca[TCA_RATE], ovr);
+	err = mall_set_parms(net, tp, new, base, tb, tca[TCA_RATE], ovr);
 	if (err)
 		goto errout;
 
 	if (tc_should_offload(dev, tp, flags)) {
-		err = mall_replace_hw_filter(tp, f, (unsigned long) f);
+		err = mall_replace_hw_filter(tp, new, (unsigned long) new);
 		if (err) {
 			if (tc_skip_sw(flags))
 				goto errout;
@@ -214,39 +187,29 @@
 		}
 	}
 
-	*arg = (unsigned long) f;
-	rcu_assign_pointer(head->filter, f);
-
+	*arg = (unsigned long) head;
+	rcu_assign_pointer(tp->root, new);
+	if (head)
+		call_rcu(&head->rcu, mall_destroy_rcu);
 	return 0;
 
 errout:
-	kfree(f);
+	kfree(new);
 	return err;
 }
 
 static int mall_delete(struct tcf_proto *tp, unsigned long arg)
 {
-	struct cls_mall_head *head = rtnl_dereference(tp->root);
-	struct cls_mall_filter *f = (struct cls_mall_filter *) arg;
-	struct net_device *dev = tp->q->dev_queue->dev;
-
-	if (tc_should_offload(dev, tp, f->flags))
-		mall_destroy_hw_filter(tp, f, (unsigned long) f);
-
-	RCU_INIT_POINTER(head->filter, NULL);
-	tcf_unbind_filter(tp, &f->res);
-	call_rcu(&f->rcu, mall_destroy_filter);
-	return 0;
+	return -EOPNOTSUPP;
 }
 
 static void mall_walk(struct tcf_proto *tp, struct tcf_walker *arg)
 {
 	struct cls_mall_head *head = rtnl_dereference(tp->root);
-	struct cls_mall_filter *f = head->filter;
 
 	if (arg->count < arg->skip)
 		goto skip;
-	if (arg->fn(tp, (unsigned long) f, arg) < 0)
+	if (arg->fn(tp, (unsigned long) head, arg) < 0)
 		arg->stop = 1;
 skip:
 	arg->count++;
@@ -255,28 +218,28 @@
 static int mall_dump(struct net *net, struct tcf_proto *tp, unsigned long fh,
 		     struct sk_buff *skb, struct tcmsg *t)
 {
-	struct cls_mall_filter *f = (struct cls_mall_filter *) fh;
+	struct cls_mall_head *head = (struct cls_mall_head *) fh;
 	struct nlattr *nest;
 
-	if (!f)
+	if (!head)
 		return skb->len;
 
-	t->tcm_handle = f->handle;
+	t->tcm_handle = head->handle;
 
 	nest = nla_nest_start(skb, TCA_OPTIONS);
 	if (!nest)
 		goto nla_put_failure;
 
-	if (f->res.classid &&
-	    nla_put_u32(skb, TCA_MATCHALL_CLASSID, f->res.classid))
+	if (head->res.classid &&
+	    nla_put_u32(skb, TCA_MATCHALL_CLASSID, head->res.classid))
 		goto nla_put_failure;
 
-	if (tcf_exts_dump(skb, &f->exts))
+	if (tcf_exts_dump(skb, &head->exts))
 		goto nla_put_failure;
 
 	nla_nest_end(skb, nest);
 
-	if (tcf_exts_dump_stats(skb, &f->exts) < 0)
+	if (tcf_exts_dump_stats(skb, &head->exts) < 0)
 		goto nla_put_failure;
 
 	return skb->len;
diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c
index 176af30..6a2532d 100644
--- a/net/sctp/ipv6.c
+++ b/net/sctp/ipv6.c
@@ -222,7 +222,8 @@
 	SCTP_INC_STATS(sock_net(sk), SCTP_MIB_OUTSCTPPACKS);
 
 	rcu_read_lock();
-	res = ip6_xmit(sk, skb, fl6, rcu_dereference(np->opt), np->tclass);
+	res = ip6_xmit(sk, skb, fl6, sk->sk_mark, rcu_dereference(np->opt),
+		       np->tclass);
 	rcu_read_unlock();
 	return res;
 }
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index ca12aa3..6cbe5bd 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -7427,7 +7427,8 @@
 		 */
 		release_sock(sk);
 		current_timeo = schedule_timeout(current_timeo);
-		BUG_ON(sk != asoc->base.sk);
+		if (sk != asoc->base.sk)
+			goto do_error;
 		lock_sock(sk);
 
 		*timeo_p = current_timeo;
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 92db80d..034f70c 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -5874,6 +5874,7 @@
 			break;
 		}
 		cfg->ht_opmode = ht_opmode;
+		mask |= (1 << (NL80211_MESHCONF_HT_OPMODE - 1));
 	}
 	FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPactivePathToRootTimeout,
 				  1, 65535, mask,
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 24bd84d..8b918f8 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -5859,7 +5859,7 @@
 		return error;
 
 	/* Obtain a SID for the context, if one was specified. */
-	if (size && str[1] && str[1] != '\n') {
+	if (size && str[0] && str[0] != '\n') {
 		if (str[size-1] == '\n') {
 			str[size-1] = 0;
 			size--;
diff --git a/sound/core/seq/seq_memory.c b/sound/core/seq/seq_memory.c
index c850345..dfa5156 100644
--- a/sound/core/seq/seq_memory.c
+++ b/sound/core/seq/seq_memory.c
@@ -419,7 +419,6 @@
 {
 	unsigned long flags;
 	struct snd_seq_event_cell *ptr;
-	int max_count = 5 * HZ;
 
 	if (snd_BUG_ON(!pool))
 		return -EINVAL;
@@ -432,14 +431,8 @@
 	if (waitqueue_active(&pool->output_sleep))
 		wake_up(&pool->output_sleep);
 
-	while (atomic_read(&pool->counter) > 0) {
-		if (max_count == 0) {
-			pr_warn("ALSA: snd_seq_pool_done timeout: %d cells remain\n", atomic_read(&pool->counter));
-			break;
-		}
+	while (atomic_read(&pool->counter) > 0)
 		schedule_timeout_uninterruptible(1);
-		max_count--;
-	}
 	
 	/* release all resources */
 	spin_lock_irqsave(&pool->lock, flags);
diff --git a/sound/core/seq/seq_queue.c b/sound/core/seq/seq_queue.c
index 0bec02e..450c518 100644
--- a/sound/core/seq/seq_queue.c
+++ b/sound/core/seq/seq_queue.c
@@ -181,6 +181,8 @@
 	}
 }
 
+static void queue_use(struct snd_seq_queue *queue, int client, int use);
+
 /* allocate a new queue -
  * return queue index value or negative value for error
  */
@@ -192,11 +194,11 @@
 	if (q == NULL)
 		return -ENOMEM;
 	q->info_flags = info_flags;
+	queue_use(q, client, 1);
 	if (queue_list_add(q) < 0) {
 		queue_delete(q);
 		return -ENOMEM;
 	}
-	snd_seq_queue_use(q->queue, client, 1); /* use this queue */
 	return q->queue;
 }
 
@@ -502,19 +504,9 @@
 	return result;
 }
 
-
-/* use or unuse this queue -
- * if it is the first client, starts the timer.
- * if it is not longer used by any clients, stop the timer.
- */
-int snd_seq_queue_use(int queueid, int client, int use)
+/* use or unuse this queue */
+static void queue_use(struct snd_seq_queue *queue, int client, int use)
 {
-	struct snd_seq_queue *queue;
-
-	queue = queueptr(queueid);
-	if (queue == NULL)
-		return -EINVAL;
-	mutex_lock(&queue->timer_mutex);
 	if (use) {
 		if (!test_and_set_bit(client, queue->clients_bitmap))
 			queue->clients++;
@@ -529,6 +521,21 @@
 	} else {
 		snd_seq_timer_close(queue);
 	}
+}
+
+/* use or unuse this queue -
+ * if it is the first client, starts the timer.
+ * if it is not longer used by any clients, stop the timer.
+ */
+int snd_seq_queue_use(int queueid, int client, int use)
+{
+	struct snd_seq_queue *queue;
+
+	queue = queueptr(queueid);
+	if (queue == NULL)
+		return -EINVAL;
+	mutex_lock(&queue->timer_mutex);
+	queue_use(queue, client, use);
 	mutex_unlock(&queue->timer_mutex);
 	queuefree(queue);
 	return 0;
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c
index 56e5204..4bf4833 100644
--- a/sound/pci/hda/patch_hdmi.c
+++ b/sound/pci/hda/patch_hdmi.c
@@ -3638,6 +3638,7 @@
 HDA_CODEC_ENTRY(0x10de0071, "GPU 71 HDMI/DP",	patch_nvhdmi),
 HDA_CODEC_ENTRY(0x10de0072, "GPU 72 HDMI/DP",	patch_nvhdmi),
 HDA_CODEC_ENTRY(0x10de007d, "GPU 7d HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0080, "GPU 80 HDMI/DP",	patch_nvhdmi),
 HDA_CODEC_ENTRY(0x10de0082, "GPU 82 HDMI/DP",	patch_nvhdmi),
 HDA_CODEC_ENTRY(0x10de0083, "GPU 83 HDMI/DP",	patch_nvhdmi),
 HDA_CODEC_ENTRY(0x10de8001, "MCP73 HDMI",	patch_nvhdmi_2ch),
diff --git a/sound/usb/line6/driver.c b/sound/usb/line6/driver.c
index 90009c0..ab3c280 100644
--- a/sound/usb/line6/driver.c
+++ b/sound/usb/line6/driver.c
@@ -754,8 +754,9 @@
 		goto error;
 	}
 
+	line6_get_interval(line6);
+
 	if (properties->capabilities & LINE6_CAP_CONTROL) {
-		line6_get_interval(line6);
 		ret = line6_init_cap_control(line6);
 		if (ret < 0)
 			goto error;
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c
index 9ff0db4..933aeec 100644
--- a/tools/perf/builtin-diff.c
+++ b/tools/perf/builtin-diff.c
@@ -1199,7 +1199,7 @@
 		BUG_ON(1);
 	}
 
-	perf_hpp__register_sort_field(fmt);
+	perf_hpp__prepend_sort_field(fmt);
 	return 0;
 }
 
diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c
index 3738839..18cfcdc9 100644
--- a/tools/perf/ui/hist.c
+++ b/tools/perf/ui/hist.c
@@ -521,6 +521,12 @@
 	list_add_tail(&format->sort_list, &list->sorts);
 }
 
+void perf_hpp_list__prepend_sort_field(struct perf_hpp_list *list,
+				       struct perf_hpp_fmt *format)
+{
+	list_add(&format->sort_list, &list->sorts);
+}
+
 void perf_hpp__column_unregister(struct perf_hpp_fmt *format)
 {
 	list_del(&format->list);
@@ -560,6 +566,10 @@
 	perf_hpp_list__for_each_sort_list(list, fmt) {
 		struct perf_hpp_fmt *pos;
 
+		/* skip sort-only fields ("sort_compute" in perf diff) */
+		if (!fmt->entry && !fmt->color)
+			continue;
+
 		perf_hpp_list__for_each_format(list, pos) {
 			if (fmt_equal(fmt, pos))
 				goto next;
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index 9928fed..a440a04 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -282,6 +282,8 @@
 				    struct perf_hpp_fmt *format);
 void perf_hpp_list__register_sort_field(struct perf_hpp_list *list,
 					struct perf_hpp_fmt *format);
+void perf_hpp_list__prepend_sort_field(struct perf_hpp_list *list,
+				       struct perf_hpp_fmt *format);
 
 static inline void perf_hpp__column_register(struct perf_hpp_fmt *format)
 {
@@ -293,6 +295,11 @@
 	perf_hpp_list__register_sort_field(&perf_hpp_list, format);
 }
 
+static inline void perf_hpp__prepend_sort_field(struct perf_hpp_fmt *format)
+{
+	perf_hpp_list__prepend_sort_field(&perf_hpp_list, format);
+}
+
 #define perf_hpp_list__for_each_format(_list, format) \
 	list_for_each_entry(format, &(_list)->fields, list)