mirror of
https://github.com/raspberrypi/linux.git
synced 2025-12-07 18:40:10 +00:00
staging: vc-sm-cma: Add in userspace allocation API
Replacing the functionality from the older vc-sm driver, add in a userspace API that allows allocation of buffers, and importing of dma-bufs. The driver hands out dma-buf fds, therefore much of the handling around lifespan and odd mmaps from the old driver goes away. Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
This commit is contained in:
committed by
popcornmix
parent
d88b49ef7c
commit
a24a46689c
@@ -36,6 +36,7 @@
|
|||||||
#include <linux/fs.h>
|
#include <linux/fs.h>
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
#include <linux/list.h>
|
#include <linux/list.h>
|
||||||
|
#include <linux/miscdevice.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/mm.h>
|
#include <linux/mm.h>
|
||||||
#include <linux/of_device.h>
|
#include <linux/of_device.h>
|
||||||
@@ -52,6 +53,7 @@
|
|||||||
#include "vc_sm.h"
|
#include "vc_sm.h"
|
||||||
#include "vc_sm_cma.h"
|
#include "vc_sm_cma.h"
|
||||||
#include "vc_sm_knl.h"
|
#include "vc_sm_knl.h"
|
||||||
|
#include <linux/broadcom/vc_sm_cma_ioctl.h>
|
||||||
|
|
||||||
/* ---- Private Constants and Types --------------------------------------- */
|
/* ---- Private Constants and Types --------------------------------------- */
|
||||||
|
|
||||||
@@ -83,6 +85,8 @@ struct sm_pde_t {
|
|||||||
struct sm_state_t {
|
struct sm_state_t {
|
||||||
struct platform_device *pdev;
|
struct platform_device *pdev;
|
||||||
|
|
||||||
|
struct miscdevice misc_dev;
|
||||||
|
|
||||||
struct sm_instance *sm_handle; /* Handle for videocore service. */
|
struct sm_instance *sm_handle; /* Handle for videocore service. */
|
||||||
struct cma *cma_heap;
|
struct cma *cma_heap;
|
||||||
|
|
||||||
@@ -346,7 +350,6 @@ static void vc_sm_release_resource(struct vc_sm_buffer *buffer)
|
|||||||
|
|
||||||
defer:
|
defer:
|
||||||
mutex_unlock(&buffer->lock);
|
mutex_unlock(&buffer->lock);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Create support for private data tracking. */
|
/* Create support for private data tracking. */
|
||||||
@@ -381,7 +384,7 @@ static struct sg_table *dup_sg_table(struct sg_table *table)
|
|||||||
ret = sg_alloc_table(new_table, table->nents, GFP_KERNEL);
|
ret = sg_alloc_table(new_table, table->nents, GFP_KERNEL);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
kfree(new_table);
|
kfree(new_table);
|
||||||
return ERR_PTR(-ENOMEM);
|
return ERR_PTR(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
new_sg = new_table->sgl;
|
new_sg = new_table->sgl;
|
||||||
@@ -417,7 +420,7 @@ static int vc_sm_dma_buf_attach(struct dma_buf *dmabuf,
|
|||||||
table = dup_sg_table(buf->sg_table);
|
table = dup_sg_table(buf->sg_table);
|
||||||
if (IS_ERR(table)) {
|
if (IS_ERR(table)) {
|
||||||
kfree(a);
|
kfree(a);
|
||||||
return -ENOMEM;
|
return PTR_ERR(table);
|
||||||
}
|
}
|
||||||
|
|
||||||
a->table = table;
|
a->table = table;
|
||||||
@@ -433,7 +436,7 @@ static int vc_sm_dma_buf_attach(struct dma_buf *dmabuf,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void vc_sm_dma_buf_detatch(struct dma_buf *dmabuf,
|
static void vc_sm_dma_buf_detach(struct dma_buf *dmabuf,
|
||||||
struct dma_buf_attachment *attachment)
|
struct dma_buf_attachment *attachment)
|
||||||
{
|
{
|
||||||
struct vc_sm_dma_buf_attachment *a = attachment->priv;
|
struct vc_sm_dma_buf_attachment *a = attachment->priv;
|
||||||
@@ -544,6 +547,9 @@ static void vc_sm_dma_buf_release(struct dma_buf *dmabuf)
|
|||||||
vc_sm_clean_up_dmabuf(buffer);
|
vc_sm_clean_up_dmabuf(buffer);
|
||||||
pr_debug("%s clean_up dmabuf done\n", __func__);
|
pr_debug("%s clean_up dmabuf done\n", __func__);
|
||||||
|
|
||||||
|
/* buffer->lock will be destroyed by vc_sm_release_resource if finished
|
||||||
|
* with, otherwise unlocked. Do NOT unlock here.
|
||||||
|
*/
|
||||||
vc_sm_release_resource(buffer);
|
vc_sm_release_resource(buffer);
|
||||||
pr_debug("%s done\n", __func__);
|
pr_debug("%s done\n", __func__);
|
||||||
}
|
}
|
||||||
@@ -613,7 +619,7 @@ static const struct dma_buf_ops dma_buf_ops = {
|
|||||||
.mmap = vc_sm_dmabuf_mmap,
|
.mmap = vc_sm_dmabuf_mmap,
|
||||||
.release = vc_sm_dma_buf_release,
|
.release = vc_sm_dma_buf_release,
|
||||||
.attach = vc_sm_dma_buf_attach,
|
.attach = vc_sm_dma_buf_attach,
|
||||||
.detach = vc_sm_dma_buf_detatch,
|
.detach = vc_sm_dma_buf_detach,
|
||||||
.begin_cpu_access = vc_sm_dma_buf_begin_cpu_access,
|
.begin_cpu_access = vc_sm_dma_buf_begin_cpu_access,
|
||||||
.end_cpu_access = vc_sm_dma_buf_end_cpu_access,
|
.end_cpu_access = vc_sm_dma_buf_end_cpu_access,
|
||||||
.map = vc_sm_dma_buf_kmap,
|
.map = vc_sm_dma_buf_kmap,
|
||||||
@@ -762,6 +768,7 @@ static const struct dma_buf_ops dma_buf_import_ops = {
|
|||||||
int
|
int
|
||||||
vc_sm_cma_import_dmabuf_internal(struct vc_sm_privdata_t *private,
|
vc_sm_cma_import_dmabuf_internal(struct vc_sm_privdata_t *private,
|
||||||
struct dma_buf *dma_buf,
|
struct dma_buf *dma_buf,
|
||||||
|
int fd,
|
||||||
struct dma_buf **imported_buf)
|
struct dma_buf **imported_buf)
|
||||||
{
|
{
|
||||||
DEFINE_DMA_BUF_EXPORT_INFO(exp_info);
|
DEFINE_DMA_BUF_EXPORT_INFO(exp_info);
|
||||||
@@ -775,10 +782,15 @@ vc_sm_cma_import_dmabuf_internal(struct vc_sm_privdata_t *private,
|
|||||||
int status;
|
int status;
|
||||||
|
|
||||||
/* Setup our allocation parameters */
|
/* Setup our allocation parameters */
|
||||||
pr_debug("%s: importing dma_buf %p\n", __func__, dma_buf);
|
pr_debug("%s: importing dma_buf %p/fd %d\n", __func__, dma_buf, fd);
|
||||||
|
|
||||||
|
if (fd < 0)
|
||||||
get_dma_buf(dma_buf);
|
get_dma_buf(dma_buf);
|
||||||
dma_buf = dma_buf;
|
else
|
||||||
|
dma_buf = dma_buf_get(fd);
|
||||||
|
|
||||||
|
if (!dma_buf)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
attach = dma_buf_attach(dma_buf, &sm_state->pdev->dev);
|
attach = dma_buf_attach(dma_buf, &sm_state->pdev->dev);
|
||||||
if (IS_ERR(attach)) {
|
if (IS_ERR(attach)) {
|
||||||
@@ -921,6 +933,10 @@ static int vc_sm_cma_vpu_alloc(u32 size, uint32_t align, const char *name,
|
|||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
mutex_init(&buffer->lock);
|
mutex_init(&buffer->lock);
|
||||||
|
/* Acquire the mutex as vc_sm_release_resource will release it in the
|
||||||
|
* error path.
|
||||||
|
*/
|
||||||
|
mutex_lock(&buffer->lock);
|
||||||
|
|
||||||
if (vc_sm_cma_buffer_allocate(sm_state->cma_heap, &buffer->alloc,
|
if (vc_sm_cma_buffer_allocate(sm_state->cma_heap, &buffer->alloc,
|
||||||
aligned_size)) {
|
aligned_size)) {
|
||||||
@@ -976,6 +992,8 @@ static int vc_sm_cma_vpu_alloc(u32 size, uint32_t align, const char *name,
|
|||||||
|
|
||||||
vc_sm_add_resource(sm_state->vpu_allocs, buffer);
|
vc_sm_add_resource(sm_state->vpu_allocs, buffer);
|
||||||
|
|
||||||
|
mutex_unlock(&buffer->lock);
|
||||||
|
|
||||||
*ret_buffer = buffer;
|
*ret_buffer = buffer;
|
||||||
return 0;
|
return 0;
|
||||||
error:
|
error:
|
||||||
@@ -1065,6 +1083,297 @@ vc_sm_vpu_event(struct sm_instance *instance, struct vc_sm_result_t *reply,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Userspace handling */
|
||||||
|
/*
|
||||||
|
* Open the device. Creates a private state to help track all allocation
|
||||||
|
* associated with this device.
|
||||||
|
*/
|
||||||
|
static int vc_sm_cma_open(struct inode *inode, struct file *file)
|
||||||
|
{
|
||||||
|
/* Make sure the device was started properly. */
|
||||||
|
if (!sm_state) {
|
||||||
|
pr_err("[%s]: invalid device\n", __func__);
|
||||||
|
return -EPERM;
|
||||||
|
}
|
||||||
|
|
||||||
|
file->private_data = vc_sm_cma_create_priv_data(current->tgid);
|
||||||
|
if (!file->private_data) {
|
||||||
|
pr_err("[%s]: failed to create data tracker\n", __func__);
|
||||||
|
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Close the vcsm-cma device.
|
||||||
|
* All allocations are file descriptors to the dmabuf objects, so we will get
|
||||||
|
* the clean up request on those as those are cleaned up.
|
||||||
|
*/
|
||||||
|
static int vc_sm_cma_release(struct inode *inode, struct file *file)
|
||||||
|
{
|
||||||
|
struct vc_sm_privdata_t *file_data =
|
||||||
|
(struct vc_sm_privdata_t *)file->private_data;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
/* Make sure the device was started properly. */
|
||||||
|
if (!sm_state || !file_data) {
|
||||||
|
pr_err("[%s]: invalid device\n", __func__);
|
||||||
|
ret = -EPERM;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
pr_debug("[%s]: using private data %p\n", __func__, file_data);
|
||||||
|
|
||||||
|
/* Terminate the private data. */
|
||||||
|
kfree(file_data);
|
||||||
|
|
||||||
|
out:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Allocate a shared memory handle and block.
|
||||||
|
* Allocation is from CMA, and then imported into the VPU mappings.
|
||||||
|
*/
|
||||||
|
int vc_sm_cma_ioctl_alloc(struct vc_sm_privdata_t *private,
|
||||||
|
struct vc_sm_cma_ioctl_alloc *ioparam)
|
||||||
|
{
|
||||||
|
DEFINE_DMA_BUF_EXPORT_INFO(exp_info);
|
||||||
|
struct vc_sm_buffer *buffer = NULL;
|
||||||
|
struct vc_sm_import import = { 0 };
|
||||||
|
struct vc_sm_import_result result = { 0 };
|
||||||
|
struct dma_buf *dmabuf = NULL;
|
||||||
|
int aligned_size;
|
||||||
|
int ret = 0;
|
||||||
|
int status;
|
||||||
|
int fd = -1;
|
||||||
|
|
||||||
|
aligned_size = PAGE_ALIGN(ioparam->size);
|
||||||
|
|
||||||
|
if (!aligned_size)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
/* Allocate local buffer to track this allocation. */
|
||||||
|
buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
|
||||||
|
if (!buffer) {
|
||||||
|
ret = -ENOMEM;
|
||||||
|
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",
|
||||||
|
__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;
|
||||||
|
}
|
||||||
|
|
||||||
|
import.type = VC_SM_ALLOC_NON_CACHED;
|
||||||
|
import.allocator = current->tgid;
|
||||||
|
|
||||||
|
if (*ioparam->name)
|
||||||
|
memcpy(import.name, ioparam->name, sizeof(import.name) - 1);
|
||||||
|
else
|
||||||
|
memcpy(import.name, VC_SM_RESOURCE_NAME_DEFAULT,
|
||||||
|
sizeof(VC_SM_RESOURCE_NAME_DEFAULT));
|
||||||
|
|
||||||
|
mutex_init(&buffer->lock);
|
||||||
|
INIT_LIST_HEAD(&buffer->attachments);
|
||||||
|
memcpy(buffer->name, import.name,
|
||||||
|
min(sizeof(buffer->name), sizeof(import.name) - 1));
|
||||||
|
|
||||||
|
exp_info.ops = &dma_buf_ops;
|
||||||
|
exp_info.size = aligned_size;
|
||||||
|
exp_info.flags = O_RDWR;
|
||||||
|
exp_info.priv = buffer;
|
||||||
|
|
||||||
|
dmabuf = dma_buf_export(&exp_info);
|
||||||
|
if (IS_ERR(dmabuf)) {
|
||||||
|
ret = PTR_ERR(dmabuf);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
buffer->dma_buf = dmabuf;
|
||||||
|
|
||||||
|
import.addr = (uint32_t)sg_dma_address(buffer->sg_table->sgl);
|
||||||
|
import.size = aligned_size;
|
||||||
|
import.kernel_id = (uint32_t)buffer;
|
||||||
|
|
||||||
|
/* Wrap it into a videocore buffer. */
|
||||||
|
status = vc_sm_cma_vchi_import(sm_state->sm_handle, &import, &result,
|
||||||
|
&sm_state->int_trans_id);
|
||||||
|
if (status == -EINTR) {
|
||||||
|
pr_debug("[%s]: requesting import memory action restart (trans_id: %u)\n",
|
||||||
|
__func__, sm_state->int_trans_id);
|
||||||
|
ret = -ERESTARTSYS;
|
||||||
|
private->restart_sys = -EINTR;
|
||||||
|
private->int_action = VC_SM_MSG_TYPE_IMPORT;
|
||||||
|
goto error;
|
||||||
|
} else if (status || !result.res_handle) {
|
||||||
|
pr_err("[%s]: failed to import memory on videocore (status: %u, trans_id: %u)\n",
|
||||||
|
__func__, status, sm_state->int_trans_id);
|
||||||
|
ret = -ENOMEM;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Keep track of the buffer we created. */
|
||||||
|
buffer->private = private;
|
||||||
|
buffer->vc_handle = result.res_handle;
|
||||||
|
buffer->size = import.size;
|
||||||
|
buffer->dma_addr = import.addr;
|
||||||
|
buffer->vpu_state = VPU_MAPPED;
|
||||||
|
//buffer->res_cached = ioparam->cached;
|
||||||
|
|
||||||
|
fd = dma_buf_fd(dmabuf, O_CLOEXEC);
|
||||||
|
if (fd < 0)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
vc_sm_add_resource(private, buffer);
|
||||||
|
|
||||||
|
pr_debug("[%s]: Added resource as fd %d, buffer %p, private %p, dma_addr %pad\n",
|
||||||
|
__func__, fd, buffer, private, &buffer->dma_addr);
|
||||||
|
|
||||||
|
/* We're done */
|
||||||
|
ioparam->handle = fd;
|
||||||
|
ioparam->vc_handle = buffer->vc_handle;
|
||||||
|
ioparam->dma_addr = buffer->dma_addr;
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
error:
|
||||||
|
if (buffer) {
|
||||||
|
pr_err("[%s]: something failed - cleanup. ret %d\n", __func__,
|
||||||
|
ret);
|
||||||
|
|
||||||
|
dma_buf_put(dmabuf);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static long vc_sm_cma_ioctl(struct file *file, unsigned int cmd,
|
||||||
|
unsigned long arg)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
unsigned int cmdnr = _IOC_NR(cmd);
|
||||||
|
struct vc_sm_privdata_t *file_data =
|
||||||
|
(struct vc_sm_privdata_t *)file->private_data;
|
||||||
|
|
||||||
|
/* Validate we can work with this device. */
|
||||||
|
if (!sm_state || !file_data) {
|
||||||
|
pr_err("[%s]: invalid device\n", __func__);
|
||||||
|
return -EPERM;
|
||||||
|
}
|
||||||
|
|
||||||
|
pr_debug("[%s]: cmd %x tgid %u, owner %u\n", __func__, cmdnr,
|
||||||
|
current->tgid, file_data->pid);
|
||||||
|
|
||||||
|
/* Action is a re-post of a previously interrupted action? */
|
||||||
|
if (file_data->restart_sys == -EINTR) {
|
||||||
|
struct vc_sm_action_clean_t action_clean;
|
||||||
|
|
||||||
|
pr_debug("[%s]: clean up of action %u (trans_id: %u) following EINTR\n",
|
||||||
|
__func__, file_data->int_action,
|
||||||
|
file_data->int_trans_id);
|
||||||
|
|
||||||
|
action_clean.res_action = file_data->int_action;
|
||||||
|
action_clean.action_trans_id = file_data->int_trans_id;
|
||||||
|
|
||||||
|
file_data->restart_sys = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now process the command. */
|
||||||
|
switch (cmdnr) {
|
||||||
|
/* New memory allocation.
|
||||||
|
*/
|
||||||
|
case VC_SM_CMA_CMD_ALLOC:
|
||||||
|
{
|
||||||
|
struct vc_sm_cma_ioctl_alloc ioparam;
|
||||||
|
|
||||||
|
/* Get the parameter data. */
|
||||||
|
if (copy_from_user
|
||||||
|
(&ioparam, (void *)arg, sizeof(ioparam)) != 0) {
|
||||||
|
pr_err("[%s]: failed to copy-from-user for cmd %x\n",
|
||||||
|
__func__, cmdnr);
|
||||||
|
ret = -EFAULT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = vc_sm_cma_ioctl_alloc(file_data, &ioparam);
|
||||||
|
if (!ret &&
|
||||||
|
(copy_to_user((void *)arg, &ioparam,
|
||||||
|
sizeof(ioparam)) != 0)) {
|
||||||
|
/* FIXME: Release allocation */
|
||||||
|
pr_err("[%s]: failed to copy-to-user for cmd %x\n",
|
||||||
|
__func__, cmdnr);
|
||||||
|
ret = -EFAULT;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case VC_SM_CMA_CMD_IMPORT_DMABUF:
|
||||||
|
{
|
||||||
|
struct vc_sm_cma_ioctl_import_dmabuf ioparam;
|
||||||
|
struct dma_buf *new_dmabuf;
|
||||||
|
|
||||||
|
/* Get the parameter data. */
|
||||||
|
if (copy_from_user
|
||||||
|
(&ioparam, (void *)arg, sizeof(ioparam)) != 0) {
|
||||||
|
pr_err("[%s]: failed to copy-from-user for cmd %x\n",
|
||||||
|
__func__, cmdnr);
|
||||||
|
ret = -EFAULT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = vc_sm_cma_import_dmabuf_internal(file_data,
|
||||||
|
NULL,
|
||||||
|
ioparam.dmabuf_fd,
|
||||||
|
&new_dmabuf);
|
||||||
|
|
||||||
|
if (!ret) {
|
||||||
|
struct vc_sm_buffer *buf = new_dmabuf->priv;
|
||||||
|
|
||||||
|
ioparam.size = buf->size;
|
||||||
|
ioparam.handle = dma_buf_fd(new_dmabuf,
|
||||||
|
O_CLOEXEC);
|
||||||
|
ioparam.vc_handle = buf->vc_handle;
|
||||||
|
ioparam.dma_addr = buf->dma_addr;
|
||||||
|
|
||||||
|
if (ioparam.handle < 0 ||
|
||||||
|
(copy_to_user((void *)arg, &ioparam,
|
||||||
|
sizeof(ioparam)) != 0)) {
|
||||||
|
dma_buf_put(new_dmabuf);
|
||||||
|
/* FIXME: Release allocation */
|
||||||
|
ret = -EFAULT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
ret = -EINVAL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Device operations that we managed in this driver. */
|
||||||
|
static const struct file_operations vc_sm_ops = {
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
.unlocked_ioctl = vc_sm_cma_ioctl,
|
||||||
|
.open = vc_sm_cma_open,
|
||||||
|
.release = vc_sm_cma_release,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Driver load/unload functions */
|
||||||
/* Videocore connected. */
|
/* Videocore connected. */
|
||||||
static void vc_sm_connected_init(void)
|
static void vc_sm_connected_init(void)
|
||||||
{
|
{
|
||||||
@@ -1075,12 +1384,11 @@ static void vc_sm_connected_init(void)
|
|||||||
|
|
||||||
pr_info("[%s]: start\n", __func__);
|
pr_info("[%s]: start\n", __func__);
|
||||||
|
|
||||||
if (vc_sm_cma_add_heaps(&sm_state->cma_heap) ||
|
vc_sm_cma_add_heaps(&sm_state->cma_heap);
|
||||||
!sm_state->cma_heap) {
|
if (!sm_state->cma_heap) {
|
||||||
pr_err("[%s]: failed to initialise CMA heaps\n",
|
pr_err("[%s]: failed to initialise CMA heap\n",
|
||||||
__func__);
|
__func__);
|
||||||
ret = -EIO;
|
return;
|
||||||
goto err_free_mem;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1092,8 +1400,7 @@ static void vc_sm_connected_init(void)
|
|||||||
pr_err("[%s]: failed to initialise VCHI instance (ret=%d)\n",
|
pr_err("[%s]: failed to initialise VCHI instance (ret=%d)\n",
|
||||||
__func__, ret);
|
__func__, ret);
|
||||||
|
|
||||||
ret = -EIO;
|
return;
|
||||||
goto err_failed;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = vchi_connect(vchi_instance);
|
ret = vchi_connect(vchi_instance);
|
||||||
@@ -1101,8 +1408,7 @@ static void vc_sm_connected_init(void)
|
|||||||
pr_err("[%s]: failed to connect VCHI instance (ret=%d)\n",
|
pr_err("[%s]: failed to connect VCHI instance (ret=%d)\n",
|
||||||
__func__, ret);
|
__func__, ret);
|
||||||
|
|
||||||
ret = -EIO;
|
return;
|
||||||
goto err_failed;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Initialize an instance of the shared memory service. */
|
/* Initialize an instance of the shared memory service. */
|
||||||
@@ -1112,8 +1418,7 @@ static void vc_sm_connected_init(void)
|
|||||||
pr_err("[%s]: failed to initialize shared memory service\n",
|
pr_err("[%s]: failed to initialize shared memory service\n",
|
||||||
__func__);
|
__func__);
|
||||||
|
|
||||||
ret = -EPERM;
|
return;
|
||||||
goto err_failed;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Create a debug fs directory entry (root). */
|
/* Create a debug fs directory entry (root). */
|
||||||
@@ -1127,11 +1432,22 @@ static void vc_sm_connected_init(void)
|
|||||||
|
|
||||||
INIT_LIST_HEAD(&sm_state->buffer_list);
|
INIT_LIST_HEAD(&sm_state->buffer_list);
|
||||||
|
|
||||||
|
/* Create a shared memory device. */
|
||||||
|
sm_state->misc_dev.minor = MISC_DYNAMIC_MINOR;
|
||||||
|
sm_state->misc_dev.name = DEVICE_NAME;
|
||||||
|
sm_state->misc_dev.fops = &vc_sm_ops;
|
||||||
|
sm_state->misc_dev.parent = NULL;
|
||||||
|
ret = misc_register(&sm_state->misc_dev);
|
||||||
|
if (ret) {
|
||||||
|
pr_err("vcsm-cma: failed to register misc device.\n");
|
||||||
|
goto err_remove_debugfs;
|
||||||
|
}
|
||||||
|
|
||||||
sm_state->data_knl = vc_sm_cma_create_priv_data(0);
|
sm_state->data_knl = vc_sm_cma_create_priv_data(0);
|
||||||
if (!sm_state->data_knl) {
|
if (!sm_state->data_knl) {
|
||||||
pr_err("[%s]: failed to create kernel private data tracker\n",
|
pr_err("[%s]: failed to create kernel private data tracker\n",
|
||||||
__func__);
|
__func__);
|
||||||
goto err_remove_shared_memory;
|
goto err_remove_misc_dev;
|
||||||
}
|
}
|
||||||
|
|
||||||
version.version = 2;
|
version.version = 2;
|
||||||
@@ -1148,11 +1464,13 @@ static void vc_sm_connected_init(void)
|
|||||||
pr_info("[%s]: installed successfully\n", __func__);
|
pr_info("[%s]: installed successfully\n", __func__);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
err_remove_shared_memory:
|
err_remove_misc_dev:
|
||||||
|
misc_deregister(&sm_state->misc_dev);
|
||||||
|
err_remove_debugfs:
|
||||||
debugfs_remove_recursive(sm_state->dir_root);
|
debugfs_remove_recursive(sm_state->dir_root);
|
||||||
vc_sm_cma_vchi_stop(&sm_state->sm_handle);
|
vc_sm_cma_vchi_stop(&sm_state->sm_handle);
|
||||||
err_failed:
|
|
||||||
pr_info("[%s]: failed, ret %d\n", __func__, ret);
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Driver loading. */
|
/* Driver loading. */
|
||||||
@@ -1184,6 +1502,8 @@ static int bcm2835_vc_sm_cma_remove(struct platform_device *pdev)
|
|||||||
{
|
{
|
||||||
pr_debug("[%s]: start\n", __func__);
|
pr_debug("[%s]: start\n", __func__);
|
||||||
if (sm_inited) {
|
if (sm_inited) {
|
||||||
|
misc_deregister(&sm_state->misc_dev);
|
||||||
|
|
||||||
/* Remove all proc entries. */
|
/* Remove all proc entries. */
|
||||||
debugfs_remove_recursive(sm_state->dir_root);
|
debugfs_remove_recursive(sm_state->dir_root);
|
||||||
|
|
||||||
@@ -1202,6 +1522,7 @@ static int bcm2835_vc_sm_cma_remove(struct platform_device *pdev)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Kernel API calls */
|
||||||
/* Get an internal resource handle mapped from the external one. */
|
/* Get an internal resource handle mapped from the external one. */
|
||||||
int vc_sm_cma_int_handle(void *handle)
|
int vc_sm_cma_int_handle(void *handle)
|
||||||
{
|
{
|
||||||
@@ -1252,7 +1573,7 @@ int vc_sm_cma_import_dmabuf(struct dma_buf *src_dmabuf, void **handle)
|
|||||||
}
|
}
|
||||||
|
|
||||||
ret = vc_sm_cma_import_dmabuf_internal(sm_state->data_knl, src_dmabuf,
|
ret = vc_sm_cma_import_dmabuf_internal(sm_state->data_knl, src_dmabuf,
|
||||||
&new_dma_buf);
|
-1, &new_dma_buf);
|
||||||
|
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
pr_debug("%s: imported to ptr %p\n", __func__, new_dma_buf);
|
pr_debug("%s: imported to ptr %p\n", __func__, new_dma_buf);
|
||||||
|
|||||||
@@ -92,8 +92,7 @@ int __vc_sm_cma_add_heaps(struct cma *cma, void *priv)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int vc_sm_cma_add_heaps(struct cma **cma_heap)
|
void vc_sm_cma_add_heaps(struct cma **cma_heap)
|
||||||
{
|
{
|
||||||
cma_for_each_area(__vc_sm_cma_add_heaps, cma_heap);
|
cma_for_each_area(__vc_sm_cma_add_heaps, cma_heap);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,6 +34,6 @@ int vc_sm_cma_buffer_allocate(struct cma *cma_heap,
|
|||||||
unsigned long len);
|
unsigned long len);
|
||||||
void vc_sm_cma_buffer_free(struct vc_sm_cma_alloc_data *buffer);
|
void vc_sm_cma_buffer_free(struct vc_sm_cma_alloc_data *buffer);
|
||||||
|
|
||||||
int vc_sm_cma_add_heaps(struct cma **cma_heap);
|
void vc_sm_cma_add_heaps(struct cma **cma_heap);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
87
include/linux/broadcom/vc_sm_cma_ioctl.h
Normal file
87
include/linux/broadcom/vc_sm_cma_ioctl.h
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
/* SPDX-License-Identifier: GPL-2.0 */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright 2019 Raspberry Pi (Trading) Ltd. All rights reserved.
|
||||||
|
*
|
||||||
|
* Based on vmcs_sm_ioctl.h Copyright Broadcom Corporation.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __VC_SM_CMA_IOCTL_H
|
||||||
|
#define __VC_SM_CMA_IOCTL_H
|
||||||
|
|
||||||
|
/* ---- Include Files ---------------------------------------------------- */
|
||||||
|
|
||||||
|
#if defined(__KERNEL__)
|
||||||
|
#include <linux/types.h> /* Needed for standard types */
|
||||||
|
#else
|
||||||
|
#include <stdint.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <linux/ioctl.h>
|
||||||
|
|
||||||
|
/* ---- Constants and Types ---------------------------------------------- */
|
||||||
|
|
||||||
|
#define VC_SM_CMA_RESOURCE_NAME 32
|
||||||
|
#define VC_SM_CMA_RESOURCE_NAME_DEFAULT "sm-host-resource"
|
||||||
|
|
||||||
|
/* Type define used to create unique IOCTL number */
|
||||||
|
#define VC_SM_CMA_MAGIC_TYPE 'J'
|
||||||
|
|
||||||
|
/* IOCTL commands on /dev/vc-sm-cma */
|
||||||
|
enum vc_sm_cma_cmd_e {
|
||||||
|
VC_SM_CMA_CMD_ALLOC = 0x5A, /* Start at 0x5A arbitrarily */
|
||||||
|
|
||||||
|
VC_SM_CMA_CMD_IMPORT_DMABUF,
|
||||||
|
|
||||||
|
VC_SM_CMA_CMD_LAST /* Do not delete */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Cache type supported, conveniently matches the user space definition in
|
||||||
|
* user-vcsm.h.
|
||||||
|
*/
|
||||||
|
enum vc_sm_cma_cache_e {
|
||||||
|
VC_SM_CMA_CACHE_NONE,
|
||||||
|
VC_SM_CMA_CACHE_HOST,
|
||||||
|
VC_SM_CMA_CACHE_VC,
|
||||||
|
VC_SM_CMA_CACHE_BOTH,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* IOCTL Data structures */
|
||||||
|
struct vc_sm_cma_ioctl_alloc {
|
||||||
|
/* user -> kernel */
|
||||||
|
__u32 size;
|
||||||
|
__u32 num;
|
||||||
|
__u32 cached; /* enum vc_sm_cma_cache_e */
|
||||||
|
__u32 pad;
|
||||||
|
__u8 name[VC_SM_CMA_RESOURCE_NAME];
|
||||||
|
|
||||||
|
/* kernel -> user */
|
||||||
|
__s32 handle;
|
||||||
|
__u32 vc_handle;
|
||||||
|
__u64 dma_addr;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct vc_sm_cma_ioctl_import_dmabuf {
|
||||||
|
/* user -> kernel */
|
||||||
|
__s32 dmabuf_fd;
|
||||||
|
__u32 cached; /* enum vc_sm_cma_cache_e */
|
||||||
|
__u8 name[VC_SM_CMA_RESOURCE_NAME];
|
||||||
|
|
||||||
|
/* kernel -> user */
|
||||||
|
__s32 handle;
|
||||||
|
__u32 vc_handle;
|
||||||
|
__u32 size;
|
||||||
|
__u32 pad;
|
||||||
|
__u64 dma_addr;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* IOCTL numbers */
|
||||||
|
#define VC_SM_CMA_IOCTL_MEM_ALLOC\
|
||||||
|
_IOR(VC_SM_CMA_MAGIC_TYPE, VC_SM_CMA_CMD_ALLOC,\
|
||||||
|
struct vc_sm_cma_ioctl_alloc)
|
||||||
|
|
||||||
|
#define VC_SM_CMA_IOCTL_MEM_IMPORT_DMABUF\
|
||||||
|
_IOR(VC_SM_CMA_MAGIC_TYPE, VC_SM_CMA_CMD_IMPORT_DMABUF,\
|
||||||
|
struct vc_sm_cma_ioctl_import_dmabuf)
|
||||||
|
|
||||||
|
#endif /* __VC_SM_CMA_IOCTL_H */
|
||||||
Reference in New Issue
Block a user