Loading drivers/usb/dwc3/dwc3-msm.c +116 −24 Original line number Diff line number Diff line Loading @@ -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. * Loading @@ -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); Loading Loading @@ -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; } Loading Loading @@ -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. Loading drivers/usb/gadget/function/f_gsi.c +43 −2 Original line number Diff line number Diff line Loading @@ -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); Loading @@ -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) { Loading Loading @@ -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) { Loading Loading @@ -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, Loading drivers/usb/gadget/function/f_gsi.h +1 −0 Original line number Diff line number Diff line Loading @@ -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; Loading include/linux/usb/dwc3-msm.h +3 −0 Original line number Diff line number Diff line Loading @@ -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) Loading Loading @@ -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; }; /* Loading Loading
drivers/usb/dwc3/dwc3-msm.c +116 −24 Original line number Diff line number Diff line Loading @@ -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. * Loading @@ -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); Loading Loading @@ -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; } Loading Loading @@ -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. Loading
drivers/usb/gadget/function/f_gsi.c +43 −2 Original line number Diff line number Diff line Loading @@ -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); Loading @@ -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) { Loading Loading @@ -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) { Loading Loading @@ -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, Loading
drivers/usb/gadget/function/f_gsi.h +1 −0 Original line number Diff line number Diff line Loading @@ -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; Loading
include/linux/usb/dwc3-msm.h +3 −0 Original line number Diff line number Diff line Loading @@ -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) Loading Loading @@ -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; }; /* Loading