Merge "arm/dt: msm8226: Update number of sensors"
diff --git a/Documentation/devicetree/bindings/media/video/msm-vidc.txt b/Documentation/devicetree/bindings/media/video/msm-vidc.txt
index cd14056..f97e063 100644
--- a/Documentation/devicetree/bindings/media/video/msm-vidc.txt
+++ b/Documentation/devicetree/bindings/media/video/msm-vidc.txt
@@ -31,6 +31,14 @@
   request by different video encoder usecases.
 - qcom,dec-ddr-ab-ib : list of bus vectors(ab, ib pair) for ddr bandwidth
   request by different video decoder usecases.
+- qcom,iommu-groups : list of IOMMU groups to be used.  Groups are defined as
+  phandles in <target>-iommu-domains.dtsi (e.g msm8974-v1-iommu-domains.dtsi)
+- qcom,iommu-group-buffer-types : bitmap of buffer types that can be mapped into
+  the corresponding IOMMU group. Buffer types are defined within the vidc driver
+  by "enum hal_buffer" in msm_smem.h
+- qcom,buffer-type-tz-usage-table : a key-value pair, mapping a buffer type
+  (enum hal_buffer) to its corresponding TZ usage. The TZ usages are defined
+  as "enum cp_mem_usage" in include/linux/msm_ion.h
 
 Example:
 
@@ -59,4 +67,8 @@
 			<60000 664950>;
 		qcom,dec-ddr-ab-ib = <0 0>,
 			<110000 909000>;
+		qcom,iommu-groups = <&venus_domain_ns &venus_domain_cp>;
+		qcom,iommu-group-buffer-types = <0xfff 0x1ff>;
+		qcom,buffer-type-tz-usage-table = <0x1 0x1>,
+						<0x1fe 0x2>;
 	};
diff --git a/Documentation/devicetree/bindings/memory.txt b/Documentation/devicetree/bindings/memory.txt
index 74e0476..e98ee05 100644
--- a/Documentation/devicetree/bindings/memory.txt
+++ b/Documentation/devicetree/bindings/memory.txt
@@ -36,6 +36,7 @@
 	reg = <(baseaddr) (size)>;
 	(linux,contiguous-region);
 	(linux,default-contiguous-region);
+        label = (unique_name);
 };
 
 name:		an name given to the defined region.
@@ -47,7 +48,11 @@
 linux,default-contiguous-region: property indicating that the region
 		is the default region for all contiguous memory
 		allocations, Linux specific (optional)
-
+label:		an internal name used for automatically associating the
+		cma region with a given device. The label is optional;
+		if the label is not given the client is responsible for
+		calling the appropriate functions to associate the region
+		with a device.
 
 * Device nodes
 
diff --git a/Documentation/devicetree/bindings/usb/msm-hsusb.txt b/Documentation/devicetree/bindings/usb/msm-hsusb.txt
index 9d0b0a5..2cdc7ff 100644
--- a/Documentation/devicetree/bindings/usb/msm-hsusb.txt
+++ b/Documentation/devicetree/bindings/usb/msm-hsusb.txt
@@ -52,6 +52,13 @@
 - qcom,hsusb-otg-clk-always-on-workaround: If present then USB core clocks
 	    remain active upon receiving bus suspend and USB cable is connected.
 	    Used for allowing USB to respond for remote wakup.
+- <supply-name>-supply: handle to the regulator device tree node
+         Required "supply-name" is "HSUSB_VDDCX" (when voting for VDDCX) or
+         "hsusb_vdd_dig" (when voting for VDDCX Corner voltage),
+         "HSUSB_1p8-supply" and "HSUSB_3p3-supply".
+- qcom,vdd-voltage-level: This property must be a list of three integer
+	values (no, min, max) where each value represents either a voltage
+	in microvolts or a value corresponding to voltage corner.
 
 Example HSUSB OTG controller device node :
 	usb@f9690000 {
@@ -72,6 +79,10 @@
 		qcom,hsusb-otg-pmic-id-irq = <47>
 		qcom,hsusb-otg-lpm-on-dev-suspend;
 		qcom,hsusb-otg-clk-always-on-workaround;
+		hsusb_vdd_dig-supply = <&pm8226_s1_corner>;
+                HSUSB_1p8-supply = <&pm8226_l10>;
+                HSUSB_3p3-supply = <&pm8226_l20>;
+		qcom,vdd-voltage-level = <1 5 7>;
 
 		qcom,msm_bus,name = "usb2";
 		qcom,msm_bus,num_cases = <2>;
diff --git a/arch/arm/boot/dts/msm-pm8226.dtsi b/arch/arm/boot/dts/msm-pm8226.dtsi
index de23f4c..6a07bad 100644
--- a/arch/arm/boot/dts/msm-pm8226.dtsi
+++ b/arch/arm/boot/dts/msm-pm8226.dtsi
@@ -22,6 +22,33 @@
 		#address-cells = <1>;
 		#size-cells = <1>;
 
+		qcom,power-on@800 {
+			compatible = "qcom,qpnp-power-on";
+			reg = <0x800 0x100>;
+			interrupts = <0x0 0x8 0x0>,
+				     <0x0 0x8 0x1>,
+				     <0x0 0x8 0x4>;
+			interrupt-names = "kpdpwr", "resin", "resin-bark";
+			qcom,pon-dbc-delay = <15625>;
+			qcom,system-reset;
+
+			qcom,pon_1 {
+				qcom,pon-type = <0>;
+				qcom,pull-up = <1>;
+				linux,code = <116>;
+			};
+
+			qcom,pon_2 {
+				qcom,pon-type = <1>;
+				qcom,support-reset = <1>;
+				qcom,pull-up = <1>;
+				qcom,s1-timer = <0>;
+				qcom,s2-timer = <2000>;
+				qcom,s2-type = <1>;
+				linux,code = <114>;
+			};
+		};
+
 		pm8226_gpios: gpios {
 			spmi-dev-container;
 			compatible = "qcom,qpnp-pin";
diff --git a/arch/arm/boot/dts/msm8226.dtsi b/arch/arm/boot/dts/msm8226.dtsi
index c255781..a7ea350 100644
--- a/arch/arm/boot/dts/msm8226.dtsi
+++ b/arch/arm/boot/dts/msm8226.dtsi
@@ -85,9 +85,10 @@
 		reg = <0xf9a55000 0x400>;
 		interrupts = <0 134 0>, <0 140 0>;
 		interrupt-names = "core_irq", "async_irq";
-		HSUSB_VDDCX-supply = <&pm8226_s1>;
+		hsusb_vdd_dig-supply = <&pm8226_s1_corner>;
 		HSUSB_1p8-supply = <&pm8226_l10>;
 		HSUSB_3p3-supply = <&pm8226_l20>;
+		qcom,vdd-voltage-level = <1 5 7>;
 
 		qcom,hsusb-otg-phy-type = <2>;
 		qcom,hsusb-otg-mode = <1>;
diff --git a/arch/arm/boot/dts/msm8974-ion.dtsi b/arch/arm/boot/dts/msm8974-ion.dtsi
index f55cff2..dfa22c1 100644
--- a/arch/arm/boot/dts/msm8974-ion.dtsi
+++ b/arch/arm/boot/dts/msm8974-ion.dtsi
@@ -24,8 +24,7 @@
 			compatible = "qcom,msm-ion-reserve";
 			reg = <8>;
 			qcom,heap-align = <0x1000>;
-			qcom,memory-reservation-type = "EBI1"; /* reserve EBI memory */
-			qcom,memory-reservation-size = <0x7800000>;
+			linux,contiguous-region = <&secure_mem>;
 		};
 
 		qcom,ion-heap@25 { /* IOMMU HEAP */
diff --git a/arch/arm/boot/dts/msm8974-v1.dtsi b/arch/arm/boot/dts/msm8974-v1.dtsi
index fc3a1d3..64014b3 100644
--- a/arch/arm/boot/dts/msm8974-v1.dtsi
+++ b/arch/arm/boot/dts/msm8974-v1.dtsi
@@ -110,6 +110,10 @@
 		<1010000 1818000>,
 		<1616000 2908800>,
 		<2020000 6400000>;
+	qcom,iommu-groups = <&venus_domain_ns &venus_domain_cp>;
+	qcom,iommu-group-buffer-types = <0xfff 0x1ff>;
+	qcom,buffer-type-tz-usage-table = <0x1 0x1>,
+					<0x1fe 0x2>;
 };
 
 &sfpb_spinlock {
diff --git a/arch/arm/boot/dts/msm8974-v2.dtsi b/arch/arm/boot/dts/msm8974-v2.dtsi
index 7e6c0bf..3dda20f 100644
--- a/arch/arm/boot/dts/msm8974-v2.dtsi
+++ b/arch/arm/boot/dts/msm8974-v2.dtsi
@@ -110,6 +110,12 @@
 		<1620000 970000>,
 		<2024000 1212000>,
 		<2132000 1279000>;
+	qcom,iommu-groups = <&venus_domain_ns &venus_domain_sec_bitstream
+			&venus_domain_sec_pixel &venus_domain_sec_non_pixel>;
+	qcom,iommu-group-buffer-types = <0xfff 0x91 0x42 0x120>;
+	qcom,buffer-type-tz-usage-table = <0x91 0x1>,
+					<0x42 0x2>,
+					<0x120 0x3>;
 };
 
 &krait_pdn {
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index 2c4d5d9..7c6a9d1 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -31,6 +31,15 @@
 		spi7 = &spi_7;
 	};
 
+	memory {
+
+		secure_mem: region@0 {
+			linux,contiguous-region;
+			reg = <0 0x7800000>;
+			label = "secure_mem";
+		};
+	};
+
 	intc: interrupt-controller@F9000000 {
 		compatible = "qcom,msm-qgic2";
 		interrupt-controller;
diff --git a/arch/arm/configs/msm8610_defconfig b/arch/arm/configs/msm8610_defconfig
index 3d710cc..e6f4396 100644
--- a/arch/arm/configs/msm8610_defconfig
+++ b/arch/arm/configs/msm8610_defconfig
@@ -220,6 +220,7 @@
 CONFIG_CRYPTO_TWOFISH=y
 # CONFIG_CRYPTO_HW is not set
 CONFIG_CRC_CCITT=y
+CONFIG_QPNP_POWER_ON=y
 CONFIG_LIBCRC32C=y
 CONFIG_MEDIA_SUPPORT=y
 CONFIG_MEDIA_CAMERA_SUPPORT=y
diff --git a/arch/arm/configs/msm8974-perf_defconfig b/arch/arm/configs/msm8974-perf_defconfig
index 5c03630..d36d5a2 100644
--- a/arch/arm/configs/msm8974-perf_defconfig
+++ b/arch/arm/configs/msm8974-perf_defconfig
@@ -234,6 +234,7 @@
 CONFIG_GENLOCK_MISCDEVICE=y
 CONFIG_SYNC=y
 CONFIG_SW_SYNC=y
+CONFIG_CMA=y
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_RAM=y
 CONFIG_HAPTIC_ISA1200=y
diff --git a/arch/arm/configs/msm8974_defconfig b/arch/arm/configs/msm8974_defconfig
index faa0471..df0b5f0 100644
--- a/arch/arm/configs/msm8974_defconfig
+++ b/arch/arm/configs/msm8974_defconfig
@@ -238,6 +238,7 @@
 CONFIG_GENLOCK_MISCDEVICE=y
 CONFIG_SYNC=y
 CONFIG_SW_SYNC=y
+CONFIG_CMA=y
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_RAM=y
 CONFIG_TSPP=m
diff --git a/arch/arm/mach-msm/bam_dmux.c b/arch/arm/mach-msm/bam_dmux.c
index 7c2c463..833b213 100644
--- a/arch/arm/mach-msm/bam_dmux.c
+++ b/arch/arm/mach-msm/bam_dmux.c
@@ -302,81 +302,56 @@
 #define bam_ch_is_in_reset(x)			\
 	(bam_ch[(x)].status & BAM_CH_IN_RESET)
 
-#define LOG_MESSAGE_MAX_SIZE 80
 struct kfifo bam_dmux_state_log;
-static uint32_t bam_dmux_state_logging_disabled;
 static int bam_dmux_uplink_vote;
 static int bam_dmux_power_state;
 
-static void bam_dmux_log(const char *fmt, ...)
-					__printf(1, 2);
-
-
-#define DMUX_LOG_KERR(fmt...) \
-do { \
-	bam_dmux_log(fmt); \
-	pr_err(fmt); \
-} while (0)
-
 static void *bam_ipc_log_txt;
 
 #define BAM_IPC_LOG_PAGES 5
 
 /**
  * Log a state change along with a small message.
- *
  * Complete size of messsage is limited to @todo.
+ * Logging is done using IPC Logging infrastructure.
+ *
+ * States
+ * D: 1 = Power collapse disabled
+ * R: 1 = in global reset
+ * P: 1 = BAM is powered up
+ * A: 1 = BAM initialized and ready for data
+ * V: 1 = Uplink vote for power
+ * U: 1 = Uplink active
+ * W: 1 = Uplink Wait-for-ack
+ * A: 1 = Uplink ACK received
+ * #: >=1 On-demand uplink vote
+ * D: 1 = Disconnect ACK active
  */
-static void bam_dmux_log(const char *fmt, ...)
-{
-	char buff[LOG_MESSAGE_MAX_SIZE];
-	va_list arg_list;
-	unsigned long long t_now;
-	unsigned long nanosec_rem;
-	int len = 0;
 
-	if (bam_dmux_state_logging_disabled)
-		return;
+#define BAM_DMUX_LOG(fmt, args...) \
+do { \
+	if (bam_ipc_log_txt) { \
+		ipc_log_string(bam_ipc_log_txt, \
+		"<DMUX> %c%c%c%c %c%c%c%c%d%c " fmt, \
+		a2_pc_disabled ? 'D' : 'd', \
+		in_global_reset ? 'R' : 'r', \
+		bam_dmux_power_state ? 'P' : 'p', \
+		bam_connection_is_active ? 'A' : 'a', \
+		bam_dmux_uplink_vote ? 'V' : 'v', \
+		bam_is_connected ?  'U' : 'u', \
+		wait_for_ack ? 'W' : 'w', \
+		ul_wakeup_ack_completion.done ? 'A' : 'a', \
+		atomic_read(&ul_ondemand_vote), \
+		disconnect_ack ? 'D' : 'd', \
+		args); \
+	} \
+} while (0)
 
-	t_now = sched_clock();
-	nanosec_rem = do_div(t_now, 1000000000U);
-
-	/*
-	 * States
-	 * D: 1 = Power collapse disabled
-	 * R: 1 = in global reset
-	 * P: 1 = BAM is powered up
-	 * A: 1 = BAM initialized and ready for data
-	 *
-	 * V: 1 = Uplink vote for power
-	 * U: 1 = Uplink active
-	 * W: 1 = Uplink Wait-for-ack
-	 * A: 1 = Uplink ACK received
-	 * #: >=1 On-demand uplink vote
-	 * D: 1 = Disconnect ACK active
-	 */
-	len += scnprintf(buff, sizeof(buff),
-		"<DMUX> %u.%09lu %c%c%c%c %c%c%c%c%d%c ",
-		(unsigned)t_now, nanosec_rem,
-		a2_pc_disabled ? 'D' : 'd',
-		in_global_reset ? 'R' : 'r',
-		bam_dmux_power_state ? 'P' : 'p',
-		bam_connection_is_active ? 'A' : 'a',
-		bam_dmux_uplink_vote ? 'V' : 'v',
-		bam_is_connected ?  'U' : 'u',
-		wait_for_ack ? 'W' : 'w',
-		ul_wakeup_ack_completion.done ? 'A' : 'a',
-		atomic_read(&ul_ondemand_vote),
-		disconnect_ack ? 'D' : 'd'
-		);
-
-	va_start(arg_list, fmt);
-	len += vscnprintf(buff + len, sizeof(buff) - len, fmt, arg_list);
-	va_end(arg_list);
-	memset(buff + len, 0x0, sizeof(buff) - len);
-	if (bam_ipc_log_txt)
-		ipc_log_string(bam_ipc_log_txt, buff);
-}
+#define DMUX_LOG_KERR(fmt, args...) \
+do { \
+	BAM_DMUX_LOG(fmt, args); \
+	pr_err(fmt, args); \
+} while (0)
 
 static inline void set_tx_timestamp(struct tx_pkt_info *pkt)
 {
@@ -396,12 +371,12 @@
 	spin_lock_irqsave(&bam_tx_pool_spinlock, flags);
 	list_for_each_entry(info, &bam_tx_pool, list_node) {
 		if (!reported) {
-			bam_dmux_log("%s: tx pool not empty\n", func);
+			BAM_DMUX_LOG("%s: tx pool not empty\n", func);
 			if (!in_global_reset)
 				pr_err("%s: tx pool not empty\n", func);
 			reported = 1;
 		}
-		bam_dmux_log("%s: node=%p ts=%u.%09lu\n", __func__,
+		BAM_DMUX_LOG("%s: node=%p ts=%u.%09lu\n", __func__,
 			&info->list_node, info->ts_sec, info->ts_nsec);
 		if (!in_global_reset)
 			pr_err("%s: node=%p ts=%u.%09lu\n", __func__,
@@ -529,7 +504,7 @@
 
 	mutex_lock(&bam_pdev_mutexlock);
 	if (in_global_reset) {
-		bam_dmux_log("%s: open cid %d aborted due to ssr\n",
+		BAM_DMUX_LOG("%s: open cid %d aborted due to ssr\n",
 				__func__, rx_hdr->ch_id);
 		mutex_unlock(&bam_pdev_mutexlock);
 		queue_rx();
@@ -593,18 +568,18 @@
 		bam_mux_process_data(rx_skb);
 		break;
 	case BAM_MUX_HDR_CMD_OPEN:
-		bam_dmux_log("%s: opening cid %d PC enabled\n", __func__,
+		BAM_DMUX_LOG("%s: opening cid %d PC enabled\n", __func__,
 				rx_hdr->ch_id);
 		handle_bam_mux_cmd_open(rx_hdr);
 		if (!(rx_hdr->reserved & ENABLE_DISCONNECT_ACK)) {
-			bam_dmux_log("%s: deactivating disconnect ack\n",
+			BAM_DMUX_LOG("%s: deactivating disconnect ack\n",
 								__func__);
 			disconnect_ack = 0;
 		}
 		dev_kfree_skb_any(rx_skb);
 		break;
 	case BAM_MUX_HDR_CMD_OPEN_NO_A2_PC:
-		bam_dmux_log("%s: opening cid %d PC disabled\n", __func__,
+		BAM_DMUX_LOG("%s: opening cid %d PC disabled\n", __func__,
 				rx_hdr->ch_id);
 
 		if (!a2_pc_disabled) {
@@ -617,11 +592,11 @@
 		break;
 	case BAM_MUX_HDR_CMD_CLOSE:
 		/* probably should drop pending write */
-		bam_dmux_log("%s: closing cid %d\n", __func__,
+		BAM_DMUX_LOG("%s: closing cid %d\n", __func__,
 				rx_hdr->ch_id);
 		mutex_lock(&bam_pdev_mutexlock);
 		if (in_global_reset) {
-			bam_dmux_log("%s: close cid %d aborted due to ssr\n",
+			BAM_DMUX_LOG("%s: close cid %d aborted due to ssr\n",
 					__func__, rx_hdr->ch_id);
 			mutex_unlock(&bam_pdev_mutexlock);
 			break;
@@ -1412,7 +1387,7 @@
 	for (i = 0; i < BAM_DMUX_NUM_CHANNELS; ++i) {
 		if (bam_ch_is_open(i)) {
 			bam_ch[i].notify(bam_ch[i].priv, event, data);
-			bam_dmux_log("%s: cid=%d, event=%d, data=%lu\n",
+			BAM_DMUX_LOG("%s: cid=%d, event=%d, data=%lu\n",
 					__func__, i, event, data);
 		}
 	}
@@ -1455,11 +1430,11 @@
 
 static void power_vote(int vote)
 {
-	bam_dmux_log("%s: curr=%d, vote=%d\n", __func__,
+	BAM_DMUX_LOG("%s: curr=%d, vote=%d\n", __func__,
 			bam_dmux_uplink_vote, vote);
 
 	if (bam_dmux_uplink_vote == vote)
-		bam_dmux_log("%s: warning - duplicate power vote\n", __func__);
+		BAM_DMUX_LOG("%s: warning - duplicate power vote\n", __func__);
 
 	bam_dmux_uplink_vote = vote;
 	if (vote)
@@ -1473,7 +1448,7 @@
  */
 static inline void ul_powerdown(void)
 {
-	bam_dmux_log("%s: powerdown\n", __func__);
+	BAM_DMUX_LOG("%s: powerdown\n", __func__);
 	verify_tx_queue_is_empty(__func__);
 
 	if (a2_pc_disabled) {
@@ -1585,7 +1560,7 @@
 		}
 
 		if (ul_packet_written || atomic_read(&ul_ondemand_vote)) {
-			bam_dmux_log("%s: pkt written %d\n",
+			BAM_DMUX_LOG("%s: pkt written %d\n",
 				__func__, ul_packet_written);
 			ul_packet_written = 0;
 			schedule_delayed_work(&ul_timeout_work,
@@ -1614,7 +1589,7 @@
 
 	mutex_lock(&wakeup_lock);
 	if (bam_is_connected) { /* bam got connected before lock grabbed */
-		bam_dmux_log("%s Already awake\n", __func__);
+		BAM_DMUX_LOG("%s Already awake\n", __func__);
 		mutex_unlock(&wakeup_lock);
 		return;
 	}
@@ -1677,35 +1652,35 @@
 	 * instead of waiting
 	 */
 	if (wait_for_ack) {
-		bam_dmux_log("%s waiting for previous ack\n", __func__);
+		BAM_DMUX_LOG("%s waiting for previous ack\n", __func__);
 		ret = wait_for_completion_timeout(
 					&ul_wakeup_ack_completion, HZ);
 		wait_for_ack = 0;
 		if (unlikely(ret == 0) && ssrestart_check()) {
 			mutex_unlock(&wakeup_lock);
-			bam_dmux_log("%s timeout previous ack\n", __func__);
+			BAM_DMUX_LOG("%s timeout previous ack\n", __func__);
 			return;
 		}
 	}
 	INIT_COMPLETION(ul_wakeup_ack_completion);
 	power_vote(1);
-	bam_dmux_log("%s waiting for wakeup ack\n", __func__);
+	BAM_DMUX_LOG("%s waiting for wakeup ack\n", __func__);
 	ret = wait_for_completion_timeout(&ul_wakeup_ack_completion, HZ);
 	if (unlikely(ret == 0) && ssrestart_check()) {
 		mutex_unlock(&wakeup_lock);
-		bam_dmux_log("%s timeout wakeup ack\n", __func__);
+		BAM_DMUX_LOG("%s timeout wakeup ack\n", __func__);
 		return;
 	}
-	bam_dmux_log("%s waiting completion\n", __func__);
+	BAM_DMUX_LOG("%s waiting completion\n", __func__);
 	ret = wait_for_completion_timeout(&bam_connection_completion, HZ);
 	if (unlikely(ret == 0) && ssrestart_check()) {
 		mutex_unlock(&wakeup_lock);
-		bam_dmux_log("%s timeout power on\n", __func__);
+		BAM_DMUX_LOG("%s timeout power on\n", __func__);
 		return;
 	}
 
 	bam_is_connected = 1;
-	bam_dmux_log("%s complete\n", __func__);
+	BAM_DMUX_LOG("%s complete\n", __func__);
 	schedule_delayed_work(&ul_timeout_work,
 				msecs_to_jiffies(UL_TIMEOUT_DELAY));
 	mutex_unlock(&wakeup_lock);
@@ -1771,7 +1746,7 @@
 	/* handle disconnect during active UL */
 	write_lock_irqsave(&ul_wakeup_lock, flags);
 	if (bam_is_connected) {
-		bam_dmux_log("%s: UL active - forcing powerdown\n", __func__);
+		BAM_DMUX_LOG("%s: UL active - forcing powerdown\n", __func__);
 		ul_powerdown();
 	}
 	write_unlock_irqrestore(&ul_wakeup_lock, flags);
@@ -1817,10 +1792,10 @@
 {
 	int rc;
 
-	bam_dmux_log("%s\n", __func__);
+	BAM_DMUX_LOG("%s\n", __func__);
 	mutex_lock(&dfab_status_lock);
 	if (dfab_is_on) {
-		bam_dmux_log("%s: dfab is already on\n", __func__);
+		BAM_DMUX_LOG("%s: dfab is already on\n", __func__);
 		mutex_unlock(&dfab_status_lock);
 		return;
 	}
@@ -1842,7 +1817,7 @@
 
 static void unvote_dfab(void)
 {
-	bam_dmux_log("%s\n", __func__);
+	BAM_DMUX_LOG("%s\n", __func__);
 	mutex_lock(&dfab_status_lock);
 	if (!dfab_is_on) {
 		DMUX_LOG_KERR("%s: dfab is already off\n", __func__);
@@ -1864,7 +1839,7 @@
 	unsigned long flags;
 
 	spin_lock_irqsave(&wakelock_reference_lock, flags);
-	bam_dmux_log("%s: ref count = %d\n", __func__,
+	BAM_DMUX_LOG("%s: ref count = %d\n", __func__,
 						wakelock_reference_count);
 	if (wakelock_reference_count == 0)
 		wake_lock(&bam_wakelock);
@@ -1883,7 +1858,7 @@
 		spin_unlock_irqrestore(&wakelock_reference_lock, flags);
 		return;
 	}
-	bam_dmux_log("%s: ref count = %d\n", __func__,
+	BAM_DMUX_LOG("%s: ref count = %d\n", __func__,
 						wakelock_reference_count);
 	--wakelock_reference_count;
 	if (wakelock_reference_count == 0)
@@ -1917,7 +1892,7 @@
 	if (code == SUBSYS_BEFORE_SHUTDOWN) {
 		in_global_reset = 1;
 		in_ssr = 1;
-		bam_dmux_log("%s: begin\n", __func__);
+		BAM_DMUX_LOG("%s: begin\n", __func__);
 		flush_workqueue(bam_mux_rx_workqueue);
 	}
 	if (code != SUBSYS_AFTER_SHUTDOWN)
@@ -1978,7 +1953,7 @@
 	}
 	spin_unlock_irqrestore(&bam_tx_pool_spinlock, flags);
 
-	bam_dmux_log("%s: complete\n", __func__);
+	BAM_DMUX_LOG("%s: complete\n", __func__);
 	return NOTIFY_DONE;
 }
 
@@ -2225,7 +2200,7 @@
 {
 	static unsigned int clear_bit; /* 0 = set the bit, else clear bit */
 
-	bam_dmux_log("%s: apps ack %d->%d\n", __func__,
+	BAM_DMUX_LOG("%s: apps ack %d->%d\n", __func__,
 			clear_bit & 0x1, ~clear_bit & 0x1);
 	smsm_change_state(SMSM_APPS_STATE,
 				clear_bit & SMSM_A2_POWER_CONTROL_ACK,
@@ -2241,10 +2216,10 @@
 	mutex_lock(&smsm_cb_lock);
 	bam_dmux_power_state = new_state & SMSM_A2_POWER_CONTROL ? 1 : 0;
 	DBG_INC_A2_POWER_CONTROL_IN_CNT();
-	bam_dmux_log("%s: 0x%08x -> 0x%08x\n", __func__, old_state,
+	BAM_DMUX_LOG("%s: 0x%08x -> 0x%08x\n", __func__, old_state,
 			new_state);
 	if (last_processed_state == (new_state & SMSM_A2_POWER_CONTROL)) {
-		bam_dmux_log("%s: already processed this state\n", __func__);
+		BAM_DMUX_LOG("%s: already processed this state\n", __func__);
 		mutex_unlock(&smsm_cb_lock);
 		return;
 	}
@@ -2252,23 +2227,23 @@
 	last_processed_state = new_state & SMSM_A2_POWER_CONTROL;
 
 	if (bam_mux_initialized && new_state & SMSM_A2_POWER_CONTROL) {
-		bam_dmux_log("%s: reconnect\n", __func__);
+		BAM_DMUX_LOG("%s: reconnect\n", __func__);
 		grab_wakelock();
 		reconnect_to_bam();
 	} else if (bam_mux_initialized &&
 					!(new_state & SMSM_A2_POWER_CONTROL)) {
-		bam_dmux_log("%s: disconnect\n", __func__);
+		BAM_DMUX_LOG("%s: disconnect\n", __func__);
 		disconnect_to_bam();
 		release_wakelock();
 	} else if (new_state & SMSM_A2_POWER_CONTROL) {
-		bam_dmux_log("%s: init\n", __func__);
+		BAM_DMUX_LOG("%s: init\n", __func__);
 		grab_wakelock();
 		if (cpu_is_msm9615())
 			msm9615_bam_init();
 		else
 			bam_init();
 	} else {
-		bam_dmux_log("%s: bad state change\n", __func__);
+		BAM_DMUX_LOG("%s: bad state change\n", __func__);
 		pr_err("%s: unsupported state change\n", __func__);
 	}
 	mutex_unlock(&smsm_cb_lock);
@@ -2279,7 +2254,7 @@
 						uint32_t new_state)
 {
 	DBG_INC_ACK_IN_CNT();
-	bam_dmux_log("%s: 0x%08x -> 0x%08x\n", __func__, old_state,
+	BAM_DMUX_LOG("%s: 0x%08x -> 0x%08x\n", __func__, old_state,
 			new_state);
 	complete_all(&ul_wakeup_ack_completion);
 }
@@ -2322,12 +2297,12 @@
 
 	xo_clk = clk_get(&pdev->dev, "xo");
 	if (IS_ERR(xo_clk)) {
-		bam_dmux_log("%s: did not get xo clock\n", __func__);
+		BAM_DMUX_LOG("%s: did not get xo clock\n", __func__);
 		xo_clk = NULL;
 	}
 	dfab_clk = clk_get(&pdev->dev, "bus_clk");
 	if (IS_ERR(dfab_clk)) {
-		bam_dmux_log("%s: did not get dfab clock\n", __func__);
+		BAM_DMUX_LOG("%s: did not get dfab clock\n", __func__);
 		dfab_clk = NULL;
 	} else {
 		rc = clk_set_rate(dfab_clk, 64000000);
@@ -2434,7 +2409,6 @@
 	bam_ipc_log_txt = ipc_log_context_create(BAM_IPC_LOG_PAGES, "bam_dmux");
 	if (!bam_ipc_log_txt) {
 		pr_err("%s : unable to create IPC Logging Context", __func__);
-		bam_dmux_state_logging_disabled = 1;
 	}
 
 	rx_timer_interval = DEFAULT_POLLING_MIN_SLEEP;
diff --git a/arch/arm/mach-msm/board-8064-gpiomux.c b/arch/arm/mach-msm/board-8064-gpiomux.c
index 0dee8f5..0f88287 100644
--- a/arch/arm/mach-msm/board-8064-gpiomux.c
+++ b/arch/arm/mach-msm/board-8064-gpiomux.c
@@ -1729,13 +1729,6 @@
 	},
 };
 
-static struct gpiomux_setting fsm8064_ep_sync_drsync_cfg = {
-	.func = GPIOMUX_FUNC_GPIO,
-	.drv = GPIOMUX_DRV_2MA,
-	.pull = GPIOMUX_PULL_UP,
-	.dir = GPIOMUX_OUT_HIGH,
-};
-
 static struct gpiomux_setting fsm8064_ep_sync_input_cfg = {
 	.func = GPIOMUX_FUNC_GPIO,
 	.drv = GPIOMUX_DRV_4MA,
@@ -1746,7 +1739,7 @@
 	{
 		.gpio      = 6,		/* GPSPPSIN_DRSYNC */
 		.settings = {
-			[GPIOMUX_SUSPENDED] = &fsm8064_ep_sync_drsync_cfg,
+			[GPIOMUX_SUSPENDED] = &fsm8064_ep_sync_input_cfg,
 		},
 	},
 	{
diff --git a/arch/arm/mach-msm/board-8064-pmic.c b/arch/arm/mach-msm/board-8064-pmic.c
index 0b3366c..a1ed251 100644
--- a/arch/arm/mach-msm/board-8064-pmic.c
+++ b/arch/arm/mach-msm/board-8064-pmic.c
@@ -137,7 +137,7 @@
 	PM8921_GPIO_OUTPUT_VIN(14, 1, PM_GPIO_VIN_VPH),
 	/* PPS_SRC_SEL_N, chooses between WGR7640 PPS source (high) or
 	 * CW GPS module PPS source (low) */
-	PM8921_GPIO_OUTPUT_VIN(19, 1, PM_GPIO_VIN_VPH),	/* PPS_SRC_SEL_N */
+	PM8921_GPIO_OUTPUT_VIN(19, 0, PM_GPIO_VIN_VPH),	/* PPS_SRC_SEL_N */
 
 	PM8921_GPIO_OUTPUT_VIN(13, 1, PM_GPIO_VIN_VPH),	/* PCIE_CLK_PWR_EN */
 	PM8921_GPIO_OUTPUT_VIN(37, 1, PM_GPIO_VIN_VPH),	/* PCIE_RST_N */
diff --git a/arch/arm/mach-msm/board-8064.c b/arch/arm/mach-msm/board-8064.c
index 9ed71da..f3d648e 100644
--- a/arch/arm/mach-msm/board-8064.c
+++ b/arch/arm/mach-msm/board-8064.c
@@ -4005,6 +4005,7 @@
 	.init_early = apq8064_allocate_memory_regions,
 	.init_very_early = apq8064_early_reserve,
 	.restart = msm_restart,
+	.smp = &msm8960_smp_ops,
 MACHINE_END
 
 MACHINE_START(APQ8064_MTP, "QCT APQ8064 MTP")
diff --git a/arch/arm/mach-msm/board-qrd7627a.c b/arch/arm/mach-msm/board-qrd7627a.c
index 7038ab9..9c9ccaa 100644
--- a/arch/arm/mach-msm/board-qrd7627a.c
+++ b/arch/arm/mach-msm/board-qrd7627a.c
@@ -93,9 +93,9 @@
 		"qup_scl" },
 	{ GPIO_CFG(61, 0, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_8MA),
 		"qup_sda" },
-	{ GPIO_CFG(131, 0, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_8MA),
+	{ GPIO_CFG(131, 0, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
 		"qup_scl" },
-	{ GPIO_CFG(132, 0, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_8MA),
+	{ GPIO_CFG(132, 0, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
 		"qup_sda" },
 };
 
@@ -104,9 +104,9 @@
 		"qup_scl" },
 	{ GPIO_CFG(61, 1, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_8MA),
 		"qup_sda" },
-	{ GPIO_CFG(131, 2, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_8MA),
+	{ GPIO_CFG(131, 2, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
 		"qup_scl" },
-	{ GPIO_CFG(132, 2, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_8MA),
+	{ GPIO_CFG(132, 2, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
 		"qup_sda" },
 };
 
diff --git a/arch/arm/mach-msm/clock-8974.c b/arch/arm/mach-msm/clock-8974.c
index bfa9ec0..4cef377 100644
--- a/arch/arm/mach-msm/clock-8974.c
+++ b/arch/arm/mach-msm/clock-8974.c
@@ -809,6 +809,7 @@
 static DEFINE_CLK_BRANCH_VOTER(cxo_wlan_clk, &cxo_clk_src.c);
 static DEFINE_CLK_BRANCH_VOTER(cxo_pil_pronto_clk, &cxo_clk_src.c);
 static DEFINE_CLK_BRANCH_VOTER(cxo_dwc3_clk, &cxo_clk_src.c);
+static DEFINE_CLK_BRANCH_VOTER(cxo_ehci_host_clk, &cxo_clk_src.c);
 
 static struct clk_freq_tbl ftbl_gcc_usb30_master_clk[] = {
 	F(125000000,  gpll0,   1,   5,  24),
@@ -4893,6 +4894,7 @@
 	CLK_LOOKUP("xo",       cxo_wlan_clk.c, "fb000000.qcom,wcnss-wlan"),
 	CLK_LOOKUP("xo", cxo_pil_pronto_clk.c,     "fb21b000.qcom,pronto"),
 	CLK_LOOKUP("xo",       cxo_dwc3_clk.c,                 "msm_dwc3"),
+	CLK_LOOKUP("xo",  cxo_ehci_host_clk.c,            "msm_ehci_host"),
 
 	CLK_LOOKUP("measure",	measure_clk.c,	"debug"),
 
@@ -5033,9 +5035,11 @@
 
 	/* MM sensor clocks */
 	CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "6e.qcom,camera"),
+	CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "20.qcom,camera"),
 	CLK_LOOKUP("cam_src_clk", mclk2_clk_src.c, "6c.qcom,camera"),
 	CLK_LOOKUP("cam_src_clk", mclk1_clk_src.c, "90.qcom,camera"),
 	CLK_LOOKUP("cam_clk", camss_mclk0_clk.c, "6e.qcom,camera"),
+	CLK_LOOKUP("cam_clk", camss_mclk0_clk.c, "20.qcom,camera"),
 	CLK_LOOKUP("cam_clk", camss_mclk2_clk.c, "6c.qcom,camera"),
 	CLK_LOOKUP("cam_clk", camss_mclk1_clk.c, "90.qcom,camera"),
 	CLK_LOOKUP("cam_clk", camss_mclk1_clk.c, ""),
diff --git a/arch/arm/mach-msm/include/mach/ipa.h b/arch/arm/mach-msm/include/mach/ipa.h
index 1073266..f2a4427 100644
--- a/arch/arm/mach-msm/include/mach/ipa.h
+++ b/arch/arm/mach-msm/include/mach/ipa.h
@@ -463,26 +463,28 @@
 		enum a2_mux_event_type event,
 		unsigned long data);
 
-#ifdef CONFIG_IPA
-
-/*
- * a2 service
+/**
+ * enum teth_tethering_mode - Tethering mode (Rmnet / MBIM)
  */
-int a2_mux_open_channel(enum a2_mux_logical_channel_id lcid,
-			void *user_data,
-			a2_mux_notify_cb notify_cb);
+enum teth_tethering_mode {
+	TETH_TETHERING_MODE_RMNET,
+	TETH_TETHERING_MODE_MBIM,
+	TETH_TETHERING_MODE_MAX,
+};
 
-int a2_mux_close_channel(enum a2_mux_logical_channel_id lcid);
+/**
+ * struct teth_bridge_connect_params - Parameters used in teth_bridge_connect()
+ * @ipa_usb_pipe_hdl:	IPA to USB pipe handle, returned from ipa_connect()
+ * @usb_ipa_pipe_hdl:	USB to IPA pipe handle, returned from ipa_connect()
+ * @tethering_mode:	Rmnet or MBIM
+ */
+struct teth_bridge_connect_params {
+	u32 ipa_usb_pipe_hdl;
+	u32 usb_ipa_pipe_hdl;
+	enum teth_tethering_mode tethering_mode;
+};
 
-int a2_mux_write(enum a2_mux_logical_channel_id lcid, struct sk_buff *skb);
-
-int a2_mux_is_ch_low(enum a2_mux_logical_channel_id lcid);
-
-int a2_mux_is_ch_full(enum a2_mux_logical_channel_id lcid);
-
-int a2_mux_get_tethered_client_handles(enum a2_mux_logical_channel_id lcid,
-		unsigned int *clnt_cons_handle,
-		unsigned int *clnt_prod_handle);
+#ifdef CONFIG_IPA
 
 /*
  * Connect / Disconnect
@@ -652,6 +654,34 @@
 int ipa_rm_inactivity_timer_release_resource(
 				enum ipa_rm_resource_name resource_name);
 
+/*
+ * a2 service
+ */
+int a2_mux_open_channel(enum a2_mux_logical_channel_id lcid,
+			void *user_data,
+			a2_mux_notify_cb notify_cb);
+
+int a2_mux_close_channel(enum a2_mux_logical_channel_id lcid);
+
+int a2_mux_write(enum a2_mux_logical_channel_id lcid, struct sk_buff *skb);
+
+int a2_mux_is_ch_low(enum a2_mux_logical_channel_id lcid);
+
+int a2_mux_is_ch_full(enum a2_mux_logical_channel_id lcid);
+
+int a2_mux_get_tethered_client_handles(enum a2_mux_logical_channel_id lcid,
+		unsigned int *clnt_cons_handle,
+		unsigned int *clnt_prod_handle);
+
+/*
+ * Tethering bridge (Rmnet / MBIM)
+ */
+int teth_bridge_init(ipa_notify_cb *usb_notify_cb_ptr, void **private_data_ptr);
+
+int teth_bridge_disconnect(void);
+
+int teth_bridge_connect(struct teth_bridge_connect_params *connect_params);
+
 #else /* CONFIG_IPA */
 
 static inline int a2_mux_open_channel(enum a2_mux_logical_channel_id lcid,
@@ -688,7 +718,6 @@
 	return -EPERM;
 }
 
-
 /*
  * Connect / Disconnect
  */
@@ -1054,6 +1083,26 @@
 	return -EPERM;
 }
 
+/*
+ * Tethering bridge (Rmnetm / MBIM)
+ */
+static inline int teth_bridge_init(ipa_notify_cb *usb_notify_cb_ptr,
+				   void **private_data_ptr)
+{
+	return -EPERM;
+}
+
+static inline int teth_bridge_disconnect(void)
+{
+	return -EPERM;
+}
+
+static inline int teth_bridge_connect(struct teth_bridge_connect_params
+				      *connect_params)
+{
+	return -EPERM;
+}
+
 #endif /* CONFIG_IPA*/
 
 #endif /* _IPA_H_ */
diff --git a/arch/arm/mach-msm/ipc_socket.c b/arch/arm/mach-msm/ipc_socket.c
index 2cec5c5..a08e7de 100644
--- a/arch/arm/mach-msm/ipc_socket.c
+++ b/arch/arm/mach-msm/ipc_socket.c
@@ -20,6 +20,9 @@
 #include <linux/fcntl.h>
 #include <linux/gfp.h>
 #include <linux/msm_ipc.h>
+#include <linux/sched.h>
+#include <linux/thread_info.h>
+#include <linux/qmi_encdec.h>
 
 #include <asm/string.h>
 #include <asm/atomic.h>
@@ -27,16 +30,93 @@
 #include <net/sock.h>
 
 #include <mach/msm_ipc_router.h>
+#include <mach/msm_ipc_logging.h>
 
 #include "ipc_router.h"
 #include "msm_ipc_router_security.h"
 
 #define msm_ipc_sk(sk) ((struct msm_ipc_sock *)(sk))
 #define msm_ipc_sk_port(sk) ((struct msm_ipc_port *)(msm_ipc_sk(sk)->port))
+#define REQ_RESP_IPC_LOG_PAGES 5
+#define IND_IPC_LOG_PAGES 5
+#define IPC_SEND 1
+#define IPC_RECV 2
+#define IPC_REQ_RESP_LOG(level, buf...) \
+do { \
+	if (ipc_req_resp_log_txt) { \
+		ipc_log_string(ipc_req_resp_log_txt, buf); \
+	} \
+} while (0) \
+
+#define IPC_IND_LOG(level, buf...) \
+do { \
+	if (ipc_ind_log_txt) { \
+		ipc_log_string(ipc_ind_log_txt, buf); \
+	} \
+} while (0) \
 
 static int sockets_enabled;
 static struct proto msm_ipc_proto;
 static const struct proto_ops msm_ipc_proto_ops;
+static void *ipc_req_resp_log_txt;
+static void *ipc_ind_log_txt;
+
+/**
+ * msm_ipc_router_ipc_log() - Pass log data to IPC logging framework
+ * @tran:	Identifies the data to be a receive or send.
+ * @ipc_buf:	Buffer to extract the log data.
+ * @port_ptr:	IPC Router port corresponding to the current log data.
+ *
+ * This function builds the data the would be passed on to the IPC logging
+ * framework. The data that would be passed corresponds to the information
+ * that is exchanged between the IPC Router and user space modules during
+ * request/response/indication transactions.
+ */
+
+static void msm_ipc_router_ipc_log(uint8_t tran,
+			struct sk_buff *ipc_buf, struct msm_ipc_port *port_ptr)
+{
+	struct qmi_header *hdr = (struct qmi_header *)ipc_buf->data;
+
+	/*
+	 * IPC Logging format is as below:-
+	 * <Name>(Name of the User Space Process):
+	 * <PID> (PID of the user space process) :
+	 * <TID> (TID of the user space thread)  :
+	 * <User Space Module>(CLNT or  SERV)    :
+	 * <Opertaion Type> (Transmit)		 :
+	 * <Control Flag> (Req/Resp/Ind)	 :
+	 * <Transaction ID>			 :
+	 * <Message ID>				 :
+	 * <Message Length>			 :
+	 */
+	if (ipc_req_resp_log_txt &&
+		(((uint8_t) hdr->cntl_flag == QMI_REQUEST_CONTROL_FLAG) ||
+		((uint8_t) hdr->cntl_flag == QMI_RESPONSE_CONTROL_FLAG)) &&
+		(port_ptr->type == CLIENT_PORT ||
+					port_ptr->type == SERVER_PORT)) {
+		IPC_REQ_RESP_LOG(KERN_DEBUG,
+			"%s %d %d %s %s CF:%x TI:%x MI:%x ML:%x",
+			current->comm, current->tgid, current->pid,
+			(port_ptr->type == CLIENT_PORT ? "QCCI" : "QCSI"),
+			(tran == IPC_RECV ? "RX" :
+			(tran == IPC_SEND ? "TX" : "ERR")),
+			(uint8_t)hdr->cntl_flag, hdr->txn_id, hdr->msg_id,
+			hdr->msg_len);
+	} else if (ipc_ind_log_txt &&
+		((uint8_t)hdr->cntl_flag == QMI_INDICATION_CONTROL_FLAG) &&
+		(port_ptr->type == CLIENT_PORT ||
+					port_ptr->type == SERVER_PORT)) {
+		IPC_IND_LOG(KERN_DEBUG,
+			"%s %d %d %s %s CF:%x TI:%x MI:%x ML:%x",
+			current->comm, current->tgid, current->pid,
+			(port_ptr->type == CLIENT_PORT ? "QCCI" : "QCSI"),
+			(tran == IPC_RECV ? "RX" :
+			(tran == IPC_SEND ? "TX" : "ERR")),
+			(uint8_t)hdr->cntl_flag, hdr->txn_id, hdr->msg_id,
+			hdr->msg_len);
+	}
+}
 
 static struct sk_buff_head *msm_ipc_router_build_msg(unsigned int num_sect,
 					  struct iovec const *msg_sect,
@@ -263,6 +343,7 @@
 	struct msm_ipc_port *port_ptr = msm_ipc_sk_port(sk);
 	struct sockaddr_msm_ipc *dest = (struct sockaddr_msm_ipc *)m->msg_name;
 	struct sk_buff_head *msg;
+	struct sk_buff *ipc_buf;
 	int ret;
 
 	if (!dest)
@@ -284,7 +365,8 @@
 
 	if (port_ptr->type == CLIENT_PORT)
 		wait_for_irsc_completion();
-
+	ipc_buf = skb_peek(msg);
+	msm_ipc_router_ipc_log(IPC_SEND, ipc_buf, port_ptr);
 	ret = msm_ipc_router_send_to(port_ptr, msg, &dest->address);
 	if (ret == (IPC_ROUTER_HDR_SIZE + total_len))
 		ret = total_len;
@@ -300,6 +382,7 @@
 	struct sock *sk = sock->sk;
 	struct msm_ipc_port *port_ptr = msm_ipc_sk_port(sk);
 	struct sk_buff_head *msg;
+	struct sk_buff *ipc_buf;
 	long timeout;
 	int ret;
 
@@ -344,6 +427,8 @@
 	}
 
 	ret = msm_ipc_router_extract_msg(m, msg);
+	ipc_buf = skb_peek(msg);
+	msm_ipc_router_ipc_log(IPC_RECV, ipc_buf, port_ptr);
 	msm_ipc_router_release_msg(msg);
 	msg = NULL;
 	release_sock(sk);
@@ -518,6 +603,29 @@
 	.obj_size       = sizeof(struct msm_ipc_sock),
 };
 
+/**
+ * msm_ipc_router_ipc_log_init() - Init function for IPC Logging
+ *
+ * Initialize the buffers to be used to provide the log information
+ * pertaining to the request, response and indication data flow that
+ * happens between user and kernel spaces.
+ */
+void msm_ipc_router_ipc_log_init(void)
+{
+	ipc_req_resp_log_txt =
+		ipc_log_context_create(REQ_RESP_IPC_LOG_PAGES, "req_resp");
+	if (!ipc_req_resp_log_txt) {
+		pr_err("%s: Unable to create IPC logging for Req/Resp",
+			__func__);
+	}
+	ipc_ind_log_txt =
+		ipc_log_context_create(IND_IPC_LOG_PAGES, "indication");
+	if (!ipc_ind_log_txt) {
+		pr_err("%s: Unable to create IPC logging for Indications",
+			__func__);
+	}
+}
+
 int msm_ipc_router_init_sockets(void)
 {
 	int ret;
@@ -536,6 +644,7 @@
 	}
 
 	sockets_enabled = 1;
+	msm_ipc_router_ipc_log_init();
 out_init_sockets:
 	return ret;
 }
diff --git a/arch/arm/mach-msm/smd_tty.c b/arch/arm/mach-msm/smd_tty.c
index 1820b23..5969a3c 100644
--- a/arch/arm/mach-msm/smd_tty.c
+++ b/arch/arm/mach-msm/smd_tty.c
@@ -47,7 +47,7 @@
 
 struct smd_tty_info {
 	smd_channel_t *ch;
-	struct tty_struct *tty;
+	struct tty_port port;
 	struct wake_lock wake_lock;
 	int open_count;
 	struct tasklet_struct tty_tsklt;
@@ -125,7 +125,7 @@
 	unsigned char *ptr;
 	int avail;
 	struct smd_tty_info *info = (struct smd_tty_info *)param;
-	struct tty_struct *tty = info->tty;
+	struct tty_struct *tty = tty_port_tty_get(&info->port);
 	unsigned long flags;
 
 	if (!tty)
@@ -156,6 +156,7 @@
 		if (avail <= 0) {
 			mod_timer(&info->buf_req_timer,
 					jiffies + msecs_to_jiffies(30));
+			tty_kref_put(tty);
 			return;
 		}
 
@@ -173,11 +174,13 @@
 
 	/* XXX only when writable and necessary */
 	tty_wakeup(tty);
+	tty_kref_put(tty);
 }
 
 static void smd_tty_notify(void *priv, unsigned event)
 {
 	struct smd_tty_info *info = priv;
+	struct tty_struct *tty;
 	unsigned long flags;
 
 	switch (event) {
@@ -195,8 +198,10 @@
 		 */
 		if (smd_write_avail(info->ch)) {
 			smd_disable_read_intr(info->ch);
-			if (info->tty)
-				wake_up_interruptible(&info->tty->write_wait);
+			tty = tty_port_tty_get(&info->port);
+			if (tty)
+				wake_up_interruptible(&tty->write_wait);
+			tty_kref_put(tty);
 		}
 		spin_lock_irqsave(&info->ra_lock, flags);
 		if (smd_read_avail(info->ch)) {
@@ -225,9 +230,11 @@
 		/* schedule task to send TTY_BREAK */
 		tasklet_hi_schedule(&info->tty_tsklt);
 
-		if (info->tty->index == LOOPBACK_IDX)
+		tty = tty_port_tty_get(&info->port);
+		if (tty->index == LOOPBACK_IDX)
 			schedule_delayed_work(&loopback_work,
 					msecs_to_jiffies(1000));
+		tty_kref_put(tty);
 		break;
 	}
 }
@@ -241,7 +248,8 @@
 	return (modem_state & ready_state) == ready_state;
 }
 
-static int smd_tty_open(struct tty_struct *tty, struct file *f)
+static int smd_tty_port_activate(struct tty_port *tport,
+				 struct tty_struct *tty)
 {
 	int res = 0;
 	unsigned int n = tty->index;
@@ -306,8 +314,6 @@
 			}
 		}
 
-
-		info->tty = tty;
 		tasklet_init(&info->tty_tsklt, smd_tty_read,
 			     (unsigned long)info);
 		wake_lock_init(&info->wake_lock, WAKE_LOCK_SUSPEND,
@@ -354,24 +360,27 @@
 	return res;
 }
 
-static void smd_tty_close(struct tty_struct *tty, struct file *f)
+static void smd_tty_port_shutdown(struct tty_port *tport)
 {
-	struct smd_tty_info *info = tty->driver_data;
+	struct smd_tty_info *info;
+	struct tty_struct *tty = tty_port_tty_get(tport);
 	unsigned long flags;
 
-	if (info == 0)
+	info = tty->driver_data;
+	if (info == 0) {
+		tty_kref_put(tty);
 		return;
+	}
 
 	mutex_lock(&smd_tty_lock);
 	if (--info->open_count == 0) {
 		spin_lock_irqsave(&info->reset_lock, flags);
 		info->is_open = 0;
 		spin_unlock_irqrestore(&info->reset_lock, flags);
-		if (info->tty) {
+		if (tty) {
 			tasklet_kill(&info->tty_tsklt);
 			wake_lock_destroy(&info->wake_lock);
 			wake_lock_destroy(&info->ra_wake_lock);
-			info->tty = 0;
 		}
 		tty->driver_data = 0;
 		del_timer(&info->buf_req_timer);
@@ -382,6 +391,21 @@
 		}
 	}
 	mutex_unlock(&smd_tty_lock);
+	tty_kref_put(tty);
+}
+
+static int smd_tty_open(struct tty_struct *tty, struct file *f)
+{
+	struct smd_tty_info *info = smd_tty + tty->index;
+
+	return tty_port_open(&info->port, tty, f);
+}
+
+static void smd_tty_close(struct tty_struct *tty, struct file *f)
+{
+	struct smd_tty_info *info = tty->driver_data;
+
+	tty_port_close(&info->port, tty, f);
 }
 
 static int smd_tty_write(struct tty_struct *tty, const unsigned char *buf, int len)
@@ -482,6 +506,11 @@
 			  0, SMSM_SMD_LOOPBACK);
 }
 
+static const struct tty_port_operations smd_tty_port_ops = {
+	.shutdown = smd_tty_port_shutdown,
+	.activate = smd_tty_port_activate,
+};
+
 static struct tty_operations smd_tty_ops = {
 	.open = smd_tty_open,
 	.close = smd_tty_close,
@@ -523,6 +552,7 @@
 	int ret;
 	int n;
 	int idx;
+	struct tty_port *port;
 
 	smd_tty_driver = alloc_tty_driver(MAX_SMD_TTYS);
 	if (smd_tty_driver == 0)
@@ -578,6 +608,10 @@
 				continue;
 		}
 
+		port = &smd_tty[idx].port;
+		tty_port_init(port);
+		port->ops = &smd_tty_port_ops;
+		/* TODO: For kernel >= 3.7 use tty_port_register_device */
 		tty_register_device(smd_tty_driver, idx, 0);
 		init_completion(&smd_tty[idx].ch_allocated);
 
diff --git a/drivers/base/dma-contiguous.c b/drivers/base/dma-contiguous.c
index e879026..3a8bbc5 100644
--- a/drivers/base/dma-contiguous.c
+++ b/drivers/base/dma-contiguous.c
@@ -58,6 +58,7 @@
 	phys_addr_t base;
 	unsigned long size;
 	struct cma *cma;
+	const char *name;
 } cma_areas[MAX_CMA_AREAS];
 static unsigned cma_area_count;
 
@@ -77,6 +78,20 @@
 	return NULL;
 }
 
+static struct cma *cma_get_area_by_name(const char *name)
+{
+	int i;
+	if (!name)
+		return NULL;
+
+	for (i = 0; i < cma_area_count; i++)
+		if (cma_areas[i].name && strcmp(cma_areas[i].name, name) == 0)
+			return cma_areas[i].cma;
+	return NULL;
+}
+
+
+
 #ifdef CONFIG_CMA_SIZE_MBYTES
 #define CMA_SIZE_MBYTES CONFIG_CMA_SIZE_MBYTES
 #else
@@ -196,6 +211,7 @@
 	phys_addr_t base, size;
 	unsigned long len;
 	__be32 *prop;
+	char *name;
 
 	if (strncmp(uname, "region@", 7) != 0 || depth != 2 ||
 	    !of_get_flat_dt_prop(node, "linux,contiguous-region", NULL))
@@ -208,9 +224,11 @@
 	base = be32_to_cpu(prop[0]);
 	size = be32_to_cpu(prop[1]);
 
+	name = of_get_flat_dt_prop(node, "label", NULL);
+
 	pr_info("Found %s, memory base %lx, size %ld MiB\n", uname,
 		(unsigned long)base, (unsigned long)size / SZ_1M);
-	dma_contiguous_reserve_area(size, &base, 0);
+	dma_contiguous_reserve_area(size, &base, 0, name);
 
 	return 0;
 }
@@ -251,7 +269,8 @@
 		pr_debug("%s: reserving %ld MiB for global area\n", __func__,
 			 (unsigned long)sel_size / SZ_1M);
 
-		if (dma_contiguous_reserve_area(sel_size, &base, limit) == 0)
+		if (dma_contiguous_reserve_area(sel_size, &base, limit, NULL)
+		    == 0)
 			dma_contiguous_def_base = base;
 	}
 #ifdef CONFIG_OF
@@ -274,7 +293,7 @@
  * devices.
  */
 int __init dma_contiguous_reserve_area(phys_addr_t size, phys_addr_t *res_base,
-				       phys_addr_t limit)
+				       phys_addr_t limit, const char *name)
 {
 	phys_addr_t base = *res_base;
 	phys_addr_t alignment;
@@ -326,6 +345,7 @@
 	 */
 	cma_areas[cma_area_count].base = base;
 	cma_areas[cma_area_count].size = size;
+	cma_areas[cma_area_count].name = name;
 	cma_area_count++;
 	*res_base = base;
 
@@ -366,6 +386,7 @@
 {
 	struct device_node *node;
 	struct cma *cma;
+	const char *name;
 	u32 value;
 
 	node = of_parse_phandle(dev->of_node, "linux,contiguous-region", 0);
@@ -373,7 +394,11 @@
 		return;
 	if (of_property_read_u32(node, "reg", &value) && !value)
 		return;
-	cma = cma_get_area(value);
+
+	if (of_property_read_string(node, "label", &name))
+		return;
+
+	cma = cma_get_area_by_name(name);
 	if (!cma)
 		return;
 
diff --git a/drivers/char/diag/diagchar_hdlc.c b/drivers/char/diag/diagchar_hdlc.c
index b94ea2f..2369c4d 100644
--- a/drivers/char/diag/diagchar_hdlc.c
+++ b/drivers/char/diag/diagchar_hdlc.c
@@ -1,4 +1,5 @@
-/* Copyright (c) 2008-2009, 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2008-2009, 2012-2013, The Linux Foundation.
+ * All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -172,11 +173,14 @@
 	uint8_t src_byte;
 
 	int pkt_bnd = 0;
+	int msg_start;
 
 	if (hdlc && hdlc->src_ptr && hdlc->dest_ptr &&
 	    (hdlc->src_size - hdlc->src_idx > 0) &&
 	    (hdlc->dest_size - hdlc->dest_idx > 0)) {
 
+		msg_start = (hdlc->src_idx == 0) ? 1 : 0;
+
 		src_ptr = hdlc->src_ptr;
 		src_ptr = &src_ptr[hdlc->src_idx];
 		src_length = hdlc->src_size - hdlc->src_idx;
@@ -203,8 +207,16 @@
 				}
 			} else if (src_byte == CONTROL_CHAR) {
 				dest_ptr[len++] = src_byte;
-				pkt_bnd = 1;
+				/*
+				 * If this is the first byte in the message,
+				 * then it is part of the command. Otherwise,
+				 * consider it as the last byte of the
+				 * message.
+				 */
+				if (msg_start && i == 0 && src_length > 1)
+					continue;
 				i++;
+				pkt_bnd = 1;
 				break;
 			} else {
 				dest_ptr[len++] = src_byte;
diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c
index 7f4edd1..2aca8cf 100644
--- a/drivers/char/diag/diagfwd.c
+++ b/drivers/char/diag/diagfwd.c
@@ -993,10 +993,18 @@
 
 	ret = diag_hdlc_decode(&hdlc);
 
-	if (hdlc.dest_idx < 3) {
-		pr_err("diag: Integer underflow in hdlc processing\n");
+	/*
+	 * If the message is 3 bytes or less in length then the message is
+	 * too short. A message will need 4 bytes minimum, since there are
+	 * 2 bytes for the CRC and 1 byte for the ending 0x7e for the hdlc
+	 * encoding
+	 */
+	if (hdlc.dest_idx < 4) {
+		pr_err_ratelimited("diag: In %s, message is too short, len: %d, dest len: %d\n",
+			__func__, len, hdlc.dest_idx);
 		return;
 	}
+
 	if (ret) {
 		type = diag_process_apps_pkt(driver->hdlc_buf,
 							  hdlc.dest_idx - 3);
diff --git a/drivers/gpu/ion/msm/msm_ion.c b/drivers/gpu/ion/msm/msm_ion.c
index 1ca457f..832a9a1 100644
--- a/drivers/gpu/ion/msm/msm_ion.c
+++ b/drivers/gpu/ion/msm/msm_ion.c
@@ -55,7 +55,7 @@
 	},
 	{
 		.id	= ION_CP_MM_HEAP_ID,
-		.type	= ION_HEAP_TYPE_CP,
+		.type	= ION_HEAP_TYPE_SECURE_DMA,
 		.name	= ION_MM_HEAP_NAME,
 		.permission_type = IPT_TYPE_MM_CARVEOUT,
 	},
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index b7d813c..b1a45bf 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -2000,8 +2000,17 @@
 		/* Is the ring buffer is empty? */
 		GSL_RB_GET_READPTR(rb, &rb->rptr);
 		if (!device->active_cnt && (rb->rptr == rb->wptr)) {
-			/* Is the core idle? */
-			status = is_adreno_rbbm_status_idle(device);
+			/*
+			 * Are there interrupts pending? If so then pretend we
+			 * are not idle - this avoids the possiblity that we go
+			 * to a lower power state without handling interrupts
+			 * first.
+			 */
+
+			if (!adreno_dev->gpudev->irq_pending(adreno_dev)) {
+				/* Is the core idle? */
+				status = is_adreno_rbbm_status_idle(device);
+			}
 		}
 	} else {
 		status = true;
diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h
index cc6eb16..b1cab9b 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -125,6 +125,7 @@
 					struct adreno_context *);
 	irqreturn_t (*irq_handler)(struct adreno_device *);
 	void (*irq_control)(struct adreno_device *, int);
+	unsigned int (*irq_pending)(struct adreno_device *);
 	void * (*snapshot)(struct adreno_device *, void *, int *, int);
 	void (*rb_init)(struct adreno_device *, struct adreno_ringbuffer *);
 	void (*start)(struct adreno_device *);
diff --git a/drivers/gpu/msm/adreno_a2xx.c b/drivers/gpu/msm/adreno_a2xx.c
index 952d1f8..6db6e7b 100644
--- a/drivers/gpu/msm/adreno_a2xx.c
+++ b/drivers/gpu/msm/adreno_a2xx.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2002,2007-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2002,2007-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -1706,34 +1706,6 @@
 		return;
 	}
 
-	if (status & CP_INT_CNTL__RB_INT_MASK) {
-		/* signal intr completion event */
-		unsigned int context_id, timestamp;
-		kgsl_sharedmem_readl(&device->memstore, &context_id,
-				KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
-					current_context));
-
-		kgsl_sharedmem_readl(&device->memstore, &timestamp,
-				KGSL_MEMSTORE_OFFSET(context_id,
-					eoptimestamp));
-
-		if (context_id < KGSL_MEMSTORE_MAX) {
-			/* reset per context ts_cmp_enable */
-			kgsl_sharedmem_writel(&device->memstore,
-					KGSL_MEMSTORE_OFFSET(context_id,
-						ts_cmp_enable), 0);
-			/* Always reset global timestamp ts_cmp_enable */
-			kgsl_sharedmem_writel(&device->memstore,
-					KGSL_MEMSTORE_OFFSET(
-						KGSL_MEMSTORE_GLOBAL,
-						ts_cmp_enable), 0);
-			wmb();
-		}
-
-		KGSL_CMD_WARN(device, "<%d:0x%x> ringbuffer interrupt\n",
-				context_id, timestamp);
-	}
-
 	for (i = 0; i < ARRAY_SIZE(kgsl_cp_error_irqs); i++) {
 		if (status & kgsl_cp_error_irqs[i].mask) {
 			KGSL_CMD_CRIT(rb->device, "%s\n",
@@ -1840,6 +1812,19 @@
 	wmb();
 }
 
+static unsigned int a2xx_irq_pending(struct adreno_device *adreno_dev)
+{
+	struct kgsl_device *device = &adreno_dev->dev;
+	unsigned int rbbm, cp, mh;
+
+	adreno_regread(device, REG_RBBM_INT_CNTL, &rbbm);
+	adreno_regread(device, REG_CP_INT_CNTL, &cp);
+	adreno_regread(device, MH_INTERRUPT_MASK, &mh);
+
+	return ((rbbm & RBBM_INT_MASK) || (cp & CP_INT_MASK) ||
+		(mh & kgsl_mmu_get_int_mask())) ? 1 : 0;
+}
+
 static void a2xx_rb_init(struct adreno_device *adreno_dev,
 			struct adreno_ringbuffer *rb)
 {
@@ -2035,6 +2020,7 @@
 	.ctxt_draw_workaround = a2xx_drawctxt_draw_workaround,
 	.irq_handler = a2xx_irq_handler,
 	.irq_control = a2xx_irq_control,
+	.irq_pending = a2xx_irq_pending,
 	.snapshot = a2xx_snapshot,
 	.rb_init = a2xx_rb_init,
 	.busy_cycles = a2xx_busy_cycles,
diff --git a/drivers/gpu/msm/adreno_a3xx.c b/drivers/gpu/msm/adreno_a3xx.c
index a3739a2..73a7f52 100644
--- a/drivers/gpu/msm/adreno_a3xx.c
+++ b/drivers/gpu/msm/adreno_a3xx.c
@@ -2591,33 +2591,7 @@
 {
 	struct kgsl_device *device = &adreno_dev->dev;
 
-	if (irq == A3XX_INT_CP_RB_INT) {
-		unsigned int context_id, timestamp;
-		kgsl_sharedmem_readl(&device->memstore, &context_id,
-				KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
-					current_context));
-
-		kgsl_sharedmem_readl(&device->memstore, &timestamp,
-				KGSL_MEMSTORE_OFFSET(context_id,
-					eoptimestamp));
-
-		if (context_id < KGSL_MEMSTORE_MAX) {
-			/* reset per context ts_cmp_enable */
-			kgsl_sharedmem_writel(&device->memstore,
-					KGSL_MEMSTORE_OFFSET(context_id,
-						ts_cmp_enable), 0);
-			/* Always reset global timestamp ts_cmp_enable */
-			kgsl_sharedmem_writel(&device->memstore,
-					KGSL_MEMSTORE_OFFSET(
-						KGSL_MEMSTORE_GLOBAL,
-						ts_cmp_enable), 0);
-			wmb();
-		}
-
-		KGSL_CMD_WARN(device, "<%d:0x%x> ringbuffer interrupt\n",
-				context_id, timestamp);
-	}
-
+	/* Wake up everybody waiting for the interrupt */
 	wake_up_interruptible_all(&device->wait_queue);
 
 	/* Schedule work to free mem and issue ibs */
@@ -2713,6 +2687,15 @@
 		adreno_regwrite(device, A3XX_RBBM_INT_0_MASK, 0);
 }
 
+static unsigned int a3xx_irq_pending(struct adreno_device *adreno_dev)
+{
+	unsigned int status;
+
+	adreno_regread(&adreno_dev->dev, A3XX_RBBM_INT_0_STATUS, &status);
+
+	return (status & A3XX_INT_MASK) ? 1 : 0;
+}
+
 static unsigned int a3xx_busy_cycles(struct adreno_device *adreno_dev)
 {
 	struct kgsl_device *device = &adreno_dev->dev;
@@ -2958,6 +2941,7 @@
 	.rb_init = a3xx_rb_init,
 	.irq_control = a3xx_irq_control,
 	.irq_handler = a3xx_irq_handler,
+	.irq_pending = a3xx_irq_pending,
 	.busy_cycles = a3xx_busy_cycles,
 	.start = a3xx_start,
 	.snapshot = a3xx_snapshot,
diff --git a/drivers/gpu/msm/adreno_ringbuffer.c b/drivers/gpu/msm/adreno_ringbuffer.c
index c43ac51..1d25646 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.c
+++ b/drivers/gpu/msm/adreno_ringbuffer.c
@@ -570,7 +570,7 @@
 	total_sizedwords += (flags & KGSL_CMD_FLAGS_INTERNAL_ISSUE) ? 2 : 0;
 
 	/* Add CP_COND_EXEC commands to generate CP_INTERRUPT */
-	total_sizedwords += context ? 7 : 0;
+	total_sizedwords += context ? 13 : 0;
 
 	if (adreno_is_a3xx(adreno_dev))
 		total_sizedwords += 7;
@@ -720,7 +720,25 @@
 				context_id, ref_wait_ts)) >> 2);
 		GSL_RB_WRITE(ringcmds, rcmd_gpu, timestamp);
 		/* # of conditional command DWORDs */
-		GSL_RB_WRITE(ringcmds, rcmd_gpu, 2);
+		GSL_RB_WRITE(ringcmds, rcmd_gpu, 8);
+
+		/* Clear the ts_cmp_enable for the context */
+		GSL_RB_WRITE(ringcmds, rcmd_gpu,
+			cp_type3_packet(CP_MEM_WRITE, 2));
+		GSL_RB_WRITE(ringcmds, rcmd_gpu, gpuaddr +
+			KGSL_MEMSTORE_OFFSET(
+				context_id, ts_cmp_enable));
+		GSL_RB_WRITE(ringcmds, rcmd_gpu, 0x0);
+
+		/* Clear the ts_cmp_enable for the global timestamp */
+		GSL_RB_WRITE(ringcmds, rcmd_gpu,
+			cp_type3_packet(CP_MEM_WRITE, 2));
+		GSL_RB_WRITE(ringcmds, rcmd_gpu, gpuaddr +
+			KGSL_MEMSTORE_OFFSET(
+				KGSL_MEMSTORE_GLOBAL, ts_cmp_enable));
+		GSL_RB_WRITE(ringcmds, rcmd_gpu, 0x0);
+
+		/* Trigger the interrupt */
 		GSL_RB_WRITE(ringcmds, rcmd_gpu,
 			cp_type3_packet(CP_INTERRUPT, 1));
 		GSL_RB_WRITE(ringcmds, rcmd_gpu, CP_INT_CNTL__RB_INT_MASK);
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index 115fcb7..7ed0b10 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -1088,10 +1088,7 @@
 				      result);
 
 	/* Fire off any pending suspend operations that are in flight */
-
-	INIT_COMPLETION(dev_priv->device->suspend_gate);
-	dev_priv->device->active_cnt--;
-	complete(&dev_priv->device->suspend_gate);
+	kgsl_active_count_put(dev_priv->device);
 
 	return result;
 }
diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h
index 62316f3..66390fc 100644
--- a/drivers/gpu/msm/kgsl_device.h
+++ b/drivers/gpu/msm/kgsl_device.h
@@ -133,6 +133,7 @@
 	void *priv;
 	struct list_head list;
 	void *owner;
+	unsigned int created;
 };
 
 
@@ -449,4 +450,23 @@
 	kref_put(&context->refcount, kgsl_context_destroy);
 }
 
+/**
+ * kgsl_active_count_put - Decrease the device active count
+ * @device: Pointer to a KGSL device
+ *
+ * Decrease the active count for the KGSL device and trigger the suspend_gate
+ * completion if it hits zero
+ */
+static inline void
+kgsl_active_count_put(struct kgsl_device *device)
+{
+	if (device->active_cnt == 1)
+		INIT_COMPLETION(device->suspend_gate);
+
+	device->active_cnt--;
+
+	if (device->active_cnt == 0)
+		complete(&device->suspend_gate);
+}
+
 #endif  /* __KGSL_DEVICE_H */
diff --git a/drivers/gpu/msm/kgsl_events.c b/drivers/gpu/msm/kgsl_events.c
index be9b5eb..6798eed 100644
--- a/drivers/gpu/msm/kgsl_events.c
+++ b/drivers/gpu/msm/kgsl_events.c
@@ -16,6 +16,8 @@
 #include <linux/module.h>
 #include <kgsl_device.h>
 
+#include "kgsl_trace.h"
+
 static void _add_event_to_list(struct list_head *head, struct kgsl_event *event)
 {
 	struct list_head *n;
@@ -71,6 +73,7 @@
 	 */
 
 	if (timestamp_cmp(cur_ts, ts) >= 0) {
+		trace_kgsl_fire_event(id, ts, 0);
 		cb(device, priv, id, ts);
 		return 0;
 	}
@@ -84,6 +87,9 @@
 	event->priv = priv;
 	event->func = cb;
 	event->owner = owner;
+	event->created = jiffies;
+
+	trace_kgsl_register_event(id, ts);
 
 	/* inc refcount to avoid race conditions in cleanup */
 	if (context)
@@ -106,6 +112,13 @@
 	} else
 		_add_event_to_list(&device->events, event);
 
+	/*
+	 * Increase the active count on the device to avoid going into power
+	 * saving modes while events are pending
+	 */
+
+	device->active_cnt++;
+
 	queue_work(device->work_queue, &device->ts_expired_ws);
 	return 0;
 }
@@ -137,12 +150,16 @@
 		 * system got before the event was canceled
 		 */
 
+		trace_kgsl_fire_event(id, cur, jiffies - event->created);
+
 		if (event->func)
 			event->func(device, event->priv, id, cur);
 
 		kgsl_context_put(context);
 		list_del(&event->list);
 		kfree(event);
+
+		kgsl_active_count_put(device);
 	}
 
 	/* Remove ourselves from the master pending list */
@@ -175,6 +192,10 @@
 		 * the callback knows how far the GPU made it before things went
 		 * explosion
 		 */
+
+		trace_kgsl_fire_event(KGSL_MEMSTORE_GLOBAL, cur,
+			jiffies - event->created);
+
 		if (event->func)
 			event->func(device, event->priv, KGSL_MEMSTORE_GLOBAL,
 				cur);
@@ -184,6 +205,8 @@
 
 		list_del(&event->list);
 		kfree(event);
+
+		kgsl_active_count_put(device);
 	}
 }
 EXPORT_SYMBOL(kgsl_cancel_events);
@@ -207,6 +230,9 @@
 		 * to the timestamp they wanted
 		 */
 
+		trace_kgsl_fire_event(id, event->timestamp,
+			jiffies - event->created);
+
 		if (event->func)
 			event->func(device, event->priv, id, event->timestamp);
 
@@ -215,6 +241,8 @@
 
 		list_del(&event->list);
 		kfree(event);
+
+		kgsl_active_count_put(device);
 	}
 }
 
diff --git a/drivers/gpu/msm/kgsl_trace.h b/drivers/gpu/msm/kgsl_trace.h
index f7818bb..8c4811e 100644
--- a/drivers/gpu/msm/kgsl_trace.h
+++ b/drivers/gpu/msm/kgsl_trace.h
@@ -693,6 +693,41 @@
 	)
 );
 
+TRACE_EVENT(kgsl_register_event,
+		TP_PROTO(unsigned int id, unsigned int timestamp),
+		TP_ARGS(id, timestamp),
+		TP_STRUCT__entry(
+			__field(unsigned int, id)
+			__field(unsigned int, timestamp)
+		),
+		TP_fast_assign(
+			__entry->id = id;
+			__entry->timestamp = timestamp;
+		),
+		TP_printk(
+			"ctx=%d ts=%d",
+			__entry->id, __entry->timestamp)
+);
+
+TRACE_EVENT(kgsl_fire_event,
+		TP_PROTO(unsigned int id, unsigned int ts,
+			unsigned int age),
+		TP_ARGS(id, ts, age),
+		TP_STRUCT__entry(
+			__field(unsigned int, id)
+			__field(unsigned int, ts)
+			__field(unsigned int, age)
+		),
+		TP_fast_assign(
+			__entry->id = id;
+			__entry->ts = ts;
+			__entry->age = age;
+		),
+		TP_printk(
+			"ctx=%d ts=%d age=%u",
+			__entry->id, __entry->ts, __entry->age)
+);
+
 #endif /* _KGSL_TRACE_H */
 
 /* This part must be outside protection */
diff --git a/drivers/input/touchscreen/synaptics_i2c_rmi4.c b/drivers/input/touchscreen/synaptics_i2c_rmi4.c
index 899c83b..2c79276 100644
--- a/drivers/input/touchscreen/synaptics_i2c_rmi4.c
+++ b/drivers/input/touchscreen/synaptics_i2c_rmi4.c
@@ -82,6 +82,8 @@
 #define RMI4_I2C_LOAD_UA	10000
 #define RMI4_I2C_LPM_LOAD_UA	10
 
+#define RMI4_GPIO_SLEEP_LOW_US 10000
+#define RMI4_GPIO_WAIT_HIGH_MS 25
 
 static int synaptics_rmi4_i2c_read(struct synaptics_rmi4_data *rmi4_data,
 		unsigned short addr, unsigned char *data,
@@ -1871,15 +1873,60 @@
 	retval = synaptics_rmi4_regulator_configure(rmi4_data, true);
 	if (retval < 0) {
 		dev_err(&client->dev, "Failed to configure regulators\n");
-		goto err_input_device;
+		goto err_reg_configure;
 	}
 
 	retval = synaptics_rmi4_power_on(rmi4_data, true);
 	if (retval < 0) {
 		dev_err(&client->dev, "Failed to power on\n");
-		goto err_input_device;
+		goto err_power_device;
 	}
 
+	if (gpio_is_valid(platform_data->irq_gpio)) {
+		/* configure touchscreen irq gpio */
+		retval = gpio_request(platform_data->irq_gpio, "rmi4_irq_gpio");
+		if (retval) {
+			dev_err(&client->dev, "unable to request gpio [%d]\n",
+						platform_data->irq_gpio);
+			goto err_query_device;
+		}
+		retval = gpio_direction_input(platform_data->irq_gpio);
+		if (retval) {
+			dev_err(&client->dev,
+				"unable to set direction for gpio [%d]\n",
+				platform_data->irq_gpio);
+			goto err_irq_gpio_req;
+		}
+	} else {
+		dev_err(&client->dev, "irq gpio not provided\n");
+		goto err_query_device;
+	}
+
+	if (gpio_is_valid(platform_data->reset_gpio)) {
+		/* configure touchscreen reset out gpio */
+		retval = gpio_request(platform_data->reset_gpio,
+				"rmi4_reset_gpio");
+		if (retval) {
+			dev_err(&client->dev, "unable to request gpio [%d]\n",
+						platform_data->reset_gpio);
+			goto err_irq_gpio_req;
+		}
+
+		retval = gpio_direction_output(platform_data->reset_gpio, 1);
+		if (retval) {
+			dev_err(&client->dev,
+				"unable to set direction for gpio [%d]\n",
+				platform_data->reset_gpio);
+			goto err_reset_gpio_req;
+		}
+
+		gpio_set_value(platform_data->reset_gpio, 0);
+		usleep(RMI4_GPIO_SLEEP_LOW_US);
+		gpio_set_value(platform_data->reset_gpio, 1);
+		msleep(RMI4_GPIO_WAIT_HIGH_MS);
+	}
+
+
 	init_waitqueue_head(&rmi4_data->wait);
 	mutex_init(&(rmi4_data->rmi4_io_ctrl_mutex));
 
@@ -1888,7 +1935,7 @@
 		dev_err(&client->dev,
 				"%s: Failed to query device\n",
 				__func__);
-		goto err_query_device;
+		goto err_reset_gpio_req;
 	}
 
 	i2c_set_clientdata(client, rmi4_data);
@@ -1972,9 +2019,6 @@
 	input_unregister_device(rmi4_data->input_dev);
 
 err_register_input:
-err_query_device:
-	synaptics_rmi4_power_on(rmi4_data, false);
-	synaptics_rmi4_regulator_configure(rmi4_data, false);
 	if (!list_empty(&rmi->support_fn_list)) {
 		list_for_each_entry(fhandler, &rmi->support_fn_list, link) {
 			if (fhandler->fn_number == SYNAPTICS_RMI4_F1A)
@@ -1984,6 +2028,17 @@
 			kfree(fhandler);
 		}
 	}
+err_reset_gpio_req:
+	if (gpio_is_valid(platform_data->reset_gpio))
+		gpio_free(platform_data->reset_gpio);
+err_irq_gpio_req:
+	if (gpio_is_valid(platform_data->irq_gpio))
+		gpio_free(platform_data->irq_gpio);
+err_query_device:
+	synaptics_rmi4_power_on(rmi4_data, false);
+err_power_device:
+	synaptics_rmi4_regulator_configure(rmi4_data, false);
+err_reg_configure:
 	input_free_device(rmi4_data->input_dev);
 	rmi4_data->input_dev = NULL;
 err_input_device:
@@ -2036,7 +2091,11 @@
 			kfree(fhandler);
 		}
 	}
-	input_free_device(rmi4_data->input_dev);
+
+	if (gpio_is_valid(rmi4_data->board->reset_gpio))
+		gpio_free(rmi4_data->board->reset_gpio);
+	if (gpio_is_valid(rmi4_data->board->irq_gpio))
+		gpio_free(rmi4_data->board->irq_gpio);
 
 	synaptics_rmi4_power_on(rmi4_data, false);
 	synaptics_rmi4_regulator_configure(rmi4_data, false);
diff --git a/drivers/media/platform/msm/camera_v2/Kconfig b/drivers/media/platform/msm/camera_v2/Kconfig
index 2bbdc22..e4777e6 100644
--- a/drivers/media/platform/msm/camera_v2/Kconfig
+++ b/drivers/media/platform/msm/camera_v2/Kconfig
@@ -82,6 +82,15 @@
 		snapshot config = 4000 * 3000 at 20 fps,
 		hfr video at 60, 90 and 120 fps.
 
+config IMX135
+	bool "Sensor IMX135 (BAYER 12M)"
+	depends on MSMB_CAMERA
+	---help---
+		Sony 12 MP Bayer Sensor with auto focus, uses
+		4 mipi lanes, preview config = 2104 x 1560 at 49 fps,
+		snapshot config = 4208 x 3120 at 24 fps,
+		Video HDR support.
+
 config OV2720
 	bool "Sensor OV2720 (BAYER 2M)"
 	depends on MSMB_CAMERA
diff --git a/drivers/media/platform/msm/camera_v2/msm.c b/drivers/media/platform/msm/camera_v2/msm.c
index 08a4566..6974cb4 100644
--- a/drivers/media/platform/msm/camera_v2/msm.c
+++ b/drivers/media/platform/msm/camera_v2/msm.c
@@ -461,9 +461,6 @@
 static inline int __msm_sd_close_session_streams(struct v4l2_subdev *sd,
 	struct msm_sd_close_ioctl *sd_close)
 {
-	v4l2_subdev_call(sd, core, ioctl,
-		MSM_SD_CLOSE_SESSION_AND_STREAM, &sd_close);
-
 	return 0;
 }
 
diff --git a/drivers/media/platform/msm/camera_v2/msm_vb2/msm_vb2.c b/drivers/media/platform/msm/camera_v2/msm_vb2/msm_vb2.c
index 6ea86ae..22131f8 100644
--- a/drivers/media/platform/msm/camera_v2/msm_vb2/msm_vb2.c
+++ b/drivers/media/platform/msm/camera_v2/msm_vb2/msm_vb2.c
@@ -105,7 +105,7 @@
 	unsigned long flags;
 
 	stream = msm_get_stream(session_id, stream_id);
-	if (!stream)
+	if (IS_ERR_OR_NULL(stream))
 		return NULL;
 
 	spin_lock_irqsave(&stream->stream_lock, flags);
@@ -163,7 +163,7 @@
 	int rc = 0;
 
 	stream = msm_get_stream(session_id, stream_id);
-	if (!stream)
+	if (IS_ERR_OR_NULL(stream))
 		return 0;
 	spin_lock_irqsave(&stream->stream_lock, flags);
 	if (vb) {
@@ -172,6 +172,7 @@
 		/* put buf before buf done */
 		if (msm_vb2->in_freeq) {
 			vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
+			msm_vb2->in_freeq = 0;
 			rc = 0;
 		} else
 			rc = -EINVAL;
diff --git a/drivers/media/platform/msm/camera_v2/sensor/Makefile b/drivers/media/platform/msm/camera_v2/sensor/Makefile
index f6011ba..6f941f7 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/Makefile
+++ b/drivers/media/platform/msm/camera_v2/sensor/Makefile
@@ -6,5 +6,6 @@
 obj-$(CONFIG_MSMB_CAMERA) += cci/ io/ csiphy/ csid/ actuator/ flash/
 obj-$(CONFIG_MSM_CAMERA_SENSOR) += msm_sensor.o
 obj-$(CONFIG_S5K3L1YX) += s5k3l1yx.o
+obj-$(CONFIG_IMX135) += imx135.o
 obj-$(CONFIG_OV2720) += ov2720.o
 obj-$(CONFIG_MT9M114) += mt9m114.o
diff --git a/drivers/media/platform/msm/camera_v2/sensor/imx135.c b/drivers/media/platform/msm/camera_v2/sensor/imx135.c
new file mode 100644
index 0000000..c9476ee
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/sensor/imx135.c
@@ -0,0 +1,149 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#include "msm_sensor.h"
+#define IMX135_SENSOR_NAME "imx135"
+DEFINE_MSM_MUTEX(imx135_mut);
+
+static struct msm_sensor_ctrl_t imx135_s_ctrl;
+
+static struct msm_sensor_power_setting imx135_power_setting[] = {
+	{
+		.seq_type = SENSOR_VREG,
+		.seq_val = CAM_VDIG,
+		.config_val = 0,
+		.delay = 0,
+	},
+	{
+		.seq_type = SENSOR_VREG,
+		.seq_val = CAM_VANA,
+		.config_val = 0,
+		.delay = 0,
+	},
+	{
+		.seq_type = SENSOR_VREG,
+		.seq_val = CAM_VIO,
+		.config_val = 0,
+		.delay = 0,
+	},
+	{
+		.seq_type = SENSOR_GPIO,
+		.seq_val = SENSOR_GPIO_RESET,
+		.config_val = GPIO_OUT_LOW,
+		.delay = 1,
+	},
+	{
+		.seq_type = SENSOR_GPIO,
+		.seq_val = SENSOR_GPIO_RESET,
+		.config_val = GPIO_OUT_HIGH,
+		.delay = 30,
+	},
+	{
+		.seq_type = SENSOR_CLK,
+		.seq_val = SENSOR_CAM_MCLK,
+		.config_val = 0,
+		.delay = 1,
+	},
+	{
+		.seq_type = SENSOR_I2C_MUX,
+		.seq_val = 0,
+		.config_val = 0,
+		.delay = 0,
+	},
+};
+
+static struct v4l2_subdev_info imx135_subdev_info[] = {
+	{
+		.code = V4L2_MBUS_FMT_SBGGR10_1X10,
+		.colorspace = V4L2_COLORSPACE_JPEG,
+		.fmt = 1,
+		.order = 0,
+	},
+};
+
+static const struct i2c_device_id imx135_i2c_id[] = {
+	{IMX135_SENSOR_NAME, (kernel_ulong_t)&imx135_s_ctrl},
+	{ }
+};
+
+static struct i2c_driver imx135_i2c_driver = {
+	.id_table = imx135_i2c_id,
+	.probe  = msm_sensor_i2c_probe,
+	.driver = {
+		.name = IMX135_SENSOR_NAME,
+	},
+};
+
+static struct msm_camera_i2c_client imx135_sensor_i2c_client = {
+	.addr_type = MSM_CAMERA_I2C_WORD_ADDR,
+};
+
+static const struct of_device_id imx135_dt_match[] = {
+	{.compatible = "qcom,imx135", .data = &imx135_s_ctrl},
+	{}
+};
+
+MODULE_DEVICE_TABLE(of, imx135_dt_match);
+
+static struct platform_driver imx135_platform_driver = {
+	.driver = {
+		.name = "qcom,imx135",
+		.owner = THIS_MODULE,
+		.of_match_table = imx135_dt_match,
+	},
+};
+
+static int32_t imx135_platform_probe(struct platform_device *pdev)
+{
+	int32_t rc = 0;
+	const struct of_device_id *match;
+	match = of_match_device(imx135_dt_match, &pdev->dev);
+	rc = msm_sensor_platform_probe(pdev, match->data);
+	return rc;
+}
+
+static int __init imx135_init_module(void)
+{
+	int32_t rc = 0;
+	pr_info("%s:%d\n", __func__, __LINE__);
+	rc = platform_driver_probe(&imx135_platform_driver,
+		imx135_platform_probe);
+	if (!rc)
+		return rc;
+	pr_err("%s:%d rc %d\n", __func__, __LINE__, rc);
+	return i2c_add_driver(&imx135_i2c_driver);
+}
+
+static void __exit imx135_exit_module(void)
+{
+	pr_info("%s:%d\n", __func__, __LINE__);
+	if (imx135_s_ctrl.pdev) {
+		msm_sensor_free_sensor_data(&imx135_s_ctrl);
+		platform_driver_unregister(&imx135_platform_driver);
+	} else
+		i2c_del_driver(&imx135_i2c_driver);
+	return;
+}
+
+static struct msm_sensor_ctrl_t imx135_s_ctrl = {
+	.sensor_i2c_client = &imx135_sensor_i2c_client,
+	.power_setting_array.power_setting = imx135_power_setting,
+	.power_setting_array.size = ARRAY_SIZE(imx135_power_setting),
+	.msm_sensor_mutex = &imx135_mut,
+	.sensor_v4l2_subdev_info = imx135_subdev_info,
+	.sensor_v4l2_subdev_info_size = ARRAY_SIZE(imx135_subdev_info),
+};
+
+module_init(imx135_init_module);
+module_exit(imx135_exit_module);
+MODULE_DESCRIPTION("imx135");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/msm/vidc/hfi_packetization.c b/drivers/media/platform/msm/vidc/hfi_packetization.c
index 8593760..f23c0aa 100644
--- a/drivers/media/platform/msm/vidc/hfi_packetization.c
+++ b/drivers/media/platform/msm/vidc/hfi_packetization.c
@@ -199,9 +199,18 @@
 	case HAL_BUFFER_INTERNAL_SCRATCH:
 		buffer = HFI_BUFFER_INTERNAL_SCRATCH;
 		break;
+	case HAL_BUFFER_INTERNAL_SCRATCH_1:
+		buffer = HFI_BUFFER_INTERNAL_SCRATCH_1;
+		break;
+	case HAL_BUFFER_INTERNAL_SCRATCH_2:
+		buffer = HFI_BUFFER_INTERNAL_SCRATCH_2;
+		break;
 	case HAL_BUFFER_INTERNAL_PERSIST:
 		buffer = HFI_BUFFER_INTERNAL_PERSIST;
 		break;
+	case HAL_BUFFER_INTERNAL_PERSIST_1:
+		buffer = HFI_BUFFER_INTERNAL_PERSIST_1;
+		break;
 	default:
 		dprintk(VIDC_ERR, "Invalid buffer :0x%x\n",
 				hal_buffer);
diff --git a/drivers/media/platform/msm/vidc/hfi_response_handler.c b/drivers/media/platform/msm/vidc/hfi_response_handler.c
index 709eafc..be9458d 100644
--- a/drivers/media/platform/msm/vidc/hfi_response_handler.c
+++ b/drivers/media/platform/msm/vidc/hfi_response_handler.c
@@ -391,12 +391,30 @@
 			buffreq->buffer[6].buffer_type =
 				HAL_BUFFER_INTERNAL_SCRATCH;
 			break;
-		case HFI_BUFFER_INTERNAL_PERSIST:
+		case HFI_BUFFER_INTERNAL_SCRATCH_1:
 			memcpy(&buffreq->buffer[7], hfi_buf_req,
-			sizeof(struct hfi_buffer_requirements));
+				sizeof(struct hfi_buffer_requirements));
 			buffreq->buffer[7].buffer_type =
+				HAL_BUFFER_INTERNAL_SCRATCH_1;
+			break;
+		case HFI_BUFFER_INTERNAL_SCRATCH_2:
+			memcpy(&buffreq->buffer[8], hfi_buf_req,
+				sizeof(struct hfi_buffer_requirements));
+			buffreq->buffer[8].buffer_type =
+				HAL_BUFFER_INTERNAL_SCRATCH_2;
+			break;
+		case HFI_BUFFER_INTERNAL_PERSIST:
+			memcpy(&buffreq->buffer[9], hfi_buf_req,
+			sizeof(struct hfi_buffer_requirements));
+			buffreq->buffer[9].buffer_type =
 				HAL_BUFFER_INTERNAL_PERSIST;
 			break;
+		case HFI_BUFFER_INTERNAL_PERSIST_1:
+			memcpy(&buffreq->buffer[10], hfi_buf_req,
+				sizeof(struct hfi_buffer_requirements));
+			buffreq->buffer[10].buffer_type =
+				HAL_BUFFER_INTERNAL_PERSIST_1;
+			break;
 		default:
 			dprintk(VIDC_ERR,
 			"hal_process_sess_get_prop_buf_req: bad_buffer_type: %d",
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index d43e5ba..8cce310 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -1443,6 +1443,198 @@
 	return flipped_state;
 }
 
+struct hal_buffer_requirements *get_buff_req_buffer(
+		struct msm_vidc_inst *inst, enum hal_buffer buffer_type)
+{
+	int i;
+	for (i = 0; i < HAL_BUFFER_MAX; i++) {
+		if (inst->buff_req.buffer[i].buffer_type == buffer_type)
+			return &inst->buff_req.buffer[i];
+	}
+	return NULL;
+}
+
+static int set_scratch_buffers(struct msm_vidc_inst *inst,
+	enum hal_buffer buffer_type)
+{
+	int rc = 0;
+	struct msm_smem *handle;
+	struct internal_buf *binfo;
+	struct vidc_buffer_addr_info buffer_info;
+	u32 smem_flags = 0;
+	int domain;
+	struct hal_buffer_requirements *scratch_buf;
+	int i;
+	struct hfi_device *hdev;
+
+	hdev = inst->core->device;
+
+	scratch_buf = get_buff_req_buffer(inst, buffer_type);
+	if (!scratch_buf) {
+		dprintk(VIDC_DBG,
+			"This scratch buffer not required, buffer_type: %x\n",
+			buffer_type);
+		return 0;
+	}
+	dprintk(VIDC_DBG,
+		"scratch: num = %d, size = %d\n",
+		scratch_buf->buffer_count_actual,
+		scratch_buf->buffer_size);
+
+	if (inst->mode == VIDC_SECURE) {
+		domain = call_hfi_op(hdev, get_domain,
+				hdev->hfi_device_data, CP_MAP);
+		smem_flags |= SMEM_SECURE;
+	} else
+		domain = call_hfi_op(hdev, get_domain,
+				hdev->hfi_device_data, NS_MAP);
+
+	if (scratch_buf->buffer_size) {
+		for (i = 0; i < scratch_buf->buffer_count_actual;
+				i++) {
+			handle = msm_smem_alloc(inst->mem_client,
+				scratch_buf->buffer_size, 1, smem_flags,
+				domain, 0, 0);
+			if (!handle) {
+				dprintk(VIDC_ERR,
+					"Failed to allocate scratch memory\n");
+				rc = -ENOMEM;
+				goto err_no_mem;
+			}
+			rc = msm_smem_cache_operations(inst->mem_client,
+					handle, SMEM_CACHE_CLEAN);
+			if (rc) {
+				dprintk(VIDC_WARN,
+				"Failed to clean cache may cause undefined behavior\n");
+			}
+			binfo = kzalloc(sizeof(*binfo), GFP_KERNEL);
+			if (!binfo) {
+				dprintk(VIDC_ERR, "Out of memory\n");
+				rc = -ENOMEM;
+				goto fail_kzalloc;
+			}
+			binfo->handle = handle;
+			buffer_info.buffer_size = scratch_buf->buffer_size;
+			buffer_info.buffer_type = buffer_type;
+			binfo->buffer_type = buffer_type;
+			buffer_info.num_buffers = 1;
+			buffer_info.align_device_addr = handle->device_addr;
+			dprintk(VIDC_DBG, "Scratch buffer address: %x",
+					buffer_info.align_device_addr);
+			rc = call_hfi_op(hdev, session_set_buffers,
+				(void *) inst->session, &buffer_info);
+			if (rc) {
+				dprintk(VIDC_ERR,
+					"vidc_hal_session_set_buffers failed");
+				goto fail_set_buffers;
+			}
+			mutex_lock(&inst->lock);
+			list_add_tail(&binfo->list, &inst->internalbufs);
+			mutex_unlock(&inst->lock);
+		}
+	}
+	return rc;
+fail_set_buffers:
+	kfree(binfo);
+fail_kzalloc:
+	msm_smem_free(inst->mem_client, handle);
+err_no_mem:
+	return rc;
+}
+
+static int set_persist_buffers(struct msm_vidc_inst *inst,
+	enum hal_buffer buffer_type)
+{
+	int rc = 0;
+	struct msm_smem *handle;
+	struct internal_buf *binfo;
+	struct vidc_buffer_addr_info buffer_info;
+	u32 smem_flags = 0;
+	int domain;
+	struct hal_buffer_requirements *persist_buf;
+	int i;
+	struct hfi_device *hdev;
+
+	hdev = inst->core->device;
+
+	persist_buf = get_buff_req_buffer(inst, buffer_type);
+	if (!persist_buf) {
+		dprintk(VIDC_DBG,
+			"This persist buffer not required, buffer_type: %x\n",
+			buffer_type);
+		return 0;
+	}
+
+	dprintk(VIDC_DBG,
+		"persist: num = %d, size = %d\n",
+		persist_buf->buffer_count_actual,
+		persist_buf->buffer_size);
+	if (!list_empty(&inst->persistbufs)) {
+		dprintk(VIDC_ERR,
+			"Persist buffers already allocated\n");
+		return rc;
+	}
+
+	if (inst->mode == VIDC_SECURE) {
+		domain = call_hfi_op(hdev, get_domain,
+				hdev->hfi_device_data, CP_MAP);
+		smem_flags |= SMEM_SECURE;
+	} else
+		domain = call_hfi_op(hdev, get_domain,
+				hdev->hfi_device_data, NS_MAP);
+
+	if (persist_buf->buffer_size) {
+		for (i = 0; i < persist_buf->buffer_count_actual; i++) {
+			handle = msm_smem_alloc(inst->mem_client,
+				persist_buf->buffer_size, 1, smem_flags,
+				domain, 0, 0);
+			if (!handle) {
+				dprintk(VIDC_ERR,
+					"Failed to allocate persist memory\n");
+				rc = -ENOMEM;
+				goto err_no_mem;
+			}
+			rc = msm_smem_cache_operations(inst->mem_client,
+					handle, SMEM_CACHE_CLEAN);
+			if (rc) {
+				dprintk(VIDC_WARN,
+				"Failed to clean cache may cause undefined behavior\n");
+			}
+			binfo = kzalloc(sizeof(*binfo), GFP_KERNEL);
+			if (!binfo) {
+				dprintk(VIDC_ERR, "Out of memory\n");
+				rc = -ENOMEM;
+				goto fail_kzalloc;
+			}
+			binfo->handle = handle;
+			buffer_info.buffer_size = persist_buf->buffer_size;
+			buffer_info.buffer_type = buffer_type;
+			binfo->buffer_type = buffer_type;
+			buffer_info.num_buffers = 1;
+			buffer_info.align_device_addr = handle->device_addr;
+			dprintk(VIDC_DBG, "Persist buffer address: %x",
+					buffer_info.align_device_addr);
+			rc = call_hfi_op(hdev, session_set_buffers,
+					(void *) inst->session, &buffer_info);
+			if (rc) {
+				dprintk(VIDC_ERR,
+					"vidc_hal_session_set_buffers failed");
+				goto fail_set_buffers;
+			}
+			mutex_lock(&inst->lock);
+			list_add_tail(&binfo->list, &inst->persistbufs);
+			mutex_unlock(&inst->lock);
+		}
+	}
+	return rc;
+fail_set_buffers:
+	kfree(binfo);
+fail_kzalloc:
+	msm_smem_free(inst->mem_client, handle);
+err_no_mem:
+	return rc;
+}
+
 int msm_comm_try_state(struct msm_vidc_inst *inst, int state)
 {
 	int rc = 0;
@@ -1723,6 +1915,7 @@
 	mutex_unlock(&inst->sync_lock);
 	return rc;
 }
+
 int msm_comm_release_scratch_buffers(struct msm_vidc_inst *inst)
 {
 	struct msm_smem *handle;
@@ -1755,7 +1948,7 @@
 					list);
 			handle = buf->handle;
 			buffer_info.buffer_size = handle->size;
-			buffer_info.buffer_type = HAL_BUFFER_INTERNAL_SCRATCH;
+			buffer_info.buffer_type = buf->buffer_type;
 			buffer_info.num_buffers = 1;
 			buffer_info.align_device_addr = handle->device_addr;
 			if (inst->state != MSM_VIDC_CORE_INVALID &&
@@ -1819,7 +2012,7 @@
 					list);
 			handle = buf->handle;
 			buffer_info.buffer_size = handle->size;
-			buffer_info.buffer_type = HAL_BUFFER_INTERNAL_PERSIST;
+			buffer_info.buffer_type = buf->buffer_type;
 			buffer_info.num_buffers = 1;
 			buffer_info.align_device_addr = handle->device_addr;
 			if (inst->state != MSM_VIDC_CORE_INVALID &&
@@ -1885,178 +2078,50 @@
 int msm_comm_set_scratch_buffers(struct msm_vidc_inst *inst)
 {
 	int rc = 0;
-	struct msm_smem *handle;
-	struct internal_buf *binfo;
-	struct vidc_buffer_addr_info buffer_info;
-	int domain;
-	unsigned long smem_flags = 0;
-	struct hal_buffer_requirements *scratch_buf;
-	int i;
-	struct hfi_device *hdev;
-
 	if (!inst || !inst->core || !inst->core->device) {
 		dprintk(VIDC_ERR, "%s invalid parameters", __func__);
 		return -EINVAL;
 	}
 
-	hdev = inst->core->device;
-
-	scratch_buf =
-		&inst->buff_req.buffer[HAL_BUFFER_INTERNAL_SCRATCH];
-	dprintk(VIDC_DBG,
-		"scratch: num = %d, size = %d\n",
-		scratch_buf->buffer_count_actual,
-		scratch_buf->buffer_size);
 	if (msm_comm_release_scratch_buffers(inst))
 		dprintk(VIDC_WARN, "Failed to release scratch buffers\n");
-	if (inst->mode == VIDC_SECURE) {
-		domain = call_hfi_op(hdev, get_domain,
-				hdev->hfi_device_data, CP_MAP);
-		smem_flags |= SMEM_SECURE;
-	} else
-		domain = call_hfi_op(hdev, get_domain,
-				hdev->hfi_device_data, NS_MAP);
 
-	if (scratch_buf->buffer_size) {
-		for (i = 0; i < scratch_buf->buffer_count_actual;
-				i++) {
-			handle = msm_smem_alloc(inst->mem_client,
-				scratch_buf->buffer_size, 1, smem_flags,
-				domain, 0, 0);
-			if (!handle) {
-				dprintk(VIDC_ERR,
-					"Failed to allocate scratch memory\n");
-				rc = -ENOMEM;
-				goto err_no_mem;
-			}
-			rc = msm_smem_cache_operations(inst->mem_client,
-					handle, SMEM_CACHE_CLEAN);
-			if (rc) {
-				dprintk(VIDC_WARN,
-				"Failed to clean cache may cause undefined behavior\n");
-			}
-			binfo = kzalloc(sizeof(*binfo), GFP_KERNEL);
-			if (!binfo) {
-				dprintk(VIDC_ERR, "Out of memory\n");
-				rc = -ENOMEM;
-				goto fail_kzalloc;
-			}
-			binfo->handle = handle;
-			buffer_info.buffer_size = scratch_buf->buffer_size;
-			buffer_info.buffer_type = HAL_BUFFER_INTERNAL_SCRATCH;
-			buffer_info.num_buffers = 1;
-			buffer_info.align_device_addr = handle->device_addr;
-			dprintk(VIDC_DBG, "Scratch buffer address: %x",
-					buffer_info.align_device_addr);
-			rc = call_hfi_op(hdev, session_set_buffers,
-				(void *) inst->session, &buffer_info);
-			if (rc) {
-				dprintk(VIDC_ERR,
-					"vidc_hal_session_set_buffers failed");
-				goto fail_set_buffers;
-			}
-			mutex_lock(&inst->lock);
-			list_add_tail(&binfo->list, &inst->internalbufs);
-			mutex_unlock(&inst->lock);
-		}
-	}
+	rc = set_scratch_buffers(inst, HAL_BUFFER_INTERNAL_SCRATCH);
+	if (rc)
+		goto error;
+
+	rc = set_scratch_buffers(inst, HAL_BUFFER_INTERNAL_SCRATCH_1);
+	if (rc)
+		goto error;
+
+	rc = set_scratch_buffers(inst, HAL_BUFFER_INTERNAL_SCRATCH_2);
+	if (rc)
+		goto error;
+
 	return rc;
-fail_set_buffers:
-	kfree(binfo);
-fail_kzalloc:
-	msm_smem_free(inst->mem_client, handle);
-err_no_mem:
+error:
+	msm_comm_release_scratch_buffers(inst);
 	return rc;
 }
 
 int msm_comm_set_persist_buffers(struct msm_vidc_inst *inst)
 {
 	int rc = 0;
-	struct msm_smem *handle;
-	struct internal_buf *binfo;
-	struct vidc_buffer_addr_info buffer_info;
-	unsigned long flags;
-	unsigned long smem_flags = 0;
-	int domain;
-	struct hal_buffer_requirements *persist_buf;
-	int i;
-	struct hfi_device *hdev;
-
 	if (!inst || !inst->core || !inst->core->device) {
 		dprintk(VIDC_ERR, "%s invalid parameters", __func__);
 		return -EINVAL;
 	}
 
-	hdev = inst->core->device;
+	rc = set_persist_buffers(inst, HAL_BUFFER_INTERNAL_PERSIST);
+	if (rc)
+		goto error;
 
-	persist_buf =
-		&inst->buff_req.buffer[HAL_BUFFER_INTERNAL_PERSIST];
-	dprintk(VIDC_DBG,
-		"persist: num = %d, size = %d\n",
-		persist_buf->buffer_count_actual,
-		persist_buf->buffer_size);
-	if (!list_empty(&inst->persistbufs)) {
-		dprintk(VIDC_ERR,
-			"Persist buffers already allocated\n");
-		return rc;
-	}
-
-	if (inst->mode == VIDC_SECURE) {
-		domain = call_hfi_op(hdev, get_domain,
-				hdev->hfi_device_data, CP_MAP);
-		flags |= SMEM_SECURE;
-	} else
-		domain = call_hfi_op(hdev, get_domain,
-				hdev->hfi_device_data, NS_MAP);
-
-	if (persist_buf->buffer_size) {
-		for (i = 0;	i <	persist_buf->buffer_count_actual; i++) {
-			handle = msm_smem_alloc(inst->mem_client,
-				persist_buf->buffer_size, 1, smem_flags,
-				domain, 0, 0);
-			if (!handle) {
-				dprintk(VIDC_ERR,
-					"Failed to allocate persist memory\n");
-				rc = -ENOMEM;
-				goto err_no_mem;
-			}
-			rc = msm_smem_cache_operations(inst->mem_client,
-					handle, SMEM_CACHE_CLEAN);
-			if (rc) {
-				dprintk(VIDC_WARN,
-				"Failed to clean cache may cause undefined behavior\n");
-			}
-			binfo = kzalloc(sizeof(*binfo), GFP_KERNEL);
-			if (!binfo) {
-				dprintk(VIDC_ERR, "Out of memory\n");
-				rc = -ENOMEM;
-				goto fail_kzalloc;
-			}
-			binfo->handle = handle;
-			buffer_info.buffer_size = persist_buf->buffer_size;
-			buffer_info.buffer_type = HAL_BUFFER_INTERNAL_PERSIST;
-			buffer_info.num_buffers = 1;
-			buffer_info.align_device_addr = handle->device_addr;
-			dprintk(VIDC_DBG, "Persist buffer address: %x",
-					buffer_info.align_device_addr);
-			rc = call_hfi_op(hdev, session_set_buffers,
-					(void *) inst->session, &buffer_info);
-			if (rc) {
-				dprintk(VIDC_ERR,
-					"vidc_hal_session_set_buffers failed");
-				goto fail_set_buffers;
-			}
-			mutex_lock(&inst->lock);
-			list_add_tail(&binfo->list, &inst->persistbufs);
-			mutex_unlock(&inst->lock);
-		}
-	}
+	rc = set_persist_buffers(inst, HAL_BUFFER_INTERNAL_PERSIST_1);
+	if (rc)
+		goto error;
 	return rc;
-fail_set_buffers:
-	kfree(binfo);
-fail_kzalloc:
-	msm_smem_free(inst->mem_client, handle);
-err_no_mem:
+error:
+	msm_comm_release_persist_buffers(inst);
 	return rc;
 }
 
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_internal.h b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
index c03a4c4..8238d42 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_internal.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
@@ -92,6 +92,7 @@
 
 struct internal_buf {
 	struct list_head list;
+	enum hal_buffer buffer_type;
 	struct msm_smem *handle;
 };
 
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi.h b/drivers/media/platform/msm/vidc/vidc_hfi.h
index 75594b3..8b3e7cb 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi.h
@@ -53,6 +53,8 @@
 #define HFI_BUFFER_EXTRADATA_INPUT (HFI_OX_BASE + 0x2)
 #define HFI_BUFFER_EXTRADATA_OUTPUT (HFI_OX_BASE + 0x3)
 #define HFI_BUFFER_EXTRADATA_OUTPUT2 (HFI_OX_BASE + 0x4)
+#define HFI_BUFFER_INTERNAL_SCRATCH_1 (HFI_OX_BASE + 0x5)
+#define HFI_BUFFER_INTERNAL_SCRATCH_2 (HFI_OX_BASE + 0x6)
 
 #define HFI_BUFFER_MODE_STATIC (HFI_OX_BASE + 0x1)
 #define HFI_BUFFER_MODE_RING (HFI_OX_BASE + 0x2)
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_api.h b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
index d06ea51..a057303 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_api.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
@@ -383,7 +383,10 @@
 	HAL_BUFFER_EXTRADATA_OUTPUT,
 	HAL_BUFFER_EXTRADATA_OUTPUT2,
 	HAL_BUFFER_INTERNAL_SCRATCH,
+	HAL_BUFFER_INTERNAL_SCRATCH_1,
+	HAL_BUFFER_INTERNAL_SCRATCH_2,
 	HAL_BUFFER_INTERNAL_PERSIST,
+	HAL_BUFFER_INTERNAL_PERSIST_1,
 	HAL_BUFFER_MAX
 };
 
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
index 37c051e..01c5e0b 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
@@ -179,6 +179,7 @@
 #define HFI_BUFFER_OUTPUT				(HFI_COMMON_BASE + 0x2)
 #define HFI_BUFFER_OUTPUT2				(HFI_COMMON_BASE + 0x3)
 #define HFI_BUFFER_INTERNAL_PERSIST		(HFI_COMMON_BASE + 0x4)
+#define HFI_BUFFER_INTERNAL_PERSIST_1		(HFI_COMMON_BASE + 0x5)
 
 struct hfi_buffer_info {
 	u32 buffer_addr;
diff --git a/drivers/misc/qseecom_kernel.h b/drivers/misc/qseecom_kernel.h
index 0c93ef2..c6c8fc9 100644
--- a/drivers/misc/qseecom_kernel.h
+++ b/drivers/misc/qseecom_kernel.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -14,6 +14,12 @@
 #define __QSEECOM_KERNEL_H_
 
 #include <linux/types.h>
+
+#define QSEECOM_ALIGN_SIZE	0x40
+#define QSEECOM_ALIGN_MASK	(QSEECOM_ALIGN_SIZE - 1)
+#define QSEECOM_ALIGN(x)	\
+	((x + QSEECOM_ALIGN_SIZE) & (~QSEECOM_ALIGN_MASK))
+
 /*
  * struct qseecom_handle -
  *      Handle to the qseecom device for kernel clients
diff --git a/drivers/platform/msm/ipa/Makefile b/drivers/platform/msm/ipa/Makefile
index a25c799..b7eca61 100644
--- a/drivers/platform/msm/ipa/Makefile
+++ b/drivers/platform/msm/ipa/Makefile
@@ -1,4 +1,4 @@
 obj-$(CONFIG_IPA) += ipat.o
 ipat-y := ipa.o ipa_debugfs.o ipa_hdr.o ipa_flt.o ipa_rt.o ipa_dp.o ipa_client.o \
-	ipa_utils.o ipa_nat.o rmnet_bridge.o a2_service.o ipa_bridge.o ipa_intf.o \
+	ipa_utils.o ipa_nat.o rmnet_bridge.o a2_service.o ipa_bridge.o ipa_intf.o teth_bridge.o \
 	ipa_rm.o ipa_rm_dependency_graph.o ipa_rm_peers_list.o ipa_rm_resource.o ipa_rm_inactivity_timer.o
diff --git a/drivers/platform/msm/ipa/a2_service.c b/drivers/platform/msm/ipa/a2_service.c
index 60cb6bd..4b5f0a2 100644
--- a/drivers/platform/msm/ipa/a2_service.c
+++ b/drivers/platform/msm/ipa/a2_service.c
@@ -1534,6 +1534,13 @@
 	}
 	if (smsm_get_state(SMSM_MODEM_STATE) & SMSM_A2_POWER_CONTROL)
 		bam_dmux_smsm_cb(NULL, 0, smsm_get_state(SMSM_MODEM_STATE));
+
+	/*
+	 * Set remote channel open for tethered channel since there is
+	 *  no actual remote tethered channel
+	 */
+	a2_mux_ctx->bam_ch[A2_MUX_TETHERED_0].status |= BAM_CH_REMOTE_OPEN;
+
 	rc = 0;
 	goto bail;
 
diff --git a/drivers/platform/msm/ipa/ipa.c b/drivers/platform/msm/ipa/ipa.c
index b8e0ce7..edf3a60 100644
--- a/drivers/platform/msm/ipa/ipa.c
+++ b/drivers/platform/msm/ipa/ipa.c
@@ -1900,10 +1900,6 @@
 	ipa_ctx->aggregation_byte_limit = 1;
 	ipa_ctx->aggregation_time_limit = 0;
 
-	/* gate IPA clocks */
-	if (ipa_ctx->ipa_hw_mode == IPA_HW_MODE_NORMAL)
-		ipa_disable_clks();
-
 	/* Initialize IPA RM (resource manager) */
 	result = ipa_rm_initialize();
 	if (result) {
@@ -1914,6 +1910,18 @@
 
 	a2_mux_init();
 
+	/* Initialize the tethering bridge driver */
+	result = teth_bridge_driver_init();
+	if (result) {
+		IPAERR(":teth_bridge_driver_init() failed\n");
+		result = -ENODEV;
+		goto fail_cdev_add;
+	}
+
+	/* gate IPA clocks */
+	if (ipa_ctx->ipa_hw_mode == IPA_HW_MODE_NORMAL)
+		ipa_disable_clks();
+
 	IPADBG(":IPA driver init OK.\n");
 
 	return 0;
diff --git a/drivers/platform/msm/ipa/ipa_i.h b/drivers/platform/msm/ipa/ipa_i.h
index a7d1efc..cb8c0f5 100644
--- a/drivers/platform/msm/ipa/ipa_i.h
+++ b/drivers/platform/msm/ipa/ipa_i.h
@@ -825,5 +825,6 @@
 
 void wwan_cleanup(void);
 
+int teth_bridge_driver_init(void);
 
 #endif /* _IPA_I_H_ */
diff --git a/drivers/platform/msm/ipa/teth_bridge.c b/drivers/platform/msm/ipa/teth_bridge.c
new file mode 100644
index 0000000..76e2eee
--- /dev/null
+++ b/drivers/platform/msm/ipa/teth_bridge.c
@@ -0,0 +1,1483 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/completion.h>
+#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 <mach/bam_dmux.h>
+#include <mach/ipa.h>
+#include <mach/sps.h>
+#include "ipa_i.h"
+
+#define TETH_BRIDGE_DRV_NAME "ipa_tethering_bridge"
+
+#ifdef TETH_DEBUG
+#define TETH_DBG(fmt, args...) \
+	pr_debug(TETH_BRIDGE_DRV_NAME " %s:%d " fmt, \
+		 __func__, __LINE__, ## args)
+#define TETH_DBG_FUNC_ENTRY() \
+	pr_debug(TETH_BRIDGE_DRV_NAME " %s:%d ENTRY\n", __func__, __LINE__)
+#define TETH_DBG_FUNC_EXIT() \
+	pr_debug(TETH_BRIDGE_DRV_NAME " %s:%d EXIT\n", __func__, __LINE__)
+#else
+#define TETH_DBG(fmt, args...)
+#define TETH_DBG_FUNC_ENTRY()
+#define TETH_DBG_FUNC_EXIT()
+#endif
+
+#define TETH_ERR(fmt, args...) \
+	pr_err(TETH_BRIDGE_DRV_NAME " %s:%d " fmt, __func__, __LINE__, ## args)
+
+#define USB_ETH_HDR_NAME_IPV4 "usb_bridge_ipv4"
+#define USB_ETH_HDR_NAME_IPV6 "usb_bridge_ipv6"
+#define A2_ETH_HDR_NAME_IPV4  "a2_bridge_ipv4"
+#define A2_ETH_HDR_NAME_IPV6  "a2_bridge_ipv6"
+
+#define USB_TO_A2_RT_TBL_NAME_IPV4 "usb_a2_rt_tbl_ipv4"
+#define A2_TO_USB_RT_TBL_NAME_IPV4 "a2_usb_rt_tbl_ipv4"
+#define USB_TO_A2_RT_TBL_NAME_IPV6 "usb_a2_rt_tbl_ipv6"
+#define A2_TO_USB_RT_TBL_NAME_IPV6 "a2_usb_rt_tbl_ipv6"
+
+#define MBIM_HEADER_NAME "mbim_header"
+#define TETH_DEFAULT_AGGR_TIME_LIMIT 1
+
+#define ETHERTYPE_IPV4 0x0800
+#define ETHERTYPE_IPV6 0x86DD
+
+struct mac_addresses_type {
+	u8 host_pc_mac_addr[ETH_ALEN];
+	bool host_pc_mac_addr_known;
+	u8 device_mac_addr[ETH_ALEN];
+	bool device_mac_addr_known;
+};
+
+struct teth_bridge_ctx {
+	struct class *class;
+	dev_t dev_num;
+	struct device *dev;
+	struct cdev cdev;
+	u32 usb_ipa_pipe_hdl;
+	u32 ipa_usb_pipe_hdl;
+	u32 a2_ipa_pipe_hdl;
+	u32 ipa_a2_pipe_hdl;
+	bool is_connected;
+	enum teth_link_protocol_type link_protocol;
+	struct mac_addresses_type mac_addresses;
+	bool is_hw_bridge_complete;
+	struct teth_aggr_params aggr_params;
+	bool aggr_params_known;
+	enum teth_tethering_mode tethering_mode;
+	struct completion is_bridge_prod_up;
+	struct completion is_bridge_prod_down;
+	struct work_struct comp_hw_bridge_work;
+	bool comp_hw_bridge_in_progress;
+	struct teth_aggr_capabilities *aggr_caps;
+};
+
+static struct teth_bridge_ctx *teth_ctx;
+
+#ifdef CONFIG_DEBUG_FS
+#define TETH_MAX_MSG_LEN 512
+static char dbg_buff[TETH_MAX_MSG_LEN];
+#endif
+
+static int add_eth_hdrs(char *hdr_name_ipv4, char *hdr_name_ipv6,
+			u8 *src_mac_addr, u8 *dst_mac_addr)
+{
+	int res;
+	struct ipa_ioc_add_hdr *hdrs;
+	struct ethhdr hdr_ipv4;
+	struct ethhdr hdr_ipv6;
+
+	TETH_DBG_FUNC_ENTRY();
+	memcpy(hdr_ipv4.h_source, src_mac_addr, ETH_ALEN);
+	memcpy(hdr_ipv4.h_dest, dst_mac_addr, ETH_ALEN);
+	hdr_ipv4.h_proto = htons(ETHERTYPE_IPV4);
+
+	memcpy(hdr_ipv6.h_source, src_mac_addr, ETH_ALEN);
+	memcpy(hdr_ipv6.h_dest, dst_mac_addr, ETH_ALEN);
+	hdr_ipv6.h_proto = htons(ETHERTYPE_IPV6);
+
+	/* Add headers to the header insertion tables */
+	hdrs = kzalloc(sizeof(struct ipa_ioc_add_hdr) +
+		       2 * sizeof(struct ipa_hdr_add), GFP_KERNEL);
+	if (hdrs == NULL) {
+		TETH_ERR("Failed allocating memory for headers !\n");
+		return -ENOMEM;
+	}
+
+	hdrs->commit = 0;
+	hdrs->num_hdrs = 2;
+
+	/* Ethernet IPv4 header */
+	strlcpy(hdrs->hdr[0].name, hdr_name_ipv4, IPA_RESOURCE_NAME_MAX);
+	hdrs->hdr[0].hdr_len = ETH_HLEN;
+	memcpy(hdrs->hdr[0].hdr, &hdr_ipv4, ETH_HLEN);
+
+	/* Ethernet IPv6 header */
+	strlcpy(hdrs->hdr[1].name, hdr_name_ipv6, IPA_RESOURCE_NAME_MAX);
+	hdrs->hdr[1].hdr_len = ETH_HLEN;
+	memcpy(hdrs->hdr[1].hdr, &hdr_ipv6, ETH_HLEN);
+
+	res = ipa_add_hdr(hdrs);
+	if (res || hdrs->hdr[0].status || hdrs->hdr[1].status)
+		TETH_ERR("Header insertion failed\n");
+	kfree(hdrs);
+	TETH_DBG_FUNC_EXIT();
+
+	return res;
+}
+
+static int configure_ipa_header_block_internal(u32 usb_ipa_hdr_len,
+					       u32 a2_ipa_hdr_len,
+					       u32 ipa_usb_hdr_len,
+					       u32 ipa_a2_hdr_len)
+{
+	struct ipa_ep_cfg_hdr hdr_cfg;
+	int res;
+
+	TETH_DBG_FUNC_ENTRY();
+	/* Configure header removal for the USB->IPA pipe and A2->IPA pipe */
+	memset(&hdr_cfg, 0, sizeof(hdr_cfg));
+	hdr_cfg.hdr_len = usb_ipa_hdr_len;
+	res = ipa_cfg_ep_hdr(teth_ctx->usb_ipa_pipe_hdl, &hdr_cfg);
+	if (res) {
+		TETH_ERR("Header removal config for USB->IPA pipe failed\n");
+		goto bail;
+	}
+
+	hdr_cfg.hdr_len = a2_ipa_hdr_len;
+	res = ipa_cfg_ep_hdr(teth_ctx->a2_ipa_pipe_hdl, &hdr_cfg);
+	if (res) {
+		TETH_ERR("Header removal config for A2->IPA pipe failed\n");
+		goto bail;
+	}
+
+	/* Configure header insertion for the IPA->USB pipe and IPA->A2 pipe */
+	hdr_cfg.hdr_len = ipa_usb_hdr_len;
+	res = ipa_cfg_ep_hdr(teth_ctx->ipa_usb_pipe_hdl, &hdr_cfg);
+	if (res) {
+		TETH_ERR("Header insertion config for IPA->USB pipe failed\n");
+		goto bail;
+	}
+
+	hdr_cfg.hdr_len = ipa_a2_hdr_len;
+	res = ipa_cfg_ep_hdr(teth_ctx->ipa_a2_pipe_hdl, &hdr_cfg);
+	if (res) {
+		TETH_ERR("Header insertion config for IPA->A2 pipe failed\n");
+		goto bail;
+	}
+	TETH_DBG_FUNC_EXIT();
+
+bail:
+	return res;
+}
+
+static int add_mbim_hdr(void)
+{
+	int res;
+	struct ipa_ioc_add_hdr *mbim_hdr;
+	u8 mbim_stream_id = 0;
+
+	TETH_DBG_FUNC_ENTRY();
+	mbim_hdr = kzalloc(sizeof(struct ipa_ioc_add_hdr) +
+			   sizeof(struct ipa_hdr_add),
+			   GFP_KERNEL);
+	if (!mbim_hdr) {
+		TETH_ERR("Failed allocating memory for MBIM header\n");
+		return -ENOMEM;
+	}
+
+	mbim_hdr->commit = 0;
+	mbim_hdr->num_hdrs = 1;
+	strlcpy(mbim_hdr->hdr[0].name, MBIM_HEADER_NAME, IPA_RESOURCE_NAME_MAX);
+	memcpy(mbim_hdr->hdr[0].hdr, &mbim_stream_id, sizeof(u8));
+	mbim_hdr->hdr[0].hdr_len = sizeof(u8);
+	mbim_hdr->hdr[0].is_partial = false;
+	res = ipa_add_hdr(mbim_hdr);
+	if (res || mbim_hdr->hdr[0].status) {
+		TETH_ERR("Failed adding MBIM header\n");
+		res = -EFAULT;
+	} else {
+		TETH_DBG("Added MBIM stream ID header\n");
+	}
+	kfree(mbim_hdr);
+	TETH_DBG_FUNC_EXIT();
+
+	return res;
+}
+
+static int configure_ipa_header_block(void)
+{
+	int res;
+	u32 hdr_len = 0;
+	u32 ipa_usb_hdr_len = 0;
+
+	TETH_DBG_FUNC_ENTRY();
+	if (teth_ctx->link_protocol == TETH_LINK_PROTOCOL_IP) {
+		/*
+		 * Create a new header for MBIM stream ID and associate it with
+		 * the IPA->USB routing table
+		 */
+		if (teth_ctx->aggr_params.dl.aggr_prot ==
+					TETH_AGGR_PROTOCOL_MBIM) {
+			ipa_usb_hdr_len = 1;
+			res = add_mbim_hdr();
+			if (res) {
+				TETH_ERR("Failed adding MBIM header\n");
+				goto bail;
+			}
+		}
+	} else if (teth_ctx->link_protocol == TETH_LINK_PROTOCOL_ETHERNET) {
+		/* Add a header entry for USB */
+		res = add_eth_hdrs(USB_ETH_HDR_NAME_IPV4,
+				   USB_ETH_HDR_NAME_IPV6,
+				   teth_ctx->mac_addresses.host_pc_mac_addr,
+				   teth_ctx->mac_addresses.device_mac_addr);
+		if (res) {
+			TETH_ERR("Failed adding USB Ethernet header\n");
+			goto bail;
+		}
+		TETH_DBG("Added USB Ethernet headers (IPv4 / IPv6)\n");
+
+		/* Add a header entry for A2 */
+		res = add_eth_hdrs(A2_ETH_HDR_NAME_IPV4,
+				   A2_ETH_HDR_NAME_IPV6,
+				   teth_ctx->mac_addresses.device_mac_addr,
+				   teth_ctx->mac_addresses.host_pc_mac_addr);
+		if (res) {
+			TETH_ERR("Failed adding A2 Ethernet header\n");
+			goto bail;
+		}
+		TETH_DBG("Added A2 Ethernet headers (IPv4 / IPv6\n");
+
+		hdr_len = ETH_HLEN;
+		ipa_usb_hdr_len = ETH_HLEN;
+	}
+
+	res = configure_ipa_header_block_internal(hdr_len,
+						  hdr_len,
+						  ipa_usb_hdr_len,
+						  hdr_len);
+	if (res) {
+		TETH_ERR("Configuration of header removal/insertion failed\n");
+		goto bail;
+	}
+
+	res = ipa_commit_hdr();
+	if (res) {
+		TETH_ERR("Failed committing headers\n");
+		goto bail;
+	}
+	TETH_DBG_FUNC_EXIT();
+
+bail:
+	return res;
+}
+
+static int configure_routing_by_ip(char *hdr_name,
+			    char *rt_tbl_name,
+			    enum ipa_client_type dst,
+			    enum ipa_ip_type ip_address_family)
+{
+
+	struct ipa_ioc_add_rt_rule *rt_rule;
+	struct ipa_ioc_get_hdr hdr_info;
+	int res;
+
+	TETH_DBG_FUNC_ENTRY();
+	/* Get the header handle */
+	memset(&hdr_info, 0, sizeof(hdr_info));
+	strlcpy(hdr_info.name, hdr_name, IPA_RESOURCE_NAME_MAX);
+	ipa_get_hdr(&hdr_info);
+
+	rt_rule = kzalloc(sizeof(struct ipa_ioc_add_rt_rule) +
+			  1 * sizeof(struct ipa_rt_rule_add),
+			  GFP_KERNEL);
+	if (!rt_rule) {
+		TETH_ERR("Memory allocation failure");
+		return -ENOMEM;
+	}
+
+	/* Match all, do not commit to HW*/
+	rt_rule->commit = 0;
+	rt_rule->num_rules = 1;
+	rt_rule->ip = ip_address_family;
+	strlcpy(rt_rule->rt_tbl_name, rt_tbl_name, IPA_RESOURCE_NAME_MAX);
+	rt_rule->rules[0].rule.dst = dst;
+	rt_rule->rules[0].rule.hdr_hdl = hdr_info.hdl;
+	rt_rule->rules[0].rule.attrib.attrib_mask = 0; /* Match all */
+	res = ipa_add_rt_rule(rt_rule);
+	if (res || rt_rule->rules[0].status)
+		TETH_ERR("Failed adding routing rule\n");
+	kfree(rt_rule);
+	TETH_DBG_FUNC_EXIT();
+
+	return res;
+}
+
+static int configure_routing(char *hdr_name_ipv4,
+			     char *rt_tbl_name_ipv4,
+			     char *hdr_name_ipv6,
+			     char *rt_tbl_name_ipv6,
+			     enum ipa_client_type dst)
+{
+	int res;
+
+	TETH_DBG_FUNC_ENTRY();
+	/* Configure IPv4 routing table */
+	res = configure_routing_by_ip(hdr_name_ipv4,
+				      rt_tbl_name_ipv4,
+				      dst,
+				      IPA_IP_v4);
+	if (res) {
+		TETH_ERR("Failed adding IPv4 routing table\n");
+		goto bail;
+	}
+
+	/* Configure IPv6 routing table */
+	res = configure_routing_by_ip(hdr_name_ipv6,
+				      rt_tbl_name_ipv6,
+				      dst,
+				      IPA_IP_v6);
+	if (res) {
+		TETH_ERR("Failed adding IPv6 routing table\n");
+		goto bail;
+	}
+	TETH_DBG_FUNC_EXIT();
+
+bail:
+	return res;
+}
+
+static int configure_ipa_routing_block(void)
+{
+	int res;
+	char hdr_name_ipv4[IPA_RESOURCE_NAME_MAX];
+	char hdr_name_ipv6[IPA_RESOURCE_NAME_MAX];
+
+	TETH_DBG_FUNC_ENTRY();
+	hdr_name_ipv4[0] = '\0';
+	hdr_name_ipv6[0] = '\0';
+
+	/* Configure USB -> A2 routing table */
+	if (teth_ctx->link_protocol == TETH_LINK_PROTOCOL_ETHERNET) {
+		strlcpy(hdr_name_ipv4,
+			A2_ETH_HDR_NAME_IPV4,
+			IPA_RESOURCE_NAME_MAX);
+		strlcpy(hdr_name_ipv6,
+			A2_ETH_HDR_NAME_IPV6,
+			IPA_RESOURCE_NAME_MAX);
+	}
+	res = configure_routing(hdr_name_ipv4,
+				USB_TO_A2_RT_TBL_NAME_IPV4,
+				hdr_name_ipv6,
+				USB_TO_A2_RT_TBL_NAME_IPV6,
+				IPA_CLIENT_A2_TETHERED_CONS);
+	if (res) {
+		TETH_ERR("USB to A2 routing block configuration failed\n");
+		goto bail;
+	}
+
+	/* Configure A2 -> USB routing table */
+	if (teth_ctx->link_protocol == TETH_LINK_PROTOCOL_ETHERNET) {
+		strlcpy(hdr_name_ipv4,
+			USB_ETH_HDR_NAME_IPV4,
+			IPA_RESOURCE_NAME_MAX);
+		strlcpy(hdr_name_ipv6,
+			USB_ETH_HDR_NAME_IPV6,
+			IPA_RESOURCE_NAME_MAX);
+	} else if (teth_ctx->aggr_params.dl.aggr_prot ==
+						TETH_AGGR_PROTOCOL_MBIM) {
+		strlcpy(hdr_name_ipv4,
+			MBIM_HEADER_NAME,
+			IPA_RESOURCE_NAME_MAX);
+		strlcpy(hdr_name_ipv6,
+			MBIM_HEADER_NAME,
+			IPA_RESOURCE_NAME_MAX);
+	}
+	res = configure_routing(hdr_name_ipv4,
+				A2_TO_USB_RT_TBL_NAME_IPV4,
+				hdr_name_ipv6,
+				A2_TO_USB_RT_TBL_NAME_IPV6,
+				IPA_CLIENT_USB_CONS);
+	if (res) {
+		TETH_ERR("A2 to USB routing block configuration failed\n");
+		goto bail;
+	}
+
+	/* Commit all the changes to HW in one shot */
+	res = ipa_commit_rt(IPA_IP_v4);
+	if (res) {
+		TETH_ERR("Failed commiting IPv4 routing tables\n");
+		goto bail;
+	}
+	res = ipa_commit_rt(IPA_IP_v6);
+	if (res) {
+		TETH_ERR("Failed commiting IPv6 routing tables\n");
+		goto bail;
+	}
+	TETH_DBG_FUNC_EXIT();
+
+bail:
+	return res;
+}
+
+static int configure_filtering_by_ip(char *rt_tbl_name,
+			      enum ipa_client_type src,
+			      enum ipa_ip_type ip_address_family)
+{
+	struct ipa_ioc_add_flt_rule *flt_tbl;
+	struct ipa_ioc_get_rt_tbl rt_tbl_info;
+	int res;
+
+	TETH_DBG_FUNC_ENTRY();
+	/* Get the needed routing table handle */
+	rt_tbl_info.ip = ip_address_family;
+	strlcpy(rt_tbl_info.name, rt_tbl_name, IPA_RESOURCE_NAME_MAX);
+	res = ipa_get_rt_tbl(&rt_tbl_info);
+	if (res) {
+		TETH_ERR("Failed getting routing table handle\n");
+		goto bail;
+	}
+
+	flt_tbl = kzalloc(sizeof(struct ipa_ioc_add_flt_rule) +
+			  1 * sizeof(struct ipa_flt_rule_add), GFP_KERNEL);
+	if (!flt_tbl) {
+		TETH_ERR("Filtering table memory allocation failure\n");
+		return -ENOMEM;
+	}
+
+	flt_tbl->commit = 0;
+	flt_tbl->ep = src;
+	flt_tbl->global = 0;
+	flt_tbl->ip = ip_address_family;
+	flt_tbl->num_rules = 1;
+	flt_tbl->rules[0].rule.action = IPA_PASS_TO_ROUTING;
+	flt_tbl->rules[0].rule.rt_tbl_hdl = rt_tbl_info.hdl;
+	flt_tbl->rules[0].rule.attrib.attrib_mask = 0; /* Match all */
+
+	res = ipa_add_flt_rule(flt_tbl);
+	if (res || flt_tbl->rules[0].status)
+		TETH_ERR("Failed adding filtering table\n");
+	kfree(flt_tbl);
+	TETH_DBG_FUNC_EXIT();
+
+bail:
+	return res;
+}
+
+static int configure_filtering(char *rt_tbl_name_ipv4,
+			char *rt_tbl_name_ipv6,
+			enum ipa_client_type src)
+{
+	int res;
+
+	TETH_DBG_FUNC_ENTRY();
+	res = configure_filtering_by_ip(rt_tbl_name_ipv4, src, IPA_IP_v4);
+	if (res) {
+		TETH_ERR("Failed adding IPv4 filtering table\n");
+		goto bail;
+	}
+
+	res = configure_filtering_by_ip(rt_tbl_name_ipv6, src, IPA_IP_v6);
+	if (res) {
+		TETH_ERR("Failed adding IPv4 filtering table\n");
+		goto bail;
+	}
+	TETH_DBG_FUNC_EXIT();
+
+bail:
+	return res;
+}
+
+static int configure_ipa_filtering_block(void)
+{
+	int res;
+
+	TETH_DBG_FUNC_ENTRY();
+	/* Filter all traffic coming from USB to A2 */
+	res = configure_filtering(USB_TO_A2_RT_TBL_NAME_IPV4,
+				  USB_TO_A2_RT_TBL_NAME_IPV6,
+				  IPA_CLIENT_USB_PROD);
+	if (res) {
+		TETH_ERR("USB_PROD ep filtering configuration failed\n");
+		goto bail;
+	}
+
+	/* Filter all traffic coming from A2 to USB */
+	res = configure_filtering(A2_TO_USB_RT_TBL_NAME_IPV4,
+				  A2_TO_USB_RT_TBL_NAME_IPV6,
+				  IPA_CLIENT_A2_TETHERED_PROD);
+	if (res) {
+		TETH_ERR("A2_PROD filtering configuration failed\n");
+		goto bail;
+	}
+
+	/* Commit all the changes to HW in one shot */
+	res = ipa_commit_flt(IPA_IP_v4);
+	if (res) {
+		TETH_ERR("Failed commiting IPv4 filtering tables\n");
+		goto bail;
+	}
+	res = ipa_commit_flt(IPA_IP_v6);
+	if (res) {
+		TETH_ERR("Failed commiting IPv6 filtering tables\n");
+		goto bail;
+	}
+	TETH_DBG_FUNC_EXIT();
+
+bail:
+	return res;
+}
+
+static int prepare_ipa_aggr_struct(
+	const struct teth_aggr_params_link *teth_aggr_params,
+	struct ipa_ep_cfg_aggr *ipa_aggr_params,
+	bool client_is_prod)
+{
+	TETH_DBG_FUNC_ENTRY();
+	memset(ipa_aggr_params, 0, sizeof(*ipa_aggr_params));
+
+	switch (teth_aggr_params->aggr_prot) {
+	case TETH_AGGR_PROTOCOL_NONE:
+		ipa_aggr_params->aggr_en = IPA_BYPASS_AGGR;
+		break;
+	case TETH_AGGR_PROTOCOL_MBIM:
+		 ipa_aggr_params->aggr = IPA_MBIM_16;
+		 ipa_aggr_params->aggr_en = (client_is_prod) ?
+			 IPA_ENABLE_DEAGGR : IPA_ENABLE_AGGR;
+		 break;
+	case TETH_AGGR_PROTOCOL_TLP:
+		ipa_aggr_params->aggr = IPA_TLP;
+		ipa_aggr_params->aggr_en = (client_is_prod) ?
+			IPA_ENABLE_DEAGGR : IPA_ENABLE_AGGR;
+		break;
+	default:
+		TETH_ERR("Unsupported aggregation protocol\n");
+		return -EFAULT;
+	}
+
+	ipa_aggr_params->aggr_byte_limit =
+		teth_aggr_params->max_transfer_size_byte / 1024;
+	ipa_aggr_params->aggr_time_limit = TETH_DEFAULT_AGGR_TIME_LIMIT;
+	TETH_DBG_FUNC_EXIT();
+
+	return 0;
+}
+
+static int teth_set_aggr_per_ep(
+	const struct teth_aggr_params_link *teth_aggr_params,
+	bool client_is_prod,
+	u32 pipe_hdl)
+{
+	struct ipa_ep_cfg_aggr agg_params;
+	struct ipa_ep_cfg_hdr hdr_params;
+	int res;
+
+	TETH_DBG_FUNC_ENTRY();
+	res = prepare_ipa_aggr_struct(teth_aggr_params,
+				      &agg_params,
+				      client_is_prod);
+	if (res) {
+		TETH_ERR("prepare_ipa_aggregation_struct() failed\n");
+		goto bail;
+	}
+
+	res = ipa_cfg_ep_aggr(pipe_hdl, &agg_params);
+	if (res) {
+		TETH_ERR("ipa_cfg_ep_aggr() failed\n");
+		goto bail;
+	}
+
+	if (!client_is_prod) {
+		memset(&hdr_params, 0, sizeof(hdr_params));
+		hdr_params.hdr_len = 1;
+		res = ipa_cfg_ep_hdr(pipe_hdl, &hdr_params);
+		if (res) {
+			TETH_ERR("ipa_cfg_ep_hdr() failed\n");
+			goto bail;
+		}
+	}
+	TETH_DBG_FUNC_EXIT();
+
+bail:
+	return res;
+}
+
+static void aggr_prot_to_str(enum teth_aggr_protocol_type aggr_prot,
+			     char *buff,
+			     uint buff_size)
+{
+	switch (aggr_prot) {
+	case TETH_AGGR_PROTOCOL_NONE:
+		strlcpy(buff, "NONE", buff_size);
+		break;
+	case TETH_AGGR_PROTOCOL_MBIM:
+		strlcpy(buff, "MBIM", buff_size);
+		break;
+	case TETH_AGGR_PROTOCOL_TLP:
+		strlcpy(buff, "TLP", buff_size);
+		break;
+	default:
+		strlcpy(buff, "ERROR", buff_size);
+		break;
+	}
+}
+
+static int teth_set_aggregation(void)
+{
+	int res;
+	char aggr_prot_str[20];
+
+	TETH_DBG_FUNC_ENTRY();
+	if (teth_ctx->aggr_params.ul.aggr_prot == TETH_AGGR_PROTOCOL_MBIM ||
+	    teth_ctx->aggr_params.dl.aggr_prot == TETH_AGGR_PROTOCOL_MBIM) {
+		res = ipa_set_aggr_mode(IPA_MBIM);
+		if (res) {
+			TETH_ERR("ipa_set_aggr_mode() failed\n");
+			goto bail;
+		}
+		res = ipa_set_single_ndp_per_mbim(false);
+		if (res) {
+			TETH_ERR("ipa_set_single_ndp_per_mbim() failed\n");
+			goto bail;
+		}
+	}
+
+	aggr_prot_to_str(teth_ctx->aggr_params.ul.aggr_prot,
+			 aggr_prot_str,
+			 sizeof(aggr_prot_str)-1);
+	TETH_DBG("Setting %s aggregation on UL\n", aggr_prot_str);
+	aggr_prot_to_str(teth_ctx->aggr_params.dl.aggr_prot,
+			 aggr_prot_str,
+			 sizeof(aggr_prot_str)-1);
+	TETH_DBG("Setting %s aggregation on DL\n", aggr_prot_str);
+
+	/* Configure aggregation on UL producer (USB->IPA) */
+	res = teth_set_aggr_per_ep(&teth_ctx->aggr_params.ul,
+				   true,
+				   teth_ctx->usb_ipa_pipe_hdl);
+	if (res) {
+		TETH_ERR("teth_set_aggregation_per_ep() failed\n");
+		goto bail;
+	}
+
+	/* Configure aggregation on DL consumer (IPA->USB) */
+	res = teth_set_aggr_per_ep(&teth_ctx->aggr_params.dl,
+				   false,
+				   teth_ctx->ipa_usb_pipe_hdl);
+	if (res) {
+		TETH_ERR("teth_set_aggregation_per_ep() failed\n");
+		goto bail;
+	}
+	TETH_DBG_FUNC_EXIT();
+bail:
+	return res;
+}
+
+static void complete_hw_bridge(struct work_struct *work)
+{
+	int res;
+	static DEFINE_MUTEX(f_lock);
+
+	mutex_lock(&f_lock);
+
+	TETH_DBG_FUNC_ENTRY();
+	TETH_DBG("Completing HW bridge in %s mode\n",
+		 (teth_ctx->link_protocol == TETH_LINK_PROTOCOL_ETHERNET) ?
+		 "ETHERNET" :
+		 "IP");
+
+	res = teth_set_aggregation();
+	if (res) {
+		TETH_ERR("Failed setting aggregation params\n");
+		goto bail;
+	}
+
+	/*
+	 * Reset the Header, Routing and Filtering blocks.
+	 * Resetting the Header block will also reset the other blocks.
+	 * This reset is not comitted to HW.
+	 */
+	res = ipa_reset_hdr();
+	if (res) {
+		TETH_ERR("Failed resetting IPA\n");
+		goto bail;
+	}
+
+	res = configure_ipa_header_block();
+	if (res) {
+		TETH_ERR("Configuration of IPA header block Failed\n");
+		goto bail;
+	}
+
+	res = configure_ipa_routing_block();
+	if (res) {
+		TETH_ERR("Configuration of IPA routing block Failed\n");
+		goto bail;
+	}
+
+	res = configure_ipa_filtering_block();
+	if (res) {
+		TETH_ERR("Configuration of IPA filtering block Failed\n");
+		goto bail;
+	}
+
+	teth_ctx->is_hw_bridge_complete = true;
+	teth_ctx->comp_hw_bridge_in_progress = false;
+bail:
+	mutex_unlock(&f_lock);
+	TETH_DBG_FUNC_EXIT();
+
+	return;
+}
+
+static void mac_addr_to_str(u8 mac_addr[ETH_ALEN],
+		     char *buff,
+		     uint buff_size)
+{
+	scnprintf(buff, buff_size, "%02x-%02x-%02x-%02x-%02x-%02x",
+		  mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3],
+		  mac_addr[4], mac_addr[5]);
+}
+
+static void check_to_complete_hw_bridge(struct sk_buff *skb,
+					u8 *my_mac_addr,
+					bool *my_mac_addr_known,
+					bool *peer_mac_addr_known)
+{
+	bool both_mac_addresses_known;
+	char mac_addr_str[20];
+
+	if ((teth_ctx->link_protocol == TETH_LINK_PROTOCOL_ETHERNET) &&
+	    (!(*my_mac_addr_known))) {
+		memcpy(my_mac_addr, &skb->data[ETH_ALEN], ETH_ALEN);
+		mac_addr_to_str(my_mac_addr,
+				mac_addr_str,
+				sizeof(mac_addr_str)-1);
+		TETH_DBG("Extracted MAC addr: %s\n", mac_addr_str);
+		*my_mac_addr_known = true;
+	}
+
+	both_mac_addresses_known = *my_mac_addr_known && *peer_mac_addr_known;
+	if ((both_mac_addresses_known ||
+	    (teth_ctx->link_protocol == TETH_LINK_PROTOCOL_IP)) &&
+	    (!teth_ctx->comp_hw_bridge_in_progress) &&
+	    (teth_ctx->aggr_params_known)) {
+		INIT_WORK(&teth_ctx->comp_hw_bridge_work, complete_hw_bridge);
+		teth_ctx->comp_hw_bridge_in_progress = true;
+		schedule_work(&teth_ctx->comp_hw_bridge_work);
+	}
+}
+
+static void usb_notify_cb(void *priv,
+			  enum ipa_dp_evt_type evt,
+			  unsigned long data)
+{
+	struct sk_buff *skb = (struct sk_buff *)data;
+	int res;
+
+	switch (evt) {
+	case IPA_RECEIVE:
+		if (!teth_ctx->is_hw_bridge_complete)
+			check_to_complete_hw_bridge(
+				skb,
+				teth_ctx->mac_addresses.host_pc_mac_addr,
+				&teth_ctx->mac_addresses.host_pc_mac_addr_known,
+				&teth_ctx->mac_addresses.device_mac_addr_known);
+
+		/* Send the packet to A2, using a2_service driver API */
+		res = a2_mux_write(A2_MUX_TETHERED_0, skb);
+		if (res) {
+			TETH_ERR("Packet send failure, dropping packet !\n");
+			dev_kfree_skb(skb);
+		}
+		break;
+
+	case IPA_WRITE_DONE:
+		dev_kfree_skb(skb);
+		break;
+
+	default:
+		TETH_ERR("Unsupported IPA event !\n");
+		WARN_ON(1);
+	}
+
+	return;
+}
+
+static void a2_notify_cb(void *user_data,
+			 enum a2_mux_event_type event,
+			 unsigned long data)
+{
+	struct sk_buff *skb = (struct sk_buff *)data;
+	int res;
+
+	switch (event) {
+	case A2_MUX_RECEIVE:
+		if (!teth_ctx->is_hw_bridge_complete)
+			check_to_complete_hw_bridge(
+				skb,
+				teth_ctx->mac_addresses.device_mac_addr,
+				&teth_ctx->mac_addresses.device_mac_addr_known,
+				&teth_ctx->
+				mac_addresses.host_pc_mac_addr_known);
+
+		/* Send the packet to USB */
+		res = ipa_tx_dp(IPA_CLIENT_USB_CONS, skb, NULL);
+		if (res) {
+			TETH_ERR("Packet send failure, dropping packet !\n");
+			dev_kfree_skb(skb);
+		}
+		break;
+
+	case A2_MUX_WRITE_DONE:
+		dev_kfree_skb(skb);
+		break;
+
+	default:
+		TETH_ERR("Unsupported IPA event !\n");
+		WARN_ON(1);
+	}
+
+	return;
+}
+
+static void bridge_prod_notify_cb(void *notify_cb_data,
+				  enum ipa_rm_event event,
+				  unsigned long data)
+{
+	switch (event) {
+	case IPA_RM_RESOURCE_GRANTED:
+		complete(&teth_ctx->is_bridge_prod_up);
+		break;
+
+	case IPA_RM_RESOURCE_RELEASED:
+		complete(&teth_ctx->is_bridge_prod_down);
+		break;
+
+	default:
+		TETH_ERR("Unsupported notification!\n");
+		WARN_ON(1);
+		break;
+	}
+
+	return;
+}
+
+/**
+* teth_bridge_init() - Initialize the Tethering bridge driver
+* @usb_notify_cb_ptr:	Callback function which should be used
+*			by the caller. Output parameter.
+* @private_data_ptr:	Data for the callback function. Should
+*			be used by the caller. Output parameter.
+* Return codes: 0: success,
+*		-EINVAL - Bad parameter
+*		Other negative value - Failure
+*/
+int teth_bridge_init(ipa_notify_cb *usb_notify_cb_ptr, void **private_data_ptr)
+{
+	int res = 0;
+	struct ipa_rm_create_params bridge_prod_params;
+
+	TETH_DBG_FUNC_ENTRY();
+	if (usb_notify_cb_ptr == NULL) {
+		TETH_ERR("Bad parameter\n");
+		res = -EINVAL;
+		goto bail;
+	}
+
+	*usb_notify_cb_ptr = usb_notify_cb;
+	*private_data_ptr = NULL;
+
+	/* Build IPA Resource manager dependency graph */
+	bridge_prod_params.name = IPA_RM_RESOURCE_BRIDGE_PROD;
+	bridge_prod_params.reg_params.user_data = NULL;
+	bridge_prod_params.reg_params.notify_cb = bridge_prod_notify_cb;
+	res = ipa_rm_create_resource(&bridge_prod_params);
+	if (res) {
+		TETH_ERR("ipa_rm_create_resource() failed\n");
+		goto bail;
+	}
+
+	res = ipa_rm_add_dependency(IPA_RM_RESOURCE_BRIDGE_PROD,
+				    IPA_RM_RESOURCE_USB_CONS);
+	if (res) {
+		TETH_ERR("ipa_rm_add_dependency() failed\n");
+		goto bail;
+	}
+
+	res = ipa_rm_add_dependency(IPA_RM_RESOURCE_BRIDGE_PROD,
+				    IPA_RM_RESOURCE_A2_CONS);
+	if (res) {
+		TETH_ERR("ipa_rm_add_dependency() failed\n");
+		goto fail_add_dependency_1;
+	}
+
+	res = ipa_rm_add_dependency(IPA_RM_RESOURCE_USB_PROD,
+				    IPA_RM_RESOURCE_A2_CONS);
+	if (res) {
+		TETH_ERR("ipa_rm_add_dependency() failed\n");
+		goto fail_add_dependency_2;
+	}
+
+	res = ipa_rm_add_dependency(IPA_RM_RESOURCE_A2_PROD,
+				    IPA_RM_RESOURCE_USB_CONS);
+	if (res) {
+		TETH_ERR("ipa_rm_add_dependency() failed\n");
+		goto fail_add_dependency_3;
+	}
+
+	init_completion(&teth_ctx->is_bridge_prod_up);
+	init_completion(&teth_ctx->is_bridge_prod_down);
+
+	/* The default link protocol is Ethernet */
+	teth_ctx->link_protocol = TETH_LINK_PROTOCOL_ETHERNET;
+	goto bail;
+
+fail_add_dependency_3:
+	ipa_rm_delete_dependency(IPA_RM_RESOURCE_USB_PROD,
+				 IPA_RM_RESOURCE_A2_CONS);
+fail_add_dependency_2:
+	ipa_rm_delete_dependency(IPA_RM_RESOURCE_BRIDGE_PROD,
+				 IPA_RM_RESOURCE_A2_CONS);
+fail_add_dependency_1:
+	ipa_rm_delete_dependency(IPA_RM_RESOURCE_BRIDGE_PROD,
+				 IPA_RM_RESOURCE_USB_CONS);
+bail:
+	TETH_DBG_FUNC_EXIT();
+	return res;
+}
+EXPORT_SYMBOL(teth_bridge_init);
+
+/**
+* teth_bridge_disconnect() - Disconnect tethering bridge module
+*
+* Return codes:	0: success
+*		-EPERM: Operation not permitted as the bridge is already
+*		disconnected
+*/
+int teth_bridge_disconnect(void)
+{
+	int res = -EPERM;
+
+	TETH_DBG_FUNC_ENTRY();
+	if (!teth_ctx->is_connected) {
+		TETH_ERR(
+		"Trying to disconnect an already disconnected bridge\n");
+		goto bail;
+	}
+
+	teth_ctx->is_connected = false;
+
+	res = ipa_rm_release_resource(IPA_RM_RESOURCE_BRIDGE_PROD);
+	if (res == -EINPROGRESS)
+		wait_for_completion(&teth_ctx->is_bridge_prod_down);
+
+bail:
+	TETH_DBG_FUNC_EXIT();
+	return res;
+}
+EXPORT_SYMBOL(teth_bridge_disconnect);
+
+/**
+* teth_bridge_connect() - Connect bridge for a tethered Rmnet / MBIM call
+* @connect_params:	Connection info
+*
+* Return codes: 0: success
+*		-EINVAL: invalid parameters
+*		-EPERM: Operation not permitted as the bridge is already
+*		connected
+*/
+int teth_bridge_connect(struct teth_bridge_connect_params *connect_params)
+{
+	int res;
+	struct ipa_ep_cfg ipa_ep_cfg;
+
+	TETH_DBG_FUNC_ENTRY();
+	if (teth_ctx->is_connected) {
+		TETH_ERR("Trying to connect an already connected bridge !\n");
+		return -EPERM;
+	}
+	if (connect_params == NULL ||
+	    connect_params->ipa_usb_pipe_hdl <= 0 ||
+	    connect_params->usb_ipa_pipe_hdl <= 0 ||
+	    connect_params->tethering_mode >= TETH_TETHERING_MODE_MAX ||
+	    connect_params->tethering_mode < 0)
+		return -EINVAL;
+
+	teth_ctx->ipa_usb_pipe_hdl = connect_params->ipa_usb_pipe_hdl;
+	teth_ctx->usb_ipa_pipe_hdl = connect_params->usb_ipa_pipe_hdl;
+	teth_ctx->tethering_mode = connect_params->tethering_mode;
+
+	res = ipa_rm_request_resource(IPA_RM_RESOURCE_BRIDGE_PROD);
+	if (res < 0) {
+		if (res == -EINPROGRESS)
+			wait_for_completion(&teth_ctx->is_bridge_prod_up);
+		else
+			goto bail;
+	}
+
+	res = a2_mux_open_channel(A2_MUX_TETHERED_0,
+				  NULL,
+				  a2_notify_cb);
+	if (res) {
+		TETH_ERR("a2_mux_open_channel() failed\n");
+		goto bail;
+	}
+
+	res = a2_mux_get_tethered_client_handles(A2_MUX_TETHERED_0,
+						 &teth_ctx->ipa_a2_pipe_hdl,
+						 &teth_ctx->a2_ipa_pipe_hdl);
+	if (res) {
+		TETH_ERR(
+		"a2_mux_get_tethered_client_handles() failed, res = %d\n", res);
+		goto bail;
+	}
+
+	/* Reset the various endpoints configuration */
+	memset(&ipa_ep_cfg, 0, sizeof(ipa_ep_cfg));
+	ipa_cfg_ep(teth_ctx->ipa_usb_pipe_hdl, &ipa_ep_cfg);
+	ipa_cfg_ep(teth_ctx->usb_ipa_pipe_hdl, &ipa_ep_cfg);
+	ipa_cfg_ep(teth_ctx->ipa_a2_pipe_hdl, &ipa_ep_cfg);
+	ipa_cfg_ep(teth_ctx->a2_ipa_pipe_hdl, &ipa_ep_cfg);
+
+	teth_ctx->is_connected = true;
+
+	if (teth_ctx->tethering_mode == TETH_TETHERING_MODE_MBIM)
+		teth_ctx->link_protocol = TETH_LINK_PROTOCOL_IP;
+	TETH_DBG_FUNC_EXIT();
+bail:
+	if (res)
+		ipa_rm_release_resource(IPA_RM_RESOURCE_BRIDGE_PROD);
+	return res;
+}
+EXPORT_SYMBOL(teth_bridge_connect);
+
+static void set_aggr_default_params(struct teth_aggr_params_link *params)
+{
+	if (params->max_datagrams == 0)
+		params->max_datagrams = 16;
+	if (params->max_transfer_size_byte == 0)
+		params->max_transfer_size_byte = 16*1024;
+}
+
+static void teth_set_bridge_mode(enum teth_link_protocol_type link_protocol)
+{
+	teth_ctx->link_protocol = link_protocol;
+	teth_ctx->is_hw_bridge_complete = false;
+	memset(&teth_ctx->mac_addresses, 0, sizeof(teth_ctx->mac_addresses));
+}
+
+static long teth_bridge_ioctl(struct file *filp,
+			      unsigned int cmd,
+			      unsigned long arg)
+{
+	int res = 0;
+
+	TETH_DBG("cmd=%x nr=%d\n", cmd, _IOC_NR(cmd));
+
+	if ((_IOC_TYPE(cmd) != TETH_BRIDGE_IOC_MAGIC) ||
+	    (_IOC_NR(cmd) >= TETH_BRIDGE_IOCTL_MAX)) {
+		TETH_ERR("Invalid ioctl\n");
+		return -ENOIOCTLCMD;
+	}
+
+	switch (cmd) {
+	case TETH_BRIDGE_IOC_SET_BRIDGE_MODE:
+		TETH_DBG("TETH_BRIDGE_IOC_SET_BRIDGE_MODE ioctl called\n");
+		if (teth_ctx->link_protocol != arg)
+			teth_set_bridge_mode(arg);
+		break;
+
+	case TETH_BRIDGE_IOC_SET_AGGR_PARAMS:
+		TETH_DBG("TETH_BRIDGE_IOC_SET_AGGR_PARAMS ioctl called\n");
+		res = copy_from_user(&teth_ctx->aggr_params,
+				   (struct teth_aggr_params *)arg,
+				   sizeof(struct teth_aggr_params));
+		if (res) {
+			TETH_ERR("Error, res = %d\n", res);
+			res = -EFAULT;
+			break;
+		}
+		set_aggr_default_params(&teth_ctx->aggr_params.dl);
+		set_aggr_default_params(&teth_ctx->aggr_params.ul);
+		teth_ctx->aggr_params_known = true;
+		break;
+
+	case TETH_BRIDGE_IOC_GET_AGGR_PARAMS:
+		TETH_DBG("TETH_BRIDGE_IOC_GET_AGGR_PARAMS ioctl called\n");
+		if (copy_to_user((u8 *)arg, (u8 *)&teth_ctx->aggr_params,
+				   sizeof(struct teth_aggr_params))) {
+			res = -EFAULT;
+			break;
+		}
+		break;
+
+	case TETH_BRIDGE_IOC_GET_AGGR_CAPABILITIES:
+	{
+		u16 sz;
+		u16 pyld_sz;
+		struct teth_aggr_capabilities caps;
+
+		TETH_DBG("GET_AGGR_CAPABILITIES ioctl called\n");
+		sz = sizeof(struct teth_aggr_capabilities);
+		if (copy_from_user(&caps,
+				   (struct teth_aggr_capabilities *)arg,
+				   sz)) {
+			res = -EFAULT;
+			break;
+		}
+
+		if (caps.num_protocols < teth_ctx->aggr_caps->num_protocols) {
+			caps.num_protocols = teth_ctx->aggr_caps->num_protocols;
+			if (copy_to_user((struct teth_aggr_capabilities *)arg,
+					 &caps,
+					 sz)) {
+				res = -EFAULT;
+				break;
+			}
+			TETH_DBG("Not enough space allocated.\n");
+			res = -EAGAIN;
+			break;
+		}
+
+		pyld_sz = sz + caps.num_protocols *
+			sizeof(struct teth_aggr_params_link);
+
+		if (copy_to_user((u8 *)arg,
+				 (u8 *)(teth_ctx->aggr_caps),
+				 pyld_sz)) {
+			res = -EFAULT;
+			break;
+		}
+	}
+	break;
+	}
+
+	return res;
+}
+
+static void set_aggr_capabilities(void)
+{
+	u16 NUM_PROTOCOLS = 2;
+
+	teth_ctx->aggr_caps = kzalloc(sizeof(struct teth_aggr_capabilities) +
+				      NUM_PROTOCOLS *
+				      sizeof(struct teth_aggr_params_link),
+				      GFP_KERNEL);
+	if (teth_ctx->aggr_caps == NULL) {
+		TETH_ERR("Memory alloc failed for aggregation capabilities.\n");
+		return;
+	}
+
+	teth_ctx->aggr_caps->num_protocols = NUM_PROTOCOLS;
+
+	teth_ctx->aggr_caps->prot_caps[0].aggr_prot = TETH_AGGR_PROTOCOL_MBIM;
+	teth_ctx->aggr_caps->prot_caps[0].max_datagrams = 16;
+	teth_ctx->aggr_caps->prot_caps[0].max_transfer_size_byte = 16*1024;
+
+	teth_ctx->aggr_caps->prot_caps[1].aggr_prot = TETH_AGGR_PROTOCOL_TLP;
+	teth_ctx->aggr_caps->prot_caps[1].max_datagrams = 16;
+	teth_ctx->aggr_caps->prot_caps[1].max_transfer_size_byte = 16*1024;
+}
+
+void teth_bridge_get_client_handles(u32 *producer_handle,
+		u32 *consumer_handle)
+{
+	if (producer_handle == NULL || consumer_handle == NULL)
+		return;
+
+	*producer_handle = teth_ctx->usb_ipa_pipe_hdl;
+	*consumer_handle = teth_ctx->ipa_usb_pipe_hdl;
+}
+
+#ifdef CONFIG_DEBUG_FS
+static struct dentry *dent;
+static struct dentry *dfile_link_protocol;
+static struct dentry *dfile_get_aggr_params;
+static struct dentry *dfile_set_aggr_protocol;
+
+static ssize_t teth_debugfs_read_link_protocol(struct file *file,
+					       char __user *ubuf,
+					       size_t count,
+					       loff_t *ppos)
+{
+	int nbytes;
+
+	nbytes = scnprintf(dbg_buff, TETH_MAX_MSG_LEN, "Link protocol = %s\n",
+			   (teth_ctx->link_protocol ==
+				TETH_LINK_PROTOCOL_ETHERNET) ?
+			   "ETHERNET" :
+			   "IP");
+
+	return simple_read_from_buffer(ubuf, count, ppos, dbg_buff, nbytes);
+}
+
+static ssize_t teth_debugfs_write_link_protocol(struct file *file,
+					const char __user *ubuf,
+					size_t count,
+					loff_t *ppos)
+{
+	unsigned long missing;
+	enum teth_link_protocol_type link_protocol;
+
+	if (sizeof(dbg_buff) < count + 1)
+		return -EFAULT;
+
+	missing = copy_from_user(dbg_buff, ubuf, count);
+	if (missing)
+		return -EFAULT;
+
+	if (count > 0)
+		dbg_buff[count-1] = '\0';
+
+	if (strcmp(dbg_buff, "ETHERNET") == 0) {
+		link_protocol = TETH_LINK_PROTOCOL_ETHERNET;
+	} else if (strcmp(dbg_buff, "IP") == 0) {
+		link_protocol = TETH_LINK_PROTOCOL_IP;
+	} else {
+		TETH_ERR("Bad link protocol, got %s,\n"
+			 "Use <ETHERNET> or <IP>.\n", dbg_buff);
+		return count;
+	}
+
+	teth_set_bridge_mode(link_protocol);
+
+	return count;
+}
+
+static ssize_t teth_debugfs_read_aggr_params(struct file *file,
+					     char __user *ubuf,
+					     size_t count,
+					     loff_t *ppos)
+{
+	int nbytes = 0;
+	char aggr_str[20];
+
+	aggr_prot_to_str(teth_ctx->aggr_params.ul.aggr_prot,
+			 aggr_str,
+			 sizeof(aggr_str)-1);
+	nbytes += scnprintf(&dbg_buff[nbytes], TETH_MAX_MSG_LEN,
+			   "Aggregation parameters for uplink:\n");
+	nbytes += scnprintf(&dbg_buff[nbytes], TETH_MAX_MSG_LEN - nbytes,
+			    "  Aggregation protocol: %s\n",
+			    aggr_str);
+	nbytes += scnprintf(&dbg_buff[nbytes], TETH_MAX_MSG_LEN - nbytes,
+			    "  Max transfer size [byte]: %d\n",
+			    teth_ctx->aggr_params.ul.max_transfer_size_byte);
+	nbytes += scnprintf(&dbg_buff[nbytes], TETH_MAX_MSG_LEN - nbytes,
+			    "  Max datagrams: %d\n",
+			    teth_ctx->aggr_params.ul.max_datagrams);
+
+	aggr_prot_to_str(teth_ctx->aggr_params.dl.aggr_prot,
+			 aggr_str,
+			 sizeof(aggr_str)-1);
+	nbytes += scnprintf(&dbg_buff[nbytes], TETH_MAX_MSG_LEN,
+			   "Aggregation parameters for downlink:\n");
+	nbytes += scnprintf(&dbg_buff[nbytes], TETH_MAX_MSG_LEN - nbytes,
+			    "  Aggregation protocol: %s\n",
+			    aggr_str);
+	nbytes += scnprintf(&dbg_buff[nbytes], TETH_MAX_MSG_LEN - nbytes,
+			    "  Max transfer size [byte]: %d\n",
+			    teth_ctx->aggr_params.dl.max_transfer_size_byte);
+	nbytes += scnprintf(&dbg_buff[nbytes], TETH_MAX_MSG_LEN - nbytes,
+			    "  Max datagrams: %d\n",
+			    teth_ctx->aggr_params.dl.max_datagrams);
+
+	return simple_read_from_buffer(ubuf, count, ppos, dbg_buff, nbytes);
+}
+
+static ssize_t teth_debugfs_set_aggr_protocol(struct file *file,
+				      const char __user *ubuf,
+				      size_t count, loff_t *ppos)
+{
+	unsigned long missing;
+	enum teth_aggr_protocol_type aggr_prot;
+	int res;
+
+	if (sizeof(dbg_buff) < count + 1)
+		return -EFAULT;
+
+	missing = copy_from_user(dbg_buff, ubuf, count);
+	if (missing)
+		return -EFAULT;
+
+	if (count > 0)
+		dbg_buff[count-1] = '\0';
+
+	set_aggr_default_params(&teth_ctx->aggr_params.dl);
+	set_aggr_default_params(&teth_ctx->aggr_params.ul);
+
+	if (strcmp(dbg_buff, "NONE") == 0) {
+		aggr_prot = TETH_AGGR_PROTOCOL_NONE;
+	} else if (strcmp(dbg_buff, "MBIM") == 0) {
+		aggr_prot = TETH_AGGR_PROTOCOL_MBIM;
+	} else if (strcmp(dbg_buff, "TLP") == 0) {
+		aggr_prot = TETH_AGGR_PROTOCOL_TLP;
+	} else {
+		TETH_ERR("Bad aggregation protocol, got %s,\n"
+			 "Use <NONE>, <MBIM> or <TLP>.\n", dbg_buff);
+		return count;
+	}
+
+	teth_ctx->aggr_params.dl.aggr_prot = aggr_prot;
+	teth_ctx->aggr_params.ul.aggr_prot = aggr_prot;
+	teth_ctx->aggr_params_known = true;
+
+	res = teth_set_aggregation();
+	if (res)
+		TETH_ERR("Failed setting aggregation params\n");
+
+	return count;
+}
+
+const struct file_operations teth_link_protocol_ops = {
+	.read = teth_debugfs_read_link_protocol,
+	.write = teth_debugfs_write_link_protocol,
+};
+
+const struct file_operations teth_get_aggr_params_ops = {
+	.read = teth_debugfs_read_aggr_params,
+};
+
+const struct file_operations teth_set_aggr_protocol_ops = {
+	.write = teth_debugfs_set_aggr_protocol,
+};
+
+void teth_debugfs_init(void)
+{
+	const mode_t read_only_mode = S_IRUSR | S_IRGRP | S_IROTH;
+	const mode_t read_write_mode = S_IRUSR | S_IRGRP | S_IROTH |
+			S_IWUSR | S_IWGRP | S_IWOTH;
+
+	dent = debugfs_create_dir("ipa_teth", 0);
+	if (IS_ERR(dent)) {
+		IPAERR("fail to create folder ipa_teth debug_fs.\n");
+		return;
+	}
+
+	dfile_link_protocol =
+		debugfs_create_file("link_protocol", read_write_mode, dent, 0,
+				    &teth_link_protocol_ops);
+	if (!dfile_link_protocol || IS_ERR(dfile_link_protocol)) {
+		IPAERR("fail to create file link_protocol\n");
+		goto fail;
+	}
+
+	dfile_get_aggr_params =
+		debugfs_create_file("get_aggr_params", read_only_mode, dent, 0,
+				    &teth_get_aggr_params_ops);
+	if (!dfile_get_aggr_params || IS_ERR(dfile_get_aggr_params)) {
+		IPAERR("fail to create file get_aggr_params\n");
+		goto fail;
+	}
+
+	dfile_set_aggr_protocol =
+		debugfs_create_file("set_aggr_protocol", read_only_mode, dent,
+				    0, &teth_set_aggr_protocol_ops);
+	if (!dfile_set_aggr_protocol || IS_ERR(dfile_set_aggr_protocol)) {
+		IPAERR("fail to create file set_aggr_protocol\n");
+		goto fail;
+	}
+
+	return;
+fail:
+	debugfs_remove_recursive(dent);
+}
+#else
+void teth_debugfs_init(void) {}
+#endif /* CONFIG_DEBUG_FS */
+
+
+static const struct file_operations teth_bridge_drv_fops = {
+	.owner = THIS_MODULE,
+	.unlocked_ioctl = teth_bridge_ioctl,
+};
+
+/**
+* teth_bridge_driver_init() - Initialize tethering bridge driver
+*
+*/
+int teth_bridge_driver_init(void)
+{
+	int res;
+
+	TETH_DBG("Tethering bridge driver init\n");
+	teth_ctx = kzalloc(sizeof(*teth_ctx), GFP_KERNEL);
+	if (!teth_ctx) {
+		TETH_ERR("kzalloc err.\n");
+		return -ENOMEM;
+	}
+
+	set_aggr_capabilities();
+
+	teth_ctx->class = class_create(THIS_MODULE, TETH_BRIDGE_DRV_NAME);
+
+	res = alloc_chrdev_region(&teth_ctx->dev_num, 0, 1,
+				  TETH_BRIDGE_DRV_NAME);
+	if (res) {
+		TETH_ERR("alloc_chrdev_region err.\n");
+		res = -ENODEV;
+		goto fail_alloc_chrdev_region;
+	}
+
+	teth_ctx->dev = device_create(teth_ctx->class, NULL, teth_ctx->dev_num,
+				      teth_ctx, TETH_BRIDGE_DRV_NAME);
+	if (IS_ERR(teth_ctx->dev)) {
+		TETH_ERR(":device_create err.\n");
+		res = -ENODEV;
+		goto fail_device_create;
+	}
+
+	cdev_init(&teth_ctx->cdev, &teth_bridge_drv_fops);
+	teth_ctx->cdev.owner = THIS_MODULE;
+	teth_ctx->cdev.ops = &teth_bridge_drv_fops;
+
+	res = cdev_add(&teth_ctx->cdev, teth_ctx->dev_num, 1);
+	if (res) {
+		TETH_ERR(":cdev_add err=%d\n", -res);
+		res = -ENODEV;
+		goto fail_cdev_add;
+	}
+
+	teth_ctx->comp_hw_bridge_in_progress = false;
+
+	teth_debugfs_init();
+	TETH_DBG("Tethering bridge driver init OK\n");
+
+	return 0;
+fail_cdev_add:
+	device_destroy(teth_ctx->class, teth_ctx->dev_num);
+fail_device_create:
+	unregister_chrdev_region(teth_ctx->dev_num, 1);
+fail_alloc_chrdev_region:
+	kfree(teth_ctx->aggr_caps);
+	kfree(teth_ctx);
+	teth_ctx = NULL;
+
+	return res;
+}
+EXPORT_SYMBOL(teth_bridge_driver_init);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Tethering bridge driver");
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c
index bd1423d..c03ca69 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -95,7 +95,7 @@
 
 static struct regulator *hsusb_3p3;
 static struct regulator *hsusb_1p8;
-static struct regulator *hsusb_vddcx;
+static struct regulator *hsusb_vdd;
 static struct regulator *vbus_otg;
 static struct regulator *mhl_usb_hs_switch;
 static struct power_supply *psy;
@@ -111,7 +111,7 @@
 #endif
 }
 
-static const int vdd_val[VDD_TYPE_MAX][VDD_VAL_MAX] = {
+static int vdd_val[VDD_TYPE_MAX][VDD_VAL_MAX] = {
 		{  /* VDD_CX CORNER Voting */
 			[VDD_NONE]	= RPM_VREG_CORNER_NONE,
 			[VDD_MIN]	= RPM_VREG_CORNER_NOMINAL,
@@ -175,7 +175,7 @@
 	int ret;
 
 	min_vol = vdd_val[vdd_type][!!high];
-	ret = regulator_set_voltage(hsusb_vddcx, min_vol, max_vol);
+	ret = regulator_set_voltage(hsusb_vdd, min_vol, max_vol);
 	if (ret) {
 		pr_err("%s: unable to set the voltage for regulator "
 			"HSUSB_VDDCX\n", __func__);
@@ -3802,6 +3802,8 @@
 static int __init msm_otg_probe(struct platform_device *pdev)
 {
 	int ret = 0;
+	int len = 0;
+	u32 tmp[3];
 	struct resource *res;
 	struct msm_otg *motg;
 	struct usb_phy *phy;
@@ -3958,24 +3960,40 @@
 	clk_prepare_enable(motg->pclk);
 
 	motg->vdd_type = VDDCX_CORNER;
-	hsusb_vddcx = devm_regulator_get(motg->phy.dev, "hsusb_vdd_dig");
-	if (IS_ERR(hsusb_vddcx)) {
-		hsusb_vddcx = devm_regulator_get(motg->phy.dev, "HSUSB_VDDCX");
-		if (IS_ERR(hsusb_vddcx)) {
+	hsusb_vdd = devm_regulator_get(motg->phy.dev, "hsusb_vdd_dig");
+	if (IS_ERR(hsusb_vdd)) {
+		hsusb_vdd = devm_regulator_get(motg->phy.dev, "HSUSB_VDDCX");
+		if (IS_ERR(hsusb_vdd)) {
 			dev_err(motg->phy.dev, "unable to get hsusb vddcx\n");
-			ret = PTR_ERR(hsusb_vddcx);
+			ret = PTR_ERR(hsusb_vdd);
 			goto devote_xo_handle;
 		}
 		motg->vdd_type = VDDCX;
 	}
 
+	if (pdev->dev.of_node) {
+		of_get_property(pdev->dev.of_node,
+				"qcom,vdd-voltage-level",
+				&len);
+		if (len == sizeof(tmp)) {
+			of_property_read_u32_array(pdev->dev.of_node,
+					"qcom,vdd-voltage-level",
+					tmp, len/sizeof(*tmp));
+			vdd_val[motg->vdd_type][0] = tmp[0];
+			vdd_val[motg->vdd_type][1] = tmp[1];
+			vdd_val[motg->vdd_type][2] = tmp[2];
+		} else {
+			dev_dbg(&pdev->dev, "Using default hsusb vdd config.\n");
+		}
+	}
+
 	ret = msm_hsusb_config_vddcx(1);
 	if (ret) {
 		dev_err(&pdev->dev, "hsusb vddcx configuration failed\n");
 		goto devote_xo_handle;
 	}
 
-	ret = regulator_enable(hsusb_vddcx);
+	ret = regulator_enable(hsusb_vdd);
 	if (ret) {
 		dev_err(&pdev->dev, "unable to enable the hsusb vddcx\n");
 		goto free_config_vddcx;
@@ -3984,7 +4002,7 @@
 	ret = msm_hsusb_ldo_init(motg, 1);
 	if (ret) {
 		dev_err(&pdev->dev, "hsusb vreg configuration failed\n");
-		goto free_hsusb_vddcx;
+		goto free_hsusb_vdd;
 	}
 
 	if (pdata->mhl_enable) {
@@ -4167,10 +4185,10 @@
 	msm_hsusb_ldo_enable(motg, USB_PHY_REG_OFF);
 free_ldo_init:
 	msm_hsusb_ldo_init(motg, 0);
-free_hsusb_vddcx:
-	regulator_disable(hsusb_vddcx);
+free_hsusb_vdd:
+	regulator_disable(hsusb_vdd);
 free_config_vddcx:
-	regulator_set_voltage(hsusb_vddcx,
+	regulator_set_voltage(hsusb_vdd,
 		vdd_val[motg->vdd_type][VDD_NONE],
 		vdd_val[motg->vdd_type][VDD_MAX]);
 devote_xo_handle:
@@ -4264,8 +4282,8 @@
 	}
 	msm_hsusb_ldo_enable(motg, USB_PHY_REG_OFF);
 	msm_hsusb_ldo_init(motg, 0);
-	regulator_disable(hsusb_vddcx);
-	regulator_set_voltage(hsusb_vddcx,
+	regulator_disable(hsusb_vdd);
+	regulator_set_voltage(hsusb_vdd,
 		vdd_val[motg->vdd_type][VDD_NONE],
 		vdd_val[motg->vdd_type][VDD_MAX]);
 
diff --git a/drivers/video/msm/mdss/mdss_mdp.h b/drivers/video/msm/mdss/mdss_mdp.h
index 4c70770..e4f78ad 100644
--- a/drivers/video/msm/mdss/mdss_mdp.h
+++ b/drivers/video/msm/mdss/mdss_mdp.h
@@ -323,6 +323,7 @@
 
 struct mdss_mdp_ctl *mdss_mdp_ctl_init(struct mdss_panel_data *pdata,
 				       struct msm_fb_data_type *mfd);
+int mdss_mdp_ctl_setup(struct mdss_mdp_ctl *ctl);
 int mdss_mdp_ctl_split_display_setup(struct mdss_mdp_ctl *ctl,
 		struct mdss_panel_data *pdata);
 int mdss_mdp_ctl_destroy(struct mdss_mdp_ctl *ctl);
diff --git a/drivers/video/msm/mdss/mdss_mdp_ctl.c b/drivers/video/msm/mdss/mdss_mdp_ctl.c
index c640c73..cabb183 100644
--- a/drivers/video/msm/mdss/mdss_mdp_ctl.c
+++ b/drivers/video/msm/mdss/mdss_mdp_ctl.c
@@ -443,7 +443,7 @@
 	return NULL;
 }
 
-static int mdss_mdp_ctl_setup(struct mdss_mdp_ctl *ctl)
+int mdss_mdp_ctl_setup(struct mdss_mdp_ctl *ctl)
 {
 	struct mdss_mdp_ctl *split_ctl;
 	u32 width, height;
@@ -566,12 +566,6 @@
 
 	ctl->opmode |= (ctl->intf_num << 4);
 
-	ret = mdss_mdp_ctl_setup(ctl);
-	if (ret) {
-		pr_err("unable to setup control path %d\n", ctl->num);
-		goto ctl_init_fail;
-	}
-
 	if (ctl->intf_num == MDSS_MDP_NO_INTF) {
 		ctl->dst_format = pdata->panel_info.out_format;
 	} else {
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index c1dcc18..daa2499 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -1017,6 +1017,12 @@
 		return;
 	}
 
+	ret = mdss_mdp_overlay_start(mfd);
+	if (ret) {
+		pr_err("unable to start overlay %d (%d)\n", mfd->index, ret);
+		return;
+	}
+
 	if (is_mdss_iommu_attached())
 		data.p[0].addr = mfd->iova;
 	else
@@ -1454,6 +1460,10 @@
 		rc = mdss_mdp_overlay_start(mfd);
 		if (!IS_ERR_VALUE(rc))
 			rc = mdss_mdp_overlay_kickoff(mfd->ctl);
+	} else {
+		rc = mdss_mdp_ctl_setup(mfd->ctl);
+		if (rc)
+			return rc;
 	}
 
 	if (!IS_ERR_VALUE(rc) && mfd->vsync_pending) {
diff --git a/include/linux/diagchar.h b/include/linux/diagchar.h
index d3ee879..7a5ab0d 100644
--- a/include/linux/diagchar.h
+++ b/include/linux/diagchar.h
@@ -112,10 +112,10 @@
 /* This needs to be modified manually now, when we add
  a new RANGE of SSIDs to the msg_mask_tbl */
 #define MSG_MASK_TBL_CNT		24
-#define EVENT_LAST_ID			0x099F
+#define EVENT_LAST_ID			0x09AB
 
 #define MSG_SSID_0			0
-#define MSG_SSID_0_LAST			93
+#define MSG_SSID_0_LAST			94
 #define MSG_SSID_1			500
 #define MSG_SSID_1_LAST			506
 #define MSG_SSID_2			1000
@@ -278,6 +278,9 @@
 	MSG_LVL_LOW,
 	MSG_LVL_MED,
 	MSG_LVL_LOW,
+	MSG_LVL_LOW,
+	MSG_LVL_LOW,
+	MSG_LVL_HIGH,
 	MSG_LVL_LOW
 };
 
@@ -713,7 +716,7 @@
 /* LOG CODES */
 
 #define LOG_0	0x0
-#define LOG_1	0x1750
+#define LOG_1	0x1755
 #define LOG_2	0x0
 #define LOG_3	0x0
 #define LOG_4	0x4910
diff --git a/include/linux/dma-contiguous.h b/include/linux/dma-contiguous.h
index 285b593..8a1b3a1 100644
--- a/include/linux/dma-contiguous.h
+++ b/include/linux/dma-contiguous.h
@@ -70,7 +70,7 @@
 void dma_contiguous_reserve(phys_addr_t addr_limit);
 
 int dma_contiguous_reserve_area(phys_addr_t size, phys_addr_t *res_base,
-				  phys_addr_t limit);
+				  phys_addr_t limit, const char *name);
 
 int dma_contiguous_add_device(struct device *dev, phys_addr_t base);
 
@@ -91,7 +91,7 @@
 					 phys_addr_t base, phys_addr_t limit)
 {
 	int ret;
-	ret = dma_contiguous_reserve_area(size, &base, limit);
+	ret = dma_contiguous_reserve_area(size, &base, limit, NULL);
 	if (ret == 0)
 		ret = dma_contiguous_add_device(dev, base);
 	return ret;
diff --git a/include/linux/msm_ipa.h b/include/linux/msm_ipa.h
index c6f0730..30bf4f2 100644
--- a/include/linux/msm_ipa.h
+++ b/include/linux/msm_ipa.h
@@ -769,4 +769,87 @@
 				IPA_IOCTL_PULL_MSG, \
 				struct ipa_msg_meta *)
 
+/*
+ * unique magic number of the Tethering bridge ioctls
+ */
+#define TETH_BRIDGE_IOC_MAGIC 0xCE
+
+/*
+ * Ioctls supported by Tethering bridge driver
+ */
+#define TETH_BRIDGE_IOCTL_SET_BRIDGE_MODE	0
+#define TETH_BRIDGE_IOCTL_SET_AGGR_PARAMS	1
+#define TETH_BRIDGE_IOCTL_GET_AGGR_PARAMS	2
+#define TETH_BRIDGE_IOCTL_GET_AGGR_CAPABILITIES	3
+#define TETH_BRIDGE_IOCTL_MAX			4
+
+
+/**
+ * enum teth_link_protocol_type - link protocol (IP / Ethernet)
+ */
+enum teth_link_protocol_type {
+	TETH_LINK_PROTOCOL_IP,
+	TETH_LINK_PROTOCOL_ETHERNET,
+	TETH_LINK_PROTOCOL_MAX,
+};
+
+/**
+ * enum teth_aggr_protocol_type - Aggregation protocol (MBIM / TLP)
+ */
+enum teth_aggr_protocol_type {
+	TETH_AGGR_PROTOCOL_NONE,
+	TETH_AGGR_PROTOCOL_MBIM,
+	TETH_AGGR_PROTOCOL_TLP,
+	TETH_AGGR_PROTOCOL_MAX,
+};
+
+/**
+ * struct teth_aggr_params_link - Aggregation parameters for uplink/downlink
+ * @aggr_prot:			Aggregation protocol (MBIM / TLP)
+ * @max_transfer_size_byte:	Maximal size of aggregated packet in bytes.
+ *				Default value is 16*1024.
+ * @max_datagrams:		Maximal number of IP packets in an aggregated
+ *				packet. Default value is 16
+ */
+struct teth_aggr_params_link {
+	enum teth_aggr_protocol_type aggr_prot;
+	uint32_t max_transfer_size_byte;
+	uint32_t max_datagrams;
+};
+
+
+/**
+ * struct teth_aggr_params - Aggregation parmeters
+ * @ul:	Uplink parameters
+ * @dl: Downlink parmaeters
+ */
+struct teth_aggr_params {
+	struct teth_aggr_params_link ul;
+	struct teth_aggr_params_link dl;
+};
+
+/**
+ * struct teth_aggr_capabilities - Aggregation capabilities
+ * @num_protocols:		Number of protocols described in the array
+ * @prot_caps[]:		Array of aggregation capabilities per protocol
+ */
+struct teth_aggr_capabilities {
+	uint16_t num_protocols;
+	struct teth_aggr_params_link prot_caps[0];
+};
+
+
+#define TETH_BRIDGE_IOC_SET_BRIDGE_MODE _IOW(TETH_BRIDGE_IOC_MAGIC, \
+				TETH_BRIDGE_IOCTL_SET_BRIDGE_MODE, \
+				enum teth_link_protocol_type)
+#define TETH_BRIDGE_IOC_SET_AGGR_PARAMS _IOW(TETH_BRIDGE_IOC_MAGIC, \
+				TETH_BRIDGE_IOCTL_SET_AGGR_PARAMS, \
+				struct teth_aggr_params *)
+#define TETH_BRIDGE_IOC_GET_AGGR_PARAMS _IOR(TETH_BRIDGE_IOC_MAGIC, \
+				TETH_BRIDGE_IOCTL_GET_AGGR_PARAMS, \
+				struct teth_aggr_params *)
+#define TETH_BRIDGE_IOC_GET_AGGR_CAPABILITIES _IOWR(TETH_BRIDGE_IOC_MAGIC, \
+				TETH_BRIDGE_IOCTL_GET_AGGR_CAPABILITIES, \
+				struct teth_aggr_capabilities *)
+
 #endif /* _MSM_IPA_H_ */
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index c6ee4f0..0683296 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -365,8 +365,8 @@
  *	requests to connect to a specified network but without separating
  *	auth and assoc steps. For this, you need to specify the SSID in a
  *	%NL80211_ATTR_SSID attribute, and can optionally specify the association
- *	IEs in %NL80211_ATTR_IE, %NL80211_ATTR_AUTH_TYPE, %NL80211_ATTR_MAC,
- *	%NL80211_ATTR_WIPHY_FREQ, %NL80211_ATTR_CONTROL_PORT,
+ *	IEs in %NL80211_ATTR_IE, %NL80211_ATTR_AUTH_TYPE, %NL80211_ATTR_USE_MFP,
+ *	%NL80211_ATTR_MAC, %NL80211_ATTR_WIPHY_FREQ, %NL80211_ATTR_CONTROL_PORT,
  *	%NL80211_ATTR_CONTROL_PORT_ETHERTYPE and
  *	%NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT.
  *	Background scan period can optionally be
@@ -906,7 +906,7 @@
  * @NL80211_ATTR_USE_MFP: Whether management frame protection (IEEE 802.11w) is
  *	used for the association (&enum nl80211_mfp, represented as a u32);
  *	this attribute can be used
- *	with %NL80211_CMD_ASSOCIATE request
+ *	with %NL80211_CMD_ASSOCIATE and %NL80211_CMD_CONNECT requests
  *
  * @NL80211_ATTR_STA_FLAGS2: Attribute containing a
  *	&struct nl80211_sta_flag_update.
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 5e32ff7..6666c69 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -1199,6 +1199,7 @@
  * @ie: IEs for association request
  * @ie_len: Length of assoc_ie in octets
  * @privacy: indicates whether privacy-enabled APs should be used
+ * @mfp: indicate whether management frame protection is used
  * @crypto: crypto settings
  * @key_len: length of WEP key for shared key authentication
  * @key_idx: index of WEP key for shared key authentication
@@ -1219,6 +1220,7 @@
 	u8 *ie;
 	size_t ie_len;
 	bool privacy;
+	enum nl80211_mfp mfp;
 	struct cfg80211_crypto_settings crypto;
 	const u8 *key;
 	u8 key_len, key_idx;
diff --git a/kernel/sys.c b/kernel/sys.c
index e7006eb..39791be 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -1179,15 +1179,16 @@
  * Work around broken programs that cannot handle "Linux 3.0".
  * Instead we map 3.x to 2.6.40+x, so e.g. 3.0 would be 2.6.40
  */
-static int override_release(char __user *release, int len)
+static int override_release(char __user *release, size_t len)
 {
 	int ret = 0;
-	char buf[65];
 
 	if (current->personality & UNAME26) {
-		char *rest = UTS_RELEASE;
+		const char *rest = UTS_RELEASE;
+		char buf[65] = { 0 };
 		int ndots = 0;
 		unsigned v;
+		size_t copy;
 
 		while (*rest) {
 			if (*rest == '.' && ++ndots >= 3)
@@ -1197,8 +1198,9 @@
 			rest++;
 		}
 		v = ((LINUX_VERSION_CODE >> 8) & 0xff) + 40;
-		snprintf(buf, len, "2.6.%u%s", v, rest);
-		ret = copy_to_user(release, buf, len);
+		copy = min(sizeof(buf), max_t(size_t, 1, len));
+		copy = scnprintf(buf, copy, "2.6.%u%s", v, rest);
+		ret = copy_to_user(release, buf, copy + 1);
 	}
 	return ret;
 }
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 5c2e805..1ccc69e 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -5173,6 +5173,15 @@
 		connect.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
 	}
 
+	if (info->attrs[NL80211_ATTR_USE_MFP]) {
+		connect.mfp = nla_get_u32(info->attrs[NL80211_ATTR_USE_MFP]);
+		if (connect.mfp != NL80211_MFP_REQUIRED &&
+		    connect.mfp != NL80211_MFP_NO)
+			return -EINVAL;
+	} else {
+		connect.mfp = NL80211_MFP_NO;
+	}
+
 	if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
 		connect.channel =
 			ieee80211_get_channel(wiphy,
diff --git a/net/wireless/sme.c b/net/wireless/sme.c
index bbbed73..ab91446 100644
--- a/net/wireless/sme.c
+++ b/net/wireless/sme.c
@@ -190,7 +190,8 @@
 					    prev_bssid,
 					    params->ssid, params->ssid_len,
 					    params->ie, params->ie_len,
-					    false, &params->crypto,
+					    params->mfp != NL80211_MFP_NO,
+					    &params->crypto,
 					    params->flags, &params->ht_capa,
 					    &params->ht_capa_mask);
 		if (err)
diff --git a/sound/soc/codecs/wcd9320.c b/sound/soc/codecs/wcd9320.c
index 7f17eef..b3d4901 100644
--- a/sound/soc/codecs/wcd9320.c
+++ b/sound/soc/codecs/wcd9320.c
@@ -932,12 +932,6 @@
 	SOC_SINGLE_TLV("ADC5 Volume", TAIKO_A_TX_5_6_EN, 5, 3, 0, analog_gain),
 	SOC_SINGLE_TLV("ADC6 Volume", TAIKO_A_TX_5_6_EN, 1, 3, 0, analog_gain),
 
-
-	SOC_SINGLE("MICBIAS1 CAPLESS Switch", TAIKO_A_MICB_1_CTL, 4, 1, 1),
-	SOC_SINGLE("MICBIAS2 CAPLESS Switch", TAIKO_A_MICB_2_CTL, 4, 1, 1),
-	SOC_SINGLE("MICBIAS3 CAPLESS Switch", TAIKO_A_MICB_3_CTL, 4, 1, 1),
-	SOC_SINGLE("MICBIAS4 CAPLESS Switch", TAIKO_A_MICB_4_CTL, 4, 1, 1),
-
 	SOC_SINGLE_EXT("ANC Slot", SND_SOC_NOPM, 0, 0, 100, taiko_get_anc_slot,
 		taiko_put_anc_slot),
 	SOC_ENUM("TX1 HPF cut off", cf_dec1_enum),
diff --git a/sound/soc/msm/qdsp6v2/audio_ocmem.c b/sound/soc/msm/qdsp6v2/audio_ocmem.c
index 1969fe8..c14cb74 100644
--- a/sound/soc/msm/qdsp6v2/audio_ocmem.c
+++ b/sound/soc/msm/qdsp6v2/audio_ocmem.c
@@ -503,6 +503,7 @@
 		rc = -EINVAL;
 	}
 
+	kfree(voice_ocm_work);
 	return;
 }
 /**
@@ -614,6 +615,7 @@
 		rc = -EINVAL;
 	}
 
+	kfree(audio_ocm_work);
 	return;
 }
 
diff --git a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
index 2d2fe31..d0b5500 100644
--- a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
@@ -148,7 +148,6 @@
 		 */
 		snd_pcm_stream_lock_irq(substream);
 		if (snd_pcm_playback_empty(substream)) {
-			atomic_set(&prtd->pending_buffer, 1);
 			runtime->render_flag |= SNDRV_RENDER_STOPPED;
 			stop_playback = 1;
 		}
@@ -1038,7 +1037,6 @@
 				(prtd->out_head + 1) & (runtime->periods - 1);
 
 		runtime->render_flag &= ~SNDRV_RENDER_STOPPED;
-		atomic_set(&prtd->pending_buffer, 0);
 		return 0;
 	}
 	return 0;
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-lpa-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-lpa-v2.c
index ae7e76c..3a4a674 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-lpa-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-lpa-v2.c
@@ -536,8 +536,8 @@
 		memset(&tstamp, 0x0, sizeof(struct snd_compr_tstamp));
 		rc = q6asm_get_session_time(prtd->audio_client, &timestamp);
 		if (rc < 0) {
-			pr_err("%s: Get Session Time return value =%lld\n",
-				__func__, timestamp);
+			pr_err("%s: Fail to get session time stamp, rc:%d\n",
+							__func__, rc);
 			return -EAGAIN;
 		}
 		temp = (timestamp * 2 * runtime->channels);
diff --git a/sound/soc/msm/qdsp6v2/q6adm.c b/sound/soc/msm/qdsp6v2/q6adm.c
index 913dded..1f2f307 100644
--- a/sound/soc/msm/qdsp6v2/q6adm.c
+++ b/sound/soc/msm/qdsp6v2/q6adm.c
@@ -223,6 +223,12 @@
 	adm_params->hdr.dest_svc = APR_SVC_ADM;
 	adm_params->hdr.dest_domain = APR_DOMAIN_ADSP;
 	index = afe_get_port_index(port_id);
+	if (index < 0 || index >= AFE_MAX_PORTS) {
+		pr_err("%s: invalid port idx %d portid %#x\n",
+				__func__, index, port_id);
+		ret = -EINVAL;
+		goto fail_cmd;
+	}
 	adm_params->hdr.dest_port = atomic_read(&this_adm.copp_id[index]);
 	adm_params->hdr.token = port_id;
 	adm_params->hdr.opcode = ADM_CMD_SET_PP_PARAMS_V5;