// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2011-2018, The Linux Foundation. All rights reserved.
// Copyright (c) 2018, Linaro Limited
#include <linux/completion.h>
#include <linux/device.h>
#include <linux/dma-buf.h>
#include <linux/dma-mapping.h>
#include <linux/idr.h>
#include <linux/list.h>
#include <linux/miscdevice.h>
#include <linux/module.h>
#include <linux/of_address.h>
#include <linux/of.h>
#include <linux/sort.h>
#include <linux/of_platform.h>
#include <linux/rpmsg.h>
#include <linux/scatterlist.h>
#include <linux/slab.h>
#include <uapi/misc/fastrpc.h>
#define ADSP_DOMAIN_ID (0)
#define MDSP_DOMAIN_ID (1)
#define SDSP_DOMAIN_ID (2)
#define CDSP_DOMAIN_ID (3)
#define FASTRPC_DEV_MAX 4 /* adsp, mdsp, slpi, cdsp*/
#define FASTRPC_MAX_SESSIONS 9 /*8 compute, 1 cpz*/
#define FASTRPC_ALIGN 128
#define FASTRPC_MAX_FDLIST 16
#define FASTRPC_MAX_CRCLIST 64
#define FASTRPC_PHYS(p) ((p) & 0xffffffff)
#define FASTRPC_CTX_MAX (256)
#define FASTRPC_INIT_HANDLE 1
#define FASTRPC_CTXID_MASK (0xFF0)
#define INIT_FILELEN_MAX (64 * 1024 * 1024)
#define FASTRPC_DEVICE_NAME "fastrpc"
/* Retrives number of input buffers from the scalars parameter */
#define REMOTE_SCALARS_INBUFS(sc) (((sc) >> 16) & 0x0ff)
/* Retrives number of output buffers from the scalars parameter */
#define REMOTE_SCALARS_OUTBUFS(sc) (((sc) >> 8) & 0x0ff)
/* Retrives number of input handles from the scalars parameter */
#define REMOTE_SCALARS_INHANDLES(sc) (((sc) >> 4) & 0x0f)
/* Retrives number of output handles from the scalars parameter */
#define REMOTE_SCALARS_OUTHANDLES(sc) ((sc) & 0x0f)
#define REMOTE_SCALARS_LENGTH(sc) (REMOTE_SCALARS_INBUFS(sc) + \
REMOTE_SCALARS_OUTBUFS(sc) + \
REMOTE_SCALARS_INHANDLES(sc)+ \
REMOTE_SCALARS_OUTHANDLES(sc))
#define FASTRPC_BUILD_SCALARS(attr, method, in, out, oin, oout) \
(((attr & 0x07) << 29) | \
((method & 0x1f) << 24) | \
((in & 0xff) << 16) | \
((out & 0xff) << 8) | \
((oin & 0x0f) << 4) | \
(oout & 0x0f))
#define FASTRPC_SCALARS(method, in, out) \
FASTRPC_BUILD_SCALARS(0, method, in, out, 0, 0)
#define FASTRPC_CREATE_PROCESS_NARGS 6
/* Remote Method id table */
#define FASTRPC_RMID_INIT_ATTACH 0
#define FASTRPC_RMID_INIT_RELEASE 1
#define FASTRPC_RMID_INIT_CREATE 6
#define FASTRPC_RMID_INIT_CREATE_ATTR 7
#define FASTRPC_RMID_INIT_CREATE_STATIC 8
#define miscdev_to_cctx(d) container_of(d, struct fastrpc_channel_ctx, miscdev)
static const char *domains[FASTRPC_DEV_MAX] = { "adsp", "mdsp",
"sdsp", "cdsp"};
struct fastrpc_phy_page {
u64 addr; /* physical address */
u64 size; /* size of contiguous region */
};
struct fastrpc_invoke_buf {
u32 num; /* number of contiguous regions */
u32 pgidx; /* index to start of contiguous region */
};
struct fastrpc_remote_arg {
u64 pv;
u64 len;
};
struct fastrpc_msg {
int pid; /* process group id */
int tid; /* thread id */
u64 ctx; /* invoke caller context */
u32 handle; /* handle to invoke */
u32 sc; /* scalars structure describing the data */
u64 addr; /* physical address */
u64 size; /* size of contiguous region */
};
struct fastrpc_invoke_rsp {
u64 ctx; /* invoke caller context */
int retval; /* invoke return value */
};
struct fastrpc_buf_overlap {
u64 start;
u64 end;
int raix;
u64 mstart;
u64 mend;
u64 offset;
};
struct fastrpc_buf {
struct fastrpc_user *fl;
struct dma_buf *dmabuf;
struct device *dev;
void *virt;
u64 phys;
u64 size;
/* Lock for dma buf attachments */
struct mutex lock;
struct list_head attachments;
};
struct fastrpc_dma_buf_attachment {
struct device *dev;
struct sg_table sgt;
struct list_head node;
};
struct fastrpc_map {
struct list_head node;
struct fastrpc_user *fl;
int fd;
struct dma_buf *buf;
struct sg_table *table;
struct dma_buf_attachment *attach;
u64 phys;
u64 size;
void *va;
u64 len;
struct kref refcount;
};
struct fastrpc_invoke_ctx {
int nscalars;
int nbufs;
int retval;
int pid;
int tgid;
u32 sc;
u32 *crc;
u64 ctxid;
u64 msg_sz;
struct kref refcount;
struct list_head node; /* list of ctxs */
struct completion work;
struct work_struct put_work;
struct fastrpc_msg msg;
struct fastrpc_user *fl;
struct fastrpc_remote_arg *rpra;
struct fastrpc_map **maps;
struct fastrpc_buf *buf;
struct fastrpc_invoke_args *args;
struct fastrpc_buf_overlap *olaps;
struct fastrpc_channel_ctx *cctx;
};
struct fastrpc_session_ctx {
struct device *dev;
int sid;
bool used;
bool valid;
};
struct fastrpc_channel_ctx {
int domain_id;
int sesscount;
struct rpmsg_device *rpdev;
struct fastrpc_session_ctx session[FASTRPC_MAX_SESSIONS];
spinlock_t lock;
struct idr ctx_idr;
struct list_head users;
struct miscdevice miscdev;
struct kref refcount;
};
struct fastrpc_user {
struct list_head user;
struct list_head maps;
struct list_head pending;
struct fastrpc_channel_ctx *cctx;
struct fastrpc_session_ctx *sctx;
struct fastrpc_buf *init_mem;
int tgid;
int pd;
/* Lock for lists */
spinlock_t lock;
/* lock for allocations */
struct mutex mutex;
};
static void fastrpc_free_map(struct kref *ref)
{
struct fastrpc_map *map;
map = container_of(ref, struct fastrpc_map, refcount);
if (map->table) {
dma_buf_unmap_attachment(map->attach, map->table,
DMA_BIDIRECTIONAL);
dma_buf_detach(map->buf, map->attach);
dma_buf_put(map->buf);
}
if (map->fl) {
spin_lock(&map->fl->lock);
list_del(&map->node);
spin_unlock(&map->fl->lock);
map->fl = NULL;
}
kfree(map);
|