You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
759 lines
21 KiB
Diff
759 lines
21 KiB
Diff
5 years ago
|
From e4cb138abe457a6ab9b98458660a1c8e548fab7f Mon Sep 17 00:00:00 2001
|
||
5 years ago
|
From: Dave Stevenson <dave.stevenson@raspberrypi.org>
|
||
|
Date: Mon, 1 Jul 2019 11:57:25 +0100
|
||
5 years ago
|
Subject: [PATCH] staging: vcsm-cma: Rework to use dma APIs, not CMA
|
||
5 years ago
|
|
||
|
Due to a misunderstanding of the DMA mapping APIs, I made
|
||
|
the wrong decision on how to implement this.
|
||
|
|
||
|
Rework to use dma_alloc_coherent instead of the CMA
|
||
|
API. This also allows it to be built as a module easily.
|
||
|
|
||
|
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
|
||
|
---
|
||
|
.../staging/vc04_services/vc-sm-cma/Kconfig | 4 +-
|
||
|
.../staging/vc04_services/vc-sm-cma/Makefile | 2 +-
|
||
|
.../staging/vc04_services/vc-sm-cma/vc_sm.c | 291 ++++++++++--------
|
||
|
.../staging/vc04_services/vc-sm-cma/vc_sm.h | 13 +-
|
||
|
.../vc04_services/vc-sm-cma/vc_sm_cma.c | 98 ------
|
||
|
.../vc04_services/vc-sm-cma/vc_sm_cma.h | 39 ---
|
||
|
6 files changed, 168 insertions(+), 279 deletions(-)
|
||
|
delete mode 100644 drivers/staging/vc04_services/vc-sm-cma/vc_sm_cma.c
|
||
|
delete mode 100644 drivers/staging/vc04_services/vc-sm-cma/vc_sm_cma.h
|
||
|
|
||
|
--- a/drivers/staging/vc04_services/vc-sm-cma/Kconfig
|
||
|
+++ b/drivers/staging/vc04_services/vc-sm-cma/Kconfig
|
||
|
@@ -1,6 +1,6 @@
|
||
|
config BCM_VC_SM_CMA
|
||
|
- bool "VideoCore Shared Memory (CMA) driver"
|
||
|
- depends on BCM2835_VCHIQ && DMA_CMA
|
||
|
+ tristate "VideoCore Shared Memory (CMA) driver"
|
||
|
+ depends on BCM2835_VCHIQ
|
||
|
select RBTREE
|
||
|
select DMA_SHARED_BUFFER
|
||
|
help
|
||
|
--- a/drivers/staging/vc04_services/vc-sm-cma/Makefile
|
||
|
+++ b/drivers/staging/vc04_services/vc-sm-cma/Makefile
|
||
|
@@ -3,6 +3,6 @@ ccflags-y += -Idrivers/staging/vc04_serv
|
||
|
ccflags-y += -D__VCCOREVER__=0
|
||
|
|
||
|
vc-sm-cma-$(CONFIG_BCM_VC_SM_CMA) := \
|
||
|
- vc_sm.o vc_sm_cma_vchi.o vc_sm_cma.o
|
||
|
+ vc_sm.o vc_sm_cma_vchi.o
|
||
|
|
||
|
obj-$(CONFIG_BCM_VC_SM_CMA) += vc-sm-cma.o
|
||
|
--- a/drivers/staging/vc04_services/vc-sm-cma/vc_sm.c
|
||
|
+++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm.c
|
||
|
@@ -6,8 +6,8 @@
|
||
|
* Dave Stevenson <dave.stevenson@raspberrypi.org>
|
||
|
*
|
||
|
* Based on vmcs_sm driver from Broadcom Corporation for some API,
|
||
|
- * and taking some code for CMA/dmabuf handling from the Android Ion
|
||
|
- * driver (Google/Linaro).
|
||
|
+ * and taking some code for buffer allocation and dmabuf handling from
|
||
|
+ * videobuf2.
|
||
|
*
|
||
|
*
|
||
|
* This driver has 3 main uses:
|
||
|
@@ -52,7 +52,6 @@
|
||
|
#include "vc_sm_cma_vchi.h"
|
||
|
|
||
|
#include "vc_sm.h"
|
||
|
-#include "vc_sm_cma.h"
|
||
|
#include "vc_sm_knl.h"
|
||
|
#include <linux/broadcom/vc_sm_cma_ioctl.h>
|
||
|
|
||
|
@@ -89,7 +88,6 @@ struct sm_state_t {
|
||
|
struct miscdevice misc_dev;
|
||
|
|
||
|
struct sm_instance *sm_handle; /* Handle for videocore service. */
|
||
|
- struct cma *cma_heap;
|
||
|
|
||
|
spinlock_t kernelid_map_lock; /* Spinlock protecting kernelid_map */
|
||
|
struct idr kernelid_map;
|
||
|
@@ -110,8 +108,9 @@ struct sm_state_t {
|
||
|
|
||
|
struct vc_sm_dma_buf_attachment {
|
||
|
struct device *dev;
|
||
|
- struct sg_table *table;
|
||
|
+ struct sg_table sg_table;
|
||
|
struct list_head list;
|
||
|
+ enum dma_data_direction dma_dir;
|
||
|
};
|
||
|
|
||
|
/* ---- Private Variables ----------------------------------------------- */
|
||
|
@@ -202,9 +201,10 @@ static int vc_sm_cma_global_state_show(s
|
||
|
resource->import.attach);
|
||
|
seq_printf(s, " SGT %p\n",
|
||
|
resource->import.sgt);
|
||
|
+ } else {
|
||
|
+ seq_printf(s, " SGT %p\n",
|
||
|
+ resource->alloc.sg_table);
|
||
|
}
|
||
|
- seq_printf(s, " SG_TABLE %p\n",
|
||
|
- resource->sg_table);
|
||
|
seq_printf(s, " DMA_ADDR %pad\n",
|
||
|
&resource->dma_addr);
|
||
|
seq_printf(s, " VC_HANDLE %08x\n",
|
||
|
@@ -296,8 +296,9 @@ static void vc_sm_vpu_free(struct vc_sm_
|
||
|
*/
|
||
|
static void vc_sm_release_resource(struct vc_sm_buffer *buffer)
|
||
|
{
|
||
|
- pr_debug("[%s]: buffer %p (name %s, size %zu)\n",
|
||
|
- __func__, buffer, buffer->name, buffer->size);
|
||
|
+ pr_debug("[%s]: buffer %p (name %s, size %zu), imported %u\n",
|
||
|
+ __func__, buffer, buffer->name, buffer->size,
|
||
|
+ buffer->imported);
|
||
|
|
||
|
if (buffer->vc_handle) {
|
||
|
/* We've sent the unmap request but not had the response. */
|
||
|
@@ -313,8 +314,6 @@ static void vc_sm_release_resource(struc
|
||
|
|
||
|
/* Release the allocation (whether imported dmabuf or CMA allocation) */
|
||
|
if (buffer->imported) {
|
||
|
- pr_debug("%s: Release imported dmabuf %p\n", __func__,
|
||
|
- buffer->import.dma_buf);
|
||
|
if (buffer->import.dma_buf)
|
||
|
dma_buf_put(buffer->import.dma_buf);
|
||
|
else
|
||
|
@@ -322,16 +321,8 @@ static void vc_sm_release_resource(struc
|
||
|
__func__, buffer);
|
||
|
buffer->import.dma_buf = NULL;
|
||
|
} else {
|
||
|
- if (buffer->sg_table) {
|
||
|
- /* Our own allocation that we need to dma_unmap_sg */
|
||
|
- dma_unmap_sg(&sm_state->pdev->dev,
|
||
|
- buffer->sg_table->sgl,
|
||
|
- buffer->sg_table->nents,
|
||
|
- DMA_BIDIRECTIONAL);
|
||
|
- }
|
||
|
- pr_debug("%s: Release our allocation\n", __func__);
|
||
|
- vc_sm_cma_buffer_free(&buffer->alloc);
|
||
|
- pr_debug("%s: Release our allocation - done\n", __func__);
|
||
|
+ dma_free_coherent(&sm_state->pdev->dev, buffer->size,
|
||
|
+ buffer->cookie, buffer->dma_addr);
|
||
|
}
|
||
|
|
||
|
|
||
|
@@ -371,38 +362,6 @@ static struct vc_sm_privdata_t *vc_sm_cm
|
||
|
return file_data;
|
||
|
}
|
||
|
|
||
|
-static struct sg_table *dup_sg_table(struct sg_table *table)
|
||
|
-{
|
||
|
- struct sg_table *new_table;
|
||
|
- int ret, i;
|
||
|
- struct scatterlist *sg, *new_sg;
|
||
|
-
|
||
|
- new_table = kzalloc(sizeof(*new_table), GFP_KERNEL);
|
||
|
- if (!new_table)
|
||
|
- return ERR_PTR(-ENOMEM);
|
||
|
-
|
||
|
- ret = sg_alloc_table(new_table, table->nents, GFP_KERNEL);
|
||
|
- if (ret) {
|
||
|
- kfree(new_table);
|
||
|
- return ERR_PTR(ret);
|
||
|
- }
|
||
|
-
|
||
|
- new_sg = new_table->sgl;
|
||
|
- for_each_sg(table->sgl, sg, table->nents, i) {
|
||
|
- memcpy(new_sg, sg, sizeof(*sg));
|
||
|
- sg->dma_address = 0;
|
||
|
- new_sg = sg_next(new_sg);
|
||
|
- }
|
||
|
-
|
||
|
- return new_table;
|
||
|
-}
|
||
|
-
|
||
|
-static void free_duped_table(struct sg_table *table)
|
||
|
-{
|
||
|
- sg_free_table(table);
|
||
|
- kfree(table);
|
||
|
-}
|
||
|
-
|
||
|
/* Dma buf operations for use with our own allocations */
|
||
|
|
||
|
static int vc_sm_dma_buf_attach(struct dma_buf *dmabuf,
|
||
|
@@ -410,28 +369,45 @@ static int vc_sm_dma_buf_attach(struct d
|
||
|
|
||
|
{
|
||
|
struct vc_sm_dma_buf_attachment *a;
|
||
|
- struct sg_table *table;
|
||
|
+ struct sg_table *sgt;
|
||
|
struct vc_sm_buffer *buf = dmabuf->priv;
|
||
|
+ struct scatterlist *rd, *wr;
|
||
|
+ int ret, i;
|
||
|
|
||
|
a = kzalloc(sizeof(*a), GFP_KERNEL);
|
||
|
if (!a)
|
||
|
return -ENOMEM;
|
||
|
|
||
|
- table = dup_sg_table(buf->sg_table);
|
||
|
- if (IS_ERR(table)) {
|
||
|
+ pr_debug("%s dmabuf %p attachment %p\n", __func__, dmabuf, attachment);
|
||
|
+
|
||
|
+ mutex_lock(&buf->lock);
|
||
|
+
|
||
|
+ INIT_LIST_HEAD(&a->list);
|
||
|
+
|
||
|
+ sgt = &a->sg_table;
|
||
|
+
|
||
|
+ /* 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->alloc.sg_table->orig_nents, GFP_KERNEL);
|
||
|
+ if (ret) {
|
||
|
kfree(a);
|
||
|
- return PTR_ERR(table);
|
||
|
+ return -ENOMEM;
|
||
|
}
|
||
|
|
||
|
- a->table = table;
|
||
|
- INIT_LIST_HEAD(&a->list);
|
||
|
+ rd = buf->alloc.sg_table->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);
|
||
|
+ }
|
||
|
|
||
|
+ a->dma_dir = DMA_NONE;
|
||
|
attachment->priv = a;
|
||
|
|
||
|
- mutex_lock(&buf->lock);
|
||
|
list_add(&a->list, &buf->attachments);
|
||
|
mutex_unlock(&buf->lock);
|
||
|
- pr_debug("%s dmabuf %p attachment %p\n", __func__, dmabuf, attachment);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
@@ -441,9 +417,20 @@ static void vc_sm_dma_buf_detach(struct
|
||
|
{
|
||
|
struct vc_sm_dma_buf_attachment *a = attachment->priv;
|
||
|
struct vc_sm_buffer *buf = dmabuf->priv;
|
||
|
+ struct sg_table *sgt;
|
||
|
|
||
|
pr_debug("%s dmabuf %p attachment %p\n", __func__, dmabuf, attachment);
|
||
|
- free_duped_table(a->table);
|
||
|
+ if (!a)
|
||
|
+ return;
|
||
|
+
|
||
|
+ sgt = &a->sg_table;
|
||
|
+
|
||
|
+ /* release the scatterlist cache */
|
||
|
+ if (a->dma_dir != DMA_NONE)
|
||
|
+ dma_unmap_sg(attachment->dev, sgt->sgl, sgt->orig_nents,
|
||
|
+ a->dma_dir);
|
||
|
+ sg_free_table(sgt);
|
||
|
+
|
||
|
mutex_lock(&buf->lock);
|
||
|
list_del(&a->list);
|
||
|
mutex_unlock(&buf->lock);
|
||
|
@@ -455,13 +442,38 @@ static struct sg_table *vc_sm_map_dma_bu
|
||
|
enum dma_data_direction direction)
|
||
|
{
|
||
|
struct vc_sm_dma_buf_attachment *a = attachment->priv;
|
||
|
+ /* stealing dmabuf mutex to serialize map/unmap operations */
|
||
|
+ struct mutex *lock = &attachment->dmabuf->lock;
|
||
|
struct sg_table *table;
|
||
|
|
||
|
- table = a->table;
|
||
|
+ mutex_lock(lock);
|
||
|
+ pr_debug("%s attachment %p\n", __func__, attachment);
|
||
|
+ table = &a->sg_table;
|
||
|
+
|
||
|
+ /* return previously mapped sg table */
|
||
|
+ if (a->dma_dir == direction) {
|
||
|
+ mutex_unlock(lock);
|
||
|
+ return table;
|
||
|
+ }
|
||
|
+
|
||
|
+ /* release any previous cache */
|
||
|
+ if (a->dma_dir != DMA_NONE) {
|
||
|
+ dma_unmap_sg(attachment->dev, table->sgl, table->orig_nents,
|
||
|
+ a->dma_dir);
|
||
|
+ a->dma_dir = DMA_NONE;
|
||
|
+ }
|
||
|
+
|
||
|
+ /* mapping to the client with new direction */
|
||
|
+ table->nents = dma_map_sg(attachment->dev, table->sgl,
|
||
|
+ table->orig_nents, direction);
|
||
|
+ if (!table->nents) {
|
||
|
+ pr_err("failed to map scatterlist\n");
|
||
|
+ mutex_unlock(lock);
|
||
|
+ return ERR_PTR(-EIO);
|
||
|
+ }
|
||
|
|
||
|
- if (!dma_map_sg(attachment->dev, table->sgl, table->nents,
|
||
|
- direction))
|
||
|
- return ERR_PTR(-ENOMEM);
|
||
|
+ a->dma_dir = direction;
|
||
|
+ mutex_unlock(lock);
|
||
|
|
||
|
pr_debug("%s attachment %p\n", __func__, attachment);
|
||
|
return table;
|
||
|
@@ -478,41 +490,26 @@ static void vc_sm_unmap_dma_buf(struct d
|
||
|
static int vc_sm_dmabuf_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma)
|
||
|
{
|
||
|
struct vc_sm_buffer *buf = dmabuf->priv;
|
||
|
- struct sg_table *table = buf->sg_table;
|
||
|
- unsigned long addr = vma->vm_start;
|
||
|
- unsigned long offset = vma->vm_pgoff * PAGE_SIZE;
|
||
|
- struct scatterlist *sg;
|
||
|
- int i;
|
||
|
- int ret = 0;
|
||
|
+ int ret;
|
||
|
|
||
|
pr_debug("%s dmabuf %p, buf %p, vm_start %08lX\n", __func__, dmabuf,
|
||
|
- buf, addr);
|
||
|
+ buf, vma->vm_start);
|
||
|
|
||
|
mutex_lock(&buf->lock);
|
||
|
|
||
|
/* now map it to userspace */
|
||
|
- for_each_sg(table->sgl, sg, table->nents, i) {
|
||
|
- struct page *page = sg_page(sg);
|
||
|
- unsigned long remainder = vma->vm_end - addr;
|
||
|
- unsigned long len = sg->length;
|
||
|
+ vma->vm_pgoff = 0;
|
||
|
|
||
|
- if (offset >= sg->length) {
|
||
|
- offset -= sg->length;
|
||
|
- continue;
|
||
|
- } else if (offset) {
|
||
|
- page += offset / PAGE_SIZE;
|
||
|
- len = sg->length - offset;
|
||
|
- offset = 0;
|
||
|
- }
|
||
|
- len = min(len, remainder);
|
||
|
- ret = remap_pfn_range(vma, addr, page_to_pfn(page), len,
|
||
|
- vma->vm_page_prot);
|
||
|
- if (ret)
|
||
|
- break;
|
||
|
- addr += len;
|
||
|
- if (addr >= vma->vm_end)
|
||
|
- break;
|
||
|
+ ret = dma_mmap_coherent(&sm_state->pdev->dev, vma, buf->cookie,
|
||
|
+ buf->dma_addr, buf->size);
|
||
|
+
|
||
|
+ if (ret) {
|
||
|
+ pr_err("Remapping memory failed, error: %d\n", ret);
|
||
|
+ return ret;
|
||
|
}
|
||
|
+
|
||
|
+ vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;
|
||
|
+
|
||
|
mutex_unlock(&buf->lock);
|
||
|
|
||
|
if (ret)
|
||
|
@@ -570,8 +567,8 @@ static int vc_sm_dma_buf_begin_cpu_acces
|
||
|
mutex_lock(&buf->lock);
|
||
|
|
||
|
list_for_each_entry(a, &buf->attachments, list) {
|
||
|
- dma_sync_sg_for_cpu(a->dev, a->table->sgl, a->table->nents,
|
||
|
- direction);
|
||
|
+ dma_sync_sg_for_cpu(a->dev, a->sg_table.sgl,
|
||
|
+ a->sg_table.nents, direction);
|
||
|
}
|
||
|
mutex_unlock(&buf->lock);
|
||
|
|
||
|
@@ -593,8 +590,8 @@ static int vc_sm_dma_buf_end_cpu_access(
|
||
|
mutex_lock(&buf->lock);
|
||
|
|
||
|
list_for_each_entry(a, &buf->attachments, list) {
|
||
|
- dma_sync_sg_for_device(a->dev, a->table->sgl, a->table->nents,
|
||
|
- direction);
|
||
|
+ dma_sync_sg_for_device(a->dev, a->sg_table.sgl,
|
||
|
+ a->sg_table.nents, direction);
|
||
|
}
|
||
|
mutex_unlock(&buf->lock);
|
||
|
|
||
|
@@ -625,7 +622,9 @@ static const struct dma_buf_ops dma_buf_
|
||
|
.map = vc_sm_dma_buf_kmap,
|
||
|
.unmap = vc_sm_dma_buf_kunmap,
|
||
|
};
|
||
|
+
|
||
|
/* Dma_buf operations for chaining through to an imported dma_buf */
|
||
|
+
|
||
|
static
|
||
|
int vc_sm_import_dma_buf_attach(struct dma_buf *dmabuf,
|
||
|
struct dma_buf_attachment *attachment)
|
||
|
@@ -819,7 +818,7 @@ vc_sm_cma_import_dmabuf_internal(struct
|
||
|
|
||
|
import.type = VC_SM_ALLOC_NON_CACHED;
|
||
|
dma_addr = sg_dma_address(sgt->sgl);
|
||
|
- import.addr = (uint32_t)dma_addr;
|
||
|
+ import.addr = (u32)dma_addr;
|
||
|
if ((import.addr & 0xC0000000) != 0xC0000000) {
|
||
|
pr_err("%s: Expecting an uncached alias for dma_addr %pad\n",
|
||
|
__func__, &dma_addr);
|
||
|
@@ -911,11 +910,12 @@ error:
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
-static int vc_sm_cma_vpu_alloc(u32 size, uint32_t align, const char *name,
|
||
|
+static int vc_sm_cma_vpu_alloc(u32 size, u32 align, const char *name,
|
||
|
u32 mem_handle, struct vc_sm_buffer **ret_buffer)
|
||
|
{
|
||
|
DEFINE_DMA_BUF_EXPORT_INFO(exp_info);
|
||
|
struct vc_sm_buffer *buffer = NULL;
|
||
|
+ struct sg_table *sgt;
|
||
|
int aligned_size;
|
||
|
int ret = 0;
|
||
|
|
||
|
@@ -938,23 +938,34 @@ static int vc_sm_cma_vpu_alloc(u32 size,
|
||
|
*/
|
||
|
mutex_lock(&buffer->lock);
|
||
|
|
||
|
- if (vc_sm_cma_buffer_allocate(sm_state->cma_heap, &buffer->alloc,
|
||
|
- aligned_size)) {
|
||
|
- pr_err("[%s]: cma alloc of %d bytes failed\n",
|
||
|
+ buffer->cookie = dma_alloc_coherent(&sm_state->pdev->dev,
|
||
|
+ aligned_size, &buffer->dma_addr,
|
||
|
+ GFP_KERNEL);
|
||
|
+ if (!buffer->cookie) {
|
||
|
+ pr_err("[%s]: dma_alloc_coherent alloc of %d bytes failed\n",
|
||
|
__func__, aligned_size);
|
||
|
ret = -ENOMEM;
|
||
|
goto error;
|
||
|
}
|
||
|
- buffer->sg_table = buffer->alloc.sg_table;
|
||
|
|
||
|
- pr_debug("[%s]: cma alloc of %d bytes success\n",
|
||
|
+ pr_debug("[%s]: alloc of %d bytes success\n",
|
||
|
__func__, aligned_size);
|
||
|
|
||
|
- if (dma_map_sg(&sm_state->pdev->dev, buffer->sg_table->sgl,
|
||
|
- buffer->sg_table->nents, DMA_BIDIRECTIONAL) <= 0) {
|
||
|
- pr_err("[%s]: dma_map_sg failed\n", __func__);
|
||
|
+ sgt = kmalloc(sizeof(*sgt), GFP_KERNEL);
|
||
|
+ if (!sgt) {
|
||
|
+ ret = -ENOMEM;
|
||
|
+ goto error;
|
||
|
+ }
|
||
|
+
|
||
|
+ ret = dma_get_sgtable(&sm_state->pdev->dev, sgt, buffer->cookie,
|
||
|
+ buffer->dma_addr, buffer->size);
|
||
|
+ if (ret < 0) {
|
||
|
+ pr_err("failed to get scatterlist from DMA API\n");
|
||
|
+ kfree(sgt);
|
||
|
+ ret = -ENOMEM;
|
||
|
goto error;
|
||
|
}
|
||
|
+ buffer->alloc.sg_table = sgt;
|
||
|
|
||
|
INIT_LIST_HEAD(&buffer->attachments);
|
||
|
|
||
|
@@ -971,10 +982,10 @@ static int vc_sm_cma_vpu_alloc(u32 size,
|
||
|
ret = PTR_ERR(buffer->dma_buf);
|
||
|
goto error;
|
||
|
}
|
||
|
- buffer->dma_addr = (uint32_t)sg_dma_address(buffer->sg_table->sgl);
|
||
|
+ buffer->dma_addr = (u32)sg_dma_address(buffer->alloc.sg_table->sgl);
|
||
|
if ((buffer->dma_addr & 0xC0000000) != 0xC0000000) {
|
||
|
- pr_err("%s: Expecting an uncached alias for dma_addr %pad\n",
|
||
|
- __func__, &buffer->dma_addr);
|
||
|
+ pr_warn_once("%s: Expecting an uncached alias for dma_addr %pad\n",
|
||
|
+ __func__, &buffer->dma_addr);
|
||
|
buffer->dma_addr |= 0xC0000000;
|
||
|
}
|
||
|
buffer->private = sm_state->vpu_allocs;
|
||
|
@@ -1145,6 +1156,7 @@ int vc_sm_cma_ioctl_alloc(struct vc_sm_p
|
||
|
struct vc_sm_import import = { 0 };
|
||
|
struct vc_sm_import_result result = { 0 };
|
||
|
struct dma_buf *dmabuf = NULL;
|
||
|
+ struct sg_table *sgt;
|
||
|
int aligned_size;
|
||
|
int ret = 0;
|
||
|
int status;
|
||
|
@@ -1162,18 +1174,13 @@ int vc_sm_cma_ioctl_alloc(struct vc_sm_p
|
||
|
goto error;
|
||
|
}
|
||
|
|
||
|
- if (vc_sm_cma_buffer_allocate(sm_state->cma_heap, &buffer->alloc,
|
||
|
- aligned_size)) {
|
||
|
- pr_err("[%s]: cma alloc of %d bytes failed\n",
|
||
|
+ buffer->cookie = dma_alloc_coherent(&sm_state->pdev->dev,
|
||
|
+ aligned_size,
|
||
|
+ &buffer->dma_addr,
|
||
|
+ GFP_KERNEL);
|
||
|
+ if (!buffer->cookie) {
|
||
|
+ pr_err("[%s]: dma_alloc_coherent alloc of %d bytes failed\n",
|
||
|
__func__, aligned_size);
|
||
|
- kfree(buffer);
|
||
|
- return -ENOMEM;
|
||
|
- }
|
||
|
- buffer->sg_table = buffer->alloc.sg_table;
|
||
|
-
|
||
|
- if (dma_map_sg(&sm_state->pdev->dev, buffer->sg_table->sgl,
|
||
|
- buffer->sg_table->nents, DMA_BIDIRECTIONAL) <= 0) {
|
||
|
- pr_err("[%s]: dma_map_sg failed\n", __func__);
|
||
|
ret = -ENOMEM;
|
||
|
goto error;
|
||
|
}
|
||
|
@@ -1204,7 +1211,7 @@ int vc_sm_cma_ioctl_alloc(struct vc_sm_p
|
||
|
}
|
||
|
buffer->dma_buf = dmabuf;
|
||
|
|
||
|
- import.addr = (uint32_t)sg_dma_address(buffer->sg_table->sgl);
|
||
|
+ import.addr = buffer->dma_addr;
|
||
|
import.size = aligned_size;
|
||
|
import.kernel_id = get_kernel_id(buffer);
|
||
|
|
||
|
@@ -1229,10 +1236,25 @@ int vc_sm_cma_ioctl_alloc(struct vc_sm_p
|
||
|
buffer->private = private;
|
||
|
buffer->vc_handle = result.res_handle;
|
||
|
buffer->size = import.size;
|
||
|
- buffer->dma_addr = import.addr;
|
||
|
buffer->vpu_state = VPU_MAPPED;
|
||
|
buffer->kernel_id = import.kernel_id;
|
||
|
- //buffer->res_cached = ioparam->cached;
|
||
|
+
|
||
|
+ sgt = kmalloc(sizeof(*sgt), GFP_KERNEL);
|
||
|
+ if (!sgt) {
|
||
|
+ ret = -ENOMEM;
|
||
|
+ goto error;
|
||
|
+ }
|
||
|
+
|
||
|
+ ret = dma_get_sgtable(&sm_state->pdev->dev, sgt, buffer->cookie,
|
||
|
+ buffer->dma_addr, buffer->size);
|
||
|
+ if (ret < 0) {
|
||
|
+ /* FIXME: error handling */
|
||
|
+ pr_err("failed to get scatterlist from DMA API\n");
|
||
|
+ kfree(sgt);
|
||
|
+ ret = -ENOMEM;
|
||
|
+ goto error;
|
||
|
+ }
|
||
|
+ buffer->alloc.sg_table = sgt;
|
||
|
|
||
|
fd = dma_buf_fd(dmabuf, O_CLOEXEC);
|
||
|
if (fd < 0)
|
||
|
@@ -1250,11 +1272,19 @@ int vc_sm_cma_ioctl_alloc(struct vc_sm_p
|
||
|
return 0;
|
||
|
|
||
|
error:
|
||
|
- if (buffer) {
|
||
|
- pr_err("[%s]: something failed - cleanup. ret %d\n", __func__,
|
||
|
- ret);
|
||
|
+ pr_err("[%s]: something failed - cleanup. ret %d\n", __func__, ret);
|
||
|
|
||
|
+ if (dmabuf) {
|
||
|
+ /* dmabuf has been exported, therefore allow dmabuf cleanup to
|
||
|
+ * deal with this
|
||
|
+ */
|
||
|
dma_buf_put(dmabuf);
|
||
|
+ } else {
|
||
|
+ /* No dmabuf, therefore just free the buffer here */
|
||
|
+ if (buffer->cookie)
|
||
|
+ dma_free_coherent(&sm_state->pdev->dev, buffer->size,
|
||
|
+ buffer->cookie, buffer->dma_addr);
|
||
|
+ kfree(buffer);
|
||
|
}
|
||
|
return ret;
|
||
|
}
|
||
|
@@ -1527,13 +1557,6 @@ static void vc_sm_connected_init(void)
|
||
|
|
||
|
pr_info("[%s]: start\n", __func__);
|
||
|
|
||
|
- vc_sm_cma_add_heaps(&sm_state->cma_heap);
|
||
|
- if (!sm_state->cma_heap) {
|
||
|
- pr_err("[%s]: failed to initialise CMA heap\n",
|
||
|
- __func__);
|
||
|
- return;
|
||
|
- }
|
||
|
-
|
||
|
/*
|
||
|
* Initialize and create a VCHI connection for the shared memory service
|
||
|
* running on videocore.
|
||
|
--- a/drivers/staging/vc04_services/vc-sm-cma/vc_sm.h
|
||
|
+++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm.h
|
||
|
@@ -21,8 +21,6 @@
|
||
|
#include <linux/types.h>
|
||
|
#include <linux/miscdevice.h>
|
||
|
|
||
|
-#include "vc_sm_cma.h"
|
||
|
-
|
||
|
#define VC_SM_MAX_NAME_LEN 32
|
||
|
|
||
|
enum vc_sm_vpu_mapping_state {
|
||
|
@@ -31,6 +29,12 @@ enum vc_sm_vpu_mapping_state {
|
||
|
VPU_UNMAPPING
|
||
|
};
|
||
|
|
||
|
+struct vc_sm_alloc_data {
|
||
|
+ unsigned long num_pages;
|
||
|
+ void *priv_virt;
|
||
|
+ struct sg_table *sg_table;
|
||
|
+};
|
||
|
+
|
||
|
struct vc_sm_imported {
|
||
|
struct dma_buf *dma_buf;
|
||
|
struct dma_buf_attachment *attach;
|
||
|
@@ -56,8 +60,6 @@ struct vc_sm_buffer {
|
||
|
int in_use:1; /* Kernel is still using this resource */
|
||
|
int imported:1; /* Imported dmabuf */
|
||
|
|
||
|
- struct sg_table *sg_table;
|
||
|
-
|
||
|
enum vc_sm_vpu_mapping_state vpu_state;
|
||
|
u32 vc_handle; /* VideoCore handle for this buffer */
|
||
|
int vpu_allocated; /*
|
||
|
@@ -69,11 +71,12 @@ struct vc_sm_buffer {
|
||
|
/* DMABUF related fields */
|
||
|
struct dma_buf *dma_buf;
|
||
|
dma_addr_t dma_addr;
|
||
|
+ void *cookie;
|
||
|
|
||
|
struct vc_sm_privdata_t *private;
|
||
|
|
||
|
union {
|
||
|
- struct vc_sm_cma_alloc_data alloc;
|
||
|
+ struct vc_sm_alloc_data alloc;
|
||
|
struct vc_sm_imported import;
|
||
|
};
|
||
|
};
|
||
|
--- a/drivers/staging/vc04_services/vc-sm-cma/vc_sm_cma.c
|
||
|
+++ /dev/null
|
||
|
@@ -1,98 +0,0 @@
|
||
|
-// SPDX-License-Identifier: GPL-2.0
|
||
|
-/*
|
||
|
- * VideoCore Shared Memory CMA allocator
|
||
|
- *
|
||
|
- * Copyright: 2018, Raspberry Pi (Trading) Ltd
|
||
|
- *
|
||
|
- * Based on the Android ION allocator
|
||
|
- * Copyright (C) Linaro 2012
|
||
|
- * Author: <benjamin.gaignard@linaro.org> for ST-Ericsson.
|
||
|
- *
|
||
|
- */
|
||
|
-
|
||
|
-#include <linux/slab.h>
|
||
|
-#include <linux/errno.h>
|
||
|
-#include <linux/err.h>
|
||
|
-#include <linux/cma.h>
|
||
|
-#include <linux/scatterlist.h>
|
||
|
-
|
||
|
-#include "vc_sm_cma.h"
|
||
|
-
|
||
|
-/* CMA heap operations functions */
|
||
|
-int vc_sm_cma_buffer_allocate(struct cma *cma_heap,
|
||
|
- struct vc_sm_cma_alloc_data *buffer,
|
||
|
- unsigned long len)
|
||
|
-{
|
||
|
- /* len should already be page aligned */
|
||
|
- unsigned long num_pages = len / PAGE_SIZE;
|
||
|
- struct sg_table *table;
|
||
|
- struct page *pages;
|
||
|
- int ret;
|
||
|
-
|
||
|
- pages = cma_alloc(cma_heap, num_pages, 0, GFP_KERNEL);
|
||
|
- if (!pages)
|
||
|
- return -ENOMEM;
|
||
|
-
|
||
|
- table = kmalloc(sizeof(*table), GFP_KERNEL);
|
||
|
- if (!table)
|
||
|
- goto err;
|
||
|
-
|
||
|
- ret = sg_alloc_table(table, 1, GFP_KERNEL);
|
||
|
- if (ret)
|
||
|
- goto free_mem;
|
||
|
-
|
||
|
- sg_set_page(table->sgl, pages, len, 0);
|
||
|
-
|
||
|
- buffer->priv_virt = pages;
|
||
|
- buffer->sg_table = table;
|
||
|
- buffer->cma_heap = cma_heap;
|
||
|
- buffer->num_pages = num_pages;
|
||
|
- return 0;
|
||
|
-
|
||
|
-free_mem:
|
||
|
- kfree(table);
|
||
|
-err:
|
||
|
- cma_release(cma_heap, pages, num_pages);
|
||
|
- return -ENOMEM;
|
||
|
-}
|
||
|
-
|
||
|
-void vc_sm_cma_buffer_free(struct vc_sm_cma_alloc_data *buffer)
|
||
|
-{
|
||
|
- struct cma *cma_heap = buffer->cma_heap;
|
||
|
- struct page *pages = buffer->priv_virt;
|
||
|
-
|
||
|
- /* release memory */
|
||
|
- if (cma_heap)
|
||
|
- cma_release(cma_heap, pages, buffer->num_pages);
|
||
|
-
|
||
|
- /* release sg table */
|
||
|
- if (buffer->sg_table) {
|
||
|
- sg_free_table(buffer->sg_table);
|
||
|
- kfree(buffer->sg_table);
|
||
|
- buffer->sg_table = NULL;
|
||
|
- }
|
||
|
-}
|
||
|
-
|
||
|
-int __vc_sm_cma_add_heaps(struct cma *cma, void *priv)
|
||
|
-{
|
||
|
- struct cma **heap = (struct cma **)priv;
|
||
|
- const char *name = cma_get_name(cma);
|
||
|
-
|
||
|
- if (!(*heap)) {
|
||
|
- phys_addr_t phys_addr = cma_get_base(cma);
|
||
|
-
|
||
|
- pr_debug("%s: Adding cma heap %s (start %pap, size %lu) for use by vcsm\n",
|
||
|
- __func__, name, &phys_addr, cma_get_size(cma));
|
||
|
- *heap = cma;
|
||
|
- } else {
|
||
|
- pr_err("%s: Ignoring heap %s as already set\n",
|
||
|
- __func__, name);
|
||
|
- }
|
||
|
-
|
||
|
- return 0;
|
||
|
-}
|
||
|
-
|
||
|
-void vc_sm_cma_add_heaps(struct cma **cma_heap)
|
||
|
-{
|
||
|
- cma_for_each_area(__vc_sm_cma_add_heaps, cma_heap);
|
||
|
-}
|
||
|
--- a/drivers/staging/vc04_services/vc-sm-cma/vc_sm_cma.h
|
||
|
+++ /dev/null
|
||
|
@@ -1,39 +0,0 @@
|
||
|
-/* SPDX-License-Identifier: GPL-2.0 */
|
||
|
-
|
||
|
-/*
|
||
|
- * VideoCore Shared Memory CMA allocator
|
||
|
- *
|
||
|
- * Copyright: 2018, Raspberry Pi (Trading) Ltd
|
||
|
- *
|
||
|
- * Based on the Android ION allocator
|
||
|
- * Copyright (C) Linaro 2012
|
||
|
- * Author: <benjamin.gaignard@linaro.org> for ST-Ericsson.
|
||
|
- *
|
||
|
- * This software is licensed under the terms of the GNU General Public
|
||
|
- * License version 2, as published by the Free Software Foundation, and
|
||
|
- * may be copied, distributed, and modified under those terms.
|
||
|
- *
|
||
|
- * This program is distributed in the hope that it will be useful,
|
||
|
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
- * GNU General Public License for more details.
|
||
|
- *
|
||
|
- */
|
||
|
-#ifndef VC_SM_CMA_H
|
||
|
-#define VC_SM_CMA_H
|
||
|
-
|
||
|
-struct vc_sm_cma_alloc_data {
|
||
|
- struct cma *cma_heap;
|
||
|
- unsigned long num_pages;
|
||
|
- void *priv_virt;
|
||
|
- struct sg_table *sg_table;
|
||
|
-};
|
||
|
-
|
||
|
-int vc_sm_cma_buffer_allocate(struct cma *cma_heap,
|
||
|
- struct vc_sm_cma_alloc_data *buffer,
|
||
|
- unsigned long len);
|
||
|
-void vc_sm_cma_buffer_free(struct vc_sm_cma_alloc_data *buffer);
|
||
|
-
|
||
|
-void vc_sm_cma_add_heaps(struct cma **cma_heap);
|
||
|
-
|
||
|
-#endif
|