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

Commit 42e87d6b authored by Mayank Rana's avatar Mayank Rana
Browse files

USB: gsi: Use dma_get_sgtable() to update USB TRB ring and data buffer



IOVA address shall be contiguous in memory but physical address is
not guaranteed to be contiguous when USB SMMU s1 is enabled. Linux IPA
driver needs to use physical address to map it into its own context
bank if IPA SMMU s1 is enabled. Hence this change updates physical and
IOVA address related to USB TRB ring and its data buffer to Linux IPA
driver using dma_get_sgtable() API.

Change-Id: I7caef18903291e9a186dce691b64f387bf7f717e
Signed-off-by: default avatarMayank Rana <mrana@codeaurora.org>
parent 1f5fdfe9
Loading
Loading
Loading
Loading
+23 −4
Original line number Diff line number Diff line
@@ -1050,6 +1050,8 @@ static int gsi_prepare_trbs(struct usb_ep *ep, struct usb_gsi_request *req)
	struct dwc3_trb *trb;
	int num_trbs = (dep->direction) ? (2 * (req->num_bufs) + 2)
					: (req->num_bufs + 2);
	struct scatterlist *sg;
	struct sg_table *sgt;

	dep->trb_pool = dma_zalloc_coherent(dwc->sysdev,
				num_trbs * sizeof(struct dwc3_trb),
@@ -1062,6 +1064,19 @@ static int gsi_prepare_trbs(struct usb_ep *ep, struct usb_gsi_request *req)
	}

	dep->num_trbs = num_trbs;
	dma_get_sgtable(dwc->sysdev, &req->sgt_trb_xfer_ring, dep->trb_pool,
		dep->trb_pool_dma, num_trbs * sizeof(struct dwc3_trb));

	sgt = &req->sgt_trb_xfer_ring;
	dev_dbg(dwc->dev, "%s(): trb_pool:%pK trb_pool_dma:%lx\n",
		__func__, dep->trb_pool, (unsigned long)dep->trb_pool_dma);

	for_each_sg(sgt->sgl, sg, sgt->nents, i)
		dev_dbg(dwc->dev,
			"%i: page_link:%lx offset:%x length:%x address:%lx\n",
			i, sg->page_link, sg->offset, sg->length,
			(unsigned long)sg->dma_address);

	/* IN direction */
	if (dep->direction) {
		for (i = 0; i < num_trbs ; i++) {
@@ -1127,11 +1142,13 @@ static int gsi_prepare_trbs(struct usb_ep *ep, struct usb_gsi_request *req)
		}
	}

	pr_debug("%s: Initialized TRB Ring for %s\n", __func__, dep->name);
	dev_dbg(dwc->dev, "%s: Initialized TRB Ring for %s\n",
					__func__, dep->name);
	trb = &dep->trb_pool[0];
	if (trb) {
		for (i = 0; i < num_trbs; i++) {
			pr_debug("TRB(%d): ADDRESS:%lx bpl:%x bph:%x size:%x ctrl:%x\n",
			dev_dbg(dwc->dev,
				"TRB %d: ADDR:%lx bpl:%x bph:%x sz:%x ctl:%x\n",
				i, (unsigned long)dwc3_trb_dma_offset(dep,
				&dep->trb_pool[i]), trb->bpl, trb->bph,
				trb->size, trb->ctrl);
@@ -1148,7 +1165,7 @@ static int gsi_prepare_trbs(struct usb_ep *ep, struct usb_gsi_request *req)
 * @usb_ep - pointer to usb_ep instance.
 *
 */
static void gsi_free_trbs(struct usb_ep *ep)
static void gsi_free_trbs(struct usb_ep *ep, struct usb_gsi_request *req)
{
	struct dwc3_ep *dep = to_dwc3_ep(ep);
	struct dwc3 *dwc = dep->dwc;
@@ -1165,6 +1182,7 @@ static void gsi_free_trbs(struct usb_ep *ep)
		dep->trb_pool = NULL;
		dep->trb_pool_dma = 0;
	}
	sg_free_table(&req->sgt_trb_xfer_ring);
}
/**
 * Configures GSI EPs. For GSI EPs we need to set interrupter numbers.
@@ -1354,7 +1372,8 @@ static int dwc3_msm_gsi_ep_op(struct usb_ep *ep,
		break;
	case GSI_EP_OP_FREE_TRBS:
		dev_dbg(mdwc->dev, "EP_OP_FREE_TRBS for %s\n", ep->name);
		gsi_free_trbs(ep);
		request = (struct usb_gsi_request *)op_data;
		gsi_free_trbs(ep, request);
		break;
	case GSI_EP_OP_CONFIG:
		request = (struct usb_gsi_request *)op_data;
+27 −2
Original line number Diff line number Diff line
@@ -314,6 +314,10 @@ static int ipa_connect_channels(struct gsi_data_port *d_port)
	in_params->data_buff_base_len = d_port->in_request.buf_len *
					d_port->in_request.num_bufs;
	in_params->data_buff_base_addr_iova = d_port->in_request.dma;
	in_params->sgt_xfer_rings = &d_port->in_request.sgt_trb_xfer_ring;
	in_params->sgt_data_buff = &d_port->in_request.sgt_data_buff;
	log_event_dbg("%s(): IN: sgt_xfer_rings:%pK sgt_data_buff:%pK\n",
		__func__, in_params->sgt_xfer_rings, in_params->sgt_data_buff);
	in_params->xfer_scratch.const_buffer_size =
		gsi_channel_info.const_buffer_size;
	in_params->xfer_scratch.depcmd_low_addr =
@@ -351,6 +355,13 @@ static int ipa_connect_channels(struct gsi_data_port *d_port)
			d_port->out_request.num_bufs;
		out_params->data_buff_base_addr_iova =
			d_port->out_request.dma;
		out_params->sgt_xfer_rings =
			&d_port->out_request.sgt_trb_xfer_ring;
		out_params->sgt_data_buff = &d_port->out_request.sgt_data_buff;
		log_event_dbg("%s(): OUT: sgt_xfer_rings:%pK sgt_data_buff:%pK\n",
			__func__, out_params->sgt_xfer_rings,
			out_params->sgt_data_buff);

		out_params->xfer_scratch.last_trb_addr_iova =
			gsi_channel_info.last_trb_addr;
		out_params->xfer_scratch.const_buffer_size =
@@ -504,10 +515,12 @@ static void ipa_disconnect_work_handler(struct gsi_data_port *d_port)
	gsi->d_port.in_channel_handle = -EINVAL;
	gsi->d_port.out_channel_handle = -EINVAL;

	usb_gsi_ep_op(gsi->d_port.in_ep, NULL, GSI_EP_OP_FREE_TRBS);
	usb_gsi_ep_op(gsi->d_port.in_ep, &gsi->d_port.in_request,
							GSI_EP_OP_FREE_TRBS);

	if (gsi->d_port.out_ep)
		usb_gsi_ep_op(gsi->d_port.out_ep, NULL, GSI_EP_OP_FREE_TRBS);
		usb_gsi_ep_op(gsi->d_port.out_ep, &gsi->d_port.out_request,
							GSI_EP_OP_FREE_TRBS);

	/* free buffers allocated with each TRB */
	gsi_free_trb_buffer(gsi);
@@ -1966,6 +1979,11 @@ static int gsi_alloc_trb_buffer(struct f_gsi *gsi)
			ret = -ENOMEM;
			goto fail1;
		}

		dma_get_sgtable(dev->parent,
			&gsi->d_port.in_request.sgt_data_buff,
			gsi->d_port.in_request.buf_base_addr,
			gsi->d_port.in_request.dma, len_in);
	}

	if (gsi->d_port.out_ep && !gsi->d_port.out_request.buf_base_addr) {
@@ -1985,6 +2003,11 @@ static int gsi_alloc_trb_buffer(struct f_gsi *gsi)
			ret = -ENOMEM;
			goto fail;
		}

		dma_get_sgtable(dev->parent,
			&gsi->d_port.out_request.sgt_data_buff,
			gsi->d_port.out_request.buf_base_addr,
			gsi->d_port.out_request.dma, len_out);
	}

	log_event_dbg("finished allocating trb's buffer\n");
@@ -2015,6 +2038,7 @@ static void gsi_free_trb_buffer(struct f_gsi *gsi)
			gsi->d_port.out_request.buf_base_addr,
			gsi->d_port.out_request.dma);
		gsi->d_port.out_request.buf_base_addr = NULL;
		sg_free_table(&gsi->d_port.out_request.sgt_data_buff);
	}

	if (gsi->d_port.in_ep &&
@@ -2025,6 +2049,7 @@ static void gsi_free_trb_buffer(struct f_gsi *gsi)
			gsi->d_port.in_request.buf_base_addr,
			gsi->d_port.in_request.dma);
		gsi->d_port.in_request.buf_base_addr = NULL;
		sg_free_table(&gsi->d_port.in_request.sgt_data_buff);
	}
}

+4 −0
Original line number Diff line number Diff line
@@ -83,6 +83,8 @@ enum gsi_ep_op {
 * @db_reg_phs_addr_lsb: IPA channel doorbell register's physical address LSB
 * @mapped_db_reg_phs_addr_lsb: doorbell LSB IOVA address mapped with IOMMU
 * @db_reg_phs_addr_msb: IPA channel doorbell register's physical address MSB
 * @sgt_trb_xfer_ring: USB TRB ring related sgtable entries
 * @sgt_data_buff: Data buffer related sgtable entries
 */
struct usb_gsi_request {
	void *buf_base_addr;
@@ -92,6 +94,8 @@ struct usb_gsi_request {
	u32 db_reg_phs_addr_lsb;
	dma_addr_t mapped_db_reg_phs_addr_lsb;
	u32 db_reg_phs_addr_msb;
	struct sg_table sgt_trb_xfer_ring;
	struct sg_table sgt_data_buff;
};

/*