mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-07 03:15:31 +09:00
dma-buf: system_heap: support cpu access partial dma-buf
Support the system_heap to allow cpu access partial dma-buf. Change-Id: I8250c0bb26b776b8c8f5e4c3ee0cb71e26445743 Signed-off-by: Jianqun Xu <jay.xu@rock-chips.com>
This commit is contained in:
@@ -25,6 +25,8 @@
|
|||||||
#include "page_pool.h"
|
#include "page_pool.h"
|
||||||
#include "deferred-free-helper.h"
|
#include "deferred-free-helper.h"
|
||||||
|
|
||||||
|
#define CONFIG_SYSTEM_HEAP_FORCE_DMA_SYNC
|
||||||
|
|
||||||
static struct dma_heap *sys_heap;
|
static struct dma_heap *sys_heap;
|
||||||
static struct dma_heap *sys_uncached_heap;
|
static struct dma_heap *sys_uncached_heap;
|
||||||
|
|
||||||
@@ -214,6 +216,141 @@ static int system_heap_dma_buf_end_cpu_access(struct dma_buf *dmabuf,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int system_heap_sgl_sync_range(struct device *dev,
|
||||||
|
struct scatterlist *sgl,
|
||||||
|
unsigned int nents,
|
||||||
|
unsigned int offset,
|
||||||
|
unsigned int length,
|
||||||
|
enum dma_data_direction dir,
|
||||||
|
bool for_cpu)
|
||||||
|
{
|
||||||
|
struct scatterlist *sg;
|
||||||
|
unsigned int len = 0;
|
||||||
|
dma_addr_t sg_dma_addr;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for_each_sg(sgl, sg, nents, i) {
|
||||||
|
unsigned int sg_offset, sg_left, size = 0;
|
||||||
|
|
||||||
|
sg_dma_addr = sg_dma_address(sg);
|
||||||
|
|
||||||
|
len += sg->length;
|
||||||
|
if (len <= offset)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
sg_left = len - offset;
|
||||||
|
sg_offset = sg->length - sg_left;
|
||||||
|
|
||||||
|
size = (length < sg_left) ? length : sg_left;
|
||||||
|
if (for_cpu)
|
||||||
|
dma_sync_single_range_for_cpu(dev, sg_dma_addr,
|
||||||
|
sg_offset, size, dir);
|
||||||
|
else
|
||||||
|
dma_sync_single_range_for_device(dev, sg_dma_addr,
|
||||||
|
sg_offset, size, dir);
|
||||||
|
|
||||||
|
offset += size;
|
||||||
|
length -= size;
|
||||||
|
|
||||||
|
if (length == 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
system_heap_dma_buf_begin_cpu_access_partial(struct dma_buf *dmabuf,
|
||||||
|
enum dma_data_direction direction,
|
||||||
|
unsigned int offset,
|
||||||
|
unsigned int len)
|
||||||
|
{
|
||||||
|
struct system_heap_buffer *buffer = dmabuf->priv;
|
||||||
|
struct sg_table *table = &buffer->sg_table;
|
||||||
|
struct dma_heap_attachment *a;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
if (direction == DMA_TO_DEVICE)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
mutex_lock(&buffer->lock);
|
||||||
|
if (IS_ENABLED(CONFIG_SYSTEM_HEAP_FORCE_DMA_SYNC)) {
|
||||||
|
struct dma_heap *heap = buffer->heap;
|
||||||
|
|
||||||
|
ret = system_heap_sgl_sync_range(dma_heap_get_dev(heap),
|
||||||
|
table->sgl,
|
||||||
|
table->nents,
|
||||||
|
offset, len,
|
||||||
|
direction, true);
|
||||||
|
goto unlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buffer->vmap_cnt)
|
||||||
|
invalidate_kernel_vmap_range(buffer->vaddr, buffer->len);
|
||||||
|
|
||||||
|
if (!buffer->uncached)
|
||||||
|
goto unlock;
|
||||||
|
|
||||||
|
list_for_each_entry(a, &buffer->attachments, list) {
|
||||||
|
if (!a->mapped)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
ret = system_heap_sgl_sync_range(a->dev, a->table->sgl,
|
||||||
|
a->table->nents,
|
||||||
|
offset, len,
|
||||||
|
direction, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
unlock:
|
||||||
|
mutex_unlock(&buffer->lock);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
system_heap_dma_buf_end_cpu_access_partial(struct dma_buf *dmabuf,
|
||||||
|
enum dma_data_direction direction,
|
||||||
|
unsigned int offset,
|
||||||
|
unsigned int len)
|
||||||
|
{
|
||||||
|
struct system_heap_buffer *buffer = dmabuf->priv;
|
||||||
|
struct sg_table *table = &buffer->sg_table;
|
||||||
|
struct dma_heap_attachment *a;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
mutex_lock(&buffer->lock);
|
||||||
|
if (IS_ENABLED(CONFIG_SYSTEM_HEAP_FORCE_DMA_SYNC)) {
|
||||||
|
struct dma_heap *heap = buffer->heap;
|
||||||
|
|
||||||
|
ret = system_heap_sgl_sync_range(dma_heap_get_dev(heap),
|
||||||
|
table->sgl,
|
||||||
|
table->nents,
|
||||||
|
offset, len,
|
||||||
|
direction, false);
|
||||||
|
goto unlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buffer->vmap_cnt)
|
||||||
|
flush_kernel_vmap_range(buffer->vaddr, buffer->len);
|
||||||
|
|
||||||
|
if (!buffer->uncached)
|
||||||
|
goto unlock;
|
||||||
|
|
||||||
|
list_for_each_entry(a, &buffer->attachments, list) {
|
||||||
|
if (!a->mapped)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
ret = system_heap_sgl_sync_range(a->dev, a->table->sgl,
|
||||||
|
a->table->nents,
|
||||||
|
offset, len,
|
||||||
|
direction, false);
|
||||||
|
}
|
||||||
|
unlock:
|
||||||
|
mutex_unlock(&buffer->lock);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static int system_heap_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma)
|
static int system_heap_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma)
|
||||||
{
|
{
|
||||||
struct system_heap_buffer *buffer = dmabuf->priv;
|
struct system_heap_buffer *buffer = dmabuf->priv;
|
||||||
@@ -370,6 +507,8 @@ static const struct dma_buf_ops system_heap_buf_ops = {
|
|||||||
.unmap_dma_buf = system_heap_unmap_dma_buf,
|
.unmap_dma_buf = system_heap_unmap_dma_buf,
|
||||||
.begin_cpu_access = system_heap_dma_buf_begin_cpu_access,
|
.begin_cpu_access = system_heap_dma_buf_begin_cpu_access,
|
||||||
.end_cpu_access = system_heap_dma_buf_end_cpu_access,
|
.end_cpu_access = system_heap_dma_buf_end_cpu_access,
|
||||||
|
.begin_cpu_access_partial = system_heap_dma_buf_begin_cpu_access_partial,
|
||||||
|
.end_cpu_access_partial = system_heap_dma_buf_end_cpu_access_partial,
|
||||||
.mmap = system_heap_mmap,
|
.mmap = system_heap_mmap,
|
||||||
.vmap = system_heap_vmap,
|
.vmap = system_heap_vmap,
|
||||||
.vunmap = system_heap_vunmap,
|
.vunmap = system_heap_vunmap,
|
||||||
|
|||||||
Reference in New Issue
Block a user