Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6fb5929e authored by Vijayavardhan Vennapusa's avatar Vijayavardhan Vennapusa
Browse files

USB: dwc3-msm: Initialize DBM ep before BAM pipe reset



On new platforms, endpoint clock gating is added for dbm endpoints
with Synopsys USB3.0 controller. This hardware feature requires
initialization of DBM endpoint before BAM pipe reset for bam2bam mode
data transfers working. Hence change sequence such that do DBM endpoint
initialization first followed by BAM pipe reset and do start transfer
as last operation.

CRs-Fixed: 965207
Change-Id: Ib5bfd1a7d258fe336a4c9924850fc9223c1c81f6
Signed-off-by: default avatarVijayavardhan Vennapusa <vvreddy@codeaurora.org>
parent b474e6d3
Loading
Loading
Loading
Loading
+107 −72
Original line number Diff line number Diff line
/* Copyright (c) 2011-2015, The Linux Foundation. All rights reserved.
/* Copyright (c) 2011-2016, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -353,6 +353,12 @@ static int usb_bam_alloc_buffer(struct usb_bam_pipe_connect *pipe_connect)
		if (pipe_connect->mem_type == OCI_MEM)
			log_event_dbg("%s: USB BAM using ocimem\n", __func__);

		if (data_buf->base) {
			log_event_err("%s: Already allocated OCI Memory\n",
								__func__);
			break;
		}

		data_buf->phys_base = pipe_connect->data_fifo_base_offset +
						pdata->usb_bam_fifo_baseaddr;
		data_buf->size = pipe_connect->data_fifo_size;
@@ -380,6 +386,13 @@ static int usb_bam_alloc_buffer(struct usb_bam_pipe_connect *pipe_connect)
		break;
	case SYSTEM_MEM:
		log_event_dbg("%s: USB BAM using system memory\n", __func__);

		if (data_buf->base) {
			log_event_err("%s: Already allocated memory\n",
								__func__);
			break;
		}

		/* BAM would use system memory, allocate FIFOs */
		data_buf->size = pipe_connect->data_fifo_size;
		/* On platforms which use CI controller, USB HW can fetch
@@ -443,6 +456,83 @@ err_exit:
	return ret;
}

int usb_bam_alloc_fifos(enum usb_ctrl cur_bam, u8 idx)
{
	int ret;
	struct usb_bam_ctx_type *ctx = &msm_usb_bam[cur_bam];
	struct usb_bam_pipe_connect *pipe_connect =
					&ctx->usb_bam_connections[idx];

	ret = usb_bam_alloc_buffer(pipe_connect);
	if (ret) {
		log_event_err("%s(): Error(%d) allocating buffer\n",
				__func__, ret);
		return ret;
	}
	return 0;
}

int usb_bam_free_fifos(enum usb_ctrl cur_bam, u8 idx)
{
	struct usb_bam_ctx_type *ctx = &msm_usb_bam[cur_bam];
	struct usb_bam_pipe_connect *pipe_connect =
				&ctx->usb_bam_connections[idx];
	struct sps_connect *sps_connection =
				&ctx->usb_bam_sps.sps_connections[idx];

	pr_debug("%s(): data size:%x desc size:%x\n",
			__func__, sps_connection->data.size,
			sps_connection->desc.size);

	switch (pipe_connect->mem_type) {
	case SYSTEM_MEM:
		log_event_dbg("%s: Freeing system memory used by PIPE\n",
				__func__);
		if (sps_connection->data.phys_base) {
			if (cur_bam == CI_CTRL)
				dma_free_coherent(&ctx->usb_bam_pdev->dev,
					(sps_connection->data.size +
						DATA_FIFO_EXTRA_MEM_ALLOC_SIZE),
					sps_connection->data.base,
					sps_connection->data.phys_base);
			else
				dma_free_coherent(&ctx->usb_bam_pdev->dev,
					sps_connection->data.size,
					sps_connection->data.base,
					sps_connection->data.phys_base);
			sps_connection->data.phys_base = 0;
			pipe_connect->data_mem_buf.base = NULL;
		}
		if (sps_connection->desc.phys_base) {
			dma_free_coherent(&ctx->usb_bam_pdev->dev,
					sps_connection->desc.size,
					sps_connection->desc.base,
					sps_connection->desc.phys_base);
			sps_connection->desc.phys_base = 0;
			pipe_connect->desc_mem_buf.base = NULL;
		}
		break;
	case OCI_MEM:
		log_event_dbg("Freeing oci memory used by BAM PIPE\n");
		if (sps_connection->data.base) {
			iounmap(sps_connection->data.base);
			sps_connection->data.base = NULL;
			pipe_connect->data_mem_buf.base = NULL;
		}
		if (sps_connection->desc.base) {
			iounmap(sps_connection->desc.base);
			sps_connection->desc.base = NULL;
			pipe_connect->desc_mem_buf.base = NULL;
		}
		break;
	case SPS_PIPE_MEM:
		log_event_dbg("%s: nothing to be be\n", __func__);
		break;
	}

	return 0;
}

static int connect_pipe(enum usb_ctrl cur_bam, u8 idx, u32 *usb_pipe_idx)
{
	int ret;
@@ -493,13 +583,6 @@ static int connect_pipe(enum usb_ctrl cur_bam, u8 idx, u32 *usb_pipe_idx)
		*usb_pipe_idx = pipe_connect->dst_pipe_index;
	}

	ret = usb_bam_alloc_buffer(pipe_connect);
	if (ret) {
		log_event_err("%s(): Error(%d) allocating buffer.\n",
				__func__, ret);
		return ret;
	}

	sps_connection->data = *data_buf;
	sps_connection->desc = *desc_buf;
	sps_connection->event_thresh = 16;
@@ -639,13 +722,6 @@ static int connect_pipe_bam2bam_ipa(enum usb_ctrl cur_bam, u8 idx,
	ipa_in_params.skip_ep_cfg = ipa_params->skip_ep_cfg;
	ipa_in_params.keep_ipa_awake = ipa_params->keep_ipa_awake;

	ret = usb_bam_alloc_buffer(pipe_connect);
	if (ret) {
		log_event_err("%s(): Error(%d) allocating buffer\n",
				__func__, ret);
		return ret;
	}

	ipa_in_params.desc = pipe_connect->desc_mem_buf;
	ipa_in_params.data = pipe_connect->data_mem_buf;

@@ -731,8 +807,6 @@ disconnect_ipa:
static int disconnect_pipe(enum usb_ctrl cur_bam, u8 idx)
{
	struct usb_bam_ctx_type *ctx = &msm_usb_bam[cur_bam];
	struct usb_bam_pipe_connect *pipe_connect =
				&ctx->usb_bam_connections[idx];
	struct sps_pipe *pipe = ctx->usb_bam_sps.sps_pipes[idx];
	struct sps_connect *sps_connection =
				&ctx->usb_bam_sps.sps_connections[idx];
@@ -740,46 +814,8 @@ static int disconnect_pipe(enum usb_ctrl cur_bam, u8 idx)
	sps_disconnect(pipe);
	sps_free_endpoint(pipe);
	ctx->usb_bam_sps.sps_pipes[idx] = NULL;


	pr_debug("%s(): data size:%x desc size:%x\n",
			__func__, sps_connection->data.size,
			sps_connection->desc.size);

	switch (pipe_connect->mem_type) {
	case SYSTEM_MEM:
		log_event_dbg("%s: Freeing system memory used by PIPE\n",
				__func__);
		if (sps_connection->data.phys_base) {
			if (cur_bam == CI_CTRL)
				dma_free_coherent(&ctx->usb_bam_pdev->dev,
					(sps_connection->data.size +
						DATA_FIFO_EXTRA_MEM_ALLOC_SIZE),
					sps_connection->data.base,
					sps_connection->data.phys_base);
			else
				dma_free_coherent(&ctx->usb_bam_pdev->dev,
					sps_connection->data.size,
					sps_connection->data.base,
					sps_connection->data.phys_base);
		}
		if (sps_connection->desc.phys_base)
			dma_free_coherent(&ctx->usb_bam_pdev->dev,
					sps_connection->desc.size,
					sps_connection->desc.base,
					sps_connection->desc.phys_base);
		break;
	case OCI_MEM:
		log_event_dbg("Freeing oci memory used by BAM PIPE\n");
		iounmap(sps_connection->data.base);
		iounmap(sps_connection->desc.base);
		break;
	case SPS_PIPE_MEM:
		log_event_dbg("%s: nothing to be be\n", __func__);
		break;
	}

	sps_connection->options &= ~SPS_O_AUTO_ENABLE;

	return 0;
}

@@ -3273,26 +3309,19 @@ bool usb_bam_get_prod_granted(enum usb_ctrl bam_type, u8 idx)
EXPORT_SYMBOL(usb_bam_get_prod_granted);

int get_bam2bam_connection_info(enum usb_ctrl bam_type, u8 idx,
	unsigned long *usb_bam_handle, u32 *usb_bam_pipe_idx,
	u32 *peer_pipe_idx, struct sps_mem_buffer *desc_fifo,
	u32 *usb_bam_pipe_idx, struct sps_mem_buffer *desc_fifo,
	struct sps_mem_buffer *data_fifo, enum usb_pipe_mem_type *mem_type)
{
	struct usb_bam_ctx_type *ctx = &msm_usb_bam[bam_type];
	struct usb_bam_pipe_connect *pipe_connect =
			&ctx->usb_bam_connections[idx];
	enum usb_bam_pipe_dir dir = pipe_connect->dir;
	struct sps_connect *sps_connection =
			&ctx->usb_bam_sps.sps_connections[idx];

	if (dir == USB_TO_PEER_PERIPHERAL) {
		*usb_bam_handle = sps_connection->source;
		*usb_bam_pipe_idx = sps_connection->src_pipe_index;
		*peer_pipe_idx = sps_connection->dest_pipe_index;
	} else {
		*usb_bam_handle = sps_connection->destination;
		*usb_bam_pipe_idx = sps_connection->dest_pipe_index;
		*peer_pipe_idx = sps_connection->src_pipe_index;
	}
	if (dir == USB_TO_PEER_PERIPHERAL)
		*usb_bam_pipe_idx = pipe_connect->src_pipe_index;
	else
		*usb_bam_pipe_idx = pipe_connect->dst_pipe_index;

	if (data_fifo)
		memcpy(data_fifo, &pipe_connect->data_mem_buf,
		sizeof(struct sps_mem_buffer));
@@ -3312,15 +3341,21 @@ int get_qdss_bam_connection_info(unsigned long *usb_bam_handle,
	enum usb_pipe_mem_type *mem_type)
{
	u8 idx;
	struct usb_bam_ctx_type *ctx = &msm_usb_bam[qdss_usb_bam_type];
	struct sps_connect *sps_connection;

	/* QDSS uses only one pipe */
	idx = usb_bam_get_connection_idx(qdss_usb_bam_type, QDSS_P_BAM,
		PEER_PERIPHERAL_TO_USB, USB_BAM_DEVICE, 0);

	get_bam2bam_connection_info(qdss_usb_bam_type, idx, usb_bam_handle,
			usb_bam_pipe_idx, peer_pipe_idx,
	get_bam2bam_connection_info(qdss_usb_bam_type, idx, usb_bam_pipe_idx,
						desc_fifo, data_fifo, mem_type);


	sps_connection = &ctx->usb_bam_sps.sps_connections[idx];
	*usb_bam_handle = sps_connection->destination;
	*peer_pipe_idx = sps_connection->src_pipe_index;

	return 0;
}
EXPORT_SYMBOL(get_qdss_bam_connection_info);
+3 −19
Original line number Diff line number Diff line
/*
 * Copyright (c) 2012-2015, The Linux Foundation. All rights reserved.
 * Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -312,9 +312,6 @@ int dbm_ep_config(struct dbm *dbm, u8 usb_ep, u8 bam_pipe, bool producer,
		return -ENODEV;
	}

	/* First, reset the dbm endpoint */
	ep_soft_reset(dbm, dbm_ep, 0);

	/* Set ioc bit for dbm_ep if needed */
	msm_dbm_write_reg_field(dbm, DBM_DBG_CNFG,
		DBM_ENABLE_IOC_MASK & 1 << dbm_ep, ioc ? 1 : 0);
@@ -391,23 +388,10 @@ int dbm_ep_unconfig(struct dbm *dbm, u8 usb_ep)
	data &= (~0x1);
	msm_dbm_write_ep_reg(dbm, DBM_EP_CFG, dbm_ep, data);

	/* Reset the dbm endpoint */
	ep_soft_reset(dbm, dbm_ep, true);
	/*
	 * The necessary delay between asserting and deasserting the dbm ep
	 * reset is based on the number of active endpoints. If there is more
	 * than one endpoint, a 1 msec delay is required. Otherwise, a shorter
	 * delay will suffice.
	 *
	 * As this function can be called in atomic context, sleeping variants
	 * for delay are not possible - albeit a 1ms delay.
	 * ep_soft_reset is not required during disconnect as pipe reset on
	 * next connect will take care of the same.
	 */
	if (dbm_get_num_of_eps_configured(dbm) > 1)
		udelay(1000);
	else
		udelay(10);
	ep_soft_reset(dbm, dbm_ep, false);

	return 0;
}

+26 −25
Original line number Diff line number Diff line
@@ -647,11 +647,6 @@ static int dwc3_msm_ep_queue(struct usb_ep *ep,
	struct dwc3_msm_req_complete *req_complete;
	unsigned long flags;
	int ret = 0, size;
	u8 bam_pipe;
	bool producer;
	bool disable_wb;
	bool internal_mem;
	bool ioc;
	bool superspeed;

	if (!(request->udc_priv & MSM_SPS_MODE)) {
@@ -710,23 +705,6 @@ static int dwc3_msm_ep_queue(struct usb_ep *ep,
	list_add_tail(&req_complete->list_item, &mdwc->req_complete_list);
	request->complete = dwc3_msm_req_complete_func;

	/*
	 * Configure the DBM endpoint
	 */
	bam_pipe = request->udc_priv & MSM_PIPE_ID_MASK;
	producer = ((request->udc_priv & MSM_PRODUCER) ? true : false);
	disable_wb = ((request->udc_priv & MSM_DISABLE_WB) ? true : false);
	internal_mem = ((request->udc_priv & MSM_INTERNAL_MEM) ? true : false);
	ioc = ((request->udc_priv & MSM_ETD_IOC) ? true : false);

	ret = dbm_ep_config(mdwc->dbm, dep->number, bam_pipe, producer,
				disable_wb, internal_mem, ioc);
	if (ret < 0) {
		dev_err(mdwc->dev,
			"error %d after calling dbm_ep_config\n", ret);
		return ret;
	}

	dev_vdbg(dwc->dev, "%s: queing request %p to ep %s length %d\n",
			__func__, request, ep->name, request->length);
	size = dwc3_msm_read_reg(mdwc->base, DWC3_GEVNTSIZ(0));
@@ -1353,12 +1331,19 @@ static int dwc3_msm_gsi_ep_op(struct usb_ep *ep,
 *
 * @return int - 0 on success, negetive on error.
 */
int msm_ep_config(struct usb_ep *ep)
int msm_ep_config(struct usb_ep *ep, struct usb_request *request,
							gfp_t gfp_flags)
{
	struct dwc3_ep *dep = to_dwc3_ep(ep);
	struct dwc3 *dwc = dep->dwc;
	struct dwc3_msm *mdwc = dev_get_drvdata(dwc->dev->parent);
	struct usb_ep_ops *new_ep_ops;
	int ret = 0;
	u8 bam_pipe;
	bool producer;
	bool disable_wb;
	bool internal_mem;
	bool ioc;


	/* Save original ep ops for future restore*/
@@ -1384,9 +1369,25 @@ int msm_ep_config(struct usb_ep *ep)
	ep->ops = new_ep_ops;

	/*
	 * Do HERE more usb endpoint configurations
	 * which are specific to MSM.
	 * Configure the DBM endpoint if required.
	 */
	if (mdwc->dbm) {
		bam_pipe = request->udc_priv & MSM_PIPE_ID_MASK;
		producer = ((request->udc_priv & MSM_PRODUCER) ? true : false);
		disable_wb = ((request->udc_priv & MSM_DISABLE_WB) ?
								true : false);
		internal_mem = ((request->udc_priv & MSM_INTERNAL_MEM) ?
								true : false);
		ioc = ((request->udc_priv & MSM_ETD_IOC) ? true : false);

		ret = dbm_ep_config(mdwc->dbm, dep->number, bam_pipe, producer,
					disable_wb, internal_mem, ioc);
		if (ret < 0) {
			dev_err(mdwc->dev,
				"error %d after calling dbm_ep_config\n", ret);
			return ret;
		}
	}

	return 0;
}
+2 −2
Original line number Diff line number Diff line
@@ -2316,7 +2316,7 @@ skip_string_id_alloc:
		if (!ep)
			goto fail;
		gsi->d_port.in_ep = ep;
		msm_ep_config(gsi->d_port.in_ep);
		msm_ep_config(gsi->d_port.in_ep, NULL, GFP_ATOMIC);
		ep->driver_data = cdev;	/* claim */
	}

@@ -2326,7 +2326,7 @@ skip_string_id_alloc:
		if (!ep)
			goto fail;
		gsi->d_port.out_ep = ep;
		msm_ep_config(gsi->d_port.out_ep);
		msm_ep_config(gsi->d_port.out_ep, NULL, GFP_ATOMIC);
		ep->driver_data = cdev;	/* claim */
	}

+1 −9
Original line number Diff line number Diff line
/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved.
/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -1217,14 +1217,6 @@ static int mbim_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
						mbim->bam_port.out);
			break;
		case USB_GADGET_XPORT_BAM2BAM_IPA:
			if (gadget_is_dwc3(cdev->gadget)) {
				if (msm_ep_config(mbim->bam_port.in) ||
					msm_ep_config(mbim->bam_port.out)) {
					pr_err("%s: ep_config failed\n",
							__func__);
					goto fail;
				}
			}
			ret = bam_data_connect(&mbim->bam_port,
				mbim->xport, mbim->port_num,
				USB_FUNC_MBIM);
Loading