From 4f273fe53c67ae9a163d0df28df15cca33839110 Mon Sep 17 00:00:00 2001 From: Yu Qiaowei Date: Wed, 22 Dec 2021 21:17:54 +0800 Subject: [PATCH] video: rockchip: rga3: Support to verify whether the memory is greater than 4G. When the memory is greater than 4G, dma_buf does not map the RGA2 device. Signed-off-by: Yu Qiaowei Change-Id: I7bf62c7d231fbc2c2e928d1387406281701a6269 --- drivers/video/rockchip/rga3/include/rga_drv.h | 9 +- drivers/video/rockchip/rga3/include/rga_mm.h | 5 + drivers/video/rockchip/rga3/rga_dma_buf.c | 1 + drivers/video/rockchip/rga3/rga_mm.c | 147 ++++++++++++++---- 4 files changed, 128 insertions(+), 34 deletions(-) diff --git a/drivers/video/rockchip/rga3/include/rga_drv.h b/drivers/video/rockchip/rga3/include/rga_drv.h index 22aa2d4db63b..99d725a79f99 100644 --- a/drivers/video/rockchip/rga3/include/rga_drv.h +++ b/drivers/video/rockchip/rga3/include/rga_drv.h @@ -174,11 +174,15 @@ struct rga_dma_buffer { unsigned long size; void *vmap_ptr; enum dma_data_direction dir; + + /* The core of the mapping */ + int core; }; struct rga_internal_buffer { /* DMA buffer */ - struct rga_dma_buffer dma_buffer; + struct rga_dma_buffer *dma_buffer; + uint32_t dma_buffer_size; /* virtual address */ uint64_t vir_addr; @@ -195,8 +199,7 @@ struct rga_internal_buffer { uint32_t handle; - /* It indicates whether the buffer is cached */ - bool cached; + uint32_t mm_flag; struct kref refcount; }; diff --git a/drivers/video/rockchip/rga3/include/rga_mm.h b/drivers/video/rockchip/rga3/include/rga_mm.h index 55ac7e2c2708..83e6266dc2b4 100644 --- a/drivers/video/rockchip/rga3/include/rga_mm.h +++ b/drivers/video/rockchip/rga3/include/rga_mm.h @@ -11,6 +11,11 @@ #include "rga_drv.h" +enum memory_flag { + /* It will identify whether the buffer is within 0 ~ 4G. */ + RGA_MM_UNDER_4G = 1 << 0, +}; + struct rga_mm { struct mutex lock; diff --git a/drivers/video/rockchip/rga3/rga_dma_buf.c b/drivers/video/rockchip/rga3/rga_dma_buf.c index 25231324df3d..cfa8bbef4fc7 100644 --- a/drivers/video/rockchip/rga3/rga_dma_buf.c +++ b/drivers/video/rockchip/rga3/rga_dma_buf.c @@ -775,6 +775,7 @@ int rga_dma_map_fd(int fd, struct rga_dma_buffer *rga_dma_buffer, rga_dma_buffer->dma_buf = dma_buf; rga_dma_buffer->attach = attach; rga_dma_buffer->sgt = sgt; + rga_dma_buffer->iova = sg_dma_address(sgt->sgl); rga_dma_buffer->size = sg_dma_len(sgt->sgl); rga_dma_buffer->dir = dir; diff --git a/drivers/video/rockchip/rga3/rga_mm.c b/drivers/video/rockchip/rga3/rga_mm.c index 7ca36b4040f9..355d72f5d30b 100644 --- a/drivers/video/rockchip/rga3/rga_mm.c +++ b/drivers/video/rockchip/rga3/rga_mm.c @@ -11,15 +11,85 @@ #include "rga_mm.h" #include "rga_dma_buf.h" -static void rga_mm_kref_release_buffer(struct kref *ref) +/* If it is within 0~4G, return 1 (true). */ +static int rga_mm_check_range_sgt(struct sg_table *sgt) { - struct rga_internal_buffer *internal_buffer; + int i; + struct scatterlist *sg; + phys_addr_t s_phys = 0; - internal_buffer = container_of(ref, struct rga_internal_buffer, refcount); + for_each_sgtable_sg(sgt, sg, i) { + s_phys = sg_phys(sg); + if ((s_phys > 0xffffffff) || (s_phys + sg->length > 0xffffffff)) + return 0; + } + return 1; +} + +static void rga_mm_unmap_dma_buffer(struct rga_internal_buffer *internal_buffer) +{ + int i; + + for (i = 0; i < internal_buffer->dma_buffer_size; i++) + rga_dma_unmap_fd(&internal_buffer->dma_buffer[i]); + + kfree(internal_buffer->dma_buffer); + internal_buffer->dma_buffer = NULL; +} + +static int rga_mm_map_dma_buffer(struct rga_external_buffer *external_buffer, + struct rga_internal_buffer *internal_buffer) +{ + int ret, i; + + internal_buffer->dma_buffer_size = rga_drvdata->num_of_scheduler; + internal_buffer->dma_buffer = kcalloc(internal_buffer->dma_buffer_size, + sizeof(struct rga_dma_buffer), GFP_KERNEL); + if (internal_buffer->dma_buffer == NULL) { + pr_err("%s alloc internal_buffer error!\n", __func__); + return -ENOMEM; + } + + internal_buffer->type = RGA_DMA_BUFFER; + + for (i = 0; i < internal_buffer->dma_buffer_size; i++) { + /* If the physical address is greater than 4G, there is no need to map RGA2. */ + if ((rga_drvdata->rga_scheduler[i]->core == RGA2_SCHEDULER_CORE0) && + (~internal_buffer->mm_flag & RGA_MM_UNDER_4G)) + continue; + + ret = rga_dma_map_fd((int)external_buffer->memory, + &internal_buffer->dma_buffer[i], + DMA_BIDIRECTIONAL, + rga_drvdata->rga_scheduler[i]->dev); + if (ret < 0) { + pr_err("%s core[%d] map dma buffer error!\n", + __func__, rga_drvdata->rga_scheduler[0]->core); + goto FREE_RGA_DMA_BUF; + } + + internal_buffer->dma_buffer[i].core = rga_drvdata->rga_scheduler[i]->core; + + /* At first, check whether the physical address is greater than 4G. */ + if (i == 0) + if (rga_mm_check_range_sgt(internal_buffer->dma_buffer[0].sgt)) + internal_buffer->mm_flag |= RGA_MM_UNDER_4G; + } + + return 0; + +FREE_RGA_DMA_BUF: + rga_mm_unmap_dma_buffer(internal_buffer); + + return ret; +} + +static int rga_mm_unmap_buffer(struct rga_internal_buffer *internal_buffer) +{ switch (internal_buffer->type) { case RGA_DMA_BUFFER: - rga_dma_unmap_fd(&internal_buffer->dma_buffer); + rga_mm_unmap_dma_buffer(internal_buffer); break; case RGA_VIRTUAL_ADDRESS: // TODO @@ -27,9 +97,44 @@ static void rga_mm_kref_release_buffer(struct kref *ref) // TODO default: pr_err("Illegal external buffer!\n"); - return; + return -EFAULT; } + return 0; +} + +static int rga_mm_map_buffer(struct rga_external_buffer *external_buffer, + struct rga_internal_buffer *internal_buffer) +{ + int ret; + + switch (external_buffer->type) { + case RGA_DMA_BUFFER: + ret = rga_mm_map_dma_buffer(external_buffer, internal_buffer); + if (ret < 0) { + pr_err("%s map dma_buf error!\n", __func__); + return ret; + } + break; + case RGA_VIRTUAL_ADDRESS: + // TODO + case RGA_PHYSICAL_ADDRESS: + // TODO + default: + pr_err("Illegal external buffer!\n"); + return -EFAULT; + } + + return 0; +} + +static void rga_mm_kref_release_buffer(struct kref *ref) +{ + struct rga_internal_buffer *internal_buffer; + + internal_buffer = container_of(ref, struct rga_internal_buffer, refcount); + rga_mm_unmap_buffer(internal_buffer); + idr_remove(&rga_drvdata->mm->memory_idr, internal_buffer->handle); kfree(internal_buffer); rga_drvdata->mm->buffer_count--; @@ -65,7 +170,7 @@ rga_mm_internal_buffer_lookup_external(struct rga_mm *mm_session, return (struct rga_internal_buffer *)dma_buf; idr_for_each_entry(&mm_session->memory_idr, temp_buffer, id) { - if (temp_buffer->dma_buffer.dma_buf == dma_buf) { + if (temp_buffer->dma_buffer[0].dma_buf == dma_buf) { output_buffer = temp_buffer; break; } @@ -108,9 +213,9 @@ void rga_mm_dump_info(struct rga_mm *mm_session) pr_info("buffer count = %d\n", mm_session->buffer_count); idr_for_each_entry(&mm_session->memory_idr, temp_buffer, id) { - pr_info("ID[%d] dma_buf = %p, handle = %d, refcount = %d, cached = %d\n", - id, temp_buffer->dma_buffer.dma_buf, temp_buffer->handle, - kref_read(&temp_buffer->refcount), temp_buffer->cached); + pr_info("ID[%d] dma_buf = %p, handle = %d, refcount = %d, mm_flag = %x\n", + id, temp_buffer->dma_buffer[0].dma_buf, temp_buffer->handle, + kref_read(&temp_buffer->refcount), temp_buffer->mm_flag); } } @@ -146,29 +251,9 @@ uint32_t rga_mm_import_buffer(struct rga_external_buffer *external_buffer) return -ENOMEM; } - switch (external_buffer->type) { - case RGA_DMA_BUFFER: - ret = rga_dma_map_fd((int)external_buffer->memory, - &internal_buffer->dma_buffer, - DMA_BIDIRECTIONAL, - rga_drvdata->rga_scheduler[0]->dev); - if (ret < 0) { - pr_err("%s map dma buffer error!\n", __func__); - goto FREE_INTERNAL_BUFFER; - } - - internal_buffer->cached = true; - internal_buffer->type = RGA_DMA_BUFFER; - break; - case RGA_VIRTUAL_ADDRESS: - // TODO - case RGA_PHYSICAL_ADDRESS: - // TODO - default: - pr_err("Illegal external buffer!\n"); - ret = -EFAULT; + ret = rga_mm_map_buffer(external_buffer, internal_buffer); + if (ret < 0) goto FREE_INTERNAL_BUFFER; - } kref_init(&internal_buffer->refcount);