mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-08 04:42:04 -04:00
dwc3-msm: Add LLCC TCM memory usage for USB IN endpoint data buffers
Add LLCC TCM memory usage for USB IN endpoint data buffers. Change-Id: Iab4153838684530736bfb7373ecb492ca4202f08 Signed-off-by: Mayank Rana <mrana@codeaurora.org>
This commit is contained in:
parent
e92ca5084e
commit
e334d6d2ed
2 changed files with 119 additions and 24 deletions
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
|||
Loading…
Reference in a new issue