From d97d0e3a21c68eb7f1c591999601443a276ad61f Mon Sep 17 00:00:00 2001 From: Pengcheng Chen Date: Thu, 21 Mar 2019 17:33:13 +0800 Subject: [PATCH] ge2d: change dma_buf to cacheable [1/2] PD#SWPL-5685 Problem: ge2d output dmabuf have high variance Solution: change dma_buf to cacheable Verify: verified by w400 Change-Id: Iff9356dd256ce69bd87e7e5a2b1feb9e74c49744 Signed-off-by: Pengcheng Chen --- drivers/amlogic/media/common/ge2d/ge2d_dmabuf.c | 119 ++++++++++-------------- drivers/amlogic/media/common/ge2d/ge2d_dmabuf.h | 1 - drivers/amlogic/media/common/ge2d/ge2d_wq.c | 1 - 3 files changed, 47 insertions(+), 74 deletions(-) diff --git a/drivers/amlogic/media/common/ge2d/ge2d_dmabuf.c b/drivers/amlogic/media/common/ge2d/ge2d_dmabuf.c index 41ff5de..c236259 100644 --- a/drivers/amlogic/media/common/ge2d/ge2d_dmabuf.c +++ b/drivers/amlogic/media/common/ge2d/ge2d_dmabuf.c @@ -29,6 +29,7 @@ #include #include #include +#include #include "ge2d_log.h" #include "ge2d_dmabuf.h" @@ -38,18 +39,19 @@ static void clear_dma_buffer(struct aml_dma_buffer *buffer, int index); static void aml_dma_put(void *buf_priv) { struct aml_dma_buf *buf = buf_priv; + struct page *cma_pages = NULL; if (!atomic_dec_and_test(&buf->refcount)) { ge2d_log_dbg("ge2d aml_dma_put, refcont=%d\n", atomic_read(&buf->refcount)); return; } - if (buf->sgt_base) { - sg_free_table(buf->sgt_base); - kfree(buf->sgt_base); + cma_pages = virt_to_page(buf->vaddr); + if (!dma_release_from_contiguous(buf->dev, cma_pages, + buf->size >> PAGE_SHIFT)) { + pr_err("failed to release cma buffer\n"); } - dma_free_attrs(buf->dev, buf->size, buf->cookie, buf->dma_addr, - buf->attrs); + buf->vaddr = NULL; clear_dma_buffer((struct aml_dma_buffer *)buf->priv, buf->index); put_device(buf->dev); kfree(buf); @@ -62,32 +64,31 @@ static void *aml_dma_alloc(struct device *dev, unsigned long attrs, gfp_t gfp_flags) { struct aml_dma_buf *buf; + struct page *cma_pages = NULL; + dma_addr_t paddr = 0; if (WARN_ON(!dev)) return (void *)(-EINVAL); - buf = kzalloc(sizeof(struct aml_dma_buf), GFP_KERNEL); + buf = kzalloc(sizeof(struct aml_dma_buf), GFP_KERNEL | gfp_flags); if (!buf) return NULL; if (attrs) buf->attrs = attrs; - buf->cookie = dma_alloc_attrs(dev, size, &buf->dma_addr, - gfp_flags, buf->attrs); - if (!buf->cookie) { - dev_err(dev, "dma_alloc_coherent of size %ld failed\n", size); - kfree(buf); + cma_pages = dma_alloc_from_contiguous(dev, + size >> PAGE_SHIFT, 0); + if (cma_pages) { + paddr = page_to_phys(cma_pages); + } else { + pr_err("failed to alloc cma pages.\n"); return NULL; } - - if ((buf->attrs & DMA_ATTR_NO_KERNEL_MAPPING) == 0) - buf->vaddr = buf->cookie; - - /* Prevent the device from being released while the buffer is used */ + buf->vaddr = phys_to_virt(paddr); buf->dev = get_device(dev); buf->size = size; buf->dma_dir = dma_dir; - + buf->dma_addr = paddr; atomic_inc(&buf->refcount); ge2d_log_dbg("aml_dma_buf=0x%p, refcont=%d\n", buf, atomic_read(&buf->refcount)); @@ -98,26 +99,23 @@ static void *aml_dma_alloc(struct device *dev, unsigned long attrs, static int aml_dma_mmap(void *buf_priv, struct vm_area_struct *vma) { struct aml_dma_buf *buf = buf_priv; - int ret; + unsigned long pfn = 0; + unsigned long vsize = vma->vm_end - vma->vm_start; + int ret = -1; - if (!buf) { - pr_err("No buffer to map\n"); + if (!buf || !vma) { + pr_err("No memory to map\n"); return -EINVAL; } - /* - * dma_mmap_* uses vm_pgoff as in-buffer offset, but we want to - * map whole buffer - */ - vma->vm_pgoff = 0; - - ret = dma_mmap_attrs(buf->dev, vma, buf->cookie, - buf->dma_addr, buf->size, buf->attrs); - + pfn = virt_to_phys(buf->vaddr) >> PAGE_SHIFT; + ret = remap_pfn_range(vma, vma->vm_start, pfn, + vsize, vma->vm_page_prot); if (ret) { - pr_err("Remapping memory failed, error: %d\n", ret); + pr_err("Remapping memory, error: %d\n", ret); return ret; } + vma->vm_flags |= VM_DONTEXPAND; ge2d_log_dbg("mapped dma addr 0x%08lx at 0x%08lx, size %d\n", (unsigned long)buf->dma_addr, vma->vm_start, buf->size); @@ -136,10 +134,12 @@ static int aml_dmabuf_ops_attach(struct dma_buf *dbuf, struct device *dev, struct dma_buf_attachment *dbuf_attach) { struct aml_attachment *attach; - unsigned int i; - struct scatterlist *rd, *wr; - struct sg_table *sgt; struct aml_dma_buf *buf = dbuf->priv; + int num_pages = PAGE_ALIGN(buf->size) / PAGE_SIZE; + struct sg_table *sgt; + struct scatterlist *sg; + void *vaddr = buf->vaddr; + unsigned int i; int ret; attach = kzalloc(sizeof(*attach), GFP_KERNEL); @@ -150,18 +150,21 @@ static int aml_dmabuf_ops_attach(struct dma_buf *dbuf, struct device *dev, /* Copy the buf->base_sgt scatter list to the attachment, as we can't * map the same scatter list to multiple attachments at the same time. */ - ret = sg_alloc_table(sgt, buf->sgt_base->orig_nents, GFP_KERNEL); + ret = sg_alloc_table(sgt, num_pages, GFP_KERNEL); if (ret) { kfree(attach); return -ENOMEM; } + for_each_sg(sgt->sgl, sg, sgt->nents, i) { + struct page *page = virt_to_page(vaddr); - rd = buf->sgt_base->sgl; - wr = sgt->sgl; - for (i = 0; i < sgt->orig_nents; ++i) { - sg_set_page(wr, sg_page(rd), rd->length, rd->offset); - rd = sg_next(rd); - wr = sg_next(wr); + if (!page) { + sg_free_table(sgt); + kfree(attach); + return -ENOMEM; + } + sg_set_page(sg, page, PAGE_SIZE, 0); + vaddr += PAGE_SIZE; } attach->dma_dir = DMA_NONE; @@ -214,7 +217,6 @@ static struct sg_table *aml_dmabuf_ops_map( attach->dma_dir); attach->dma_dir = DMA_NONE; } - /* mapping to the client with new direction */ sgt->nents = dma_map_sg(db_attach->dev, sgt->sgl, sgt->orig_nents, dma_dir); @@ -274,25 +276,6 @@ static struct dma_buf_ops ge2d_dmabuf_ops = { .release = aml_dmabuf_ops_release, }; -static struct sg_table *get_base_sgt(struct aml_dma_buf *buf) -{ - int ret; - struct sg_table *sgt; - - sgt = kmalloc(sizeof(struct sg_table), GFP_KERNEL); - if (!sgt) - return NULL; - - ret = dma_get_sgtable(buf->dev, sgt, buf->cookie, - buf->dma_addr, buf->size); - if (ret < 0) { - dev_err(buf->dev, "failed to get scatterlist from DMA API\n"); - kfree(sgt); - return NULL; - } - return sgt; -} - static struct dma_buf *get_dmabuf(void *buf_priv, unsigned long flags) { struct aml_dma_buf *buf = buf_priv; @@ -303,11 +286,7 @@ static struct dma_buf *get_dmabuf(void *buf_priv, unsigned long flags) exp_info.size = buf->size; exp_info.flags = flags; exp_info.priv = buf; - - if (!buf->sgt_base) - buf->sgt_base = get_base_sgt(buf); - - if (WARN_ON(!buf->sgt_base)) + if (WARN_ON(!buf->vaddr)) return NULL; dbuf = dma_buf_export(&exp_info); @@ -393,20 +372,16 @@ int ge2d_dma_buffer_alloc(struct aml_dma_buffer *buffer, size = PAGE_ALIGN(ge2d_req_buf->len); if (size == 0) return (-EINVAL); - buf = aml_dma_alloc(dev, 0, size, ge2d_req_buf->dma_dir, GFP_HIGHUSER | __GFP_ZERO); if (!buf) return (-ENOMEM); - dma_buf = (struct aml_dma_buf *)buf; mutex_lock(&(buffer->lock)); index = find_empty_dma_buffer(buffer); if ((index < 0) || (index >= AML_MAX_DMABUF)) { pr_err("no empty buffer found\n"); - dma_free_attrs(dev, dma_buf->size, dma_buf->cookie, - dma_buf->dma_addr, - dma_buf->attrs); mutex_unlock(&(buffer->lock)); + aml_dma_put(buf); return (-ENOMEM); } ((struct aml_dma_buf *)buf)->priv = buffer; @@ -628,7 +603,7 @@ void ge2d_dma_buffer_dma_flush(struct device *dev, int fd) pr_err("error input param"); return; } - if (buf->size > 0) + if ((buf->size > 0) && (buf->dev == dev)) dma_sync_single_for_device(buf->dev, buf->dma_addr, buf->size, DMA_TO_DEVICE); dma_buf_put(dmabuf); @@ -650,7 +625,7 @@ void ge2d_dma_buffer_cache_flush(struct device *dev, int fd) pr_err("error input param"); return; } - if (buf->size > 0) + if ((buf->size > 0) && (buf->dev == dev)) dma_sync_single_for_cpu(buf->dev, buf->dma_addr, buf->size, DMA_FROM_DEVICE); dma_buf_put(dmabuf); diff --git a/drivers/amlogic/media/common/ge2d/ge2d_dmabuf.h b/drivers/amlogic/media/common/ge2d/ge2d_dmabuf.h index 396a6a8..c3c03d3 100644 --- a/drivers/amlogic/media/common/ge2d/ge2d_dmabuf.h +++ b/drivers/amlogic/media/common/ge2d/ge2d_dmabuf.h @@ -37,7 +37,6 @@ struct aml_dma_buf { unsigned int index; dma_addr_t dma_addr; atomic_t refcount; - struct sg_table *sgt_base; /* DMABUF related */ struct dma_buf_attachment *db_attach; void *priv; diff --git a/drivers/amlogic/media/common/ge2d/ge2d_wq.c b/drivers/amlogic/media/common/ge2d/ge2d_wq.c index 2420c28..eee2126 100644 --- a/drivers/amlogic/media/common/ge2d/ge2d_wq.c +++ b/drivers/amlogic/media/common/ge2d/ge2d_wq.c @@ -1190,7 +1190,6 @@ static int build_ge2d_config_ex_dma(struct ge2d_context_s *context, dma_cfg->dir = dir; cfg->dma_cfg = dma_cfg; ret = ge2d_dma_buffer_get_phys(dma_cfg, &addr); - ge2d_log_info("phys: addr=%lx\n", addr); if (ret != 0) return ret; -- 2.7.4