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

Commit c5a53f9a authored by qctecmdr's avatar qctecmdr Committed by Gerrit - the friendly Code Review server
Browse files

Merge "usb: gadget: f_gsi: Add support to enable/disable using TCM MEM"

parents e4c91ca6 99e27d7d
Loading
Loading
Loading
Loading
+116 −24
Original line number Diff line number Diff line
@@ -1447,6 +1447,112 @@ static int gsi_updatexfer_for_ep(struct usb_ep *ep,
	return ret;
}

#define TCM_BUF_SIZE	(16 * 1024)
#define TCM_BUF_NUM	8
#define TCM_MEM_REQ	(TCM_BUF_SIZE * TCM_BUF_NUM)

/* Using IOVA base address at end of USB IOVA address */
#define TCM_IOVA_BASE	0x9ffe0000
static void gsi_free_data_buffers(struct usb_ep *ep,
			struct usb_gsi_request *req)
{
	struct dwc3_ep *dep = to_dwc3_ep(ep);
	struct dwc3 *dwc = dep->dwc;

	if (req->tcm_mem) {
		dbg_log_string("free tcm based buffer for ep:%s\n", dep->name);
		iommu_unmap(iommu_get_domain_for_dev(dwc->sysdev),
				TCM_IOVA_BASE, TCM_MEM_REQ);
		llcc_tcm_deactivate(req->tcm_mem);
		req->tcm_mem = NULL;
		req->dma = 0;
	} else {
		dma_free_coherent(dwc->sysdev,
			req->buf_len * req->num_bufs,
			req->buf_base_addr, req->dma);
	}
	req->buf_base_addr = NULL;
	sg_free_table(&req->sgt_data_buff);
}

static int gsi_allocate_data_buffers(struct usb_ep *ep,
			struct usb_gsi_request *req)
{
	size_t len = 0;
	int ret = 0;
	struct dwc3_ep *dep = to_dwc3_ep(ep);
	struct dwc3 *dwc = dep->dwc;
	struct iommu_domain *usb_domain = NULL;

	/* Check need of using tcm for IN endpoint only */
	if (!(req->use_tcm_mem && dep->direction))
		goto normal_alloc;

	usb_domain = iommu_get_domain_for_dev(dwc->sysdev);
	if (usb_domain == NULL) {
		dev_err(dwc->dev, "No USB IOMMU domain\n");
		goto normal_alloc;
	}

	/* Validate USB IOVA range with TCM IOVA base */
	if (usb_domain->geometry.aperture_start <= TCM_IOVA_BASE &&
		usb_domain->geometry.aperture_end > TCM_IOVA_BASE) {
		dev_err(dwc->dev, "overlap IOVA: TCM:%x USB:(%x-%x)\n",
				TCM_IOVA_BASE,
				usb_domain->geometry.aperture_start,
				usb_domain->geometry.aperture_end);
		goto normal_alloc;
	}

	/* Check availability of TCM memory */
	req->tcm_mem = llcc_tcm_activate();
	if (IS_ERR_OR_NULL(req->tcm_mem)) {
		dev_err(dwc->dev, "can't use tcm_mem ep:%s err:%ld\n",
				dep->name, PTR_ERR(req->tcm_mem));
		req->tcm_mem = NULL;
		goto normal_alloc;
	}

	if (req->tcm_mem->mem_size < TCM_MEM_REQ) {
		dev_err(dwc->dev, "err:tcm_mem: req sz:(%d) > avail_sz(%d)\n",
				TCM_MEM_REQ, req->tcm_mem->mem_size);
		llcc_tcm_deactivate(req->tcm_mem);
		req->tcm_mem = NULL;
		goto normal_alloc;
	}

	len = TCM_MEM_REQ;
	ret = iommu_map(usb_domain, TCM_IOVA_BASE, req->tcm_mem->phys_addr, len,
			IOMMU_READ | IOMMU_WRITE | IOMMU_NOEXEC);
	if (ret) {
		dev_err(dwc->dev, "%s: can't map TCM mem, using DDR\n",
				dep->name);
		llcc_tcm_deactivate(req->tcm_mem);
		req->tcm_mem = NULL;
		goto normal_alloc;
	}

	req->buf_base_addr = (void __force *)req->tcm_mem->virt_addr;
	req->buf_len = TCM_BUF_SIZE;
	req->num_bufs = TCM_BUF_NUM;
	req->dma = TCM_IOVA_BASE;
	goto fill_sgtable;

normal_alloc:
	len = req->buf_len * req->num_bufs;
	req->buf_base_addr = dma_alloc_coherent(dwc->sysdev, len,
			&req->dma, GFP_KERNEL);
	if (!req->buf_base_addr)
		return -ENOMEM;

fill_sgtable:
	dma_get_sgtable(dwc->sysdev, &req->sgt_data_buff,
			req->buf_base_addr, req->dma, len);
	dbg_log_string("alloc buffer for ep:%s use_tcm_mem:%d mem_type:%s\n",
		dep->name, req->use_tcm_mem, req->tcm_mem ? "TCM" : "DDR");
	return 0;
}

/**
 * Allocates Buffers and TRBs. Configures TRBs for GSI EPs.
 *
@@ -1457,39 +1563,30 @@ static int gsi_updatexfer_for_ep(struct usb_ep *ep,
 */
static int gsi_prepare_trbs(struct usb_ep *ep, struct usb_gsi_request *req)
{
	int i = 0;
	size_t len;
	int i = 0, ret;
	dma_addr_t buffer_addr;
	dma_addr_t trb0_dma;
	struct dwc3_ep *dep = to_dwc3_ep(ep);
	struct dwc3		*dwc = dep->dwc;
	struct dwc3_trb *trb;
	int num_trbs = (dep->direction) ? (2 * (req->num_bufs) + 2)
					: (req->num_bufs + 2);
	int num_trbs;
	struct scatterlist *sg;
	struct sg_table *sgt;

	/* Allocate TRB buffers */

	len = req->buf_len * req->num_bufs;
	req->buf_base_addr = dma_alloc_coherent(dwc->sysdev, len, &req->dma,
					GFP_KERNEL);
	if (!req->buf_base_addr) {
		dev_err(dwc->dev, "buf_base_addr allocate failed %s\n",
	ret = gsi_allocate_data_buffers(ep, req);
	if (ret) {
		dev_err(dep->dwc->dev, "failed to alloc TRB buffer for %s\n",
				dep->name);
		return -ENOMEM;
		return ret;
	}

	dma_get_sgtable(dwc->sysdev, &req->sgt_data_buff, req->buf_base_addr,
			req->dma, len);

	buffer_addr = req->dma;

	/* Allocate and configure TRBs */
	num_trbs = (dep->direction) ? (2 * (req->num_bufs) + 2)
					: (req->num_bufs + 2);
	dep->trb_pool = dma_alloc_coherent(dwc->sysdev,
				num_trbs * sizeof(struct dwc3_trb),
				&dep->trb_pool_dma, GFP_KERNEL);

	if (!dep->trb_pool) {
		dev_err(dep->dwc->dev, "failed to alloc trb dma pool for %s\n",
				dep->name);
@@ -1564,9 +1661,7 @@ static int gsi_prepare_trbs(struct usb_ep *ep, struct usb_gsi_request *req)
	return 0;

free_trb_buffer:
	dma_free_coherent(dwc->sysdev, len, req->buf_base_addr, req->dma);
	req->buf_base_addr = NULL;
	sg_free_table(&req->sgt_data_buff);
	gsi_free_data_buffers(ep, req);
	return -ENOMEM;
}

@@ -1596,10 +1691,7 @@ static void gsi_free_trbs(struct usb_ep *ep, struct usb_gsi_request *req)
	sg_free_table(&req->sgt_trb_xfer_ring);

	/* free TRB buffers */
	dma_free_coherent(dwc->sysdev, req->buf_len * req->num_bufs,
		req->buf_base_addr, req->dma);
	req->buf_base_addr = NULL;
	sg_free_table(&req->sgt_data_buff);
	gsi_free_data_buffers(ep, req);
}
/**
 * Configures GSI EPs. For GSI EPs we need to set interrupter numbers.
+43 −2
Original line number Diff line number Diff line
@@ -501,8 +501,8 @@ static int ipa_connect_channels(struct gsi_data_port *d_port)
	struct ipa_req_chan_out_params ipa_in_channel_out_params;
	struct ipa_req_chan_out_params ipa_out_channel_out_params;

	log_event_dbg("IN: num_bufs:=%zu, buf_len=%zu\n",
		d_port->in_request.num_bufs, d_port->in_request.buf_len);
	if (gsi->prot_id == IPA_USB_RMNET)
		d_port->in_request.use_tcm_mem = gsi->rmnet_use_tcm_mem;

	ret = usb_gsi_ep_op(d_port->in_ep, &d_port->in_request,
			GSI_EP_OP_PREPARE_TRBS);
@@ -512,6 +512,9 @@ static int ipa_connect_channels(struct gsi_data_port *d_port)
		return ret;
	}

	log_event_dbg("IN: num_bufs:=%zu, buf_len=%zu\n",
		d_port->in_request.num_bufs, d_port->in_request.buf_len);

	ret = usb_gsi_ep_op(d_port->in_ep, &d_port->in_request,
			GSI_EP_OP_STARTXFER);
	if (ret) {
@@ -3797,6 +3800,40 @@ static struct config_item_type gsi_func_ecm_type = {
	.ct_owner	= THIS_MODULE,
};

static ssize_t gsi_rmnet_use_tcm_mem_show(struct config_item *item, char *page)
{
	struct f_gsi *gsi = to_gsi_opts(item)->gsi;

	return scnprintf(page, PAGE_SIZE, "%s\n",
			gsi->rmnet_use_tcm_mem ? "Enabled" : "Disabled");
}

static ssize_t gsi_rmnet_use_tcm_mem_store(struct config_item *item,
			const char *page, size_t len)
{
	struct f_gsi *gsi = to_gsi_opts(item)->gsi;
	bool enable;

	if (kstrtobool(page, &enable))
		return -EINVAL;

	gsi->rmnet_use_tcm_mem = enable;
	return len;
}
CONFIGFS_ATTR(gsi_, rmnet_use_tcm_mem);

static struct configfs_attribute *gsi_rmnet_attrs[] = {
	&gsi_attr_info,
	&gsi_attr_rmnet_use_tcm_mem,
	NULL,
};

static struct config_item_type gsi_func_rmnet_type = {
	.ct_item_ops	= &gsi_item_ops,
	.ct_attrs	= gsi_rmnet_attrs,
	.ct_owner	= THIS_MODULE,
};

static void gsi_inst_clean(struct gsi_opts *opts)
{
	if (opts->gsi->c_port.cdev.dev) {
@@ -3858,6 +3895,10 @@ static int gsi_set_inst_name(struct usb_function_instance *fi,
	}
	mutex_unlock(&inst_status[prot_id].gsi_lock);

	if (prot_id == IPA_USB_RMNET)
		config_group_init_type_name(&opts->func_inst.group,
						fi->group.cg_item.ci_name,
						&gsi_func_rmnet_type);
	if (prot_id == IPA_USB_RNDIS)
		config_group_init_type_name(&opts->func_inst.group,
						fi->group.cg_item.ci_name,
+1 −0
Original line number Diff line number Diff line
@@ -312,6 +312,7 @@ struct f_gsi {
	struct gsi_ctrl_port c_port;
	void *ipc_log_ctxt;
	bool rmnet_dtr_status;
	bool rmnet_use_tcm_mem;

	bool rwake_inprogress;

+3 −0
Original line number Diff line number Diff line
@@ -8,6 +8,7 @@

#include <linux/scatterlist.h>
#include <linux/usb/gadget.h>
#include <linux/soc/qcom/llcc-tcm.h>

/* used for struct usb_phy flags */
#define PHY_HOST_MODE			BIT(0)
@@ -85,6 +86,8 @@ struct usb_gsi_request {
	struct sg_table sgt_trb_xfer_ring;
	struct sg_table sgt_data_buff;
	struct device *dev;
	bool use_tcm_mem;
	struct llcc_tcm_data *tcm_mem;
};

/*