Merge "ARM: dts: msm: Update SDC1 lines sleep configuration for 8909w BG"
diff --git a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-qg.txt b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-qg.txt
index afeb65d..43e7380 100644
--- a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-qg.txt
+++ b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-qg.txt
@@ -262,6 +262,39 @@
 		    capacity learning cycle. If this is not specified, then
 		    the default value is 0. Unit is in decipercentage.
 
+- qcom,esr-disable
+	Usage:      optional
+	Value type: <bool>
+	Definition: Boolean property to disable ESR estimation. If not defined
+		    ESR estimation stays enabled for charge-cycles.
+
+- qcom,esr-discharge-enable
+	Usage:      optional
+	Value type: <bool>
+	Definition: Boolean property to enable ESR estimation during discharge.
+		    Only valid if 'qcom,esr-disable' is not defined.
+
+- qcom,esr-qual-current-ua
+	Usage:      optional
+	Value type: <u32>
+	Definition: Minimum current differential in uA to qualify an ESR
+		    reading as valid. If not defined the value defaults
+		    to 130mA.
+
+- qcom,esr-qual-vbatt-uv
+	Usage:      optional
+	Value type: <u32>
+	Definition: Minimum vbatt differential in uV to qualify an ESR
+		    reading as valid. If not defined the value defaults
+		    to 7mV.
+
+- qcom,esr-disable-soc
+	Usage:      optional
+	Value type: <u32>
+	Definition: Minimum battery SOC below which ESR will not be
+		    attempted by QG. If not defined the value defaults
+		    to 10%.
+
 ==========================================================
 Second Level Nodes - Peripherals managed by QGAUGE driver
 ==========================================================
diff --git a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb2.txt b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb2.txt
index afa8009..9de24c3 100644
--- a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb2.txt
+++ b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb2.txt
@@ -193,6 +193,12 @@
 		to be get from these properties defined in battery profile:
 		qcom,step-chg-ranges, qcom,jeita-fcc-ranges, qcom,jeita-fv-ranges.
 
+- qcom,disable-stat-sw-override
+  Usage:      optional
+  Value type: bool
+  Definition: Boolean flag which when present disables STAT pin default software
+		override configuration.
+
 =============================================
 Second Level Nodes - SMB2 Charger Peripherals
 =============================================
diff --git a/Documentation/devicetree/bindings/pwm/pwm-qti-lpg.txt b/Documentation/devicetree/bindings/pwm/pwm-qti-lpg.txt
index ddd90e1..2a84dd6 100644
--- a/Documentation/devicetree/bindings/pwm/pwm-qti-lpg.txt
+++ b/Documentation/devicetree/bindings/pwm/pwm-qti-lpg.txt
@@ -20,7 +20,8 @@
 	Value type: <string>
 	Definition: The name of the register defined in the reg property.
 		      It must have "lpg-base", "lut-base" is optional but
-		      it's required if any LPG channels support LUT mode.
+		      it's required if any LPG channels support LUT mode
+		      with a LUT module.
 
 - #pwm-cells:
 	Usage: required
@@ -30,14 +31,47 @@
 		      the PWM channel ID indexed from 0, and the second
 		      cell is the PWM default period in nanoseconds.
 
+- nvmem-names:
+	Usage: optional
+	Value type: <string>
+	Definition: The nvmem device name for the SDAM module where the LUT
+		      pattern is stored. It must be "ppg_sdam". This property
+		      is required only when LUT mode is supported with a SDAM
+		      module instead of a LUT module.
+
+- nvmem:
+	Usage: optional
+	Value type: <phandle>
+	Definition: Phandle of the nvmem device to access the LUT stored
+		      in the SDAM module. This property is required only when
+		      LUT mode is supported and the LUT pattern is stored in a
+		      SDAM module instead of a LUT module.
+
+- qcom,pbs-client
+	Usage: optional
+	Value type: <phandle>
+	Definition: Phandle of the PBS client used for sending the PBS
+		      trigger. This property is required when LUT mode is
+		      supported and the LUT pattern is stored in a SDAM
+		      module instead of a LUT module.
+
+- qcom,lut-sdam-base:
+	Usage: optional
+	Value type: <u32>
+	Definition: The register base of the LUT entries stored in SDAM. This
+		      property is required only when LUT mode is supported and
+		      the LUT pattern is stored in a SDAM module instead of a
+		      LUT module.
+
 - qcom,lut-patterns:
 	Usage: optional
 	Value type: <prop-encoded-array>
 	Definition: Duty ratios in percentages for LPG working at LUT mode.
 		      These duty ratios will be translated into PWM values
-		      and stored in LUT module. The LUT module has resource
-		      to store 47 PWM values at max and shared for all LPG
-		      channels. This property is required if any LPG channels
+		      and stored in LUT or SDAM module shared for all LPG
+		      channels. The LUT module has resource to store 47 PWM
+		      values at max while SDAM module can store upto 64 PWM
+		      values. This property is required if any LPG channels
 		      support LUT mode.
 
 Subnode is optional if LUT mode is not required, it's required if any LPG
@@ -54,31 +88,37 @@
 		      range is 1 - 8. Maximum value depends on the number of
 		      channels supported on PMIC.
 
+- qcom,lpg-sdam-base:
+	Usage: optional
+	Value type: <u32>
+	Definition: Register base address for LPG configuration in SDAM for
+		      the LPG channel specified under "qcom,lpg-chan-id".
+		      This property is required if LUT mode is supported with
+		      a SDAM module.
+
 - qcom,ramp-step-ms:
 	Usage: required
 	Value type: <u32>
 	Definition: The step duration in milliseconds for LPG staying at each
-		      duty specified in the LUT pattern. Allowed range is
-		      1 - 511.
+		      duty specified in the LUT pattern. Allowed range:
+		      1 - 511 when LUT module is used, and 8 - 2000 when SDAM
+		      is used.
 
 - qcom,ramp-high-index:
 	Usage: required
 	Value type: <u32>
 	Definition: The high index of the LUT pattern where LPG ends up
-		      ramping to. Allowed range is 1 - 47.
+		      ramping to. Allowed range: 1 - 47 when LUT module
+		      is used, and 1 - 64 when SDAM module is used.
 
 - qcom,ramp-low-index:
 	Usage: required
 	Value type: <u32>
 	Definition: The low index of the LUT pattern from where LPG begins
-		      ramping from. Allowed range is 0 - 46.
-
-- qcom,ramp-from-low-to-high:
-	Usage: optional
-	Value type: <empty>
-	Definition: The flag to specify the LPG ramping direction. The ramping
-		      direction is from low index to high index of the LUT
-		      pattern if it's specified.
+		      ramping from. The ramp-low-index should be always less
+		      than ramp-high-index when SDAM module is used. Allowed
+		      range: 0 - 46 when LUT module is used, and 0 - 63 when
+		      SDAM module is used.
 
 - qcom,ramp-pattern-repeat:
 	Usage: optional
@@ -86,34 +126,66 @@
 	Definition: The flag to specify if LPG would be ramping with the LUT
 		      pattern repeatedly.
 
+- qcom,ramp-from-low-to-high:
+	Usage: optional
+	Value type: <empty>
+	Definition: The flag to specify the LPG ramping direction. The ramping
+		      direction is from low index to high index of the LUT
+		      pattern if it's specified. This property is not required
+		      when SDAM module is used.
+
 - qcom,ramp-toggle:
 	Usage: optional
 	Value type: <empty>
 	Definition: The flag to specify if LPG would toggle the LUT pattern
 		      in ramping. If toggling enabled, LPG would return to the
 		      low index when high index is reached, or return to the high
-		      index when low index is reached.
+		      index when low index is reached. This property is not
+		      required when SDAM module is used.
 
 - qcom,ramp-pause-hi-count:
 	Usage: optional
 	Value type: <u32>
 	Definition: The step count that LPG stop the output when it ramped up
-		      to the high index of the LUT.
+		      to the high index of the LUT. This property is not
+		      required when SDAM module is used.
 
 - qcom,ramp-pause-lo-count:
 	Usage: optional
 	Value type: <u32>
 	Definition: The step count that LPG stop the output when it ramped up
-		      to the low index of the LUT.
-Example:
+		      to the low index of the LUT. This property is not
+		      required when SDAM module is used.
 
-	pmi8998_lpg: lpg@b100 {
+Example when LUT pattern is stored in a LUT module:
+
+	pm8150l_lpg: lpg@b100 {
 		compatible = "qcom,pwm-lpg";
 		reg = <0xb100 0x600>, <0xb000 0x100>;
 		reg-names = "lpg-base", "lut-base";
 		#pwm-cells = <2>;
 		qcom,lut-patterns = <0 14 28 42 56 70 84 100
 					100 84 70 56 42 28 14 0>;
+		lpg@1 {
+			qcom,lpg-chan-id = <1>;
+			qcom,ramp-step-ms = <200>;
+			qcom,ramp-pause-hi-count = <10>;
+			qcom,ramp-pause-lo-count = <10>;
+			qcom,ramp-low-index = <0>;
+			qcom,ramp-high-index = <15>;
+			qcom,ramp-from-low-to-high;
+			qcom,ramp-pattern-repeat;
+		};
+		lpg@2 {
+			qcom,lpg-chan-id = <2>;
+			qcom,ramp-step-ms = <200>;
+			qcom,ramp-pause-hi-count = <10>;
+			qcom,ramp-pause-lo-count = <10>;
+			qcom,ramp-low-index = <0>;
+			qcom,ramp-high-index = <15>;
+			qcom,ramp-from-low-to-high;
+			qcom,ramp-pattern-repeat;
+		};
 		lpg@3 {
 			qcom,lpg-chan-id = <3>;
 			qcom,ramp-step-ms = <200>;
@@ -124,24 +196,43 @@
 			qcom,ramp-from-low-to-high;
 			qcom,ramp-pattern-repeat;
 		};
-		lpg@4 {
-			qcom,lpg-chan-id = <4>;
+	};
+
+Example when LUT pattern is stored in a SDAM module:
+
+	pmi632_lpg: lpg@b100 {
+		compatible = "qcom,pwm-lpg";
+		reg = <0xb100 0x600>;
+		reg-names = "lpg-base";
+		#pwm-cells = <2>;
+		nvmem-names = "ppg_sdam";
+		nvmem = <&sdam7>;
+		qcom,pbs-client = <&pbs_client_3>;
+		qcom,lut-sdam-base = <0x80>;
+		qcom,lut-patterns = <0 14 28 42 56 70 84 100
+					100 84 70 56 42 28 14 0>;
+		lpg@1 {
+			qcom,lpg-chan-id = <1>;
 			qcom,ramp-step-ms = <200>;
-			qcom,ramp-pause-hi-count = <10>;
-			qcom,ramp-pause-lo-count = <10>;
 			qcom,ramp-low-index = <0>;
 			qcom,ramp-high-index = <15>;
-			qcom,ramp-from-low-to-high;
 			qcom,ramp-pattern-repeat;
+			qcom,lpg-sdam-base = <0x48>:
 		};
-		lpg@5 {
-			qcom,lpg-chan-id = <5>;
+		lpg@2 {
+			qcom,lpg-chan-id = <2>;
 			qcom,ramp-step-ms = <200>;
-			qcom,ramp-pause-hi-count = <10>;
-			qcom,ramp-pause-lo-count = <10>;
 			qcom,ramp-low-index = <0>;
 			qcom,ramp-high-index = <15>;
-			qcom,ramp-from-low-to-high;
 			qcom,ramp-pattern-repeat;
+			qcom,lpg-sdam-base = <0x56>;
+		};
+		lpg@3 {
+			qcom,lpg-chan-id = <3>;
+			qcom,ramp-step-ms = <200>;
+			qcom,ramp-low-index = <0>;
+			qcom,ramp-high-index = <15>;
+			qcom,ramp-pattern-repeat;
+			qcom,lpg-sdam-base = <0x64>;
 		};
 	};
diff --git a/Makefile b/Makefile
index ab77d85..2f08005 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
 VERSION = 4
 PATCHLEVEL = 9
-SUBLEVEL = 99
+SUBLEVEL = 101
 EXTRAVERSION =
 NAME = Roaring Lionus
 
diff --git a/arch/alpha/include/asm/futex.h b/arch/alpha/include/asm/futex.h
index f939794..5647469 100644
--- a/arch/alpha/include/asm/futex.h
+++ b/arch/alpha/include/asm/futex.h
@@ -29,18 +29,10 @@
 	:	"r" (uaddr), "r"(oparg)				\
 	:	"memory")
 
-static inline int futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
+static inline int arch_futex_atomic_op_inuser(int op, int oparg, int *oval,
+		u32 __user *uaddr)
 {
-	int op = (encoded_op >> 28) & 7;
-	int cmp = (encoded_op >> 24) & 15;
-	int oparg = (encoded_op << 8) >> 20;
-	int cmparg = (encoded_op << 20) >> 20;
 	int oldval = 0, ret;
-	if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
-		oparg = 1 << oparg;
-
-	if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
-		return -EFAULT;
 
 	pagefault_disable();
 
@@ -66,17 +58,9 @@
 
 	pagefault_enable();
 
-	if (!ret) {
-		switch (cmp) {
-		case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
-		case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
-		case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
-		case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
-		case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
-		case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
-		default: ret = -ENOSYS;
-		}
-	}
+	if (!ret)
+		*oval = oldval;
+
 	return ret;
 }
 
diff --git a/arch/arc/include/asm/futex.h b/arch/arc/include/asm/futex.h
index 11e1b1f..eb887dd 100644
--- a/arch/arc/include/asm/futex.h
+++ b/arch/arc/include/asm/futex.h
@@ -73,20 +73,11 @@
 
 #endif
 
-static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
+static inline int arch_futex_atomic_op_inuser(int op, int oparg, int *oval,
+		u32 __user *uaddr)
 {
-	int op = (encoded_op >> 28) & 7;
-	int cmp = (encoded_op >> 24) & 15;
-	int oparg = (encoded_op << 8) >> 20;
-	int cmparg = (encoded_op << 20) >> 20;
 	int oldval = 0, ret;
 
-	if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
-		oparg = 1 << oparg;
-
-	if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
-		return -EFAULT;
-
 #ifndef CONFIG_ARC_HAS_LLSC
 	preempt_disable();	/* to guarantee atomic r-m-w of futex op */
 #endif
@@ -118,30 +109,9 @@
 	preempt_enable();
 #endif
 
-	if (!ret) {
-		switch (cmp) {
-		case FUTEX_OP_CMP_EQ:
-			ret = (oldval == cmparg);
-			break;
-		case FUTEX_OP_CMP_NE:
-			ret = (oldval != cmparg);
-			break;
-		case FUTEX_OP_CMP_LT:
-			ret = (oldval < cmparg);
-			break;
-		case FUTEX_OP_CMP_GE:
-			ret = (oldval >= cmparg);
-			break;
-		case FUTEX_OP_CMP_LE:
-			ret = (oldval <= cmparg);
-			break;
-		case FUTEX_OP_CMP_GT:
-			ret = (oldval > cmparg);
-			break;
-		default:
-			ret = -ENOSYS;
-		}
-	}
+	if (!ret)
+		*oval = oldval;
+
 	return ret;
 }
 
diff --git a/arch/arm/boot/dts/imx6qdl-wandboard.dtsi b/arch/arm/boot/dts/imx6qdl-wandboard.dtsi
index 47c9554..2b9c2be 100644
--- a/arch/arm/boot/dts/imx6qdl-wandboard.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-wandboard.dtsi
@@ -88,7 +88,6 @@
 		clocks = <&clks IMX6QDL_CLK_CKO>;
 		VDDA-supply = <&reg_2p5v>;
 		VDDIO-supply = <&reg_3p3v>;
-		lrclk-strength = <3>;
 	};
 };
 
diff --git a/arch/arm/configs/msm8909-perf_defconfig b/arch/arm/configs/msm8909-perf_defconfig
index cb3c333..f42b90a 100644
--- a/arch/arm/configs/msm8909-perf_defconfig
+++ b/arch/arm/configs/msm8909-perf_defconfig
@@ -31,13 +31,15 @@
 # CONFIG_RD_XZ is not set
 # CONFIG_RD_LZO is not set
 # CONFIG_RD_LZ4 is not set
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
 CONFIG_KALLSYMS_ALL=y
 CONFIG_BPF_SYSCALL=y
 # CONFIG_MEMBARRIER is not set
 CONFIG_EMBEDDED=y
 # CONFIG_COMPAT_BRK is not set
 CONFIG_PROFILING=y
-CONFIG_CC_STACKPROTECTOR_STRONG=y
+CONFIG_OPROFILE=y
+CONFIG_CC_STACKPROTECTOR_REGULAR=y
 CONFIG_ARCH_MMAP_RND_BITS=16
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
@@ -57,6 +59,7 @@
 CONFIG_CMA=y
 CONFIG_ZSMALLOC=y
 CONFIG_BALANCE_ANON_FILE_RECLAIM=y
+CONFIG_PROCESS_RECLAIM=y
 CONFIG_SECCOMP=y
 CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE=y
 CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y
@@ -145,6 +148,7 @@
 CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
 CONFIG_NETFILTER_XT_MATCH_QUOTA=y
 CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y
 CONFIG_NETFILTER_XT_MATCH_SOCKET=y
 CONFIG_NETFILTER_XT_MATCH_STATE=y
 CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
@@ -263,6 +267,7 @@
 CONFIG_CNSS_SDIO=y
 CONFIG_CLD_HL_SDIO_CORE=y
 CONFIG_INPUT_EVDEV=y
+CONFIG_INPUT_EVBUG=y
 CONFIG_KEYBOARD_GPIO=y
 CONFIG_INPUT_JOYSTICK=y
 CONFIG_INPUT_TOUCHSCREEN=y
@@ -272,6 +277,8 @@
 CONFIG_SERIAL_MSM=y
 CONFIG_SERIAL_MSM_CONSOLE=y
 CONFIG_SERIAL_MSM_SMD=y
+CONFIG_DIAG_CHAR=y
+CONFIG_DIAG_USES_SMD=y
 CONFIG_HW_RANDOM=y
 CONFIG_HW_RANDOM_MSM_LEGACY=y
 CONFIG_MSM_SMD_PKT=y
@@ -360,6 +367,9 @@
 CONFIG_USB_MON=y
 CONFIG_USB_EHCI_HCD=y
 CONFIG_USB_EHCI_MSM=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_DWC3=y
+CONFIG_USB_DWC3_GADGET=y
 CONFIG_NOP_USB_XCEIV=y
 CONFIG_DUAL_ROLE_USB_INTF=y
 CONFIG_USB_GADGET=y
@@ -369,6 +379,9 @@
 CONFIG_USB_CI13XXX_MSM=y
 CONFIG_USB_CONFIGFS=y
 CONFIG_USB_CONFIGFS_SERIAL=y
+CONFIG_USB_CONFIGFS_NCM=y
+CONFIG_USB_CONFIGFS_RMNET_BAM=y
+CONFIG_USB_CONFIGFS_MASS_STORAGE=y
 CONFIG_USB_CONFIGFS_F_FS=y
 CONFIG_USB_CONFIGFS_UEVENT=y
 CONFIG_USB_CONFIGFS_F_DIAG=y
@@ -400,6 +413,8 @@
 CONFIG_ANDROID_LOW_MEMORY_KILLER=y
 CONFIG_ION=y
 CONFIG_ION_MSM=y
+CONFIG_IPA=y
+CONFIG_RMNET_IPA=y
 CONFIG_SPS=y
 CONFIG_SPS_SUPPORT_NDP_BAM=y
 CONFIG_QPNP_REVID=y
@@ -422,6 +437,7 @@
 CONFIG_MSM_SMD=y
 CONFIG_MSM_SMD_DEBUG=y
 CONFIG_MSM_GLINK=y
+CONFIG_MSM_TZ_SMMU=y
 CONFIG_MSM_GLINK_LOOPBACK_SERVER=y
 CONFIG_MSM_GLINK_SMEM_NATIVE_XPRT=y
 CONFIG_MSM_GLINK_SPI_XPRT=y
@@ -433,9 +449,12 @@
 CONFIG_MSM_GLINK_PKT=y
 CONFIG_MSM_SUBSYSTEM_RESTART=y
 CONFIG_MSM_PIL=y
+CONFIG_MSM_PIL_SSR_GENERIC=y
+CONFIG_MSM_PIL_MSS_QDSP6V5=y
 CONFIG_MSM_EVENT_TIMER=y
 CONFIG_QTI_RPM_STATS_LOG=y
 CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y
+CONFIG_MSM_BAM_DMUX=y
 CONFIG_CNSS_CRYPTO=y
 CONFIG_PWM=y
 CONFIG_PWM_QPNP=y
@@ -480,8 +499,13 @@
 CONFIG_PID_IN_CONTEXTIDR=y
 CONFIG_DEBUG_SET_MODULE_RONX=y
 CONFIG_CORESIGHT=y
+CONFIG_CORESIGHT_LINK_AND_SINK_TMC=y
+CONFIG_CORESIGHT_SINK_TPIU=y
+CONFIG_CORESIGHT_SOURCE_ETM3X=y
 CONFIG_CORESIGHT_REMOTE_ETM=y
 CONFIG_CORESIGHT_REMOTE_ETM_DEFAULT_ENABLE=0
+CONFIG_CORESIGHT_QCOM_REPLICATOR=y
+CONFIG_CORESIGHT_DBGUI=y
 CONFIG_CORESIGHT_STM=y
 CONFIG_CORESIGHT_TPDA=y
 CONFIG_CORESIGHT_TPDM=y
@@ -496,13 +520,14 @@
 CONFIG_SECURITY_SMACK=y
 CONFIG_SECURITY_APPARMOR=y
 CONFIG_DEFAULT_SECURITY_DAC=y
-CONFIG_CRYPTO_CTR=y
-CONFIG_CRYPTO_XTS=y
 CONFIG_CRYPTO_XCBC=y
+CONFIG_CRYPTO_CRC32=y
 CONFIG_CRYPTO_MD4=y
 CONFIG_CRYPTO_TWOFISH=y
 CONFIG_CRYPTO_ANSI_CPRNG=y
+CONFIG_CRYPTO_DEV_QCE=y
 CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y
+CONFIG_CRYPTO_DEV_QCEDEV=y
 CONFIG_CRYPTO_DEV_OTA_CRYPTO=y
 CONFIG_CRYPTO_DEV_QCOM_ICE=y
 CONFIG_ARM_CRYPTO=y
diff --git a/arch/arm/configs/msm8909_defconfig b/arch/arm/configs/msm8909_defconfig
index bab3132..9eb0afd 100644
--- a/arch/arm/configs/msm8909_defconfig
+++ b/arch/arm/configs/msm8909_defconfig
@@ -27,11 +27,14 @@
 CONFIG_SCHED_TUNE=y
 CONFIG_DEFAULT_USE_ENERGY_AWARE=y
 CONFIG_BLK_DEV_INITRD=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
 CONFIG_KALLSYMS_ALL=y
 CONFIG_BPF_SYSCALL=y
 CONFIG_EMBEDDED=y
 CONFIG_PROFILING=y
-CONFIG_OPROFILE=y
+CONFIG_OPROFILE=m
+CONFIG_KPROBES=y
+CONFIG_CC_STACKPROTECTOR_REGULAR=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 CONFIG_MODULE_FORCE_UNLOAD=y
@@ -138,6 +141,7 @@
 CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
 CONFIG_NETFILTER_XT_MATCH_QUOTA=y
 CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y
 CONFIG_NETFILTER_XT_MATCH_SOCKET=y
 CONFIG_NETFILTER_XT_MATCH_STATE=y
 CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
@@ -257,16 +261,25 @@
 CONFIG_CNSS_SDIO=y
 CONFIG_CLD_HL_SDIO_CORE=y
 CONFIG_INPUT_EVDEV=y
+CONFIG_INPUT_EVBUG=y
 CONFIG_KEYBOARD_GPIO=y
+# CONFIG_INPUT_MOUSE is not set
 CONFIG_INPUT_JOYSTICK=y
+CONFIG_JOYSTICK_XPAD=y
 CONFIG_INPUT_TOUCHSCREEN=y
 CONFIG_INPUT_MISC=y
 CONFIG_INPUT_QPNP_POWER_ON=y
 CONFIG_INPUT_UINPUT=y
+CONFIG_INPUT_GPIO=y
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_DEVMEM is not set
+# CONFIG_DEVKMEM is not set
 CONFIG_SERIAL_MSM=y
 CONFIG_SERIAL_MSM_CONSOLE=y
 CONFIG_SERIAL_MSM_HS=y
 CONFIG_SERIAL_MSM_SMD=y
+CONFIG_DIAG_CHAR=y
+CONFIG_DIAG_USES_SMD=y
 CONFIG_HW_RANDOM=y
 CONFIG_HW_RANDOM_MSM_LEGACY=y
 CONFIG_MSM_SMD_PKT=y
@@ -350,11 +363,16 @@
 CONFIG_HID_MICROSOFT=y
 CONFIG_HID_MONTEREY=y
 CONFIG_HID_MULTITOUCH=y
-CONFIG_USB=y
 CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
 CONFIG_USB_MON=y
 CONFIG_USB_EHCI_HCD=y
 CONFIG_USB_EHCI_MSM=y
+CONFIG_USB_ACM=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_DWC3=y
+CONFIG_USB_DWC3_GADGET=y
+CONFIG_USB_SERIAL=y
+CONFIG_USB_EHSET_TEST_FIXTURE=y
 CONFIG_NOP_USB_XCEIV=y
 CONFIG_DUAL_ROLE_USB_INTF=y
 CONFIG_USB_GADGET=y
@@ -364,7 +382,12 @@
 CONFIG_USB_CI13XXX_MSM=y
 CONFIG_USB_CONFIGFS=y
 CONFIG_USB_CONFIGFS_SERIAL=y
+CONFIG_USB_CONFIGFS_NCM=y
+CONFIG_USB_CONFIGFS_RMNET_BAM=y
+CONFIG_USB_CONFIGFS_MASS_STORAGE=y
 CONFIG_USB_CONFIGFS_F_FS=y
+CONFIG_USB_CONFIGFS_F_MTP=y
+CONFIG_USB_CONFIGFS_F_PTP=y
 CONFIG_USB_CONFIGFS_UEVENT=y
 CONFIG_USB_CONFIGFS_F_DIAG=y
 CONFIG_USB_CONFIGFS_F_CDEV=y
@@ -395,6 +418,8 @@
 CONFIG_ANDROID_LOW_MEMORY_KILLER=y
 CONFIG_ION=y
 CONFIG_ION_MSM=y
+CONFIG_IPA=y
+CONFIG_RMNET_IPA=y
 CONFIG_SPS=y
 CONFIG_SPS_SUPPORT_NDP_BAM=y
 CONFIG_QPNP_REVID=y
@@ -417,6 +442,7 @@
 CONFIG_MSM_SMD=y
 CONFIG_MSM_SMD_DEBUG=y
 CONFIG_MSM_GLINK=y
+CONFIG_MSM_TZ_SMMU=y
 CONFIG_MSM_GLINK_LOOPBACK_SERVER=y
 CONFIG_MSM_GLINK_SMEM_NATIVE_XPRT=y
 CONFIG_MSM_GLINK_SPI_XPRT=y
@@ -428,10 +454,14 @@
 CONFIG_MSM_GLINK_PKT=y
 CONFIG_MSM_SUBSYSTEM_RESTART=y
 CONFIG_MSM_PIL=y
+CONFIG_MSM_PIL_SSR_GENERIC=y
+CONFIG_MSM_PIL_MSS_QDSP6V5=y
 CONFIG_MSM_EVENT_TIMER=y
 CONFIG_QTI_RPM_STATS_LOG=y
 CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y
+CONFIG_MSM_BAM_DMUX=y
 CONFIG_CNSS_CRYPTO=y
+CONFIG_QCOM_DEVFREQ_DEVBW=y
 CONFIG_PWM=y
 CONFIG_PWM_QPNP=y
 CONFIG_QTI_MPM=y
@@ -445,13 +475,16 @@
 CONFIG_EXT4_FS_SECURITY=y
 CONFIG_QUOTA=y
 CONFIG_QUOTA_NETLINK_INTERFACE=y
+# CONFIG_PRINT_QUOTA_WARNING is not set
 CONFIG_FUSE_FS=y
 CONFIG_MSDOS_FS=y
 CONFIG_VFAT_FS=y
 CONFIG_TMPFS=y
 CONFIG_ECRYPT_FS=y
 CONFIG_ECRYPT_FS_MESSAGING=y
+CONFIG_SDCARD_FS=y
 CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ASCII=y
 CONFIG_NLS_ISO8859_1=y
 CONFIG_PRINTK_TIME=y
 CONFIG_DYNAMIC_DEBUG=y
@@ -476,6 +509,7 @@
 CONFIG_DEBUG_STACK_USAGE=y
 CONFIG_DEBUG_MEMORY_INIT=y
 CONFIG_LOCKUP_DETECTOR=y
+CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC=y
 # CONFIG_DETECT_HUNG_TASK is not set
 CONFIG_WQ_WATCHDOG=y
 CONFIG_PANIC_TIMEOUT=5
@@ -506,8 +540,13 @@
 CONFIG_PID_IN_CONTEXTIDR=y
 CONFIG_DEBUG_SET_MODULE_RONX=y
 CONFIG_CORESIGHT=y
+CONFIG_CORESIGHT_LINK_AND_SINK_TMC=y
+CONFIG_CORESIGHT_SINK_TPIU=y
+CONFIG_CORESIGHT_SOURCE_ETM3X=y
 CONFIG_CORESIGHT_REMOTE_ETM=y
 CONFIG_CORESIGHT_REMOTE_ETM_DEFAULT_ENABLE=0
+CONFIG_CORESIGHT_QCOM_REPLICATOR=y
+CONFIG_CORESIGHT_DBGUI=y
 CONFIG_CORESIGHT_STM=y
 CONFIG_CORESIGHT_TPDA=y
 CONFIG_CORESIGHT_TPDM=y
@@ -525,10 +564,13 @@
 CONFIG_CRYPTO_CTR=y
 CONFIG_CRYPTO_XTS=y
 CONFIG_CRYPTO_XCBC=y
+CONFIG_CRYPTO_CRC32=y
 CONFIG_CRYPTO_MD4=y
 CONFIG_CRYPTO_TWOFISH=y
 CONFIG_CRYPTO_ANSI_CPRNG=y
 CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y
+CONFIG_CRYPTO_DEV_QCRYPTO=y
+CONFIG_CRYPTO_DEV_QCEDEV=y
 CONFIG_CRYPTO_DEV_OTA_CRYPTO=y
 CONFIG_CRYPTO_DEV_QCOM_ICE=y
 CONFIG_ARM_CRYPTO=y
diff --git a/arch/arm/configs/msm8909w_defconfig b/arch/arm/configs/msm8909w_defconfig
index 2eb602b..3c60037 100644
--- a/arch/arm/configs/msm8909w_defconfig
+++ b/arch/arm/configs/msm8909w_defconfig
@@ -6,7 +6,6 @@
 CONFIG_IRQ_TIME_ACCOUNTING=y
 CONFIG_SCHED_WALT=y
 CONFIG_TASKSTATS=y
-CONFIG_TASK_DELAY_ACCT=y
 CONFIG_TASK_XACCT=y
 CONFIG_TASK_IO_ACCOUNTING=y
 CONFIG_RCU_EXPERT=y
@@ -18,7 +17,6 @@
 CONFIG_LOG_CPU_MAX_BUF_SHIFT=17
 CONFIG_CGROUP_DEBUG=y
 CONFIG_CGROUP_FREEZER=y
-CONFIG_CPUSETS=y
 CONFIG_CGROUP_CPUACCT=y
 CONFIG_CGROUP_SCHEDTUNE=y
 CONFIG_RT_GROUP_SCHED=y
@@ -29,12 +27,18 @@
 CONFIG_SCHED_TUNE=y
 CONFIG_DEFAULT_USE_ENERGY_AWARE=y
 CONFIG_BLK_DEV_INITRD=y
+# CONFIG_RD_BZIP2 is not set
+# CONFIG_RD_LZMA is not set
+# CONFIG_RD_XZ is not set
+# CONFIG_RD_LZO is not set
+# CONFIG_RD_LZ4 is not set
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
 CONFIG_KALLSYMS_ALL=y
 CONFIG_BPF_SYSCALL=y
 CONFIG_EMBEDDED=y
+# CONFIG_SLUB_DEBUG is not set
 CONFIG_PROFILING=y
-CONFIG_OPROFILE=y
+CONFIG_OPROFILE=m
 CONFIG_CC_STACKPROTECTOR_REGULAR=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
@@ -50,11 +54,11 @@
 CONFIG_SCHED_MC=y
 CONFIG_PREEMPT=y
 CONFIG_AEABI=y
-CONFIG_HIGHMEM=y
 CONFIG_CMA=y
 CONFIG_CMA_DEBUGFS=y
 CONFIG_ZSMALLOC=y
 CONFIG_BALANCE_ANON_FILE_RECLAIM=y
+CONFIG_PROCESS_RECLAIM=y
 CONFIG_SECCOMP=y
 CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE=y
 CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y
@@ -65,12 +69,10 @@
 CONFIG_PM_AUTOSLEEP=y
 CONFIG_PM_WAKELOCKS=y
 CONFIG_PM_WAKELOCKS_LIMIT=0
-CONFIG_PM_DEBUG=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
 CONFIG_XFRM_USER=y
-CONFIG_XFRM_STATISTICS=y
 CONFIG_NET_KEY=y
 CONFIG_INET=y
 CONFIG_IP_MULTICAST=y
@@ -111,14 +113,13 @@
 CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y
 CONFIG_NETFILTER_XT_TARGET_CONNMARK=y
 CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y
+CONFIG_NETFILTER_XT_TARGET_CT=y
 CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y
 CONFIG_NETFILTER_XT_TARGET_HARDIDLETIMER=y
 CONFIG_NETFILTER_XT_TARGET_LOG=y
 CONFIG_NETFILTER_XT_TARGET_MARK=y
 CONFIG_NETFILTER_XT_TARGET_NFLOG=y
 CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y
-CONFIG_NETFILTER_XT_TARGET_NOTRACK=y
-CONFIG_NETFILTER_XT_TARGET_TEE=y
 CONFIG_NETFILTER_XT_TARGET_TPROXY=y
 CONFIG_NETFILTER_XT_TARGET_TRACE=y
 CONFIG_NETFILTER_XT_TARGET_SECMARK=y
@@ -128,7 +129,6 @@
 CONFIG_NETFILTER_XT_MATCH_CONNMARK=y
 CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
 CONFIG_NETFILTER_XT_MATCH_DSCP=y
-CONFIG_NETFILTER_XT_MATCH_ESP=y
 CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y
 CONFIG_NETFILTER_XT_MATCH_HELPER=y
 CONFIG_NETFILTER_XT_MATCH_IPRANGE=y
@@ -150,6 +150,7 @@
 CONFIG_NETFILTER_XT_MATCH_TIME=y
 CONFIG_NETFILTER_XT_MATCH_U32=y
 CONFIG_NF_CONNTRACK_IPV4=y
+CONFIG_NF_DUP_IPV4=y
 CONFIG_IP_NF_IPTABLES=y
 CONFIG_IP_NF_MATCH_AH=y
 CONFIG_IP_NF_MATCH_ECN=y
@@ -168,14 +169,13 @@
 CONFIG_IP_NF_ARPFILTER=y
 CONFIG_IP_NF_ARP_MANGLE=y
 CONFIG_NF_CONNTRACK_IPV6=y
+CONFIG_NF_DUP_IPV6=y
 CONFIG_IP6_NF_IPTABLES=y
 CONFIG_IP6_NF_MATCH_RPFILTER=y
 CONFIG_IP6_NF_FILTER=y
 CONFIG_IP6_NF_TARGET_REJECT=y
 CONFIG_IP6_NF_MANGLE=y
 CONFIG_IP6_NF_RAW=y
-CONFIG_BRIDGE_NF_EBTABLES=y
-CONFIG_BRIDGE_EBT_BROUTE=y
 CONFIG_L2TP=y
 CONFIG_L2TP_DEBUGFS=y
 CONFIG_L2TP_V3=y
@@ -185,8 +185,6 @@
 CONFIG_NET_SCHED=y
 CONFIG_NET_SCH_HTB=y
 CONFIG_NET_SCH_PRIO=y
-CONFIG_NET_SCH_MULTIQ=y
-CONFIG_NET_SCH_INGRESS=y
 CONFIG_NET_CLS_FW=y
 CONFIG_NET_CLS_U32=y
 CONFIG_CLS_U32_MARK=y
@@ -199,8 +197,6 @@
 CONFIG_NET_EMATCH_TEXT=y
 CONFIG_NET_CLS_ACT=y
 CONFIG_NET_ACT_GACT=y
-CONFIG_NET_ACT_MIRRED=y
-CONFIG_NET_ACT_SKBEDIT=y
 CONFIG_DNS_RESOLVER=y
 CONFIG_RMNET_DATA=y
 CONFIG_RMNET_DATA_FC=y
@@ -219,26 +215,11 @@
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_SIZE=8192
-CONFIG_HDCP_QSEECOM=y
 CONFIG_QSEECOM=y
 CONFIG_UID_SYS_STATS=y
-CONFIG_MEMORY_STATE_TIME=y
 CONFIG_QPNP_MISC=y
-CONFIG_SCSI=y
-CONFIG_BLK_DEV_SD=y
-CONFIG_CHR_DEV_SG=y
-CONFIG_CHR_DEV_SCH=y
-CONFIG_SCSI_CONSTANTS=y
-CONFIG_SCSI_LOGGING=y
-CONFIG_SCSI_SCAN_ASYNC=y
-CONFIG_SCSI_UFSHCD=y
-CONFIG_SCSI_UFSHCD_PLATFORM=y
-CONFIG_SCSI_UFS_QCOM=y
-CONFIG_SCSI_UFS_QCOM_ICE=y
-CONFIG_SCSI_UFSHCD_CMD_LOGGING=y
 CONFIG_MD=y
 CONFIG_BLK_DEV_DM=y
-CONFIG_DM_DEBUG=y
 CONFIG_DM_CRYPT=y
 CONFIG_DM_UEVENT=y
 CONFIG_DM_VERITY=y
@@ -262,7 +243,6 @@
 CONFIG_CLD_LL_CORE=y
 CONFIG_INPUT_EVDEV=y
 CONFIG_KEYBOARD_GPIO=y
-CONFIG_INPUT_JOYSTICK=y
 CONFIG_INPUT_TOUCHSCREEN=y
 CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_CORE_v26=y
 CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_RMI_DEV_v26=y
@@ -343,25 +323,7 @@
 CONFIG_SND_DYNAMIC_MINORS=y
 CONFIG_SND_SOC=y
 CONFIG_UHID=y
-CONFIG_HID_A4TECH=y
-CONFIG_HID_APPLE=y
-CONFIG_HID_BELKIN=y
-CONFIG_HID_CHERRY=y
-CONFIG_HID_CHICONY=y
-CONFIG_HID_CYPRESS=y
-CONFIG_HID_ELECOM=y
-CONFIG_HID_EZKEY=y
-CONFIG_HID_KENSINGTON=y
-CONFIG_HID_LOGITECH=y
-CONFIG_HID_MAGICMOUSE=y
-CONFIG_HID_MICROSOFT=y
-CONFIG_HID_MONTEREY=y
-CONFIG_HID_MULTITOUCH=y
-CONFIG_USB_DWC3=y
-CONFIG_NOP_USB_XCEIV=y
 CONFIG_DUAL_ROLE_USB_INTF=y
-CONFIG_USB_MSM_SSPHY_QMP=y
-CONFIG_MSM_QUSB_PHY=y
 CONFIG_USB_GADGET=y
 CONFIG_USB_GADGET_DEBUG_FILES=y
 CONFIG_USB_GADGET_DEBUG_FS=y
@@ -369,15 +331,10 @@
 CONFIG_USB_CI13XXX_MSM=y
 CONFIG_USB_CONFIGFS=y
 CONFIG_USB_CONFIGFS_SERIAL=y
-CONFIG_USB_CONFIGFS_ACM=y
 CONFIG_USB_CONFIGFS_NCM=y
-CONFIG_USB_CONFIGFS_ECM=y
 CONFIG_USB_CONFIGFS_RMNET_BAM=y
-CONFIG_USB_CONFIGFS_EEM=y
 CONFIG_USB_CONFIGFS_MASS_STORAGE=y
 CONFIG_USB_CONFIGFS_F_FS=y
-CONFIG_USB_CONFIGFS_F_MTP=y
-CONFIG_USB_CONFIGFS_F_PTP=y
 CONFIG_USB_CONFIGFS_F_ACC=y
 CONFIG_USB_CONFIGFS_F_AUDIO_SRC=y
 CONFIG_USB_CONFIGFS_UEVENT=y
@@ -386,7 +343,6 @@
 CONFIG_USB_CONFIGFS_F_DIAG=y
 CONFIG_USB_CONFIGFS_F_CDEV=y
 CONFIG_USB_CONFIGFS_F_CCID=y
-CONFIG_USB_CONFIGFS_F_GSI=y
 CONFIG_MMC=y
 CONFIG_MMC_PERF_PROFILING=y
 CONFIG_MMC_RING_BUFFER=y
@@ -477,15 +433,12 @@
 CONFIG_ANDROID_BINDER_IPC=y
 CONFIG_SENSORS_SSC=y
 CONFIG_MSM_TZ_LOG=y
-CONFIG_EXT2_FS=y
-CONFIG_EXT2_FS_XATTR=y
-CONFIG_EXT3_FS=y
+CONFIG_EXT4_FS=y
 CONFIG_EXT4_FS_SECURITY=y
 CONFIG_QUOTA=y
 CONFIG_QUOTA_NETLINK_INTERFACE=y
 CONFIG_QFMT_V2=y
 CONFIG_FUSE_FS=y
-CONFIG_MSDOS_FS=y
 CONFIG_VFAT_FS=y
 CONFIG_TMPFS=y
 CONFIG_ECRYPT_FS=y
@@ -500,15 +453,7 @@
 CONFIG_PAGE_OWNER_ENABLE_DEFAULT=y
 CONFIG_MAGIC_SYSRQ=y
 CONFIG_DEBUG_PAGEALLOC=y
-CONFIG_SLUB_DEBUG_PANIC_ON=y
 CONFIG_DEBUG_PAGEALLOC_ENABLE_DEFAULT=y
-CONFIG_DEBUG_OBJECTS=y
-CONFIG_DEBUG_OBJECTS_FREE=y
-CONFIG_DEBUG_OBJECTS_TIMERS=y
-CONFIG_DEBUG_OBJECTS_WORK=y
-CONFIG_DEBUG_OBJECTS_RCU_HEAD=y
-CONFIG_DEBUG_OBJECTS_PERCPU_COUNTER=y
-CONFIG_SLUB_DEBUG_ON=y
 CONFIG_DEBUG_KMEMLEAK=y
 CONFIG_DEBUG_KMEMLEAK_EARLY_LOG_SIZE=4000
 CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF=y
diff --git a/arch/arm/include/asm/etmv4x.h b/arch/arm/include/asm/etmv4x.h
new file mode 100644
index 0000000..7ad0a92
--- /dev/null
+++ b/arch/arm/include/asm/etmv4x.h
@@ -0,0 +1,387 @@
+/* Copyright (c) 2016, 2018, 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 __ASM_ETMV4X_H
+#define __ASM_ETMV4X_H
+
+#include <linux/types.h>
+
+
+/* 32 bit register read for AArch32 */
+#define trc_readl(reg)			RSYSL_##reg()
+#define trc_readq(reg)			RSYSL_##reg()
+
+/* 32 bit register write for AArch32 */
+#define trc_write(val, reg)		WSYS_##reg(val)
+
+#define MRC(op0, op1, crn, crm, op2)					    \
+({									    \
+uint32_t val;								    \
+asm volatile("mrc p"#op0", "#op1", %0, "#crn", "#crm", "#op2 : "=r" (val)); \
+val;									    \
+})
+
+#define MCR(val, op0, op1, crn, crm, op2)				    \
+({									    \
+asm volatile("mcr p"#op0", "#op1", %0, "#crn", "#crm", "#op2 : : "r" (val));\
+})
+
+/* Clock and Power Management Register */
+#define RSYSL_CPMR_EL1()		MRC(15, 7, c15, c0, 5)
+#define WSYS_CPMR_EL1(val)		MCR(val, 15, 7, c15, c0, 5)
+
+/*
+ * ETMv4 Registers
+ *
+ * Read only
+ * ETMAUTHSTATUS, ETMDEVARCH, ETMDEVID, ETMIDRn[0-13], ETMOSLSR, ETMSTATR
+ *
+ * Write only
+ * ETMOSLAR
+ */
+/* 32 bit registers */
+#define RSYSL_ETMAUTHSTATUS()		MRC(14, 1, c7, c14, 6)
+#define RSYSL_ETMAUXCTLR()		MRC(14, 1, c0, c6, 0)
+#define RSYSL_ETMCCCTLR()		MRC(14, 1, c0, c14, 0)
+#define RSYSL_ETMCIDCCTLR0()		MRC(14, 1, c3, c0, 2)
+#define RSYSL_ETMCNTCTLR0()		MRC(14, 1, c0, c4, 5)
+#define RSYSL_ETMCNTCTLR1()		MRC(14, 1, c0, c5, 5)
+#define RSYSL_ETMCNTCTLR2()		MRC(14, 1, c0, c6, 5)
+#define RSYSL_ETMCNTCTLR3()		MRC(14, 1, c0, c7, 5)
+#define RSYSL_ETMCNTRLDVR0()		MRC(14, 1, c0, c0, 5)
+#define RSYSL_ETMCNTRLDVR1()		MRC(14, 1, c0, c1, 5)
+#define RSYSL_ETMCNTRLDVR2()		MRC(14, 1, c0, c2, 5)
+#define RSYSL_ETMCNTRLDVR3()		MRC(14, 1, c0, c3, 5)
+#define RSYSL_ETMCNTVR0()		MRC(14, 1, c0, c8, 5)
+#define RSYSL_ETMCNTVR1()		MRC(14, 1, c0, c9, 5)
+#define RSYSL_ETMCNTVR2()		MRC(14, 1, c0, c10, 5)
+#define RSYSL_ETMCNTVR3()		MRC(14, 1, c0, c11, 5)
+#define RSYSL_ETMCONFIGR()		MRC(14, 1, c0, c4, 0)
+#define RSYSL_ETMDEVARCH()		MRC(14, 1, c7, c15, 6)
+#define RSYSL_ETMDEVID()		MRC(14, 1, c7, c2, 7)
+#define RSYSL_ETMEVENTCTL0R()		MRC(14, 1, c0, c8, 0)
+#define RSYSL_ETMEVENTCTL1R()		MRC(14, 1, c0, c9, 0)
+#define RSYSL_ETMEXTINSELR()		MRC(14, 1, c0, c8, 4)
+#define RSYSL_ETMIDR0()			MRC(14, 1, c0, c8, 7)
+#define RSYSL_ETMIDR1()			MRC(14, 1, c0, c9, 7)
+#define RSYSL_ETMIDR10()		MRC(14, 1, c0, c2, 6)
+#define RSYSL_ETMIDR11()		MRC(14, 1, c0, c3, 6)
+#define RSYSL_ETMIDR12()		MRC(14, 1, c0, c4, 6)
+#define RSYSL_ETMIDR13()		MRC(14, 1, c0, c5, 6)
+#define RSYSL_ETMIDR2()			MRC(14, 1, c0, c10, 7)
+#define RSYSL_ETMIDR3()			MRC(14, 1, c0, c11, 7)
+#define RSYSL_ETMIDR4()			MRC(14, 1, c0, c12, 7)
+#define RSYSL_ETMIDR5()			MRC(14, 1, c0, c13, 7)
+#define RSYSL_ETMIDR6()			MRC(14, 1, c0, c14, 7)
+#define RSYSL_ETMIDR7()			MRC(14, 1, c0, c15, 7)
+#define RSYSL_ETMIDR8()			MRC(14, 1, c0, c0, 6)
+#define RSYSL_ETMIDR9()			MRC(14, 1, c0, c1, 6)
+#define RSYSL_ETMIMSPEC0()		MRC(14, 1, c0, c0, 7)
+#define RSYSL_ETMOSLSR()		MRC(14, 1, c1, c1, 4)
+#define RSYSL_ETMPRGCTLR()		MRC(14, 1, c0, c1, 0)
+#define RSYSL_ETMRSCTLR10()		MRC(14, 1, c1, c10, 0)
+#define RSYSL_ETMRSCTLR11()		MRC(14, 1, c1, c11, 0)
+#define RSYSL_ETMRSCTLR12()		MRC(14, 1, c1, c12, 0)
+#define RSYSL_ETMRSCTLR13()		MRC(14, 1, c1, c13, 0)
+#define RSYSL_ETMRSCTLR14()		MRC(14, 1, c1, c14, 0)
+#define RSYSL_ETMRSCTLR15()		MRC(14, 1, c1, c15, 0)
+#define RSYSL_ETMRSCTLR2()		MRC(14, 1, c1, c2, 0)
+#define RSYSL_ETMRSCTLR3()		MRC(14, 1, c1, c3, 0)
+#define RSYSL_ETMRSCTLR4()		MRC(14, 1, c1, c4, 0)
+#define RSYSL_ETMRSCTLR5()		MRC(14, 1, c1, c5, 0)
+#define RSYSL_ETMRSCTLR6()		MRC(14, 1, c1, c6, 0)
+#define RSYSL_ETMRSCTLR7()		MRC(14, 1, c1, c7, 0)
+#define RSYSL_ETMRSCTLR8()		MRC(14, 1, c1, c8, 0)
+#define RSYSL_ETMRSCTLR9()		MRC(14, 1, c1, c9, 0)
+#define RSYSL_ETMRSCTLR16()		MRC(14, 1, c1, c0, 1)
+#define RSYSL_ETMRSCTLR17()		MRC(14, 1, c1, c1, 1)
+#define RSYSL_ETMRSCTLR18()		MRC(14, 1, c1, c2, 1)
+#define RSYSL_ETMRSCTLR19()		MRC(14, 1, c1, c3, 1)
+#define RSYSL_ETMRSCTLR20()		MRC(14, 1, c1, c4, 1)
+#define RSYSL_ETMRSCTLR21()		MRC(14, 1, c1, c5, 1)
+#define RSYSL_ETMRSCTLR22()		MRC(14, 1, c1, c6, 1)
+#define RSYSL_ETMRSCTLR23()		MRC(14, 1, c1, c7, 1)
+#define RSYSL_ETMRSCTLR24()		MRC(14, 1, c1, c8, 1)
+#define RSYSL_ETMRSCTLR25()		MRC(14, 1, c1, c9, 1)
+#define RSYSL_ETMRSCTLR26()		MRC(14, 1, c1, c10, 1)
+#define RSYSL_ETMRSCTLR27()		MRC(14, 1, c1, c11, 1)
+#define RSYSL_ETMRSCTLR28()		MRC(14, 1, c1, c12, 1)
+#define RSYSL_ETMRSCTLR29()		MRC(14, 1, c1, c13, 1)
+#define RSYSL_ETMRSCTLR30()		MRC(14, 1, c1, c14, 1)
+#define RSYSL_ETMRSCTLR31()		MRC(14, 1, c1, c15, 1)
+#define RSYSL_ETMSEQEVR0()		MRC(14, 1, c0, c0, 4)
+#define RSYSL_ETMSEQEVR1()		MRC(14, 1, c0, c1, 4)
+#define RSYSL_ETMSEQEVR2()		MRC(14, 1, c0, c2, 4)
+#define RSYSL_ETMSEQRSTEVR()		MRC(14, 1, c0, c6, 4)
+#define RSYSL_ETMSEQSTR()		MRC(14, 1, c0, c7, 4)
+#define RSYSL_ETMSTALLCTLR()		MRC(14, 1, c0, c11, 0)
+#define RSYSL_ETMSTATR()		MRC(14, 1, c0, c3, 0)
+#define RSYSL_ETMSYNCPR()		MRC(14, 1, c0, c13, 0)
+#define RSYSL_ETMTRACEIDR()		MRC(14, 1, c0, c0, 1)
+#define RSYSL_ETMTSCTLR()		MRC(14, 1, c0, c12, 0)
+#define RSYSL_ETMVICTLR()		MRC(14, 1, c0, c0, 2)
+#define RSYSL_ETMVIIECTLR()		MRC(14, 1, c0, c1, 2)
+#define RSYSL_ETMVISSCTLR()		MRC(14, 1, c0, c2, 2)
+#define RSYSL_ETMSSCCR0()		MRC(14, 1, c1, c0, 2)
+#define RSYSL_ETMSSCCR1()		MRC(14, 1, c1, c1, 2)
+#define RSYSL_ETMSSCCR2()		MRC(14, 1, c1, c2, 2)
+#define RSYSL_ETMSSCCR3()		MRC(14, 1, c1, c3, 2)
+#define RSYSL_ETMSSCCR4()		MRC(14, 1, c1, c4, 2)
+#define RSYSL_ETMSSCCR5()		MRC(14, 1, c1, c5, 2)
+#define RSYSL_ETMSSCCR6()		MRC(14, 1, c1, c6, 2)
+#define RSYSL_ETMSSCCR7()		MRC(14, 1, c1, c7, 2)
+#define RSYSL_ETMSSCSR0()		MRC(14, 1, c1, c8, 2)
+#define RSYSL_ETMSSCSR1()		MRC(14, 1, c1, c9, 2)
+#define RSYSL_ETMSSCSR2()		MRC(14, 1, c1, c10, 2)
+#define RSYSL_ETMSSCSR3()		MRC(14, 1, c1, c11, 2)
+#define RSYSL_ETMSSCSR4()		MRC(14, 1, c1, c12, 2)
+#define RSYSL_ETMSSCSR5()		MRC(14, 1, c1, c13, 2)
+#define RSYSL_ETMSSCSR6()		MRC(14, 1, c1, c14, 2)
+#define RSYSL_ETMSSCSR7()		MRC(14, 1, c1, c15, 2)
+#define RSYSL_ETMSSPCICR0()		MRC(14, 1, c1, c0, 3)
+#define RSYSL_ETMSSPCICR1()		MRC(14, 1, c1, c1, 3)
+#define RSYSL_ETMSSPCICR2()		MRC(14, 1, c1, c2, 3)
+#define RSYSL_ETMSSPCICR3()		MRC(14, 1, c1, c3, 3)
+#define RSYSL_ETMSSPCICR4()		MRC(14, 1, c1, c4, 3)
+#define RSYSL_ETMSSPCICR5()		MRC(14, 1, c1, c5, 3)
+#define RSYSL_ETMSSPCICR6()		MRC(14, 1, c1, c6, 3)
+#define RSYSL_ETMSSPCICR7()		MRC(14, 1, c1, c7, 3)
+
+/*
+ * 64 bit registers, ignore the upper 32bit
+ * A read from a 32-bit register location using a 64-bit access result
+ * in the upper 32bits being return as RES0.
+ */
+#define RSYSL_ETMACATR0()		MRC(14, 1, c2, c0, 2)
+#define RSYSL_ETMACATR1()		MRC(14, 1, c2, c2, 2)
+#define RSYSL_ETMACATR2()		MRC(14, 1, c2, c4, 2)
+#define RSYSL_ETMACATR3()		MRC(14, 1, c2, c6, 2)
+#define RSYSL_ETMACATR4()		MRC(14, 1, c2, c8, 2)
+#define RSYSL_ETMACATR5()		MRC(14, 1, c2, c10, 2)
+#define RSYSL_ETMACATR6()		MRC(14, 1, c2, c12, 2)
+#define RSYSL_ETMACATR7()		MRC(14, 1, c2, c14, 2)
+#define RSYSL_ETMACATR8()		MRC(14, 1, c2, c0, 3)
+#define RSYSL_ETMACATR9()		MRC(14, 1, c2, c2, 3)
+#define RSYSL_ETMACATR10()		MRC(14, 1, c2, c4, 3)
+#define RSYSL_ETMACATR11()		MRC(14, 1, c2, c6, 3)
+#define RSYSL_ETMACATR12()		MRC(14, 1, c2, c8, 3)
+#define RSYSL_ETMACATR13()		MRC(14, 1, c2, c10, 3)
+#define RSYSL_ETMACATR14()		MRC(14, 1, c2, c12, 3)
+#define RSYSL_ETMACATR15()		MRC(14, 1, c2, c14, 3)
+#define RSYSL_ETMCIDCVR0()		MRC(14, 1, c3, c0, 0)
+#define RSYSL_ETMCIDCVR1()		MRC(14, 1, c3, c2, 0)
+#define RSYSL_ETMCIDCVR2()		MRC(14, 1, c3, c4, 0)
+#define RSYSL_ETMCIDCVR3()		MRC(14, 1, c3, c6, 0)
+#define RSYSL_ETMCIDCVR4()		MRC(14, 1, c3, c8, 0)
+#define RSYSL_ETMCIDCVR5()		MRC(14, 1, c3, c10, 0)
+#define RSYSL_ETMCIDCVR6()		MRC(14, 1, c3, c12, 0)
+#define RSYSL_ETMCIDCVR7()		MRC(14, 1, c3, c14, 0)
+#define RSYSL_ETMACVR0()		MRC(14, 1, c2, c0, 0)
+#define RSYSL_ETMACVR1()		MRC(14, 1, c2, c2, 0)
+#define RSYSL_ETMACVR2()		MRC(14, 1, c2, c4, 0)
+#define RSYSL_ETMACVR3()		MRC(14, 1, c2, c6, 0)
+#define RSYSL_ETMACVR4()		MRC(14, 1, c2, c8, 0)
+#define RSYSL_ETMACVR5()		MRC(14, 1, c2, c10, 0)
+#define RSYSL_ETMACVR6()		MRC(14, 1, c2, c12, 0)
+#define RSYSL_ETMACVR7()		MRC(14, 1, c2, c14, 0)
+#define RSYSL_ETMACVR8()		MRC(14, 1, c2, c0, 1)
+#define RSYSL_ETMACVR9()		MRC(14, 1, c2, c2, 1)
+#define RSYSL_ETMACVR10()		MRC(14, 1, c2, c4, 1)
+#define RSYSL_ETMACVR11()		MRC(14, 1, c2, c6, 1)
+#define RSYSL_ETMACVR12()		MRC(14, 1, c2, c8, 1)
+#define RSYSL_ETMACVR13()		MRC(14, 1, c2, c10, 1)
+#define RSYSL_ETMACVR14()		MRC(14, 1, c2, c12, 1)
+#define RSYSL_ETMACVR15()		MRC(14, 1, c2, c14, 1)
+#define RSYSL_ETMVMIDCVR0()		MRC(14, 1, c3, c0, 1)
+#define RSYSL_ETMVMIDCVR1()		MRC(14, 1, c3, c2, 1)
+#define RSYSL_ETMVMIDCVR2()		MRC(14, 1, c3, c4, 1)
+#define RSYSL_ETMVMIDCVR3()		MRC(14, 1, c3, c6, 1)
+#define RSYSL_ETMVMIDCVR4()		MRC(14, 1, c3, c8, 1)
+#define RSYSL_ETMVMIDCVR5()		MRC(14, 1, c3, c10, 1)
+#define RSYSL_ETMVMIDCVR6()		MRC(14, 1, c3, c12, 1)
+#define RSYSL_ETMVMIDCVR7()		MRC(14, 1, c3, c14, 1)
+#define RSYSL_ETMDVCVR0()		MRC(14, 1, c2, c0, 4)
+#define RSYSL_ETMDVCVR1()		MRC(14, 1, c2, c4, 4)
+#define RSYSL_ETMDVCVR2()		MRC(14, 1, c2, c8, 4)
+#define RSYSL_ETMDVCVR3()		MRC(14, 1, c2, c12, 4)
+#define RSYSL_ETMDVCVR4()		MRC(14, 1, c2, c0, 5)
+#define RSYSL_ETMDVCVR5()		MRC(14, 1, c2, c4, 5)
+#define RSYSL_ETMDVCVR6()		MRC(14, 1, c2, c8, 5)
+#define RSYSL_ETMDVCVR7()		MRC(14, 1, c2, c12, 5)
+#define RSYSL_ETMDVCMR0()		MRC(14, 1, c2, c0, 6)
+#define RSYSL_ETMDVCMR1()		MRC(14, 1, c2, c4, 6)
+#define RSYSL_ETMDVCMR2()		MRC(14, 1, c2, c8, 6)
+#define RSYSL_ETMDVCMR3()		MRC(14, 1, c2, c12, 6)
+#define RSYSL_ETMDVCMR4()		MRC(14, 1, c2, c0, 7)
+#define RSYSL_ETMDVCMR5()		MRC(14, 1, c2, c4, 7)
+#define RSYSL_ETMDVCMR6()		MRC(14, 1, c2, c8, 7)
+#define RSYSL_ETMDVCMR7()		MRC(14, 1, c2, c12, 7)
+
+/*
+ * 32 and 64 bit registers
+ * A write to a 32-bit register location using a 64-bit access result
+ * in the upper 32bit of access
+ */
+#define WSYS_ETMAUXCTLR(val)		MCR(val, 14, 1, c0, c6, 0)
+#define WSYS_ETMACATR0(val)		MCR(val, 14, 1, c2, c0, 2)
+#define WSYS_ETMACATR1(val)		MCR(val, 14, 1, c2, c2, 2)
+#define WSYS_ETMACATR2(val)		MCR(val, 14, 1, c2, c4, 2)
+#define WSYS_ETMACATR3(val)		MCR(val, 14, 1, c2, c6, 2)
+#define WSYS_ETMACATR4(val)		MCR(val, 14, 1, c2, c8, 2)
+#define WSYS_ETMACATR5(val)		MCR(val, 14, 1, c2, c10, 2)
+#define WSYS_ETMACATR6(val)		MCR(val, 14, 1, c2, c12, 2)
+#define WSYS_ETMACATR7(val)		MCR(val, 14, 1, c2, c14, 2)
+#define WSYS_ETMACATR8(val)		MCR(val, 14, 1, c2, c0, 3)
+#define WSYS_ETMACATR9(val)		MCR(val, 14, 1, c2, c2, 3)
+#define WSYS_ETMACATR10(val)		MCR(val, 14, 1, c2, c4, 3)
+#define WSYS_ETMACATR11(val)		MCR(val, 14, 1, c2, c6, 3)
+#define WSYS_ETMACATR12(val)		MCR(val, 14, 1, c2, c8, 3)
+#define WSYS_ETMACATR13(val)		MCR(val, 14, 1, c2, c10, 3)
+#define WSYS_ETMACATR14(val)		MCR(val, 14, 1, c2, c12, 3)
+#define WSYS_ETMACATR15(val)		MCR(val, 14, 1, c2, c14, 3)
+#define WSYS_ETMACVR0(val)		MCR(val, 14, 1, c2, c0, 0)
+#define WSYS_ETMACVR1(val)		MCR(val, 14, 1, c2, c2, 0)
+#define WSYS_ETMACVR2(val)		MCR(val, 14, 1, c2, c4, 0)
+#define WSYS_ETMACVR3(val)		MCR(val, 14, 1, c2, c6, 0)
+#define WSYS_ETMACVR4(val)		MCR(val, 14, 1, c2, c8, 0)
+#define WSYS_ETMACVR5(val)		MCR(val, 14, 1, c2, c10, 0)
+#define WSYS_ETMACVR6(val)		MCR(val, 14, 1, c2, c12, 0)
+#define WSYS_ETMACVR7(val)		MCR(val, 14, 1, c2, c14, 0)
+#define WSYS_ETMACVR8(val)		MCR(val, 14, 1, c2, c0, 1)
+#define WSYS_ETMACVR9(val)		MCR(val, 14, 1, c2, c2, 1)
+#define WSYS_ETMACVR10(val)		MCR(val, 14, 1, c2, c4, 1)
+#define WSYS_ETMACVR11(val)		MCR(val, 14, 1, c2, c6, 1)
+#define WSYS_ETMACVR12(val)		MCR(val, 14, 1, c2, c8, 1)
+#define WSYS_ETMACVR13(val)		MCR(val, 14, 1, c2, c10, 1)
+#define WSYS_ETMACVR14(val)		MCR(val, 14, 1, c2, c12, 1)
+#define WSYS_ETMACVR15(val)		MCR(val, 14, 1, c2, c14, 1)
+#define WSYS_ETMCCCTLR(val)		MCR(val, 14, 1, c0, c14, 0)
+#define WSYS_ETMCIDCCTLR0(val)		MCR(val, 14, 1, c3, c0, 2)
+#define WSYS_ETMCIDCVR0(val)		MCR(val, 14, 1, c3, c0, 0)
+#define WSYS_ETMCIDCVR1(val)		MCR(val, 14, 1, c3, c2, 0)
+#define WSYS_ETMCIDCVR2(val)		MCR(val, 14, 1, c3, c4, 0)
+#define WSYS_ETMCIDCVR3(val)		MCR(val, 14, 1, c3, c6, 0)
+#define WSYS_ETMCIDCVR4(val)		MCR(val, 14, 1, c3, c8, 0)
+#define WSYS_ETMCIDCVR5(val)		MCR(val, 14, 1, c3, c10, 0)
+#define WSYS_ETMCIDCVR6(val)		MCR(val, 14, 1, c3, c12, 0)
+#define WSYS_ETMCIDCVR7(val)		MCR(val, 14, 1, c3, c14, 0)
+#define WSYS_ETMCNTCTLR0(val)		MCR(val, 14, 1, c0, c4, 5)
+#define WSYS_ETMCNTCTLR1(val)		MCR(val, 14, 1, c0, c5, 5)
+#define WSYS_ETMCNTCTLR2(val)		MCR(val, 14, 1, c0, c6, 5)
+#define WSYS_ETMCNTCTLR3(val)		MCR(val, 14, 1, c0, c7, 5)
+#define WSYS_ETMCNTRLDVR0(val)		MCR(val, 14, 1, c0, c0, 5)
+#define WSYS_ETMCNTRLDVR1(val)		MCR(val, 14, 1, c0, c1, 5)
+#define WSYS_ETMCNTRLDVR2(val)		MCR(val, 14, 1, c0, c2, 5)
+#define WSYS_ETMCNTRLDVR3(val)		MCR(val, 14, 1, c0, c3, 5)
+#define WSYS_ETMCNTVR0(val)		MCR(val, 14, 1, c0, c8, 5)
+#define WSYS_ETMCNTVR1(val)		MCR(val, 14, 1, c0, c9, 5)
+#define WSYS_ETMCNTVR2(val)		MCR(val, 14, 1, c0, c10, 5)
+#define WSYS_ETMCNTVR3(val)		MCR(val, 14, 1, c0, c11, 5)
+#define WSYS_ETMCONFIGR(val)		MCR(val, 14, 1, c0, c4, 0)
+#define WSYS_ETMEVENTCTL0R(val)		MCR(val, 14, 1, c0, c8, 0)
+#define WSYS_ETMEVENTCTL1R(val)		MCR(val, 14, 1, c0, c9, 0)
+#define WSYS_ETMEXTINSELR(val)		MCR(val, 14, 1, c0, c8, 4)
+#define WSYS_ETMIMSPEC0(val)		MCR(val, 14, 1, c0, c0, 7)
+#define WSYS_ETMOSLAR(val)		MCR(val, 14, 1, c1, c0, 4)
+#define WSYS_ETMPRGCTLR(val)		MCR(val, 14, 1, c0, c1, 0)
+#define WSYS_ETMRSCTLR10(val)		MCR(val, 14, 1, c1, c10, 0)
+#define WSYS_ETMRSCTLR11(val)		MCR(val, 14, 1, c1, c11, 0)
+#define WSYS_ETMRSCTLR12(val)		MCR(val, 14, 1, c1, c12, 0)
+#define WSYS_ETMRSCTLR13(val)		MCR(val, 14, 1, c1, c13, 0)
+#define WSYS_ETMRSCTLR14(val)		MCR(val, 14, 1, c1, c14, 0)
+#define WSYS_ETMRSCTLR15(val)		MCR(val, 14, 1, c1, c15, 0)
+#define WSYS_ETMRSCTLR2(val)		MCR(val, 14, 1, c1, c2, 0)
+#define WSYS_ETMRSCTLR3(val)		MCR(val, 14, 1, c1, c3, 0)
+#define WSYS_ETMRSCTLR4(val)		MCR(val, 14, 1, c1, c4, 0)
+#define WSYS_ETMRSCTLR5(val)		MCR(val, 14, 1, c1, c5, 0)
+#define WSYS_ETMRSCTLR6(val)		MCR(val, 14, 1, c1, c6, 0)
+#define WSYS_ETMRSCTLR7(val)		MCR(val, 14, 1, c1, c7, 0)
+#define WSYS_ETMRSCTLR8(val)		MCR(val, 14, 1, c1, c8, 0)
+#define WSYS_ETMRSCTLR9(val)		MCR(val, 14, 1, c1, c9, 0)
+#define WSYS_ETMRSCTLR16(val)		MCR(val, 14, 1, c1, c0, 1)
+#define WSYS_ETMRSCTLR17(val)		MCR(val, 14, 1, c1, c1, 1)
+#define WSYS_ETMRSCTLR18(val)		MCR(val, 14, 1, c1, c2, 1)
+#define WSYS_ETMRSCTLR19(val)		MCR(val, 14, 1, c1, c3, 1)
+#define WSYS_ETMRSCTLR20(val)		MCR(val, 14, 1, c1, c4, 1)
+#define WSYS_ETMRSCTLR21(val)		MCR(val, 14, 1, c1, c5, 1)
+#define WSYS_ETMRSCTLR22(val)		MCR(val, 14, 1, c1, c6, 1)
+#define WSYS_ETMRSCTLR23(val)		MCR(val, 14, 1, c1, c7, 1)
+#define WSYS_ETMRSCTLR24(val)		MCR(val, 14, 1, c1, c8, 1)
+#define WSYS_ETMRSCTLR25(val)		MCR(val, 14, 1, c1, c9, 1)
+#define WSYS_ETMRSCTLR26(val)		MCR(val, 14, 1, c1, c10, 1)
+#define WSYS_ETMRSCTLR27(val)		MCR(val, 14, 1, c1, c11, 1)
+#define WSYS_ETMRSCTLR28(val)		MCR(val, 14, 1, c1, c12, 1)
+#define WSYS_ETMRSCTLR29(val)		MCR(val, 14, 1, c1, c13, 1)
+#define WSYS_ETMRSCTLR30(val)		MCR(val, 14, 1, c1, c14, 1)
+#define WSYS_ETMRSCTLR31(val)		MCR(val, 14, 1, c1, c15, 1)
+#define WSYS_ETMSEQEVR0(val)		MCR(val, 14, 1, c0, c0, 4)
+#define WSYS_ETMSEQEVR1(val)		MCR(val, 14, 1, c0, c1, 4)
+#define WSYS_ETMSEQEVR2(val)		MCR(val, 14, 1, c0, c2, 4)
+#define WSYS_ETMSEQRSTEVR(val)		MCR(val, 14, 1, c0, c6, 4)
+#define WSYS_ETMSEQSTR(val)		MCR(val, 14, 1, c0, c7, 4)
+#define WSYS_ETMSTALLCTLR(val)		MCR(val, 14, 1, c0, c11, 0)
+#define WSYS_ETMSYNCPR(val)		MCR(val, 14, 1, c0, c13, 0)
+#define WSYS_ETMTRACEIDR(val)		MCR(val, 14, 1, c0, c0, 1)
+#define WSYS_ETMTSCTLR(val)		MCR(val, 14, 1, c0, c12, 0)
+#define WSYS_ETMVICTLR(val)		MCR(val, 14, 1, c0, c0, 2)
+#define WSYS_ETMVIIECTLR(val)		MCR(val, 14, 1, c0, c1, 2)
+#define WSYS_ETMVISSCTLR(val)		MCR(val, 14, 1, c0, c2, 2)
+#define WSYS_ETMVMIDCVR0(val)		MCR(val, 14, 1, c3, c0, 1)
+#define WSYS_ETMVMIDCVR1(val)		MCR(val, 14, 1, c3, c2, 1)
+#define WSYS_ETMVMIDCVR2(val)		MCR(val, 14, 1, c3, c4, 1)
+#define WSYS_ETMVMIDCVR3(val)		MCR(val, 14, 1, c3, c6, 1)
+#define WSYS_ETMVMIDCVR4(val)		MCR(val, 14, 1, c3, c8, 1)
+#define WSYS_ETMVMIDCVR5(val)		MCR(val, 14, 1, c3, c10, 1)
+#define WSYS_ETMVMIDCVR6(val)		MCR(val, 14, 1, c3, c12, 1)
+#define WSYS_ETMVMIDCVR7(val)		MCR(val, 14, 1, c3, c14, 1)
+#define WSYS_ETMDVCVR0(val)		MCR(val, 14, 1, c2, c0, 4)
+#define WSYS_ETMDVCVR1(val)		MCR(val, 14, 1, c2, c4, 4)
+#define WSYS_ETMDVCVR2(val)		MCR(val, 14, 1, c2, c8, 4)
+#define WSYS_ETMDVCVR3(val)		MCR(val, 14, 1, c2, c12, 4)
+#define WSYS_ETMDVCVR4(val)		MCR(val, 14, 1, c2, c0, 5)
+#define WSYS_ETMDVCVR5(val)		MCR(val, 14, 1, c2, c4, 5)
+#define WSYS_ETMDVCVR6(val)		MCR(val, 14, 1, c2, c8, 5)
+#define WSYS_ETMDVCVR7(val)		MCR(val, 14, 1, c2, c12, 5)
+#define WSYS_ETMDVCMR0(val)		MCR(val, 14, 1, c2, c0, 6)
+#define WSYS_ETMDVCMR1(val)		MCR(val, 14, 1, c2, c4, 6)
+#define WSYS_ETMDVCMR2(val)		MCR(val, 14, 1, c2, c8, 6)
+#define WSYS_ETMDVCMR3(val)		MCR(val, 14, 1, c2, c12, 6)
+#define WSYS_ETMDVCMR4(val)		MCR(val, 14, 1, c2, c0, 7)
+#define WSYS_ETMDVCMR5(val)		MCR(val, 14, 1, c2, c4, 7)
+#define WSYS_ETMDVCMR6(val)		MCR(val, 14, 1, c2, c8, 7)
+#define WSYS_ETMDVCMR7(val)		MCR(val, 14, 1, c2, c12, 7)
+#define WSYS_ETMSSCCR0(val)		MCR(val, 14, 1, c1, c0, 2)
+#define WSYS_ETMSSCCR1(val)		MCR(val, 14, 1, c1, c1, 2)
+#define WSYS_ETMSSCCR2(val)		MCR(val, 14, 1, c1, c2, 2)
+#define WSYS_ETMSSCCR3(val)		MCR(val, 14, 1, c1, c3, 2)
+#define WSYS_ETMSSCCR4(val)		MCR(val, 14, 1, c1, c4, 2)
+#define WSYS_ETMSSCCR5(val)		MCR(val, 14, 1, c1, c5, 2)
+#define WSYS_ETMSSCCR6(val)		MCR(val, 14, 1, c1, c6, 2)
+#define WSYS_ETMSSCCR7(val)		MCR(val, 14, 1, c1, c7, 2)
+#define WSYS_ETMSSCSR0(val)		MCR(val, 14, 1, c1, c8, 2)
+#define WSYS_ETMSSCSR1(val)		MCR(val, 14, 1, c1, c9, 2)
+#define WSYS_ETMSSCSR2(val)		MCR(val, 14, 1, c1, c10, 2)
+#define WSYS_ETMSSCSR3(val)		MCR(val, 14, 1, c1, c11, 2)
+#define WSYS_ETMSSCSR4(val)		MCR(val, 14, 1, c1, c12, 2)
+#define WSYS_ETMSSCSR5(val)		MCR(val, 14, 1, c1, c13, 2)
+#define WSYS_ETMSSCSR6(val)		MCR(val, 14, 1, c1, c14, 2)
+#define WSYS_ETMSSCSR7(val)		MCR(val, 14, 1, c1, c15, 2)
+#define WSYS_ETMSSPCICR0(val)		MCR(val, 14, 1, c1, c0, 3)
+#define WSYS_ETMSSPCICR1(val)		MCR(val, 14, 1, c1, c1, 3)
+#define WSYS_ETMSSPCICR2(val)		MCR(val, 14, 1, c1, c2, 3)
+#define WSYS_ETMSSPCICR3(val)		MCR(val, 14, 1, c1, c3, 3)
+#define WSYS_ETMSSPCICR4(val)		MCR(val, 14, 1, c1, c4, 3)
+#define WSYS_ETMSSPCICR5(val)		MCR(val, 14, 1, c1, c5, 3)
+#define WSYS_ETMSSPCICR6(val)		MCR(val, 14, 1, c1, c6, 3)
+#define WSYS_ETMSSPCICR7(val)		MCR(val, 14, 1, c1, c7, 3)
+
+#endif
diff --git a/arch/arm/include/asm/futex.h b/arch/arm/include/asm/futex.h
index 6795368..cc41438 100644
--- a/arch/arm/include/asm/futex.h
+++ b/arch/arm/include/asm/futex.h
@@ -128,20 +128,10 @@
 #endif /* !SMP */
 
 static inline int
-futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
+arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr)
 {
-	int op = (encoded_op >> 28) & 7;
-	int cmp = (encoded_op >> 24) & 15;
-	int oparg = (encoded_op << 8) >> 20;
-	int cmparg = (encoded_op << 20) >> 20;
 	int oldval = 0, ret, tmp;
 
-	if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
-		oparg = 1 << oparg;
-
-	if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
-		return -EFAULT;
-
 #ifndef CONFIG_SMP
 	preempt_disable();
 #endif
@@ -172,17 +162,9 @@
 	preempt_enable();
 #endif
 
-	if (!ret) {
-		switch (cmp) {
-		case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
-		case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
-		case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
-		case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
-		case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
-		case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
-		default: ret = -ENOSYS;
-		}
-	}
+	if (!ret)
+		*oval = oldval;
+
 	return ret;
 }
 
diff --git a/arch/arm/include/asm/hardware/debugv8.h b/arch/arm/include/asm/hardware/debugv8.h
new file mode 100644
index 0000000..a8249cd
--- /dev/null
+++ b/arch/arm/include/asm/hardware/debugv8.h
@@ -0,0 +1,247 @@
+/* Copyright (c) 2016, 2018, 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 __ASM_HARDWARE_DEBUGV8_H
+#define __ASM_HARDWARE_DEBUGV8_H
+
+#include <linux/types.h>
+
+/* Accessors for CP14 registers */
+#define dbg_read(reg)			RCP14_##reg()
+#define dbg_write(val, reg)		WCP14_##reg(val)
+
+/* MRC14 registers */
+#define MRC14(op1, crn, crm, op2)					\
+({									\
+uint32_t val;								\
+asm volatile("mrc p14, "#op1", %0, "#crn", "#crm", "#op2 : "=r" (val));	\
+val;									\
+})
+
+/* MCR14 registers */
+#define MCR14(val, op1, crn, crm, op2)					\
+({									\
+asm volatile("mcr p14, "#op1", %0, "#crn", "#crm", "#op2 : : "r" (val));\
+})
+
+/*
+ * Debug Registers
+ *
+ * Read only
+ * DBGDIDR, DBGDSCRint, DBGDTRRXint, DBGDRAR, DBGOSLSR, DBGOSSRR, DBGDSAR,
+ * DBGAUTHSTATUS, DBGDEVID2, DBGDEVID1, DBGDEVID
+ *
+ * Write only
+ * DBGDTRTXint, DBGOSLAR
+ */
+#define RCP14_DBGDIDR()			MRC14(0, c0, c0, 0)
+#define RCP14_DBGDSCRint()		MRC14(0, c0, c1, 0)
+#define RCP14_DBGDCCINT()		MRC14(0, c0, c2, 0)
+#define RCP14_DBGDTRRXint()		MRC14(0, c0, c5, 0)
+#define RCP14_DBGWFAR()			MRC14(0, c0, c6, 0)
+#define RCP14_DBGVCR()			MRC14(0, c0, c7, 0)
+#define RCP14_DBGDTRRXext()		MRC14(0, c0, c0, 2)
+#define RCP14_DBGDSCRext()		MRC14(0, c0, c2, 2)
+#define RCP14_DBGDTRTXext()		MRC14(0, c0, c3, 2)
+#define RCP14_DBGOSECCR()		MRC14(0, c0, c6, 2)
+#define RCP14_DBGBVR0()			MRC14(0, c0, c0, 4)
+#define RCP14_DBGBVR1()			MRC14(0, c0, c1, 4)
+#define RCP14_DBGBVR2()			MRC14(0, c0, c2, 4)
+#define RCP14_DBGBVR3()			MRC14(0, c0, c3, 4)
+#define RCP14_DBGBVR4()			MRC14(0, c0, c4, 4)
+#define RCP14_DBGBVR5()			MRC14(0, c0, c5, 4)
+#define RCP14_DBGBVR6()			MRC14(0, c0, c6, 4)
+#define RCP14_DBGBVR7()			MRC14(0, c0, c7, 4)
+#define RCP14_DBGBVR8()			MRC14(0, c0, c8, 4)
+#define RCP14_DBGBVR9()			MRC14(0, c0, c9, 4)
+#define RCP14_DBGBVR10()		MRC14(0, c0, c10, 4)
+#define RCP14_DBGBVR11()		MRC14(0, c0, c11, 4)
+#define RCP14_DBGBVR12()		MRC14(0, c0, c12, 4)
+#define RCP14_DBGBVR13()		MRC14(0, c0, c13, 4)
+#define RCP14_DBGBVR14()		MRC14(0, c0, c14, 4)
+#define RCP14_DBGBVR15()		MRC14(0, c0, c15, 4)
+#define RCP14_DBGBCR0()			MRC14(0, c0, c0, 5)
+#define RCP14_DBGBCR1()			MRC14(0, c0, c1, 5)
+#define RCP14_DBGBCR2()			MRC14(0, c0, c2, 5)
+#define RCP14_DBGBCR3()			MRC14(0, c0, c3, 5)
+#define RCP14_DBGBCR4()			MRC14(0, c0, c4, 5)
+#define RCP14_DBGBCR5()			MRC14(0, c0, c5, 5)
+#define RCP14_DBGBCR6()			MRC14(0, c0, c6, 5)
+#define RCP14_DBGBCR7()			MRC14(0, c0, c7, 5)
+#define RCP14_DBGBCR8()			MRC14(0, c0, c8, 5)
+#define RCP14_DBGBCR9()			MRC14(0, c0, c9, 5)
+#define RCP14_DBGBCR10()		MRC14(0, c0, c10, 5)
+#define RCP14_DBGBCR11()		MRC14(0, c0, c11, 5)
+#define RCP14_DBGBCR12()		MRC14(0, c0, c12, 5)
+#define RCP14_DBGBCR13()		MRC14(0, c0, c13, 5)
+#define RCP14_DBGBCR14()		MRC14(0, c0, c14, 5)
+#define RCP14_DBGBCR15()		MRC14(0, c0, c15, 5)
+#define RCP14_DBGWVR0()			MRC14(0, c0, c0, 6)
+#define RCP14_DBGWVR1()			MRC14(0, c0, c1, 6)
+#define RCP14_DBGWVR2()			MRC14(0, c0, c2, 6)
+#define RCP14_DBGWVR3()			MRC14(0, c0, c3, 6)
+#define RCP14_DBGWVR4()			MRC14(0, c0, c4, 6)
+#define RCP14_DBGWVR5()			MRC14(0, c0, c5, 6)
+#define RCP14_DBGWVR6()			MRC14(0, c0, c6, 6)
+#define RCP14_DBGWVR7()			MRC14(0, c0, c7, 6)
+#define RCP14_DBGWVR8()			MRC14(0, c0, c8, 6)
+#define RCP14_DBGWVR9()			MRC14(0, c0, c9, 6)
+#define RCP14_DBGWVR10()		MRC14(0, c0, c10, 6)
+#define RCP14_DBGWVR11()		MRC14(0, c0, c11, 6)
+#define RCP14_DBGWVR12()		MRC14(0, c0, c12, 6)
+#define RCP14_DBGWVR13()		MRC14(0, c0, c13, 6)
+#define RCP14_DBGWVR14()		MRC14(0, c0, c14, 6)
+#define RCP14_DBGWVR15()		MRC14(0, c0, c15, 6)
+#define RCP14_DBGWCR0()			MRC14(0, c0, c0, 7)
+#define RCP14_DBGWCR1()			MRC14(0, c0, c1, 7)
+#define RCP14_DBGWCR2()			MRC14(0, c0, c2, 7)
+#define RCP14_DBGWCR3()			MRC14(0, c0, c3, 7)
+#define RCP14_DBGWCR4()			MRC14(0, c0, c4, 7)
+#define RCP14_DBGWCR5()			MRC14(0, c0, c5, 7)
+#define RCP14_DBGWCR6()			MRC14(0, c0, c6, 7)
+#define RCP14_DBGWCR7()			MRC14(0, c0, c7, 7)
+#define RCP14_DBGWCR8()			MRC14(0, c0, c8, 7)
+#define RCP14_DBGWCR9()			MRC14(0, c0, c9, 7)
+#define RCP14_DBGWCR10()		MRC14(0, c0, c10, 7)
+#define RCP14_DBGWCR11()		MRC14(0, c0, c11, 7)
+#define RCP14_DBGWCR12()		MRC14(0, c0, c12, 7)
+#define RCP14_DBGWCR13()		MRC14(0, c0, c13, 7)
+#define RCP14_DBGWCR14()		MRC14(0, c0, c14, 7)
+#define RCP14_DBGWCR15()		MRC14(0, c0, c15, 7)
+#define RCP14_DBGDRAR()			MRC14(0, c1, c0, 0)
+#define RCP14_DBGBXVR0()		MRC14(0, c1, c0, 1)
+#define RCP14_DBGBXVR1()		MRC14(0, c1, c1, 1)
+#define RCP14_DBGBXVR2()		MRC14(0, c1, c2, 1)
+#define RCP14_DBGBXVR3()		MRC14(0, c1, c3, 1)
+#define RCP14_DBGBXVR4()		MRC14(0, c1, c4, 1)
+#define RCP14_DBGBXVR5()		MRC14(0, c1, c5, 1)
+#define RCP14_DBGBXVR6()		MRC14(0, c1, c6, 1)
+#define RCP14_DBGBXVR7()		MRC14(0, c1, c7, 1)
+#define RCP14_DBGBXVR8()		MRC14(0, c1, c8, 1)
+#define RCP14_DBGBXVR9()		MRC14(0, c1, c9, 1)
+#define RCP14_DBGBXVR10()		MRC14(0, c1, c10, 1)
+#define RCP14_DBGBXVR11()		MRC14(0, c1, c11, 1)
+#define RCP14_DBGBXVR12()		MRC14(0, c1, c12, 1)
+#define RCP14_DBGBXVR13()		MRC14(0, c1, c13, 1)
+#define RCP14_DBGBXVR14()		MRC14(0, c1, c14, 1)
+#define RCP14_DBGBXVR15()		MRC14(0, c1, c15, 1)
+#define RCP14_DBGOSLSR()		MRC14(0, c1, c1, 4)
+#define RCP14_DBGOSSRR()		MRC14(0, c1, c2, 4)
+#define RCP14_DBGOSDLR()		MRC14(0, c1, c3, 4)
+#define RCP14_DBGPRCR()			MRC14(0, c1, c4, 4)
+#define RCP14_DBGPRSR()			MRC14(0, c1, c5, 4)
+#define RCP14_DBGDSAR()			MRC14(0, c2, c0, 0)
+#define RCP14_DBGITCTRL()		MRC14(0, c7, c0, 4)
+#define RCP14_DBGCLAIMSET()		MRC14(0, c7, c8, 6)
+#define RCP14_DBGCLAIMCLR()		MRC14(0, c7, c9, 6)
+#define RCP14_DBGAUTHSTATUS()		MRC14(0, c7, c14, 6)
+#define RCP14_DBGDEVID2()		MRC14(0, c7, c0, 7)
+#define RCP14_DBGDEVID1()		MRC14(0, c7, c1, 7)
+#define RCP14_DBGDEVID()		MRC14(0, c7, c2, 7)
+
+#define WCP14_DBGDCCINT(val)		MCR14(val, 0, c0, c2, 0)
+#define WCP14_DBGDTRTXint(val)		MCR14(val, 0, c0, c5, 0)
+#define WCP14_DBGWFAR(val)		MCR14(val, 0, c0, c6, 0)
+#define WCP14_DBGVCR(val)		MCR14(val, 0, c0, c7, 0)
+#define WCP14_DBGDTRRXext(val)		MCR14(val, 0, c0, c0, 2)
+#define WCP14_DBGDSCRext(val)		MCR14(val, 0, c0, c2, 2)
+#define WCP14_DBGDTRTXext(val)		MCR14(val, 0, c0, c3, 2)
+#define WCP14_DBGOSECCR(val)		MCR14(val, 0, c0, c6, 2)
+#define WCP14_DBGBVR0(val)		MCR14(val, 0, c0, c0, 4)
+#define WCP14_DBGBVR1(val)		MCR14(val, 0, c0, c1, 4)
+#define WCP14_DBGBVR2(val)		MCR14(val, 0, c0, c2, 4)
+#define WCP14_DBGBVR3(val)		MCR14(val, 0, c0, c3, 4)
+#define WCP14_DBGBVR4(val)		MCR14(val, 0, c0, c4, 4)
+#define WCP14_DBGBVR5(val)		MCR14(val, 0, c0, c5, 4)
+#define WCP14_DBGBVR6(val)		MCR14(val, 0, c0, c6, 4)
+#define WCP14_DBGBVR7(val)		MCR14(val, 0, c0, c7, 4)
+#define WCP14_DBGBVR8(val)		MCR14(val, 0, c0, c8, 4)
+#define WCP14_DBGBVR9(val)		MCR14(val, 0, c0, c9, 4)
+#define WCP14_DBGBVR10(val)		MCR14(val, 0, c0, c10, 4)
+#define WCP14_DBGBVR11(val)		MCR14(val, 0, c0, c11, 4)
+#define WCP14_DBGBVR12(val)		MCR14(val, 0, c0, c12, 4)
+#define WCP14_DBGBVR13(val)		MCR14(val, 0, c0, c13, 4)
+#define WCP14_DBGBVR14(val)		MCR14(val, 0, c0, c14, 4)
+#define WCP14_DBGBVR15(val)		MCR14(val, 0, c0, c15, 4)
+#define WCP14_DBGBCR0(val)		MCR14(val, 0, c0, c0, 5)
+#define WCP14_DBGBCR1(val)		MCR14(val, 0, c0, c1, 5)
+#define WCP14_DBGBCR2(val)		MCR14(val, 0, c0, c2, 5)
+#define WCP14_DBGBCR3(val)		MCR14(val, 0, c0, c3, 5)
+#define WCP14_DBGBCR4(val)		MCR14(val, 0, c0, c4, 5)
+#define WCP14_DBGBCR5(val)		MCR14(val, 0, c0, c5, 5)
+#define WCP14_DBGBCR6(val)		MCR14(val, 0, c0, c6, 5)
+#define WCP14_DBGBCR7(val)		MCR14(val, 0, c0, c7, 5)
+#define WCP14_DBGBCR8(val)		MCR14(val, 0, c0, c8, 5)
+#define WCP14_DBGBCR9(val)		MCR14(val, 0, c0, c9, 5)
+#define WCP14_DBGBCR10(val)		MCR14(val, 0, c0, c10, 5)
+#define WCP14_DBGBCR11(val)		MCR14(val, 0, c0, c11, 5)
+#define WCP14_DBGBCR12(val)		MCR14(val, 0, c0, c12, 5)
+#define WCP14_DBGBCR13(val)		MCR14(val, 0, c0, c13, 5)
+#define WCP14_DBGBCR14(val)		MCR14(val, 0, c0, c14, 5)
+#define WCP14_DBGBCR15(val)		MCR14(val, 0, c0, c15, 5)
+#define WCP14_DBGWVR0(val)		MCR14(val, 0, c0, c0, 6)
+#define WCP14_DBGWVR1(val)		MCR14(val, 0, c0, c1, 6)
+#define WCP14_DBGWVR2(val)		MCR14(val, 0, c0, c2, 6)
+#define WCP14_DBGWVR3(val)		MCR14(val, 0, c0, c3, 6)
+#define WCP14_DBGWVR4(val)		MCR14(val, 0, c0, c4, 6)
+#define WCP14_DBGWVR5(val)		MCR14(val, 0, c0, c5, 6)
+#define WCP14_DBGWVR6(val)		MCR14(val, 0, c0, c6, 6)
+#define WCP14_DBGWVR7(val)		MCR14(val, 0, c0, c7, 6)
+#define WCP14_DBGWVR8(val)		MCR14(val, 0, c0, c8, 6)
+#define WCP14_DBGWVR9(val)		MCR14(val, 0, c0, c9, 6)
+#define WCP14_DBGWVR10(val)		MCR14(val, 0, c0, c10, 6)
+#define WCP14_DBGWVR11(val)		MCR14(val, 0, c0, c11, 6)
+#define WCP14_DBGWVR12(val)		MCR14(val, 0, c0, c12, 6)
+#define WCP14_DBGWVR13(val)		MCR14(val, 0, c0, c13, 6)
+#define WCP14_DBGWVR14(val)		MCR14(val, 0, c0, c14, 6)
+#define WCP14_DBGWVR15(val)		MCR14(val, 0, c0, c15, 6)
+#define WCP14_DBGWCR0(val)		MCR14(val, 0, c0, c0, 7)
+#define WCP14_DBGWCR1(val)		MCR14(val, 0, c0, c1, 7)
+#define WCP14_DBGWCR2(val)		MCR14(val, 0, c0, c2, 7)
+#define WCP14_DBGWCR3(val)		MCR14(val, 0, c0, c3, 7)
+#define WCP14_DBGWCR4(val)		MCR14(val, 0, c0, c4, 7)
+#define WCP14_DBGWCR5(val)		MCR14(val, 0, c0, c5, 7)
+#define WCP14_DBGWCR6(val)		MCR14(val, 0, c0, c6, 7)
+#define WCP14_DBGWCR7(val)		MCR14(val, 0, c0, c7, 7)
+#define WCP14_DBGWCR8(val)		MCR14(val, 0, c0, c8, 7)
+#define WCP14_DBGWCR9(val)		MCR14(val, 0, c0, c9, 7)
+#define WCP14_DBGWCR10(val)		MCR14(val, 0, c0, c10, 7)
+#define WCP14_DBGWCR11(val)		MCR14(val, 0, c0, c11, 7)
+#define WCP14_DBGWCR12(val)		MCR14(val, 0, c0, c12, 7)
+#define WCP14_DBGWCR13(val)		MCR14(val, 0, c0, c13, 7)
+#define WCP14_DBGWCR14(val)		MCR14(val, 0, c0, c14, 7)
+#define WCP14_DBGWCR15(val)		MCR14(val, 0, c0, c15, 7)
+#define WCP14_DBGBXVR0(val)		MCR14(val, 0, c1, c0, 1)
+#define WCP14_DBGBXVR1(val)		MCR14(val, 0, c1, c1, 1)
+#define WCP14_DBGBXVR2(val)		MCR14(val, 0, c1, c2, 1)
+#define WCP14_DBGBXVR3(val)		MCR14(val, 0, c1, c3, 1)
+#define WCP14_DBGBXVR4(val)		MCR14(val, 0, c1, c4, 1)
+#define WCP14_DBGBXVR5(val)		MCR14(val, 0, c1, c5, 1)
+#define WCP14_DBGBXVR6(val)		MCR14(val, 0, c1, c6, 1)
+#define WCP14_DBGBXVR7(val)		MCR14(val, 0, c1, c7, 1)
+#define WCP14_DBGBXVR8(val)		MCR14(val, 0, c1, c8, 1)
+#define WCP14_DBGBXVR9(val)		MCR14(val, 0, c1, c9, 1)
+#define WCP14_DBGBXVR10(val)		MCR14(val, 0, c1, c10, 1)
+#define WCP14_DBGBXVR11(val)		MCR14(val, 0, c1, c11, 1)
+#define WCP14_DBGBXVR12(val)		MCR14(val, 0, c1, c12, 1)
+#define WCP14_DBGBXVR13(val)		MCR14(val, 0, c1, c13, 1)
+#define WCP14_DBGBXVR14(val)		MCR14(val, 0, c1, c14, 1)
+#define WCP14_DBGBXVR15(val)		MCR14(val, 0, c1, c15, 1)
+#define WCP14_DBGOSLAR(val)		MCR14(val, 0, c1, c0, 4)
+#define WCP14_DBGOSSRR(val)		MCR14(val, 0, c1, c2, 4)
+#define WCP14_DBGOSDLR(val)		MCR14(val, 0, c1, c3, 4)
+#define WCP14_DBGPRCR(val)		MCR14(val, 0, c1, c4, 4)
+#define WCP14_DBGITCTRL(val)		MCR14(val, 0, c7, c0, 4)
+#define WCP14_DBGCLAIMSET(val)		MCR14(val, 0, c7, c8, 6)
+#define WCP14_DBGCLAIMCLR(val)		MCR14(val, 0, c7, c9, 6)
+
+#endif
diff --git a/arch/arm/include/asm/hw_breakpoint.h b/arch/arm/include/asm/hw_breakpoint.h
index afcaf8b..e40bbc5 100644
--- a/arch/arm/include/asm/hw_breakpoint.h
+++ b/arch/arm/include/asm/hw_breakpoint.h
@@ -52,6 +52,7 @@
 #define ARM_DEBUG_ARCH_V7_MM	4
 #define ARM_DEBUG_ARCH_V7_1	5
 #define ARM_DEBUG_ARCH_V8	6
+#define ARM_DEBUG_ARCH_V8_8	8
 
 /* Breakpoint */
 #define ARM_BREAKPOINT_EXECUTE	0
diff --git a/arch/arm/mach-qcom/Makefile b/arch/arm/mach-qcom/Makefile
index 5b93fa3..2f26f39 100644
--- a/arch/arm/mach-qcom/Makefile
+++ b/arch/arm/mach-qcom/Makefile
@@ -1,5 +1,6 @@
 obj-$(CONFIG_USE_OF) += board-dt.o
 obj-$(CONFIG_SMP)	+= platsmp.o
+obj-$(CONFIG_MSM_PM_LEGACY)	+=hotplug.o
 obj-$(CONFIG_ARCH_SDXPOORWILLS) += board-poorwills.o
 obj-$(CONFIG_ARCH_MSM8953) += board-msm8953.o
 obj-$(CONFIG_ARCH_MSM8937) += board-msm8937.o
diff --git a/arch/arm/mach-qcom/hotplug.c b/arch/arm/mach-qcom/hotplug.c
new file mode 100644
index 0000000..c038f4b
--- /dev/null
+++ b/arch/arm/mach-qcom/hotplug.c
@@ -0,0 +1,109 @@
+/*
+ *  Copyright (C) 2002 ARM Ltd.
+ *  All Rights Reserved
+ *  Copyright (c) 2011-2014, 2016, 2018, 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 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/smp.h>
+#include <linux/cpu.h>
+#include <soc/qcom/spm.h>
+#include <soc/qcom/pm-legacy.h>
+#include <asm/smp_plat.h>
+#include "platsmp.h"
+#include <soc/qcom/jtag.h>
+
+static cpumask_t cpu_dying_mask;
+static DEFINE_PER_CPU(unsigned int, warm_boot_flag);
+
+static inline void cpu_enter_lowpower(void)
+{
+}
+
+static inline void cpu_leave_lowpower(void)
+{
+}
+
+static inline void platform_do_lowpower(unsigned int cpu)
+{
+	lpm_cpu_hotplug_enter(cpu);
+	/*
+	 * getting here, means that we have come out of low power mode
+	 * without having been woken up - this shouldn't happen
+	 *
+	 */
+	pr_err("%s: CPU%u has failed to Hotplug\n", __func__, cpu);
+}
+
+int qcom_cpu_kill_legacy(unsigned int cpu)
+{
+	int ret = 0;
+
+	if (cpumask_test_and_clear_cpu(cpu, &cpu_dying_mask))
+		ret = msm_pm_wait_cpu_shutdown(cpu);
+
+	return ret ? 0 : 1;
+}
+
+/*
+ * platform-specific code to shutdown a CPU
+ *
+ * Called with IRQs disabled
+ */
+void __ref qcom_cpu_die_legacy(unsigned int cpu)
+{
+	if (unlikely(cpu != smp_processor_id())) {
+		pr_crit("%s: running on %u, should be %u\n",
+			__func__, smp_processor_id(), cpu);
+		WARN_ON(cpu);
+	}
+	/*
+	 * we're ready for shutdown now, so do it
+	 */
+	cpu_enter_lowpower();
+	platform_do_lowpower(cpu);
+
+	pr_debug("CPU%u: %s: normal wakeup\n", cpu, __func__);
+	cpu_leave_lowpower();
+}
+
+int msm_platform_secondary_init(unsigned int cpu)
+{
+	int ret;
+	unsigned int *warm_boot = this_cpu_ptr(&warm_boot_flag);
+
+	if (!(*warm_boot)) {
+		*warm_boot = 1;
+		/*
+		 * All CPU0 boots are considered warm boots (restore needed)
+		 * since CPU0 is the system boot CPU and never cold-booted
+		 * by the kernel.
+		 */
+		if (cpu)
+			return 0;
+	}
+	msm_jtag_restore_state();
+	ret = msm_spm_set_low_power_mode(MSM_SPM_MODE_CLOCK_GATING, false);
+
+	return ret;
+}
+
+static int hotplug_dying_cpu(unsigned int cpu)
+{
+	cpumask_set_cpu(cpu, &cpu_dying_mask);
+	return 0;
+}
+
+static int __init init_hotplug_dying(void)
+{
+	cpuhp_setup_state(CPUHP_AP_QCOM_SLEEP_STARTING,
+		 "AP_QCOM_HOTPLUG_STARTING", NULL, hotplug_dying_cpu);
+
+	return 0;
+}
+early_initcall(init_hotplug_dying);
diff --git a/arch/arm/mach-qcom/platsmp.c b/arch/arm/mach-qcom/platsmp.c
index c422ac3..803804d 100644
--- a/arch/arm/mach-qcom/platsmp.c
+++ b/arch/arm/mach-qcom/platsmp.c
@@ -22,6 +22,9 @@
 #include <asm/smp_plat.h>
 #include <asm/fixmap.h>
 #include "platsmp.h"
+#ifdef CONFIG_MSM_PM_LEGACY
+#include <soc/qcom/pm-legacy.h>
+#endif
 
 #define MSM_APCS_IDR 0x0B011030
 
@@ -62,10 +65,18 @@
 {
 	wfi();
 }
+
+static bool qcom_cpu_can_disable(unsigned int cpu)
+{
+	return true; /*Hotplug of any CPU is supported */
+}
 #endif
 
 static void qcom_secondary_init(unsigned int cpu)
 {
+#ifdef CONFIG_MSM_PM_LEGACY
+	WARN_ON(msm_platform_secondary_init(cpu));
+#endif
 	/*
 	 * Synchronise with the boot thread.
 	 */
@@ -472,8 +483,14 @@
 	.smp_secondary_init = qcom_secondary_init,
 	.smp_boot_secondary = msm8909_boot_secondary,
 #ifdef CONFIG_HOTPLUG_CPU
+#ifdef CONFIG_MSM_PM_LEGACY
+	.cpu_die		= qcom_cpu_die_legacy,
+	.cpu_kill		= qcom_cpu_kill_legacy,
+#else
 	.cpu_die		= qcom_cpu_die,
 #endif
+	.cpu_can_disable	= qcom_cpu_can_disable,
+#endif
 };
 
 CPU_METHOD_OF_DECLARE(qcom_smp_8909, "qcom,apss-8909", &msm8909_smp_ops);
diff --git a/arch/arm64/boot/dts/qcom/msm8937-regulator.dtsi b/arch/arm64/boot/dts/qcom/msm8937-regulator.dtsi
index 44bdfc9..d6f24d9 100644
--- a/arch/arm64/boot/dts/qcom/msm8937-regulator.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8937-regulator.dtsi
@@ -62,7 +62,7 @@
 		pm8937_cx_cdev: regulator-cx-cdev {
 			compatible = "qcom,regulator-cooling-device";
 			regulator-cdev-supply = <&pm8937_s2_floor_level>;
-			regulator-levels = <RPM_SMD_REGULATOR_LEVEL_NOM
+			regulator-levels = <RPM_SMD_REGULATOR_LEVEL_NOM_PLUS
 					RPM_SMD_REGULATOR_LEVEL_RETENTION>;
 			#cooling-cells = <2>;
 		};
diff --git a/arch/arm64/boot/dts/qcom/sdm439-regulator.dtsi b/arch/arm64/boot/dts/qcom/sdm439-regulator.dtsi
index 4c4c4bd..b97e66e 100644
--- a/arch/arm64/boot/dts/qcom/sdm439-regulator.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm439-regulator.dtsi
@@ -67,7 +67,7 @@
 		pm8953_cx_cdev: regulator-cx-cdev {
 			compatible = "qcom,regulator-cooling-device";
 			regulator-cdev-supply = <&pm8953_s2_floor_level>;
-			regulator-levels = <RPM_SMD_REGULATOR_LEVEL_NOM
+			regulator-levels = <RPM_SMD_REGULATOR_LEVEL_NOM_PLUS
 					RPM_SMD_REGULATOR_LEVEL_RETENTION>;
 			#cooling-cells = <2>;
 		};
diff --git a/arch/arm64/boot/dts/qcom/sdm670.dtsi b/arch/arm64/boot/dts/qcom/sdm670.dtsi
index fbfae4d..8ba878b 100644
--- a/arch/arm64/boot/dts/qcom/sdm670.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670.dtsi
@@ -1867,6 +1867,7 @@
 		ufs-qcom-crypto = <&ufs_ice>;
 
 		lanes-per-direction = <1>;
+		spm-level = <5>;
 		dev-ref-clk-freq = <0>; /* 19.2 MHz */
 
 		clock-names =
diff --git a/arch/arm64/include/asm/futex.h b/arch/arm64/include/asm/futex.h
index c5bc52e..a891bb6 100644
--- a/arch/arm64/include/asm/futex.h
+++ b/arch/arm64/include/asm/futex.h
@@ -48,20 +48,9 @@
 } while (0)
 
 static inline int
-futex_atomic_op_inuser(unsigned int encoded_op, u32 __user *_uaddr)
+arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr)
 {
-	int op = (encoded_op >> 28) & 7;
-	int cmp = (encoded_op >> 24) & 15;
-	int oparg = (int)(encoded_op << 8) >> 20;
-	int cmparg = (int)(encoded_op << 20) >> 20;
 	int oldval = 0, ret, tmp;
-	u32 __user *uaddr = __uaccess_mask_ptr(_uaddr);
-
-	if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
-		oparg = 1U << (oparg & 0x1f);
-
-	if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
-		return -EFAULT;
 
 	pagefault_disable();
 
@@ -92,17 +81,9 @@
 
 	pagefault_enable();
 
-	if (!ret) {
-		switch (cmp) {
-		case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
-		case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
-		case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
-		case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
-		case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
-		case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
-		default: ret = -ENOSYS;
-		}
-	}
+	if (!ret)
+		*oval = oldval;
+
 	return ret;
 }
 
diff --git a/arch/frv/include/asm/futex.h b/arch/frv/include/asm/futex.h
index 4bea27f..2702bd8 100644
--- a/arch/frv/include/asm/futex.h
+++ b/arch/frv/include/asm/futex.h
@@ -7,7 +7,8 @@
 #include <asm/errno.h>
 #include <asm/uaccess.h>
 
-extern int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr);
+extern int arch_futex_atomic_op_inuser(int op, int oparg, int *oval,
+		u32 __user *uaddr);
 
 static inline int
 futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
diff --git a/arch/frv/kernel/futex.c b/arch/frv/kernel/futex.c
index d155ca9..37f7b2b 100644
--- a/arch/frv/kernel/futex.c
+++ b/arch/frv/kernel/futex.c
@@ -186,20 +186,10 @@
 /*
  * do the futex operations
  */
-int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
+int arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr)
 {
-	int op = (encoded_op >> 28) & 7;
-	int cmp = (encoded_op >> 24) & 15;
-	int oparg = (encoded_op << 8) >> 20;
-	int cmparg = (encoded_op << 20) >> 20;
 	int oldval = 0, ret;
 
-	if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
-		oparg = 1 << oparg;
-
-	if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
-		return -EFAULT;
-
 	pagefault_disable();
 
 	switch (op) {
@@ -225,18 +215,9 @@
 
 	pagefault_enable();
 
-	if (!ret) {
-		switch (cmp) {
-		case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
-		case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
-		case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
-		case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
-		case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
-		case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
-		default: ret = -ENOSYS; break;
-		}
-	}
+	if (!ret)
+		*oval = oldval;
 
 	return ret;
 
-} /* end futex_atomic_op_inuser() */
+} /* end arch_futex_atomic_op_inuser() */
diff --git a/arch/hexagon/include/asm/futex.h b/arch/hexagon/include/asm/futex.h
index 7e597f8..c607b77 100644
--- a/arch/hexagon/include/asm/futex.h
+++ b/arch/hexagon/include/asm/futex.h
@@ -31,18 +31,9 @@
 
 
 static inline int
-futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
+arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr)
 {
-	int op = (encoded_op >> 28) & 7;
-	int cmp = (encoded_op >> 24) & 15;
-	int oparg = (encoded_op << 8) >> 20;
-	int cmparg = (encoded_op << 20) >> 20;
 	int oldval = 0, ret;
-	if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
-		oparg = 1 << oparg;
-
-	if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
-		return -EFAULT;
 
 	pagefault_disable();
 
@@ -72,30 +63,9 @@
 
 	pagefault_enable();
 
-	if (!ret) {
-		switch (cmp) {
-		case FUTEX_OP_CMP_EQ:
-			ret = (oldval == cmparg);
-			break;
-		case FUTEX_OP_CMP_NE:
-			ret = (oldval != cmparg);
-			break;
-		case FUTEX_OP_CMP_LT:
-			ret = (oldval < cmparg);
-			break;
-		case FUTEX_OP_CMP_GE:
-			ret = (oldval >= cmparg);
-			break;
-		case FUTEX_OP_CMP_LE:
-			ret = (oldval <= cmparg);
-			break;
-		case FUTEX_OP_CMP_GT:
-			ret = (oldval > cmparg);
-			break;
-		default:
-			ret = -ENOSYS;
-		}
-	}
+	if (!ret)
+		*oval = oldval;
+
 	return ret;
 }
 
diff --git a/arch/ia64/include/asm/futex.h b/arch/ia64/include/asm/futex.h
index 76acbcd..6d67dc1 100644
--- a/arch/ia64/include/asm/futex.h
+++ b/arch/ia64/include/asm/futex.h
@@ -45,18 +45,9 @@
 } while (0)
 
 static inline int
-futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
+arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr)
 {
-	int op = (encoded_op >> 28) & 7;
-	int cmp = (encoded_op >> 24) & 15;
-	int oparg = (encoded_op << 8) >> 20;
-	int cmparg = (encoded_op << 20) >> 20;
 	int oldval = 0, ret;
-	if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
-		oparg = 1 << oparg;
-
-	if (! access_ok (VERIFY_WRITE, uaddr, sizeof(u32)))
-		return -EFAULT;
 
 	pagefault_disable();
 
@@ -84,17 +75,9 @@
 
 	pagefault_enable();
 
-	if (!ret) {
-		switch (cmp) {
-		case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
-		case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
-		case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
-		case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
-		case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
-		case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
-		default: ret = -ENOSYS;
-		}
-	}
+	if (!ret)
+		*oval = oldval;
+
 	return ret;
 }
 
diff --git a/arch/microblaze/include/asm/futex.h b/arch/microblaze/include/asm/futex.h
index 01848f0..a9dad9e 100644
--- a/arch/microblaze/include/asm/futex.h
+++ b/arch/microblaze/include/asm/futex.h
@@ -29,18 +29,9 @@
 })
 
 static inline int
-futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
+arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr)
 {
-	int op = (encoded_op >> 28) & 7;
-	int cmp = (encoded_op >> 24) & 15;
-	int oparg = (encoded_op << 8) >> 20;
-	int cmparg = (encoded_op << 20) >> 20;
 	int oldval = 0, ret;
-	if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
-		oparg = 1 << oparg;
-
-	if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
-		return -EFAULT;
 
 	pagefault_disable();
 
@@ -66,30 +57,9 @@
 
 	pagefault_enable();
 
-	if (!ret) {
-		switch (cmp) {
-		case FUTEX_OP_CMP_EQ:
-			ret = (oldval == cmparg);
-			break;
-		case FUTEX_OP_CMP_NE:
-			ret = (oldval != cmparg);
-			break;
-		case FUTEX_OP_CMP_LT:
-			ret = (oldval < cmparg);
-			break;
-		case FUTEX_OP_CMP_GE:
-			ret = (oldval >= cmparg);
-			break;
-		case FUTEX_OP_CMP_LE:
-			ret = (oldval <= cmparg);
-			break;
-		case FUTEX_OP_CMP_GT:
-			ret = (oldval > cmparg);
-			break;
-		default:
-			ret = -ENOSYS;
-		}
-	}
+	if (!ret)
+		*oval = oldval;
+
 	return ret;
 }
 
diff --git a/arch/mips/include/asm/futex.h b/arch/mips/include/asm/futex.h
index 1de190b..a9e61ea 100644
--- a/arch/mips/include/asm/futex.h
+++ b/arch/mips/include/asm/futex.h
@@ -83,18 +83,9 @@
 }
 
 static inline int
-futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
+arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr)
 {
-	int op = (encoded_op >> 28) & 7;
-	int cmp = (encoded_op >> 24) & 15;
-	int oparg = (encoded_op << 8) >> 20;
-	int cmparg = (encoded_op << 20) >> 20;
 	int oldval = 0, ret;
-	if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
-		oparg = 1 << oparg;
-
-	if (! access_ok (VERIFY_WRITE, uaddr, sizeof(u32)))
-		return -EFAULT;
 
 	pagefault_disable();
 
@@ -125,17 +116,9 @@
 
 	pagefault_enable();
 
-	if (!ret) {
-		switch (cmp) {
-		case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
-		case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
-		case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
-		case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
-		case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
-		case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
-		default: ret = -ENOSYS;
-		}
-	}
+	if (!ret)
+		*oval = oldval;
+
 	return ret;
 }
 
diff --git a/arch/parisc/include/asm/futex.h b/arch/parisc/include/asm/futex.h
index ac8bd58..06a1a88 100644
--- a/arch/parisc/include/asm/futex.h
+++ b/arch/parisc/include/asm/futex.h
@@ -32,22 +32,12 @@
 }
 
 static inline int
-futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
+arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr)
 {
 	unsigned long int flags;
-	int op = (encoded_op >> 28) & 7;
-	int cmp = (encoded_op >> 24) & 15;
-	int oparg = (encoded_op << 8) >> 20;
-	int cmparg = (encoded_op << 20) >> 20;
 	int oldval, ret;
 	u32 tmp;
 
-	if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
-		oparg = 1 << oparg;
-
-	if (!access_ok(VERIFY_WRITE, uaddr, sizeof(*uaddr)))
-		return -EFAULT;
-
 	_futex_spin_lock_irqsave(uaddr, &flags);
 	pagefault_disable();
 
@@ -85,17 +75,9 @@
 	pagefault_enable();
 	_futex_spin_unlock_irqrestore(uaddr, &flags);
 
-	if (ret == 0) {
-		switch (cmp) {
-		case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
-		case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
-		case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
-		case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
-		case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
-		case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
-		default: ret = -ENOSYS;
-		}
-	}
+	if (!ret)
+		*oval = oldval;
+
 	return ret;
 }
 
diff --git a/arch/powerpc/include/asm/futex.h b/arch/powerpc/include/asm/futex.h
index 2a9cf84..f4c7467f 100644
--- a/arch/powerpc/include/asm/futex.h
+++ b/arch/powerpc/include/asm/futex.h
@@ -31,18 +31,10 @@
 	: "b" (uaddr), "i" (-EFAULT), "r" (oparg) \
 	: "cr0", "memory")
 
-static inline int futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
+static inline int arch_futex_atomic_op_inuser(int op, int oparg, int *oval,
+		u32 __user *uaddr)
 {
-	int op = (encoded_op >> 28) & 7;
-	int cmp = (encoded_op >> 24) & 15;
-	int oparg = (encoded_op << 8) >> 20;
-	int cmparg = (encoded_op << 20) >> 20;
 	int oldval = 0, ret;
-	if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
-		oparg = 1 << oparg;
-
-	if (! access_ok (VERIFY_WRITE, uaddr, sizeof(u32)))
-		return -EFAULT;
 
 	pagefault_disable();
 
@@ -68,17 +60,9 @@
 
 	pagefault_enable();
 
-	if (!ret) {
-		switch (cmp) {
-		case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
-		case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
-		case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
-		case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
-		case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
-		case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
-		default: ret = -ENOSYS;
-		}
-	}
+	if (!ret)
+		*oval = oldval;
+
 	return ret;
 }
 
diff --git a/arch/powerpc/kvm/book3s_hv_rmhandlers.S b/arch/powerpc/kvm/book3s_hv_rmhandlers.S
index 55fbc0c..79a180c 100644
--- a/arch/powerpc/kvm/book3s_hv_rmhandlers.S
+++ b/arch/powerpc/kvm/book3s_hv_rmhandlers.S
@@ -299,7 +299,6 @@
 	stw	r12, STACK_SLOT_TRAP(r1)
 	bl	kvmhv_commence_exit
 	nop
-	lwz	r12, STACK_SLOT_TRAP(r1)
 	b	kvmhv_switch_to_host
 
 /*
@@ -1023,6 +1022,7 @@
 
 secondary_too_late:
 	li	r12, 0
+	stw	r12, STACK_SLOT_TRAP(r1)
 	cmpdi	r4, 0
 	beq	11f
 	stw	r12, VCPU_TRAP(r4)
@@ -1266,12 +1266,12 @@
 	bl	kvmhv_accumulate_time
 #endif
 
+	stw	r12, STACK_SLOT_TRAP(r1)
 	mr 	r3, r12
 	/* Increment exit count, poke other threads to exit */
 	bl	kvmhv_commence_exit
 	nop
 	ld	r9, HSTATE_KVM_VCPU(r13)
-	lwz	r12, VCPU_TRAP(r9)
 
 	/* Stop others sending VCPU interrupts to this physical CPU */
 	li	r0, -1
@@ -1549,6 +1549,7 @@
 	 * POWER7/POWER8 guest -> host partition switch code.
 	 * We don't have to lock against tlbies but we do
 	 * have to coordinate the hardware threads.
+	 * Here STACK_SLOT_TRAP(r1) contains the trap number.
 	 */
 kvmhv_switch_to_host:
 	/* Secondary threads wait for primary to do partition switch */
@@ -1599,11 +1600,11 @@
 END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S)
 
 	/* If HMI, call kvmppc_realmode_hmi_handler() */
+	lwz	r12, STACK_SLOT_TRAP(r1)
 	cmpwi	r12, BOOK3S_INTERRUPT_HMI
 	bne	27f
 	bl	kvmppc_realmode_hmi_handler
 	nop
-	li	r12, BOOK3S_INTERRUPT_HMI
 	/*
 	 * At this point kvmppc_realmode_hmi_handler would have resync-ed
 	 * the TB. Hence it is not required to subtract guest timebase
@@ -1678,6 +1679,7 @@
 	li	r0, KVM_GUEST_MODE_NONE
 	stb	r0, HSTATE_IN_GUEST(r13)
 
+	lwz	r12, STACK_SLOT_TRAP(r1)	/* return trap # in r12 */
 	ld	r0, SFS+PPC_LR_STKOFF(r1)
 	addi	r1, r1, SFS
 	mtlr	r0
diff --git a/arch/s390/include/asm/futex.h b/arch/s390/include/asm/futex.h
index a4811aa..8f8eec9e 100644
--- a/arch/s390/include/asm/futex.h
+++ b/arch/s390/include/asm/futex.h
@@ -21,17 +21,12 @@
 		: "0" (-EFAULT), "d" (oparg), "a" (uaddr),		\
 		  "m" (*uaddr) : "cc");
 
-static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
+static inline int arch_futex_atomic_op_inuser(int op, int oparg, int *oval,
+		u32 __user *uaddr)
 {
-	int op = (encoded_op >> 28) & 7;
-	int cmp = (encoded_op >> 24) & 15;
-	int oparg = (encoded_op << 8) >> 20;
-	int cmparg = (encoded_op << 20) >> 20;
 	int oldval = 0, newval, ret;
 
 	load_kernel_asce();
-	if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
-		oparg = 1 << oparg;
 
 	pagefault_disable();
 	switch (op) {
@@ -60,17 +55,9 @@
 	}
 	pagefault_enable();
 
-	if (!ret) {
-		switch (cmp) {
-		case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
-		case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
-		case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
-		case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
-		case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
-		case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
-		default: ret = -ENOSYS;
-		}
-	}
+	if (!ret)
+		*oval = oldval;
+
 	return ret;
 }
 
diff --git a/arch/sh/include/asm/futex.h b/arch/sh/include/asm/futex.h
index d007874..8f8cf94 100644
--- a/arch/sh/include/asm/futex.h
+++ b/arch/sh/include/asm/futex.h
@@ -27,21 +27,12 @@
 	return atomic_futex_op_cmpxchg_inatomic(uval, uaddr, oldval, newval);
 }
 
-static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
+static inline int arch_futex_atomic_op_inuser(int op, u32 oparg, int *oval,
+		u32 __user *uaddr)
 {
-	int op = (encoded_op >> 28) & 7;
-	int cmp = (encoded_op >> 24) & 15;
-	u32 oparg = (encoded_op << 8) >> 20;
-	u32 cmparg = (encoded_op << 20) >> 20;
 	u32 oldval, newval, prev;
 	int ret;
 
-	if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
-		oparg = 1 << oparg;
-
-	if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
-		return -EFAULT;
-
 	pagefault_disable();
 
 	do {
@@ -80,17 +71,8 @@
 
 	pagefault_enable();
 
-	if (!ret) {
-		switch (cmp) {
-		case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
-		case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
-		case FUTEX_OP_CMP_LT: ret = ((int)oldval < (int)cmparg); break;
-		case FUTEX_OP_CMP_GE: ret = ((int)oldval >= (int)cmparg); break;
-		case FUTEX_OP_CMP_LE: ret = ((int)oldval <= (int)cmparg); break;
-		case FUTEX_OP_CMP_GT: ret = ((int)oldval > (int)cmparg); break;
-		default: ret = -ENOSYS;
-		}
-	}
+	if (!ret)
+		*oval = oldval;
 
 	return ret;
 }
diff --git a/arch/sparc/include/asm/futex_64.h b/arch/sparc/include/asm/futex_64.h
index 4e899b0..1cfd89d 100644
--- a/arch/sparc/include/asm/futex_64.h
+++ b/arch/sparc/include/asm/futex_64.h
@@ -29,22 +29,14 @@
 	: "r" (uaddr), "r" (oparg), "i" (-EFAULT)	\
 	: "memory")
 
-static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
+static inline int arch_futex_atomic_op_inuser(int op, int oparg, int *oval,
+		u32 __user *uaddr)
 {
-	int op = (encoded_op >> 28) & 7;
-	int cmp = (encoded_op >> 24) & 15;
-	int oparg = (encoded_op << 8) >> 20;
-	int cmparg = (encoded_op << 20) >> 20;
 	int oldval = 0, ret, tem;
 
-	if (unlikely(!access_ok(VERIFY_WRITE, uaddr, sizeof(u32))))
-		return -EFAULT;
 	if (unlikely((((unsigned long) uaddr) & 0x3UL)))
 		return -EINVAL;
 
-	if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
-		oparg = 1 << oparg;
-
 	pagefault_disable();
 
 	switch (op) {
@@ -69,17 +61,9 @@
 
 	pagefault_enable();
 
-	if (!ret) {
-		switch (cmp) {
-		case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
-		case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
-		case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
-		case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
-		case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
-		case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
-		default: ret = -ENOSYS;
-		}
-	}
+	if (!ret)
+		*oval = oldval;
+
 	return ret;
 }
 
diff --git a/arch/tile/include/asm/futex.h b/arch/tile/include/asm/futex.h
index e64a1b7..83c1e63 100644
--- a/arch/tile/include/asm/futex.h
+++ b/arch/tile/include/asm/futex.h
@@ -106,12 +106,9 @@
 	lock = __atomic_hashed_lock((int __force *)uaddr)
 #endif
 
-static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
+static inline int arch_futex_atomic_op_inuser(int op, u32 oparg, int *oval,
+		u32 __user *uaddr)
 {
-	int op = (encoded_op >> 28) & 7;
-	int cmp = (encoded_op >> 24) & 15;
-	int oparg = (encoded_op << 8) >> 20;
-	int cmparg = (encoded_op << 20) >> 20;
 	int uninitialized_var(val), ret;
 
 	__futex_prolog();
@@ -119,12 +116,6 @@
 	/* The 32-bit futex code makes this assumption, so validate it here. */
 	BUILD_BUG_ON(sizeof(atomic_t) != sizeof(int));
 
-	if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
-		oparg = 1 << oparg;
-
-	if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
-		return -EFAULT;
-
 	pagefault_disable();
 	switch (op) {
 	case FUTEX_OP_SET:
@@ -148,30 +139,9 @@
 	}
 	pagefault_enable();
 
-	if (!ret) {
-		switch (cmp) {
-		case FUTEX_OP_CMP_EQ:
-			ret = (val == cmparg);
-			break;
-		case FUTEX_OP_CMP_NE:
-			ret = (val != cmparg);
-			break;
-		case FUTEX_OP_CMP_LT:
-			ret = (val < cmparg);
-			break;
-		case FUTEX_OP_CMP_GE:
-			ret = (val >= cmparg);
-			break;
-		case FUTEX_OP_CMP_LE:
-			ret = (val <= cmparg);
-			break;
-		case FUTEX_OP_CMP_GT:
-			ret = (val > cmparg);
-			break;
-		default:
-			ret = -ENOSYS;
-		}
-	}
+	if (!ret)
+		*oval = val;
+
 	return ret;
 }
 
diff --git a/arch/x86/events/core.c b/arch/x86/events/core.c
index f73796d..02e547f 100644
--- a/arch/x86/events/core.c
+++ b/arch/x86/events/core.c
@@ -26,6 +26,7 @@
 #include <linux/cpu.h>
 #include <linux/bitops.h>
 #include <linux/device.h>
+#include <linux/nospec.h>
 
 #include <asm/apic.h>
 #include <asm/stacktrace.h>
@@ -303,17 +304,20 @@
 
 	config = attr->config;
 
-	cache_type = (config >>  0) & 0xff;
+	cache_type = (config >> 0) & 0xff;
 	if (cache_type >= PERF_COUNT_HW_CACHE_MAX)
 		return -EINVAL;
+	cache_type = array_index_nospec(cache_type, PERF_COUNT_HW_CACHE_MAX);
 
 	cache_op = (config >>  8) & 0xff;
 	if (cache_op >= PERF_COUNT_HW_CACHE_OP_MAX)
 		return -EINVAL;
+	cache_op = array_index_nospec(cache_op, PERF_COUNT_HW_CACHE_OP_MAX);
 
 	cache_result = (config >> 16) & 0xff;
 	if (cache_result >= PERF_COUNT_HW_CACHE_RESULT_MAX)
 		return -EINVAL;
+	cache_result = array_index_nospec(cache_result, PERF_COUNT_HW_CACHE_RESULT_MAX);
 
 	val = hw_cache_event_ids[cache_type][cache_op][cache_result];
 
@@ -420,6 +424,8 @@
 	if (attr->config >= x86_pmu.max_events)
 		return -EINVAL;
 
+	attr->config = array_index_nospec((unsigned long)attr->config, x86_pmu.max_events);
+
 	/*
 	 * The generic map:
 	 */
diff --git a/arch/x86/events/intel/cstate.c b/arch/x86/events/intel/cstate.c
index 1076c9a..47d526c 100644
--- a/arch/x86/events/intel/cstate.c
+++ b/arch/x86/events/intel/cstate.c
@@ -90,6 +90,7 @@
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/perf_event.h>
+#include <linux/nospec.h>
 #include <asm/cpu_device_id.h>
 #include <asm/intel-family.h>
 #include "../perf_event.h"
@@ -300,6 +301,7 @@
 	} else if (event->pmu == &cstate_pkg_pmu) {
 		if (cfg >= PERF_CSTATE_PKG_EVENT_MAX)
 			return -EINVAL;
+		cfg = array_index_nospec((unsigned long)cfg, PERF_CSTATE_PKG_EVENT_MAX);
 		if (!pkg_msr[cfg].attr)
 			return -EINVAL;
 		event->hw.event_base = pkg_msr[cfg].msr;
diff --git a/arch/x86/events/msr.c b/arch/x86/events/msr.c
index 4bb3ec6..be0b196 100644
--- a/arch/x86/events/msr.c
+++ b/arch/x86/events/msr.c
@@ -1,4 +1,5 @@
 #include <linux/perf_event.h>
+#include <linux/nospec.h>
 #include <asm/intel-family.h>
 
 enum perf_msr_id {
@@ -136,9 +137,6 @@
 	if (event->attr.type != event->pmu->type)
 		return -ENOENT;
 
-	if (cfg >= PERF_MSR_EVENT_MAX)
-		return -EINVAL;
-
 	/* unsupported modes and filters */
 	if (event->attr.exclude_user   ||
 	    event->attr.exclude_kernel ||
@@ -149,6 +147,11 @@
 	    event->attr.sample_period) /* no sampling */
 		return -EINVAL;
 
+	if (cfg >= PERF_MSR_EVENT_MAX)
+		return -EINVAL;
+
+	cfg = array_index_nospec((unsigned long)cfg, PERF_MSR_EVENT_MAX);
+
 	if (!msr[cfg].attr)
 		return -EINVAL;
 
diff --git a/arch/x86/include/asm/futex.h b/arch/x86/include/asm/futex.h
index b4c1f54..f4dc9b6 100644
--- a/arch/x86/include/asm/futex.h
+++ b/arch/x86/include/asm/futex.h
@@ -41,20 +41,11 @@
 		       "+m" (*uaddr), "=&r" (tem)		\
 		     : "r" (oparg), "i" (-EFAULT), "1" (0))
 
-static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
+static inline int arch_futex_atomic_op_inuser(int op, int oparg, int *oval,
+		u32 __user *uaddr)
 {
-	int op = (encoded_op >> 28) & 7;
-	int cmp = (encoded_op >> 24) & 15;
-	int oparg = (encoded_op << 8) >> 20;
-	int cmparg = (encoded_op << 20) >> 20;
 	int oldval = 0, ret, tem;
 
-	if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
-		oparg = 1 << oparg;
-
-	if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
-		return -EFAULT;
-
 	pagefault_disable();
 
 	switch (op) {
@@ -80,30 +71,9 @@
 
 	pagefault_enable();
 
-	if (!ret) {
-		switch (cmp) {
-		case FUTEX_OP_CMP_EQ:
-			ret = (oldval == cmparg);
-			break;
-		case FUTEX_OP_CMP_NE:
-			ret = (oldval != cmparg);
-			break;
-		case FUTEX_OP_CMP_LT:
-			ret = (oldval < cmparg);
-			break;
-		case FUTEX_OP_CMP_GE:
-			ret = (oldval >= cmparg);
-			break;
-		case FUTEX_OP_CMP_LE:
-			ret = (oldval <= cmparg);
-			break;
-		case FUTEX_OP_CMP_GT:
-			ret = (oldval > cmparg);
-			break;
-		default:
-			ret = -ENOSYS;
-		}
-	}
+	if (!ret)
+		*oval = oldval;
+
 	return ret;
 }
 
diff --git a/arch/xtensa/include/asm/futex.h b/arch/xtensa/include/asm/futex.h
index 72bfc1c..5bfbc1c 100644
--- a/arch/xtensa/include/asm/futex.h
+++ b/arch/xtensa/include/asm/futex.h
@@ -44,18 +44,10 @@
 	: "r" (uaddr), "I" (-EFAULT), "r" (oparg)	\
 	: "memory")
 
-static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
+static inline int arch_futex_atomic_op_inuser(int op, int oparg, int *oval,
+		u32 __user *uaddr)
 {
-	int op = (encoded_op >> 28) & 7;
-	int cmp = (encoded_op >> 24) & 15;
-	int oparg = (encoded_op << 8) >> 20;
-	int cmparg = (encoded_op << 20) >> 20;
 	int oldval = 0, ret;
-	if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
-		oparg = 1 << oparg;
-
-	if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
-		return -EFAULT;
 
 #if !XCHAL_HAVE_S32C1I
 	return -ENOSYS;
@@ -89,19 +81,10 @@
 
 	pagefault_enable();
 
-	if (ret)
-		return ret;
+	if (!ret)
+		*oval = oldval;
 
-	switch (cmp) {
-	case FUTEX_OP_CMP_EQ: return (oldval == cmparg);
-	case FUTEX_OP_CMP_NE: return (oldval != cmparg);
-	case FUTEX_OP_CMP_LT: return (oldval < cmparg);
-	case FUTEX_OP_CMP_GE: return (oldval >= cmparg);
-	case FUTEX_OP_CMP_LE: return (oldval <= cmparg);
-	case FUTEX_OP_CMP_GT: return (oldval > cmparg);
-	}
-
-	return -ENOSYS;
+	return ret;
 }
 
 static inline int
diff --git a/block/ioctl.c b/block/ioctl.c
index d4a78d0..c4555b1 100644
--- a/block/ioctl.c
+++ b/block/ioctl.c
@@ -564,8 +564,6 @@
 		if ((size >> 9) > ~0UL)
 			return -EFBIG;
 		return put_ulong(arg, size >> 9);
-	case BLKGETSTPART:
-		return put_ulong(arg, bdev->bd_part->start_sect);
 	case BLKGETSIZE64:
 		return put_u64(arg, i_size_read(bdev->bd_inode));
 	case BLKTRACESTART:
diff --git a/crypto/af_alg.c b/crypto/af_alg.c
index ca50eeb..b5953f1 100644
--- a/crypto/af_alg.c
+++ b/crypto/af_alg.c
@@ -157,16 +157,16 @@
 	void *private;
 	int err;
 
-	/* If caller uses non-allowed flag, return error. */
-	if ((sa->salg_feat & ~allowed) || (sa->salg_mask & ~allowed))
-		return -EINVAL;
-
 	if (sock->state == SS_CONNECTED)
 		return -EINVAL;
 
 	if (addr_len != sizeof(*sa))
 		return -EINVAL;
 
+	/* If caller uses non-allowed flag, return error. */
+	if ((sa->salg_feat & ~allowed) || (sa->salg_mask & ~allowed))
+		return -EINVAL;
+
 	sa->salg_type[sizeof(sa->salg_type) - 1] = 0;
 	sa->salg_name[sizeof(sa->salg_name) - 1] = 0;
 
diff --git a/drivers/android/binder.c b/drivers/android/binder.c
index e7e4560..957eb3c 100644
--- a/drivers/android/binder.c
+++ b/drivers/android/binder.c
@@ -3001,6 +3001,14 @@
 			else
 				return_error = BR_DEAD_REPLY;
 			mutex_unlock(&context->context_mgr_node_lock);
+			if (target_node && target_proc == proc) {
+				binder_user_error("%d:%d got transaction to context manager from process owning it\n",
+						  proc->pid, thread->pid);
+				return_error = BR_FAILED_REPLY;
+				return_error_param = -EINVAL;
+				return_error_line = __LINE__;
+				goto err_invalid_target_handle;
+			}
 		}
 		if (!target_node) {
 			/*
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index e08c09f..4fe3ec1 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -4422,6 +4422,9 @@
 						ATA_HORKAGE_ZERO_AFTER_TRIM |
 						ATA_HORKAGE_NOLPM, },
 
+	/* Sandisk devices which are known to not handle LPM well */
+	{ "SanDisk SD7UB3Q*G1001",	NULL,	ATA_HORKAGE_NOLPM, },
+
 	/* devices that don't properly handle queued TRIM commands */
 	{ "Micron_M500_*",		NULL,	ATA_HORKAGE_NO_NCQ_TRIM |
 						ATA_HORKAGE_ZERO_AFTER_TRIM, },
diff --git a/drivers/atm/zatm.c b/drivers/atm/zatm.c
index d3dc954..81bfeec 100644
--- a/drivers/atm/zatm.c
+++ b/drivers/atm/zatm.c
@@ -23,6 +23,7 @@
 #include <linux/bitops.h>
 #include <linux/wait.h>
 #include <linux/slab.h>
+#include <linux/nospec.h>
 #include <asm/byteorder.h>
 #include <asm/string.h>
 #include <asm/io.h>
@@ -1458,6 +1459,8 @@
 					return -EFAULT;
 				if (pool < 0 || pool > ZATM_LAST_POOL)
 					return -EINVAL;
+				pool = array_index_nospec(pool,
+							  ZATM_LAST_POOL + 1);
 				spin_lock_irqsave(&zatm_dev->lock, flags);
 				info = zatm_dev->pool_info[pool];
 				if (cmd == ZATM_GETPOOLZ) {
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index f8ba5c7..3257647 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -217,6 +217,7 @@
 	{ USB_DEVICE(0x0930, 0x0227), .driver_info = BTUSB_ATH3012 },
 	{ USB_DEVICE(0x0b05, 0x17d0), .driver_info = BTUSB_ATH3012 },
 	{ USB_DEVICE(0x0cf3, 0x0036), .driver_info = BTUSB_ATH3012 },
+	{ USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_ATH3012 },
 	{ USB_DEVICE(0x0cf3, 0x3008), .driver_info = BTUSB_ATH3012 },
 	{ USB_DEVICE(0x0cf3, 0x311d), .driver_info = BTUSB_ATH3012 },
 	{ USB_DEVICE(0x0cf3, 0x311e), .driver_info = BTUSB_ATH3012 },
@@ -249,7 +250,6 @@
 	{ USB_DEVICE(0x0489, 0xe03c), .driver_info = BTUSB_ATH3012 },
 
 	/* QCA ROME chipset */
-	{ USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_QCA_ROME },
 	{ USB_DEVICE(0x0cf3, 0xe007), .driver_info = BTUSB_QCA_ROME },
 	{ USB_DEVICE(0x0cf3, 0xe009), .driver_info = BTUSB_QCA_ROME },
 	{ USB_DEVICE(0x0cf3, 0xe300), .driver_info = BTUSB_QCA_ROME },
diff --git a/drivers/char/diag/diag_ipc_logging.h b/drivers/char/diag/diag_ipc_logging.h
index b9958a4..4b8dd1b 100644
--- a/drivers/char/diag/diag_ipc_logging.h
+++ b/drivers/char/diag/diag_ipc_logging.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015, 2018, 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
@@ -24,6 +24,7 @@
 #define DIAG_DEBUG_MASKS	0x0010
 #define DIAG_DEBUG_POWER	0x0020
 #define DIAG_DEBUG_BRIDGE	0x0040
+#define DIAG_DEBUG_CONTROL	0x0080
 
 #define DIAG_DEBUG
 
diff --git a/drivers/char/diag/diag_memorydevice.c b/drivers/char/diag/diag_memorydevice.c
index 55b1b49..c00fbfc 100644
--- a/drivers/char/diag/diag_memorydevice.c
+++ b/drivers/char/diag/diag_memorydevice.c
@@ -37,6 +37,7 @@
 		.ctx = 0,
 		.mempool = POOL_TYPE_MUX_APPS,
 		.num_tbl_entries = 0,
+		.md_info_inited = 0,
 		.tbl = NULL,
 		.ops = NULL,
 	},
@@ -46,6 +47,7 @@
 		.ctx = 0,
 		.mempool = POOL_TYPE_MDM_MUX,
 		.num_tbl_entries = 0,
+		.md_info_inited = 0,
 		.tbl = NULL,
 		.ops = NULL,
 	},
@@ -54,6 +56,7 @@
 		.ctx = 0,
 		.mempool = POOL_TYPE_MDM2_MUX,
 		.num_tbl_entries = 0,
+		.md_info_inited = 0,
 		.tbl = NULL,
 		.ops = NULL,
 	},
@@ -62,6 +65,7 @@
 		.ctx = 0,
 		.mempool = POOL_TYPE_QSC_MUX,
 		.num_tbl_entries = 0,
+		.md_info_inited = 0,
 		.tbl = NULL,
 		.ops = NULL,
 	}
@@ -85,6 +89,8 @@
 
 	for (i = 0; i < NUM_DIAG_MD_DEV; i++) {
 		ch = &diag_md[i];
+		if (!ch->md_info_inited)
+			continue;
 		if (ch->ops && ch->ops->open)
 			ch->ops->open(ch->ctx, DIAG_MEMORY_DEVICE_MODE);
 	}
@@ -99,6 +105,8 @@
 
 	for (i = 0; i < NUM_DIAG_MD_DEV; i++) {
 		ch = &diag_md[i];
+		if (!ch->md_info_inited)
+			continue;
 
 		if (ch->ops && ch->ops->close)
 			ch->ops->close(ch->ctx, DIAG_MEMORY_DEVICE_MODE);
@@ -155,7 +163,7 @@
 	mutex_unlock(&driver->md_session_lock);
 
 	ch = &diag_md[id];
-	if (!ch)
+	if (!ch || !ch->md_info_inited)
 		return -EINVAL;
 
 	spin_lock_irqsave(&ch->lock, flags);
@@ -232,6 +240,8 @@
 
 	for (i = 0; i < NUM_DIAG_MD_DEV && !err; i++) {
 		ch = &diag_md[i];
+		if (!ch->md_info_inited)
+			continue;
 		for (j = 0; j < ch->num_tbl_entries && !err; j++) {
 			entry = &ch->tbl[j];
 			if (entry->len <= 0 || entry->buf == NULL)
@@ -352,6 +362,8 @@
 		return -EINVAL;
 
 	ch = &diag_md[id];
+	if (!ch || !ch->md_info_inited)
+		return -EINVAL;
 
 	spin_lock_irqsave(&ch->lock, flags);
 	for (i = 0; i < ch->num_tbl_entries && !found; i++) {
@@ -399,6 +411,7 @@
 			ch->tbl[j].ctx = 0;
 		}
 		spin_lock_init(&(ch->lock));
+		ch->md_info_inited = 1;
 	}
 
 	return 0;
@@ -427,6 +440,7 @@
 			ch->tbl[j].ctx = 0;
 		}
 		spin_lock_init(&(ch->lock));
+		ch->md_info_inited = 1;
 	}
 
 	return 0;
diff --git a/drivers/char/diag/diag_memorydevice.h b/drivers/char/diag/diag_memorydevice.h
index 9b4aa39..4d65ded 100644
--- a/drivers/char/diag/diag_memorydevice.h
+++ b/drivers/char/diag/diag_memorydevice.h
@@ -38,6 +38,7 @@
 	int ctx;
 	int mempool;
 	int num_tbl_entries;
+	int md_info_inited;
 	spinlock_t lock;
 	struct diag_buf_tbl_t *tbl;
 	struct diag_mux_ops *ops;
diff --git a/drivers/char/diag/diagfwd_cntl.c b/drivers/char/diag/diagfwd_cntl.c
index 8d47ee38..6f81bfd 100644
--- a/drivers/char/diag/diagfwd_cntl.c
+++ b/drivers/char/diag/diagfwd_cntl.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2018, 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
@@ -45,8 +45,11 @@
 
 void diag_cntl_channel_open(struct diagfwd_info *p_info)
 {
-	if (!p_info)
+	if (!p_info) {
+		DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
+		"diag: Invalid fwd_info structure\n");
 		return;
+	}
 	driver->mask_update |= PERIPHERAL_MASK(p_info->peripheral);
 	queue_work(driver->cntl_wq, &driver->mask_update_work);
 	diag_notify_md_client(p_info->peripheral, DIAG_STATUS_OPEN);
@@ -56,12 +59,18 @@
 {
 	uint8_t peripheral;
 
-	if (!p_info)
+	if (!p_info) {
+		DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
+		"diag: Invalid fwd_info structure\n");
 		return;
+	}
 
 	peripheral = p_info->peripheral;
-	if (peripheral >= NUM_PERIPHERALS)
+	if (peripheral >= NUM_PERIPHERALS) {
+		DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
+			"diag: Invalid peripheral (%d)\n", peripheral);
 		return;
+	}
 
 	driver->feature[peripheral].sent_feature_mask = 0;
 	driver->feature[peripheral].rcvd_feature_mask = 0;
@@ -87,8 +96,11 @@
 	driver->stm_peripheral = 0;
 	mutex_unlock(&driver->cntl_lock);
 
-	if (peripheral_mask == 0)
+	if (peripheral_mask == 0) {
+		DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
+			"diag: Empty Peripheral mask\n");
 		return;
+	}
 
 	for (i = 0; i < NUM_PERIPHERALS; i++) {
 		if (!driver->feature[i].stm_support)
@@ -111,11 +123,18 @@
 	struct pid *pid_struct;
 	struct task_struct *result;
 
-	if (peripheral > NUM_PERIPHERALS)
+	if (peripheral > NUM_PERIPHERALS) {
+		DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
+			"diag: Invalid peripheral (%d)\n", peripheral);
 		return;
+	}
 
-	if (driver->logging_mode != DIAG_MEMORY_DEVICE_MODE)
+	if (driver->logging_mode != DIAG_MEMORY_DEVICE_MODE) {
+		DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
+			"diag: Invalid logging_mode (%d)\n",
+			driver->logging_mode);
 		return;
+	}
 
 	mutex_lock(&driver->md_session_lock);
 	memset(&info, 0, sizeof(struct siginfo));
@@ -171,8 +190,12 @@
 	uint32_t pd;
 	int status = DIAG_STATUS_CLOSED;
 
-	if (!buf || peripheral >= NUM_PERIPHERALS || len < sizeof(*pd_msg))
+	if (!buf || peripheral >= NUM_PERIPHERALS || len < sizeof(*pd_msg)) {
+		DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
+		"diag: Invalid parameters:(!buf) = %d, peripheral = %d, len = %d, pd_msg_len = %d\n",
+		!buf, peripheral, len, (int)sizeof(*pd_msg));
 		return;
+	}
 
 	pd_msg = (struct diag_ctrl_msg_pd_status *)buf;
 	pd = pd_msg->pd_id;
@@ -182,8 +205,11 @@
 
 static void enable_stm_feature(uint8_t peripheral)
 {
-	if (peripheral >= NUM_PERIPHERALS)
+	if (peripheral >= NUM_PERIPHERALS) {
+		DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
+		"diag: Invalid peripheral (%d)\n", peripheral);
 		return;
+	}
 
 	mutex_lock(&driver->cntl_lock);
 	driver->feature[peripheral].stm_support = ENABLE_STM;
@@ -195,8 +221,11 @@
 
 static void enable_socket_feature(uint8_t peripheral)
 {
-	if (peripheral >= NUM_PERIPHERALS)
+	if (peripheral >= NUM_PERIPHERALS) {
+		DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
+		"diag: Invalid peripheral (%d)\n", peripheral);
 		return;
+	}
 
 	if (driver->supports_sockets)
 		driver->feature[peripheral].sockets_enabled = 1;
@@ -206,8 +235,11 @@
 
 static void process_hdlc_encoding_feature(uint8_t peripheral)
 {
-	if (peripheral >= NUM_PERIPHERALS)
+	if (peripheral >= NUM_PERIPHERALS) {
+		DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
+		"diag: Invalid peripheral (%d)\n", peripheral);
 		return;
+	}
 
 	if (driver->supports_apps_hdlc_encoding) {
 		driver->feature[peripheral].encode_hdlc =
@@ -220,8 +252,11 @@
 
 static void process_upd_header_untagging_feature(uint8_t peripheral)
 {
-	if (peripheral >= NUM_PERIPHERALS)
+	if (peripheral >= NUM_PERIPHERALS) {
+		DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
+		"diag: Invalid peripheral (%d)\n", peripheral);
 		return;
+	}
 
 	if (driver->supports_apps_header_untagging) {
 		driver->feature[peripheral].untag_header =
@@ -247,8 +282,16 @@
 	 * Perform Basic sanity. The len field is the size of the data payload.
 	 * This doesn't include the header size.
 	 */
-	if (!buf || peripheral >= NUM_PERIPHERALS || len == 0)
+	if (!buf || peripheral >= NUM_PERIPHERALS || len == 0) {
+		DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
+		"diag: Invalid parameters:(!buf) = %d, peripheral = %d, len = %d\n",
+		!buf, peripheral, len);
 		return;
+	}
+
+	DIAG_LOG(DIAG_DEBUG_CONTROL,
+		"diag:peripheral(%d) command deregistration packet processing started\n",
+		peripheral);
 
 	dereg = (struct diag_ctrl_cmd_dereg *)ptr;
 	ptr += header_len;
@@ -256,8 +299,8 @@
 	read_len += header_len - (2 * sizeof(uint32_t));
 
 	if (dereg->count_entries == 0) {
-		pr_debug("diag: In %s, received reg tbl with no entries\n",
-			 __func__);
+		DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
+			"diag: received reg tbl with no entries\n");
 		return;
 	}
 
@@ -276,6 +319,9 @@
 		pr_err("diag: In %s, reading less than available, read_len: %d, len: %d count: %d\n",
 		       __func__, read_len, len, dereg->count_entries);
 	}
+	DIAG_LOG(DIAG_DEBUG_CONTROL,
+		"diag:peripheral(%d) command deregistration packet processing complete\n",
+		peripheral);
 }
 static void process_command_registration(uint8_t *buf, uint32_t len,
 					 uint8_t peripheral)
@@ -292,8 +338,15 @@
 	 * Perform Basic sanity. The len field is the size of the data payload.
 	 * This doesn't include the header size.
 	 */
-	if (!buf || peripheral >= NUM_PERIPHERALS || len == 0)
+	if (!buf || peripheral >= NUM_PERIPHERALS || len == 0) {
+		DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
+		"diag: Invalid parameters:(!buf) = %d, peripheral = %d, len = %d\n",
+		!buf, peripheral, len);
 		return;
+	}
+	DIAG_LOG(DIAG_DEBUG_CONTROL,
+		"diag: peripheral(%d) command registration packet processing started\n",
+		peripheral);
 
 	reg = (struct diag_ctrl_cmd_reg *)ptr;
 	ptr += header_len;
@@ -301,7 +354,8 @@
 	read_len += header_len - (2 * sizeof(uint32_t));
 
 	if (reg->count_entries == 0) {
-		pr_debug("diag: In %s, received reg tbl with no entries\n",
+		DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
+			"diag: In %s, received reg tbl with no entries\n",
 			 __func__);
 		return;
 	}
@@ -321,6 +375,9 @@
 		pr_err("diag: In %s, reading less than available, read_len: %d, len: %d count: %d\n",
 		       __func__, read_len, len, reg->count_entries);
 	}
+	DIAG_LOG(DIAG_DEBUG_CONTROL,
+		"diag: peripheral(%d) command registration packet processing complete\n",
+		peripheral);
 }
 
 static void diag_close_transport_work_fn(struct work_struct *work)
@@ -347,8 +404,11 @@
 
 static void process_socket_feature(uint8_t peripheral)
 {
-	if (peripheral >= NUM_PERIPHERALS)
+	if (peripheral >= NUM_PERIPHERALS) {
+		DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
+		"diag: Invalid peripheral (%d)\n", peripheral);
 		return;
+	}
 
 	mutex_lock(&driver->cntl_lock);
 	driver->close_transport |= PERIPHERAL_MASK(peripheral);
@@ -379,15 +439,20 @@
 	uint32_t feature_mask = 0;
 	uint8_t *ptr = buf;
 
-	if (!buf || peripheral >= NUM_PERIPHERALS || len == 0)
+	if (!buf || peripheral >= NUM_PERIPHERALS || len == 0) {
+		DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
+		"diag: Invalid parameters:(!buf) = %d, peripheral = %d, len = %d\n",
+		!buf, peripheral, len);
 		return;
+	}
 
 	header = (struct diag_ctrl_feature_mask *)ptr;
 	ptr += header_len;
 	feature_mask_len = header->feature_mask_len;
 
 	if (feature_mask_len == 0) {
-		pr_debug("diag: In %s, received invalid feature mask from peripheral %d\n",
+		DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
+			"diag: In %s, received invalid feature mask from peripheral %d\n",
 			 __func__, peripheral);
 		return;
 	}
@@ -400,6 +465,8 @@
 	diag_cmd_remove_reg_by_proc(peripheral);
 
 	driver->feature[peripheral].rcvd_feature_mask = 1;
+	DIAG_LOG(DIAG_DEBUG_CONTROL,
+	"diag: Received feature mask for peripheral %d\n", peripheral);
 
 	for (i = 0; i < feature_mask_len && read_len < len; i++) {
 		feature_mask = *(uint8_t *)ptr;
@@ -431,6 +498,10 @@
 
 	process_socket_feature(peripheral);
 	process_log_on_demand_feature(peripheral);
+
+	DIAG_LOG(DIAG_DEBUG_CONTROL,
+		"diag: Peripheral(%d) feature mask is processed\n",
+		peripheral);
 }
 
 static void process_last_event_report(uint8_t *buf, uint32_t len,
@@ -442,14 +513,23 @@
 	uint32_t pkt_len = sizeof(uint32_t) + sizeof(uint16_t);
 	uint16_t event_size = 0;
 
-	if (!buf || peripheral >= NUM_PERIPHERALS || len != pkt_len)
+	if (!buf || peripheral >= NUM_PERIPHERALS || len != pkt_len) {
+		DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
+		"diag: Invalid parameters:(!buf) = %d, peripheral = %d, len = %d, pkt_len = %d\n",
+		!buf, peripheral, len, pkt_len);
 		return;
+	}
+
+	DIAG_LOG(DIAG_DEBUG_CONTROL,
+		"diag:started processing last event report for peripheral (%d)\n",
+		peripheral);
 
 	mutex_lock(&event_mask.lock);
 	header = (struct diag_ctrl_last_event_report *)ptr;
 	event_size = ((header->event_last_id / 8) + 1);
 	if (event_size >= driver->event_mask_size) {
-		pr_debug("diag: In %s, receiving event mask size more that Apps can handle\n",
+		DIAG_LOG(DIAG_DEBUG_CONTROL,
+			"diag: In %s, receiving event mask size more that Apps can handle\n",
 			 __func__);
 		temp = krealloc(driver->event_mask->ptr, event_size,
 				GFP_KERNEL);
@@ -467,6 +547,9 @@
 		driver->last_event_id = header->event_last_id;
 err:
 	mutex_unlock(&event_mask.lock);
+	DIAG_LOG(DIAG_DEBUG_CONTROL,
+		"diag: last event report processed for peripheral (%d)\n",
+		peripheral);
 }
 
 static void process_log_range_report(uint8_t *buf, uint32_t len,
@@ -480,8 +563,15 @@
 	struct diag_ctrl_log_range *log_range = NULL;
 	struct diag_log_mask_t *mask_ptr = NULL;
 
-	if (!buf || peripheral >= NUM_PERIPHERALS || len < 0)
+	if (!buf || peripheral >= NUM_PERIPHERALS || len < 0) {
+		DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
+		"diag: Invalid parameters:(!buf) = %d, peripheral = %d, len = %d\n",
+		!buf, peripheral, len);
 		return;
+	}
+	DIAG_LOG(DIAG_DEBUG_CONTROL,
+		"diag:started processing log range report for peripheral(%d)\n",
+		peripheral);
 
 	header = (struct diag_ctrl_log_range_report *)ptr;
 	ptr += header_len;
@@ -507,6 +597,9 @@
 		mask_ptr->range = LOG_ITEMS_TO_SIZE(log_range->num_items);
 		mutex_unlock(&(mask_ptr->lock));
 	}
+	DIAG_LOG(DIAG_DEBUG_CONTROL,
+		"diag: log range report processed for peripheral (%d)\n",
+		peripheral);
 }
 
 static int update_msg_mask_tbl_entry(struct diag_msg_mask_t *mask,
@@ -514,8 +607,12 @@
 {
 	uint32_t temp_range;
 
-	if (!mask || !range)
+	if (!mask || !range) {
+		DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
+		"diag: Invalid %s\n",
+		(!mask ? "mask" : (!range ? "range" : " ")));
 		return -EIO;
+	}
 	if (range->ssid_last < range->ssid_first) {
 		pr_err("diag: In %s, invalid ssid range, first: %d, last: %d\n",
 		       __func__, range->ssid_first, range->ssid_last);
@@ -547,8 +644,16 @@
 	uint8_t *temp = NULL;
 	uint32_t min_len = header_len - sizeof(struct diag_ctrl_pkt_header_t);
 
-	if (!buf || peripheral >= NUM_PERIPHERALS || len < min_len)
+	if (!buf || peripheral >= NUM_PERIPHERALS || len < min_len) {
+		DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
+		"diag: Invalid parameters:(!buf) = %d, peripheral = %d, len = %d, min_len = %d\n",
+		!buf, peripheral, len, min_len);
 		return;
+	}
+
+	DIAG_LOG(DIAG_DEBUG_CONTROL,
+		"diag: started processing ssid range for peripheral (%d)\n",
+		peripheral);
 
 	header = (struct diag_ctrl_ssid_range_report *)ptr;
 	ptr += header_len;
@@ -600,6 +705,9 @@
 		driver->msg_mask_tbl_count += 1;
 	}
 	mutex_unlock(&driver->msg_mask_lock);
+	DIAG_LOG(DIAG_DEBUG_CONTROL,
+		"diag: processed ssid range for peripheral(%d)\n",
+		peripheral);
 }
 
 static void diag_build_time_mask_update(uint8_t *buf,
@@ -616,8 +724,12 @@
 	uint32_t *dest_ptr = NULL;
 	struct diag_msg_mask_t *build_mask = NULL;
 
-	if (!range || !buf)
+	if (!range || !buf) {
+		DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
+		"diag: Invalid %s\n",
+		(!range ? "range" : (!buf ? "buf" : " ")));
 		return;
+	}
 
 	if (range->ssid_last < range->ssid_first) {
 		pr_err("diag: In %s, invalid ssid range, first: %d, last: %d\n",
@@ -679,8 +791,16 @@
 	struct diag_ctrl_build_mask_report *header = NULL;
 	struct diag_ssid_range_t *range = NULL;
 
-	if (!buf || peripheral >= NUM_PERIPHERALS || len < header_len)
+	if (!buf || peripheral >= NUM_PERIPHERALS || len < header_len) {
+		DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
+		"diag: Invalid parameters:(!buf) = %d, peripheral = %d, len = %d, header_len = %d\n",
+		!buf, peripheral, len, header_len);
 		return;
+	}
+
+	DIAG_LOG(DIAG_DEBUG_CONTROL,
+		"diag: started processing build mask for peripheral(%d)\n",
+		peripheral);
 
 	header = (struct diag_ctrl_build_mask_report *)ptr;
 	ptr += header_len;
@@ -696,6 +816,8 @@
 		ptr += num_items * sizeof(uint32_t);
 		read_len += num_items * sizeof(uint32_t);
 	}
+	DIAG_LOG(DIAG_DEBUG_CONTROL,
+		"diag: processing build mask complete (%d)\n", peripheral);
 }
 
 int diag_add_diag_id_to_list(uint8_t diag_id, char *process_name,
@@ -703,8 +825,12 @@
 {
 	struct diag_id_tbl_t *new_item = NULL;
 
-	if (!process_name || diag_id == 0)
+	if (!process_name || diag_id == 0) {
+		DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
+		"diag: Invalid parameters: !process_name = %d, diag_id = %d\n",
+		!process_name, diag_id);
 		return -EINVAL;
+	}
 
 	new_item = kzalloc(sizeof(struct diag_id_tbl_t), GFP_KERNEL);
 	if (!new_item)
@@ -734,8 +860,10 @@
 	struct list_head *temp;
 	struct diag_id_tbl_t *item = NULL;
 
-	if (!process_name || !diag_id)
+	if (!process_name || !diag_id) {
+		DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "diag: Invalid parameters\n");
 		return -EINVAL;
+	}
 
 	mutex_lock(&driver->diag_id_mutex);
 	list_for_each_safe(start, temp, &driver->diag_id_list) {
@@ -762,8 +890,12 @@
 	uint8_t local_diag_id = 0;
 	uint8_t new_request = 0, i = 0, ch_type = 0;
 
-	if (!buf || len == 0 || peripheral >= NUM_PERIPHERALS)
+	if (!buf || len == 0 || peripheral >= NUM_PERIPHERALS) {
+		DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
+		"diag: Invalid parameters: !buf = %d, len = %d, peripheral = %d\n",
+		!buf, len, peripheral);
 		return;
+	}
 
 	header = (struct diag_ctrl_diagid *)buf;
 	process_name = (char *)&header->process_name;
@@ -841,7 +973,7 @@
 		fwd_info = &peripheral_info[TYPE_DATA][peripheral];
 		diagfwd_buffers_init(fwd_info);
 		DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
-		"diag: diag_id sent = %d to peripheral = %d with diag_id = %d for %s :\n",
+		"diag: diag_id sent = %d to peripheral = %d with diag_id = %d for %s\n",
 			driver->diag_id_sent[peripheral], peripheral,
 			ctrl_pkt.diag_id, process_name);
 	}
@@ -855,8 +987,10 @@
 	uint8_t *ptr = buf;
 	struct diag_ctrl_pkt_header_t *ctrl_pkt = NULL;
 
-	if (!buf || len <= 0 || !p_info)
+	if (!buf || len <= 0 || !p_info) {
+		DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "diag: Invalid parameters\n");
 		return;
+	}
 
 	if (reg_dirty & PERIPHERAL_MASK(p_info->peripheral)) {
 		pr_err_ratelimited("diag: dropping command registration from peripheral %d\n",
@@ -866,6 +1000,9 @@
 
 	while (read_len + header_len < len) {
 		ctrl_pkt = (struct diag_ctrl_pkt_header_t *)ptr;
+		DIAG_LOG(DIAG_DEBUG_CONTROL,
+			"diag:peripheral: %d: pkt_id: %d\n",
+			p_info->peripheral, ctrl_pkt->pkt_id);
 		switch (ctrl_pkt->pkt_id) {
 		case DIAG_CTRL_MSG_REG:
 			process_command_registration(ptr, ctrl_pkt->len,
@@ -904,12 +1041,15 @@
 						   p_info->peripheral);
 			break;
 		default:
-			pr_debug("diag: Control packet %d not supported\n",
-				 ctrl_pkt->pkt_id);
+			DIAG_LOG(DIAG_DEBUG_CONTROL,
+			"diag: Control packet %d not supported\n",
+			 ctrl_pkt->pkt_id);
 		}
 		ptr += header_len + ctrl_pkt->len;
 		read_len += header_len + ctrl_pkt->len;
 	}
+	DIAG_LOG(DIAG_DEBUG_CONTROL,
+	"diag: control packet processing complete\n");
 }
 
 static int diag_compute_real_time(int idx)
@@ -1127,15 +1267,16 @@
 	for (i = 0; i < DIAG_NUM_PROC; i++) {
 		temp_real_time = diag_compute_real_time(i);
 		if (temp_real_time == driver->real_time_mode[i]) {
-			pr_debug("diag: did not update real time mode on proc %d, already in the req mode %d",
+			DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
+				"diag: did not update real time mode on proc %d, already in the req mode %d\n",
 				i, temp_real_time);
 			continue;
 		}
 
 		if (i == DIAG_LOCAL_PROC) {
 			if (!send_update) {
-				pr_debug("diag: In %s, cannot send real time mode pkt since one of the periperhal is in buffering mode\n",
-					 __func__);
+				DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
+				"diag: cannot send real time mode pkt since one of the periperhal is in buffering mode\n");
 				break;
 			}
 			for (j = 0; j < NUM_PERIPHERALS; j++)
@@ -1169,7 +1310,8 @@
 			temp_real_time = MODE_NONREALTIME;
 		}
 		if (temp_real_time == driver->real_time_mode[i]) {
-			pr_debug("diag: did not update real time mode on proc %d, already in the req mode %d",
+			DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
+				"diag: did not update real time mode on proc %d, already in the req mode %d\n",
 				i, temp_real_time);
 			continue;
 		}
@@ -1204,8 +1346,8 @@
 
 	if (!driver->diagfwd_cntl[peripheral] ||
 	    !driver->diagfwd_cntl[peripheral]->ch_open) {
-		pr_debug("diag: In %s, control channel is not open, p: %d\n",
-			 __func__, peripheral);
+		DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
+		"diag: control channel is not open, p: %d\n", peripheral);
 		return err;
 	}
 
@@ -1317,8 +1459,9 @@
 	}
 
 	if (!driver->feature[peripheral].peripheral_buffering) {
-		pr_debug("diag: In %s, peripheral %d doesn't support buffering\n",
-			 __func__, peripheral);
+		DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
+			"diag: peripheral %d doesn't support buffering\n",
+			 peripheral);
 		driver->buffering_flag[params->peripheral] = 0;
 		return -EIO;
 	}
@@ -1383,8 +1526,9 @@
 
 	if (!driver->diagfwd_cntl[peripheral] ||
 	    !driver->diagfwd_cntl[peripheral]->ch_open) {
-		pr_debug("diag: In %s, control channel is not open, p: %d\n",
-			 __func__, peripheral);
+		DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
+			"diag: control channel is not open, p: %d\n",
+			 peripheral);
 		return -ENODEV;
 	}
 
@@ -1413,15 +1557,17 @@
 	struct diag_ctrl_drain_immediate_v2 ctrl_pkt_v2;
 
 	if (!driver->feature[peripheral].peripheral_buffering) {
-		pr_debug("diag: In %s, peripheral  %d doesn't support buffering\n",
-			 __func__, peripheral);
+		DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
+			"diag: peripheral  %d doesn't support buffering\n",
+			 peripheral);
 		return -EINVAL;
 	}
 
 	if (!driver->diagfwd_cntl[peripheral] ||
 	    !driver->diagfwd_cntl[peripheral]->ch_open) {
-		pr_debug("diag: In %s, control channel is not open, p: %d\n",
-			 __func__, peripheral);
+		DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
+			"diag: control channel is not open, p: %d\n",
+			 peripheral);
 		return -ENODEV;
 	}
 
@@ -1478,8 +1624,9 @@
 	}
 
 	if (!driver->feature[peripheral].peripheral_buffering) {
-		pr_debug("diag: In %s, peripheral  %d doesn't support buffering\n",
-			 __func__, peripheral);
+		DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
+			"diag: peripheral  %d doesn't support buffering\n",
+			 peripheral);
 		return -EINVAL;
 	}
 
@@ -1557,15 +1704,17 @@
 	}
 
 	if (!driver->feature[peripheral].peripheral_buffering) {
-		pr_debug("diag: In %s, peripheral  %d doesn't support buffering\n",
-			 __func__, peripheral);
+		DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
+			"diag: peripheral  %d doesn't support buffering\n",
+			 peripheral);
 		return -EINVAL;
 	}
 
 	if (!driver->diagfwd_cntl[peripheral] ||
 	    !driver->diagfwd_cntl[peripheral]->ch_open) {
-		pr_debug("diag: In %s, control channel is not open, p: %d\n",
-			 __func__, peripheral);
+		DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
+			"diag: control channel is not open, p: %d\n",
+			 peripheral);
 		return -ENODEV;
 	}
 
diff --git a/drivers/char/diag/diagfwd_peripheral.c b/drivers/char/diag/diagfwd_peripheral.c
index 7225dc2..2022e7b 100644
--- a/drivers/char/diag/diagfwd_peripheral.c
+++ b/drivers/char/diag/diagfwd_peripheral.c
@@ -723,6 +723,7 @@
 				   unsigned char *buf, int len)
 {
 	if (!fwd_info) {
+		DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "diag: Invalid fwd_info\n");
 		diag_ws_release();
 		return;
 	}
@@ -743,8 +744,12 @@
 	 */
 	diag_ws_on_copy_fail(DIAG_WS_MUX);
 	/* Reset the buffer in_busy value after processing the data */
-	if (fwd_info->buf_1)
+	if (fwd_info->buf_1) {
 		atomic_set(&fwd_info->buf_1->in_busy, 0);
+		DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
+		"Buffer 1 for core PD is marked free, p: %d, t: %d\n",
+			fwd_info->peripheral, fwd_info->type);
+	}
 
 	diagfwd_queue_read(fwd_info);
 	diagfwd_queue_read(&peripheral_info[TYPE_DATA][fwd_info->peripheral]);
@@ -769,8 +774,12 @@
 
 	diag_dci_process_peripheral_data(fwd_info, (void *)buf, len);
 	/* Reset the buffer in_busy value after processing the data */
-	if (fwd_info->buf_1)
+	if (fwd_info->buf_1) {
 		atomic_set(&fwd_info->buf_1->in_busy, 0);
+		DIAG_LOG(DIAG_DEBUG_DCI,
+		"Buffer 1 for core PD is marked free, p: %d, t: %d\n",
+			fwd_info->peripheral, fwd_info->type);
+	}
 
 	diagfwd_queue_read(fwd_info);
 }
@@ -1638,13 +1647,15 @@
 	struct diagfwd_buf_t *temp_buf = NULL;
 
 	if (!fwd_info) {
+		DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "diag: Invalid fwd_info\n");
 		diag_ws_release();
 		return;
 	}
 
 	if (!fwd_info->inited || !atomic_read(&fwd_info->opened)) {
-		pr_debug("diag: In %s, p: %d, t: %d, inited: %d, opened: %d  ch_open: %d\n",
-			 __func__, fwd_info->peripheral, fwd_info->type,
+		DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
+			"diag: p: %d, t: %d, inited: %d, opened: %d, ch_open: %d\n",
+			 fwd_info->peripheral, fwd_info->type,
 			 fwd_info->inited, atomic_read(&fwd_info->opened),
 			 fwd_info->ch_open);
 		diag_ws_release();
@@ -1680,8 +1691,9 @@
 			atomic_set(&temp_buf->in_busy, 1);
 		}
 	} else {
-		pr_debug("diag: In %s, both buffers are empty for p: %d, t: %d\n",
-			 __func__, fwd_info->peripheral, fwd_info->type);
+		DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
+			"diag: both buffers are busy for p: %d, t: %d\n",
+			 fwd_info->peripheral, fwd_info->type);
 	}
 
 	if (!read_buf) {
diff --git a/drivers/crypto/msm/ice.c b/drivers/crypto/msm/ice.c
index f15267e..199d573 100644
--- a/drivers/crypto/msm/ice.c
+++ b/drivers/crypto/msm/ice.c
@@ -77,6 +77,8 @@
 #define QCOM_ICE_ENCRYPT	0x1
 #define QCOM_ICE_DECRYPT	0x2
 #define QCOM_SECT_LEN_IN_BYTE	512
+#define QCOM_UD_FOOTER_SIZE	0x4000
+#define QCOM_UD_FOOTER_SECS	(QCOM_UD_FOOTER_SIZE / QCOM_SECT_LEN_IN_BYTE)
 
 struct ice_clk_info {
 	struct list_head list;
@@ -127,8 +129,6 @@
 };
 
 static int ice_fde_flag;
-static unsigned long userdata_start;
-static unsigned long userdata_end;
 static struct ice_crypto_setting ice_data;
 
 static int qti_ice_setting_config(struct request *req,
@@ -160,17 +160,21 @@
 		memcpy(&setting->crypto_data, crypto_data,
 				sizeof(setting->crypto_data));
 
-		if (rq_data_dir(req) == WRITE &&
-				(ice_fde_flag & QCOM_ICE_ENCRYPT))
-			setting->encr_bypass = false;
-		else if (rq_data_dir(req) == READ &&
-				(ice_fde_flag & QCOM_ICE_DECRYPT))
-			setting->decr_bypass = false;
-		else {
+		switch (rq_data_dir(req)) {
+		case WRITE:
+			if (!ice_fde_flag || (ice_fde_flag & QCOM_ICE_ENCRYPT))
+				setting->encr_bypass = false;
+			break;
+		case READ:
+			if (!ice_fde_flag || (ice_fde_flag & QCOM_ICE_DECRYPT))
+				setting->decr_bypass = false;
+			break;
+		default:
 			/* Should I say BUG_ON */
 			setting->encr_bypass = true;
 			setting->decr_bypass = true;
-			pr_debug("%s direction unknown", __func__);
+			pr_debug("%s(): direction unknown\n", __func__);
+			break;
 		}
 	}
 
@@ -184,26 +188,6 @@
 }
 EXPORT_SYMBOL(qcom_ice_set_fde_flag);
 
-int qcom_ice_set_fde_conf(sector_t s_sector, sector_t size,
-					int index, int mode)
-{
-	userdata_start = s_sector;
-	userdata_end = s_sector + size;
-	if (INT_MAX - s_sector < size) {
-		WARN_ON(1);
-		return -EINVAL;
-	}
-	ice_data.key_index = index;
-	ice_data.algo_mode = mode;
-	ice_data.key_size = ICE_CRYPTO_KEY_SIZE_256;
-	ice_data.key_mode = ICE_CRYPTO_USE_LUT_SW_KEY;
-
-	pr_debug("%s sector info set start %lu end %lu\n", __func__,
-		userdata_start, userdata_end);
-	return 0;
-}
-EXPORT_SYMBOL(qcom_ice_set_fde_conf);
-
 static int qcom_ice_enable_clocks(struct ice_device *, bool);
 
 #ifdef CONFIG_MSM_BUS_SCALING
@@ -1486,10 +1470,13 @@
 		struct request *req,
 		struct ice_data_setting *setting, bool async)
 {
+	struct ice_crypto_setting *crypto_data;
 	struct ice_crypto_setting pfk_crypto_data = {0};
 	int ret = 0;
 	bool is_pfe = false;
 	sector_t data_size;
+	union map_info *info;
+	unsigned long sec_end = 0;
 
 	if (!pdev || !req) {
 		pr_err("%s: Invalid params passed\n", __func__);
@@ -1525,22 +1512,46 @@
 				&pfk_crypto_data, setting);
 	}
 
-	if (ice_fde_flag == 0)
-		return 0;
-
-	if ((req->__sector >= userdata_start) &&
-			(req->__sector < userdata_end)) {
-	/*
-	 * Ugly hack to address non-block-size aligned userdata end address in
-	 * eMMC based devices.
-	 */
-		data_size = req->__data_len/QCOM_SECT_LEN_IN_BYTE;
-
-		if ((req->__sector + data_size) > userdata_end)
-			return 0;
-		else
+	if (!ice_fde_flag) {
+		if (bio_flagged(req->bio, BIO_INLINECRYPT)) {
+			info = dm_get_rq_mapinfo(req);
+			if (!info) {
+				pr_debug("%s info not available in request\n",
+							__func__);
+				return 0;
+			}
+			crypto_data = (struct ice_crypto_setting *)info->ptr;
+			if (!crypto_data) {
+				pr_err("%s crypto_data not available in req\n",
+							__func__);
+				return -EINVAL;
+			}
 			return qti_ice_setting_config(req, pdev,
-				&ice_data, setting);
+						crypto_data, setting);
+		}
+		return 0;
+	}
+
+	if (req->part && req->part->info && req->part->info->volname[0]) {
+		if (!strcmp(req->part->info->volname, "userdata")) {
+			sec_end = req->part->start_sect + req->part->nr_sects -
+					QCOM_UD_FOOTER_SECS;
+			if ((req->__sector >= req->part->start_sect) &&
+				(req->__sector < sec_end)) {
+				/*
+				 * Ugly hack to address non-block-size aligned
+				 * userdata end address in eMMC based devices.
+				 */
+				data_size = req->__data_len /
+						QCOM_SECT_LEN_IN_BYTE;
+
+				if ((req->__sector + data_size) > sec_end)
+					return 0;
+				else
+					return qti_ice_setting_config(req, pdev,
+						&ice_data, setting);
+			}
+		}
 	}
 
 	/*
diff --git a/drivers/devfreq/arm-memlat-mon.c b/drivers/devfreq/arm-memlat-mon.c
index 81f7c16..fe249e7 100644
--- a/drivers/devfreq/arm-memlat-mon.c
+++ b/drivers/devfreq/arm-memlat-mon.c
@@ -420,6 +420,7 @@
 	.driver = {
 		.name = "arm-memlat-mon",
 		.of_match_table = memlat_match_table,
+		.suppress_bind_attrs = true,
 	},
 };
 
diff --git a/drivers/devfreq/bimc-bwmon.c b/drivers/devfreq/bimc-bwmon.c
index 33e16261..d2aaffb 100644
--- a/drivers/devfreq/bimc-bwmon.c
+++ b/drivers/devfreq/bimc-bwmon.c
@@ -1128,6 +1128,7 @@
 	.driver = {
 		.name = "bimc-bwmon",
 		.of_match_table = bimc_bwmon_match_table,
+		.suppress_bind_attrs = true,
 	},
 };
 
diff --git a/drivers/dma-buf/sync_file.c b/drivers/dma-buf/sync_file.c
index 7053bb4..1936383 100644
--- a/drivers/dma-buf/sync_file.c
+++ b/drivers/dma-buf/sync_file.c
@@ -305,7 +305,8 @@
 
 	poll_wait(file, &sync_file->wq, wait);
 
-	if (!test_and_set_bit(POLL_ENABLED, &sync_file->flags)) {
+	if (list_empty(&sync_file->cb.node) &&
+	    !test_and_set_bit(POLL_ENABLED, &sync_file->flags)) {
 		if (fence_add_callback(sync_file->fence, &sync_file->cb,
 					   fence_check_cb_func) < 0)
 			wake_up_all(&sync_file->wq);
diff --git a/drivers/gpio/gpio-aspeed.c b/drivers/gpio/gpio-aspeed.c
index 03a5925..a9daf71 100644
--- a/drivers/gpio/gpio-aspeed.c
+++ b/drivers/gpio/gpio-aspeed.c
@@ -256,7 +256,7 @@
 	if (set)
 		reg |= bit;
 	else
-		reg &= bit;
+		reg &= ~bit;
 	iowrite32(reg, addr);
 
 	spin_unlock_irqrestore(&gpio->lock, flags);
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 4f54ff4..56b2419 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -425,7 +425,7 @@
 	struct gpiohandle_request handlereq;
 	struct linehandle_state *lh;
 	struct file *file;
-	int fd, i, ret;
+	int fd, i, count = 0, ret;
 
 	if (copy_from_user(&handlereq, ip, sizeof(handlereq)))
 		return -EFAULT;
@@ -471,6 +471,7 @@
 		if (ret)
 			goto out_free_descs;
 		lh->descs[i] = desc;
+		count = i;
 
 		if (lflags & GPIOHANDLE_REQUEST_ACTIVE_LOW)
 			set_bit(FLAG_ACTIVE_LOW, &desc->flags);
@@ -537,7 +538,7 @@
 out_put_unused_fd:
 	put_unused_fd(fd);
 out_free_descs:
-	for (; i >= 0; i--)
+	for (i = 0; i < count; i++)
 		gpiod_free(lh->descs[i]);
 	kfree(lh->label);
 out_free_lh:
@@ -794,7 +795,7 @@
 	desc = &gdev->descs[offset];
 	ret = gpiod_request(desc, le->label);
 	if (ret)
-		goto out_free_desc;
+		goto out_free_label;
 	le->desc = desc;
 	le->eflags = eflags;
 
diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c
index e1d47d5..3517c0e 100644
--- a/drivers/gpu/drm/i915/intel_lvds.c
+++ b/drivers/gpu/drm/i915/intel_lvds.c
@@ -321,7 +321,8 @@
 
 	I915_WRITE(PP_CONTROL(0), I915_READ(PP_CONTROL(0)) | PANEL_POWER_ON);
 	POSTING_READ(lvds_encoder->reg);
-	if (intel_wait_for_register(dev_priv, PP_STATUS(0), PP_ON, PP_ON, 1000))
+
+	if (intel_wait_for_register(dev_priv, PP_STATUS(0), PP_ON, PP_ON, 5000))
 		DRM_ERROR("timed out waiting for panel to power on\n");
 
 	intel_panel_enable_backlight(intel_connector);
diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c
index 881bf48..7505655 100644
--- a/drivers/gpu/drm/vc4/vc4_plane.c
+++ b/drivers/gpu/drm/vc4/vc4_plane.c
@@ -533,7 +533,7 @@
 	 * the scl fields here.
 	 */
 	if (num_planes == 1) {
-		scl0 = vc4_get_scl_field(state, 1);
+		scl0 = vc4_get_scl_field(state, 0);
 		scl1 = scl0;
 	} else {
 		scl0 = vc4_get_scl_field(state, 1);
diff --git a/drivers/infiniband/core/device.c b/drivers/infiniband/core/device.c
index 760ef60..15f4bdf 100644
--- a/drivers/infiniband/core/device.c
+++ b/drivers/infiniband/core/device.c
@@ -999,8 +999,7 @@
 		return -ENOMEM;
 
 	ib_comp_wq = alloc_workqueue("ib-comp-wq",
-			WQ_UNBOUND | WQ_HIGHPRI | WQ_MEM_RECLAIM,
-			WQ_UNBOUND_MAX_ACTIVE);
+			WQ_HIGHPRI | WQ_MEM_RECLAIM | WQ_SYSFS, 0);
 	if (!ib_comp_wq) {
 		ret = -ENOMEM;
 		goto err;
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index 2b31ed3..d61f20e 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -6979,19 +6979,6 @@
 		break;
 	}
 
-	case QSEECOM_IOCTL_SET_ENCDEC_INFO: {
-		struct qseecom_encdec_conf_t conf;
-
-		ret = copy_from_user(&conf, argp, sizeof(conf));
-		if (ret) {
-			pr_err("copy_from_user failed\n");
-			return -EFAULT;
-		}
-		ret = qcom_ice_set_fde_conf(conf.start_sector, conf.fs_size,
-					conf.index, conf.mode);
-		break;
-	}
-
 	case QSEECOM_IOCTL_UNREGISTER_LISTENER_REQ: {
 		if ((data->listener.id == 0) ||
 			(data->type != QSEECOM_LISTENER_SERVICE)) {
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 2405ae3..e1cced6 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -3630,7 +3630,7 @@
 	 * or disable state so cannot receive any completion of
 	 * other requests.
 	 */
-	BUG_ON(test_bit(CMDQ_STATE_ERR, &ctx_info->curr_state));
+	WARN_ON(test_bit(CMDQ_STATE_ERR, &ctx_info->curr_state));
 
 	/* clear pending request */
 	BUG_ON(!test_and_clear_bit(cmdq_req->tag,
@@ -3664,7 +3664,7 @@
 out:
 
 	mmc_cmdq_clk_scaling_stop_busy(host, true, is_dcmd);
-	if (!test_bit(CMDQ_STATE_ERR, &ctx_info->curr_state)) {
+	if (!(err || cmdq_req->resp_err)) {
 		mmc_host_clk_release(host);
 		wake_up(&ctx_info->wait);
 		mmc_put_card(host->card);
diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c
index 551f0f8..91d8a48 100644
--- a/drivers/net/bonding/bond_alb.c
+++ b/drivers/net/bonding/bond_alb.c
@@ -450,7 +450,7 @@
 {
 	int i;
 
-	if (!client_info->slave)
+	if (!client_info->slave || !is_valid_ether_addr(client_info->mac_dst))
 		return;
 
 	for (i = 0; i < RLB_ARP_BURST_SIZE; i++) {
@@ -944,6 +944,10 @@
 	skb->priority = TC_PRIO_CONTROL;
 	skb->dev = slave->dev;
 
+	netdev_dbg(slave->bond->dev,
+		   "Send learning packet: dev %s mac %pM vlan %d\n",
+		   slave->dev->name, mac_addr, vid);
+
 	if (vid)
 		__vlan_hwaccel_put_tag(skb, vlan_proto, vid);
 
@@ -966,14 +970,13 @@
 	 */
 	rcu_read_lock();
 	netdev_for_each_all_upper_dev_rcu(bond->dev, upper, iter) {
-		if (is_vlan_dev(upper) && vlan_get_encap_level(upper) == 0) {
-			if (strict_match &&
-			    ether_addr_equal_64bits(mac_addr,
-						    upper->dev_addr)) {
+		if (is_vlan_dev(upper) &&
+		    bond->nest_level == vlan_get_encap_level(upper) - 1) {
+			if (upper->addr_assign_type == NET_ADDR_STOLEN) {
 				alb_send_lp_vid(slave, mac_addr,
 						vlan_dev_vlan_proto(upper),
 						vlan_dev_vlan_id(upper));
-			} else if (!strict_match) {
+			} else {
 				alb_send_lp_vid(slave, upper->dev_addr,
 						vlan_dev_vlan_proto(upper),
 						vlan_dev_vlan_id(upper));
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 13a015b..1a139d0 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -1732,6 +1732,8 @@
 	if (bond_mode_uses_xmit_hash(bond))
 		bond_update_slave_arr(bond, NULL);
 
+	bond->nest_level = dev_get_nest_level(bond_dev);
+
 	netdev_info(bond_dev, "Enslaving %s as %s interface with %s link\n",
 		    slave_dev->name,
 		    bond_is_active_slave(new_slave) ? "an active" : "a backup",
diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c
index c9d61a6..3a75352 100644
--- a/drivers/net/can/usb/kvaser_usb.c
+++ b/drivers/net/can/usb/kvaser_usb.c
@@ -1179,7 +1179,7 @@
 
 	skb = alloc_can_skb(priv->netdev, &cf);
 	if (!skb) {
-		stats->tx_dropped++;
+		stats->rx_dropped++;
 		return;
 	}
 
diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c
index 795a133..4ffbe85 100644
--- a/drivers/net/ethernet/broadcom/tg3.c
+++ b/drivers/net/ethernet/broadcom/tg3.c
@@ -8720,14 +8720,15 @@
 	tg3_mem_rx_release(tp);
 	tg3_mem_tx_release(tp);
 
-	/* Protect tg3_get_stats64() from reading freed tp->hw_stats. */
-	tg3_full_lock(tp, 0);
+	/* tp->hw_stats can be referenced safely:
+	 *     1. under rtnl_lock
+	 *     2. or under tp->lock if TG3_FLAG_INIT_COMPLETE is set.
+	 */
 	if (tp->hw_stats) {
 		dma_free_coherent(&tp->pdev->dev, sizeof(struct tg3_hw_stats),
 				  tp->hw_stats, tp->stats_mapping);
 		tp->hw_stats = NULL;
 	}
-	tg3_full_unlock(tp);
 }
 
 /*
@@ -14161,7 +14162,7 @@
 	struct tg3 *tp = netdev_priv(dev);
 
 	spin_lock_bh(&tp->lock);
-	if (!tp->hw_stats) {
+	if (!tp->hw_stats || !tg3_flag(tp, INIT_COMPLETE)) {
 		*stats = tp->net_stats_prev;
 		spin_unlock_bh(&tp->lock);
 		return stats;
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c
index 24977cc..9a4c4f8 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c
@@ -970,6 +970,22 @@
 	if (!coal->tx_max_coalesced_frames_irq)
 		return -EINVAL;
 
+	if (coal->tx_coalesce_usecs > MLX4_EN_MAX_COAL_TIME ||
+	    coal->rx_coalesce_usecs > MLX4_EN_MAX_COAL_TIME ||
+	    coal->rx_coalesce_usecs_low > MLX4_EN_MAX_COAL_TIME ||
+	    coal->rx_coalesce_usecs_high > MLX4_EN_MAX_COAL_TIME) {
+		netdev_info(dev, "%s: maximum coalesce time supported is %d usecs\n",
+			    __func__, MLX4_EN_MAX_COAL_TIME);
+		return -ERANGE;
+	}
+
+	if (coal->tx_max_coalesced_frames > MLX4_EN_MAX_COAL_PKTS ||
+	    coal->rx_max_coalesced_frames > MLX4_EN_MAX_COAL_PKTS) {
+		netdev_info(dev, "%s: maximum coalesced frames supported is %d\n",
+			    __func__, MLX4_EN_MAX_COAL_PKTS);
+		return -ERANGE;
+	}
+
 	priv->rx_frames = (coal->rx_max_coalesced_frames ==
 			   MLX4_EN_AUTO_CONF) ?
 				MLX4_EN_RX_COAL_TARGET :
diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
index 18f221d..247d340 100644
--- a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
+++ b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
@@ -141,6 +141,9 @@
 #define MLX4_EN_TX_COAL_PKTS	16
 #define MLX4_EN_TX_COAL_TIME	0x10
 
+#define MLX4_EN_MAX_COAL_PKTS	U16_MAX
+#define MLX4_EN_MAX_COAL_TIME	U16_MAX
+
 #define MLX4_EN_RX_RATE_LOW		400000
 #define MLX4_EN_RX_COAL_TIME_LOW	0
 #define MLX4_EN_RX_RATE_HIGH		450000
@@ -543,8 +546,8 @@
 	u16 rx_usecs_low;
 	u32 pkt_rate_high;
 	u16 rx_usecs_high;
-	u16 sample_interval;
-	u16 adaptive_rx_coal;
+	u32 sample_interval;
+	u32 adaptive_rx_coal;
 	u32 msg_enable;
 	u32 loopback_ok;
 	u32 validate_loopback;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c
index a8966e6..5d6eab1 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c
@@ -1924,26 +1924,35 @@
 	memset(vf_stats, 0, sizeof(*vf_stats));
 	vf_stats->rx_packets =
 		MLX5_GET_CTR(out, received_eth_unicast.packets) +
+		MLX5_GET_CTR(out, received_ib_unicast.packets) +
 		MLX5_GET_CTR(out, received_eth_multicast.packets) +
+		MLX5_GET_CTR(out, received_ib_multicast.packets) +
 		MLX5_GET_CTR(out, received_eth_broadcast.packets);
 
 	vf_stats->rx_bytes =
 		MLX5_GET_CTR(out, received_eth_unicast.octets) +
+		MLX5_GET_CTR(out, received_ib_unicast.octets) +
 		MLX5_GET_CTR(out, received_eth_multicast.octets) +
+		MLX5_GET_CTR(out, received_ib_multicast.octets) +
 		MLX5_GET_CTR(out, received_eth_broadcast.octets);
 
 	vf_stats->tx_packets =
 		MLX5_GET_CTR(out, transmitted_eth_unicast.packets) +
+		MLX5_GET_CTR(out, transmitted_ib_unicast.packets) +
 		MLX5_GET_CTR(out, transmitted_eth_multicast.packets) +
+		MLX5_GET_CTR(out, transmitted_ib_multicast.packets) +
 		MLX5_GET_CTR(out, transmitted_eth_broadcast.packets);
 
 	vf_stats->tx_bytes =
 		MLX5_GET_CTR(out, transmitted_eth_unicast.octets) +
+		MLX5_GET_CTR(out, transmitted_ib_unicast.octets) +
 		MLX5_GET_CTR(out, transmitted_eth_multicast.octets) +
+		MLX5_GET_CTR(out, transmitted_ib_multicast.octets) +
 		MLX5_GET_CTR(out, transmitted_eth_broadcast.octets);
 
 	vf_stats->multicast =
-		MLX5_GET_CTR(out, received_eth_multicast.packets);
+		MLX5_GET_CTR(out, received_eth_multicast.packets) +
+		MLX5_GET_CTR(out, received_ib_multicast.packets);
 
 	vf_stats->broadcast =
 		MLX5_GET_CTR(out, received_eth_broadcast.packets);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c
index 331a6ca..5f3402b 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c
@@ -153,6 +153,7 @@
 static void del_flow_table(struct fs_node *node);
 static void del_flow_group(struct fs_node *node);
 static void del_fte(struct fs_node *node);
+static void cleanup_root_ns(struct mlx5_flow_root_namespace *root_ns);
 
 static void tree_init_node(struct fs_node *node,
 			   unsigned int refcount,
@@ -1690,24 +1691,28 @@
 
 static int init_root_ns(struct mlx5_flow_steering *steering)
 {
+	int err;
 
 	steering->root_ns = create_root_ns(steering, FS_FT_NIC_RX);
 	if (!steering->root_ns)
-		goto cleanup;
+		return -ENOMEM;
 
-	if (init_root_tree(steering, &root_fs, &steering->root_ns->ns.node))
-		goto cleanup;
+	err = init_root_tree(steering, &root_fs, &steering->root_ns->ns.node);
+	if (err)
+		goto out_err;
 
 	set_prio_attrs(steering->root_ns);
 
-	if (create_anchor_flow_table(steering))
-		goto cleanup;
+	err = create_anchor_flow_table(steering);
+	if (err)
+		goto out_err;
 
 	return 0;
 
-cleanup:
-	mlx5_cleanup_fs(steering->dev);
-	return -ENOMEM;
+out_err:
+	cleanup_root_ns(steering->root_ns);
+	steering->root_ns = NULL;
+	return err;
 }
 
 static void clean_tree(struct fs_node *node)
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c
index 4ca82bd..eee6e59 100644
--- a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c
+++ b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c
@@ -854,6 +854,8 @@
 
 	netdev_tx_sent_queue(nd_q, txbuf->real_len);
 
+	skb_tx_timestamp(skb);
+
 	tx_ring->wr_p += nr_frags + 1;
 	if (nfp_net_tx_ring_should_stop(tx_ring))
 		nfp_net_tx_ring_stop(nd_q, tx_ring);
@@ -866,8 +868,6 @@
 		tx_ring->wr_ptr_add = 0;
 	}
 
-	skb_tx_timestamp(skb);
-
 	return NETDEV_TX_OK;
 
 err_unmap:
diff --git a/drivers/net/ethernet/realtek/8139too.c b/drivers/net/ethernet/realtek/8139too.c
index da4c2d8..1420dfb 100644
--- a/drivers/net/ethernet/realtek/8139too.c
+++ b/drivers/net/ethernet/realtek/8139too.c
@@ -2233,7 +2233,7 @@
 	struct rtl8139_private *tp = netdev_priv(dev);
 	const int irq = tp->pci_dev->irq;
 
-	disable_irq(irq);
+	disable_irq_nosync(irq);
 	rtl8139_interrupt(irq, dev);
 	enable_irq(irq);
 }
diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c
index dbb6364..59b932d 100644
--- a/drivers/net/ethernet/realtek/r8169.c
+++ b/drivers/net/ethernet/realtek/r8169.c
@@ -4861,6 +4861,9 @@
 static void rtl_pll_power_up(struct rtl8169_private *tp)
 {
 	rtl_generic_op(tp, tp->pll_power_ops.up);
+
+	/* give MAC/PHY some time to resume */
+	msleep(20);
 }
 
 static void rtl_init_pll_power_ops(struct rtl8169_private *tp)
diff --git a/drivers/net/ethernet/sun/niu.c b/drivers/net/ethernet/sun/niu.c
index a2371aa..e45e2f1 100644
--- a/drivers/net/ethernet/sun/niu.c
+++ b/drivers/net/ethernet/sun/niu.c
@@ -3442,7 +3442,7 @@
 
 		len = (val & RCR_ENTRY_L2_LEN) >>
 			RCR_ENTRY_L2_LEN_SHIFT;
-		len -= ETH_FCS_LEN;
+		append_size = len + ETH_HLEN + ETH_FCS_LEN;
 
 		addr = (val & RCR_ENTRY_PKT_BUF_ADDR) <<
 			RCR_ENTRY_PKT_BUF_ADDR_SHIFT;
@@ -3452,7 +3452,6 @@
 					 RCR_ENTRY_PKTBUFSZ_SHIFT];
 
 		off = addr & ~PAGE_MASK;
-		append_size = rcr_size;
 		if (num_rcr == 1) {
 			int ptype;
 
@@ -3465,7 +3464,7 @@
 			else
 				skb_checksum_none_assert(skb);
 		} else if (!(val & RCR_ENTRY_MULTI))
-			append_size = len - skb->len;
+			append_size = append_size - skb->len;
 
 		niu_rx_skb_append(skb, page, off, append_size, rcr_size);
 		if ((page->index + rp->rbr_block_size) - rcr_size == addr) {
diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c
index de33689..d7cb205 100644
--- a/drivers/net/ethernet/ti/cpsw.c
+++ b/drivers/net/ethernet/ti/cpsw.c
@@ -1141,6 +1141,8 @@
 	cpsw_ale_add_ucast(cpsw->ale, priv->mac_addr,
 			   HOST_PORT_NUM, ALE_VLAN |
 			   ALE_SECURE, slave->port_vlan);
+	cpsw_ale_control_set(cpsw->ale, slave_port,
+			     ALE_PORT_DROP_UNKNOWN_VLAN, 1);
 }
 
 static void soft_reset_slave(struct cpsw_slave *slave)
diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c
index 1029bd23..3e893fe 100644
--- a/drivers/net/usb/qmi_wwan.c
+++ b/drivers/net/usb/qmi_wwan.c
@@ -1039,6 +1039,18 @@
 		id->driver_info = (unsigned long)&qmi_wwan_info;
 	}
 
+	/* There are devices where the same interface number can be
+	 * configured as different functions. We should only bind to
+	 * vendor specific functions when matching on interface number
+	 */
+	if (id->match_flags & USB_DEVICE_ID_MATCH_INT_NUMBER &&
+	    desc->bInterfaceClass != USB_CLASS_VENDOR_SPEC) {
+		dev_dbg(&intf->dev,
+			"Rejecting interface number match for class %02x\n",
+			desc->bInterfaceClass);
+		return -ENODEV;
+	}
+
 	/* Quectel EC20 quirk where we've QMI on interface 4 instead of 0 */
 	if (quectel_ec20_detected(intf) && desc->bInterfaceNumber == 0) {
 		dev_dbg(&intf->dev, "Quectel EC20 quirk, skipping interface 0\n");
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
index 54354a3..538457e 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
@@ -2776,7 +2776,6 @@
 				   struct brcmf_bss_info_le *bi)
 {
 	struct wiphy *wiphy = cfg_to_wiphy(cfg);
-	struct ieee80211_channel *notify_channel;
 	struct cfg80211_bss *bss;
 	struct ieee80211_supported_band *band;
 	struct brcmu_chan ch;
@@ -2786,7 +2785,7 @@
 	u16 notify_interval;
 	u8 *notify_ie;
 	size_t notify_ielen;
-	s32 notify_signal;
+	struct cfg80211_inform_bss bss_data = {};
 
 	if (le32_to_cpu(bi->length) > WL_BSS_INFO_MAX) {
 		brcmf_err("Bss info is larger than buffer. Discarding\n");
@@ -2806,27 +2805,28 @@
 		band = wiphy->bands[NL80211_BAND_5GHZ];
 
 	freq = ieee80211_channel_to_frequency(channel, band->band);
-	notify_channel = ieee80211_get_channel(wiphy, freq);
+	bss_data.chan = ieee80211_get_channel(wiphy, freq);
+	bss_data.scan_width = NL80211_BSS_CHAN_WIDTH_20;
+	bss_data.boottime_ns = ktime_to_ns(ktime_get_boottime());
 
 	notify_capability = le16_to_cpu(bi->capability);
 	notify_interval = le16_to_cpu(bi->beacon_period);
 	notify_ie = (u8 *)bi + le16_to_cpu(bi->ie_offset);
 	notify_ielen = le32_to_cpu(bi->ie_length);
-	notify_signal = (s16)le16_to_cpu(bi->RSSI) * 100;
+	bss_data.signal = (s16)le16_to_cpu(bi->RSSI) * 100;
 
 	brcmf_dbg(CONN, "bssid: %pM\n", bi->BSSID);
 	brcmf_dbg(CONN, "Channel: %d(%d)\n", channel, freq);
 	brcmf_dbg(CONN, "Capability: %X\n", notify_capability);
 	brcmf_dbg(CONN, "Beacon interval: %d\n", notify_interval);
-	brcmf_dbg(CONN, "Signal: %d\n", notify_signal);
+	brcmf_dbg(CONN, "Signal: %d\n", bss_data.signal);
 
-	bss = cfg80211_inform_bss(wiphy, notify_channel,
-				  CFG80211_BSS_FTYPE_UNKNOWN,
-				  (const u8 *)bi->BSSID,
-				  0, notify_capability,
-				  notify_interval, notify_ie,
-				  notify_ielen, notify_signal,
-				  GFP_KERNEL);
+	bss = cfg80211_inform_bss_data(wiphy, &bss_data,
+				       CFG80211_BSS_FTYPE_UNKNOWN,
+				       (const u8 *)bi->BSSID,
+				       0, notify_capability,
+				       notify_interval, notify_ie,
+				       notify_ielen, GFP_KERNEL);
 
 	if (!bss)
 		return -ENOMEM;
diff --git a/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c b/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c
index 0991a99..bdce49b 100644
--- a/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c
+++ b/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2014, 2016-2017 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2014, 2016-2018 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
@@ -529,7 +529,7 @@
 			pad->pullup = arg;
 			break;
 		case PMIC_GPIO_CONF_STRENGTH:
-			if (arg > PMIC_GPIO_STRENGTH_LOW)
+			if (arg > PMIC_GPIO_STRENGTH_HIGH)
 				return -EINVAL;
 			pad->strength = arg;
 			break;
diff --git a/drivers/pinctrl/qcom/pinctrl-ssbi-gpio.c b/drivers/pinctrl/qcom/pinctrl-ssbi-gpio.c
index d3f5501d..a562ed7 100644
--- a/drivers/pinctrl/qcom/pinctrl-ssbi-gpio.c
+++ b/drivers/pinctrl/qcom/pinctrl-ssbi-gpio.c
@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2015, Sony Mobile Communications AB.
- * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013, 2018 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
@@ -365,7 +365,7 @@
 			banks |= BIT(0);
 			break;
 		case PM8XXX_QCOM_DRIVE_STRENGH:
-			if (arg > PMIC_GPIO_STRENGTH_LOW) {
+			if (arg > PM8921_GPIO_STRENGTH_LOW) {
 				dev_err(pctrl->dev, "invalid drive strength\n");
 				return -EINVAL;
 			}
diff --git a/drivers/platform/msm/ipa/ipa_clients/Makefile b/drivers/platform/msm/ipa/ipa_clients/Makefile
index 738d88f..a213130 100644
--- a/drivers/platform/msm/ipa/ipa_clients/Makefile
+++ b/drivers/platform/msm/ipa/ipa_clients/Makefile
@@ -1,4 +1,4 @@
-obj-$(CONFIG_IPA3) += ipa_usb.o odu_bridge.o ipa_mhi_client.o ipa_uc_offload.o ipa_wdi3.o
+obj-$(CONFIG_IPA3) += ipa_usb.o odu_bridge.o ipa_mhi_client.o ipa_uc_offload.o ipa_wdi3.o ipa_gsb.o
 obj-$(CONFIG_IPA) += odu_bridge.o ipa_mhi_client.o ipa_uc_offload.o ipa_wdi3.o
 obj-$(CONFIG_ECM_IPA) += ecm_ipa.o
 obj-$(CONFIG_RNDIS_IPA) += rndis_ipa.o
diff --git a/drivers/platform/msm/ipa/ipa_clients/ipa_gsb.c b/drivers/platform/msm/ipa/ipa_clients/ipa_gsb.c
new file mode 100644
index 0000000..df19384
--- /dev/null
+++ b/drivers/platform/msm/ipa/ipa_clients/ipa_gsb.c
@@ -0,0 +1,1071 @@
+/* Copyright (c) 2018, 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/debugfs.h>
+#include <linux/export.h>
+#include <linux/fs.h>
+#include <linux/if_ether.h>
+#include <linux/ioctl.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/msm_ipa.h>
+#include <linux/mutex.h>
+#include <linux/skbuff.h>
+#include <linux/types.h>
+#include <linux/ipv6.h>
+#include <net/addrconf.h>
+#include <linux/ipa.h>
+#include <linux/cdev.h>
+#include <linux/ipa_odu_bridge.h>
+#include "../ipa_common_i.h"
+#ifdef CONFIG_IPA3
+#include "../ipa_v3/ipa_pm.h"
+#endif
+
+#define IPA_GSB_DRV_NAME "ipa_gsb"
+
+#define MAX_SUPPORTED_IFACE 5
+
+#define IPA_GSB_DBG(fmt, args...) \
+	do { \
+		pr_debug(IPA_GSB_DRV_NAME " %s:%d " fmt, \
+			__func__, __LINE__, ## args); \
+		IPA_IPC_LOGGING(ipa_get_ipc_logbuf(), \
+			IPA_GSB_DRV_NAME " %s:%d " fmt, ## args); \
+		IPA_IPC_LOGGING(ipa_get_ipc_logbuf_low(), \
+			IPA_GSB_DRV_NAME " %s:%d " fmt, ## args); \
+	} while (0)
+
+#define IPA_GSB_DBG_LOW(fmt, args...) \
+	do { \
+		pr_debug(IPA_GSB_DRV_NAME " %s:%d " fmt, \
+			__func__, __LINE__, ## args); \
+		IPA_IPC_LOGGING(ipa_get_ipc_logbuf_low(), \
+			IPA_GSB_DRV_NAME " %s:%d " fmt, ## args); \
+	} while (0)
+
+#define IPA_GSB_ERR(fmt, args...) \
+	do { \
+		pr_err(IPA_GSB_DRV_NAME " %s:%d " fmt, \
+			__func__, __LINE__, ## args); \
+		IPA_IPC_LOGGING(ipa_get_ipc_logbuf(), \
+			IPA_GSB_DRV_NAME " %s:%d " fmt, ## args); \
+		IPA_IPC_LOGGING(ipa_get_ipc_logbuf_low(), \
+			IPA_GSB_DRV_NAME " %s:%d " fmt, ## args); \
+	} while (0)
+
+#define IPA_GSB_MAX_MSG_LEN 512
+static char dbg_buff[IPA_GSB_MAX_MSG_LEN];
+
+#define IPA_GSB_SKB_HEADROOM 256
+#define IPA_GSB_AGGR_BYTE_LIMIT 6
+#define IPA_GSB_AGGR_TIME_LIMIT 1
+
+static struct dentry *dent;
+static struct dentry *dfile_stats;
+
+/**
+ * struct stats - driver statistics,
+ * @num_ul_packets: number of uplink packets
+ * @num_dl_packets: number of downlink packets
+ * @num_insufficient_headroom_packets: number of
+	packets with insufficient headroom
+ */
+struct stats {
+	u64 num_ul_packets;
+	u64 num_dl_packets;
+	u64 num_insufficient_headroom_packets;
+};
+
+/**
+ * struct ipa_gsb_mux_hdr - ipa gsb mux header,
+ * @iface_hdl: interface handle
+ * @qmap_id: qmap id
+ * @pkt_size: packet size
+ */
+struct ipa_gsb_mux_hdr {
+	u8 iface_hdl;
+	u8 qmap_id;
+	u16 pkt_size;
+};
+
+/**
+ * struct ipa_gsb_iface_info - GSB interface information
+ * @netdev_name: network interface name
+ * @device_ethaddr: network interface ethernet address
+ * @priv: client's private data. to be used in client's callbacks
+ * @tx_dp_notify: client callback for handling IPA ODU_PROD callback
+ * @send_dl_skb: client callback for sending skb in downlink direction
+ * @iface_stats: statistics, how many packets were transmitted
+ * using the SW bridge.
+ * @partial_hdr_hdl: handle for partial header
+ * @wakeup_request: client callback to wakeup
+ * @is_conencted: is interface connected ?
+ * @is_resumed: is interface resumed ?
+ * @iface_hdl: interface handle
+ */
+struct ipa_gsb_iface_info {
+	char netdev_name[IPA_RESOURCE_NAME_MAX];
+	u8 device_ethaddr[ETH_ALEN];
+	void *priv;
+	ipa_notify_cb tx_dp_notify;
+	int (*send_dl_skb)(void *priv, struct sk_buff *skb);
+	struct stats iface_stats;
+	uint32_t partial_hdr_hdl[IPA_IP_MAX];
+	void (*wakeup_request)(void *);
+	bool is_connected;
+	bool is_resumed;
+	u8 iface_hdl;
+};
+
+/**
+ * struct ipa_gsb_context - GSB driver context information
+ * @logbuf: buffer of ipc logging
+ * @logbuf_low: buffer of ipc logging (low priority)
+ * @lock: mutex lock
+ * @prod_hdl: handle for prod pipe
+ * @cons_hdl: handle for cons pipe
+ * @ipa_sys_desc_size: sys pipe desc size
+ * @num_iface: number of interface
+ * @iface_hdl: interface handles
+ * @num_connected_iface: number of connected interface
+ * @num_resumed_iface: number of resumed interface
+ * @iface: interface information
+ * @pm_hdl: IPA PM handle
+ */
+struct ipa_gsb_context {
+	void *logbuf;
+	void *logbuf_low;
+	struct mutex lock;
+	u32 prod_hdl;
+	u32 cons_hdl;
+	u32 ipa_sys_desc_size;
+	int num_iface;
+	bool iface_hdl[MAX_SUPPORTED_IFACE];
+	int num_connected_iface;
+	int num_resumed_iface;
+	struct ipa_gsb_iface_info *iface[MAX_SUPPORTED_IFACE];
+	u32 pm_hdl;
+};
+
+static struct ipa_gsb_context *ipa_gsb_ctx;
+
+#ifdef CONFIG_DEBUG_FS
+static ssize_t ipa_gsb_debugfs_stats(struct file *file,
+				  char __user *ubuf,
+				  size_t count,
+				  loff_t *ppos)
+{
+	int i, nbytes = 0;
+
+	for (i = 0; i < MAX_SUPPORTED_IFACE; i++)
+		if (ipa_gsb_ctx->iface[i] != NULL) {
+			nbytes += scnprintf(&dbg_buff[nbytes],
+				IPA_GSB_MAX_MSG_LEN - nbytes,
+				"netdev: %s\n",
+				ipa_gsb_ctx->iface[i]->netdev_name);
+
+			nbytes += scnprintf(&dbg_buff[nbytes],
+				IPA_GSB_MAX_MSG_LEN - nbytes,
+				"UL packets: %lld\n",
+				ipa_gsb_ctx->iface[i]->
+				iface_stats.num_ul_packets);
+
+			nbytes += scnprintf(&dbg_buff[nbytes],
+				IPA_GSB_MAX_MSG_LEN - nbytes,
+				"DL packets: %lld\n",
+				ipa_gsb_ctx->iface[i]->
+				iface_stats.num_dl_packets);
+
+			nbytes += scnprintf(&dbg_buff[nbytes],
+				IPA_GSB_MAX_MSG_LEN - nbytes,
+				"packets with insufficient headroom: %lld\n",
+				ipa_gsb_ctx->iface[i]->
+				iface_stats.num_insufficient_headroom_packets);
+		}
+	return simple_read_from_buffer(ubuf, count, ppos, dbg_buff, nbytes);
+}
+
+static const struct file_operations ipa_gsb_stats_ops = {
+	.read = ipa_gsb_debugfs_stats,
+};
+
+static void ipa_gsb_debugfs_init(void)
+{
+	const mode_t read_only_mode = 00444;
+
+	dent = debugfs_create_dir("ipa_gsb", NULL);
+	if (IS_ERR(dent)) {
+		IPA_GSB_ERR("fail to create folder ipa_gsb\n");
+		return;
+	}
+
+	dfile_stats =
+		debugfs_create_file("stats", read_only_mode, dent,
+					NULL, &ipa_gsb_stats_ops);
+	if (!dfile_stats || IS_ERR(dfile_stats)) {
+		IPA_GSB_ERR("fail to create file stats\n");
+		goto fail;
+	}
+
+	return;
+
+fail:
+	debugfs_remove_recursive(dent);
+}
+
+static void ipa_gsb_debugfs_destroy(void)
+{
+	debugfs_remove_recursive(dent);
+}
+#else
+static void ipa_gsb_debugfs_init(void)
+{
+}
+
+static void ipa_gsb_debugfs_destroy(void)
+{
+}
+#endif
+
+static int ipa_gsb_driver_init(struct odu_bridge_params *params)
+{
+	if (!ipa_is_ready()) {
+		IPA_GSB_ERR("IPA is not ready\n");
+		return -EFAULT;
+	}
+
+	ipa_gsb_ctx = kzalloc(sizeof(*ipa_gsb_ctx),
+		GFP_KERNEL);
+
+	if (!ipa_gsb_ctx)
+		return -ENOMEM;
+
+	mutex_init(&ipa_gsb_ctx->lock);
+	ipa_gsb_debugfs_init();
+
+	return 0;
+}
+
+static int ipa_gsb_commit_partial_hdr(struct ipa_gsb_iface_info *iface_info)
+{
+	int i;
+	struct ipa_ioc_add_hdr *hdr;
+
+	if (!iface_info) {
+		IPA_GSB_ERR("invalid input\n");
+		return -EINVAL;
+	}
+
+	hdr = kzalloc(sizeof(struct ipa_ioc_add_hdr) +
+		2 * sizeof(struct ipa_hdr_add), GFP_KERNEL);
+	if (!hdr)
+		return -ENOMEM;
+
+	hdr->commit = 1;
+	hdr->num_hdrs = 2;
+
+	snprintf(hdr->hdr[0].name, sizeof(hdr->hdr[0].name),
+			 "%s_ipv4", iface_info->netdev_name);
+	snprintf(hdr->hdr[1].name, sizeof(hdr->hdr[1].name),
+			 "%s_ipv6", iface_info->netdev_name);
+	/* partial header: [hdl][QMAP ID][pkt size][ETH header] */
+	for (i = IPA_IP_v4; i < IPA_IP_MAX; i++) {
+		hdr->hdr[i].hdr_len = ETH_HLEN + sizeof(struct ipa_gsb_mux_hdr);
+		hdr->hdr[i].type = IPA_HDR_L2_ETHERNET_II;
+		hdr->hdr[i].is_partial = 1;
+		hdr->hdr[i].is_eth2_ofst_valid = 1;
+		hdr->hdr[i].eth2_ofst = sizeof(struct ipa_gsb_mux_hdr);
+		/* populate iface handle */
+		hdr->hdr[i].hdr[0] = iface_info->iface_hdl;
+		/* populate src ETH address */
+		memcpy(&hdr->hdr[i].hdr[10], iface_info->device_ethaddr, 6);
+		/* populate Ethertype */
+		if (i == IPA_IP_v4)
+			*(u16 *)(hdr->hdr[i].hdr + 16) = htons(ETH_P_IP);
+		else
+			*(u16 *)(hdr->hdr[i].hdr + 16) = htons(ETH_P_IPV6);
+	}
+
+	if (ipa_add_hdr(hdr)) {
+		IPA_GSB_ERR("fail to add partial headers\n");
+		kfree(hdr);
+		return -EFAULT;
+	}
+
+	for (i = IPA_IP_v4; i < IPA_IP_MAX; i++)
+		iface_info->partial_hdr_hdl[i] =
+			hdr->hdr[i].hdr_hdl;
+
+	IPA_GSB_DBG("added partial hdr hdl for ipv4: %d\n",
+		iface_info->partial_hdr_hdl[IPA_IP_v4]);
+	IPA_GSB_DBG("added partial hdr hdl for ipv6: %d\n",
+		iface_info->partial_hdr_hdl[IPA_IP_v6]);
+
+	kfree(hdr);
+	return 0;
+}
+
+static void ipa_gsb_delete_partial_hdr(struct ipa_gsb_iface_info *iface_info)
+{
+	struct ipa_ioc_del_hdr *del_hdr;
+
+	del_hdr = kzalloc(sizeof(struct ipa_ioc_del_hdr) +
+		2 * sizeof(struct ipa_hdr_del), GFP_KERNEL);
+	if (!del_hdr)
+		return;
+
+	del_hdr->commit = 1;
+	del_hdr->num_hdls = 2;
+	del_hdr->hdl[IPA_IP_v4].hdl = iface_info->partial_hdr_hdl[IPA_IP_v4];
+	del_hdr->hdl[IPA_IP_v6].hdl = iface_info->partial_hdr_hdl[IPA_IP_v6];
+
+	if (ipa_del_hdr(del_hdr) != 0)
+		IPA_GSB_ERR("failed to delete partial hdr\n");
+
+	IPA_GSB_DBG("deleted partial hdr hdl for ipv4: %d\n",
+		iface_info->partial_hdr_hdl[IPA_IP_v4]);
+	IPA_GSB_DBG("deleted partial hdr hdl for ipv6: %d\n",
+		iface_info->partial_hdr_hdl[IPA_IP_v6]);
+
+	kfree(del_hdr);
+}
+
+static int ipa_gsb_reg_intf_props(struct ipa_gsb_iface_info *iface_info)
+{
+	struct ipa_tx_intf tx;
+	struct ipa_rx_intf rx;
+	struct ipa_ioc_tx_intf_prop tx_prop[2];
+	struct ipa_ioc_rx_intf_prop rx_prop[2];
+
+	/* populate tx prop */
+	tx.num_props = 2;
+	tx.prop = tx_prop;
+
+	memset(tx_prop, 0, sizeof(tx_prop));
+	tx_prop[0].ip = IPA_IP_v4;
+	tx_prop[0].dst_pipe = IPA_CLIENT_ODU_EMB_CONS;
+	tx_prop[0].hdr_l2_type = IPA_HDR_L2_ETHERNET_II;
+	snprintf(tx_prop[0].hdr_name, sizeof(tx_prop[0].hdr_name),
+			 "%s_ipv4", iface_info->netdev_name);
+
+	tx_prop[1].ip = IPA_IP_v6;
+	tx_prop[1].dst_pipe = IPA_CLIENT_ODU_EMB_CONS;
+	tx_prop[1].hdr_l2_type = IPA_HDR_L2_ETHERNET_II;
+	snprintf(tx_prop[1].hdr_name, sizeof(tx_prop[1].hdr_name),
+			 "%s_ipv6", iface_info->netdev_name);
+
+	/* populate rx prop */
+	rx.num_props = 2;
+	rx.prop = rx_prop;
+
+	memset(rx_prop, 0, sizeof(rx_prop));
+	rx_prop[0].ip = IPA_IP_v4;
+	rx_prop[0].src_pipe = IPA_CLIENT_ODU_PROD;
+	rx_prop[0].hdr_l2_type = IPA_HDR_L2_ETHERNET_II;
+	rx_prop[0].attrib.attrib_mask |= IPA_FLT_META_DATA;
+	rx_prop[0].attrib.meta_data = iface_info->iface_hdl;
+	rx_prop[0].attrib.meta_data_mask = 0xFF;
+
+	rx_prop[1].ip = IPA_IP_v6;
+	rx_prop[1].src_pipe = IPA_CLIENT_ODU_PROD;
+	rx_prop[1].hdr_l2_type = IPA_HDR_L2_ETHERNET_II;
+	rx_prop[1].attrib.attrib_mask |= IPA_FLT_META_DATA;
+	rx_prop[1].attrib.meta_data = iface_info->iface_hdl;
+	rx_prop[1].attrib.meta_data_mask = 0xFF;
+
+	if (ipa_register_intf(iface_info->netdev_name, &tx, &rx)) {
+		IPA_GSB_ERR("fail to add interface prop\n");
+		return -EFAULT;
+	}
+
+	return 0;
+}
+
+static void ipa_gsb_dereg_intf_props(struct ipa_gsb_iface_info *iface_info)
+{
+	if (ipa_deregister_intf(iface_info->netdev_name) != 0)
+		IPA_GSB_ERR("fail to dereg intf props\n");
+
+	IPA_GSB_DBG("deregistered iface props for %s\n",
+		iface_info->netdev_name);
+}
+
+static void ipa_gsb_pm_cb(void *user_data, enum ipa_pm_cb_event event)
+{
+	int i;
+
+	if (event != IPA_PM_REQUEST_WAKEUP) {
+		IPA_GSB_ERR("Unexpected event %d\n", event);
+		WARN_ON(1);
+		return;
+	}
+
+	IPA_GSB_DBG("wake up clients\n");
+	for (i = 0; i < MAX_SUPPORTED_IFACE; i++)
+		if (ipa_gsb_ctx->iface[i] != NULL)
+			ipa_gsb_ctx->iface[i]->wakeup_request(
+				ipa_gsb_ctx->iface[i]->priv);
+}
+
+static int ipa_gsb_register_pm(void)
+{
+	struct ipa_pm_register_params reg_params;
+	int ret;
+
+	memset(&reg_params, 0, sizeof(reg_params));
+	reg_params.name = "ipa_gsb";
+	reg_params.callback = ipa_gsb_pm_cb;
+	reg_params.user_data = NULL;
+	reg_params.group = IPA_PM_GROUP_DEFAULT;
+
+	ret = ipa_pm_register(&reg_params,
+		&ipa_gsb_ctx->pm_hdl);
+	if (ret) {
+		IPA_GSB_ERR("fail to register with PM %d\n", ret);
+		goto fail_pm_reg;
+	}
+	IPA_GSB_DBG("ipa pm hdl: %d\n", ipa_gsb_ctx->pm_hdl);
+
+	ret = ipa_pm_associate_ipa_cons_to_client(ipa_gsb_ctx->pm_hdl,
+		IPA_CLIENT_ODU_EMB_CONS);
+	if (ret) {
+		IPA_GSB_ERR("fail to associate cons with PM %d\n", ret);
+		goto fail_pm_cons;
+	}
+
+	return 0;
+
+fail_pm_cons:
+	ipa_pm_deregister(ipa_gsb_ctx->pm_hdl);
+	ipa_gsb_ctx->pm_hdl = ~0;
+fail_pm_reg:
+	return ret;
+}
+
+int ipa_bridge_init(struct ipa_bridge_init_params *params, u32 *hdl)
+{
+	int i, ret;
+	struct ipa_gsb_iface_info *new_intf;
+
+	if (!params || !params->wakeup_request || !hdl ||
+		!params->info.netdev_name || !params->info.tx_dp_notify ||
+		!params->info.send_dl_skb) {
+		IPA_GSB_ERR("NULL parameters\n");
+		return -EINVAL;
+	}
+
+	IPA_GSB_DBG("netdev_name: %s\n", params->info.netdev_name);
+
+	if (ipa_gsb_ctx == NULL) {
+		ret = ipa_gsb_driver_init(&params->info);
+		if (ret) {
+			IPA_GSB_ERR("fail to init ipa gsb driver\n");
+			return -EFAULT;
+		}
+		ipa_gsb_ctx->ipa_sys_desc_size =
+			params->info.ipa_desc_size;
+		IPA_GSB_DBG("desc size: %d\n", ipa_gsb_ctx->ipa_sys_desc_size);
+	}
+
+	mutex_lock(&ipa_gsb_ctx->lock);
+
+	if (params->info.ipa_desc_size != ipa_gsb_ctx->ipa_sys_desc_size) {
+		IPA_GSB_ERR("unmatch: orig desc size %d, new desc size %d\n",
+			ipa_gsb_ctx->ipa_sys_desc_size,
+			params->info.ipa_desc_size);
+		mutex_unlock(&ipa_gsb_ctx->lock);
+		return -EFAULT;
+	}
+
+	for (i = 0; i < MAX_SUPPORTED_IFACE; i++)
+		if (ipa_gsb_ctx->iface[i] != NULL &&
+			strnlen(ipa_gsb_ctx->iface[i]->netdev_name,
+					IPA_RESOURCE_NAME_MAX) ==
+			strnlen(params->info.netdev_name,
+					IPA_RESOURCE_NAME_MAX) &&
+			strcmp(ipa_gsb_ctx->iface[i]->netdev_name,
+				params->info.netdev_name) == 0) {
+			IPA_GSB_ERR("intf was added before.\n");
+			mutex_unlock(&ipa_gsb_ctx->lock);
+			return -EFAULT;
+		}
+
+	if (ipa_gsb_ctx->num_iface == MAX_SUPPORTED_IFACE) {
+		IPA_GSB_ERR("reached maximum supported interfaces");
+		mutex_unlock(&ipa_gsb_ctx->lock);
+		return -EFAULT;
+	}
+
+	for (i = 0; i < MAX_SUPPORTED_IFACE; i++)
+		if (ipa_gsb_ctx->iface_hdl[i] == false) {
+			ipa_gsb_ctx->iface_hdl[i] = true;
+			*hdl = i;
+			IPA_GSB_DBG("iface hdl: %d\n", *hdl);
+			break;
+		}
+
+	IPA_GSB_DBG("intf was not added before, proceed.\n");
+	new_intf = kzalloc(sizeof(*new_intf), GFP_KERNEL);
+	if (new_intf == NULL) {
+		ret = -ENOMEM;
+		goto fail_alloc_mem;
+	}
+
+	strlcpy(new_intf->netdev_name, params->info.netdev_name,
+		sizeof(new_intf->netdev_name));
+	new_intf->wakeup_request = params->wakeup_request;
+	new_intf->priv = params->info.priv;
+	new_intf->tx_dp_notify = params->info.tx_dp_notify;
+	new_intf->send_dl_skb = params->info.send_dl_skb;
+	new_intf->iface_hdl = *hdl;
+	memcpy(new_intf->device_ethaddr, params->info.device_ethaddr,
+		sizeof(new_intf->device_ethaddr));
+
+	if (ipa_gsb_commit_partial_hdr(new_intf) != 0) {
+		IPA_GSB_ERR("fail to commit partial hdrs\n");
+		ret = -EFAULT;
+		goto fail_partial_hdr;
+	}
+
+	if (ipa_gsb_reg_intf_props(new_intf) != 0) {
+		IPA_GSB_ERR("fail to register interface props\n");
+		ret = -EFAULT;
+		goto fail_reg_intf_props;
+	}
+
+	if (ipa_gsb_ctx->num_iface == 0) {
+		ret = ipa_gsb_register_pm();
+		if (ret) {
+			IPA_GSB_ERR("fail to register with IPA PM %d\n", ret);
+			ret = -EFAULT;
+			goto fail_register_pm;
+		}
+	}
+
+	ipa_gsb_ctx->iface[*hdl] = new_intf;
+	ipa_gsb_ctx->num_iface++;
+	IPA_GSB_DBG("num_iface %d\n", ipa_gsb_ctx->num_iface);
+	mutex_unlock(&ipa_gsb_ctx->lock);
+	return 0;
+
+fail_register_pm:
+	ipa_gsb_dereg_intf_props(new_intf);
+fail_reg_intf_props:
+	ipa_gsb_delete_partial_hdr(new_intf);
+fail_partial_hdr:
+	kfree(new_intf);
+fail_alloc_mem:
+	ipa_gsb_ctx->iface_hdl[*hdl] = false;
+	mutex_unlock(&ipa_gsb_ctx->lock);
+	return ret;
+}
+EXPORT_SYMBOL(ipa_bridge_init);
+
+static void ipa_gsb_deregister_pm(void)
+{
+	IPA_GSB_DBG("deregister ipa pm hdl: %d\n", ipa_gsb_ctx->pm_hdl);
+	ipa_pm_deactivate_sync(ipa_gsb_ctx->pm_hdl);
+	ipa_pm_deregister(ipa_gsb_ctx->pm_hdl);
+	ipa_gsb_ctx->pm_hdl = ~0;
+}
+
+int ipa_bridge_cleanup(u32 hdl)
+{
+	if (!ipa_gsb_ctx) {
+		IPA_GSB_ERR("ipa_gsb_ctx was not initialized\n");
+		return -EFAULT;
+	}
+
+	if (hdl >= MAX_SUPPORTED_IFACE) {
+		IPA_GSB_ERR("invalid hdl: %d\n", hdl);
+		return -EINVAL;
+	}
+
+	if (ipa_gsb_ctx->iface[hdl] == NULL) {
+		IPA_GSB_ERR("fail to find interface\n");
+		return -EFAULT;
+	}
+
+	IPA_GSB_DBG("client hdl: %d\n", hdl);
+	mutex_lock(&ipa_gsb_ctx->lock);
+
+	if (ipa_gsb_ctx->iface[hdl]->is_connected) {
+		IPA_GSB_ERR("cannot cleanup when iface is connected\n");
+		mutex_unlock(&ipa_gsb_ctx->lock);
+		return -EFAULT;
+	}
+
+	ipa_gsb_dereg_intf_props(ipa_gsb_ctx->iface[hdl]);
+	ipa_gsb_delete_partial_hdr(ipa_gsb_ctx->iface[hdl]);
+	kfree(ipa_gsb_ctx->iface[hdl]);
+	ipa_gsb_ctx->iface[hdl] = NULL;
+	ipa_gsb_ctx->iface_hdl[hdl] = false;
+	ipa_gsb_ctx->num_iface--;
+	IPA_GSB_DBG("num_iface %d\n", ipa_gsb_ctx->num_iface);
+
+	if (ipa_gsb_ctx->num_iface == 0) {
+		ipa_gsb_deregister_pm();
+		ipa_gsb_debugfs_destroy();
+		ipc_log_context_destroy(ipa_gsb_ctx->logbuf);
+		ipc_log_context_destroy(ipa_gsb_ctx->logbuf_low);
+		mutex_unlock(&ipa_gsb_ctx->lock);
+		kfree(ipa_gsb_ctx);
+		ipa_gsb_ctx = NULL;
+		return 0;
+	}
+
+	mutex_unlock(&ipa_gsb_ctx->lock);
+	return 0;
+}
+EXPORT_SYMBOL(ipa_bridge_cleanup);
+
+static struct sk_buff *ipa_gsb_skb_copy(struct sk_buff *skb, int len)
+{
+	struct sk_buff *skb2 = NULL;
+
+	skb2 = __dev_alloc_skb(len + IPA_GSB_SKB_HEADROOM, GFP_KERNEL);
+	if (likely(skb2)) {
+		skb_reserve(skb2, IPA_GSB_SKB_HEADROOM);
+		memcpy(skb2->data, skb->data, len);
+		skb2->len = len;
+		skb_set_tail_pointer(skb2, len);
+	}
+
+	return skb2;
+}
+
+static void ipa_gsb_cons_cb(void *priv, enum ipa_dp_evt_type evt,
+	unsigned long data)
+{
+	struct sk_buff *skb;
+	struct sk_buff *skb2;
+	struct ipa_gsb_mux_hdr *mux_hdr;
+	u16 pkt_size, pad_byte;
+	u8 hdl;
+
+	if (evt != IPA_RECEIVE) {
+		IPA_GSB_ERR("unexpected event\n");
+		WARN_ON(1);
+		return;
+	}
+
+	skb = (struct sk_buff *)data;
+
+	while (skb->len) {
+		mux_hdr = (struct ipa_gsb_mux_hdr *)skb->data;
+		pkt_size = mux_hdr->pkt_size;
+		/* 4-byte padding */
+		pad_byte = ((pkt_size + sizeof(*mux_hdr) + ETH_HLEN + 3) & ~3)
+			- (pkt_size + sizeof(*mux_hdr) + ETH_HLEN);
+		hdl = mux_hdr->iface_hdl;
+		IPA_GSB_DBG("pkt_size: %d, pad_byte: %d, hdl: %d\n",
+			pkt_size, pad_byte, hdl);
+
+		/* remove 4 byte mux header */
+		skb_pull(skb, sizeof(*mux_hdr));
+		skb2 = ipa_gsb_skb_copy(skb, pkt_size + ETH_HLEN);
+		ipa_gsb_ctx->iface[hdl]->send_dl_skb(
+			ipa_gsb_ctx->iface[hdl]->priv, skb2);
+		ipa_gsb_ctx->iface[hdl]->iface_stats.num_dl_packets++;
+
+		skb_pull(skb, pkt_size + ETH_HLEN + pad_byte);
+	}
+}
+
+static void ipa_gsb_tx_dp_notify(void *priv, enum ipa_dp_evt_type evt,
+		       unsigned long data)
+{
+	struct sk_buff *skb;
+	struct ipa_gsb_mux_hdr *mux_hdr;
+	u8 hdl;
+
+	skb = (struct sk_buff *)data;
+
+	if (evt != IPA_WRITE_DONE && evt != IPA_RECEIVE) {
+		IPA_GSB_ERR("unexpected event: %d\n", evt);
+		dev_kfree_skb_any(skb);
+		return;
+	}
+
+	/* fetch iface handle from header */
+	mux_hdr = (struct ipa_gsb_mux_hdr *)skb->data;
+	/* change to host order */
+	*(u32 *)mux_hdr = ntohl(*(u32 *)mux_hdr);
+	hdl = mux_hdr->iface_hdl;
+	IPA_GSB_DBG("evt: %d, hdl in tx_dp_notify: %d\n", evt, hdl);
+
+	/* remove 4 byte mux header */
+	skb_pull(skb, sizeof(struct ipa_gsb_mux_hdr));
+	ipa_gsb_ctx->iface[hdl]->tx_dp_notify(
+		ipa_gsb_ctx->iface[hdl]->priv, evt,
+		(unsigned long)skb);
+}
+
+static int ipa_gsb_connect_sys_pipe(void)
+{
+	struct ipa_sys_connect_params prod_params;
+	struct ipa_sys_connect_params cons_params;
+	int res;
+
+	memset(&prod_params, 0, sizeof(prod_params));
+	memset(&cons_params, 0, sizeof(cons_params));
+
+	/* configure RX EP */
+	prod_params.client = IPA_CLIENT_ODU_PROD;
+	prod_params.ipa_ep_cfg.hdr.hdr_len =
+		ETH_HLEN + sizeof(struct ipa_gsb_mux_hdr);
+	prod_params.ipa_ep_cfg.nat.nat_en = IPA_SRC_NAT;
+	prod_params.ipa_ep_cfg.hdr.hdr_ofst_metadata_valid = 1;
+	prod_params.ipa_ep_cfg.hdr.hdr_ofst_metadata = 0;
+	prod_params.desc_fifo_sz = ipa_gsb_ctx->ipa_sys_desc_size;
+	prod_params.priv = NULL;
+	prod_params.notify = ipa_gsb_tx_dp_notify;
+	res = ipa_setup_sys_pipe(&prod_params,
+		&ipa_gsb_ctx->prod_hdl);
+	if (res) {
+		IPA_GSB_ERR("fail to setup prod sys pipe %d\n", res);
+		goto fail_prod;
+	}
+
+	/* configure TX EP */
+	cons_params.client = IPA_CLIENT_ODU_EMB_CONS;
+	cons_params.ipa_ep_cfg.hdr.hdr_len =
+		ETH_HLEN + sizeof(struct ipa_gsb_mux_hdr);
+	cons_params.ipa_ep_cfg.hdr.hdr_ofst_pkt_size_valid = 1;
+	cons_params.ipa_ep_cfg.hdr.hdr_ofst_pkt_size = 2;
+	cons_params.ipa_ep_cfg.hdr_ext.hdr_pad_to_alignment = 2;
+	cons_params.ipa_ep_cfg.hdr_ext.hdr_little_endian = true;
+	cons_params.ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT;
+	/* setup aggregation */
+	cons_params.ipa_ep_cfg.aggr.aggr_en = IPA_ENABLE_AGGR;
+	cons_params.ipa_ep_cfg.aggr.aggr = IPA_GENERIC;
+	cons_params.ipa_ep_cfg.aggr.aggr_time_limit =
+		IPA_GSB_AGGR_TIME_LIMIT;
+	cons_params.ipa_ep_cfg.aggr.aggr_byte_limit =
+		IPA_GSB_AGGR_BYTE_LIMIT;
+	cons_params.desc_fifo_sz = ipa_gsb_ctx->ipa_sys_desc_size;
+	cons_params.priv = NULL;
+	cons_params.notify = ipa_gsb_cons_cb;
+	res = ipa_setup_sys_pipe(&cons_params,
+		&ipa_gsb_ctx->cons_hdl);
+	if (res) {
+		IPA_GSB_ERR("fail to setup cons sys pipe %d\n", res);
+		goto fail_cons;
+	}
+
+	IPA_GSB_DBG("prod_hdl = %d, cons_hdl = %d\n",
+		ipa_gsb_ctx->prod_hdl, ipa_gsb_ctx->cons_hdl);
+
+	return 0;
+
+fail_cons:
+	ipa_teardown_sys_pipe(ipa_gsb_ctx->prod_hdl);
+	ipa_gsb_ctx->prod_hdl = 0;
+fail_prod:
+	return res;
+}
+
+int ipa_bridge_connect(u32 hdl)
+{
+	int ret;
+
+	if (!ipa_gsb_ctx) {
+		IPA_GSB_ERR("ipa_gsb_ctx was not initialized\n");
+		return -EFAULT;
+	}
+
+	IPA_GSB_DBG("client hdl: %d\n", hdl);
+
+	mutex_lock(&ipa_gsb_ctx->lock);
+
+	if (ipa_gsb_ctx->iface[hdl]->is_connected) {
+		IPA_GSB_DBG("iface was already connected\n");
+		mutex_unlock(&ipa_gsb_ctx->lock);
+		return 0;
+	}
+
+	if (ipa_gsb_ctx->num_connected_iface == 0) {
+		ret = ipa_pm_activate_sync(ipa_gsb_ctx->pm_hdl);
+		if (ret) {
+			IPA_GSB_ERR("failed to activate ipa pm\n");
+			mutex_unlock(&ipa_gsb_ctx->lock);
+			return ret;
+		}
+		ret = ipa_gsb_connect_sys_pipe();
+		if (ret) {
+			IPA_GSB_ERR("fail to connect pipe\n");
+			mutex_unlock(&ipa_gsb_ctx->lock);
+			return ret;
+		}
+	}
+
+	/* connect = connect + resume */
+	ipa_gsb_ctx->iface[hdl]->is_connected = true;
+	ipa_gsb_ctx->iface[hdl]->is_resumed = true;
+
+	ipa_gsb_ctx->num_connected_iface++;
+	IPA_GSB_DBG("connected iface: %d\n",
+		ipa_gsb_ctx->num_connected_iface);
+	ipa_gsb_ctx->num_resumed_iface++;
+	IPA_GSB_DBG("num resumed iface: %d\n",
+		ipa_gsb_ctx->num_resumed_iface);
+
+	mutex_unlock(&ipa_gsb_ctx->lock);
+	return 0;
+}
+EXPORT_SYMBOL(ipa_bridge_connect);
+
+static int ipa_gsb_disconnect_sys_pipe(void)
+{
+	int ret;
+
+	IPA_GSB_DBG("prod_hdl = %d, cons_hdl = %d\n",
+		ipa_gsb_ctx->prod_hdl, ipa_gsb_ctx->cons_hdl);
+
+	ret = ipa_teardown_sys_pipe(ipa_gsb_ctx->prod_hdl);
+	if (ret) {
+		IPA_GSB_ERR("failed to tear down prod pipe\n");
+		return -EFAULT;
+	}
+	ipa_gsb_ctx->prod_hdl = 0;
+
+	ret = ipa_teardown_sys_pipe(ipa_gsb_ctx->cons_hdl);
+	if (ret) {
+		IPA_GSB_ERR("failed to tear down cons pipe\n");
+		return -EFAULT;
+	}
+	ipa_gsb_ctx->cons_hdl = 0;
+
+	return 0;
+}
+
+int ipa_bridge_disconnect(u32 hdl)
+{
+	int ret;
+
+	if (!ipa_gsb_ctx) {
+		IPA_GSB_ERR("ipa_gsb_ctx was not initialized\n");
+		return -EFAULT;
+	}
+
+	IPA_GSB_DBG("client hdl: %d\n", hdl);
+
+	mutex_lock(&ipa_gsb_ctx->lock);
+
+	if (!ipa_gsb_ctx->iface[hdl]->is_connected) {
+		IPA_GSB_DBG("iface was not connected\n");
+		mutex_unlock(&ipa_gsb_ctx->lock);
+		return 0;
+	}
+
+	if (ipa_gsb_ctx->num_connected_iface == 1) {
+		ret = ipa_gsb_disconnect_sys_pipe();
+		if (ret) {
+			IPA_GSB_ERR("fail to discon pipes\n");
+			mutex_unlock(&ipa_gsb_ctx->lock);
+			return -EFAULT;
+		}
+
+		ret = ipa_pm_deactivate_sync(ipa_gsb_ctx->pm_hdl);
+		if (ret) {
+			IPA_GSB_ERR("failed to deactivate ipa pm\n");
+			mutex_unlock(&ipa_gsb_ctx->lock);
+			return -EFAULT;
+		}
+	}
+
+	/* disconnect = suspend + disconnect */
+	ipa_gsb_ctx->iface[hdl]->is_connected = false;
+	ipa_gsb_ctx->num_connected_iface--;
+	IPA_GSB_DBG("connected iface: %d\n",
+		ipa_gsb_ctx->num_connected_iface);
+
+	if (ipa_gsb_ctx->iface[hdl]->is_resumed) {
+		ipa_gsb_ctx->iface[hdl]->is_resumed = false;
+		ipa_gsb_ctx->num_resumed_iface--;
+		IPA_GSB_DBG("num resumed iface: %d\n",
+			ipa_gsb_ctx->num_resumed_iface);
+	}
+
+	mutex_unlock(&ipa_gsb_ctx->lock);
+	return 0;
+}
+EXPORT_SYMBOL(ipa_bridge_disconnect);
+
+int ipa_bridge_resume(u32 hdl)
+{
+	int ret;
+
+	if (!ipa_gsb_ctx) {
+		IPA_GSB_ERR("ipa_gsb_ctx was not initialized\n");
+		return -EFAULT;
+	}
+
+	IPA_GSB_DBG("client hdl: %d\n", hdl);
+
+	if (!ipa_gsb_ctx->iface[hdl]->is_connected) {
+		IPA_GSB_ERR("iface is not connected\n");
+		return -EFAULT;
+	}
+
+	if (ipa_gsb_ctx->iface[hdl]->is_resumed) {
+		IPA_GSB_DBG("iface was already resumed\n");
+		return 0;
+	}
+
+	mutex_lock(&ipa_gsb_ctx->lock);
+
+	if (ipa_gsb_ctx->num_resumed_iface == 0) {
+		ret = ipa_pm_activate_sync(ipa_gsb_ctx->pm_hdl);
+		if (ret) {
+			IPA_GSB_ERR("fail to activate ipa pm\n");
+			mutex_unlock(&ipa_gsb_ctx->lock);
+			return ret;
+		}
+
+		ret = ipa_start_gsi_channel(
+			ipa_gsb_ctx->cons_hdl);
+		if (ret) {
+			IPA_GSB_ERR(
+				"fail to start con ep %d\n",
+				ret);
+			mutex_unlock(&ipa_gsb_ctx->lock);
+			return ret;
+		}
+	}
+
+	ipa_gsb_ctx->iface[hdl]->is_resumed = true;
+	ipa_gsb_ctx->num_resumed_iface++;
+	IPA_GSB_DBG("num resumed iface: %d\n",
+		ipa_gsb_ctx->num_resumed_iface);
+
+	mutex_unlock(&ipa_gsb_ctx->lock);
+	return 0;
+}
+EXPORT_SYMBOL(ipa_bridge_resume);
+
+int ipa_bridge_suspend(u32 hdl)
+{
+	int ret;
+
+	if (!ipa_gsb_ctx) {
+		IPA_GSB_ERR("ipa_gsb_ctx was not initialized\n");
+		return -EFAULT;
+	}
+
+	IPA_GSB_DBG("client hdl: %d\n", hdl);
+
+	if (!ipa_gsb_ctx->iface[hdl]->is_connected) {
+		IPA_GSB_ERR("iface is not connected\n");
+		return -EFAULT;
+	}
+
+	if (!ipa_gsb_ctx->iface[hdl]->is_resumed) {
+		IPA_GSB_DBG("iface was already suspended\n");
+		return 0;
+	}
+
+	mutex_lock(&ipa_gsb_ctx->lock);
+
+	if (ipa_gsb_ctx->num_resumed_iface == 1) {
+		ret = ipa_stop_gsi_channel(
+			ipa_gsb_ctx->cons_hdl);
+		if (ret) {
+			IPA_GSB_ERR(
+				"fail to stop cons ep %d\n",
+				ret);
+			mutex_unlock(&ipa_gsb_ctx->lock);
+			return ret;
+		}
+
+		ret = ipa_pm_deactivate_sync(ipa_gsb_ctx->pm_hdl);
+		if (ret) {
+			IPA_GSB_ERR("fail to deactivate ipa pm\n");
+			ipa_start_gsi_channel(ipa_gsb_ctx->cons_hdl);
+			mutex_unlock(&ipa_gsb_ctx->lock);
+			return ret;
+		}
+	}
+
+	ipa_gsb_ctx->iface[hdl]->is_resumed = false;
+	ipa_gsb_ctx->num_resumed_iface--;
+	IPA_GSB_DBG("num resumed iface: %d\n",
+		ipa_gsb_ctx->num_resumed_iface);
+
+	mutex_unlock(&ipa_gsb_ctx->lock);
+	return 0;
+}
+EXPORT_SYMBOL(ipa_bridge_suspend);
+
+int ipa_bridge_set_perf_profile(u32 hdl, u32 bandwidth)
+{
+	int ret;
+
+	IPA_GSB_DBG("client hdl: %d, BW: %d\n", hdl, bandwidth);
+
+	mutex_lock(&ipa_gsb_ctx->lock);
+
+	ret = ipa_pm_set_perf_profile(ipa_gsb_ctx->pm_hdl,
+		bandwidth);
+	if (ret)
+		IPA_GSB_ERR("fail to set perf profile\n");
+
+	mutex_unlock(&ipa_gsb_ctx->lock);
+	return ret;
+}
+EXPORT_SYMBOL(ipa_bridge_set_perf_profile);
+
+int ipa_bridge_tx_dp(u32 hdl, struct sk_buff *skb,
+	struct ipa_tx_meta *metadata)
+{
+	struct ipa_gsb_mux_hdr *mux_hdr;
+	struct sk_buff *skb2;
+	int ret;
+
+	IPA_GSB_DBG("client hdl: %d\n", hdl);
+
+	/* make sure skb has enough headroom */
+	if (unlikely(skb_headroom(skb) < sizeof(struct ipa_gsb_mux_hdr))) {
+		IPA_GSB_DBG("skb doesn't have enough headroom\n");
+		skb2 = skb_copy_expand(skb, sizeof(struct ipa_gsb_mux_hdr),
+			0, GFP_ATOMIC);
+		if (!skb2) {
+			dev_kfree_skb_any(skb);
+			return -ENOMEM;
+		}
+		dev_kfree_skb_any(skb);
+		skb = skb2;
+		ipa_gsb_ctx->iface[hdl]->iface_stats.
+			num_insufficient_headroom_packets++;
+	}
+
+	/* add 4 byte header for mux */
+	mux_hdr = (struct ipa_gsb_mux_hdr *)skb_push(skb,
+		sizeof(struct ipa_gsb_mux_hdr));
+	mux_hdr->iface_hdl = (u8)hdl;
+	/* change to network order */
+	*(u32 *)mux_hdr = htonl(*(u32 *)mux_hdr);
+
+	ret = ipa_tx_dp(IPA_CLIENT_ODU_PROD, skb, metadata);
+	if (ret) {
+		IPA_GSB_ERR("tx dp failed %d\n", ret);
+		return -EFAULT;
+	}
+	ipa_gsb_ctx->iface[hdl]->iface_stats.num_ul_packets++;
+
+	return 0;
+}
+EXPORT_SYMBOL(ipa_bridge_tx_dp);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("ipa gsb driver");
diff --git a/drivers/platform/msm/ipa/ipa_clients/odu_bridge.c b/drivers/platform/msm/ipa/ipa_clients/odu_bridge.c
index df546cd..3228410 100644
--- a/drivers/platform/msm/ipa/ipa_clients/odu_bridge.c
+++ b/drivers/platform/msm/ipa/ipa_clients/odu_bridge.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2018, 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
@@ -1262,385 +1262,5 @@
 }
 EXPORT_SYMBOL(odu_bridge_cleanup);
 
-/* IPA Bridge implementation */
-#ifdef CONFIG_IPA3
-
-static void ipa_br_rm_notify(void *user_data, enum ipa_rm_event event,
-	unsigned long data)
-{
-	if (event == IPA_RM_RESOURCE_GRANTED)
-		complete(&odu_bridge_ctx->rm_comp);
-}
-
-static int ipa_br_request_prod(void)
-{
-	int res;
-
-	ODU_BRIDGE_FUNC_ENTRY();
-
-	reinit_completion(&odu_bridge_ctx->rm_comp);
-	ODU_BRIDGE_DBG("requesting odu prod\n");
-	res = ipa_rm_request_resource(IPA_RM_RESOURCE_ODU_ADAPT_PROD);
-	if (res) {
-		if (res != -EINPROGRESS) {
-			ODU_BRIDGE_ERR("failed to request prod %d\n", res);
-			return res;
-		}
-		wait_for_completion(&odu_bridge_ctx->rm_comp);
-	}
-
-	ODU_BRIDGE_FUNC_EXIT();
-	return 0;
-
-}
-
-static int ipa_br_release_prod(void)
-{
-	int res;
-
-	ODU_BRIDGE_FUNC_ENTRY();
-
-	reinit_completion(&odu_bridge_ctx->rm_comp);
-	ODU_BRIDGE_DBG("requesting odu prod\n");
-	res = ipa_rm_release_resource(IPA_RM_RESOURCE_ODU_ADAPT_PROD);
-	if (res) {
-		ODU_BRIDGE_ERR("failed to release prod %d\n", res);
-		return res;
-	}
-
-	ODU_BRIDGE_FUNC_EXIT();
-	return 0;
-
-}
-
-static int ipa_br_cons_request(void)
-{
-	ODU_BRIDGE_FUNC_ENTRY();
-	if (odu_bridge_ctx->is_suspended)
-		odu_bridge_ctx->wakeup_request(odu_bridge_ctx->priv);
-	ODU_BRIDGE_FUNC_EXIT();
-	return 0;
-}
-
-static int ipa_br_cons_release(void)
-{
-	ODU_BRIDGE_FUNC_ENTRY();
-	ODU_BRIDGE_FUNC_EXIT();
-	return 0;
-}
-
-static void ipa_br_pm_cb(void *p, enum ipa_pm_cb_event event)
-{
-	ODU_BRIDGE_FUNC_ENTRY();
-	if (event != IPA_PM_REQUEST_WAKEUP) {
-		ODU_BRIDGE_ERR("Unexpected event %d\n", event);
-		WARN_ON(1);
-		return;
-	}
-
-	if (odu_bridge_ctx->is_suspended)
-		odu_bridge_ctx->wakeup_request(odu_bridge_ctx->priv);
-	ODU_BRIDGE_FUNC_EXIT();
-}
-
-static int ipa_br_register_pm(void)
-{
-	struct ipa_pm_register_params reg_params;
-	int ret;
-
-	memset(&reg_params, 0, sizeof(reg_params));
-	reg_params.name = "ODU Bridge";
-	reg_params.callback = ipa_br_pm_cb;
-	reg_params.group = IPA_PM_GROUP_DEFAULT;
-
-	ret = ipa_pm_register(&reg_params,
-		&odu_bridge_ctx->pm_hdl);
-	if (ret) {
-		ODU_BRIDGE_ERR("fail to register with PM %d\n", ret);
-		goto fail_pm_reg;
-	}
-
-	ret = ipa_pm_associate_ipa_cons_to_client(odu_bridge_ctx->pm_hdl,
-		IPA_CLIENT_ODU_EMB_CONS);
-	if (ret) {
-		ODU_BRIDGE_ERR("fail to associate cons with PM %d\n", ret);
-		goto fail_pm_cons;
-	}
-
-	return 0;
-
-fail_pm_cons:
-	ipa_pm_deregister(odu_bridge_ctx->pm_hdl);
-	odu_bridge_ctx->pm_hdl = ~0;
-fail_pm_reg:
-	return ret;
-}
-
-static int ipa_br_create_rm_resources(void)
-{
-	int ret;
-	struct ipa_rm_create_params create_params;
-
-	/* create IPA RM resources for power management */
-	init_completion(&odu_bridge_ctx->rm_comp);
-	memset(&create_params, 0, sizeof(create_params));
-	create_params.name = IPA_RM_RESOURCE_ODU_ADAPT_PROD;
-	create_params.reg_params.user_data = odu_bridge_ctx;
-	create_params.reg_params.notify_cb = ipa_br_rm_notify;
-	create_params.floor_voltage = IPA_VOLTAGE_SVS;
-	ret = ipa_rm_create_resource(&create_params);
-	if (ret) {
-		ODU_BRIDGE_ERR("failed to create RM prod %d\n", ret);
-		goto fail_rm_prod;
-	}
-
-	ret = ipa_rm_add_dependency_sync(IPA_RM_RESOURCE_ODU_ADAPT_PROD,
-		IPA_RM_RESOURCE_APPS_CONS);
-	if (ret) {
-		ODU_BRIDGE_ERR("failed to add ODU->APPS dependency %d\n", ret);
-		goto fail_add_dep;
-	}
-
-	memset(&create_params, 0, sizeof(create_params));
-	create_params.name = IPA_RM_RESOURCE_ODU_ADAPT_CONS;
-	create_params.request_resource = ipa_br_cons_request;
-	create_params.release_resource = ipa_br_cons_release;
-	create_params.floor_voltage = IPA_VOLTAGE_SVS;
-	ret = ipa_rm_create_resource(&create_params);
-	if (ret) {
-		ODU_BRIDGE_ERR("failed to create RM cons %d\n", ret);
-		goto fail_rm_cons;
-	}
-
-	return 0;
-
-fail_rm_cons:
-	ipa_rm_delete_dependency(IPA_RM_RESOURCE_ODU_ADAPT_PROD,
-		IPA_RM_RESOURCE_APPS_CONS);
-fail_add_dep:
-	ipa_rm_delete_resource(IPA_RM_RESOURCE_ODU_ADAPT_PROD);
-fail_rm_prod:
-	return ret;
-}
-
-/* IPA Bridge API is the new API which will replaces old odu_bridge API */
-int ipa_bridge_init(struct ipa_bridge_init_params *params, u32 *hdl)
-{
-	int ret;
-
-	if (!params || !params->wakeup_request || !hdl) {
-		ODU_BRIDGE_ERR("NULL arg\n");
-		return -EINVAL;
-	}
-
-
-	ret = odu_bridge_init(&params->info);
-	if (ret)
-		return ret;
-
-	odu_bridge_ctx->wakeup_request = params->wakeup_request;
-
-	if (ipa_pm_is_used())
-		ret = ipa_br_register_pm();
-	else
-		ret = ipa_br_create_rm_resources();
-	if (ret) {
-		ODU_BRIDGE_ERR("fail to register woth RM/PM %d\n", ret);
-		goto fail_pm;
-	}
-
-	/* handle is ignored for now */
-	*hdl = 0;
-
-	return 0;
-
-fail_pm:
-	odu_bridge_cleanup();
-	return ret;
-}
-EXPORT_SYMBOL(ipa_bridge_init);
-
-int ipa_bridge_connect(u32 hdl)
-{
-	int ret;
-
-	if (!odu_bridge_ctx) {
-		ODU_BRIDGE_ERR("Not initialized\n");
-		return -EFAULT;
-	}
-
-	if (odu_bridge_ctx->is_connected) {
-		ODU_BRIDGE_ERR("already connected\n");
-		return -EFAULT;
-	}
-
-	if (ipa_pm_is_used())
-		ret = ipa_pm_activate_sync(odu_bridge_ctx->pm_hdl);
-	else
-		ret = ipa_br_request_prod();
-	if (ret)
-		return ret;
-
-	return odu_bridge_connect();
-}
-EXPORT_SYMBOL(ipa_bridge_connect);
-
-int ipa_bridge_set_perf_profile(u32 hdl, u32 bandwidth)
-{
-	struct ipa_rm_perf_profile profile = {0};
-	int ret;
-
-	if (ipa_pm_is_used())
-		return ipa_pm_set_perf_profile(odu_bridge_ctx->pm_hdl,
-			bandwidth);
-
-	profile.max_supported_bandwidth_mbps = bandwidth;
-	ret = ipa_rm_set_perf_profile(IPA_RM_RESOURCE_ODU_ADAPT_PROD, &profile);
-	if (ret) {
-		ODU_BRIDGE_ERR("failed to set perf profile to prod %d\n", ret);
-		return ret;
-	}
-
-	ret = ipa_rm_set_perf_profile(IPA_RM_RESOURCE_ODU_ADAPT_CONS, &profile);
-	if (ret) {
-		ODU_BRIDGE_ERR("failed to set perf profile to cons %d\n", ret);
-		return ret;
-	}
-
-	return 0;
-}
-EXPORT_SYMBOL(ipa_bridge_set_perf_profile);
-
-int ipa_bridge_disconnect(u32 hdl)
-{
-	int ret;
-
-	ret = odu_bridge_disconnect();
-	if (ret)
-		return ret;
-
-	if (ipa_pm_is_used())
-		ret = ipa_pm_deactivate_sync(odu_bridge_ctx->pm_hdl);
-	else
-		ret = ipa_br_release_prod();
-	if (ret)
-		return ret;
-
-	return 0;
-}
-EXPORT_SYMBOL(ipa_bridge_disconnect);
-
-int ipa_bridge_suspend(u32 hdl)
-{
-	int ret;
-
-	if (!odu_bridge_ctx) {
-		ODU_BRIDGE_ERR("Not initialized\n");
-		return -EFAULT;
-	}
-
-	if (!odu_bridge_ctx->is_connected) {
-		ODU_BRIDGE_ERR("bridge is  disconnected\n");
-		return -EFAULT;
-	}
-
-	if (odu_bridge_ctx->is_suspended) {
-		ODU_BRIDGE_ERR("bridge is already suspended\n");
-		return -EFAULT;
-	}
-
-	/* stop cons channel to prevent downlink data during suspend */
-	ret = ipa_stop_gsi_channel(odu_bridge_ctx->odu_emb_cons_hdl);
-	if (ret) {
-		ODU_BRIDGE_ERR("failed to stop CONS channel %d\n", ret);
-		return ret;
-	}
-
-	if (ipa_pm_is_used())
-		ret = ipa_pm_deactivate_sync(odu_bridge_ctx->pm_hdl);
-	else
-		ret = ipa_br_release_prod();
-	if (ret) {
-		ODU_BRIDGE_ERR("failed to release prod %d\n", ret);
-		ipa_start_gsi_channel(odu_bridge_ctx->odu_emb_cons_hdl);
-		return ret;
-	}
-	odu_bridge_ctx->is_suspended = true;
-
-	return 0;
-}
-EXPORT_SYMBOL(ipa_bridge_suspend);
-
-int ipa_bridge_resume(u32 hdl)
-{
-	int ret;
-
-	if (!odu_bridge_ctx) {
-		ODU_BRIDGE_ERR("Not initialized\n");
-		return -EFAULT;
-	}
-
-	if (!odu_bridge_ctx->is_connected) {
-		ODU_BRIDGE_ERR("bridge is  disconnected\n");
-		return -EFAULT;
-	}
-
-	if (!odu_bridge_ctx->is_suspended) {
-		ODU_BRIDGE_ERR("bridge is not suspended\n");
-		return -EFAULT;
-	}
-
-	if (ipa_pm_is_used())
-		ret = ipa_pm_activate_sync(odu_bridge_ctx->pm_hdl);
-	else
-		ret = ipa_br_request_prod();
-	if (ret)
-		return ret;
-
-	ret = ipa_start_gsi_channel(odu_bridge_ctx->odu_emb_cons_hdl);
-	if (ret) {
-		ODU_BRIDGE_ERR("failed to start CONS channel %d\n", ret);
-		return ret;
-	}
-	odu_bridge_ctx->is_suspended = false;
-
-	return 0;
-}
-EXPORT_SYMBOL(ipa_bridge_resume);
-
-int ipa_bridge_tx_dp(u32 hdl, struct sk_buff *skb,
-	struct ipa_tx_meta *metadata)
-{
-	return odu_bridge_tx_dp(skb, metadata);
-}
-EXPORT_SYMBOL(ipa_bridge_tx_dp);
-
-static void ipa_br_delete_rm_resources(void)
-{
-	ipa_rm_delete_dependency(IPA_RM_RESOURCE_ODU_ADAPT_PROD,
-		IPA_RM_RESOURCE_APPS_CONS);
-	ipa_rm_delete_resource(IPA_RM_RESOURCE_ODU_ADAPT_PROD);
-	ipa_rm_delete_resource(IPA_RM_RESOURCE_ODU_ADAPT_CONS);
-}
-
-static void ipa_br_deregister_pm(void)
-{
-	ipa_pm_deactivate_sync(odu_bridge_ctx->pm_hdl);
-	ipa_pm_deregister(odu_bridge_ctx->pm_hdl);
-	odu_bridge_ctx->pm_hdl = ~0;
-}
-
-int ipa_bridge_cleanup(u32 hdl)
-{
-	if (ipa_pm_is_used())
-		ipa_br_deregister_pm();
-	else
-		ipa_br_delete_rm_resources();
-	return odu_bridge_cleanup();
-}
-EXPORT_SYMBOL(ipa_bridge_cleanup);
-
-#endif /* CONFIG_IPA3 */
-
 MODULE_LICENSE("GPL v2");
 MODULE_DESCRIPTION("ODU bridge driver");
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
index 84124ab..34f3265 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
@@ -2936,7 +2936,6 @@
 			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 /
 				IPA_FIFO_ELEMENT_SIZE - 1;
 			if (sys->rx_pool_sz > IPA_ODU_RX_POOL_SZ)
@@ -2944,8 +2943,20 @@
 			sys->pyld_hdlr = ipa3_odu_rx_pyld_hdlr;
 			sys->get_skb = ipa3_get_skb_ipa_rx;
 			sys->free_skb = ipa3_free_skb_rx;
-			sys->free_rx_wrapper = ipa3_free_rx_wrapper;
-			sys->repl_hdlr = ipa3_replenish_rx_cache;
+			/* recycle skb for GSB use case */
+			if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0) {
+				sys->free_rx_wrapper =
+					ipa3_recycle_rx_wrapper;
+				sys->repl_hdlr =
+					ipa3_replenish_rx_cache_recycle;
+				sys->rx_buff_sz = IPA_GENERIC_RX_BUFF_SZ(
+					IPA_GENERIC_RX_BUFF_BASE_SZ);
+			} else {
+				sys->free_rx_wrapper =
+					ipa3_free_rx_wrapper;
+				sys->repl_hdlr = ipa3_replenish_rx_cache;
+				sys->rx_buff_sz = IPA_ODU_RX_BUFF_SZ;
+			}
 		} else if (in->client ==
 				IPA_CLIENT_MEMCPY_DMA_ASYNC_CONS) {
 			IPADBG("assigning policy to client:%d",
diff --git a/drivers/power/supply/qcom/fg-alg.c b/drivers/power/supply/qcom/fg-alg.c
index 129af7b..4003679 100644
--- a/drivers/power/supply/qcom/fg-alg.c
+++ b/drivers/power/supply/qcom/fg-alg.c
@@ -16,12 +16,38 @@
 #include <linux/kernel.h>
 #include <linux/mutex.h>
 #include <linux/power_supply.h>
+#include <linux/slab.h>
+#include <linux/sort.h>
 #include "fg-alg.h"
 
 #define FULL_SOC_RAW		255
 #define FULL_BATT_SOC		GENMASK(31, 0)
 #define CAPACITY_DELTA_DECIPCT	500
 
+#define CENTI_ICORRECT_C0	105
+#define CENTI_ICORRECT_C1	20
+
+#define HOURS_TO_SECONDS	3600
+#define OCV_SLOPE_UV		10869
+#define MILLI_UNIT		1000
+#define MICRO_UNIT		1000000
+#define NANO_UNIT		1000000000
+
+#define DEFAULT_TTF_RUN_PERIOD_MS	10000
+#define DEFAULT_TTF_ITERM_DELTA_MA	200
+
+static const struct ttf_pt ttf_ln_table[] = {
+	{ 1000,		0 },
+	{ 2000,		693 },
+	{ 4000,		1386 },
+	{ 6000,		1792 },
+	{ 8000,		2079 },
+	{ 16000,	2773 },
+	{ 32000,	3466 },
+	{ 64000,	4159 },
+	{ 128000,	4852 },
+};
+
 /* Cycle counter APIs */
 
 /**
@@ -670,3 +696,508 @@
 	mutex_init(&cl->lock);
 	return 0;
 }
+
+/* Time to full/empty algorithm  helper functions */
+
+static void ttf_circ_buf_add(struct ttf_circ_buf *buf, int val)
+{
+	buf->arr[buf->head] = val;
+	buf->head = (buf->head + 1) % ARRAY_SIZE(buf->arr);
+	buf->size = min(++buf->size, (int)ARRAY_SIZE(buf->arr));
+}
+
+static void ttf_circ_buf_clr(struct ttf_circ_buf *buf)
+{
+	buf->size = 0;
+	buf->head = 0;
+	memset(buf->arr, 0, sizeof(buf->arr));
+}
+
+static int cmp_int(const void *a, const void *b)
+{
+	return *(int *)a - *(int *)b;
+}
+
+static int ttf_circ_buf_median(struct ttf_circ_buf *buf, int *median)
+{
+	int *temp;
+
+	if (buf->size == 0)
+		return -ENODATA;
+
+	if (buf->size == 1) {
+		*median = buf->arr[0];
+		return 0;
+	}
+
+	temp = kmalloc_array(buf->size, sizeof(*temp), GFP_KERNEL);
+	if (!temp)
+		return -ENOMEM;
+
+	memcpy(temp, buf->arr, buf->size * sizeof(*temp));
+	sort(temp, buf->size, sizeof(*temp), cmp_int, NULL);
+
+	if (buf->size % 2)
+		*median = temp[buf->size / 2];
+	else
+		*median = (temp[buf->size / 2 - 1] + temp[buf->size / 2]) / 2;
+
+	kfree(temp);
+	return 0;
+}
+
+static int ttf_lerp(const struct ttf_pt *pts, size_t tablesize,
+						s32 input, s32 *output)
+{
+	int i;
+	s64 temp;
+
+	if (pts == NULL) {
+		pr_err("Table is NULL\n");
+		return -EINVAL;
+	}
+
+	if (tablesize < 1) {
+		pr_err("Table has no entries\n");
+		return -ENOENT;
+	}
+
+	if (tablesize == 1) {
+		*output = pts[0].y;
+		return 0;
+	}
+
+	if (pts[0].x > pts[1].x) {
+		pr_err("Table is not in acending order\n");
+		return -EINVAL;
+	}
+
+	if (input <= pts[0].x) {
+		*output = pts[0].y;
+		return 0;
+	}
+
+	if (input >= pts[tablesize - 1].x) {
+		*output = pts[tablesize - 1].y;
+		return 0;
+	}
+
+	for (i = 1; i < tablesize; i++) {
+		if (input >= pts[i].x)
+			continue;
+
+		temp = ((s64)pts[i].y - pts[i - 1].y) *
+						((s64)input - pts[i - 1].x);
+		temp = div_s64(temp, pts[i].x - pts[i - 1].x);
+		*output = temp + pts[i - 1].y;
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
+static int get_time_to_full_locked(struct ttf *ttf, int *val)
+{
+	int rc, ibatt_avg, vbatt_avg, rbatt = 0, msoc = 0, act_cap_mah = 0,
+		i_cc2cv = 0, soc_cc2cv, tau, divisor, iterm = 0, ttf_mode = 0,
+		i, soc_per_step, msoc_this_step, msoc_next_step,
+		ibatt_this_step, t_predicted_this_step, ttf_slope,
+		t_predicted_cv, t_predicted = 0, charge_type = 0,
+		float_volt_uv = 0;
+	s64 delta_ms;
+
+	rc = ttf->get_ttf_param(ttf->data, TTF_MSOC, &msoc);
+	if (rc < 0) {
+		pr_err("failed to get msoc rc=%d\n", rc);
+		return rc;
+	}
+	pr_debug("TTF: msoc=%d\n", msoc);
+
+	/* the battery is considered full if the SOC is 100% */
+	if (msoc >= 100) {
+		*val = 0;
+		return 0;
+	}
+
+	rc = ttf->get_ttf_param(ttf->data, TTF_MODE, &ttf_mode);
+
+	/* when switching TTF algorithms the TTF needs to be reset */
+	if (ttf->mode != ttf_mode) {
+		ttf_circ_buf_clr(&ttf->ibatt);
+		ttf_circ_buf_clr(&ttf->vbatt);
+		ttf->last_ttf = 0;
+		ttf->last_ms = 0;
+		ttf->mode = ttf_mode;
+	}
+
+	/* at least 10 samples are required to produce a stable IBATT */
+	if (ttf->ibatt.size < MAX_TTF_SAMPLES) {
+		*val = -1;
+		return 0;
+	}
+
+	rc = ttf_circ_buf_median(&ttf->ibatt, &ibatt_avg);
+	if (rc < 0) {
+		pr_err("failed to get IBATT AVG rc=%d\n", rc);
+		return rc;
+	}
+
+	rc = ttf_circ_buf_median(&ttf->vbatt, &vbatt_avg);
+	if (rc < 0) {
+		pr_err("failed to get VBATT AVG rc=%d\n", rc);
+		return rc;
+	}
+
+	ibatt_avg = -ibatt_avg / MILLI_UNIT;
+	vbatt_avg /= MILLI_UNIT;
+
+	rc = ttf->get_ttf_param(ttf->data, TTF_ITERM, &iterm);
+	if (rc < 0) {
+		pr_err("failed to get iterm rc=%d\n", rc);
+		return rc;
+	}
+	/* clamp ibatt_avg to iterm */
+	if (ibatt_avg < abs(iterm))
+		ibatt_avg = abs(iterm);
+
+	rc =  ttf->get_ttf_param(ttf->data, TTF_RBATT, &rbatt);
+	if (rc < 0) {
+		pr_err("failed to get battery resistance rc=%d\n", rc);
+		return rc;
+	}
+	rbatt /= MILLI_UNIT;
+
+	rc =  ttf->get_ttf_param(ttf->data, TTF_FCC, &act_cap_mah);
+	if (rc < 0) {
+		pr_err("failed to get ACT_BATT_CAP rc=%d\n", rc);
+		return rc;
+	}
+
+	pr_debug(" TTF: ibatt_avg=%d vbatt_avg=%d rbatt=%d act_cap_mah=%d\n",
+				ibatt_avg, vbatt_avg, rbatt, act_cap_mah);
+
+	rc =  ttf->get_ttf_param(ttf->data, TTF_VFLOAT, &float_volt_uv);
+	if (rc < 0) {
+		pr_err("failed to get float_volt_uv rc=%d\n", rc);
+		return rc;
+	}
+
+	rc =  ttf->get_ttf_param(ttf->data, TTF_CHG_TYPE, &charge_type);
+	if (rc < 0) {
+		pr_err("failed to get charge_type rc=%d\n", rc);
+		return rc;
+	}
+	/* estimated battery current at the CC to CV transition */
+	switch (ttf->mode) {
+	case TTF_MODE_NORMAL:
+		i_cc2cv = ibatt_avg * vbatt_avg /
+			max(MILLI_UNIT, float_volt_uv / MILLI_UNIT);
+		break;
+	case TTF_MODE_QNOVO:
+		i_cc2cv = min(
+			ttf->cc_step.arr[MAX_CC_STEPS - 1] / MILLI_UNIT,
+			ibatt_avg * vbatt_avg /
+			max(MILLI_UNIT, float_volt_uv / MILLI_UNIT));
+		break;
+	default:
+		pr_err("TTF mode %d is not supported\n", ttf->mode);
+		break;
+	}
+	pr_debug("TTF: i_cc2cv=%d\n", i_cc2cv);
+
+	/* if we are already in CV state then we can skip estimating CC */
+	if (charge_type == POWER_SUPPLY_CHARGE_TYPE_TAPER)
+		goto cv_estimate;
+
+	/* estimated SOC at the CC to CV transition */
+	soc_cc2cv = DIV_ROUND_CLOSEST(rbatt * i_cc2cv, OCV_SLOPE_UV);
+	soc_cc2cv = 100 - soc_cc2cv;
+	pr_debug("TTF: soc_cc2cv=%d\n", soc_cc2cv);
+
+	switch (ttf->mode) {
+	case TTF_MODE_NORMAL:
+		if (soc_cc2cv - msoc <= 0)
+			goto cv_estimate;
+
+		divisor = max(100, (ibatt_avg + i_cc2cv) / 2 * 100);
+		t_predicted = div_s64((s64)act_cap_mah * (soc_cc2cv - msoc) *
+						HOURS_TO_SECONDS, divisor);
+		break;
+	case TTF_MODE_QNOVO:
+		soc_per_step = 100 / MAX_CC_STEPS;
+		for (i = msoc / soc_per_step; i < MAX_CC_STEPS - 1; ++i) {
+			msoc_next_step = (i + 1) * soc_per_step;
+			if (i == msoc / soc_per_step)
+				msoc_this_step = msoc;
+			else
+				msoc_this_step = i * soc_per_step;
+
+			/* scale ibatt by 85% to account for discharge pulses */
+			ibatt_this_step = min(
+					ttf->cc_step.arr[i] / MILLI_UNIT,
+					ibatt_avg) * 85 / 100;
+			divisor = max(100, ibatt_this_step * 100);
+			t_predicted_this_step = div_s64((s64)act_cap_mah *
+					(msoc_next_step - msoc_this_step) *
+					HOURS_TO_SECONDS, divisor);
+			t_predicted += t_predicted_this_step;
+			pr_debug("TTF: [%d, %d] ma=%d t=%d\n",
+				msoc_this_step, msoc_next_step,
+				ibatt_this_step, t_predicted_this_step);
+		}
+		break;
+	default:
+		pr_err("TTF mode %d is not supported\n", ttf->mode);
+		break;
+	}
+
+cv_estimate:
+	pr_debug("TTF: t_predicted_cc=%d\n", t_predicted);
+
+	iterm = max(100, abs(iterm) + ttf->iterm_delta);
+	pr_debug("TTF: iterm=%d\n", iterm);
+
+	if (charge_type == POWER_SUPPLY_CHARGE_TYPE_TAPER)
+		tau = max(MILLI_UNIT, ibatt_avg * MILLI_UNIT / iterm);
+	else
+		tau = max(MILLI_UNIT, i_cc2cv * MILLI_UNIT / iterm);
+
+	rc = ttf_lerp(ttf_ln_table, ARRAY_SIZE(ttf_ln_table), tau, &tau);
+	if (rc < 0) {
+		pr_err("failed to interpolate tau rc=%d\n", rc);
+		return rc;
+	}
+
+	/* tau is scaled linearly from 95% to 100% SOC */
+	if (msoc >= 95)
+		tau = tau * 2 * (100 - msoc) / 10;
+
+	pr_debug("TTF: tau=%d\n", tau);
+	t_predicted_cv = div_s64((s64)act_cap_mah * rbatt * tau *
+						HOURS_TO_SECONDS, NANO_UNIT);
+	pr_debug("TTF: t_predicted_cv=%d\n", t_predicted_cv);
+	t_predicted += t_predicted_cv;
+
+	pr_debug("TTF: t_predicted_prefilter=%d\n", t_predicted);
+	if (ttf->last_ms != 0) {
+		delta_ms = ktime_ms_delta(ktime_get_boottime(),
+					  ms_to_ktime(ttf->last_ms));
+		if (delta_ms > 10000) {
+			ttf_slope = div64_s64(
+				((s64)t_predicted - ttf->last_ttf) *
+				MICRO_UNIT, delta_ms);
+			if (ttf_slope > -100)
+				ttf_slope = -100;
+			else if (ttf_slope < -2000)
+				ttf_slope = -2000;
+
+			t_predicted = div_s64(
+				(s64)ttf_slope * delta_ms, MICRO_UNIT) +
+				ttf->last_ttf;
+			pr_debug("TTF: ttf_slope=%d\n", ttf_slope);
+		} else {
+			t_predicted = ttf->last_ttf;
+		}
+	}
+
+	/* clamp the ttf to 0 */
+	if (t_predicted < 0)
+		t_predicted = 0;
+
+	pr_debug("TTF: t_predicted_postfilter=%d\n", t_predicted);
+	*val = t_predicted;
+	return 0;
+}
+
+/**
+ * ttf_get_time_to_full -
+ * @ttf: ttf object
+ * @val: Average time to full returned to the caller
+ *
+ * Get Average time to full the battery based on current soc, rbatt
+ * battery voltage and charge current etc.
+ */
+int ttf_get_time_to_full(struct ttf *ttf, int *val)
+{
+	int rc;
+
+	mutex_lock(&ttf->lock);
+	rc = get_time_to_full_locked(ttf, val);
+	mutex_unlock(&ttf->lock);
+
+	return rc;
+}
+
+static void ttf_work(struct work_struct *work)
+{
+	struct ttf *ttf = container_of(work,
+				struct ttf, ttf_work.work);
+	int rc, ibatt_now, vbatt_now, ttf_now, charge_status;
+	ktime_t ktime_now;
+
+	mutex_lock(&ttf->lock);
+	rc =  ttf->get_ttf_param(ttf->data, TTF_CHG_STATUS, &charge_status);
+	if (rc < 0) {
+		pr_err("failed to get charge_status rc=%d\n", rc);
+		goto end_work;
+	}
+	if (charge_status != POWER_SUPPLY_STATUS_CHARGING &&
+			charge_status != POWER_SUPPLY_STATUS_DISCHARGING)
+		goto end_work;
+
+	rc =  ttf->get_ttf_param(ttf->data, TTF_IBAT, &ibatt_now);
+	if (rc < 0) {
+		pr_err("failed to get battery current, rc=%d\n", rc);
+		goto end_work;
+	}
+
+	rc =  ttf->get_ttf_param(ttf->data, TTF_VBAT, &vbatt_now);
+	if (rc < 0) {
+		pr_err("failed to get battery voltage, rc=%d\n", rc);
+		goto end_work;
+	}
+
+	ttf_circ_buf_add(&ttf->ibatt, ibatt_now);
+	ttf_circ_buf_add(&ttf->vbatt, vbatt_now);
+
+	if (charge_status == POWER_SUPPLY_STATUS_CHARGING) {
+		rc = get_time_to_full_locked(ttf, &ttf_now);
+		if (rc < 0) {
+			pr_err("failed to get ttf, rc=%d\n", rc);
+			goto end_work;
+		}
+
+		/* keep the wake lock and prime the IBATT and VBATT buffers */
+		if (ttf_now < 0) {
+			/* delay for one FG cycle */
+			schedule_delayed_work(&ttf->ttf_work,
+					msecs_to_jiffies(1000));
+			mutex_unlock(&ttf->lock);
+			return;
+		}
+
+		/* update the TTF reference point every minute */
+		ktime_now = ktime_get_boottime();
+		if (ktime_ms_delta(ktime_now,
+				   ms_to_ktime(ttf->last_ms)) > 60000 ||
+				   ttf->last_ms == 0) {
+			ttf->last_ttf = ttf_now;
+			ttf->last_ms = ktime_to_ms(ktime_now);
+		}
+	}
+
+	/* recurse every 10 seconds */
+	schedule_delayed_work(&ttf->ttf_work, msecs_to_jiffies(ttf->period_ms));
+end_work:
+	ttf->awake_voter(ttf->data, false);
+	mutex_unlock(&ttf->lock);
+}
+
+/**
+ * ttf_get_time_to_empty -
+ * @ttf: ttf object
+ * @val: Average time to empty returned to the caller
+ *
+ * Get Average time to empty the battery based on current soc
+ * and average battery current.
+ */
+int ttf_get_time_to_empty(struct ttf *ttf, int *val)
+{
+	int rc, ibatt_avg, msoc, act_cap_mah, divisor;
+
+	rc = ttf_circ_buf_median(&ttf->ibatt, &ibatt_avg);
+	if (rc < 0) {
+		/* try to get instantaneous current */
+		rc = ttf->get_ttf_param(ttf->data, TTF_IBAT, &ibatt_avg);
+		if (rc < 0) {
+			pr_err("failed to get battery current, rc=%d\n", rc);
+			return rc;
+		}
+	}
+
+	ibatt_avg /= MILLI_UNIT;
+	/* clamp ibatt_avg to 100mA */
+	if (ibatt_avg < 100)
+		ibatt_avg = 100;
+
+	rc = ttf->get_ttf_param(ttf->data, TTF_MSOC, &msoc);
+	if (rc < 0) {
+		pr_err("Error in getting capacity, rc=%d\n", rc);
+		return rc;
+	}
+
+	rc = ttf->get_ttf_param(ttf->data, TTF_FCC, &act_cap_mah);
+	if (rc < 0) {
+		pr_err("Error in getting ACT_BATT_CAP, rc=%d\n", rc);
+		return rc;
+	}
+
+	divisor = CENTI_ICORRECT_C0 * 100 + CENTI_ICORRECT_C1 * msoc;
+	divisor = ibatt_avg * divisor / 100;
+	divisor = max(100, divisor);
+	*val = act_cap_mah * msoc * HOURS_TO_SECONDS / divisor;
+	return 0;
+}
+
+/**
+ * ttf_update -
+ * @ttf: ttf object
+ * @input_present: Indicator for input presence
+ *
+ * Called by FG/QG driver when there is a state change (Charging status, SOC)
+ *
+ */
+void ttf_update(struct ttf *ttf, bool input_present)
+{
+	int delay_ms;
+
+	if (ttf->input_present == input_present)
+		return;
+
+	ttf->input_present = input_present;
+	if (input_present)
+		/* wait 35 seconds for the input to settle */
+		delay_ms = 35000;
+	else
+		/* wait 5 seconds for current to settle during discharge */
+		delay_ms = 5000;
+
+	ttf->awake_voter(ttf->data, true);
+	cancel_delayed_work_sync(&ttf->ttf_work);
+	mutex_lock(&ttf->lock);
+	ttf_circ_buf_clr(&ttf->ibatt);
+	ttf_circ_buf_clr(&ttf->vbatt);
+	ttf->last_ttf = 0;
+	ttf->last_ms = 0;
+	mutex_unlock(&ttf->lock);
+	schedule_delayed_work(&ttf->ttf_work, msecs_to_jiffies(delay_ms));
+}
+
+/**
+ * ttf_tte_init -
+ * @ttf: Time to full object
+ *
+ * FG/QG have to call this during driver probe to validate the required
+ * parameters after allocating ttf object.
+ *
+ */
+int ttf_tte_init(struct ttf *ttf)
+{
+	if (!ttf)
+		return -ENODEV;
+
+	if (!ttf->awake_voter || !ttf->get_ttf_param) {
+		pr_err("Insufficient functions for supporting ttf\n");
+		return -EINVAL;
+	}
+
+	if (!ttf->iterm_delta)
+		ttf->iterm_delta = DEFAULT_TTF_ITERM_DELTA_MA;
+	if (!ttf->period_ms)
+		ttf->period_ms = DEFAULT_TTF_RUN_PERIOD_MS;
+
+	mutex_init(&ttf->lock);
+	INIT_DELAYED_WORK(&ttf->ttf_work, ttf_work);
+
+	return 0;
+}
diff --git a/drivers/power/supply/qcom/fg-alg.h b/drivers/power/supply/qcom/fg-alg.h
index 7c25007..70183ba 100644
--- a/drivers/power/supply/qcom/fg-alg.h
+++ b/drivers/power/supply/qcom/fg-alg.h
@@ -15,6 +15,8 @@
 
 #define BUCKET_COUNT		8
 #define BUCKET_SOC_PCT		(256 / BUCKET_COUNT)
+#define MAX_CC_STEPS		20
+#define MAX_TTF_SAMPLES		10
 
 struct cycle_counter {
 	void		*data;
@@ -58,6 +60,57 @@
 	int (*prime_cc_soc)(void *data, u32 cc_soc_sw);
 };
 
+enum ttf_mode {
+	TTF_MODE_NORMAL = 0,
+	TTF_MODE_QNOVO,
+};
+
+enum ttf_param {
+	TTF_MSOC = 0,
+	TTF_VBAT,
+	TTF_IBAT,
+	TTF_FCC,
+	TTF_MODE,
+	TTF_ITERM,
+	TTF_RBATT,
+	TTF_VFLOAT,
+	TTF_CHG_TYPE,
+	TTF_CHG_STATUS,
+};
+
+struct ttf_circ_buf {
+	int	arr[MAX_TTF_SAMPLES];
+	int	size;
+	int	head;
+};
+
+struct ttf_cc_step_data {
+	int arr[MAX_CC_STEPS];
+	int sel;
+};
+
+struct ttf_pt {
+	s32 x;
+	s32 y;
+};
+
+struct ttf {
+	void			*data;
+	struct ttf_circ_buf	ibatt;
+	struct ttf_circ_buf	vbatt;
+	struct ttf_cc_step_data	cc_step;
+	struct mutex		lock;
+	int			mode;
+	int			last_ttf;
+	int			input_present;
+	int			iterm_delta;
+	int			period_ms;
+	s64			last_ms;
+	struct delayed_work	ttf_work;
+	int (*get_ttf_param)(void *data, enum ttf_param, int *val);
+	int (*awake_voter)(void *data, bool vote);
+};
+
 int restore_cycle_count(struct cycle_counter *counter);
 void clear_cycle_count(struct cycle_counter *counter);
 void cycle_count_update(struct cycle_counter *counter, int batt_soc,
@@ -72,5 +125,9 @@
 int cap_learning_init(struct cap_learning *cl);
 int cap_learning_post_profile_init(struct cap_learning *cl,
 		int64_t nom_cap_uah);
+void ttf_update(struct ttf *ttf, bool input_present);
+int ttf_get_time_to_empty(struct ttf *ttf, int *val);
+int ttf_get_time_to_full(struct ttf *ttf, int *val);
+int ttf_tte_init(struct ttf *ttf);
 
 #endif
diff --git a/drivers/power/supply/qcom/qg-core.h b/drivers/power/supply/qcom/qg-core.h
index a1aeac2..e834b8e 100644
--- a/drivers/power/supply/qcom/qg-core.h
+++ b/drivers/power/supply/qcom/qg-core.h
@@ -14,6 +14,7 @@
 
 #include <linux/kernel.h>
 #include "fg-alg.h"
+#include "qg-defs.h"
 
 struct qg_batt_props {
 	const char		*batt_type_str;
@@ -50,10 +51,24 @@
 	int			rbat_conn_mohm;
 	int			ignore_shutdown_soc_secs;
 	int			cold_temp_threshold;
+	int			esr_qual_i_ua;
+	int			esr_qual_v_uv;
+	int			esr_disable_soc;
 	bool			hold_soc_while_full;
 	bool			linearize_soc;
 	bool			cl_disable;
 	bool			cl_feedback_on;
+	bool			esr_disable;
+	bool			esr_discharge_enable;
+};
+
+struct qg_esr_data {
+	u32			pre_esr_v;
+	u32			pre_esr_i;
+	u32			post_esr_v;
+	u32			post_esr_i;
+	u32			esr;
+	bool			valid;
 };
 
 struct qpnp_qg {
@@ -87,6 +102,7 @@
 	struct power_supply	*batt_psy;
 	struct power_supply	*usb_psy;
 	struct power_supply	*parallel_psy;
+	struct qg_esr_data	esr_data[QG_MAX_ESR_COUNT];
 
 	/* status variable */
 	u32			*debug_mask;
@@ -102,10 +118,14 @@
 	bool			charge_full;
 	int			charge_status;
 	int			charge_type;
+	int			chg_iterm_ma;
 	int			next_wakeup_ms;
+	u32			fifo_done_count;
 	u32			wa_flags;
 	u32			seq_no;
 	u32			charge_counter_uah;
+	u32			esr_avg;
+	u32			esr_last;
 	ktime_t			last_user_update_time;
 	ktime_t			last_fifo_update_time;
 
@@ -116,6 +136,7 @@
 	int			pon_soc;
 	int			batt_soc;
 	int			cc_soc;
+	int			full_soc;
 	struct alarm		alarm_timer;
 	u32			sdam_data[SDAM_MAX];
 
@@ -126,6 +147,8 @@
 	struct cap_learning	*cl;
 	/* charge counter */
 	struct cycle_counter	*counter;
+	/* ttf */
+	struct ttf		*ttf;
 };
 
 enum ocv_type {
@@ -147,6 +170,7 @@
 	QG_DEBUG_BUS_READ	= BIT(8),
 	QG_DEBUG_BUS_WRITE	= BIT(9),
 	QG_DEBUG_ALG_CL		= BIT(10),
+	QG_DEBUG_ESR		= BIT(11),
 };
 
 enum qg_irq {
diff --git a/drivers/power/supply/qcom/qg-defs.h b/drivers/power/supply/qcom/qg-defs.h
index 2061208..997ff70 100644
--- a/drivers/power/supply/qcom/qg-defs.h
+++ b/drivers/power/supply/qcom/qg-defs.h
@@ -34,6 +34,7 @@
 #define GOOD_OCV_VOTER			"GOOD_OCV_VOTER"
 #define PROFILE_IRQ_DISABLE		"NO_PROFILE_IRQ_DISABLE"
 #define QG_INIT_STATE_IRQ_DISABLE	"QG_INIT_STATE_IRQ_DISABLE"
+#define TTF_AWAKE_VOTER			"TTF_AWAKE_VOTER"
 
 #define V_RAW_TO_UV(V_RAW)		div_u64(194637ULL * (u64)V_RAW, 1000)
 #define I_RAW_TO_UA(I_RAW)		div_s64(152588LL * (s64)I_RAW, 1000)
@@ -44,6 +45,9 @@
 #define UV_TO_DECIUV(a)			(a / 100)
 #define DECIUV_TO_UV(a)			(a * 100)
 
+#define QG_MAX_ESR_COUNT		10
+#define QG_MIN_ESR_COUNT		2
+
 #define CAP(min, max, value)			\
 		((min > value) ? min : ((value > max) ? max : value))
 
diff --git a/drivers/power/supply/qcom/qg-reg.h b/drivers/power/supply/qcom/qg-reg.h
index 66f9be1..d586a72 100644
--- a/drivers/power/supply/qcom/qg-reg.h
+++ b/drivers/power/supply/qcom/qg-reg.h
@@ -18,6 +18,7 @@
 
 #define QG_STATUS1_REG				0x08
 #define BATTERY_PRESENT_BIT			BIT(0)
+#define ESR_MEAS_DONE_BIT			BIT(4)
 
 #define QG_STATUS2_REG				0x09
 #define GOOD_OCV_BIT				BIT(1)
@@ -25,6 +26,9 @@
 #define QG_STATUS3_REG				0x0A
 #define COUNT_FIFO_RT_MASK			GENMASK(3, 0)
 
+#define QG_STATUS4_REG				0x0B
+#define ESR_MEAS_IN_PROGRESS_BIT		BIT(4)
+
 #define QG_INT_RT_STS_REG			0x10
 #define FIFO_UPDATE_DONE_RT_STS_BIT		BIT(3)
 #define VBAT_LOW_INT_RT_STS_BIT			BIT(1)
@@ -60,11 +64,19 @@
 #define QG_S3_ENTRY_IBAT_THRESHOLD_REG		0x5E
 #define QG_S3_EXIT_IBAT_THRESHOLD_REG		0x5F
 
+#define QG_ESR_MEAS_TRIG_REG			0x68
+#define HW_ESR_MEAS_START_BIT			BIT(0)
+
 #define QG_S7_PON_OCV_V_DATA0_REG		0x70
 #define QG_S7_PON_OCV_I_DATA0_REG		0x72
 #define QG_S3_GOOD_OCV_V_DATA0_REG		0x74
 #define QG_S3_GOOD_OCV_I_DATA0_REG		0x76
 
+#define QG_PRE_ESR_V_DATA0_REG			0x78
+#define QG_PRE_ESR_I_DATA0_REG			0x7A
+#define QG_POST_ESR_V_DATA0_REG			0x7C
+#define QG_POST_ESR_I_DATA0_REG			0x7E
+
 #define QG_V_ACCUM_DATA0_RT_REG			0x88
 #define QG_I_ACCUM_DATA0_RT_REG			0x8B
 #define QG_ACCUM_CNT_RT_REG			0x8E
@@ -80,15 +92,19 @@
 #define QG_LAST_S3_SLEEP_V_DATA0_REG		0xCC
 
 /* SDAM offsets */
-#define QG_SDAM_VALID_OFFSET			0x46
-#define QG_SDAM_SOC_OFFSET			0x47
-#define QG_SDAM_TEMP_OFFSET			0x48
-#define QG_SDAM_RBAT_OFFSET			0x4A
-#define QG_SDAM_OCV_OFFSET			0x4C
-#define QG_SDAM_IBAT_OFFSET			0x50
-#define QG_SDAM_TIME_OFFSET			0x54
-#define QG_SDAM_CYCLE_COUNT_OFFSET		0x58
-#define QG_SDAM_LEARNED_CAPACITY_OFFSET		0x68
-#define QG_SDAM_PON_OCV_OFFSET			0x7C
+#define QG_SDAM_VALID_OFFSET			0x46 /* 1-byte 0x46 */
+#define QG_SDAM_SOC_OFFSET			0x47 /* 1-byte 0x47 */
+#define QG_SDAM_TEMP_OFFSET			0x48 /* 2-byte 0x48-0x49 */
+#define QG_SDAM_RBAT_OFFSET			0x4A /* 2-byte 0x4A-0x4B */
+#define QG_SDAM_OCV_OFFSET			0x4C /* 4-byte 0x4C-0x4F */
+#define QG_SDAM_IBAT_OFFSET			0x50 /* 4-byte 0x50-0x53 */
+#define QG_SDAM_TIME_OFFSET			0x54 /* 4-byte 0x54-0x57 */
+#define QG_SDAM_CYCLE_COUNT_OFFSET		0x58 /* 16-byte 0x58-0x67 */
+#define QG_SDAM_LEARNED_CAPACITY_OFFSET		0x68 /* 2-byte 0x68-0x69 */
+#define QG_SDAM_ESR_CHARGE_DELTA_OFFSET		0x6A /* 4-byte 0x6A-0x6D */
+#define QG_SDAM_ESR_DISCHARGE_DELTA_OFFSET	0x6E /* 4-byte 0x6E-0x71 */
+#define QG_SDAM_ESR_CHARGE_SF_OFFSET		0x72 /* 2-byte 0x72-0x73 */
+#define QG_SDAM_ESR_DISCHARGE_SF_OFFSET		0x74 /* 2-byte 0x74-0x75 */
+#define QG_SDAM_PON_OCV_OFFSET			0x7C /* 2-byte 0x7C-0x7D */
 
 #endif
diff --git a/drivers/power/supply/qcom/qg-sdam.c b/drivers/power/supply/qcom/qg-sdam.c
index 7bc4afa..e7ffcb5 100644
--- a/drivers/power/supply/qcom/qg-sdam.c
+++ b/drivers/power/supply/qcom/qg-sdam.c
@@ -68,6 +68,26 @@
 		.offset = QG_SDAM_PON_OCV_OFFSET,
 		.length = 2,
 	},
+	[SDAM_ESR_CHARGE_DELTA] = {
+		.name	= "SDAM_ESR_CHARGE_DELTA",
+		.offset = QG_SDAM_ESR_CHARGE_DELTA_OFFSET,
+		.length = 4,
+	},
+	[SDAM_ESR_DISCHARGE_DELTA] = {
+		.name	= "SDAM_ESR_DISCHARGE_DELTA",
+		.offset = QG_SDAM_ESR_DISCHARGE_DELTA_OFFSET,
+		.length = 4,
+	},
+	[SDAM_ESR_CHARGE_SF] = {
+		.name	= "SDAM_ESR_CHARGE_SF_OFFSET",
+		.offset = QG_SDAM_ESR_CHARGE_SF_OFFSET,
+		.length = 2,
+	},
+	[SDAM_ESR_DISCHARGE_SF] = {
+		.name	= "SDAM_ESR_DISCHARGE_SF_OFFSET",
+		.offset = QG_SDAM_ESR_DISCHARGE_SF_OFFSET,
+		.length = 2,
+	},
 };
 
 int qg_sdam_write(u8 param, u32 data)
diff --git a/drivers/power/supply/qcom/qg-sdam.h b/drivers/power/supply/qcom/qg-sdam.h
index 10e684f..45218a8 100644
--- a/drivers/power/supply/qcom/qg-sdam.h
+++ b/drivers/power/supply/qcom/qg-sdam.h
@@ -24,6 +24,10 @@
 	SDAM_IBAT_UA,
 	SDAM_TIME_SEC,
 	SDAM_PON_OCV_UV,
+	SDAM_ESR_CHARGE_DELTA,
+	SDAM_ESR_DISCHARGE_DELTA,
+	SDAM_ESR_CHARGE_SF,
+	SDAM_ESR_DISCHARGE_SF,
 	SDAM_MAX,
 };
 
diff --git a/drivers/power/supply/qcom/qg-util.c b/drivers/power/supply/qcom/qg-util.c
index d354799..824d914 100644
--- a/drivers/power/supply/qcom/qg-util.c
+++ b/drivers/power/supply/qcom/qg-util.c
@@ -111,6 +111,22 @@
 	return rc;
 }
 
+int qg_read_raw_data(struct qpnp_qg *chip, int addr, u32 *data)
+{
+	int rc;
+	u8 reg[2] = {0};
+
+	rc = qg_read(chip, chip->qg_base + addr, &reg[0], 2);
+	if (rc < 0) {
+		pr_err("Failed to read QG addr %d rc=%d\n", addr, rc);
+		return rc;
+	}
+
+	*data = reg[0] | (reg[1] << 8);
+
+	return rc;
+}
+
 int get_fifo_length(struct qpnp_qg *chip, u32 *fifo_length, bool rt)
 {
 	int rc;
diff --git a/drivers/power/supply/qcom/qg-util.h b/drivers/power/supply/qcom/qg-util.h
index 385c9e0..bb17afb 100644
--- a/drivers/power/supply/qcom/qg-util.h
+++ b/drivers/power/supply/qcom/qg-util.h
@@ -15,6 +15,7 @@
 int qg_read(struct qpnp_qg *chip, u32 addr, u8 *val, int len);
 int qg_write(struct qpnp_qg *chip, u32 addr, u8 *val, int len);
 int qg_masked_write(struct qpnp_qg *chip, int addr, u32 mask, u32 val);
+int qg_read_raw_data(struct qpnp_qg *chip, int addr, u32 *data);
 int get_fifo_length(struct qpnp_qg *chip, u32 *fifo_length, bool rt);
 int get_sample_count(struct qpnp_qg *chip, u32 *sample_count);
 int get_sample_interval(struct qpnp_qg *chip, u32 *sample_interval);
diff --git a/drivers/power/supply/qcom/qpnp-qg.c b/drivers/power/supply/qcom/qpnp-qg.c
index 5a0682c..a8a7826 100644
--- a/drivers/power/supply/qcom/qpnp-qg.c
+++ b/drivers/power/supply/qcom/qpnp-qg.c
@@ -43,6 +43,16 @@
 	debug_mask, qg_debug_mask, int, 0600
 );
 
+static int qg_esr_mod_count = 10;
+module_param_named(
+	esr_mod_count, qg_esr_mod_count, int, 0600
+);
+
+static int qg_esr_count = 5;
+module_param_named(
+	esr_count, qg_esr_count, int, 0600
+);
+
 static bool is_battery_present(struct qpnp_qg *chip)
 {
 	u8 reg = 0;
@@ -211,6 +221,14 @@
 	}
 
 	pr_debug("Notified charger on float voltage and FCC\n");
+
+	rc = power_supply_get_property(chip->batt_psy,
+			POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT, &prop);
+	if (rc < 0) {
+		pr_err("Failed to get charge term current, rc=%d\n", rc);
+		return;
+	}
+	chip->chg_iterm_ma = prop.intval;
 }
 
 static bool is_batt_available(struct qpnp_qg *chip)
@@ -228,7 +246,7 @@
 	return true;
 }
 
-static int qg_update_sdam_params(struct qpnp_qg *chip)
+static int qg_store_soc_params(struct qpnp_qg *chip)
 {
 	int rc, batt_temp = 0, i;
 	unsigned long rtc_sec = 0;
@@ -245,13 +263,11 @@
 	else
 		chip->sdam_data[SDAM_TEMP] = (u32)batt_temp;
 
-	rc = qg_sdam_write_all(chip->sdam_data);
-	if (rc < 0)
-		pr_err("Failed to write to SDAM rc=%d\n", rc);
-
-	for (i = 0; i < SDAM_MAX; i++)
+	for (i = 0; i <= SDAM_TIME_SEC; i++) {
+		rc |= qg_sdam_write(i, chip->sdam_data[i]);
 		qg_dbg(chip, QG_DEBUG_STATUS, "SDAM write param %d value=%d\n",
 					i, chip->sdam_data[i]);
+	}
 
 	return rc;
 }
@@ -433,6 +449,87 @@
 	return rc;
 }
 
+#define MIN_FIFO_FULL_TIME_MS			12000
+static int process_rt_fifo_data(struct qpnp_qg *chip,
+				bool vbat_low, bool update_smb)
+{
+	int rc = 0;
+	ktime_t now = ktime_get();
+	s64 time_delta;
+
+	/*
+	 * Reject the FIFO read event if there are back-to-back requests
+	 * This is done to gaurantee that there is always a minimum FIFO
+	 * data to be processed, ignore this if vbat_low is set.
+	 */
+	time_delta = ktime_ms_delta(now, chip->last_user_update_time);
+
+	qg_dbg(chip, QG_DEBUG_FIFO, "time_delta=%lld ms vbat_low=%d\n",
+				time_delta, vbat_low);
+
+	if (time_delta > MIN_FIFO_FULL_TIME_MS || vbat_low || update_smb) {
+		rc = qg_master_hold(chip, true);
+		if (rc < 0) {
+			pr_err("Failed to hold master, rc=%d\n", rc);
+			goto done;
+		}
+
+		rc = qg_process_rt_fifo(chip);
+		if (rc < 0) {
+			pr_err("Failed to process FIFO real-time, rc=%d\n", rc);
+			goto done;
+		}
+
+		if (vbat_low) {
+			/* change FIFO length */
+			rc = qg_update_fifo_length(chip,
+					chip->dt.s2_vbat_low_fifo_length);
+			if (rc < 0)
+				goto done;
+
+			qg_dbg(chip, QG_DEBUG_STATUS,
+				"FIFO length updated to %d vbat_low=%d\n",
+					chip->dt.s2_vbat_low_fifo_length,
+					vbat_low);
+		}
+
+		if (update_smb) {
+			rc = qg_masked_write(chip, chip->qg_base +
+				QG_MODE_CTL1_REG, PARALLEL_IBAT_SENSE_EN_BIT,
+				chip->parallel_enabled ?
+					PARALLEL_IBAT_SENSE_EN_BIT : 0);
+			if (rc < 0) {
+				pr_err("Failed to update SMB_EN, rc=%d\n", rc);
+				goto done;
+			}
+			qg_dbg(chip, QG_DEBUG_STATUS, "Parallel SENSE %d\n",
+						chip->parallel_enabled);
+		}
+
+		rc = qg_master_hold(chip, false);
+		if (rc < 0) {
+			pr_err("Failed to release master, rc=%d\n", rc);
+			goto done;
+		}
+		/* FIFOs restarted */
+		chip->last_fifo_update_time = ktime_get();
+
+		/* signal the read thread */
+		chip->data_ready = true;
+		wake_up_interruptible(&chip->qg_wait_q);
+		chip->last_user_update_time = now;
+
+		/* vote to stay awake until userspace reads data */
+		vote(chip->awake_votable, FIFO_RT_DONE_VOTER, true, 0);
+	} else {
+		qg_dbg(chip, QG_DEBUG_FIFO, "FIFO processing too early time_delta=%lld\n",
+							time_delta);
+	}
+done:
+	qg_master_hold(chip, false);
+	return rc;
+}
+
 #define VBAT_LOW_HYST_UV		50000 /* 50mV */
 static int qg_vbat_low_wa(struct qpnp_qg *chip)
 {
@@ -561,82 +658,353 @@
 	return rc;
 }
 
-#define MIN_FIFO_FULL_TIME_MS			12000
-static int process_rt_fifo_data(struct qpnp_qg *chip,
-				bool vbat_low, bool update_smb)
+static void qg_retrieve_esr_params(struct qpnp_qg *chip)
 {
-	int rc = 0;
-	ktime_t now = ktime_get();
-	s64 time_delta;
+	u32 data = 0;
+	int rc;
+
+	rc = qg_sdam_read(SDAM_ESR_CHARGE_DELTA, &data);
+	if (!rc && data) {
+		chip->kdata.param[QG_ESR_CHARGE_DELTA].data = data;
+		chip->kdata.param[QG_ESR_CHARGE_DELTA].valid = true;
+		qg_dbg(chip, QG_DEBUG_ESR,
+				"ESR_CHARGE_DELTA SDAM=%d\n", data);
+	} else if (rc < 0) {
+		pr_err("Failed to read ESR_CHARGE_DELTA rc=%d\n", rc);
+	}
+
+	rc = qg_sdam_read(SDAM_ESR_DISCHARGE_DELTA, &data);
+	if (!rc && data) {
+		chip->kdata.param[QG_ESR_DISCHARGE_DELTA].data = data;
+		chip->kdata.param[QG_ESR_DISCHARGE_DELTA].valid = true;
+		qg_dbg(chip, QG_DEBUG_ESR,
+				"ESR_DISCHARGE_DELTA SDAM=%d\n", data);
+	} else if (rc < 0) {
+		pr_err("Failed to read ESR_DISCHARGE_DELTA rc=%d\n", rc);
+	}
+
+	rc = qg_sdam_read(SDAM_ESR_CHARGE_SF, &data);
+	if (!rc && data) {
+		chip->kdata.param[QG_ESR_CHARGE_SF].data = data;
+		chip->kdata.param[QG_ESR_CHARGE_SF].valid = true;
+		qg_dbg(chip, QG_DEBUG_ESR,
+				"ESR_CHARGE_SF SDAM=%d\n", data);
+	} else if (rc < 0) {
+		pr_err("Failed to read ESR_CHARGE_SF rc=%d\n", rc);
+	}
+
+	rc = qg_sdam_read(SDAM_ESR_DISCHARGE_SF, &data);
+	if (!rc && data) {
+		chip->kdata.param[QG_ESR_DISCHARGE_SF].data = data;
+		chip->kdata.param[QG_ESR_DISCHARGE_SF].valid = true;
+		qg_dbg(chip, QG_DEBUG_ESR,
+				"ESR_DISCHARGE_SF SDAM=%d\n", data);
+	} else if (rc < 0) {
+		pr_err("Failed to read ESR_DISCHARGE_SF rc=%d\n", rc);
+	}
+}
+
+static void qg_store_esr_params(struct qpnp_qg *chip)
+{
+	unsigned int esr;
+
+	if (chip->udata.param[QG_ESR_CHARGE_DELTA].valid) {
+		esr = chip->udata.param[QG_ESR_CHARGE_DELTA].data;
+		qg_sdam_write(SDAM_ESR_CHARGE_DELTA, esr);
+		qg_dbg(chip, QG_DEBUG_ESR,
+			"SDAM store ESR_CHARGE_DELTA=%d\n", esr);
+	}
+
+	if (chip->udata.param[QG_ESR_DISCHARGE_DELTA].valid) {
+		esr = chip->udata.param[QG_ESR_DISCHARGE_DELTA].data;
+		qg_sdam_write(SDAM_ESR_DISCHARGE_DELTA, esr);
+		qg_dbg(chip, QG_DEBUG_ESR,
+			"SDAM store ESR_DISCHARGE_DELTA=%d\n", esr);
+	}
+
+	if (chip->udata.param[QG_ESR_CHARGE_SF].valid) {
+		esr = chip->udata.param[QG_ESR_CHARGE_SF].data;
+		qg_sdam_write(SDAM_ESR_CHARGE_SF, esr);
+		qg_dbg(chip, QG_DEBUG_ESR,
+			"SDAM store ESR_CHARGE_SF=%d\n", esr);
+	}
+
+	if (chip->udata.param[QG_ESR_DISCHARGE_SF].valid) {
+		esr = chip->udata.param[QG_ESR_DISCHARGE_SF].data;
+		qg_sdam_write(SDAM_ESR_DISCHARGE_SF, esr);
+		qg_dbg(chip, QG_DEBUG_ESR,
+			"SDAM store ESR_DISCHARGE_SF=%d\n", esr);
+	}
+}
+
+#define MAX_ESR_RETRY_COUNT		10
+#define ESR_SD_PERCENT			10
+static int qg_process_esr_data(struct qpnp_qg *chip)
+{
+	int i;
+	int pre_i, post_i, pre_v, post_v, first_pre_i = 0;
+	int diff_v, diff_i, esr_avg = 0, count = 0;
+
+	for (i = 0; i < qg_esr_count; i++) {
+		if (!chip->esr_data[i].valid)
+			continue;
+
+		pre_i = chip->esr_data[i].pre_esr_i;
+		pre_v = chip->esr_data[i].pre_esr_v;
+		post_i = chip->esr_data[i].post_esr_i;
+		post_v = chip->esr_data[i].post_esr_v;
+
+		/*
+		 * Check if any of the pre/post readings have changed
+		 * signs by comparing it with the first valid
+		 * pre_i value.
+		 */
+		if (!first_pre_i)
+			first_pre_i = pre_i;
+
+		if ((first_pre_i < 0 && pre_i > 0) ||
+			(first_pre_i > 0 && post_i < 0) ||
+			(first_pre_i < 0 && post_i > 0)) {
+			qg_dbg(chip, QG_DEBUG_ESR,
+				"ESR-sign mismatch %d reject all data\n", i);
+			esr_avg = count = 0;
+			break;
+		}
+
+		/* calculate ESR */
+		diff_v = abs(post_v - pre_v);
+		diff_i = abs(post_i - pre_i);
+
+		if (!diff_v || !diff_i ||
+			(diff_i < chip->dt.esr_qual_i_ua) ||
+			(diff_v < chip->dt.esr_qual_v_uv)) {
+			qg_dbg(chip, QG_DEBUG_ESR,
+				"ESR (%d) V/I %duA %duV fails qualification\n",
+				i, diff_i, diff_v);
+			chip->esr_data[i].valid = false;
+			continue;
+		}
+
+		chip->esr_data[i].esr =
+			DIV_ROUND_CLOSEST(diff_v * 1000, diff_i);
+		qg_dbg(chip, QG_DEBUG_ESR,
+			"ESR qualified: i=%d pre_i=%d pre_v=%d post_i=%d post_v=%d esr_diff_v=%d esr_diff_i=%d esr=%d\n",
+			i, pre_i, pre_v, post_i, post_v,
+			diff_v, diff_i, chip->esr_data[i].esr);
+
+		esr_avg += chip->esr_data[i].esr;
+		count++;
+	}
+
+	if (!count) {
+		qg_dbg(chip, QG_DEBUG_ESR,
+			"No ESR samples qualified, ESR not found\n");
+		chip->esr_avg = 0;
+		return 0;
+	}
+
+	esr_avg /= count;
+	qg_dbg(chip, QG_DEBUG_ESR,
+		"ESR all sample average=%d count=%d apply_SD=%d\n",
+		esr_avg, count, (esr_avg * ESR_SD_PERCENT) / 100);
 
 	/*
-	 * Reject the FIFO read event if there are back-to-back requests
-	 * This is done to gaurantee that there is always a minimum FIFO
-	 * data to be processed, ignore this if vbat_low is set.
+	 * Reject ESR samples which do not fall in
+	 * 10% the standard-deviation
 	 */
-	time_delta = ktime_ms_delta(now, chip->last_user_update_time);
+	count = 0;
+	for (i = 0; i < qg_esr_count; i++) {
+		if (!chip->esr_data[i].valid)
+			continue;
 
-	qg_dbg(chip, QG_DEBUG_FIFO, "time_delta=%lld ms vbat_low=%d\n",
-				time_delta, vbat_low);
+		if ((abs(chip->esr_data[i].esr - esr_avg) <=
+			(esr_avg * ESR_SD_PERCENT) / 100)) {
+			/* valid ESR */
+			chip->esr_avg += chip->esr_data[i].esr;
+			count++;
+			qg_dbg(chip, QG_DEBUG_ESR,
+				"Valid ESR after SD (%d) %d mOhm\n",
+				i, chip->esr_data[i].esr);
+		} else {
+			qg_dbg(chip, QG_DEBUG_ESR,
+				"ESR (%d) %d falls-out of SD(%d)\n",
+				i, chip->esr_data[i].esr, ESR_SD_PERCENT);
+		}
+	}
 
-	if (time_delta > MIN_FIFO_FULL_TIME_MS || vbat_low || update_smb) {
-		rc = qg_master_hold(chip, true);
+	if (count >= QG_MIN_ESR_COUNT) {
+		chip->esr_avg /= count;
+		qg_dbg(chip, QG_DEBUG_ESR, "Average estimated ESR %d mOhm\n",
+					chip->esr_avg);
+	} else {
+		qg_dbg(chip, QG_DEBUG_ESR,
+			"Not enough ESR samples, ESR not found\n");
+		chip->esr_avg = 0;
+	}
+
+	return 0;
+}
+
+static int qg_esr_estimate(struct qpnp_qg *chip)
+{
+	int rc, i, ibat;
+	u8 esr_done_count, reg0 = 0, reg1 = 0;
+	bool is_charging = false;
+
+	if (chip->dt.esr_disable)
+		return 0;
+
+	/*
+	 * Charge - enable ESR estimation only during fast-charging.
+	 * Discharge - enable ESR estimation only if enabled via DT.
+	 */
+	if (chip->charge_status == POWER_SUPPLY_STATUS_CHARGING &&
+			chip->charge_type != POWER_SUPPLY_CHARGE_TYPE_FAST) {
+		qg_dbg(chip, QG_DEBUG_ESR,
+			"Skip ESR, Not in fast-charge (CC)\n");
+		return 0;
+	}
+
+	if (chip->charge_status != POWER_SUPPLY_STATUS_CHARGING &&
+			!chip->dt.esr_discharge_enable)
+		return 0;
+
+	if (chip->batt_soc != INT_MIN && (chip->batt_soc <
+					chip->dt.esr_disable_soc)) {
+		qg_dbg(chip, QG_DEBUG_ESR,
+			"Skip ESR, batt-soc below %d\n",
+				chip->dt.esr_disable_soc);
+		return 0;
+	}
+
+	qg_dbg(chip, QG_DEBUG_ESR, "FIFO done count=%d ESR mod count=%d\n",
+			chip->fifo_done_count, qg_esr_mod_count);
+
+	if ((chip->fifo_done_count % qg_esr_mod_count) != 0)
+		return 0;
+
+	if (qg_esr_count > QG_MAX_ESR_COUNT)
+		qg_esr_count = QG_MAX_ESR_COUNT;
+
+	if (qg_esr_count < QG_MIN_ESR_COUNT)
+		qg_esr_count = QG_MIN_ESR_COUNT;
+
+	/* clear all data */
+	chip->esr_avg = 0;
+	memset(&chip->esr_data, 0, sizeof(chip->esr_data));
+
+	rc = qg_master_hold(chip, true);
+	if (rc < 0) {
+		pr_err("Failed to hold master, rc=%d\n", rc);
+		goto done;
+	}
+
+	for (i = 0; i < qg_esr_count; i++) {
+		/* Fire ESR measurement */
+		rc = qg_masked_write(chip,
+			chip->qg_base + QG_ESR_MEAS_TRIG_REG,
+			HW_ESR_MEAS_START_BIT, HW_ESR_MEAS_START_BIT);
 		if (rc < 0) {
-			pr_err("Failed to hold master, rc=%d\n", rc);
-			goto done;
+			pr_err("Failed to start ESR rc=%d\n", rc);
+			continue;
 		}
 
-		rc = qg_process_rt_fifo(chip);
-		if (rc < 0) {
-			pr_err("Failed to process FIFO real-time, rc=%d\n", rc);
-			goto done;
-		}
+		esr_done_count = reg0 = reg1 = 0;
+		do {
+			/* delay for ESR processing to complete */
+			msleep(50);
 
-		if (vbat_low) {
-			/* change FIFO length */
-			rc = qg_update_fifo_length(chip,
-					chip->dt.s2_vbat_low_fifo_length);
+			esr_done_count++;
+
+			rc = qg_read(chip,
+				chip->qg_base + QG_STATUS1_REG, &reg0, 1);
+			if (rc < 0)
+				continue;
+
+			rc = qg_read(chip,
+				chip->qg_base + QG_STATUS4_REG, &reg1, 1);
+			if (rc < 0)
+				continue;
+
+			/* check ESR-done status */
+			if (!(reg1 & ESR_MEAS_IN_PROGRESS_BIT) &&
+					(reg0 & ESR_MEAS_DONE_BIT)) {
+				qg_dbg(chip, QG_DEBUG_ESR,
+					"ESR measurement done %d count %d\n",
+						i, esr_done_count);
+				break;
+			}
+		} while (esr_done_count < MAX_ESR_RETRY_COUNT);
+
+		if (esr_done_count == MAX_ESR_RETRY_COUNT) {
+			pr_err("Failed to get ESR done for %d iteration\n", i);
+			continue;
+		} else {
+			/* found a valid ESR, read pre-post data */
+			rc = qg_read_raw_data(chip, QG_PRE_ESR_V_DATA0_REG,
+					&chip->esr_data[i].pre_esr_v);
 			if (rc < 0)
 				goto done;
 
-			qg_dbg(chip, QG_DEBUG_STATUS,
-				"FIFO length updated to %d vbat_low=%d\n",
-					chip->dt.s2_vbat_low_fifo_length,
-					vbat_low);
-		}
-
-		if (update_smb) {
-			rc = qg_masked_write(chip, chip->qg_base +
-				QG_MODE_CTL1_REG, PARALLEL_IBAT_SENSE_EN_BIT,
-				chip->parallel_enabled ?
-					PARALLEL_IBAT_SENSE_EN_BIT : 0);
-			if (rc < 0) {
-				pr_err("Failed to update SMB_EN, rc=%d\n", rc);
+			rc = qg_read_raw_data(chip, QG_PRE_ESR_I_DATA0_REG,
+					&chip->esr_data[i].pre_esr_i);
+			if (rc < 0)
 				goto done;
-			}
-			qg_dbg(chip, QG_DEBUG_STATUS, "Parallel SENSE %d\n",
-						chip->parallel_enabled);
+
+			rc = qg_read_raw_data(chip, QG_POST_ESR_V_DATA0_REG,
+					&chip->esr_data[i].post_esr_v);
+			if (rc < 0)
+				goto done;
+
+			rc = qg_read_raw_data(chip, QG_POST_ESR_I_DATA0_REG,
+					&chip->esr_data[i].post_esr_i);
+			if (rc < 0)
+				goto done;
+
+			chip->esr_data[i].pre_esr_v =
+				V_RAW_TO_UV(chip->esr_data[i].pre_esr_v);
+			ibat = sign_extend32(chip->esr_data[i].pre_esr_i, 15);
+			chip->esr_data[i].pre_esr_i = I_RAW_TO_UA(ibat);
+			chip->esr_data[i].post_esr_v =
+				V_RAW_TO_UV(chip->esr_data[i].post_esr_v);
+			ibat = sign_extend32(chip->esr_data[i].post_esr_i, 15);
+			chip->esr_data[i].post_esr_i = I_RAW_TO_UA(ibat);
+
+			chip->esr_data[i].valid = true;
+
+			if ((int)chip->esr_data[i].pre_esr_i < 0)
+				is_charging = true;
+
+			qg_dbg(chip, QG_DEBUG_ESR,
+				"ESR values for %d iteration pre_v=%d pre_i=%d post_v=%d post_i=%d\n",
+				i, chip->esr_data[i].pre_esr_v,
+				(int)chip->esr_data[i].pre_esr_i,
+				chip->esr_data[i].post_esr_v,
+				(int)chip->esr_data[i].post_esr_i);
 		}
-
-		rc = qg_master_hold(chip, false);
-		if (rc < 0) {
-			pr_err("Failed to release master, rc=%d\n", rc);
-			goto done;
-		}
-		/* FIFOs restarted */
-		chip->last_fifo_update_time = ktime_get();
-
-		/* signal the read thread */
-		chip->data_ready = true;
-		wake_up_interruptible(&chip->qg_wait_q);
-		chip->last_user_update_time = now;
-
-		/* vote to stay awake until userspace reads data */
-		vote(chip->awake_votable, FIFO_RT_DONE_VOTER, true, 0);
-	} else {
-		qg_dbg(chip, QG_DEBUG_FIFO, "FIFO processing too early time_delta=%lld\n",
-							time_delta);
+		/* delay before the next ESR measurement */
+		msleep(200);
 	}
+
+	rc = qg_process_esr_data(chip);
+	if (rc < 0)
+		pr_err("Failed to process ESR data rc=%d\n", rc);
+
+	rc = qg_master_hold(chip, false);
+	if (rc < 0) {
+		pr_err("Failed to release master, rc=%d\n", rc);
+		goto done;
+	}
+
+	if (chip->esr_avg) {
+		chip->kdata.param[QG_ESR].data = chip->esr_avg;
+		chip->kdata.param[QG_ESR].valid = true;
+		qg_dbg(chip, QG_DEBUG_ESR, "ESR_SW=%d during %s\n",
+			chip->esr_avg, is_charging ? "CHARGE" : "DISCHARGE");
+		qg_retrieve_esr_params(chip);
+	}
+
+	return 0;
 done:
 	qg_master_hold(chip, false);
 	return rc;
@@ -654,6 +1022,9 @@
 	if (chip->udata.param[QG_BATT_SOC].valid)
 		chip->batt_soc = chip->udata.param[QG_BATT_SOC].data;
 
+	if (chip->udata.param[QG_FULL_SOC].valid)
+		chip->full_soc = chip->udata.param[QG_FULL_SOC].data;
+
 	if (chip->udata.param[QG_SOC].valid) {
 		qg_dbg(chip, QG_DEBUG_SOC, "udata SOC=%d last SOC=%d\n",
 			chip->udata.param[QG_SOC].data, chip->catch_up_soc);
@@ -669,7 +1040,7 @@
 				chip->udata.param[QG_RBAT_MOHM].data;
 		chip->sdam_data[SDAM_VALID] = 1;
 
-		rc = qg_update_sdam_params(chip);
+		rc = qg_store_soc_params(chip);
 		if (rc < 0)
 			pr_err("Failed to update SDAM params, rc=%d\n", rc);
 	}
@@ -678,6 +1049,14 @@
 		chip->charge_counter_uah =
 			chip->udata.param[QG_CHARGE_COUNTER].data;
 
+	if (chip->udata.param[QG_ESR].valid)
+		chip->esr_last = chip->udata.param[QG_ESR].data;
+
+	if (!chip->dt.esr_disable)
+		qg_store_esr_params(chip);
+
+	qg_dbg(chip, QG_DEBUG_STATUS, "udata update: batt_soc=%d cc_soc=%d full_soc=%d qg_esr=%d\n",
+		chip->batt_soc, chip->cc_soc, chip->full_soc, chip->esr_last);
 	vote(chip->awake_votable, UDATA_READY_VOTER, false, 0);
 }
 
@@ -717,6 +1096,9 @@
 		goto done;
 	}
 
+	if (++chip->fifo_done_count == U32_MAX)
+		chip->fifo_done_count = 0;
+
 	rc = qg_vbat_thresholds_config(chip);
 	if (rc < 0)
 		pr_err("Failed to apply VBAT EMPTY config rc=%d\n", rc);
@@ -727,6 +1109,12 @@
 		goto done;
 	}
 
+	rc = qg_esr_estimate(chip);
+	if (rc < 0) {
+		pr_err("Failed to estimate ESR, rc=%d\n", rc);
+		goto done;
+	}
+
 	rc = get_fifo_done_time(chip, false, &hw_delta_ms);
 	if (rc < 0)
 		hw_delta_ms = 0;
@@ -794,7 +1182,7 @@
 	chip->sdam_data[SDAM_OCV_UV] = ocv_uv;
 	chip->sdam_data[SDAM_VALID] = 1;
 
-	qg_update_sdam_params(chip);
+	qg_store_soc_params(chip);
 
 	if (chip->qg_psy)
 		power_supply_changed(chip->qg_psy);
@@ -1195,6 +1583,87 @@
 	return 0;
 }
 
+static int qg_get_ttf_param(void *data, enum ttf_param param, int *val)
+{
+	union power_supply_propval prop = {0, };
+	struct qpnp_qg *chip = data;
+	int rc = 0;
+	int64_t temp = 0;
+
+	if (!chip)
+		return -ENODEV;
+
+	if (chip->battery_missing || !chip->profile_loaded)
+		return -EPERM;
+
+	switch (param) {
+	case TTF_MSOC:
+		rc = qg_get_battery_capacity(chip, val);
+		break;
+	case TTF_VBAT:
+		rc = qg_get_battery_voltage(chip, val);
+		break;
+	case TTF_IBAT:
+		rc = qg_get_battery_current(chip, val);
+		break;
+	case TTF_FCC:
+		if (chip->qg_psy) {
+			rc = power_supply_get_property(chip->qg_psy,
+				POWER_SUPPLY_PROP_CHARGE_FULL, &prop);
+			if (rc >= 0) {
+				temp = div64_u64(prop.intval, 1000);
+				*val  = div64_u64(chip->full_soc * temp,
+						QG_SOC_FULL);
+			}
+		}
+		break;
+	case TTF_MODE:
+		*val = TTF_MODE_NORMAL;
+		break;
+	case TTF_ITERM:
+		if (chip->chg_iterm_ma == INT_MIN)
+			*val = 0;
+		else
+			*val = chip->chg_iterm_ma;
+		break;
+	case TTF_RBATT:
+		rc = qg_sdam_read(SDAM_RBAT_MOHM, val);
+		if (!rc)
+			*val *= 1000;
+		break;
+	case TTF_VFLOAT:
+		*val = chip->bp.float_volt_uv;
+		break;
+	case TTF_CHG_TYPE:
+		*val = chip->charge_type;
+		break;
+	case TTF_CHG_STATUS:
+		*val = chip->charge_status;
+		break;
+	default:
+		pr_err("Unsupported property %d\n", param);
+		rc = -EINVAL;
+		break;
+	}
+
+	return rc;
+}
+
+static int qg_ttf_awake_voter(void *data, bool val)
+{
+	struct qpnp_qg *chip = data;
+
+	if (!chip)
+		return -ENODEV;
+
+	if (chip->battery_missing || !chip->profile_loaded)
+		return -EPERM;
+
+	vote(chip->awake_votable, TTF_AWAKE_VOTER, val, 0);
+
+	return 0;
+}
+
 static int qg_psy_set_property(struct power_supply *psy,
 			       enum power_supply_property psp,
 			       const union power_supply_propval *pval)
@@ -1265,6 +1734,9 @@
 		if (!rc)
 			pval->intval *= 1000;
 		break;
+	case POWER_SUPPLY_PROP_RESISTANCE_NOW:
+		pval->intval = chip->esr_last;
+		break;
 	case POWER_SUPPLY_PROP_RESISTANCE_CAPACITIVE:
 		pval->intval = chip->dt.rbat_conn_mohm;
 		break;
@@ -1307,6 +1779,12 @@
 	case POWER_SUPPLY_PROP_CYCLE_COUNT:
 		rc = get_cycle_count(chip->counter, &pval->intval);
 		break;
+	case POWER_SUPPLY_PROP_TIME_TO_FULL_AVG:
+		rc = ttf_get_time_to_full(chip->ttf, &pval->intval);
+		break;
+	case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG:
+		rc = ttf_get_time_to_empty(chip->ttf, &pval->intval);
+		break;
 	default:
 		pr_debug("Unsupported property %d\n", psp);
 		break;
@@ -1336,6 +1814,7 @@
 	POWER_SUPPLY_PROP_CHARGE_COUNTER,
 	POWER_SUPPLY_PROP_RESISTANCE,
 	POWER_SUPPLY_PROP_RESISTANCE_ID,
+	POWER_SUPPLY_PROP_RESISTANCE_NOW,
 	POWER_SUPPLY_PROP_RESISTANCE_CAPACITIVE,
 	POWER_SUPPLY_PROP_DEBUG_BATTERY,
 	POWER_SUPPLY_PROP_BATTERY_TYPE,
@@ -1347,6 +1826,8 @@
 	POWER_SUPPLY_PROP_CYCLE_COUNTS,
 	POWER_SUPPLY_PROP_CHARGE_FULL,
 	POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
+	POWER_SUPPLY_PROP_TIME_TO_FULL_AVG,
+	POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG,
 };
 
 static const struct power_supply_desc qg_psy_desc = {
@@ -1481,6 +1962,13 @@
 	}
 
 	rc = power_supply_get_property(chip->batt_psy,
+			POWER_SUPPLY_PROP_CHARGE_TYPE, &prop);
+	if (rc < 0)
+		pr_err("Failed to get charge-type, rc=%d\n", rc);
+	else
+		chip->charge_type = prop.intval;
+
+	rc = power_supply_get_property(chip->batt_psy,
 			POWER_SUPPLY_PROP_STATUS, &prop);
 	if (rc < 0)
 		pr_err("Failed to get charger status, rc=%d\n", rc);
@@ -1526,6 +2014,8 @@
 	rc = qg_charge_full_update(chip);
 	if (rc < 0)
 		pr_err("Failed in charge_full_update, rc=%d\n", rc);
+
+	ttf_update(chip->ttf, chip->usb_present);
 out:
 	pm_relax(chip->dev);
 }
@@ -1996,7 +2486,7 @@
 	if (rc < 0)
 		pr_err("Failed to update MSOC register rc=%d\n", rc);
 
-	rc = qg_update_sdam_params(chip);
+	rc = qg_store_soc_params(chip);
 	if (rc < 0)
 		pr_err("Failed to update sdam params rc=%d\n", rc);
 
@@ -2224,6 +2714,10 @@
 				QG_INIT_STATE_IRQ_DISABLE, true, 0);
 	}
 
+	/* restore ESR data */
+	if (!chip->dt.esr_disable)
+		qg_retrieve_esr_params(chip);
+
 	return 0;
 }
 
@@ -2298,10 +2792,12 @@
 	return 0;
 }
 
+#define QG_TTF_ITERM_DELTA_MA		1
 static int qg_alg_init(struct qpnp_qg *chip)
 {
 	struct cycle_counter *counter;
 	struct cap_learning *cl;
+	struct ttf *ttf;
 	struct device_node *node = chip->dev->of_node;
 	int rc;
 
@@ -2324,6 +2820,28 @@
 
 	chip->counter = counter;
 
+	ttf = devm_kzalloc(chip->dev, sizeof(*ttf), GFP_KERNEL);
+	if (!ttf)
+		return -ENOMEM;
+
+	ttf->get_ttf_param = qg_get_ttf_param;
+	ttf->awake_voter = qg_ttf_awake_voter;
+	ttf->iterm_delta = QG_TTF_ITERM_DELTA_MA;
+	ttf->data = chip;
+
+	rc = ttf_tte_init(ttf);
+	if (rc < 0) {
+		dev_err(chip->dev, "Error in initializing ttf, rc:%d\n",
+			rc);
+		ttf->data = NULL;
+		counter->data = NULL;
+		devm_kfree(chip->dev, ttf);
+		devm_kfree(chip->dev, counter);
+		return rc;
+	}
+
+	chip->ttf = ttf;
+
 	chip->dt.cl_disable = of_property_read_bool(node,
 					"qcom,cl-disable");
 
@@ -2348,6 +2866,7 @@
 		counter->data = NULL;
 		cl->data = NULL;
 		devm_kfree(chip->dev, counter);
+		devm_kfree(chip->dev, ttf);
 		devm_kfree(chip->dev, cl);
 		return rc;
 	}
@@ -2373,10 +2892,13 @@
 #define DEFAULT_CL_MAX_START_SOC	15
 #define DEFAULT_CL_MIN_TEMP_DECIDEGC	150
 #define DEFAULT_CL_MAX_TEMP_DECIDEGC	500
-#define DEFAULT_CL_MAX_INC_DECIPERC	5
-#define DEFAULT_CL_MAX_DEC_DECIPERC	100
-#define DEFAULT_CL_MIN_LIM_DECIPERC	0
-#define DEFAULT_CL_MAX_LIM_DECIPERC	0
+#define DEFAULT_CL_MAX_INC_DECIPERC	10
+#define DEFAULT_CL_MAX_DEC_DECIPERC	20
+#define DEFAULT_CL_MIN_LIM_DECIPERC	500
+#define DEFAULT_CL_MAX_LIM_DECIPERC	100
+#define DEFAULT_ESR_QUAL_CURRENT_UA	130000
+#define DEFAULT_ESR_QUAL_VBAT_UV	7000
+#define DEFAULT_ESR_DISABLE_SOC		1000
 static int qg_parse_dt(struct qpnp_qg *chip)
 {
 	int rc = 0;
@@ -2570,6 +3092,31 @@
 	else
 		chip->dt.rbat_conn_mohm = temp;
 
+	/* esr */
+	chip->dt.esr_disable = of_property_read_bool(node,
+					"qcom,esr-disable");
+
+	chip->dt.esr_discharge_enable = of_property_read_bool(node,
+					"qcom,esr-discharge-enable");
+
+	rc = of_property_read_u32(node, "qcom,esr-qual-current-ua", &temp);
+	if (rc < 0)
+		chip->dt.esr_qual_i_ua = DEFAULT_ESR_QUAL_CURRENT_UA;
+	else
+		chip->dt.esr_qual_i_ua = temp;
+
+	rc = of_property_read_u32(node, "qcom,esr-qual-vbatt-uv", &temp);
+	if (rc < 0)
+		chip->dt.esr_qual_v_uv = DEFAULT_ESR_QUAL_VBAT_UV;
+	else
+		chip->dt.esr_qual_v_uv = temp;
+
+	rc = of_property_read_u32(node, "qcom,esr-disable-soc", &temp);
+	if (rc < 0)
+		chip->dt.esr_disable_soc = DEFAULT_ESR_DISABLE_SOC;
+	else
+		chip->dt.esr_disable_soc = temp * 100;
+
 	/* Capacity learning params*/
 	if (!chip->dt.cl_disable) {
 		chip->dt.cl_feedback_on = of_property_read_bool(node,
@@ -2646,6 +3193,7 @@
 	if (!chip->profile_loaded)
 		return 0;
 
+	cancel_delayed_work_sync(&chip->ttf->ttf_work);
 	/* disable GOOD_OCV IRQ in sleep */
 	vote(chip->good_ocv_irq_disable_votable,
 			QG_INIT_STATE_IRQ_DISABLE, true, 0);
@@ -2778,6 +3326,8 @@
 		chip->suspend_data = false;
 	}
 
+	schedule_delayed_work(&chip->ttf->ttf_work, 0);
+
 	return rc;
 }
 
@@ -2855,6 +3405,8 @@
 	chip->maint_soc = -EINVAL;
 	chip->batt_soc = INT_MIN;
 	chip->cc_soc = INT_MIN;
+	chip->full_soc = QG_SOC_FULL;
+	chip->chg_iterm_ma = INT_MIN;
 
 	rc = qg_alg_init(chip);
 	if (rc < 0) {
@@ -2920,6 +3472,7 @@
 			pr_err("Error in restoring cycle_count, rc=%d\n", rc);
 			return rc;
 		}
+		schedule_delayed_work(&chip->ttf->ttf_work, 10000);
 	}
 
 	rc = qg_determine_pon_soc(chip);
diff --git a/drivers/power/supply/qcom/qpnp-smb2.c b/drivers/power/supply/qcom/qpnp-smb2.c
index 5df241f..617ef62 100644
--- a/drivers/power/supply/qcom/qpnp-smb2.c
+++ b/drivers/power/supply/qcom/qpnp-smb2.c
@@ -331,6 +331,9 @@
 	if (rc < 0)
 		chg->otg_delay_ms = OTG_DEFAULT_DEGLITCH_TIME_MS;
 
+	chg->disable_stat_sw_override = of_property_read_bool(node,
+					"qcom,disable-stat-sw-override");
+
 	return 0;
 }
 
@@ -1837,6 +1840,16 @@
 		}
 	}
 
+	if (chg->disable_stat_sw_override) {
+		rc = smblib_masked_write(chg, STAT_CFG_REG,
+				STAT_SW_OVERRIDE_CFG_BIT, 0);
+		if (rc < 0) {
+			dev_err(chg->dev, "Couldn't disable STAT SW override rc=%d\n",
+				rc);
+			return rc;
+		}
+	}
+
 	return rc;
 }
 
diff --git a/drivers/power/supply/qcom/smb-lib.h b/drivers/power/supply/qcom/smb-lib.h
index 3129861..097b24a 100644
--- a/drivers/power/supply/qcom/smb-lib.h
+++ b/drivers/power/supply/qcom/smb-lib.h
@@ -353,6 +353,7 @@
 	bool			use_extcon;
 	bool			otg_present;
 	bool			is_audio_adapter;
+	bool			disable_stat_sw_override;
 
 	/* workaround flag */
 	u32			wa_flags;
diff --git a/drivers/power/supply/qcom/smb5-lib.c b/drivers/power/supply/qcom/smb5-lib.c
index 9f39561..4bf07a1 100644
--- a/drivers/power/supply/qcom/smb5-lib.c
+++ b/drivers/power/supply/qcom/smb5-lib.c
@@ -894,9 +894,10 @@
 		goto set_mode;
 
 	/* configure current */
-	if (((chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT)
-		|| (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB))
-		&& (chg->real_charger_type == POWER_SUPPLY_TYPE_USB)) {
+	if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB
+		&& (chg->typec_legacy
+		|| chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT
+		|| chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB)) {
 		rc = set_sdp_current(chg, icl_ua);
 		if (rc < 0) {
 			smblib_err(chg, "Couldn't set SDP ICL rc=%d\n", rc);
@@ -2789,6 +2790,8 @@
 		rc = smblib_request_dpdm(chg, false);
 		if (rc < 0)
 			smblib_err(chg, "Couldn't disable DPDM rc=%d\n", rc);
+
+		smblib_update_usb_type(chg);
 	}
 
 	if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB)
diff --git a/drivers/pwm/pwm-qti-lpg.c b/drivers/pwm/pwm-qti-lpg.c
index 31f5204..d24bef1 100644
--- a/drivers/pwm/pwm-qti-lpg.c
+++ b/drivers/pwm/pwm-qti-lpg.c
@@ -19,10 +19,12 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/mutex.h>
+#include <linux/nvmem-consumer.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/platform_device.h>
 #include <linux/pwm.h>
+#include <linux/qpnp/qpnp-pbs.h>
 #include <linux/regmap.h>
 #include <linux/slab.h>
 #include <linux/types.h>
@@ -105,6 +107,34 @@
 #define LPG_LUT_VALUE_MSB_MASK		BIT(0)
 #define LPG_LUT_COUNT_MAX		47
 
+/* LPG config settings in SDAM */
+#define SDAM_REG_PBS_SEQ_EN			0x42
+#define PBS_SW_TRG_BIT				BIT(0)
+
+#define SDAM_REG_RAMP_STEP_DURATION		0x47
+
+#define SDAM_LUT_EN_OFFSET			0x0
+#define SDAM_PATTERN_CONFIG_OFFSET		0x1
+#define SDAM_END_INDEX_OFFSET			0x3
+#define SDAM_START_INDEX_OFFSET			0x4
+#define SDAM_PBS_SCRATCH_LUT_COUNTER_OFFSET	0x6
+
+/* SDAM_REG_LUT_EN */
+#define SDAM_LUT_EN_BIT				BIT(0)
+
+/* SDAM_REG_PATTERN_CONFIG */
+#define SDAM_PATTERN_LOOP_ENABLE		BIT(3)
+#define SDAM_PATTERN_RAMP_TOGGLE		BIT(2)
+#define SDAM_PATTERN_EN_PAUSE_END		BIT(1)
+#define SDAM_PATTERN_EN_PAUSE_START		BIT(0)
+
+/* SDAM_REG_PAUSE_MULTIPLIER */
+#define SDAM_PAUSE_START_SHIFT			4
+#define SDAM_PAUSE_START_MASK			GENMASK(7, 4)
+#define SDAM_PAUSE_END_MASK			GENMASK(3, 0)
+
+#define SDAM_LUT_COUNT_MAX			64
+
 enum lpg_src {
 	LUT_PATTERN = 0,
 	PWM_VALUE,
@@ -151,6 +181,7 @@
 	u32				lpg_idx;
 	u32				reg_base;
 	u32				max_pattern_length;
+	u32				lpg_sdam_base;
 	u8				src_sel;
 	u8				subtype;
 	bool				lut_written;
@@ -165,7 +196,11 @@
 	struct qpnp_lpg_channel	*lpgs;
 	struct qpnp_lpg_lut	*lut;
 	struct mutex		bus_lock;
+	struct nvmem_device	*sdam_nvmem;
+	struct device_node	*pbs_dev_node;
 	u32			num_lpgs;
+	unsigned long		pbs_en_bitmap;
+	bool			use_sdam;
 };
 
 static int qpnp_lpg_read(struct qpnp_lpg_channel *lpg, u16 addr, u8 *val)
@@ -192,7 +227,7 @@
 	mutex_lock(&lpg->chip->bus_lock);
 	rc = regmap_write(lpg->chip->regmap, lpg->reg_base + addr, val);
 	if (rc < 0)
-		dev_err(lpg->chip->dev, "Write addr 0x%x with value %d failed, rc=%d\n",
+		dev_err(lpg->chip->dev, "Write addr 0x%x with value 0x%x failed, rc=%d\n",
 				lpg->reg_base + addr, val, rc);
 	mutex_unlock(&lpg->chip->bus_lock);
 
@@ -245,6 +280,90 @@
 	return rc;
 }
 
+static int qpnp_sdam_write(struct qpnp_lpg_chip *chip, u16 addr, u8 val)
+{
+	int rc;
+
+	mutex_lock(&chip->bus_lock);
+	rc = nvmem_device_write(chip->sdam_nvmem, addr, 1, &val);
+	if (rc < 0)
+		dev_err(chip->dev, "write SDAM add 0x%x failed, rc=%d\n",
+				addr, rc);
+
+	mutex_unlock(&chip->bus_lock);
+
+	return rc > 0 ? 0 : rc;
+}
+
+static int qpnp_lpg_sdam_write(struct qpnp_lpg_channel *lpg, u16 addr, u8 val)
+{
+	struct qpnp_lpg_chip *chip = lpg->chip;
+	int rc;
+
+	mutex_lock(&chip->bus_lock);
+	rc = nvmem_device_write(chip->sdam_nvmem,
+			lpg->lpg_sdam_base + addr, 1, &val);
+	if (rc < 0)
+		dev_err(chip->dev, "write SDAM add 0x%x failed, rc=%d\n",
+				lpg->lpg_sdam_base + addr, rc);
+
+	mutex_unlock(&chip->bus_lock);
+
+	return rc > 0 ? 0 : rc;
+}
+
+static int qpnp_lpg_sdam_masked_write(struct qpnp_lpg_channel *lpg,
+					u16 addr, u8 mask, u8 val)
+{
+	int rc;
+	u8 tmp;
+	struct qpnp_lpg_chip *chip = lpg->chip;
+
+	mutex_lock(&chip->bus_lock);
+
+	rc = nvmem_device_read(chip->sdam_nvmem,
+			lpg->lpg_sdam_base + addr, 1, &tmp);
+	if (rc < 0) {
+		dev_err(chip->dev, "Read SDAM addr %d failed, rc=%d\n",
+				lpg->lpg_sdam_base + addr, rc);
+		goto unlock;
+	}
+
+	tmp = tmp & ~mask;
+	tmp |= val & mask;
+	rc = nvmem_device_write(chip->sdam_nvmem,
+			lpg->lpg_sdam_base + addr, 1, &tmp);
+	if (rc < 0)
+		dev_err(chip->dev, "write SDAM addr %d failed, rc=%d\n",
+				lpg->lpg_sdam_base + addr, rc);
+
+unlock:
+	mutex_unlock(&chip->bus_lock);
+
+	return rc > 0 ? 0 : rc;
+}
+
+static int qpnp_lut_sdam_write(struct qpnp_lpg_lut *lut,
+		u16 addr, u8 *val, size_t length)
+{
+	struct qpnp_lpg_chip *chip = lut->chip;
+	int rc;
+
+	if (addr >= SDAM_LUT_COUNT_MAX)
+		return -EINVAL;
+
+	mutex_lock(&chip->bus_lock);
+	rc = nvmem_device_write(chip->sdam_nvmem,
+			lut->reg_base + addr, length, val);
+	if (rc < 0)
+		dev_err(chip->dev, "write SDAM addr %d failed, rc=%d\n",
+				lut->reg_base + addr, rc);
+
+	mutex_unlock(&chip->bus_lock);
+
+	return rc > 0 ? 0 : rc;
+}
+
 static struct qpnp_lpg_channel *pwm_dev_to_qpnp_lpg(struct pwm_chip *pwm_chip,
 				struct pwm_device *pwm) {
 
@@ -365,14 +484,111 @@
 	return rc;
 }
 
-static int qpnp_lpg_set_lut_pattern(struct qpnp_lpg_channel *lpg,
+static int qpnp_lpg_set_sdam_lut_pattern(struct qpnp_lpg_channel *lpg,
 		unsigned int *pattern, unsigned int length)
 {
 	struct qpnp_lpg_lut *lut = lpg->chip->lut;
 	int i, rc = 0;
-	u16 full_duty_value, pwm_values[LPG_LUT_COUNT_MAX + 1] = {0};
+	u8 val[SDAM_LUT_COUNT_MAX + 1], addr;
+
+	if (length > lpg->max_pattern_length) {
+		dev_err(lpg->chip->dev, "new pattern length (%d) larger than predefined (%d)\n",
+				length, lpg->max_pattern_length);
+		return -EINVAL;
+	}
+
+	/* Program LUT pattern */
+	mutex_lock(&lut->lock);
+	addr = lpg->ramp_config.lo_idx;
+	for (i = 0; i < length; i++)
+		val[i] = pattern[i] * 255 / 100;
+
+	rc = qpnp_lut_sdam_write(lut, addr, val, length);
+	if (rc < 0) {
+		dev_err(lpg->chip->dev, "Write pattern in SDAM failed, rc=%d",
+				rc);
+		goto unlock;
+	}
+
+	lpg->ramp_config.pattern_length = length;
+unlock:
+	mutex_unlock(&lut->lock);
+
+	return rc;
+}
+
+static int qpnp_lpg_set_sdam_ramp_config(struct qpnp_lpg_channel *lpg)
+{
+	struct lpg_ramp_config *ramp = &lpg->ramp_config;
+	u8 addr, mask, val;
+	int rc = 0;
+
+	/* clear PBS scatchpad register */
+	val = 0;
+	rc = qpnp_lpg_sdam_write(lpg,
+			SDAM_PBS_SCRATCH_LUT_COUNTER_OFFSET, val);
+	if (rc < 0) {
+		dev_err(lpg->chip->dev, "Write SDAM_PBS_SCRATCH_LUT_COUNTER_OFFSET failed, rc=%d\n",
+				rc);
+		return rc;
+	}
+
+	/* Set ramp step duration, one WAIT_TICK is 7.8ms */
+	val = (ramp->step_ms * 1000 / 7800) & 0xff;
+	if (val > 0)
+		val--;
+	addr = SDAM_REG_RAMP_STEP_DURATION;
+	rc = qpnp_sdam_write(lpg->chip, addr, val);
+	if (rc < 0) {
+		dev_err(lpg->chip->dev, "Write SDAM_REG_RAMP_STEP_DURATION failed, rc=%d\n",
+				rc);
+		return rc;
+	}
+
+	/* Set hi_idx and lo_idx */
+	rc = qpnp_lpg_sdam_write(lpg, SDAM_END_INDEX_OFFSET, ramp->hi_idx);
+	if (rc < 0) {
+		dev_err(lpg->chip->dev, "Write SDAM_REG_END_INDEX failed, rc=%d\n",
+					rc);
+		return rc;
+	}
+
+	rc = qpnp_lpg_sdam_write(lpg, SDAM_START_INDEX_OFFSET,
+						ramp->lo_idx);
+	if (rc < 0) {
+		dev_err(lpg->chip->dev, "Write SDAM_REG_START_INDEX failed, rc=%d\n",
+					rc);
+		return rc;
+	}
+
+	/* Set LPG_PATTERN_CONFIG */
+	addr = SDAM_PATTERN_CONFIG_OFFSET;
+	mask = SDAM_PATTERN_LOOP_ENABLE;
+	val = 0;
+	if (ramp->pattern_repeat)
+		val |= SDAM_PATTERN_LOOP_ENABLE;
+
+	rc = qpnp_lpg_sdam_masked_write(lpg, addr, mask, val);
+	if (rc < 0) {
+		dev_err(lpg->chip->dev, "Write SDAM_REG_PATTERN_CONFIG failed, rc=%d\n",
+					rc);
+		return rc;
+	}
+
+	return rc;
+}
+
+static int qpnp_lpg_set_lut_pattern(struct qpnp_lpg_channel *lpg,
+		unsigned int *pattern, unsigned int length)
+{
+	struct qpnp_lpg_lut *lut = lpg->chip->lut;
+	u16 full_duty_value, pwm_values[SDAM_LUT_COUNT_MAX + 1] = {0};
+	int i, rc = 0;
 	u8 lsb, msb, addr;
 
+	if (lpg->chip->use_sdam)
+		return qpnp_lpg_set_sdam_lut_pattern(lpg, pattern, length);
+
 	if (length > lpg->max_pattern_length) {
 		dev_err(lpg->chip->dev, "new pattern length (%d) larger than predefined (%d)\n",
 				length, lpg->max_pattern_length);
@@ -426,6 +642,9 @@
 	u8 lsb, msb, addr, mask, val;
 	int rc = 0;
 
+	if (lpg->chip->use_sdam)
+		return qpnp_lpg_set_sdam_ramp_config(lpg);
+
 	/* Set ramp step duration */
 	lsb = ramp->step_ms & 0xff;
 	msb = ramp->step_ms >> 8;
@@ -507,6 +726,8 @@
 static void __qpnp_lpg_calc_pwm_period(int period_ns,
 			struct lpg_pwm_config *pwm_config)
 {
+	struct qpnp_lpg_channel *lpg = container_of(pwm_config,
+			struct qpnp_lpg_channel, pwm_config);
 	struct lpg_pwm_config configs[NUM_PWM_SIZE];
 	int i, j, m, n;
 	int tmp1, tmp2;
@@ -522,7 +743,12 @@
 	 *
 	 * Searching the closest settings for the requested PWM period.
 	 */
-	for (n = 0; n < ARRAY_SIZE(pwm_size); n++) {
+	if (lpg->chip->use_sdam)
+		/* SDAM pattern control can only use 9 bit resolution */
+		n = 1;
+	else
+		n = 0;
+	for (; n < ARRAY_SIZE(pwm_size); n++) {
 		pwm_clk_period_ns = period_ns >> pwm_size[n];
 		for (i = ARRAY_SIZE(clk_freq_hz) - 1; i >= 0; i--) {
 			for (j = 0; j < ARRAY_SIZE(clk_prediv); j++) {
@@ -654,6 +880,45 @@
 	return rc;
 }
 
+static int qpnp_lpg_pbs_trigger_enable(struct qpnp_lpg_channel *lpg, bool en)
+{
+	struct qpnp_lpg_chip *chip = lpg->chip;
+	int rc = 0;
+
+	if (en) {
+		if (chip->pbs_en_bitmap == 0) {
+			rc = qpnp_sdam_write(chip, SDAM_REG_PBS_SEQ_EN,
+					PBS_SW_TRG_BIT);
+			if (rc < 0) {
+				dev_err(chip->dev, "Write SDAM_REG_PBS_SEQ_EN failed, rc=%d\n",
+						rc);
+				return rc;
+			}
+
+			rc = qpnp_pbs_trigger_event(chip->pbs_dev_node,
+					PBS_SW_TRG_BIT);
+			if (rc < 0) {
+				dev_err(chip->dev, "Failed to trigger PBS, rc=%d\n",
+						rc);
+				return rc;
+			}
+		}
+		set_bit(lpg->lpg_idx, &chip->pbs_en_bitmap);
+	} else {
+		clear_bit(lpg->lpg_idx, &chip->pbs_en_bitmap);
+		if (chip->pbs_en_bitmap == 0) {
+			rc = qpnp_sdam_write(chip, SDAM_REG_PBS_SEQ_EN, 0);
+			if (rc < 0) {
+				dev_err(chip->dev, "Write SDAM_REG_PBS_SEQ_EN failed, rc=%d\n",
+						rc);
+				return rc;
+			}
+		}
+	}
+
+	return rc;
+}
+
 static int qpnp_lpg_pwm_src_enable(struct qpnp_lpg_channel *lpg, bool en)
 {
 	struct qpnp_lpg_chip *chip = lpg->chip;
@@ -665,7 +930,7 @@
 					LPG_EN_RAMP_GEN_MASK;
 	val = lpg->src_sel << LPG_PWM_SRC_SELECT_SHIFT;
 
-	if (lpg->src_sel == LUT_PATTERN)
+	if (lpg->src_sel == LUT_PATTERN && !chip->use_sdam)
 		val |= 1 << LPG_EN_RAMP_GEN_SHIFT;
 
 	if (en)
@@ -678,6 +943,27 @@
 		return rc;
 	}
 
+	if (chip->use_sdam) {
+		if (lpg->src_sel == LUT_PATTERN && en) {
+			val = SDAM_LUT_EN_BIT;
+			en = true;
+		} else {
+			val = 0;
+			en = false;
+		}
+
+		rc = qpnp_lpg_sdam_write(lpg, SDAM_LUT_EN_OFFSET, val);
+		if (rc < 0) {
+			dev_err(chip->dev, "Write SDAM_REG_LUT_EN failed, rc=%d\n",
+					rc);
+			return rc;
+		}
+
+		qpnp_lpg_pbs_trigger_enable(lpg, en);
+
+		return rc;
+	}
+
 	if (lpg->src_sel == LUT_PATTERN && en) {
 		mutex_lock(&lut->lock);
 		val = 1 << lpg->lpg_idx;
@@ -697,6 +983,7 @@
 	struct qpnp_lpg_channel *lpg;
 	enum lpg_src src_sel;
 	int rc;
+	bool is_enabled;
 
 	lpg = pwm_dev_to_qpnp_lpg(pwm_chip, pwm);
 	if (lpg == NULL) {
@@ -714,6 +1001,23 @@
 	if (src_sel == lpg->src_sel)
 		return 0;
 
+	is_enabled = pwm_is_enabled(pwm);
+	if (is_enabled) {
+		/*
+		 * Disable the channel first then enable it later to make
+		 * sure the output type is changed successfully. This is
+		 * especially useful in SDAM use case to stop the PBS
+		 * sequence when changing the PWM output type from
+		 * MODULATED to FIXED.
+		 */
+		rc = qpnp_lpg_pwm_src_enable(lpg, false);
+		if (rc < 0) {
+			dev_err(pwm_chip->dev, "Enable PWM output failed for channel %d, rc=%d\n",
+					lpg->lpg_idx, rc);
+			return rc;
+		}
+	}
+
 	if (src_sel == LUT_PATTERN) {
 		/* program LUT if it's never been programmed */
 		if (!lpg->lut_written) {
@@ -738,7 +1042,14 @@
 
 	lpg->src_sel = src_sel;
 
-	if (pwm_is_enabled(pwm)) {
+	if (is_enabled) {
+		rc = qpnp_lpg_set_pwm_config(lpg);
+		if (rc < 0) {
+			dev_err(pwm_chip->dev, "Config PWM failed for channel %d, rc=%d\n",
+							lpg->lpg_idx, rc);
+			return rc;
+		}
+
 		rc = qpnp_lpg_pwm_src_enable(lpg, true);
 		if (rc < 0) {
 			dev_err(pwm_chip->dev, "Enable PWM output failed for channel %d, rc=%d\n",
@@ -979,7 +1290,7 @@
 	struct qpnp_lpg_channel *lpg;
 	struct lpg_ramp_config *ramp;
 	int rc = 0, i;
-	u32 base, length, lpg_chan_id, tmp;
+	u32 base, length, lpg_chan_id, tmp, max_count;
 	const __be32 *addr;
 
 	addr = of_get_address(chip->dev->of_node, 0, NULL, NULL);
@@ -1010,18 +1321,47 @@
 		}
 	}
 
-	addr = of_get_address(chip->dev->of_node, 1, NULL, NULL);
-	if (!addr) {
-		pr_debug("NO LUT address assigned\n");
-		return 0;
-	}
-
 	chip->lut = devm_kmalloc(chip->dev, sizeof(*chip->lut), GFP_KERNEL);
 	if (!chip->lut)
 		return -ENOMEM;
 
+	chip->sdam_nvmem = devm_nvmem_device_get(chip->dev, "ppg_sdam");
+	if (IS_ERR_OR_NULL(chip->sdam_nvmem)) {
+		if (PTR_ERR(chip->sdam_nvmem) == -EPROBE_DEFER)
+			return -EPROBE_DEFER;
+
+		addr = of_get_address(chip->dev->of_node, 1, NULL, NULL);
+		if (!addr) {
+			pr_debug("NO LUT address assigned\n");
+			devm_kfree(chip->dev, chip->lut);
+			chip->lut = NULL;
+			return 0;
+		}
+
+		chip->lut->reg_base = be32_to_cpu(*addr);
+		max_count = LPG_LUT_COUNT_MAX;
+	} else {
+		chip->use_sdam = true;
+		chip->pbs_dev_node = of_parse_phandle(chip->dev->of_node,
+				"qcom,pbs-client", 0);
+		if (!chip->pbs_dev_node) {
+			dev_err(chip->dev, "Missing qcom,pbs-client property\n");
+			return -EINVAL;
+		}
+
+		rc = of_property_read_u32(chip->dev->of_node,
+				"qcom,lut-sdam-base",
+				&chip->lut->reg_base);
+		if (rc < 0) {
+			dev_err(chip->dev, "Read qcom,lut-sdam-base failed, rc=%d\n",
+					rc);
+			return rc;
+		}
+
+		max_count = SDAM_LUT_COUNT_MAX;
+	}
+
 	chip->lut->chip = chip;
-	chip->lut->reg_base = be32_to_cpu(*addr);
 	mutex_init(&chip->lut->lock);
 
 	rc = of_property_count_elems_of_size(chip->dev->of_node,
@@ -1033,13 +1373,13 @@
 	}
 
 	length = rc;
-	if (length > LPG_LUT_COUNT_MAX) {
+	if (length > max_count) {
 		dev_err(chip->dev, "qcom,lut-patterns length %d exceed max %d\n",
-				length, LPG_LUT_COUNT_MAX);
+				length, max_count);
 		return -EINVAL;
 	}
 
-	chip->lut->pattern = devm_kcalloc(chip->dev, LPG_LUT_COUNT_MAX,
+	chip->lut->pattern = devm_kcalloc(chip->dev, max_count,
 			sizeof(*chip->lut->pattern), GFP_KERNEL);
 	if (!chip->lut->pattern)
 		return -ENOMEM;
@@ -1066,12 +1406,24 @@
 			return rc;
 		}
 
-		if (lpg_chan_id > chip->num_lpgs) {
+		if (lpg_chan_id < 1 || lpg_chan_id > chip->num_lpgs) {
 			dev_err(chip->dev, "lpg-chann-id %d is out of range 1~%d\n",
 					lpg_chan_id, chip->num_lpgs);
 			return -EINVAL;
 		}
 
+		if (chip->use_sdam) {
+			rc = of_property_read_u32(child,
+					"qcom,lpg-sdam-base",
+					&tmp);
+			if (rc < 0) {
+				dev_err(chip->dev, "get qcom,lpg-sdam-base failed for lpg%d, rc=%d\n",
+						lpg_chan_id, rc);
+				return rc;
+			}
+			chip->lpgs[lpg_chan_id - 1].lpg_sdam_base = tmp;
+		}
+
 		/* lpg channel id is indexed from 1 in hardware */
 		lpg = &chip->lpgs[lpg_chan_id - 1];
 		ramp = &lpg->ramp_config;
@@ -1091,9 +1443,9 @@
 			return rc;
 		}
 		ramp->lo_idx = (u8)tmp;
-		if (ramp->lo_idx >= LPG_LUT_COUNT_MAX) {
+		if (ramp->lo_idx >= max_count) {
 			dev_err(chip->dev, "qcom,ramp-low-index should less than max %d\n",
-					LPG_LUT_COUNT_MAX);
+						max_count);
 			return -EINVAL;
 		}
 
@@ -1105,14 +1457,14 @@
 		}
 		ramp->hi_idx = (u8)tmp;
 
-		if (ramp->hi_idx > LPG_LUT_COUNT_MAX) {
+		if (ramp->hi_idx > max_count) {
 			dev_err(chip->dev, "qcom,ramp-high-index shouldn't exceed max %d\n",
-						LPG_LUT_COUNT_MAX);
+						max_count);
 			return -EINVAL;
 		}
 
-		if (ramp->hi_idx <= ramp->lo_idx) {
-			dev_err(chip->dev, "high-index(%d) should be larger than low-index(%d)\n",
+		if (chip->use_sdam && ramp->hi_idx <= ramp->lo_idx) {
+			dev_err(chip->dev, "high-index(%d) should be larger than low-index(%d) when SDAM used\n",
 						ramp->hi_idx, ramp->lo_idx);
 			return -EINVAL;
 		}
@@ -1121,6 +1473,12 @@
 		ramp->pattern = &chip->lut->pattern[ramp->lo_idx];
 		lpg->max_pattern_length = ramp->pattern_length;
 
+		ramp->pattern_repeat = of_property_read_bool(child,
+				"qcom,ramp-pattern-repeat");
+
+		if (chip->use_sdam)
+			continue;
+
 		rc = of_property_read_u32(child,
 				"qcom,ramp-pause-hi-count", &tmp);
 		if (rc < 0)
@@ -1138,9 +1496,6 @@
 		ramp->ramp_dir_low_to_hi = of_property_read_bool(child,
 				"qcom,ramp-from-low-to-high");
 
-		ramp->pattern_repeat = of_property_read_bool(child,
-				"qcom,ramp-pattern-repeat");
-
 		ramp->toggle =  of_property_read_bool(child,
 				"qcom,ramp-toggle");
 	}
@@ -1148,6 +1503,36 @@
 	return 0;
 }
 
+static int qpnp_lpg_sdam_hw_init(struct qpnp_lpg_chip *chip)
+{
+	struct qpnp_lpg_channel *lpg;
+	int i, rc = 0;
+
+	if (!chip->use_sdam)
+		return 0;
+
+	for (i = 0; i < chip->num_lpgs; i++) {
+		lpg = &chip->lpgs[i];
+		if (lpg->lpg_sdam_base != 0) {
+			rc = qpnp_lpg_sdam_write(lpg, SDAM_LUT_EN_OFFSET, 0);
+			if (rc < 0) {
+				dev_err(chip->dev, "Write SDAM_REG_LUT_EN failed, rc=%d\n",
+						rc);
+				return rc;
+			}
+			rc = qpnp_lpg_sdam_write(lpg,
+					SDAM_PBS_SCRATCH_LUT_COUNTER_OFFSET, 0);
+			if (rc < 0) {
+				dev_err(lpg->chip->dev, "Write SDAM_REG_PBS_SCRATCH_LUT_COUNTER failed, rc=%d\n",
+						rc);
+				return rc;
+			}
+		}
+	}
+
+	return rc;
+}
+
 static int qpnp_lpg_probe(struct platform_device *pdev)
 {
 	int rc;
@@ -1172,6 +1557,13 @@
 		goto err_out;
 	}
 
+	rc = qpnp_lpg_sdam_hw_init(chip);
+	if (rc < 0) {
+		dev_err(chip->dev, "SDAM HW init failed, rc=%d\n",
+				rc);
+		goto err_out;
+	}
+
 	dev_set_drvdata(chip->dev, chip);
 	chip->pwm_chip.dev = chip->dev;
 	chip->pwm_chip.base = -1;
diff --git a/drivers/soc/qcom/jtagv8-etm.c b/drivers/soc/qcom/jtagv8-etm.c
index 3f4b8bc..23cbb7b 100644
--- a/drivers/soc/qcom/jtagv8-etm.c
+++ b/drivers/soc/qcom/jtagv8-etm.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2018, 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
@@ -345,7 +345,7 @@
 						       TRCCNTVRn(j));
 		}
 		/* resource selection registers */
-		for (j = 0; j < etmdata->nr_resource; j++)
+		for (j = 0; j < etmdata->nr_resource * 2; j++)
 			etmdata->state[i++] = etm_readl(etmdata, TRCRSCTLRn(j));
 		/* comparator registers */
 		for (j = 0; j < etmdata->nr_addr_cmp * 2; j++) {
@@ -448,7 +448,7 @@
 			etm_writel(etmdata, etmdata->state[i++], TRCCNTVRn(j));
 		}
 		/* resource selection registers */
-		for (j = 0; j < etmdata->nr_resource; j++)
+		for (j = 0; j < etmdata->nr_resource * 2; j++)
 			etm_writel(etmdata, etmdata->state[i++], TRCRSCTLRn(j));
 		/* comparator registers */
 		for (j = 0; j < etmdata->nr_addr_cmp * 2; j++) {
@@ -932,7 +932,7 @@
 		for (j = 0; j < etmdata->nr_cntr; j++)
 			i = etm_read_crxr(etmdata->state, i, j);
 		/* resource selection registers */
-		for (j = 0; j < etmdata->nr_resource; j++)
+		for (j = 0; j < etmdata->nr_resource * 2; j++)
 			i = etm_read_rsxr(etmdata->state, i, j + 2);
 		/* comparator registers */
 		for (j = 0; j < etmdata->nr_addr_cmp * 2; j++)
@@ -1387,7 +1387,7 @@
 		for (j = 0; j < etmdata->nr_cntr; j++)
 			i = etm_write_crxr(etmdata->state, i, j);
 		/* resource selection registers */
-		for (j = 0; j < etmdata->nr_resource; j++)
+		for (j = 0; j < etmdata->nr_resource * 2; j++)
 			i = etm_write_rsxr(etmdata->state, i, j + 2);
 		/* comparator registers */
 		for (j = 0; j < etmdata->nr_addr_cmp * 2; j++)
@@ -1496,7 +1496,7 @@
 	val = etm_readl(etmdata, TRCIDR4);
 	etmdata->nr_addr_cmp = BMVAL(val, 0, 3);
 	etmdata->nr_data_cmp = BMVAL(val, 4, 7);
-	etmdata->nr_resource = BMVAL(val, 16, 19);
+	etmdata->nr_resource = BMVAL(val, 16, 19) + 1;
 	etmdata->nr_ss_cmp = BMVAL(val, 20, 23);
 	etmdata->nr_ctxid_cmp = BMVAL(val, 24, 27);
 	etmdata->nr_vmid_cmp = BMVAL(val, 28, 31);
diff --git a/drivers/spi/spi-geni-qcom.c b/drivers/spi/spi-geni-qcom.c
index dfa387c..5998c20 100644
--- a/drivers/spi/spi-geni-qcom.c
+++ b/drivers/spi/spi-geni-qcom.c
@@ -311,7 +311,7 @@
 				struct spi_message *spi_msg)
 {
 	struct spi_geni_master *mas = spi_master_get_devdata(spi);
-	int mode = FIFO_MODE;
+	int mode = SE_DMA;
 	int fifo_disable = (geni_read_reg(mas->base, GENI_IF_FIFO_DISABLE_RO) &
 							FIFO_IF_DISABLE);
 	bool dma_chan_valid =
@@ -325,10 +325,10 @@
 	 */
 	if (fifo_disable && !dma_chan_valid)
 		mode = -EINVAL;
+	else if (!fifo_disable)
+		mode = SE_DMA;
 	else if (dma_chan_valid)
 		mode = GSI_DMA;
-	else
-		mode = FIFO_MODE;
 	return mode;
 }
 
@@ -715,25 +715,20 @@
 
 	mas->cur_xfer_mode = select_xfer_mode(spi, spi_msg);
 
-	if (mas->cur_xfer_mode == FIFO_MODE) {
-		geni_se_select_mode(mas->base, FIFO_MODE);
-		reinit_completion(&mas->xfer_done);
-		ret = setup_fifo_params(spi_msg->spi, spi);
+	if (mas->cur_xfer_mode < 0) {
+		dev_err(mas->dev, "%s: Couldn't select mode %d", __func__,
+							mas->cur_xfer_mode);
+		ret = -EINVAL;
 	} else if (mas->cur_xfer_mode == GSI_DMA) {
-		mas->num_tx_eot = 0;
-		mas->num_rx_eot = 0;
-		mas->num_xfers = 0;
-		reinit_completion(&mas->tx_cb);
-		reinit_completion(&mas->rx_cb);
 		memset(mas->gsi, 0,
 				(sizeof(struct spi_geni_gsi) * NUM_SPI_XFER));
 		geni_se_select_mode(mas->base, GSI_DMA);
 		ret = spi_geni_map_buf(mas, spi_msg);
 	} else {
-		dev_err(mas->dev, "%s: Couldn't select mode %d", __func__,
-							mas->cur_xfer_mode);
-		ret = -EINVAL;
+		geni_se_select_mode(mas->base, mas->cur_xfer_mode);
+		ret = setup_fifo_params(spi_msg->spi, spi);
 	}
+
 	return ret;
 }
 
@@ -965,26 +960,64 @@
 		geni_write_reg(trans_len, mas->base, SE_SPI_RX_TRANS_LEN);
 		mas->rx_rem_bytes = xfer->len;
 	}
+
+	if (trans_len > (mas->tx_fifo_depth * mas->tx_fifo_width)) {
+		if (mas->cur_xfer_mode != SE_DMA) {
+			mas->cur_xfer_mode = SE_DMA;
+			geni_se_select_mode(mas->base, mas->cur_xfer_mode);
+		}
+	} else {
+		if (mas->cur_xfer_mode != FIFO_MODE) {
+			mas->cur_xfer_mode = FIFO_MODE;
+			geni_se_select_mode(mas->base, mas->cur_xfer_mode);
+		}
+	}
+
 	geni_write_reg(spi_tx_cfg, mas->base, SE_SPI_TRANS_CFG);
 	geni_setup_m_cmd(mas->base, m_cmd, m_param);
 	GENI_SE_DBG(mas->ipc, false, mas->dev,
-		"%s: trans_len %d xferlen%d tx_cfg 0x%x cmd 0x%x cs %d\n",
+		"%s: trans_len %d xferlen%d tx_cfg 0x%x cmd 0x%x cs%d mode%d\n",
 		__func__, trans_len, xfer->len, spi_tx_cfg, m_cmd,
-		xfer->cs_change);
-	if (m_cmd & SPI_TX_ONLY)
-		geni_write_reg(mas->tx_wm, mas->base, SE_GENI_TX_WATERMARK_REG);
+		xfer->cs_change, mas->cur_xfer_mode);
+	if ((m_cmd & SPI_RX_ONLY) && (mas->cur_xfer_mode == SE_DMA)) {
+		int ret = 0;
+
+		ret =  geni_se_rx_dma_prep(mas->wrapper_dev, mas->base,
+				xfer->rx_buf, xfer->len, &xfer->rx_dma);
+		if (ret)
+			GENI_SE_ERR(mas->ipc, true, mas->dev,
+				"Failed to setup Rx dma %d\n", ret);
+	}
+	if (m_cmd & SPI_TX_ONLY) {
+		if (mas->cur_xfer_mode == FIFO_MODE) {
+			geni_write_reg(mas->tx_wm, mas->base,
+					SE_GENI_TX_WATERMARK_REG);
+		} else if (mas->cur_xfer_mode == SE_DMA) {
+			int ret = 0;
+
+			ret =  geni_se_tx_dma_prep(mas->wrapper_dev, mas->base,
+					(void *)xfer->tx_buf, xfer->len,
+							&xfer->tx_dma);
+			if (ret)
+				GENI_SE_ERR(mas->ipc, true, mas->dev,
+					"Failed to setup tx dma %d\n", ret);
+		}
+	}
+
 	/* Ensure all writes are done before the WM interrupt */
 	mb();
 }
 
-static void handle_fifo_timeout(struct spi_geni_master *mas)
+static void handle_fifo_timeout(struct spi_geni_master *mas,
+					struct spi_transfer *xfer)
 {
 	unsigned long timeout;
 
 	geni_se_dump_dbg_regs(&mas->spi_rsc, mas->base, mas->ipc);
 	reinit_completion(&mas->xfer_done);
 	geni_cancel_m_cmd(mas->base);
-	geni_write_reg(0, mas->base, SE_GENI_TX_WATERMARK_REG);
+	if (mas->cur_xfer_mode == FIFO_MODE)
+		geni_write_reg(0, mas->base, SE_GENI_TX_WATERMARK_REG);
 	/* Ensure cmd cancel is written */
 	mb();
 	timeout = wait_for_completion_timeout(&mas->xfer_done, HZ);
@@ -999,6 +1032,15 @@
 			dev_err(mas->dev,
 				"Failed to cancel/abort m_cmd\n");
 	}
+	if (mas->cur_xfer_mode == SE_DMA) {
+		if (xfer->tx_buf)
+			geni_se_tx_dma_unprep(mas->wrapper_dev,
+					xfer->tx_dma, xfer->len);
+		if (xfer->rx_buf)
+			geni_se_rx_dma_unprep(mas->wrapper_dev,
+					xfer->rx_dma, xfer->len);
+	}
+
 }
 
 static int spi_geni_transfer_one(struct spi_master *spi,
@@ -1014,7 +1056,8 @@
 		return -EINVAL;
 	}
 
-	if (mas->cur_xfer_mode == FIFO_MODE) {
+	if (mas->cur_xfer_mode != GSI_DMA) {
+		reinit_completion(&mas->xfer_done);
 		setup_fifo_xfer(xfer, mas, slv->mode, spi);
 		timeout = wait_for_completion_timeout(&mas->xfer_done,
 					msecs_to_jiffies(SPI_XFER_TIMEOUT_MS));
@@ -1028,7 +1071,22 @@
 			ret = -ETIMEDOUT;
 			goto err_fifo_geni_transfer_one;
 		}
+
+		if (mas->cur_xfer_mode == SE_DMA) {
+			if (xfer->tx_buf)
+				geni_se_tx_dma_unprep(mas->wrapper_dev,
+					xfer->tx_dma, xfer->len);
+			if (xfer->rx_buf)
+				geni_se_rx_dma_unprep(mas->wrapper_dev,
+					xfer->rx_dma, xfer->len);
+		}
 	} else {
+		mas->num_tx_eot = 0;
+		mas->num_rx_eot = 0;
+		mas->num_xfers = 0;
+		reinit_completion(&mas->tx_cb);
+		reinit_completion(&mas->rx_cb);
+
 		setup_gsi_xfer(xfer, mas, slv, spi);
 		if ((mas->num_xfers >= NUM_SPI_XFER) ||
 			(list_is_last(&xfer->transfer_list,
@@ -1072,7 +1130,7 @@
 	dmaengine_terminate_all(mas->tx);
 	return ret;
 err_fifo_geni_transfer_one:
-	handle_fifo_timeout(mas);
+	handle_fifo_timeout(mas, xfer);
 	return ret;
 }
 
@@ -1188,33 +1246,59 @@
 		goto exit_geni_spi_irq;
 	}
 	m_irq = geni_read_reg(mas->base, SE_GENI_M_IRQ_STATUS);
-	if ((m_irq & M_RX_FIFO_WATERMARK_EN) || (m_irq & M_RX_FIFO_LAST_EN))
-		geni_spi_handle_rx(mas);
+	if (mas->cur_xfer_mode == FIFO_MODE) {
+		if ((m_irq & M_RX_FIFO_WATERMARK_EN) ||
+						(m_irq & M_RX_FIFO_LAST_EN))
+			geni_spi_handle_rx(mas);
 
-	if ((m_irq & M_TX_FIFO_WATERMARK_EN))
-		geni_spi_handle_tx(mas);
+		if ((m_irq & M_TX_FIFO_WATERMARK_EN))
+			geni_spi_handle_tx(mas);
 
-	if ((m_irq & M_CMD_DONE_EN) || (m_irq & M_CMD_CANCEL_EN) ||
-		(m_irq & M_CMD_ABORT_EN)) {
-		complete(&mas->xfer_done);
-		/*
-		 * If this happens, then a CMD_DONE came before all the buffer
-		 * bytes were sent out. This is unusual, log this condition and
-		 * disable the WM interrupt to prevent the system from stalling
-		 * due an interrupt storm.
-		 * If this happens when all Rx bytes haven't been received, log
-		 * the condition.
-		 */
-		if (mas->tx_rem_bytes) {
-			geni_write_reg(0, mas->base, SE_GENI_TX_WATERMARK_REG);
-			GENI_SE_DBG(mas->ipc, false, mas->dev,
-				"%s:Premature Done.tx_rem%d bpw%d\n",
-				__func__, mas->tx_rem_bytes, mas->cur_word_len);
+		if ((m_irq & M_CMD_DONE_EN) || (m_irq & M_CMD_CANCEL_EN) ||
+			(m_irq & M_CMD_ABORT_EN)) {
+			complete(&mas->xfer_done);
+			/*
+			 * If this happens, then a CMD_DONE came before all the
+			 * buffer bytes were sent out. This is unusual, log this
+			 * condition and disable the WM interrupt to prevent the
+			 * system from stalling due an interrupt storm.
+			 * If this happens when all Rx bytes haven't been
+			 * received, log the condition.
+			 */
+			if (mas->tx_rem_bytes) {
+				geni_write_reg(0, mas->base,
+						SE_GENI_TX_WATERMARK_REG);
+				GENI_SE_DBG(mas->ipc, false, mas->dev,
+					"%s:Premature Done.tx_rem%d bpw%d\n",
+					__func__, mas->tx_rem_bytes,
+						mas->cur_word_len);
+			}
+			if (mas->rx_rem_bytes)
+				GENI_SE_DBG(mas->ipc, false, mas->dev,
+					"%s:Premature Done.rx_rem%d bpw%d\n",
+						__func__, mas->rx_rem_bytes,
+							mas->cur_word_len);
 		}
-		if (mas->rx_rem_bytes)
-			GENI_SE_DBG(mas->ipc, false, mas->dev,
-				"%s:Premature Done.rx_rem%d bpw%d\n",
-				__func__, mas->rx_rem_bytes, mas->cur_word_len);
+	} else if (mas->cur_xfer_mode == SE_DMA) {
+		u32 dma_tx_status = geni_read_reg(mas->base,
+							SE_DMA_TX_IRQ_STAT);
+		u32 dma_rx_status = geni_read_reg(mas->base,
+							SE_DMA_RX_IRQ_STAT);
+
+		if (dma_tx_status)
+			geni_write_reg(dma_tx_status, mas->base,
+						SE_DMA_TX_IRQ_CLR);
+		if (dma_rx_status)
+			geni_write_reg(dma_rx_status, mas->base,
+						SE_DMA_RX_IRQ_CLR);
+		if (dma_tx_status & TX_DMA_DONE)
+			mas->tx_rem_bytes = 0;
+		if (dma_rx_status & RX_DMA_DONE)
+			mas->rx_rem_bytes = 0;
+		if (!mas->tx_rem_bytes && !mas->rx_rem_bytes)
+			complete(&mas->xfer_done);
+		if ((m_irq & M_CMD_CANCEL_EN) || (m_irq & M_CMD_ABORT_EN))
+			complete(&mas->xfer_done);
 	}
 exit_geni_spi_irq:
 	geni_write_reg(m_irq, mas->base, SE_GENI_M_IRQ_CLEAR);
diff --git a/drivers/staging/android/lowmemorykiller.c b/drivers/staging/android/lowmemorykiller.c
index a1602e4..027094f 100644
--- a/drivers/staging/android/lowmemorykiller.c
+++ b/drivers/staging/android/lowmemorykiller.c
@@ -63,6 +63,10 @@
 #define CREATE_TRACE_POINTS
 #include "trace/lowmemorykiller.h"
 
+/* to enable lowmemorykiller */
+static int enable_lmk = 1;
+module_param_named(enable_lmk, enable_lmk, int, 0644);
+
 static u32 lowmem_debug_level = 1;
 static short lowmem_adj[6] = {
 	0,
@@ -93,6 +97,9 @@
 static unsigned long lowmem_count(struct shrinker *s,
 				  struct shrink_control *sc)
 {
+	if (!enable_lmk)
+		return 0;
+
 	return global_node_page_state(NR_ACTIVE_ANON) +
 		global_node_page_state(NR_ACTIVE_FILE) +
 		global_node_page_state(NR_INACTIVE_ANON) +
diff --git a/drivers/thermal/cpu_cooling.c b/drivers/thermal/cpu_cooling.c
index 2c4a63a..02f93f4 100644
--- a/drivers/thermal/cpu_cooling.c
+++ b/drivers/thermal/cpu_cooling.c
@@ -224,7 +224,7 @@
 static int cpufreq_cooling_pm_notify(struct notifier_block *nb,
 				unsigned long mode, void *_unused)
 {
-	struct cpufreq_cooling_device *cpufreq_dev;
+	struct cpufreq_cooling_device *cpufreq_dev, *next;
 	unsigned int cpu;
 
 	switch (mode) {
@@ -236,8 +236,8 @@
 	case PM_POST_HIBERNATION:
 	case PM_POST_RESTORE:
 	case PM_POST_SUSPEND:
-		mutex_lock(&cooling_list_lock);
-		list_for_each_entry(cpufreq_dev, &cpufreq_dev_list, node) {
+		list_for_each_entry_safe(cpufreq_dev, next, &cpufreq_dev_list,
+						node) {
 			mutex_lock(&core_isolate_lock);
 			if (cpufreq_dev->cpufreq_state ==
 				cpufreq_dev->max_level) {
@@ -259,7 +259,6 @@
 			}
 			mutex_unlock(&core_isolate_lock);
 		}
-		mutex_unlock(&cooling_list_lock);
 
 		atomic_set(&in_suspend, 0);
 		break;
diff --git a/drivers/thermal/gov_low_limits.c b/drivers/thermal/gov_low_limits.c
index 278869c..d02ea26 100644
--- a/drivers/thermal/gov_low_limits.c
+++ b/drivers/thermal/gov_low_limits.c
@@ -62,19 +62,30 @@
 		dev_dbg(&instance->cdev->device, "old_target=%d, target=%d\n",
 					old_target, (int)instance->target);
 
-		if (old_target == instance->target)
+		if (instance->initialized && old_target == instance->target)
 			continue;
 
-		if (old_target == THERMAL_NO_TARGET &&
+		if (!instance->initialized) {
+			if (instance->target != THERMAL_NO_TARGET) {
+				trace_thermal_zone_trip(tz, trip, trip_type,
+							true);
+				tz->passive += 1;
+			}
+		} else {
+			if (old_target == THERMAL_NO_TARGET &&
 				instance->target != THERMAL_NO_TARGET) {
-			trace_thermal_zone_trip(tz, trip, trip_type, true);
-			tz->passive += 1;
-		} else if (old_target != THERMAL_NO_TARGET &&
+				trace_thermal_zone_trip(tz, trip, trip_type,
+							true);
+				tz->passive += 1;
+			} else if (old_target != THERMAL_NO_TARGET &&
 				instance->target == THERMAL_NO_TARGET) {
-			trace_thermal_zone_trip(tz, trip, trip_type, false);
-			tz->passive -= 1;
+				trace_thermal_zone_trip(tz, trip, trip_type,
+							false);
+				tz->passive -= 1;
+			}
 		}
 
+		instance->initialized = true;
 		instance->cdev->updated = false; /* cdev needs update */
 	}
 
diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c
index ad1186d..a45810b 100644
--- a/drivers/thermal/samsung/exynos_tmu.c
+++ b/drivers/thermal/samsung/exynos_tmu.c
@@ -185,6 +185,7 @@
  * @regulator: pointer to the TMU regulator structure.
  * @reg_conf: pointer to structure to register with core thermal.
  * @ntrip: number of supported trip points.
+ * @enabled: current status of TMU device
  * @tmu_initialize: SoC specific TMU initialization method
  * @tmu_control: SoC specific TMU control method
  * @tmu_read: SoC specific TMU temperature read method
@@ -205,6 +206,7 @@
 	struct regulator *regulator;
 	struct thermal_zone_device *tzd;
 	unsigned int ntrip;
+	bool enabled;
 
 	int (*tmu_initialize)(struct platform_device *pdev);
 	void (*tmu_control)(struct platform_device *pdev, bool on);
@@ -398,6 +400,7 @@
 	mutex_lock(&data->lock);
 	clk_enable(data->clk);
 	data->tmu_control(pdev, on);
+	data->enabled = on;
 	clk_disable(data->clk);
 	mutex_unlock(&data->lock);
 }
@@ -889,19 +892,24 @@
 static int exynos_get_temp(void *p, int *temp)
 {
 	struct exynos_tmu_data *data = p;
+	int value, ret = 0;
 
-	if (!data || !data->tmu_read)
+	if (!data || !data->tmu_read || !data->enabled)
 		return -EINVAL;
 
 	mutex_lock(&data->lock);
 	clk_enable(data->clk);
 
-	*temp = code_to_temp(data, data->tmu_read(data)) * MCELSIUS;
+	value = data->tmu_read(data);
+	if (value < 0)
+		ret = value;
+	else
+		*temp = code_to_temp(data, value) * MCELSIUS;
 
 	clk_disable(data->clk);
 	mutex_unlock(&data->lock);
 
-	return 0;
+	return ret;
 }
 
 #ifdef CONFIG_THERMAL_EMULATION
diff --git a/drivers/thermal/step_wise.c b/drivers/thermal/step_wise.c
index 4bbb47a..4d75f6b 100644
--- a/drivers/thermal/step_wise.c
+++ b/drivers/thermal/step_wise.c
@@ -190,16 +190,26 @@
 		if (instance->initialized && old_target == instance->target)
 			continue;
 
-		/* Activate a passive thermal instance */
-		if (old_target == THERMAL_NO_TARGET &&
-			instance->target != THERMAL_NO_TARGET) {
-			update_passive_instance(tz, trip_type, 1);
-			trace_thermal_zone_trip(tz, trip, trip_type, true);
-		/* Deactivate a passive thermal instance */
-		} else if (old_target != THERMAL_NO_TARGET &&
-			instance->target == THERMAL_NO_TARGET) {
-			update_passive_instance(tz, trip_type, -1);
-			trace_thermal_zone_trip(tz, trip, trip_type, false);
+		if (!instance->initialized) {
+			if (instance->target != THERMAL_NO_TARGET) {
+				trace_thermal_zone_trip(tz, trip, trip_type,
+							true);
+				update_passive_instance(tz, trip_type, 1);
+			}
+		} else {
+			/* Activate a passive thermal instance */
+			if (old_target == THERMAL_NO_TARGET &&
+				instance->target != THERMAL_NO_TARGET) {
+				trace_thermal_zone_trip(tz, trip, trip_type,
+							true);
+				update_passive_instance(tz, trip_type, 1);
+			/* Deactivate a passive thermal instance */
+			} else if (old_target != THERMAL_NO_TARGET &&
+				instance->target == THERMAL_NO_TARGET) {
+				trace_thermal_zone_trip(tz, trip, trip_type,
+							false);
+				update_passive_instance(tz, trip_type, -1);
+			}
 		}
 
 		instance->initialized = true;
diff --git a/drivers/tty/serial/sccnxp.c b/drivers/tty/serial/sccnxp.c
index cdd2f94..b9c7a90 100644
--- a/drivers/tty/serial/sccnxp.c
+++ b/drivers/tty/serial/sccnxp.c
@@ -889,7 +889,16 @@
 			goto err_out;
 		uartclk = 0;
 	} else {
-		clk_prepare_enable(clk);
+		ret = clk_prepare_enable(clk);
+		if (ret)
+			goto err_out;
+
+		ret = devm_add_action_or_reset(&pdev->dev,
+				(void(*)(void *))clk_disable_unprepare,
+				clk);
+		if (ret)
+			goto err_out;
+
 		uartclk = clk_get_rate(clk);
 	}
 
@@ -988,7 +997,7 @@
 	uart_unregister_driver(&s->uart);
 err_out:
 	if (!IS_ERR(s->regulator))
-		return regulator_disable(s->regulator);
+		regulator_disable(s->regulator);
 
 	return ret;
 }
diff --git a/drivers/usb/gadget/function/f_cdev.c b/drivers/usb/gadget/function/f_cdev.c
index 4d4f039..a7166e2 100644
--- a/drivers/usb/gadget/function/f_cdev.c
+++ b/drivers/usb/gadget/function/f_cdev.c
@@ -1256,6 +1256,7 @@
 		ret = -EFAULT;
 	} else {
 		req->length = xfer_size;
+		req->zero = 1;
 		ret = usb_ep_queue(in, req, GFP_KERNEL);
 		if (ret) {
 			pr_err("EP QUEUE failed:%d\n", ret);
diff --git a/drivers/usb/phy/phy-msm-usb.c b/drivers/usb/phy/phy-msm-usb.c
index 1550cae..a6326d5 100644
--- a/drivers/usb/phy/phy-msm-usb.c
+++ b/drivers/usb/phy/phy-msm-usb.c
@@ -273,6 +273,11 @@
 module_param(dcp_max_current, int, 0644);
 MODULE_PARM_DESC(dcp_max_current, "max current drawn for DCP charger");
 
+static bool chg_detection_for_float_charger;
+module_param(chg_detection_for_float_charger, bool, 0644);
+MODULE_PARM_DESC(chg_detection_for_float_charger,
+	"Whether to do PHY based charger detection for float chargers");
+
 static struct msm_otg *the_msm_otg;
 static bool debug_bus_voting_enabled;
 
@@ -2974,10 +2979,20 @@
 			set_bit(ID, &motg->inputs);
 	}
 
-	if (test_bit(B_SESS_VLD, &motg->inputs) &&
-	     get_psy_type(motg) == POWER_SUPPLY_TYPE_UNKNOWN &&
-	     !motg->chg_detection)
-		motg->chg_detection = true;
+	/*
+	 * Enable PHY based charger detection in 2 cases:
+	 * 1. PMI not capable of doing charger detection and provides VBUS
+	 *    notification with UNKNOWN psy type.
+	 * 2. Data lines have been cut off from PMI, in which case it provides
+	 *    VBUS notification with FLOAT psy type and we want to do PHY based
+	 *    charger detection by setting 'chg_detection_for_float_charger'.
+	 */
+	if (test_bit(B_SESS_VLD, &motg->inputs) && !motg->chg_detection) {
+		if ((get_psy_type(motg) == POWER_SUPPLY_TYPE_UNKNOWN) ||
+		    (get_psy_type(motg) == POWER_SUPPLY_TYPE_USB_FLOAT &&
+		     chg_detection_for_float_charger))
+			motg->chg_detection = true;
+	}
 
 	if (motg->chg_detection)
 		queue_delayed_work(motg->otg_wq, &motg->chg_work, 0);
diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c
index 5af226f..17ad41d 100644
--- a/fs/fs-writeback.c
+++ b/fs/fs-writeback.c
@@ -1942,7 +1942,7 @@
 	}
 
 	if (!list_empty(&wb->work_list))
-		mod_delayed_work(bdi_wq, &wb->dwork, 0);
+		wb_wakeup(wb);
 	else if (wb_has_dirty_io(wb) && dirty_writeback_interval)
 		wb_wakeup_delayed(wb);
 
diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c
index 4d51259..d484c63 100644
--- a/fs/lockd/svc.c
+++ b/fs/lockd/svc.c
@@ -274,6 +274,8 @@
 	if (ln->nlmsvc_users) {
 		if (--ln->nlmsvc_users == 0) {
 			nlm_shutdown_hosts_net(net);
+			cancel_delayed_work_sync(&ln->grace_period_end);
+			locks_end_grace(&ln->lockd_manager);
 			svc_shutdown_net(serv, net);
 			dprintk("lockd_down_net: per-net data destroyed; net=%p\n", net);
 		}
diff --git a/fs/proc/base.c b/fs/proc/base.c
index abe157a5..5b2d1ea 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -253,7 +253,7 @@
 	 * Inherently racy -- command line shares address space
 	 * with code and data.
 	 */
-	rv = access_remote_vm(mm, arg_end - 1, &c, 1, 0);
+	rv = access_remote_vm(mm, arg_end - 1, &c, 1, FOLL_ANON);
 	if (rv <= 0)
 		goto out_free_page;
 
@@ -271,7 +271,7 @@
 			int nr_read;
 
 			_count = min3(count, len, PAGE_SIZE);
-			nr_read = access_remote_vm(mm, p, page, _count, 0);
+			nr_read = access_remote_vm(mm, p, page, _count, FOLL_ANON);
 			if (nr_read < 0)
 				rv = nr_read;
 			if (nr_read <= 0)
@@ -306,7 +306,7 @@
 			bool final;
 
 			_count = min3(count, len, PAGE_SIZE);
-			nr_read = access_remote_vm(mm, p, page, _count, 0);
+			nr_read = access_remote_vm(mm, p, page, _count, FOLL_ANON);
 			if (nr_read < 0)
 				rv = nr_read;
 			if (nr_read <= 0)
@@ -355,7 +355,7 @@
 			bool final;
 
 			_count = min3(count, len, PAGE_SIZE);
-			nr_read = access_remote_vm(mm, p, page, _count, 0);
+			nr_read = access_remote_vm(mm, p, page, _count, FOLL_ANON);
 			if (nr_read < 0)
 				rv = nr_read;
 			if (nr_read <= 0)
@@ -971,7 +971,7 @@
 		max_len = min_t(size_t, PAGE_SIZE, count);
 		this_len = min(max_len, this_len);
 
-		retval = access_remote_vm(mm, (env_start + src), page, this_len, 0);
+		retval = access_remote_vm(mm, (env_start + src), page, this_len, FOLL_ANON);
 
 		if (retval <= 0) {
 			ret = retval;
diff --git a/fs/sdcardfs/dentry.c b/fs/sdcardfs/dentry.c
index 166f14b..776d549 100644
--- a/fs/sdcardfs/dentry.c
+++ b/fs/sdcardfs/dentry.c
@@ -51,7 +51,6 @@
 	 * whether the base obbpath has been changed or not
 	 */
 	if (is_obbpath_invalid(dentry)) {
-		d_drop(dentry);
 		return 0;
 	}
 
@@ -65,7 +64,6 @@
 	if ((lower_dentry->d_flags & DCACHE_OP_REVALIDATE)) {
 		err = lower_dentry->d_op->d_revalidate(lower_dentry, flags);
 		if (err == 0) {
-			d_drop(dentry);
 			goto out;
 		}
 	}
@@ -73,14 +71,12 @@
 	spin_lock(&lower_dentry->d_lock);
 	if (d_unhashed(lower_dentry)) {
 		spin_unlock(&lower_dentry->d_lock);
-		d_drop(dentry);
 		err = 0;
 		goto out;
 	}
 	spin_unlock(&lower_dentry->d_lock);
 
 	if (parent_lower_dentry != lower_cur_parent_dentry) {
-		d_drop(dentry);
 		err = 0;
 		goto out;
 	}
@@ -94,7 +90,6 @@
 	}
 
 	if (!qstr_case_eq(&dentry->d_name, &lower_dentry->d_name)) {
-		__d_drop(dentry);
 		err = 0;
 	}
 
@@ -113,7 +108,6 @@
 	if (inode) {
 		data = top_data_get(SDCARDFS_I(inode));
 		if (!data || data->abandoned) {
-			d_drop(dentry);
 			err = 0;
 		}
 		if (data)
diff --git a/include/asm-generic/futex.h b/include/asm-generic/futex.h
index bf2d34c..f0d8b1c 100644
--- a/include/asm-generic/futex.h
+++ b/include/asm-generic/futex.h
@@ -13,7 +13,7 @@
  */
 
 /**
- * futex_atomic_op_inuser() - Atomic arithmetic operation with constant
+ * arch_futex_atomic_op_inuser() - Atomic arithmetic operation with constant
  *			  argument and comparison of the previous
  *			  futex value with another constant.
  *
@@ -25,18 +25,11 @@
  * <0 - On error
  */
 static inline int
-futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
+arch_futex_atomic_op_inuser(int op, u32 oparg, int *oval, u32 __user *uaddr)
 {
-	int op = (encoded_op >> 28) & 7;
-	int cmp = (encoded_op >> 24) & 15;
-	int oparg = (encoded_op << 8) >> 20;
-	int cmparg = (encoded_op << 20) >> 20;
 	int oldval, ret;
 	u32 tmp;
 
-	if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
-		oparg = 1 << oparg;
-
 	preempt_disable();
 	pagefault_disable();
 
@@ -74,17 +67,9 @@
 	pagefault_enable();
 	preempt_enable();
 
-	if (ret == 0) {
-		switch (cmp) {
-		case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
-		case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
-		case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
-		case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
-		case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
-		case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
-		default: ret = -ENOSYS;
-		}
-	}
+	if (ret == 0)
+		*oval = oldval;
+
 	return ret;
 }
 
@@ -126,18 +111,9 @@
 
 #else
 static inline int
-futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
+arch_futex_atomic_op_inuser(int op, u32 oparg, int *oval, u32 __user *uaddr)
 {
-	int op = (encoded_op >> 28) & 7;
-	int cmp = (encoded_op >> 24) & 15;
-	int oparg = (encoded_op << 8) >> 20;
-	int cmparg = (encoded_op << 20) >> 20;
 	int oldval = 0, ret;
-	if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
-		oparg = 1 << oparg;
-
-	if (! access_ok (VERIFY_WRITE, uaddr, sizeof(u32)))
-		return -EFAULT;
 
 	pagefault_disable();
 
@@ -153,17 +129,9 @@
 
 	pagefault_enable();
 
-	if (!ret) {
-		switch (cmp) {
-		case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
-		case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
-		case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
-		case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
-		case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
-		case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
-		default: ret = -ENOSYS;
-		}
-	}
+	if (!ret)
+		*oval = oldval;
+
 	return ret;
 }
 
diff --git a/include/dt-bindings/pinctrl/qcom,pmic-gpio.h b/include/dt-bindings/pinctrl/qcom,pmic-gpio.h
index 64e2dc7..7ac6f16 100644
--- a/include/dt-bindings/pinctrl/qcom,pmic-gpio.h
+++ b/include/dt-bindings/pinctrl/qcom,pmic-gpio.h
@@ -11,9 +11,14 @@
 #define PMIC_GPIO_PULL_UP_1P5_30	3
 
 #define PMIC_GPIO_STRENGTH_NO		0
-#define PMIC_GPIO_STRENGTH_HIGH		1
+#define PMIC_GPIO_STRENGTH_LOW		1
 #define PMIC_GPIO_STRENGTH_MED		2
-#define PMIC_GPIO_STRENGTH_LOW		3
+#define PMIC_GPIO_STRENGTH_HIGH		3
+
+#define PM8921_GPIO_STRENGTH_NO		0
+#define PM8921_GPIO_STRENGTH_HIGH	1
+#define PM8921_GPIO_STRENGTH_MED	2
+#define PM8921_GPIO_STRENGTH_LOW	3
 
 /*
  * Note: PM8018 GPIO3 and GPIO4 are supporting
diff --git a/include/linux/diagchar.h b/include/linux/diagchar.h
index d9912e0..62f4fa8 100644
--- a/include/linux/diagchar.h
+++ b/include/linux/diagchar.h
@@ -146,7 +146,7 @@
  * a new RANGE of SSIDs to the msg_mask_tbl.
  */
 #define MSG_MASK_TBL_CNT		26
-#define APPS_EVENT_LAST_ID		0x0C5B
+#define APPS_EVENT_LAST_ID		0xC7A
 
 #define MSG_SSID_0			0
 #define MSG_SSID_0_LAST			125
diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h
index f4c0d36..ab7938a 100644
--- a/include/linux/ftrace.h
+++ b/include/linux/ftrace.h
@@ -244,8 +244,16 @@
 	return *this_cpu_ptr(ops->disabled);
 }
 
+#ifdef CONFIG_CFI_CLANG
+/* Use a C stub with the correct type for CFI */
+static inline void ftrace_stub(unsigned long a0, unsigned long a1,
+			       struct ftrace_ops *op, struct pt_regs *regs)
+{
+}
+#else
 extern void ftrace_stub(unsigned long a0, unsigned long a1,
 			struct ftrace_ops *op, struct pt_regs *regs);
+#endif
 
 #else /* !CONFIG_FUNCTION_TRACER */
 /*
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 270f032..b328cca 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -2246,6 +2246,7 @@
 #define FOLL_MLOCK	0x1000	/* lock present pages */
 #define FOLL_REMOTE	0x2000	/* we are working on non-current tsk/mm */
 #define FOLL_COW	0x4000	/* internal GUP flag */
+#define FOLL_ANON	0x8000	/* don't do file mappings */
 
 typedef int (*pte_fn_t)(pte_t *pte, pgtable_t token, unsigned long addr,
 			void *data);
diff --git a/include/linux/mm_inline.h b/include/linux/mm_inline.h
index 41d376e..e030a68 100644
--- a/include/linux/mm_inline.h
+++ b/include/linux/mm_inline.h
@@ -50,6 +50,13 @@
 	list_add(&page->lru, &lruvec->lists[lru]);
 }
 
+static __always_inline void add_page_to_lru_list_tail(struct page *page,
+				struct lruvec *lruvec, enum lru_list lru)
+{
+	update_lru_size(lruvec, lru, page_zonenum(page), hpage_nr_pages(page));
+	list_add_tail(&page->lru, &lruvec->lists[lru]);
+}
+
 static __always_inline void del_page_from_lru_list(struct page *page,
 				struct lruvec *lruvec, enum lru_list lru)
 {
diff --git a/include/linux/writeback.h b/include/linux/writeback.h
index 9a8eb83..3eed4f1 100644
--- a/include/linux/writeback.h
+++ b/include/linux/writeback.h
@@ -43,7 +43,7 @@
  */
 enum wb_reason {
 	WB_REASON_BACKGROUND,
-	WB_REASON_TRY_TO_FREE_PAGES,
+	WB_REASON_VMSCAN,
 	WB_REASON_SYNC,
 	WB_REASON_PERIODIC,
 	WB_REASON_LAPTOP_TIMER,
diff --git a/include/net/bonding.h b/include/net/bonding.h
index f32f7ef..7734cc9 100644
--- a/include/net/bonding.h
+++ b/include/net/bonding.h
@@ -197,6 +197,7 @@
 	struct   slave __rcu *primary_slave;
 	struct   bond_up_slave __rcu *slave_arr; /* Array of usable slaves */
 	bool     force_primary;
+	u32      nest_level;
 	s32      slave_cnt; /* never change this value outside the attach/detach wrappers */
 	int     (*recv_probe)(const struct sk_buff *, struct bonding *,
 			      struct slave *);
diff --git a/include/net/inet_timewait_sock.h b/include/net/inet_timewait_sock.h
index c9b3eb7..567017b 100644
--- a/include/net/inet_timewait_sock.h
+++ b/include/net/inet_timewait_sock.h
@@ -55,6 +55,7 @@
 #define tw_family		__tw_common.skc_family
 #define tw_state		__tw_common.skc_state
 #define tw_reuse		__tw_common.skc_reuse
+#define tw_reuseport		__tw_common.skc_reuseport
 #define tw_ipv6only		__tw_common.skc_ipv6only
 #define tw_bound_dev_if		__tw_common.skc_bound_dev_if
 #define tw_node			__tw_common.skc_nulls_node
diff --git a/include/net/nexthop.h b/include/net/nexthop.h
index 3334dbf..7fc7866 100644
--- a/include/net/nexthop.h
+++ b/include/net/nexthop.h
@@ -6,7 +6,7 @@
 
 static inline int rtnh_ok(const struct rtnexthop *rtnh, int remaining)
 {
-	return remaining >= sizeof(*rtnh) &&
+	return remaining >= (int)sizeof(*rtnh) &&
 	       rtnh->rtnh_len >= sizeof(*rtnh) &&
 	       rtnh->rtnh_len <= remaining;
 }
diff --git a/include/soc/qcom/pm-legacy.h b/include/soc/qcom/pm-legacy.h
index 7fdb0cd..0ae5d7b 100644
--- a/include/soc/qcom/pm-legacy.h
+++ b/include/soc/qcom/pm-legacy.h
@@ -179,9 +179,13 @@
 #endif
 
 #ifdef CONFIG_HOTPLUG_CPU
+void qcom_cpu_die_legacy(unsigned int cpu);
+int qcom_cpu_kill_legacy(unsigned int cpu);
 int msm_platform_secondary_init(unsigned int cpu);
 #else
 static inline int msm_platform_secondary_init(unsigned int cpu) { return 0; }
+static inline void qcom_cpu_die_legacy(unsigned int cpu) {}
+static inline int qcom_cpu_kill_legacy(unsigned int cpu) { return 0; }
 #endif
 
 enum msm_pm_time_stats_id {
diff --git a/include/trace/events/writeback.h b/include/trace/events/writeback.h
index 2ccd9cc..7bd8783 100644
--- a/include/trace/events/writeback.h
+++ b/include/trace/events/writeback.h
@@ -31,7 +31,7 @@
 
 #define WB_WORK_REASON							\
 	EM( WB_REASON_BACKGROUND,		"background")		\
-	EM( WB_REASON_TRY_TO_FREE_PAGES,	"try_to_free_pages")	\
+	EM( WB_REASON_VMSCAN,			"vmscan")		\
 	EM( WB_REASON_SYNC,			"sync")			\
 	EM( WB_REASON_PERIODIC,			"periodic")		\
 	EM( WB_REASON_LAPTOP_TIMER,		"laptop_timer")		\
diff --git a/include/uapi/linux/fs.h b/include/uapi/linux/fs.h
index dfcf371..fb1ec56 100644
--- a/include/uapi/linux/fs.h
+++ b/include/uapi/linux/fs.h
@@ -226,7 +226,6 @@
 #define BLKSECDISCARD _IO(0x12,125)
 #define BLKROTATIONAL _IO(0x12,126)
 #define BLKZEROOUT _IO(0x12,127)
-#define BLKGETSTPART _IO(0x12, 128)
 
 #define BMAP_IOCTL 1		/* obsolete - kept for compatibility */
 #define FIBMAP	   _IO(0x00,1)	/* bmap access */
diff --git a/include/uapi/linux/qg.h b/include/uapi/linux/qg.h
index 2c7b49a..2194e1f 100644
--- a/include/uapi/linux/qg.h
+++ b/include/uapi/linux/qg.h
@@ -14,11 +14,11 @@
 	QG_FIFO_TIME_DELTA,
 	QG_BATT_SOC,
 	QG_CC_SOC,
-	QG_RESERVED_3,
-	QG_RESERVED_4,
-	QG_RESERVED_5,
-	QG_RESERVED_6,
-	QG_RESERVED_7,
+	QG_ESR_CHARGE_DELTA,
+	QG_ESR_DISCHARGE_DELTA,
+	QG_ESR_CHARGE_SF,
+	QG_ESR_DISCHARGE_SF,
+	QG_FULL_SOC,
 	QG_RESERVED_8,
 	QG_RESERVED_9,
 	QG_RESERVED_10,
@@ -27,6 +27,11 @@
 
 #define QG_BATT_SOC QG_BATT_SOC
 #define QG_CC_SOC QG_CC_SOC
+#define QG_ESR_CHARGE_DELTA QG_ESR_CHARGE_DELTA
+#define QG_ESR_DISCHARGE_DELTA QG_ESR_DISCHARGE_DELTA
+#define QG_ESR_CHARGE_SF QG_ESR_CHARGE_SF
+#define QG_ESR_DISCHARGE_SF QG_ESR_DISCHARGE_SF
+#define QG_FULL_SOC QG_FULL_SOC
 
 struct fifo_data {
 	unsigned int			v;
diff --git a/include/uapi/linux/qseecom.h b/include/uapi/linux/qseecom.h
index f0a26b2..6de4c76 100644
--- a/include/uapi/linux/qseecom.h
+++ b/include/uapi/linux/qseecom.h
@@ -281,13 +281,6 @@
 	int flag;
 };
 
-struct qseecom_encdec_conf_t {
-	__le64 start_sector;
-	size_t fs_size;
-	int index;
-	int mode;
-};
-
 #define SG_ENTRY_SZ		sizeof(struct qseecom_sg_entry)
 #define SG_ENTRY_SZ_64BIT	sizeof(struct qseecom_sg_entry_64bit)
 
@@ -399,7 +392,4 @@
 #define QSEECOM_IOCTL_SET_ICE_INFO \
 	_IOWR(QSEECOM_IOC_MAGIC, 43, struct qseecom_ice_data_t)
 
-#define QSEECOM_IOCTL_SET_ENCDEC_INFO \
-	_IOWR(QSEECOM_IOC_MAGIC, 44, struct qseecom_encdec_conf_t)
-
 #endif /* _UAPI_QSEECOM_H_ */
diff --git a/kernel/events/callchain.c b/kernel/events/callchain.c
index 04988d64..c265f1c 100644
--- a/kernel/events/callchain.c
+++ b/kernel/events/callchain.c
@@ -129,14 +129,8 @@
 		goto exit;
 	}
 
-	if (count > 1) {
-		/* If the allocation failed, give up */
-		if (!callchain_cpus_entries)
-			err = -ENOMEM;
-		goto exit;
-	}
-
-	err = alloc_callchain_buffers();
+	if (count == 1)
+		err = alloc_callchain_buffers();
 exit:
 	if (err)
 		atomic_dec(&nr_callchain_events);
diff --git a/kernel/events/ring_buffer.c b/kernel/events/ring_buffer.c
index 257fa46..017f793 100644
--- a/kernel/events/ring_buffer.c
+++ b/kernel/events/ring_buffer.c
@@ -14,6 +14,7 @@
 #include <linux/slab.h>
 #include <linux/circ_buf.h>
 #include <linux/poll.h>
+#include <linux/nospec.h>
 
 #include "internal.h"
 
@@ -844,8 +845,10 @@
 			return NULL;
 
 		/* AUX space */
-		if (pgoff >= rb->aux_pgoff)
-			return virt_to_page(rb->aux_pages[pgoff - rb->aux_pgoff]);
+		if (pgoff >= rb->aux_pgoff) {
+			int aux_pgoff = array_index_nospec(pgoff - rb->aux_pgoff, rb->aux_nr_pages);
+			return virt_to_page(rb->aux_pages[aux_pgoff]);
+		}
 	}
 
 	return __perf_mmap_to_page(rb, pgoff);
diff --git a/kernel/exit.c b/kernel/exit.c
index 4b4f03a..2c18194 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -1680,6 +1680,10 @@
 			__WNOTHREAD|__WCLONE|__WALL))
 		return -EINVAL;
 
+	/* -INT_MIN is not defined */
+	if (upid == INT_MIN)
+		return -ESRCH;
+
 	if (upid == -1)
 		type = PIDTYPE_MAX;
 	else if (upid < 0) {
diff --git a/kernel/futex.c b/kernel/futex.c
index bb2265a..c3ea6f2 100644
--- a/kernel/futex.c
+++ b/kernel/futex.c
@@ -1458,6 +1458,45 @@
 	return ret;
 }
 
+static int futex_atomic_op_inuser(unsigned int encoded_op, u32 __user *uaddr)
+{
+	unsigned int op =	  (encoded_op & 0x70000000) >> 28;
+	unsigned int cmp =	  (encoded_op & 0x0f000000) >> 24;
+	int oparg = sign_extend32((encoded_op & 0x00fff000) >> 12, 11);
+	int cmparg = sign_extend32(encoded_op & 0x00000fff, 11);
+	int oldval, ret;
+
+	if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) {
+		if (oparg < 0 || oparg > 31)
+			return -EINVAL;
+		oparg = 1 << oparg;
+	}
+
+	if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
+		return -EFAULT;
+
+	ret = arch_futex_atomic_op_inuser(op, oparg, &oldval, uaddr);
+	if (ret)
+		return ret;
+
+	switch (cmp) {
+	case FUTEX_OP_CMP_EQ:
+		return oldval == cmparg;
+	case FUTEX_OP_CMP_NE:
+		return oldval != cmparg;
+	case FUTEX_OP_CMP_LT:
+		return oldval < cmparg;
+	case FUTEX_OP_CMP_GE:
+		return oldval >= cmparg;
+	case FUTEX_OP_CMP_LE:
+		return oldval <= cmparg;
+	case FUTEX_OP_CMP_GT:
+		return oldval > cmparg;
+	default:
+		return -ENOSYS;
+	}
+}
+
 /*
  * Wake up all waiters hashed on the physical page that is mapped
  * to this virtual address:
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index fff4170..5ad731a 100644
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -5710,6 +5710,9 @@
 	for_each_cpu(i, sched_group_cpus(sg))
 		state = min(state, idle_get_state_idx(cpu_rq(i)));
 
+	if (unlikely(state == INT_MAX))
+		return -EINVAL;
+
 	/* Take non-cpuidle idling into account (active idle/arch_cpu_idle()) */
 	state++;
 
@@ -5776,7 +5779,7 @@
  * The required scaling will be performed just one time, by the calling
  * functions, once we accumulated the contributons for all the SGs.
  */
-static void calc_sg_energy(struct energy_env *eenv)
+static int calc_sg_energy(struct energy_env *eenv)
 {
 	struct sched_group *sg = eenv->sg;
 	int busy_energy, idle_energy;
@@ -5805,6 +5808,11 @@
 
 		/* Compute IDLE energy */
 		idle_idx = group_idle_state(eenv, cpu_idx);
+		if (unlikely(idle_idx < 0))
+			return idle_idx;
+		if (idle_idx > sg->sge->nr_idle_states - 1)
+			idle_idx = sg->sge->nr_idle_states - 1;
+
 		idle_power = sg->sge->idle_states[idle_idx].power;
 
 		idle_energy   = SCHED_CAPACITY_SCALE - sg_util;
@@ -5813,6 +5821,7 @@
 		total_energy = busy_energy + idle_energy;
 		eenv->cpu[cpu_idx].energy += total_energy;
 	}
+	return 0;
 }
 
 /*
@@ -5874,7 +5883,8 @@
 				 * CPUs in the current visited SG.
 				 */
 				eenv->sg = sg;
-				calc_sg_energy(eenv);
+				if (calc_sg_energy(eenv))
+					return -EINVAL;
 
 				/* remove CPUs we have just visited */
 				if (!sd->child) {
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index 063dd22..5534be1 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -120,8 +120,9 @@
 				 struct ftrace_ops *op, struct pt_regs *regs);
 #else
 /* See comment below, where ftrace_ops_list_func is defined */
-static void ftrace_ops_no_ops(unsigned long ip, unsigned long parent_ip);
-#define ftrace_ops_list_func ((ftrace_func_t)ftrace_ops_no_ops)
+static void ftrace_ops_no_ops(unsigned long ip, unsigned long parent_ip,
+			      struct ftrace_ops *op, struct pt_regs *regs);
+#define ftrace_ops_list_func ftrace_ops_no_ops
 #endif
 
 /*
@@ -5309,7 +5310,8 @@
 	__ftrace_ops_list_func(ip, parent_ip, NULL, regs);
 }
 #else
-static void ftrace_ops_no_ops(unsigned long ip, unsigned long parent_ip)
+static void ftrace_ops_no_ops(unsigned long ip, unsigned long parent_ip,
+			      struct ftrace_ops *op, struct pt_regs *regs)
 {
 	__ftrace_ops_list_func(ip, parent_ip, NULL, NULL);
 }
@@ -5735,14 +5737,17 @@
 	fgraph_graph_time = enable;
 }
 
+void ftrace_graph_return_stub(struct ftrace_graph_ret *trace)
+{
+}
+
 int ftrace_graph_entry_stub(struct ftrace_graph_ent *trace)
 {
 	return 0;
 }
 
 /* The callbacks that hook a function */
-trace_func_graph_ret_t ftrace_graph_return =
-			(trace_func_graph_ret_t)ftrace_stub;
+trace_func_graph_ret_t ftrace_graph_return = ftrace_graph_return_stub;
 trace_func_graph_ent_t ftrace_graph_entry = ftrace_graph_entry_stub;
 static trace_func_graph_ent_t __ftrace_graph_entry = ftrace_graph_entry_stub;
 
@@ -5970,7 +5975,7 @@
 		goto out;
 
 	ftrace_graph_active--;
-	ftrace_graph_return = (trace_func_graph_ret_t)ftrace_stub;
+	ftrace_graph_return = ftrace_graph_return_stub;
 	ftrace_graph_entry = ftrace_graph_entry_stub;
 	__ftrace_graph_entry = ftrace_graph_entry_stub;
 	ftrace_shutdown(&graph_ops, FTRACE_STOP_FUNC_RET);
diff --git a/kernel/trace/trace_events_filter.c b/kernel/trace/trace_events_filter.c
index 0193f58..e35a411 100644
--- a/kernel/trace/trace_events_filter.c
+++ b/kernel/trace/trace_events_filter.c
@@ -322,6 +322,9 @@
 
 static int regex_match_front(char *str, struct regex *r, int len)
 {
+	if (len < r->len)
+		return 0;
+
 	if (strncmp(str, r->pattern, r->len) == 0)
 		return 1;
 	return 0;
diff --git a/kernel/trace/trace_uprobe.c b/kernel/trace/trace_uprobe.c
index bc6c6ec..83afbf2 100644
--- a/kernel/trace/trace_uprobe.c
+++ b/kernel/trace/trace_uprobe.c
@@ -149,6 +149,8 @@
 		return;
 
 	ret = strncpy_from_user(dst, src, maxlen);
+	if (ret == maxlen)
+		dst[--ret] = '\0';
 
 	if (ret < 0) {	/* Failed to fetch string */
 		((u8 *)get_rloc_data(dest))[0] = '\0';
diff --git a/mm/gup.c b/mm/gup.c
index 6c3b4e8..be4ccdd 100644
--- a/mm/gup.c
+++ b/mm/gup.c
@@ -430,6 +430,9 @@
 	if (vm_flags & (VM_IO | VM_PFNMAP))
 		return -EFAULT;
 
+	if (gup_flags & FOLL_ANON && !vma_is_anonymous(vma))
+		return -EFAULT;
+
 	if (write) {
 		if (!(vm_flags & VM_WRITE)) {
 			if (!(gup_flags & FOLL_FORCE))
diff --git a/mm/swap.c b/mm/swap.c
index 4dcf852..6f22754 100644
--- a/mm/swap.c
+++ b/mm/swap.c
@@ -208,9 +208,10 @@
 {
 	int *pgmoved = arg;
 
-	if (PageLRU(page) && !PageActive(page) && !PageUnevictable(page)) {
-		enum lru_list lru = page_lru_base_type(page);
-		list_move_tail(&page->lru, &lruvec->lists[lru]);
+	if (PageLRU(page) && !PageUnevictable(page)) {
+		del_page_from_lru_list(page, lruvec, page_lru(page));
+		ClearPageActive(page);
+		add_page_to_lru_list_tail(page, lruvec, page_lru(page));
 		(*pgmoved)++;
 	}
 }
@@ -234,7 +235,7 @@
  */
 void rotate_reclaimable_page(struct page *page)
 {
-	if (!PageLocked(page) && !PageDirty(page) && !PageActive(page) &&
+	if (!PageLocked(page) && !PageDirty(page) &&
 	    !PageUnevictable(page) && PageLRU(page)) {
 		struct pagevec *pvec;
 		unsigned long flags;
diff --git a/mm/vmscan.c b/mm/vmscan.c
index 99d5c9d..c8e300c 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -1058,6 +1058,15 @@
 		 *    throttling so we could easily OOM just because too many
 		 *    pages are in writeback and there is nothing else to
 		 *    reclaim. Wait for the writeback to complete.
+		 *
+		 * In cases 1) and 2) we activate the pages to get them out of
+		 * the way while we continue scanning for clean pages on the
+		 * inactive list and refilling from the active list. The
+		 * observation here is that waiting for disk writes is more
+		 * expensive than potentially causing reloads down the line.
+		 * Since they're marked for immediate reclaim, they won't put
+		 * memory pressure on the cache working set any longer than it
+		 * takes to write them to disk.
 		 */
 		if (PageWriteback(page)) {
 			/* Case 1 above */
@@ -1065,7 +1074,7 @@
 			    PageReclaim(page) &&
 			    (pgdat && test_bit(PGDAT_WRITEBACK, &pgdat->flags))) {
 				nr_immediate++;
-				goto keep_locked;
+				goto activate_locked;
 
 			/* Case 2 above */
 			} else if (sane_reclaim(sc) ||
@@ -1083,7 +1092,7 @@
 				 */
 				SetPageReclaim(page);
 				nr_writeback++;
-				goto keep_locked;
+				goto activate_locked;
 
 			/* Case 3 above */
 			} else {
@@ -1154,14 +1163,18 @@
 
 		if (PageDirty(page)) {
 			/*
-			 * Only kswapd can writeback filesystem pages to
-			 * avoid risk of stack overflow but only writeback
-			 * if many dirty pages have been encountered.
+			 * Only kswapd can writeback filesystem pages
+			 * to avoid risk of stack overflow. But avoid
+			 * injecting inefficient single-page IO into
+			 * flusher writeback as much as possible: only
+			 * write pages when we've encountered many
+			 * dirty pages, and when we've already scanned
+			 * the rest of the LRU for clean pages and see
+			 * the same dirty pages again (PageReclaim).
 			 */
 			if (page_is_file_cache(page) &&
-					(!current_is_kswapd() ||
-					(pgdat &&
-					 !test_bit(PGDAT_DIRTY, &pgdat->flags)))) {
+			    (!current_is_kswapd() || !PageReclaim(page) ||
+			     !test_bit(PGDAT_DIRTY, &pgdat->flags))) {
 				/*
 				 * Immediately reclaim when written back.
 				 * Similar in principal to deactivate_page()
@@ -1171,7 +1184,7 @@
 				inc_node_page_state(page, NR_VMSCAN_IMMEDIATE);
 				SetPageReclaim(page);
 
-				goto keep_locked;
+				goto activate_locked;
 			}
 
 			if (references == PAGEREF_RECLAIM_CLEAN)
@@ -1886,6 +1899,20 @@
 		set_bit(PGDAT_WRITEBACK, &pgdat->flags);
 
 	/*
+	 * If dirty pages are scanned that are not queued for IO, it
+	 * implies that flushers are not doing their job. This can
+	 * happen when memory pressure pushes dirty pages to the end of
+	 * the LRU before the dirty limits are breached and the dirty
+	 * data has expired. It can also happen when the proportion of
+	 * dirty pages grows not through writes but through memory
+	 * pressure reclaiming all the clean cache. And in some cases,
+	 * the flushers simply cannot keep up with the allocation
+	 * rate. Nudge the flusher threads in case they are asleep.
+	 */
+	if (nr_unqueued_dirty == nr_taken)
+		wakeup_flusher_threads(0, WB_REASON_VMSCAN);
+
+	/*
 	 * Legacy memcg will stall in page writeback so avoid forcibly
 	 * stalling here.
 	 */
@@ -1897,12 +1924,7 @@
 		if (nr_dirty && nr_dirty == nr_congested)
 			set_bit(PGDAT_CONGESTED, &pgdat->flags);
 
-		/*
-		 * If dirty pages are scanned that are not queued for IO, it
-		 * implies that flushers are not keeping up. In this case, flag
-		 * the pgdat PGDAT_DIRTY and kswapd will start writing pages from
-		 * reclaim context.
-		 */
+		/* Allow kswapd to start writing pages during reclaim. */
 		if (nr_unqueued_dirty == nr_taken)
 			set_bit(PGDAT_DIRTY, &pgdat->flags);
 
@@ -2813,8 +2835,6 @@
 					  struct scan_control *sc)
 {
 	int initial_priority = sc->priority;
-	unsigned long total_scanned = 0;
-	unsigned long writeback_threshold;
 retry:
 	delayacct_freepages_start();
 
@@ -2827,7 +2847,6 @@
 		sc->nr_scanned = 0;
 		shrink_zones(zonelist, sc);
 
-		total_scanned += sc->nr_scanned;
 		if (sc->nr_reclaimed >= sc->nr_to_reclaim)
 			break;
 
@@ -2840,20 +2859,6 @@
 		 */
 		if (sc->priority < DEF_PRIORITY - 2)
 			sc->may_writepage = 1;
-
-		/*
-		 * Try to write back as many pages as we just scanned.  This
-		 * tends to cause slow streaming writers to write data to the
-		 * disk smoothly, at the dirtying rate, which is nice.   But
-		 * that's undesirable in laptop mode, where we *want* lumpy
-		 * writeout.  So in laptop mode, write out the whole world.
-		 */
-		writeback_threshold = sc->nr_to_reclaim + sc->nr_to_reclaim / 2;
-		if (total_scanned > writeback_threshold) {
-			wakeup_flusher_threads(laptop_mode ? 0 : total_scanned,
-						WB_REASON_TRY_TO_FREE_PAGES);
-			sc->may_writepage = 1;
-		}
 	} while (--sc->priority >= 0);
 
 	delayacct_freepages_end();
diff --git a/net/atm/lec.c b/net/atm/lec.c
index 5d26938..1e84c52 100644
--- a/net/atm/lec.c
+++ b/net/atm/lec.c
@@ -41,6 +41,9 @@
 #include <linux/module.h>
 #include <linux/init.h>
 
+/* Hardening for Spectre-v1 */
+#include <linux/nospec.h>
+
 #include "lec.h"
 #include "lec_arpc.h"
 #include "resources.h"
@@ -697,8 +700,10 @@
 	bytes_left = copy_from_user(&ioc_data, arg, sizeof(struct atmlec_ioc));
 	if (bytes_left != 0)
 		pr_info("copy from user failed for %d bytes\n", bytes_left);
-	if (ioc_data.dev_num < 0 || ioc_data.dev_num >= MAX_LEC_ITF ||
-	    !dev_lec[ioc_data.dev_num])
+	if (ioc_data.dev_num < 0 || ioc_data.dev_num >= MAX_LEC_ITF)
+		return -EINVAL;
+	ioc_data.dev_num = array_index_nospec(ioc_data.dev_num, MAX_LEC_ITF);
+	if (!dev_lec[ioc_data.dev_num])
 		return -EINVAL;
 	vpriv = kmalloc(sizeof(struct lec_vcc_priv), GFP_KERNEL);
 	if (!vpriv)
diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c
index 9218931..f57de0a 100644
--- a/net/bridge/br_if.c
+++ b/net/bridge/br_if.c
@@ -504,8 +504,8 @@
 	if (dev->netdev_ops->ndo_start_xmit == br_dev_xmit)
 		return -ELOOP;
 
-	/* Device is already being bridged */
-	if (br_port_exists(dev))
+	/* Device has master upper dev */
+	if (netdev_master_upper_dev_get(dev))
 		return -EBUSY;
 
 	/* No bridging devices that dislike that (e.g. wireless) */
diff --git a/net/compat.c b/net/compat.c
index a96fd2f..73671e6 100644
--- a/net/compat.c
+++ b/net/compat.c
@@ -372,7 +372,8 @@
 	    optname == SO_ATTACH_REUSEPORT_CBPF)
 		return do_set_attach_filter(sock, level, optname,
 					    optval, optlen);
-	if (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO)
+	if (!COMPAT_USE_64BIT_TIME &&
+	    (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO))
 		return do_set_sock_timeout(sock, level, optname, optval, optlen);
 
 	return sock_setsockopt(sock, level, optname, optval, optlen);
@@ -437,7 +438,8 @@
 static int compat_sock_getsockopt(struct socket *sock, int level, int optname,
 				char __user *optval, int __user *optlen)
 {
-	if (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO)
+	if (!COMPAT_USE_64BIT_TIME &&
+	    (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO))
 		return do_get_sock_timeout(sock, level, optname, optval, optlen);
 	return sock_getsockopt(sock, level, optname, optval, optlen);
 }
diff --git a/net/core/dev_addr_lists.c b/net/core/dev_addr_lists.c
index c0548d2..e3e6a3e 100644
--- a/net/core/dev_addr_lists.c
+++ b/net/core/dev_addr_lists.c
@@ -57,8 +57,8 @@
 		return -EINVAL;
 
 	list_for_each_entry(ha, &list->list, list) {
-		if (!memcmp(ha->addr, addr, addr_len) &&
-		    ha->type == addr_type) {
+		if (ha->type == addr_type &&
+		    !memcmp(ha->addr, addr, addr_len)) {
 			if (global) {
 				/* check if addr is already used as global */
 				if (ha->global_use)
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index e2136eb..9c2e60e 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -909,6 +909,7 @@
 	n->hdr_len = skb->nohdr ? skb_headroom(skb) : skb->hdr_len;
 	n->cloned = 1;
 	n->nohdr = 0;
+	n->peeked = 0;
 	n->destructor = NULL;
 	C(tail);
 	C(end);
diff --git a/net/dccp/ccids/ccid2.c b/net/dccp/ccids/ccid2.c
index 7753681..86a2ed0 100644
--- a/net/dccp/ccids/ccid2.c
+++ b/net/dccp/ccids/ccid2.c
@@ -126,6 +126,16 @@
 						  DCCPF_SEQ_WMAX));
 }
 
+static void dccp_tasklet_schedule(struct sock *sk)
+{
+	struct tasklet_struct *t = &dccp_sk(sk)->dccps_xmitlet;
+
+	if (!test_and_set_bit(TASKLET_STATE_SCHED, &t->state)) {
+		sock_hold(sk);
+		__tasklet_schedule(t);
+	}
+}
+
 static void ccid2_hc_tx_rto_expire(unsigned long data)
 {
 	struct sock *sk = (struct sock *)data;
@@ -166,7 +176,7 @@
 
 	/* if we were blocked before, we may now send cwnd=1 packet */
 	if (sender_was_blocked)
-		tasklet_schedule(&dccp_sk(sk)->dccps_xmitlet);
+		dccp_tasklet_schedule(sk);
 	/* restart backed-off timer */
 	sk_reset_timer(sk, &hc->tx_rtotimer, jiffies + hc->tx_rto);
 out:
@@ -706,7 +716,7 @@
 done:
 	/* check if incoming Acks allow pending packets to be sent */
 	if (sender_was_blocked && !ccid2_cwnd_network_limited(hc))
-		tasklet_schedule(&dccp_sk(sk)->dccps_xmitlet);
+		dccp_tasklet_schedule(sk);
 	dccp_ackvec_parsed_cleanup(&hc->tx_av_chunks);
 }
 
diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c
index 8c7799cd..6697b18 100644
--- a/net/dccp/ipv4.c
+++ b/net/dccp/ipv4.c
@@ -620,6 +620,7 @@
 	ireq = inet_rsk(req);
 	sk_rcv_saddr_set(req_to_sk(req), ip_hdr(skb)->daddr);
 	sk_daddr_set(req_to_sk(req), ip_hdr(skb)->saddr);
+	ireq->ir_mark = inet_request_mark(sk, skb);
 	ireq->ireq_family = AF_INET;
 	ireq->ir_iif = sk->sk_bound_dev_if;
 
diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c
index 28e8252..6cbcf39 100644
--- a/net/dccp/ipv6.c
+++ b/net/dccp/ipv6.c
@@ -349,6 +349,7 @@
 	ireq->ir_v6_rmt_addr = ipv6_hdr(skb)->saddr;
 	ireq->ir_v6_loc_addr = ipv6_hdr(skb)->daddr;
 	ireq->ireq_family = AF_INET6;
+	ireq->ir_mark = inet_request_mark(sk, skb);
 
 	if (ipv6_opt_accepted(sk, skb, IP6CB(skb)) ||
 	    np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo ||
diff --git a/net/dccp/timer.c b/net/dccp/timer.c
index 3a2c340..2a952cb 100644
--- a/net/dccp/timer.c
+++ b/net/dccp/timer.c
@@ -230,12 +230,12 @@
 	else
 		dccp_write_xmit(sk);
 	bh_unlock_sock(sk);
+	sock_put(sk);
 }
 
 static void dccp_write_xmit_timer(unsigned long data)
 {
 	dccp_write_xmitlet(data);
-	sock_put((struct sock *)data);
 }
 
 void dccp_init_xmit_timers(struct sock *sk)
diff --git a/net/ipv4/inet_timewait_sock.c b/net/ipv4/inet_timewait_sock.c
index ddcd56c..a6b34ac 100644
--- a/net/ipv4/inet_timewait_sock.c
+++ b/net/ipv4/inet_timewait_sock.c
@@ -182,6 +182,7 @@
 		tw->tw_dport	    = inet->inet_dport;
 		tw->tw_family	    = sk->sk_family;
 		tw->tw_reuse	    = sk->sk_reuse;
+		tw->tw_reuseport    = sk->sk_reuseport;
 		tw->tw_hash	    = sk->sk_hash;
 		tw->tw_ipv6only	    = 0;
 		tw->tw_transparent  = inet->transparent;
diff --git a/net/ipv4/ping.c b/net/ipv4/ping.c
index 93bfadf..8fa153c 100644
--- a/net/ipv4/ping.c
+++ b/net/ipv4/ping.c
@@ -775,8 +775,10 @@
 	ipc.addr = faddr = daddr;
 
 	if (ipc.opt && ipc.opt->opt.srr) {
-		if (!daddr)
-			return -EINVAL;
+		if (!daddr) {
+			err = -EINVAL;
+			goto out_free;
+		}
 		faddr = ipc.opt->opt.faddr;
 	}
 	tos = get_rttos(&ipc, inet);
@@ -842,6 +844,7 @@
 
 out:
 	ip_rt_put(rt);
+out_free:
 	if (free)
 		kfree(ipc.opt);
 	if (!err) {
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 6e6278b..fdfaaf0 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -1146,7 +1146,8 @@
 	lock_sock(sk);
 
 	flags = msg->msg_flags;
-	if (unlikely(flags & MSG_FASTOPEN || inet_sk(sk)->defer_connect)) {
+	if (unlikely(flags & MSG_FASTOPEN || inet_sk(sk)->defer_connect) &&
+	    !tp->repair) {
 		err = tcp_sendmsg_fastopen(sk, msg, &copied_syn, size);
 		if (err == -EINPROGRESS && copied_syn > 0)
 			goto out;
@@ -2558,7 +2559,7 @@
 	case TCP_REPAIR_QUEUE:
 		if (!tp->repair)
 			err = -EPERM;
-		else if (val < TCP_QUEUES_NR)
+		else if ((unsigned int)val < TCP_QUEUES_NR)
 			tp->repair_queue = val;
 		else
 			err = -EINVAL;
diff --git a/net/ipv4/tcp_bbr.c b/net/ipv4/tcp_bbr.c
index 8ec6053..91698595 100644
--- a/net/ipv4/tcp_bbr.c
+++ b/net/ipv4/tcp_bbr.c
@@ -773,7 +773,9 @@
 			}
 		}
 	}
-	bbr->idle_restart = 0;
+	/* Restart after idle ends only once we process a new S/ACK for data */
+	if (rs->delivered > 0)
+		bbr->idle_restart = 0;
 }
 
 static void bbr_update_model(struct sock *sk, const struct rate_sample *rs)
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index 5af27b9..885cc39 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -987,8 +987,10 @@
 	sock_tx_timestamp(sk, ipc.sockc.tsflags, &ipc.tx_flags);
 
 	if (ipc.opt && ipc.opt->opt.srr) {
-		if (!daddr)
-			return -EINVAL;
+		if (!daddr) {
+			err = -EINVAL;
+			goto out_free;
+		}
 		faddr = ipc.opt->opt.faddr;
 		connected = 0;
 	}
@@ -1096,6 +1098,7 @@
 
 out:
 	ip_rt_put(rt);
+out_free:
 	if (free)
 		kfree(ipc.opt);
 	if (!err)
diff --git a/net/kcm/kcmsock.c b/net/kcm/kcmsock.c
index 63e6d08..cc306de 100644
--- a/net/kcm/kcmsock.c
+++ b/net/kcm/kcmsock.c
@@ -1424,6 +1424,7 @@
 	 */
 	if (csk->sk_user_data) {
 		write_unlock_bh(&csk->sk_callback_lock);
+		strp_stop(&psock->strp);
 		strp_done(&psock->strp);
 		kmem_cache_free(kcm_psockp, psock);
 		err = -EALREADY;
diff --git a/net/l2tp/l2tp_netlink.c b/net/l2tp/l2tp_netlink.c
index ce12384..ee03bc8 100644
--- a/net/l2tp/l2tp_netlink.c
+++ b/net/l2tp/l2tp_netlink.c
@@ -750,8 +750,6 @@
 
 	if ((session->ifname[0] &&
 	     nla_put_string(skb, L2TP_ATTR_IFNAME, session->ifname)) ||
-	    (session->offset &&
-	     nla_put_u16(skb, L2TP_ATTR_OFFSET, session->offset)) ||
 	    (session->cookie_len &&
 	     nla_put(skb, L2TP_ATTR_COOKIE, session->cookie_len,
 		     &session->cookie[0])) ||
diff --git a/net/llc/af_llc.c b/net/llc/af_llc.c
index d6bc5f2a..85aae8c 100644
--- a/net/llc/af_llc.c
+++ b/net/llc/af_llc.c
@@ -926,6 +926,9 @@
 	if (size > llc->dev->mtu)
 		size = llc->dev->mtu;
 	copied = size - hdrlen;
+	rc = -EINVAL;
+	if (copied < 0)
+		goto release;
 	release_sock(sk);
 	skb = sock_alloc_send_skb(sk, size, noblock, &rc);
 	lock_sock(sk);
diff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c
index 74d1195..c5f2350 100644
--- a/net/netfilter/ipvs/ip_vs_ctl.c
+++ b/net/netfilter/ipvs/ip_vs_ctl.c
@@ -2393,11 +2393,7 @@
 			strlcpy(cfg.mcast_ifn, dm->mcast_ifn,
 				sizeof(cfg.mcast_ifn));
 			cfg.syncid = dm->syncid;
-			rtnl_lock();
-			mutex_lock(&ipvs->sync_mutex);
 			ret = start_sync_thread(ipvs, &cfg, dm->state);
-			mutex_unlock(&ipvs->sync_mutex);
-			rtnl_unlock();
 		} else {
 			mutex_lock(&ipvs->sync_mutex);
 			ret = stop_sync_thread(ipvs, dm->state);
@@ -3495,12 +3491,8 @@
 	if (ipvs->mixed_address_family_dests > 0)
 		return -EINVAL;
 
-	rtnl_lock();
-	mutex_lock(&ipvs->sync_mutex);
 	ret = start_sync_thread(ipvs, &c,
 				nla_get_u32(attrs[IPVS_DAEMON_ATTR_STATE]));
-	mutex_unlock(&ipvs->sync_mutex);
-	rtnl_unlock();
 	return ret;
 }
 
diff --git a/net/netfilter/ipvs/ip_vs_sync.c b/net/netfilter/ipvs/ip_vs_sync.c
index 9350530..5fbf4b2 100644
--- a/net/netfilter/ipvs/ip_vs_sync.c
+++ b/net/netfilter/ipvs/ip_vs_sync.c
@@ -48,6 +48,7 @@
 #include <linux/kthread.h>
 #include <linux/wait.h>
 #include <linux/kernel.h>
+#include <linux/sched.h>
 
 #include <asm/unaligned.h>		/* Used for ntoh_seq and hton_seq */
 
@@ -1359,15 +1360,9 @@
 /*
  *      Specifiy default interface for outgoing multicasts
  */
-static int set_mcast_if(struct sock *sk, char *ifname)
+static int set_mcast_if(struct sock *sk, struct net_device *dev)
 {
-	struct net_device *dev;
 	struct inet_sock *inet = inet_sk(sk);
-	struct net *net = sock_net(sk);
-
-	dev = __dev_get_by_name(net, ifname);
-	if (!dev)
-		return -ENODEV;
 
 	if (sk->sk_bound_dev_if && dev->ifindex != sk->sk_bound_dev_if)
 		return -EINVAL;
@@ -1395,19 +1390,14 @@
  *      in the in_addr structure passed in as a parameter.
  */
 static int
-join_mcast_group(struct sock *sk, struct in_addr *addr, char *ifname)
+join_mcast_group(struct sock *sk, struct in_addr *addr, struct net_device *dev)
 {
-	struct net *net = sock_net(sk);
 	struct ip_mreqn mreq;
-	struct net_device *dev;
 	int ret;
 
 	memset(&mreq, 0, sizeof(mreq));
 	memcpy(&mreq.imr_multiaddr, addr, sizeof(struct in_addr));
 
-	dev = __dev_get_by_name(net, ifname);
-	if (!dev)
-		return -ENODEV;
 	if (sk->sk_bound_dev_if && dev->ifindex != sk->sk_bound_dev_if)
 		return -EINVAL;
 
@@ -1422,15 +1412,10 @@
 
 #ifdef CONFIG_IP_VS_IPV6
 static int join_mcast_group6(struct sock *sk, struct in6_addr *addr,
-			     char *ifname)
+			     struct net_device *dev)
 {
-	struct net *net = sock_net(sk);
-	struct net_device *dev;
 	int ret;
 
-	dev = __dev_get_by_name(net, ifname);
-	if (!dev)
-		return -ENODEV;
 	if (sk->sk_bound_dev_if && dev->ifindex != sk->sk_bound_dev_if)
 		return -EINVAL;
 
@@ -1442,24 +1427,18 @@
 }
 #endif
 
-static int bind_mcastif_addr(struct socket *sock, char *ifname)
+static int bind_mcastif_addr(struct socket *sock, struct net_device *dev)
 {
-	struct net *net = sock_net(sock->sk);
-	struct net_device *dev;
 	__be32 addr;
 	struct sockaddr_in sin;
 
-	dev = __dev_get_by_name(net, ifname);
-	if (!dev)
-		return -ENODEV;
-
 	addr = inet_select_addr(dev, 0, RT_SCOPE_UNIVERSE);
 	if (!addr)
 		pr_err("You probably need to specify IP address on "
 		       "multicast interface.\n");
 
 	IP_VS_DBG(7, "binding socket with (%s) %pI4\n",
-		  ifname, &addr);
+		  dev->name, &addr);
 
 	/* Now bind the socket with the address of multicast interface */
 	sin.sin_family	     = AF_INET;
@@ -1492,7 +1471,8 @@
 /*
  *      Set up sending multicast socket over UDP
  */
-static struct socket *make_send_sock(struct netns_ipvs *ipvs, int id)
+static int make_send_sock(struct netns_ipvs *ipvs, int id,
+			  struct net_device *dev, struct socket **sock_ret)
 {
 	/* multicast addr */
 	union ipvs_sockaddr mcast_addr;
@@ -1504,9 +1484,10 @@
 				  IPPROTO_UDP, &sock);
 	if (result < 0) {
 		pr_err("Error during creation of socket; terminating\n");
-		return ERR_PTR(result);
+		goto error;
 	}
-	result = set_mcast_if(sock->sk, ipvs->mcfg.mcast_ifn);
+	*sock_ret = sock;
+	result = set_mcast_if(sock->sk, dev);
 	if (result < 0) {
 		pr_err("Error setting outbound mcast interface\n");
 		goto error;
@@ -1521,7 +1502,7 @@
 		set_sock_size(sock->sk, 1, result);
 
 	if (AF_INET == ipvs->mcfg.mcast_af)
-		result = bind_mcastif_addr(sock, ipvs->mcfg.mcast_ifn);
+		result = bind_mcastif_addr(sock, dev);
 	else
 		result = 0;
 	if (result < 0) {
@@ -1537,19 +1518,18 @@
 		goto error;
 	}
 
-	return sock;
+	return 0;
 
 error:
-	sock_release(sock);
-	return ERR_PTR(result);
+	return result;
 }
 
 
 /*
  *      Set up receiving multicast socket over UDP
  */
-static struct socket *make_receive_sock(struct netns_ipvs *ipvs, int id,
-					int ifindex)
+static int make_receive_sock(struct netns_ipvs *ipvs, int id,
+			     struct net_device *dev, struct socket **sock_ret)
 {
 	/* multicast addr */
 	union ipvs_sockaddr mcast_addr;
@@ -1561,8 +1541,9 @@
 				  IPPROTO_UDP, &sock);
 	if (result < 0) {
 		pr_err("Error during creation of socket; terminating\n");
-		return ERR_PTR(result);
+		goto error;
 	}
+	*sock_ret = sock;
 	/* it is equivalent to the REUSEADDR option in user-space */
 	sock->sk->sk_reuse = SK_CAN_REUSE;
 	result = sysctl_sync_sock_size(ipvs);
@@ -1570,7 +1551,7 @@
 		set_sock_size(sock->sk, 0, result);
 
 	get_mcast_sockaddr(&mcast_addr, &salen, &ipvs->bcfg, id);
-	sock->sk->sk_bound_dev_if = ifindex;
+	sock->sk->sk_bound_dev_if = dev->ifindex;
 	result = sock->ops->bind(sock, (struct sockaddr *)&mcast_addr, salen);
 	if (result < 0) {
 		pr_err("Error binding to the multicast addr\n");
@@ -1581,21 +1562,20 @@
 #ifdef CONFIG_IP_VS_IPV6
 	if (ipvs->bcfg.mcast_af == AF_INET6)
 		result = join_mcast_group6(sock->sk, &mcast_addr.in6.sin6_addr,
-					   ipvs->bcfg.mcast_ifn);
+					   dev);
 	else
 #endif
 		result = join_mcast_group(sock->sk, &mcast_addr.in.sin_addr,
-					  ipvs->bcfg.mcast_ifn);
+					  dev);
 	if (result < 0) {
 		pr_err("Error joining to the multicast group\n");
 		goto error;
 	}
 
-	return sock;
+	return 0;
 
 error:
-	sock_release(sock);
-	return ERR_PTR(result);
+	return result;
 }
 
 
@@ -1780,13 +1760,12 @@
 int start_sync_thread(struct netns_ipvs *ipvs, struct ipvs_sync_daemon_cfg *c,
 		      int state)
 {
-	struct ip_vs_sync_thread_data *tinfo;
+	struct ip_vs_sync_thread_data *tinfo = NULL;
 	struct task_struct **array = NULL, *task;
-	struct socket *sock;
 	struct net_device *dev;
 	char *name;
 	int (*threadfn)(void *data);
-	int id, count, hlen;
+	int id = 0, count, hlen;
 	int result = -ENOMEM;
 	u16 mtu, min_mtu;
 
@@ -1794,6 +1773,18 @@
 	IP_VS_DBG(7, "Each ip_vs_sync_conn entry needs %Zd bytes\n",
 		  sizeof(struct ip_vs_sync_conn_v0));
 
+	/* Do not hold one mutex and then to block on another */
+	for (;;) {
+		rtnl_lock();
+		if (mutex_trylock(&ipvs->sync_mutex))
+			break;
+		rtnl_unlock();
+		mutex_lock(&ipvs->sync_mutex);
+		if (rtnl_trylock())
+			break;
+		mutex_unlock(&ipvs->sync_mutex);
+	}
+
 	if (!ipvs->sync_state) {
 		count = clamp(sysctl_sync_ports(ipvs), 1, IPVS_SYNC_PORTS_MAX);
 		ipvs->threads_mask = count - 1;
@@ -1812,7 +1803,8 @@
 	dev = __dev_get_by_name(ipvs->net, c->mcast_ifn);
 	if (!dev) {
 		pr_err("Unknown mcast interface: %s\n", c->mcast_ifn);
-		return -ENODEV;
+		result = -ENODEV;
+		goto out_early;
 	}
 	hlen = (AF_INET6 == c->mcast_af) ?
 	       sizeof(struct ipv6hdr) + sizeof(struct udphdr) :
@@ -1829,26 +1821,30 @@
 		c->sync_maxlen = mtu - hlen;
 
 	if (state == IP_VS_STATE_MASTER) {
+		result = -EEXIST;
 		if (ipvs->ms)
-			return -EEXIST;
+			goto out_early;
 
 		ipvs->mcfg = *c;
 		name = "ipvs-m:%d:%d";
 		threadfn = sync_thread_master;
 	} else if (state == IP_VS_STATE_BACKUP) {
+		result = -EEXIST;
 		if (ipvs->backup_threads)
-			return -EEXIST;
+			goto out_early;
 
 		ipvs->bcfg = *c;
 		name = "ipvs-b:%d:%d";
 		threadfn = sync_thread_backup;
 	} else {
-		return -EINVAL;
+		result = -EINVAL;
+		goto out_early;
 	}
 
 	if (state == IP_VS_STATE_MASTER) {
 		struct ipvs_master_sync_state *ms;
 
+		result = -ENOMEM;
 		ipvs->ms = kzalloc(count * sizeof(ipvs->ms[0]), GFP_KERNEL);
 		if (!ipvs->ms)
 			goto out;
@@ -1864,39 +1860,38 @@
 	} else {
 		array = kzalloc(count * sizeof(struct task_struct *),
 				GFP_KERNEL);
+		result = -ENOMEM;
 		if (!array)
 			goto out;
 	}
 
-	tinfo = NULL;
 	for (id = 0; id < count; id++) {
-		if (state == IP_VS_STATE_MASTER)
-			sock = make_send_sock(ipvs, id);
-		else
-			sock = make_receive_sock(ipvs, id, dev->ifindex);
-		if (IS_ERR(sock)) {
-			result = PTR_ERR(sock);
-			goto outtinfo;
-		}
+		result = -ENOMEM;
 		tinfo = kmalloc(sizeof(*tinfo), GFP_KERNEL);
 		if (!tinfo)
-			goto outsocket;
+			goto out;
 		tinfo->ipvs = ipvs;
-		tinfo->sock = sock;
+		tinfo->sock = NULL;
 		if (state == IP_VS_STATE_BACKUP) {
 			tinfo->buf = kmalloc(ipvs->bcfg.sync_maxlen,
 					     GFP_KERNEL);
 			if (!tinfo->buf)
-				goto outtinfo;
+				goto out;
 		} else {
 			tinfo->buf = NULL;
 		}
 		tinfo->id = id;
+		if (state == IP_VS_STATE_MASTER)
+			result = make_send_sock(ipvs, id, dev, &tinfo->sock);
+		else
+			result = make_receive_sock(ipvs, id, dev, &tinfo->sock);
+		if (result < 0)
+			goto out;
 
 		task = kthread_run(threadfn, tinfo, name, ipvs->gen, id);
 		if (IS_ERR(task)) {
 			result = PTR_ERR(task);
-			goto outtinfo;
+			goto out;
 		}
 		tinfo = NULL;
 		if (state == IP_VS_STATE_MASTER)
@@ -1913,20 +1908,20 @@
 	ipvs->sync_state |= state;
 	spin_unlock_bh(&ipvs->sync_buff_lock);
 
+	mutex_unlock(&ipvs->sync_mutex);
+	rtnl_unlock();
+
 	/* increase the module use count */
 	ip_vs_use_count_inc();
 
 	return 0;
 
-outsocket:
-	sock_release(sock);
-
-outtinfo:
-	if (tinfo) {
-		sock_release(tinfo->sock);
-		kfree(tinfo->buf);
-		kfree(tinfo);
-	}
+out:
+	/* We do not need RTNL lock anymore, release it here so that
+	 * sock_release below and in the kthreads can use rtnl_lock
+	 * to leave the mcast group.
+	 */
+	rtnl_unlock();
 	count = id;
 	while (count-- > 0) {
 		if (state == IP_VS_STATE_MASTER)
@@ -1934,13 +1929,23 @@
 		else
 			kthread_stop(array[count]);
 	}
-	kfree(array);
-
-out:
 	if (!(ipvs->sync_state & IP_VS_STATE_MASTER)) {
 		kfree(ipvs->ms);
 		ipvs->ms = NULL;
 	}
+	mutex_unlock(&ipvs->sync_mutex);
+	if (tinfo) {
+		if (tinfo->sock)
+			sock_release(tinfo->sock);
+		kfree(tinfo->buf);
+		kfree(tinfo);
+	}
+	kfree(array);
+	return result;
+
+out_early:
+	mutex_unlock(&ipvs->sync_mutex);
+	rtnl_unlock();
 	return result;
 }
 
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index 1e97b8d..15e6e7b 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -1795,6 +1795,8 @@
 
 	if (msg->msg_namelen) {
 		err = -EINVAL;
+		if (msg->msg_namelen < sizeof(struct sockaddr_nl))
+			goto out;
 		if (addr->nl_family != AF_NETLINK)
 			goto out;
 		dst_portid = addr->nl_pid;
diff --git a/net/openvswitch/flow_netlink.c b/net/openvswitch/flow_netlink.c
index 1668916..326945d 100644
--- a/net/openvswitch/flow_netlink.c
+++ b/net/openvswitch/flow_netlink.c
@@ -1296,13 +1296,10 @@
 
 	/* The nlattr stream should already have been validated */
 	nla_for_each_nested(nla, attr, rem) {
-		if (tbl[nla_type(nla)].len == OVS_ATTR_NESTED) {
-			if (tbl[nla_type(nla)].next)
-				tbl = tbl[nla_type(nla)].next;
-			nlattr_set(nla, val, tbl);
-		} else {
+		if (tbl[nla_type(nla)].len == OVS_ATTR_NESTED)
+			nlattr_set(nla, val, tbl[nla_type(nla)].next ? : tbl);
+		else
 			memset(nla_data(nla), val, nla_len(nla));
-		}
 
 		if (nla_type(nla) == OVS_KEY_ATTR_CT_STATE)
 			*(u32 *)nla_data(nla) &= CT_SUPPORTED_MASK;
diff --git a/net/rfkill/rfkill-gpio.c b/net/rfkill/rfkill-gpio.c
index 76c01cb..d6d8b34 100644
--- a/net/rfkill/rfkill-gpio.c
+++ b/net/rfkill/rfkill-gpio.c
@@ -138,13 +138,18 @@
 
 	ret = rfkill_register(rfkill->rfkill_dev);
 	if (ret < 0)
-		return ret;
+		goto err_destroy;
 
 	platform_set_drvdata(pdev, rfkill);
 
 	dev_info(&pdev->dev, "%s device registered.\n", rfkill->name);
 
 	return 0;
+
+err_destroy:
+	rfkill_destroy(rfkill->rfkill_dev);
+
+	return ret;
 }
 
 static int rfkill_gpio_remove(struct platform_device *pdev)
diff --git a/net/sched/sch_fq.c b/net/sched/sch_fq.c
index 18e7524..b57b4de 100644
--- a/net/sched/sch_fq.c
+++ b/net/sched/sch_fq.c
@@ -128,6 +128,28 @@
 	return f->next == &detached;
 }
 
+static bool fq_flow_is_throttled(const struct fq_flow *f)
+{
+	return f->next == &throttled;
+}
+
+static void fq_flow_add_tail(struct fq_flow_head *head, struct fq_flow *flow)
+{
+	if (head->first)
+		head->last->next = flow;
+	else
+		head->first = flow;
+	head->last = flow;
+	flow->next = NULL;
+}
+
+static void fq_flow_unset_throttled(struct fq_sched_data *q, struct fq_flow *f)
+{
+	rb_erase(&f->rate_node, &q->delayed);
+	q->throttled_flows--;
+	fq_flow_add_tail(&q->old_flows, f);
+}
+
 static void fq_flow_set_throttled(struct fq_sched_data *q, struct fq_flow *f)
 {
 	struct rb_node **p = &q->delayed.rb_node, *parent = NULL;
@@ -155,15 +177,6 @@
 
 static struct kmem_cache *fq_flow_cachep __read_mostly;
 
-static void fq_flow_add_tail(struct fq_flow_head *head, struct fq_flow *flow)
-{
-	if (head->first)
-		head->last->next = flow;
-	else
-		head->first = flow;
-	head->last = flow;
-	flow->next = NULL;
-}
 
 /* limit number of collected flows per round */
 #define FQ_GC_MAX 8
@@ -267,6 +280,8 @@
 				     f->socket_hash != sk->sk_hash)) {
 				f->credit = q->initial_quantum;
 				f->socket_hash = sk->sk_hash;
+				if (fq_flow_is_throttled(f))
+					fq_flow_unset_throttled(q, f);
 				f->time_next_packet = 0ULL;
 			}
 			return f;
@@ -430,9 +445,7 @@
 			q->time_next_delayed_flow = f->time_next_packet;
 			break;
 		}
-		rb_erase(p, &q->delayed);
-		q->throttled_flows--;
-		fq_flow_add_tail(&q->old_flows, f);
+		fq_flow_unset_throttled(q, f);
 	}
 }
 
diff --git a/net/sctp/associola.c b/net/sctp/associola.c
index f10d339..738c55e 100644
--- a/net/sctp/associola.c
+++ b/net/sctp/associola.c
@@ -1006,9 +1006,10 @@
 	struct sctp_endpoint *ep;
 	struct sctp_chunk *chunk;
 	struct sctp_inq *inqueue;
-	int state;
 	sctp_subtype_t subtype;
+	int first_time = 1;	/* is this the first time through the loop */
 	int error = 0;
+	int state;
 
 	/* The association should be held so we should be safe. */
 	ep = asoc->ep;
@@ -1019,6 +1020,30 @@
 		state = asoc->state;
 		subtype = SCTP_ST_CHUNK(chunk->chunk_hdr->type);
 
+		/* If the first chunk in the packet is AUTH, do special
+		 * processing specified in Section 6.3 of SCTP-AUTH spec
+		 */
+		if (first_time && subtype.chunk == SCTP_CID_AUTH) {
+			struct sctp_chunkhdr *next_hdr;
+
+			next_hdr = sctp_inq_peek(inqueue);
+			if (!next_hdr)
+				goto normal;
+
+			/* If the next chunk is COOKIE-ECHO, skip the AUTH
+			 * chunk while saving a pointer to it so we can do
+			 * Authentication later (during cookie-echo
+			 * processing).
+			 */
+			if (next_hdr->type == SCTP_CID_COOKIE_ECHO) {
+				chunk->auth_chunk = skb_clone(chunk->skb,
+							      GFP_ATOMIC);
+				chunk->auth = 1;
+				continue;
+			}
+		}
+
+normal:
 		/* SCTP-AUTH, Section 6.3:
 		 *    The receiver has a list of chunk types which it expects
 		 *    to be received only after an AUTH-chunk.  This list has
@@ -1057,6 +1082,9 @@
 		/* If there is an error on chunk, discard this packet. */
 		if (error && chunk)
 			chunk->pdiscard = 1;
+
+		if (first_time)
+			first_time = 0;
 	}
 	sctp_association_put(asoc);
 }
diff --git a/net/sctp/inqueue.c b/net/sctp/inqueue.c
index f731de3..e06083c 100644
--- a/net/sctp/inqueue.c
+++ b/net/sctp/inqueue.c
@@ -217,7 +217,7 @@
 	skb_pull(chunk->skb, sizeof(sctp_chunkhdr_t));
 	chunk->subh.v = NULL; /* Subheader is no longer valid.  */
 
-	if (chunk->chunk_end + sizeof(sctp_chunkhdr_t) <
+	if (chunk->chunk_end + sizeof(sctp_chunkhdr_t) <=
 	    skb_tail_pointer(chunk->skb)) {
 		/* This is not a singleton */
 		chunk->singleton = 0;
diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c
index e031797..f4d5efb 100644
--- a/net/sctp/ipv6.c
+++ b/net/sctp/ipv6.c
@@ -864,6 +864,9 @@
 	if (sctp_is_any(sk, addr1) || sctp_is_any(sk, addr2))
 		return 1;
 
+	if (addr1->sa.sa_family == AF_INET && addr2->sa.sa_family == AF_INET)
+		return addr1->v4.sin_addr.s_addr == addr2->v4.sin_addr.s_addr;
+
 	return __sctp_v6_cmp_addr(addr1, addr2);
 }
 
diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c
index 8ec20a6..bfd0686 100644
--- a/net/sctp/sm_statefuns.c
+++ b/net/sctp/sm_statefuns.c
@@ -144,10 +144,8 @@
 				     void *arg,
 				     sctp_cmd_seq_t *commands);
 
-static sctp_ierror_t sctp_sf_authenticate(struct net *net,
-				    const struct sctp_endpoint *ep,
+static sctp_ierror_t sctp_sf_authenticate(
 				    const struct sctp_association *asoc,
-				    const sctp_subtype_t type,
 				    struct sctp_chunk *chunk);
 
 static sctp_disposition_t __sctp_sf_do_9_1_abort(struct net *net,
@@ -615,6 +613,38 @@
 	return SCTP_DISPOSITION_CONSUME;
 }
 
+static bool sctp_auth_chunk_verify(struct net *net, struct sctp_chunk *chunk,
+				   const struct sctp_association *asoc)
+{
+	struct sctp_chunk auth;
+
+	if (!chunk->auth_chunk)
+		return true;
+
+	/* SCTP-AUTH:  auth_chunk pointer is only set when the cookie-echo
+	 * is supposed to be authenticated and we have to do delayed
+	 * authentication.  We've just recreated the association using
+	 * the information in the cookie and now it's much easier to
+	 * do the authentication.
+	 */
+
+	/* Make sure that we and the peer are AUTH capable */
+	if (!net->sctp.auth_enable || !asoc->peer.auth_capable)
+		return false;
+
+	/* set-up our fake chunk so that we can process it */
+	auth.skb = chunk->auth_chunk;
+	auth.asoc = chunk->asoc;
+	auth.sctp_hdr = chunk->sctp_hdr;
+	auth.chunk_hdr = (struct sctp_chunkhdr *)
+				skb_push(chunk->auth_chunk,
+					 sizeof(struct sctp_chunkhdr));
+	skb_pull(chunk->auth_chunk, sizeof(struct sctp_chunkhdr));
+	auth.transport = chunk->transport;
+
+	return sctp_sf_authenticate(asoc, &auth) == SCTP_IERROR_NO_ERROR;
+}
+
 /*
  * Respond to a normal COOKIE ECHO chunk.
  * We are the side that is being asked for an association.
@@ -751,36 +781,9 @@
 	if (error)
 		goto nomem_init;
 
-	/* SCTP-AUTH:  auth_chunk pointer is only set when the cookie-echo
-	 * is supposed to be authenticated and we have to do delayed
-	 * authentication.  We've just recreated the association using
-	 * the information in the cookie and now it's much easier to
-	 * do the authentication.
-	 */
-	if (chunk->auth_chunk) {
-		struct sctp_chunk auth;
-		sctp_ierror_t ret;
-
-		/* Make sure that we and the peer are AUTH capable */
-		if (!net->sctp.auth_enable || !new_asoc->peer.auth_capable) {
-			sctp_association_free(new_asoc);
-			return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
-		}
-
-		/* set-up our fake chunk so that we can process it */
-		auth.skb = chunk->auth_chunk;
-		auth.asoc = chunk->asoc;
-		auth.sctp_hdr = chunk->sctp_hdr;
-		auth.chunk_hdr = (sctp_chunkhdr_t *)skb_push(chunk->auth_chunk,
-					    sizeof(sctp_chunkhdr_t));
-		skb_pull(chunk->auth_chunk, sizeof(sctp_chunkhdr_t));
-		auth.transport = chunk->transport;
-
-		ret = sctp_sf_authenticate(net, ep, new_asoc, type, &auth);
-		if (ret != SCTP_IERROR_NO_ERROR) {
-			sctp_association_free(new_asoc);
-			return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
-		}
+	if (!sctp_auth_chunk_verify(net, chunk, new_asoc)) {
+		sctp_association_free(new_asoc);
+		return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
 	}
 
 	repl = sctp_make_cookie_ack(new_asoc, chunk);
@@ -1717,13 +1720,15 @@
 			       GFP_ATOMIC))
 		goto nomem;
 
+	if (!sctp_auth_chunk_verify(net, chunk, new_asoc))
+		return SCTP_DISPOSITION_DISCARD;
+
 	/* Make sure no new addresses are being added during the
 	 * restart.  Though this is a pretty complicated attack
 	 * since you'd have to get inside the cookie.
 	 */
-	if (!sctp_sf_check_restart_addrs(new_asoc, asoc, chunk, commands)) {
+	if (!sctp_sf_check_restart_addrs(new_asoc, asoc, chunk, commands))
 		return SCTP_DISPOSITION_CONSUME;
-	}
 
 	/* If the endpoint is in the SHUTDOWN-ACK-SENT state and recognizes
 	 * the peer has restarted (Action A), it MUST NOT setup a new
@@ -1828,6 +1833,9 @@
 			       GFP_ATOMIC))
 		goto nomem;
 
+	if (!sctp_auth_chunk_verify(net, chunk, new_asoc))
+		return SCTP_DISPOSITION_DISCARD;
+
 	/* Update the content of current association.  */
 	sctp_add_cmd_sf(commands, SCTP_CMD_UPDATE_ASSOC, SCTP_ASOC(new_asoc));
 	sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
@@ -1920,6 +1928,9 @@
 	 * a COOKIE ACK.
 	 */
 
+	if (!sctp_auth_chunk_verify(net, chunk, asoc))
+		return SCTP_DISPOSITION_DISCARD;
+
 	/* Don't accidentally move back into established state. */
 	if (asoc->state < SCTP_STATE_ESTABLISHED) {
 		sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP,
@@ -1959,7 +1970,7 @@
 		}
 	}
 
-	repl = sctp_make_cookie_ack(new_asoc, chunk);
+	repl = sctp_make_cookie_ack(asoc, chunk);
 	if (!repl)
 		goto nomem;
 
@@ -3981,10 +3992,8 @@
  *
  * The return value is the disposition of the chunk.
  */
-static sctp_ierror_t sctp_sf_authenticate(struct net *net,
-				    const struct sctp_endpoint *ep,
+static sctp_ierror_t sctp_sf_authenticate(
 				    const struct sctp_association *asoc,
-				    const sctp_subtype_t type,
 				    struct sctp_chunk *chunk)
 {
 	struct sctp_authhdr *auth_hdr;
@@ -4083,7 +4092,7 @@
 						  commands);
 
 	auth_hdr = (struct sctp_authhdr *)chunk->skb->data;
-	error = sctp_sf_authenticate(net, ep, asoc, type, chunk);
+	error = sctp_sf_authenticate(asoc, chunk);
 	switch (error) {
 	case SCTP_IERROR_AUTH_BAD_HMAC:
 		/* Generate the ERROR chunk and discard the rest
diff --git a/net/sctp/ulpevent.c b/net/sctp/ulpevent.c
index bea0005..6825e05 100644
--- a/net/sctp/ulpevent.c
+++ b/net/sctp/ulpevent.c
@@ -723,7 +723,6 @@
 	return event;
 
 fail_mark:
-	sctp_chunk_put(chunk);
 	kfree_skb(skb);
 fail:
 	return NULL;
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
index d869b1d..3fbe584 100644
--- a/net/xfrm/xfrm_state.c
+++ b/net/xfrm/xfrm_state.c
@@ -1197,6 +1197,7 @@
 
 	if (orig->aead) {
 		x->aead = xfrm_algo_aead_clone(orig->aead);
+		x->geniv = orig->geniv;
 		if (!x->aead)
 			goto error;
 	}