Merge "media: dvb: mpq: Secure demux API updates"
diff --git a/arch/arm/boot/dts/msm8974-v2-iommu.dtsi b/arch/arm/boot/dts/msm8974-v2-iommu.dtsi
index 500f1de..584869d 100644
--- a/arch/arm/boot/dts/msm8974-v2-iommu.dtsi
+++ b/arch/arm/boot/dts/msm8974-v2-iommu.dtsi
@@ -41,8 +41,8 @@
 				0x2034
 				0x2038>;
 
-	qcom,iommu-bfb-data =  <0x1FFFFFF
-				0x0
+	qcom,iommu-bfb-data =  <0xFFFFFFFF
+				0xFFFFFFFF
 				0x00000004
 				0x00000008
 				0x00000000
@@ -119,7 +119,7 @@
 				0x0
 				0x10
 				0x50
-				0x00002000
+				0x0
 				0x00002804
 				0x00009614
 				0x0
@@ -233,7 +233,7 @@
 				0x0
 				0x20
 				0x78
-				0x00004000
+				0x0
 				0x00003c08
 				0x0000b41e
 				0x0
diff --git a/arch/arm/configs/msm9625_defconfig b/arch/arm/configs/msm9625_defconfig
index 540fdf6..0f93930 100644
--- a/arch/arm/configs/msm9625_defconfig
+++ b/arch/arm/configs/msm9625_defconfig
@@ -147,6 +147,7 @@
 CONFIG_IP6_NF_RAW=y
 CONFIG_BRIDGE_NF_EBTABLES=y
 CONFIG_BRIDGE_EBT_BROUTE=y
+CONFIG_BRIDGE_EBT_T_FILTER=y
 CONFIG_BRIDGE=y
 CONFIG_NET_SCHED=y
 CONFIG_NET_SCH_HTB=y
diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c
index 4147b44..bf022ac 100644
--- a/drivers/cpufreq/cpufreq_ondemand.c
+++ b/drivers/cpufreq/cpufreq_ondemand.c
@@ -1170,10 +1170,10 @@
 		this_dbs_info->cur_policy = NULL;
 		if (!cpu)
 			input_unregister_handler(&dbs_input_handler);
-		mutex_unlock(&dbs_mutex);
 		if (!dbs_enable)
 			sysfs_remove_group(cpufreq_global_kobject,
 					   &dbs_attr_group);
+		mutex_unlock(&dbs_mutex);
 
 		break;
 
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
index f6b97d4..d412435 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
@@ -184,6 +184,7 @@
 	struct msm_vfe_stats_hardware_info *stats_hw_info;
 	struct v4l2_subdev_internal_ops *subdev_internal_ops;
 	struct v4l2_subdev_ops *subdev_ops;
+	uint32_t dmi_reg_offset;
 };
 
 struct msm_vfe_axi_hardware_info {
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
index a522bd6..750963c 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
@@ -919,6 +919,7 @@
 			.get_pingpong_status = msm_vfe32_get_pingpong_status,
 		},
 	},
+	.dmi_reg_offset = 0x5A0,
 	.axi_hw_info = &msm_vfe32_axi_hw_info,
 	.subdev_ops = &msm_vfe32_subdev_ops,
 	.subdev_internal_ops = &msm_vfe32_internal_ops,
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
index dba59d7..ed4aa7f 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
@@ -1302,6 +1302,7 @@
 			.get_pingpong_status = msm_vfe40_get_pingpong_status,
 		},
 	},
+	.dmi_reg_offset = 0x918,
 	.axi_hw_info = &msm_vfe40_axi_hw_info,
 	.stats_hw_info = &msm_vfe40_stats_hw_info,
 	.subdev_ops = &msm_vfe40_subdev_ops,
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
index 606ee89..ac3ce0a 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
@@ -35,6 +35,8 @@
 	stream_cfg_cmd->axi_stream_handle =
 		(++axi_data->stream_handle_cnt) << 8 | i;
 
+	memset(&axi_data->stream_info[i], 0,
+		   sizeof(struct msm_vfe_axi_stream));
 	axi_data->stream_info[i].session_id = stream_cfg_cmd->session_id;
 	axi_data->stream_info[i].stream_id = stream_cfg_cmd->stream_id;
 	axi_data->stream_info[i].buf_divert = stream_cfg_cmd->buf_divert;
@@ -621,7 +623,6 @@
 	int i;
 	struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
 	uint32_t wm_reload_mask = 0x0, reg_update_mask = 0x1;
-	int send_update_complete = 0;
 	for (i = 0; i < MAX_NUM_STREAM; i++) {
 		if (axi_data->stream_info[i].state == START_PENDING ||
 				axi_data->stream_info[i].state ==
@@ -631,9 +632,6 @@
 				&wm_reload_mask, &reg_update_mask);
 			if (axi_data->stream_info[i].state == STOP_PENDING)
 				axi_data->stream_info[i].state = STOPPING;
-		} else if (axi_data->stream_info[i].state == STOPPING) {
-			send_update_complete = 1;
-			axi_data->stream_info[i].state = INACTIVE;
 		}
 	}
 	/*Reload AXI*/
@@ -642,47 +640,31 @@
 	/*Reg update per src*/
 	vfe_dev->hw_info->vfe_ops.core_ops.
 		reg_update(vfe_dev, reg_update_mask);
-	if (send_update_complete) {
+	if (vfe_dev->axi_data.stream_update) {
 		ISP_DBG("%s: send update complete\n", __func__);
 		vfe_dev->axi_data.stream_update = 0;
 		complete(&vfe_dev->stream_config_complete);
 	}
 }
 
-int msm_isp_cfg_ping_pong_address(struct vfe_device *vfe_dev,
-	struct msm_vfe_axi_stream *stream_info, uint32_t pingpong_status,
-	struct timeval *tv)
+static void msm_isp_cfg_pong_address(struct vfe_device *vfe_dev,
+		struct msm_vfe_axi_stream *stream_info)
 {
-	int i, rc = -1;
-	struct msm_isp_buffer *buf = NULL;
-	struct msm_isp_event_data buf_event;
-	uint32_t pingpong_bit = 0;
-	uint32_t bufq_handle = stream_info->bufq_handle;
-	uint32_t stream_idx = stream_info->stream_handle & 0xFF;
+	int i;
+	struct msm_isp_buffer *buf = stream_info->buf[1];
+	for (i = 0; i < stream_info->num_planes; i++)
+		vfe_dev->hw_info->vfe_ops.axi_ops.update_ping_pong_addr(
+		vfe_dev, stream_info->wm[i],
+		VFE_PING_FLAG, buf->mapped_info[i].paddr);
+	stream_info->buf[0] = buf;
+}
 
+static void msm_isp_get_done_buf(struct vfe_device *vfe_dev,
+	struct msm_vfe_axi_stream *stream_info, uint32_t pingpong_status,
+	struct msm_isp_buffer **done_buf)
+{
+	uint32_t pingpong_bit = 0, i;
 	pingpong_bit = (~(pingpong_status >> stream_info->wm[0]) & 0x1);
-	rc = vfe_dev->buf_mgr->ops->get_buf(
-		vfe_dev->buf_mgr, bufq_handle, &buf);
-	if (rc < 0) {
-		if (stream_info->stream_type == BURST_STREAM &&
-				stream_info->num_burst_capture <= 1) {
-			rc = 0;
-			if (pingpong_bit)
-				buf = stream_info->buf[0];
-			else
-				buf = stream_info->buf[1];
-		} else {
-			vfe_dev->error_info.
-				stream_framedrop_count[stream_idx]++;
-			return rc;
-		}
-	}
-
-	if (buf->num_planes != stream_info->num_planes) {
-		pr_err("%s: Invalid buffer\n", __func__);
-		rc = -EINVAL;
-		goto buf_error;
-	}
 	for (i = 0; i < stream_info->num_planes; i++) {
 		if (pingpong_bit !=
 			(~(pingpong_status >> stream_info->wm[i]) & 0x1)) {
@@ -690,19 +672,58 @@
 				__func__, pingpong_status);
 		}
 	}
+	*done_buf = stream_info->buf[pingpong_bit];
+}
+
+static int msm_isp_cfg_ping_pong_address(struct vfe_device *vfe_dev,
+	struct msm_vfe_axi_stream *stream_info, uint32_t pingpong_status)
+{
+	int i, rc = -1;
+	struct msm_isp_buffer *buf = NULL;
+	uint32_t pingpong_bit = 0;
+	uint32_t bufq_handle = stream_info->bufq_handle;
+	uint32_t stream_idx = stream_info->stream_handle & 0xFF;
+
+	rc = vfe_dev->buf_mgr->ops->get_buf(
+		vfe_dev->buf_mgr, bufq_handle, &buf);
+	if (rc < 0) {
+		vfe_dev->error_info.
+			stream_framedrop_count[stream_idx]++;
+		return rc;
+	}
+
+	if (buf->num_planes != stream_info->num_planes) {
+		pr_err("%s: Invalid buffer\n", __func__);
+		rc = -EINVAL;
+		goto buf_error;
+	}
+
 	for (i = 0; i < stream_info->num_planes; i++)
 		vfe_dev->hw_info->vfe_ops.axi_ops.update_ping_pong_addr(
 		vfe_dev, stream_info->wm[i],
 		pingpong_status, buf->mapped_info[i].paddr);
 
-	if (stream_info->buf[pingpong_bit] && tv) {
+	pingpong_bit = (~(pingpong_status >> stream_info->wm[0]) & 0x1);
+	stream_info->buf[pingpong_bit] = buf;
+	return 0;
+buf_error:
+	vfe_dev->buf_mgr->ops->put_buf(vfe_dev->buf_mgr,
+		buf->bufq_handle, buf->buf_idx);
+	return rc;
+}
+
+static void msm_isp_process_done_buf(struct vfe_device *vfe_dev,
+	struct msm_vfe_axi_stream *stream_info, struct msm_isp_buffer *buf,
+	struct timeval *tv)
+{
+	struct msm_isp_event_data buf_event;
+	uint32_t frame_id = vfe_dev->axi_data.
+		src_info[stream_info->stream_src].frame_id;
+	if (buf && tv) {
 		if (stream_info->buf_divert) {
 			vfe_dev->buf_mgr->ops->buf_divert(vfe_dev->buf_mgr,
-				stream_info->buf[pingpong_bit]->bufq_handle,
-				stream_info->buf[pingpong_bit]->buf_idx,
-				tv, stream_info->frame_id);
-
-			buf_event.frame_id = stream_info->frame_id;
+				buf->bufq_handle, buf->buf_idx, tv, frame_id);
+			buf_event.frame_id = frame_id;
 			buf_event.timestamp = *tv;
 			buf_event.u.buf_done.session_id =
 				stream_info->session_id;
@@ -710,24 +731,14 @@
 				stream_info->stream_id;
 			buf_event.u.buf_done.handle =
 				stream_info->bufq_handle;
-			buf_event.u.buf_done.buf_idx =
-			stream_info->buf[pingpong_bit]->buf_idx;
+			buf_event.u.buf_done.buf_idx = buf->buf_idx;
 			msm_isp_send_event(
 				vfe_dev, ISP_EVENT_BUF_DIVERT, &buf_event);
 		} else {
 			vfe_dev->buf_mgr->ops->buf_done(vfe_dev->buf_mgr,
-				stream_info->buf[pingpong_bit]->bufq_handle,
-				stream_info->buf[pingpong_bit]->buf_idx,
-				tv, stream_info->frame_id);
+				buf->bufq_handle, buf->buf_idx, tv, frame_id);
 		}
 	}
-
-	stream_info->buf[pingpong_bit] = buf;
-	return 0;
-buf_error:
-	vfe_dev->buf_mgr->ops->put_buf(vfe_dev->buf_mgr,
-		buf->bufq_handle, buf->buf_idx);
-	return rc;
 }
 
 enum msm_isp_camif_update_state
@@ -855,7 +866,6 @@
 			&axi_data->stream_info[
 				(stream_cfg_cmd->stream_handle[i] & 0xFF)];
 
-
 		if (stream_info->stream_src == RDI)
 			src_state =
 				axi_data->src_info[
@@ -869,9 +879,23 @@
 		if (stream_cfg_cmd->cmd == START_STREAM) {
 			/*Set address for both PING & PONG register */
 			rc = msm_isp_cfg_ping_pong_address(vfe_dev,
-				stream_info, VFE_PING_FLAG, NULL);
-			rc = msm_isp_cfg_ping_pong_address(vfe_dev,
-				stream_info, VFE_PONG_FLAG, NULL);
+				stream_info, VFE_PONG_FLAG);
+			if (rc < 0) {
+				pr_err("%s: No buffer for start stream\n",
+					   __func__);
+				return rc;
+			}
+			/* For burst stream of one capture, only one buffer
+			 * is allocated. Duplicate ping buffer address to pong
+			 * buffer to ensure hardware write to a valid address
+			 */
+			if (stream_info->stream_type == BURST_STREAM &&
+				stream_info->num_burst_capture <= 1) {
+				msm_isp_cfg_pong_address(vfe_dev, stream_info);
+			} else {
+				rc = msm_isp_cfg_ping_pong_address(vfe_dev,
+					stream_info, VFE_PING_FLAG);
+			}
 		}
 		if (src_state && camif_update != DISABLE_CAMIF) {
 			/*On the fly stream start/stop */
@@ -888,7 +912,8 @@
 	}
 	if (!wait_for_complete) {
 		/*Reload AXI*/
-		vfe_dev->hw_info->vfe_ops.axi_ops.
+		if (stream_cfg_cmd->cmd == START_STREAM)
+			vfe_dev->hw_info->vfe_ops.axi_ops.
 			reload_wm(vfe_dev, wm_reload_mask);
 		/*Reg update per src*/
 		vfe_dev->hw_info->vfe_ops.core_ops.
@@ -904,7 +929,8 @@
 		axi_data->stream_update = 1;
 		spin_unlock_irqrestore(&vfe_dev->shared_data_lock, flags);
 		/*Reload AXI*/
-		vfe_dev->hw_info->vfe_ops.axi_ops.
+		if (stream_cfg_cmd->cmd == START_STREAM)
+			vfe_dev->hw_info->vfe_ops.axi_ops.
 			reload_wm(vfe_dev, wm_reload_mask);
 		/*Reg update per src*/
 		vfe_dev->hw_info->vfe_ops.core_ops.
@@ -956,7 +982,8 @@
 	uint32_t irq_status0, uint32_t irq_status1,
 	struct timeval *tv)
 {
-	int i;
+	int i, rc = 0;
+	struct msm_isp_buffer *done_buf = NULL;
 	uint32_t comp_mask = 0, wm_mask = 0;
 	uint32_t pingpong_status, stream_idx;
 	struct msm_vfe_axi_stream *stream_info;
@@ -988,8 +1015,18 @@
 					__func__,
 					stream_idx, stream_info->frame_id);
 				stream_info->frame_id++;
-				msm_isp_cfg_ping_pong_address(vfe_dev,
-					stream_info, pingpong_status, tv);
+				msm_isp_get_done_buf(vfe_dev, stream_info,
+					pingpong_status, &done_buf);
+				if (stream_info->stream_type ==
+					CONTINUOUS_STREAM ||
+					stream_info->num_burst_capture > 1) {
+					rc = msm_isp_cfg_ping_pong_address(
+							vfe_dev, stream_info,
+							pingpong_status);
+				}
+				if (done_buf && !rc)
+					msm_isp_process_done_buf(vfe_dev,
+					stream_info, done_buf, tv);
 			}
 		}
 		wm_mask &= ~(comp_info->stream_composite_mask);
@@ -1005,8 +1042,16 @@
 			stream_idx = axi_data->free_wm[i] & 0xFF;
 			stream_info = &axi_data->stream_info[stream_idx];
 			stream_info->frame_id++;
-			msm_isp_cfg_ping_pong_address(vfe_dev,
-			stream_info, pingpong_status, tv);
+			msm_isp_get_done_buf(vfe_dev, stream_info,
+						pingpong_status, &done_buf);
+			if (stream_info->stream_type == CONTINUOUS_STREAM ||
+				stream_info->num_burst_capture > 1) {
+				rc = msm_isp_cfg_ping_pong_address(vfe_dev,
+					stream_info, pingpong_status);
+			}
+			if (done_buf && !rc)
+				msm_isp_process_done_buf(vfe_dev,
+				stream_info, done_buf, tv);
 		}
 	}
 	return;
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.h
index 0c64c19..9765ae2 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.h
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.h
@@ -52,10 +52,6 @@
 
 void msm_isp_axi_stream_update(struct vfe_device *vfe_dev);
 
-int msm_isp_cfg_ping_pong_address(struct vfe_device *vfe_dev,
-	struct msm_vfe_axi_stream *stream_info, uint32_t pingpong_status,
-	struct timeval *tv);
-
 void msm_isp_update_framedrop_reg(struct vfe_device *vfe_dev);
 void msm_isp_update_framedrop_count(struct vfe_device *vfe_dev);
 void msm_isp_sof_notify(struct vfe_device *vfe_dev,
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
index ab8dc95..e181b53 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
@@ -219,15 +219,15 @@
 				lo_val1 = lo_val & 0x0000FFFF;
 				lo_val = (lo_val & 0xFFFF0000)>>16;
 				msm_camera_io_w(lo_val1, vfe_dev->vfe_base +
-								0x091C);
+					vfe_dev->hw_info->dmi_reg_offset + 0x4);
 			} else if (reg_cfg_cmd->cmd_type ==
 					VFE_WRITE_DMI_64BIT) {
 				hi_val = *hi_tbl_ptr++;
 				msm_camera_io_w(hi_val, vfe_dev->vfe_base +
-					   0x0918);
+					   vfe_dev->hw_info->dmi_reg_offset);
 			}
 			msm_camera_io_w(lo_val, vfe_dev->vfe_base +
-							0x091C);
+					vfe_dev->hw_info->dmi_reg_offset + 0x4);
 		}
 		break;
 	}
@@ -258,16 +258,16 @@
 		for (i = 0; i < reg_cfg_cmd->u.dmi_info.len/4; i++) {
 			if (reg_cfg_cmd->cmd_type == VFE_READ_DMI_64BIT) {
 				hi_val = msm_camera_io_r(vfe_dev->vfe_base +
-								0x0918);
+					vfe_dev->hw_info->dmi_reg_offset);
 				*hi_tbl_ptr++ = hi_val;
 			}
 
 			lo_val = msm_camera_io_r(vfe_dev->vfe_base +
-							0x091C);
+					vfe_dev->hw_info->dmi_reg_offset + 0x4);
 
 			if (reg_cfg_cmd->cmd_type == VFE_READ_DMI_16BIT) {
 				lo_val1 = msm_camera_io_r(vfe_dev->vfe_base +
-								0x091C);
+					vfe_dev->hw_info->dmi_reg_offset + 0x4);
 				lo_val |= lo_val1 << 16;
 			}
 			*lo_tbl_ptr++ = lo_val;
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c
index 2e78f33..a8e5c97 100644
--- a/drivers/mmc/host/msm_sdcc.c
+++ b/drivers/mmc/host/msm_sdcc.c
@@ -4325,6 +4325,69 @@
 	}
 }
 
+/**
+ *	msmsdcc_stop_request - stops ongoing request
+ *	@mmc: MMC host, running the request
+ *
+ *	Stops currently running request synchronously. All relevant request
+ *	information is cleared.
+ */
+int msmsdcc_stop_request(struct mmc_host *mmc)
+{
+	struct msmsdcc_host *host = mmc_priv(mmc);
+	struct mmc_request *mrq;
+	unsigned long flags;
+	int rc = 0;
+
+	spin_lock_irqsave(&host->lock, flags);
+	mrq = host->curr.mrq;
+	if (mrq) {
+		msmsdcc_reset_and_restore(host);
+		/*
+		 * Note: We are just taking care of SPS. We may also
+		 * need to think about ADM (and PIO?) later if required.
+		 */
+		if (host->sps.sg && is_sps_mode(host)) {
+			if (!mrq->data->host_cookie)
+				dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg,
+					host->sps.num_ents, host->sps.dir);
+			host->sps.sg = NULL;
+			host->sps.busy = 0;
+		}
+
+		/*
+		 * Clear current request information as current
+		 * request has ended
+		 */
+		memset(&host->curr, 0, sizeof(struct msmsdcc_curr_req));
+		del_timer(&host->req_tout_timer);
+	} else {
+		rc = -EINVAL;
+	}
+	spin_unlock_irqrestore(&host->lock, flags);
+
+	return rc;
+}
+
+/**
+ *	msmsdcc_get_xfer_remain - returns number of bytes passed on bus
+ *	@mmc: MMC host, running the request
+ *
+ *	Returns the number of bytes passed for SPS transfer. 0 - for non-SPS
+ *	transfer.
+ */
+unsigned int msmsdcc_get_xfer_remain(struct mmc_host *mmc)
+{
+	struct msmsdcc_host *host = mmc_priv(mmc);
+	u32 data_cnt = 0;
+
+	/* Currently, we don't support to stop the non-SPS transfer */
+	if (host->sps.busy && atomic_read(&host->clks_on))
+		data_cnt = readl_relaxed(host->base + MMCIDATACNT);
+
+	return data_cnt;
+}
+
 static const struct mmc_host_ops msmsdcc_ops = {
 	.enable		= msmsdcc_enable,
 	.disable	= msmsdcc_disable,
@@ -4337,6 +4400,8 @@
 	.start_signal_voltage_switch = msmsdcc_switch_io_voltage,
 	.execute_tuning = msmsdcc_execute_tuning,
 	.hw_reset = msmsdcc_hw_reset,
+	.stop_request = msmsdcc_stop_request,
+	.get_xfer_remain = msmsdcc_get_xfer_remain,
 };
 
 static void msmsdcc_enable_status_gpio(struct msmsdcc_host *host)
diff --git a/drivers/usb/dwc3/debug.h b/drivers/usb/dwc3/debug.h
index 5894ee8..b156c5f 100644
--- a/drivers/usb/dwc3/debug.h
+++ b/drivers/usb/dwc3/debug.h
@@ -39,9 +39,24 @@
 #include "core.h"
 
 #ifdef CONFIG_DEBUG_FS
+extern void dbg_event(u8, const char*, int);
+extern void dbg_print(u8, const char*, int, const char*);
+extern void dbg_done(u8, const u32, int);
+extern void dbg_queue(u8, const struct usb_request*, int);
+extern void dbg_setup(u8, const struct usb_ctrlrequest*);
 extern int dwc3_debugfs_init(struct dwc3 *);
 extern void dwc3_debugfs_exit(struct dwc3 *);
 #else
+static inline void dbg_event(u8, const char*, int)
+{  }
+static inline void dbg_print(u8, const char*, int, const char*)
+{  }
+static inline void dbg_done(u8, const u32, int)
+{  }
+static inline void dbg_queue(u8, const struct usb_request*, int)
+{  }
+static inline void dbg_setup(u8, const struct usb_ctrlrequest*)
+{  }
 static inline int dwc3_debugfs_init(struct dwc3 *d)
 {  return 0;  }
 static inline void dwc3_debugfs_exit(struct dwc3 *d)
diff --git a/drivers/usb/dwc3/debugfs.c b/drivers/usb/dwc3/debugfs.c
index be4eff7..93504eb 100644
--- a/drivers/usb/dwc3/debugfs.c
+++ b/drivers/usb/dwc3/debugfs.c
@@ -36,6 +36,7 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+#include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/ptrace.h>
@@ -652,6 +653,382 @@
 	.release		= single_release,
 };
 
+static int ep_num;
+static ssize_t dwc3_store_ep_num(struct file *file, const char __user *ubuf,
+				 size_t count, loff_t *ppos)
+{
+	struct seq_file		*s = file->private_data;
+	struct dwc3		*dwc = s->private;
+	char			kbuf[10];
+	unsigned int		num, dir;
+	unsigned long		flags;
+
+	memset(kbuf, 0, 10);
+
+	if (copy_from_user(kbuf, ubuf, count > 10 ? 10 : count))
+		return -EFAULT;
+
+	if (sscanf(kbuf, "%u %u", &num, &dir) != 2)
+		return -EINVAL;
+
+	spin_lock_irqsave(&dwc->lock, flags);
+	ep_num = (num << 1) + dir;
+	spin_unlock_irqrestore(&dwc->lock, flags);
+
+	return count;
+}
+
+static int dwc3_ep_req_list_show(struct seq_file *s, void *unused)
+{
+	struct dwc3		*dwc = s->private;
+	struct dwc3_ep		*dep;
+	struct dwc3_request	*req = NULL;
+	struct list_head	*ptr = NULL;
+	unsigned long		flags;
+
+	spin_lock_irqsave(&dwc->lock, flags);
+	dep = dwc->eps[ep_num];
+
+	seq_printf(s, "%s request list: flags: 0x%x\n", dep->name, dep->flags);
+	list_for_each(ptr, &dep->request_list) {
+		req = list_entry(ptr, struct dwc3_request, list);
+
+		seq_printf(s, "req:0x%p len: %d sts: %d dma:0x%x num_sgs: %d\n",
+			req, req->request.length, req->request.status,
+			req->request.dma, req->request.num_sgs);
+	}
+	spin_unlock_irqrestore(&dwc->lock, flags);
+
+	return 0;
+}
+
+static int dwc3_ep_req_list_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, dwc3_ep_req_list_show, inode->i_private);
+}
+
+static const struct file_operations dwc3_ep_req_list_fops = {
+	.open			= dwc3_ep_req_list_open,
+	.write			= dwc3_store_ep_num,
+	.read			= seq_read,
+	.llseek			= seq_lseek,
+	.release		= single_release,
+};
+
+static int dwc3_ep_queued_req_show(struct seq_file *s, void *unused)
+{
+	struct dwc3		*dwc = s->private;
+	struct dwc3_ep		*dep;
+	struct dwc3_request	*req = NULL;
+	struct list_head	*ptr = NULL;
+	unsigned long		flags;
+
+	spin_lock_irqsave(&dwc->lock, flags);
+	dep = dwc->eps[ep_num];
+
+	seq_printf(s, "%s queued reqs to HW: flags:0x%x\n", dep->name,
+								dep->flags);
+	list_for_each(ptr, &dep->req_queued) {
+		req = list_entry(ptr, struct dwc3_request, list);
+
+		seq_printf(s, "req:0x%p len:%d sts:%d dma:%x nsg:%d trb:0x%p\n",
+			req, req->request.length, req->request.status,
+			req->request.dma, req->request.num_sgs, req->trb);
+	}
+	spin_unlock_irqrestore(&dwc->lock, flags);
+
+	return 0;
+}
+
+static int dwc3_ep_queued_req_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, dwc3_ep_queued_req_show, inode->i_private);
+}
+
+const struct file_operations dwc3_ep_req_queued_fops = {
+	.open			= dwc3_ep_queued_req_open,
+	.write			= dwc3_store_ep_num,
+	.read			= seq_read,
+	.llseek			= seq_lseek,
+	.release		= single_release,
+};
+
+static int dwc3_ep_trbs_show(struct seq_file *s, void *unused)
+{
+	struct dwc3		*dwc = s->private;
+	struct dwc3_ep		*dep;
+	struct dwc3_trb		*trb;
+	unsigned long		flags;
+	int			j;
+
+	if (!ep_num)
+		return 0;
+
+	spin_lock_irqsave(&dwc->lock, flags);
+	dep = dwc->eps[ep_num];
+
+	seq_printf(s, "%s trb pool: flags:0x%x freeslot:%d busyslot:%d\n",
+		dep->name, dep->flags, dep->free_slot, dep->busy_slot);
+	for (j = 0; j < DWC3_TRB_NUM; j++) {
+		trb = &dep->trb_pool[j];
+		seq_printf(s, "trb:0x%p bph:0x%x bpl:0x%x size:0x%x ctrl: %x\n",
+			trb, trb->bph, trb->bpl, trb->size, trb->ctrl);
+	}
+	spin_unlock_irqrestore(&dwc->lock, flags);
+
+	return 0;
+}
+
+static int dwc3_ep_trbs_list_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, dwc3_ep_trbs_show, inode->i_private);
+}
+
+const struct file_operations dwc3_ep_trb_list_fops = {
+	.open			= dwc3_ep_trbs_list_open,
+	.write			= dwc3_store_ep_num,
+	.read			= seq_read,
+	.llseek			= seq_lseek,
+	.release		= single_release,
+};
+
+static unsigned int ep_addr_rxdbg_mask;
+module_param(ep_addr_rxdbg_mask, uint, S_IRUGO | S_IWUSR);
+static unsigned int ep_addr_txdbg_mask;
+module_param(ep_addr_txdbg_mask, uint, S_IRUGO | S_IWUSR);
+
+/* Maximum debug message length */
+#define DBG_DATA_MSG   64UL
+
+/* Maximum number of messages */
+#define DBG_DATA_MAX   128UL
+
+static struct {
+	char     (buf[DBG_DATA_MAX])[DBG_DATA_MSG];   /* buffer */
+	unsigned idx;   /* index */
+	unsigned tty;   /* print to console? */
+	rwlock_t lck;   /* lock */
+} dbg_dwc3_data = {
+	.idx = 0,
+	.tty = 0,
+	.lck = __RW_LOCK_UNLOCKED(lck)
+};
+
+/**
+ * dbg_dec: decrements debug event index
+ * @idx: buffer index
+ */
+static inline void __maybe_unused dbg_dec(unsigned *idx)
+{
+	*idx = (*idx - 1) % DBG_DATA_MAX;
+}
+
+/**
+ * dbg_inc: increments debug event index
+ * @idx: buffer index
+ */
+static inline void dbg_inc(unsigned *idx)
+{
+	*idx = (*idx + 1) % DBG_DATA_MAX;
+}
+
+#define TIME_BUF_LEN  20
+/*get_timestamp - returns time of day in us */
+static char *get_timestamp(char *tbuf)
+{
+	unsigned long long t;
+	unsigned long nanosec_rem;
+
+	t = cpu_clock(smp_processor_id());
+	nanosec_rem = do_div(t, 1000000000)/1000;
+	scnprintf(tbuf, TIME_BUF_LEN, "[%5lu.%06lu] ", (unsigned long)t,
+		nanosec_rem);
+	return tbuf;
+}
+
+static int allow_dbg_print(u8 ep_num)
+{
+	int dir, num;
+
+	/* allow bus wide events */
+	if (ep_num == 0xff)
+		return 1;
+
+	dir = ep_num & 0x1;
+	num = ep_num >> 1;
+	num = 1 << num;
+
+	if (dir && (num & ep_addr_txdbg_mask))
+		return 1;
+	if (!dir && (num & ep_addr_rxdbg_mask))
+		return 1;
+
+	return 0;
+}
+
+/**
+ * dbg_print:  prints the common part of the event
+ * @addr:   endpoint address
+ * @name:   event name
+ * @status: status
+ * @extra:  extra information
+ */
+void dbg_print(u8 ep_num, const char *name, int status, const char *extra)
+{
+	unsigned long flags;
+	char tbuf[TIME_BUF_LEN];
+
+	if (!allow_dbg_print(ep_num))
+		return;
+
+	write_lock_irqsave(&dbg_dwc3_data.lck, flags);
+
+	scnprintf(dbg_dwc3_data.buf[dbg_dwc3_data.idx], DBG_DATA_MSG,
+		  "%s\t? %02X %-7.7s %4i ?\t%s\n",
+		  get_timestamp(tbuf), ep_num, name, status, extra);
+
+	dbg_inc(&dbg_dwc3_data.idx);
+
+	write_unlock_irqrestore(&dbg_dwc3_data.lck, flags);
+
+	if (dbg_dwc3_data.tty != 0)
+		pr_notice("%s\t? %02X %-7.7s %4i ?\t%s\n",
+			  get_timestamp(tbuf), ep_num, name, status, extra);
+}
+
+/**
+ * dbg_done: prints a DONE event
+ * @addr:   endpoint address
+ * @td:     transfer descriptor
+ * @status: status
+ */
+void dbg_done(u8 ep_num, const u32 count, int status)
+{
+	char msg[DBG_DATA_MSG];
+
+	if (!allow_dbg_print(ep_num))
+		return;
+
+	scnprintf(msg, sizeof(msg), "%d", count);
+	dbg_print(ep_num, "DONE", status, msg);
+}
+
+/**
+ * dbg_event: prints a generic event
+ * @addr:   endpoint address
+ * @name:   event name
+ * @status: status
+ */
+void dbg_event(u8 ep_num, const char *name, int status)
+{
+	if (!allow_dbg_print(ep_num))
+		return;
+
+	if (name != NULL)
+		dbg_print(ep_num, name, status, "");
+}
+
+/*
+ * dbg_queue: prints a QUEUE event
+ * @addr:   endpoint address
+ * @req:    USB request
+ * @status: status
+ */
+void dbg_queue(u8 ep_num, const struct usb_request *req, int status)
+{
+	char msg[DBG_DATA_MSG];
+
+	if (!allow_dbg_print(ep_num))
+		return;
+
+	if (req != NULL) {
+		scnprintf(msg, sizeof(msg),
+			  "%d %d", !req->no_interrupt, req->length);
+		dbg_print(ep_num, "QUEUE", status, msg);
+	}
+}
+
+/**
+ * dbg_setup: prints a SETUP event
+ * @addr: endpoint address
+ * @req:  setup request
+ */
+void dbg_setup(u8 ep_num, const struct usb_ctrlrequest *req)
+{
+	char msg[DBG_DATA_MSG];
+
+	if (!allow_dbg_print(ep_num))
+		return;
+
+	if (req != NULL) {
+		scnprintf(msg, sizeof(msg),
+			  "%02X %02X %04X %04X %d", req->bRequestType,
+			  req->bRequest, le16_to_cpu(req->wValue),
+			  le16_to_cpu(req->wIndex), le16_to_cpu(req->wLength));
+		dbg_print(ep_num, "SETUP", 0, msg);
+	}
+}
+
+/**
+ * store_events: configure if events are going to be also printed to console
+ *
+ */
+static ssize_t dwc3_store_events(struct file *file,
+			    const char __user *buf, size_t count, loff_t *ppos)
+{
+	unsigned tty;
+
+	if (buf == NULL) {
+		pr_err("[%s] EINVAL\n", __func__);
+		goto done;
+	}
+
+	if (sscanf(buf, "%u", &tty) != 1 || tty > 1) {
+		pr_err("<1|0>: enable|disable console log\n");
+		goto done;
+	}
+
+	dbg_dwc3_data.tty = tty;
+	pr_info("tty = %u", dbg_dwc3_data.tty);
+
+ done:
+	return count;
+}
+
+static int dwc3_gadget_data_events_show(struct seq_file *s, void *unused)
+{
+	unsigned long	flags;
+	unsigned	i;
+
+	read_lock_irqsave(&dbg_dwc3_data.lck, flags);
+
+	i = dbg_dwc3_data.idx;
+	if (strnlen(dbg_dwc3_data.buf[i], DBG_DATA_MSG))
+		seq_printf(s, "%s\n", dbg_dwc3_data.buf[i]);
+	for (dbg_inc(&i); i != dbg_dwc3_data.idx; dbg_inc(&i)) {
+		if (!strnlen(dbg_dwc3_data.buf[i], DBG_DATA_MSG))
+			continue;
+		seq_printf(s, "%s\n", dbg_dwc3_data.buf[i]);
+	}
+
+	read_unlock_irqrestore(&dbg_dwc3_data.lck, flags);
+
+	return 0;
+}
+
+static int dwc3_gadget_data_events_open(struct inode *inode, struct file *f)
+{
+	return single_open(f, dwc3_gadget_data_events_show, inode->i_private);
+}
+
+const struct file_operations dwc3_gadget_dbg_data_fops = {
+	.open			= dwc3_gadget_data_events_open,
+	.read			= seq_read,
+	.write			= dwc3_store_events,
+	.llseek			= seq_lseek,
+	.release		= single_release,
+};
+
 int __devinit dwc3_debugfs_init(struct dwc3 *dwc)
 {
 	struct dentry		*root;
@@ -694,6 +1071,33 @@
 		goto err1;
 	}
 
+	file = debugfs_create_file("trbs", S_IRUGO | S_IWUSR, root,
+			dwc, &dwc3_ep_trb_list_fops);
+	if (!file) {
+		ret = -ENOMEM;
+		goto err1;
+	}
+
+	file = debugfs_create_file("requests", S_IRUGO | S_IWUSR, root,
+			dwc, &dwc3_ep_req_list_fops);
+	if (!file) {
+		ret = -ENOMEM;
+		goto err1;
+	}
+
+	file = debugfs_create_file("queued_reqs", S_IRUGO | S_IWUSR, root,
+			dwc, &dwc3_ep_req_queued_fops);
+	if (!file) {
+		ret = -ENOMEM;
+		goto err1;
+	}
+
+	file = debugfs_create_file("events", S_IRUGO | S_IWUSR, root,
+			dwc, &dwc3_gadget_dbg_data_fops);
+	if (!file) {
+		ret = -ENOMEM;
+		goto err1;
+	}
 	return 0;
 
 err1:
diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c
index 1512513..a1d7a87 100644
--- a/drivers/usb/dwc3/ep0.c
+++ b/drivers/usb/dwc3/ep0.c
@@ -53,6 +53,7 @@
 #include "core.h"
 #include "gadget.h"
 #include "io.h"
+#include "debug.h"
 
 static void __dwc3_ep0_do_control_status(struct dwc3 *dwc, struct dwc3_ep *dep);
 static void __dwc3_ep0_do_control_data(struct dwc3 *dwc,
@@ -741,6 +742,7 @@
 		dwc->ep0_next_event = DWC3_EP0_NRDY_DATA;
 	}
 
+	dbg_setup(0x00, ctrl);
 	if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD)
 		ret = dwc3_ep0_std_request(dwc, ctrl);
 	else
@@ -849,6 +851,7 @@
 	if (status == DWC3_TRBSTS_SETUP_PENDING)
 		dev_dbg(dwc->dev, "Setup Pending received\n");
 
+	dbg_print(dep->number, "DONE", status, "STATUS");
 	dwc->ep0state = EP0_SETUP_PHASE;
 	dwc3_ep0_out_start(dwc);
 }
@@ -931,6 +934,7 @@
 				req->request.length, DWC3_TRBCTL_CONTROL_DATA);
 	}
 
+	dbg_queue(dep->number, &req->request, ret);
 	WARN_ON(ret < 0);
 }
 
@@ -948,13 +952,16 @@
 
 static void __dwc3_ep0_do_control_status(struct dwc3 *dwc, struct dwc3_ep *dep)
 {
+	int ret;
 	if (dwc->resize_fifos) {
 		dev_dbg(dwc->dev, "starting to resize fifos\n");
 		dwc3_gadget_resize_tx_fifos(dwc);
 		dwc->resize_fifos = 0;
 	}
 
-	WARN_ON(dwc3_ep0_start_control_status(dep));
+	ret = dwc3_ep0_start_control_status(dep);
+	dbg_print(dep->number, "QUEUE", ret, "STATUS");
+	WARN_ON(ret);
 }
 
 static void dwc3_ep0_do_control_status(struct dwc3 *dwc,
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 9fa1ab4..2db9eea 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -53,6 +53,7 @@
 
 #include "core.h"
 #include "gadget.h"
+#include "debug.h"
 #include "io.h"
 
 /**
@@ -276,6 +277,7 @@
 			req, dep->name, req->request.actual,
 			req->request.length, status);
 
+	dbg_done(dep->number, req->request.actual, req->request.status);
 	spin_unlock(&dwc->lock);
 	req->request.complete(&dep->endpoint, &req->request);
 	spin_lock(&dwc->lock);
@@ -690,6 +692,7 @@
 
 	spin_lock_irqsave(&dwc->lock, flags);
 	ret = __dwc3_gadget_ep_enable(dep, desc, ep->comp_desc, false);
+	dbg_event(dep->number, "ENABLE", ret);
 	spin_unlock_irqrestore(&dwc->lock, flags);
 
 	return ret;
@@ -722,6 +725,7 @@
 
 	spin_lock_irqsave(&dwc->lock, flags);
 	ret = __dwc3_gadget_ep_disable(dep);
+	dbg_event(dep->number, "DISABLE", ret);
 	spin_unlock_irqrestore(&dwc->lock, flags);
 
 	return ret;
@@ -929,6 +933,7 @@
 				if (last_one)
 					break;
 			}
+			dbg_queue(dep->number, &req->request, 0);
 		} else {
 			dma = req->request.dma;
 			length = req->request.length;
@@ -944,6 +949,7 @@
 			dwc3_prepare_one_trb(dep, req, dma, length,
 					last_one, false);
 
+			dbg_queue(dep->number, &req->request, 0);
 			if (last_one)
 				break;
 		}
@@ -985,6 +991,7 @@
 	}
 	if (!req) {
 		dep->flags |= DWC3_EP_PENDING_REQUEST;
+		dbg_event(dep->number, "NO REQ", 0);
 		return 0;
 	}
 
@@ -1057,6 +1064,7 @@
 		struct dwc3_ep *dep, u32 cur_uf)
 {
 	u32 uf;
+	int ret;
 
 	dep->current_uf = cur_uf;
 
@@ -1070,7 +1078,9 @@
 	/* 4 micro frames in the future */
 	uf = cur_uf + dep->interval * 4;
 
-	__dwc3_gadget_kick_transfer(dep, uf, 1);
+	ret = __dwc3_gadget_kick_transfer(dep, uf, 1);
+	if (ret < 0)
+		dbg_event(dep->number, "QUEUE", ret);
 }
 
 static void dwc3_gadget_start_isoc(struct dwc3 *dwc,
@@ -1156,9 +1166,11 @@
 		}
 
 		ret = __dwc3_gadget_kick_transfer(dep, 0, true);
-		if (ret && ret != -EBUSY)
+		if (ret && ret != -EBUSY) {
+			dbg_event(dep->number, "QUEUE", ret);
 			dev_dbg(dwc->dev, "%s: failed to kick transfers\n",
 					dep->name);
+		}
 	}
 
 	/*
@@ -1172,9 +1184,11 @@
 		WARN_ON_ONCE(!dep->resource_index);
 		ret = __dwc3_gadget_kick_transfer(dep, dep->resource_index,
 				false);
-		if (ret && ret != -EBUSY)
+		if (ret && ret != -EBUSY) {
+			dbg_event(dep->number, "QUEUE", ret);
 			dev_dbg(dwc->dev, "%s: failed to kick transfers\n",
 					dep->name);
+		}
 	}
 
 	return 0;
@@ -1246,6 +1260,7 @@
 	}
 
 out1:
+	dbg_event(dep->number, "DEQUEUE", 0);
 	/* giveback the request */
 	dwc3_gadget_giveback(dep, req, -ECONNRESET);
 
@@ -1303,6 +1318,7 @@
 		goto out;
 	}
 
+	dbg_event(dep->number, "HALT", value);
 	ret = __dwc3_gadget_ep_set_halt(dep, value);
 out:
 	spin_unlock_irqrestore(&dwc->lock, flags);
@@ -1317,6 +1333,7 @@
 	unsigned long			flags;
 
 	spin_lock_irqsave(&dwc->lock, flags);
+	dbg_event(dep->number, "WEDGE", 0);
 	dep->flags |= DWC3_EP_WEDGE;
 	spin_unlock_irqrestore(&dwc->lock, flags);
 
@@ -1910,6 +1927,8 @@
 					 * request in the request_list.
 					 */
 					dep->flags |= DWC3_EP_MISSED_ISOC;
+					dbg_event(dep->number, "MISSED ISOC",
+									status);
 				} else {
 					dev_err(dwc->dev, "incomplete IN transfer %s\n",
 							dep->name);
@@ -2060,6 +2079,8 @@
 			ret = __dwc3_gadget_kick_transfer(dep, 0, 1);
 			if (!ret || ret == -EBUSY)
 				return;
+			else
+				dbg_event(dep->number, "QUEUE", ret);
 
 			dev_dbg(dwc->dev, "%s: failed to kick transfers\n",
 					dep->name);
@@ -2196,6 +2217,7 @@
 	reg &= ~DWC3_DCTL_INITU2ENA;
 	dwc3_writel(dwc->regs, DWC3_DCTL, reg);
 
+	dbg_event(0xFF, "DISCONNECT", 0);
 	dwc3_disconnect_gadget(dwc);
 	dwc->start_config_issued = false;
 
@@ -2269,6 +2291,7 @@
 			dwc3_gadget_disconnect_interrupt(dwc);
 	}
 
+	dbg_event(0xFF, "BUS RST", 0);
 	/* after reset -> Default State */
 	dwc->dev_state = DWC3_DEFAULT_STATE;
 
@@ -2435,6 +2458,7 @@
 	 * implemented.
 	 */
 
+	dbg_event(0xFF, "WAKEUP", 0);
 	dwc->gadget_driver->resume(&dwc->gadget);
 }
 
@@ -2490,9 +2514,12 @@
 	}
 
 	if (next == DWC3_LINK_STATE_U0) {
-		if (dwc->link_state == DWC3_LINK_STATE_U3)
+		if (dwc->link_state == DWC3_LINK_STATE_U3) {
+			dbg_event(0xFF, "RESUME", 0);
 			dwc->gadget_driver->resume(&dwc->gadget);
+		}
 	} else if (next == DWC3_LINK_STATE_U3) {
+		dbg_event(0xFF, "SUSPEND", 0);
 		dwc->gadget_driver->suspend(&dwc->gadget);
 	}
 
@@ -2527,12 +2554,14 @@
 		dev_vdbg(dwc->dev, "Start of Periodic Frame\n");
 		break;
 	case DWC3_DEVICE_EVENT_ERRATIC_ERROR:
+		dbg_event(0xFF, "ERROR", 0);
 		dev_vdbg(dwc->dev, "Erratic Error\n");
 		break;
 	case DWC3_DEVICE_EVENT_CMD_CMPL:
 		dev_vdbg(dwc->dev, "Command Complete\n");
 		break;
 	case DWC3_DEVICE_EVENT_OVERFLOW:
+		dbg_event(0xFF, "OVERFL", 0);
 		dev_vdbg(dwc->dev, "Overflow\n");
 		/*
 		 * Controllers prior to 2.30a revision has a bug where
@@ -2559,6 +2588,7 @@
 		 * Add a warning message to indicate that this event is received
 		 * which means that event buffer might have corrupted.
 		 */
+		dbg_event(0xFF, "TSTLMP", 0);
 		if (dwc->revision < DWC3_REVISION_230A)
 			dev_warn(dwc->dev, "Vendor Device Test LMP Received\n");
 		break;
diff --git a/drivers/usb/gadget/u_ether.c b/drivers/usb/gadget/u_ether.c
index 2b8118b..2d974ab 100644
--- a/drivers/usb/gadget/u_ether.c
+++ b/drivers/usb/gadget/u_ether.c
@@ -610,11 +610,13 @@
 	unsigned long		flags;
 	struct usb_ep		*in;
 	u16			cdc_filter;
+	bool			multi_pkt_xfer = false;
 
 	spin_lock_irqsave(&dev->lock, flags);
 	if (dev->port_usb) {
 		in = dev->port_usb->in_ep;
 		cdc_filter = dev->port_usb->cdc_filter;
+		multi_pkt_xfer = dev->port_usb->multi_pkt_xfer;
 	} else {
 		in = NULL;
 		cdc_filter = 0;
@@ -627,7 +629,7 @@
 	}
 
 	/* Allocate memory for tx_reqs to support multi packet transfer */
-	if (dev->port_usb->multi_pkt_xfer && !dev->tx_req_bufsize)
+	if (multi_pkt_xfer && !dev->tx_req_bufsize)
 		alloc_tx_buffer(dev);
 
 	/* apply outgoing CDC or RNDIS filters */
@@ -690,7 +692,7 @@
 	dev->tx_skb_hold_count++;
 	spin_unlock_irqrestore(&dev->req_lock, flags);
 
-	if (dev->port_usb->multi_pkt_xfer) {
+	if (multi_pkt_xfer) {
 		memcpy(req->buf + req->length, skb->data, skb->len);
 		req->length = req->length + skb->len;
 		length = req->length;
@@ -762,7 +764,7 @@
 	}
 
 	if (retval) {
-		if (!dev->port_usb->multi_pkt_xfer)
+		if (!multi_pkt_xfer)
 			dev_kfree_skb_any(skb);
 drop:
 		dev->net->stats.tx_dropped++;