162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci// Copyright (c) 2011-2018, The Linux Foundation. All rights reserved.
362306a36Sopenharmony_ci// Copyright (c) 2018, Linaro Limited
462306a36Sopenharmony_ci
562306a36Sopenharmony_ci#include <linux/completion.h>
662306a36Sopenharmony_ci#include <linux/device.h>
762306a36Sopenharmony_ci#include <linux/dma-buf.h>
862306a36Sopenharmony_ci#include <linux/dma-mapping.h>
962306a36Sopenharmony_ci#include <linux/dma-resv.h>
1062306a36Sopenharmony_ci#include <linux/idr.h>
1162306a36Sopenharmony_ci#include <linux/list.h>
1262306a36Sopenharmony_ci#include <linux/miscdevice.h>
1362306a36Sopenharmony_ci#include <linux/module.h>
1462306a36Sopenharmony_ci#include <linux/of_address.h>
1562306a36Sopenharmony_ci#include <linux/of.h>
1662306a36Sopenharmony_ci#include <linux/platform_device.h>
1762306a36Sopenharmony_ci#include <linux/sort.h>
1862306a36Sopenharmony_ci#include <linux/of_platform.h>
1962306a36Sopenharmony_ci#include <linux/rpmsg.h>
2062306a36Sopenharmony_ci#include <linux/scatterlist.h>
2162306a36Sopenharmony_ci#include <linux/slab.h>
2262306a36Sopenharmony_ci#include <linux/firmware/qcom/qcom_scm.h>
2362306a36Sopenharmony_ci#include <uapi/misc/fastrpc.h>
2462306a36Sopenharmony_ci#include <linux/of_reserved_mem.h>
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci#define ADSP_DOMAIN_ID (0)
2762306a36Sopenharmony_ci#define MDSP_DOMAIN_ID (1)
2862306a36Sopenharmony_ci#define SDSP_DOMAIN_ID (2)
2962306a36Sopenharmony_ci#define CDSP_DOMAIN_ID (3)
3062306a36Sopenharmony_ci#define FASTRPC_DEV_MAX		4 /* adsp, mdsp, slpi, cdsp*/
3162306a36Sopenharmony_ci#define FASTRPC_MAX_SESSIONS	14
3262306a36Sopenharmony_ci#define FASTRPC_MAX_VMIDS	16
3362306a36Sopenharmony_ci#define FASTRPC_ALIGN		128
3462306a36Sopenharmony_ci#define FASTRPC_MAX_FDLIST	16
3562306a36Sopenharmony_ci#define FASTRPC_MAX_CRCLIST	64
3662306a36Sopenharmony_ci#define FASTRPC_PHYS(p)	((p) & 0xffffffff)
3762306a36Sopenharmony_ci#define FASTRPC_CTX_MAX (256)
3862306a36Sopenharmony_ci#define FASTRPC_INIT_HANDLE	1
3962306a36Sopenharmony_ci#define FASTRPC_DSP_UTILITIES_HANDLE	2
4062306a36Sopenharmony_ci#define FASTRPC_CTXID_MASK (0xFF0)
4162306a36Sopenharmony_ci#define INIT_FILELEN_MAX (2 * 1024 * 1024)
4262306a36Sopenharmony_ci#define INIT_FILE_NAMELEN_MAX (128)
4362306a36Sopenharmony_ci#define FASTRPC_DEVICE_NAME	"fastrpc"
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci/* Add memory to static PD pool, protection thru XPU */
4662306a36Sopenharmony_ci#define ADSP_MMAP_HEAP_ADDR  4
4762306a36Sopenharmony_ci/* MAP static DMA buffer on DSP User PD */
4862306a36Sopenharmony_ci#define ADSP_MMAP_DMA_BUFFER  6
4962306a36Sopenharmony_ci/* Add memory to static PD pool protection thru hypervisor */
5062306a36Sopenharmony_ci#define ADSP_MMAP_REMOTE_HEAP_ADDR  8
5162306a36Sopenharmony_ci/* Add memory to userPD pool, for user heap */
5262306a36Sopenharmony_ci#define ADSP_MMAP_ADD_PAGES 0x1000
5362306a36Sopenharmony_ci/* Add memory to userPD pool, for LLC heap */
5462306a36Sopenharmony_ci#define ADSP_MMAP_ADD_PAGES_LLC 0x3000,
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci#define DSP_UNSUPPORTED_API (0x80000414)
5762306a36Sopenharmony_ci/* MAX NUMBER of DSP ATTRIBUTES SUPPORTED */
5862306a36Sopenharmony_ci#define FASTRPC_MAX_DSP_ATTRIBUTES (256)
5962306a36Sopenharmony_ci#define FASTRPC_MAX_DSP_ATTRIBUTES_LEN (sizeof(u32) * FASTRPC_MAX_DSP_ATTRIBUTES)
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci/* Retrives number of input buffers from the scalars parameter */
6262306a36Sopenharmony_ci#define REMOTE_SCALARS_INBUFS(sc)	(((sc) >> 16) & 0x0ff)
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci/* Retrives number of output buffers from the scalars parameter */
6562306a36Sopenharmony_ci#define REMOTE_SCALARS_OUTBUFS(sc)	(((sc) >> 8) & 0x0ff)
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci/* Retrives number of input handles from the scalars parameter */
6862306a36Sopenharmony_ci#define REMOTE_SCALARS_INHANDLES(sc)	(((sc) >> 4) & 0x0f)
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci/* Retrives number of output handles from the scalars parameter */
7162306a36Sopenharmony_ci#define REMOTE_SCALARS_OUTHANDLES(sc)	((sc) & 0x0f)
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci#define REMOTE_SCALARS_LENGTH(sc)	(REMOTE_SCALARS_INBUFS(sc) +   \
7462306a36Sopenharmony_ci					 REMOTE_SCALARS_OUTBUFS(sc) +  \
7562306a36Sopenharmony_ci					 REMOTE_SCALARS_INHANDLES(sc)+ \
7662306a36Sopenharmony_ci					 REMOTE_SCALARS_OUTHANDLES(sc))
7762306a36Sopenharmony_ci#define FASTRPC_BUILD_SCALARS(attr, method, in, out, oin, oout)  \
7862306a36Sopenharmony_ci				(((attr & 0x07) << 29) |		\
7962306a36Sopenharmony_ci				((method & 0x1f) << 24) |	\
8062306a36Sopenharmony_ci				((in & 0xff) << 16) |		\
8162306a36Sopenharmony_ci				((out & 0xff) <<  8) |		\
8262306a36Sopenharmony_ci				((oin & 0x0f) <<  4) |		\
8362306a36Sopenharmony_ci				(oout & 0x0f))
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci#define FASTRPC_SCALARS(method, in, out) \
8662306a36Sopenharmony_ci		FASTRPC_BUILD_SCALARS(0, method, in, out, 0, 0)
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci#define FASTRPC_CREATE_PROCESS_NARGS	6
8962306a36Sopenharmony_ci#define FASTRPC_CREATE_STATIC_PROCESS_NARGS	3
9062306a36Sopenharmony_ci/* Remote Method id table */
9162306a36Sopenharmony_ci#define FASTRPC_RMID_INIT_ATTACH	0
9262306a36Sopenharmony_ci#define FASTRPC_RMID_INIT_RELEASE	1
9362306a36Sopenharmony_ci#define FASTRPC_RMID_INIT_MMAP		4
9462306a36Sopenharmony_ci#define FASTRPC_RMID_INIT_MUNMAP	5
9562306a36Sopenharmony_ci#define FASTRPC_RMID_INIT_CREATE	6
9662306a36Sopenharmony_ci#define FASTRPC_RMID_INIT_CREATE_ATTR	7
9762306a36Sopenharmony_ci#define FASTRPC_RMID_INIT_CREATE_STATIC	8
9862306a36Sopenharmony_ci#define FASTRPC_RMID_INIT_MEM_MAP      10
9962306a36Sopenharmony_ci#define FASTRPC_RMID_INIT_MEM_UNMAP    11
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci/* Protection Domain(PD) ids */
10262306a36Sopenharmony_ci#define ROOT_PD		(0)
10362306a36Sopenharmony_ci#define USER_PD		(1)
10462306a36Sopenharmony_ci#define SENSORS_PD	(2)
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci#define miscdev_to_fdevice(d) container_of(d, struct fastrpc_device, miscdev)
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_cistatic const char *domains[FASTRPC_DEV_MAX] = { "adsp", "mdsp",
10962306a36Sopenharmony_ci						"sdsp", "cdsp"};
11062306a36Sopenharmony_cistruct fastrpc_phy_page {
11162306a36Sopenharmony_ci	u64 addr;		/* physical address */
11262306a36Sopenharmony_ci	u64 size;		/* size of contiguous region */
11362306a36Sopenharmony_ci};
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_cistruct fastrpc_invoke_buf {
11662306a36Sopenharmony_ci	u32 num;		/* number of contiguous regions */
11762306a36Sopenharmony_ci	u32 pgidx;		/* index to start of contiguous region */
11862306a36Sopenharmony_ci};
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_cistruct fastrpc_remote_dmahandle {
12162306a36Sopenharmony_ci	s32 fd;		/* dma handle fd */
12262306a36Sopenharmony_ci	u32 offset;	/* dma handle offset */
12362306a36Sopenharmony_ci	u32 len;	/* dma handle length */
12462306a36Sopenharmony_ci};
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_cistruct fastrpc_remote_buf {
12762306a36Sopenharmony_ci	u64 pv;		/* buffer pointer */
12862306a36Sopenharmony_ci	u64 len;	/* length of buffer */
12962306a36Sopenharmony_ci};
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ciunion fastrpc_remote_arg {
13262306a36Sopenharmony_ci	struct fastrpc_remote_buf buf;
13362306a36Sopenharmony_ci	struct fastrpc_remote_dmahandle dma;
13462306a36Sopenharmony_ci};
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_cistruct fastrpc_mmap_rsp_msg {
13762306a36Sopenharmony_ci	u64 vaddr;
13862306a36Sopenharmony_ci};
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_cistruct fastrpc_mmap_req_msg {
14162306a36Sopenharmony_ci	s32 pgid;
14262306a36Sopenharmony_ci	u32 flags;
14362306a36Sopenharmony_ci	u64 vaddr;
14462306a36Sopenharmony_ci	s32 num;
14562306a36Sopenharmony_ci};
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_cistruct fastrpc_mem_map_req_msg {
14862306a36Sopenharmony_ci	s32 pgid;
14962306a36Sopenharmony_ci	s32 fd;
15062306a36Sopenharmony_ci	s32 offset;
15162306a36Sopenharmony_ci	u32 flags;
15262306a36Sopenharmony_ci	u64 vaddrin;
15362306a36Sopenharmony_ci	s32 num;
15462306a36Sopenharmony_ci	s32 data_len;
15562306a36Sopenharmony_ci};
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_cistruct fastrpc_munmap_req_msg {
15862306a36Sopenharmony_ci	s32 pgid;
15962306a36Sopenharmony_ci	u64 vaddr;
16062306a36Sopenharmony_ci	u64 size;
16162306a36Sopenharmony_ci};
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_cistruct fastrpc_mem_unmap_req_msg {
16462306a36Sopenharmony_ci	s32 pgid;
16562306a36Sopenharmony_ci	s32 fd;
16662306a36Sopenharmony_ci	u64 vaddrin;
16762306a36Sopenharmony_ci	u64 len;
16862306a36Sopenharmony_ci};
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_cistruct fastrpc_msg {
17162306a36Sopenharmony_ci	int pid;		/* process group id */
17262306a36Sopenharmony_ci	int tid;		/* thread id */
17362306a36Sopenharmony_ci	u64 ctx;		/* invoke caller context */
17462306a36Sopenharmony_ci	u32 handle;	/* handle to invoke */
17562306a36Sopenharmony_ci	u32 sc;		/* scalars structure describing the data */
17662306a36Sopenharmony_ci	u64 addr;		/* physical address */
17762306a36Sopenharmony_ci	u64 size;		/* size of contiguous region */
17862306a36Sopenharmony_ci};
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_cistruct fastrpc_invoke_rsp {
18162306a36Sopenharmony_ci	u64 ctx;		/* invoke caller context */
18262306a36Sopenharmony_ci	int retval;		/* invoke return value */
18362306a36Sopenharmony_ci};
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_cistruct fastrpc_buf_overlap {
18662306a36Sopenharmony_ci	u64 start;
18762306a36Sopenharmony_ci	u64 end;
18862306a36Sopenharmony_ci	int raix;
18962306a36Sopenharmony_ci	u64 mstart;
19062306a36Sopenharmony_ci	u64 mend;
19162306a36Sopenharmony_ci	u64 offset;
19262306a36Sopenharmony_ci};
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_cistruct fastrpc_buf {
19562306a36Sopenharmony_ci	struct fastrpc_user *fl;
19662306a36Sopenharmony_ci	struct dma_buf *dmabuf;
19762306a36Sopenharmony_ci	struct device *dev;
19862306a36Sopenharmony_ci	void *virt;
19962306a36Sopenharmony_ci	u64 phys;
20062306a36Sopenharmony_ci	u64 size;
20162306a36Sopenharmony_ci	/* Lock for dma buf attachments */
20262306a36Sopenharmony_ci	struct mutex lock;
20362306a36Sopenharmony_ci	struct list_head attachments;
20462306a36Sopenharmony_ci	/* mmap support */
20562306a36Sopenharmony_ci	struct list_head node; /* list of user requested mmaps */
20662306a36Sopenharmony_ci	uintptr_t raddr;
20762306a36Sopenharmony_ci};
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_cistruct fastrpc_dma_buf_attachment {
21062306a36Sopenharmony_ci	struct device *dev;
21162306a36Sopenharmony_ci	struct sg_table sgt;
21262306a36Sopenharmony_ci	struct list_head node;
21362306a36Sopenharmony_ci};
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_cistruct fastrpc_map {
21662306a36Sopenharmony_ci	struct list_head node;
21762306a36Sopenharmony_ci	struct fastrpc_user *fl;
21862306a36Sopenharmony_ci	int fd;
21962306a36Sopenharmony_ci	struct dma_buf *buf;
22062306a36Sopenharmony_ci	struct sg_table *table;
22162306a36Sopenharmony_ci	struct dma_buf_attachment *attach;
22262306a36Sopenharmony_ci	u64 phys;
22362306a36Sopenharmony_ci	u64 size;
22462306a36Sopenharmony_ci	void *va;
22562306a36Sopenharmony_ci	u64 len;
22662306a36Sopenharmony_ci	u64 raddr;
22762306a36Sopenharmony_ci	u32 attr;
22862306a36Sopenharmony_ci	struct kref refcount;
22962306a36Sopenharmony_ci};
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_cistruct fastrpc_invoke_ctx {
23262306a36Sopenharmony_ci	int nscalars;
23362306a36Sopenharmony_ci	int nbufs;
23462306a36Sopenharmony_ci	int retval;
23562306a36Sopenharmony_ci	int pid;
23662306a36Sopenharmony_ci	int tgid;
23762306a36Sopenharmony_ci	u32 sc;
23862306a36Sopenharmony_ci	u32 *crc;
23962306a36Sopenharmony_ci	u64 ctxid;
24062306a36Sopenharmony_ci	u64 msg_sz;
24162306a36Sopenharmony_ci	struct kref refcount;
24262306a36Sopenharmony_ci	struct list_head node; /* list of ctxs */
24362306a36Sopenharmony_ci	struct completion work;
24462306a36Sopenharmony_ci	struct work_struct put_work;
24562306a36Sopenharmony_ci	struct fastrpc_msg msg;
24662306a36Sopenharmony_ci	struct fastrpc_user *fl;
24762306a36Sopenharmony_ci	union fastrpc_remote_arg *rpra;
24862306a36Sopenharmony_ci	struct fastrpc_map **maps;
24962306a36Sopenharmony_ci	struct fastrpc_buf *buf;
25062306a36Sopenharmony_ci	struct fastrpc_invoke_args *args;
25162306a36Sopenharmony_ci	struct fastrpc_buf_overlap *olaps;
25262306a36Sopenharmony_ci	struct fastrpc_channel_ctx *cctx;
25362306a36Sopenharmony_ci};
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_cistruct fastrpc_session_ctx {
25662306a36Sopenharmony_ci	struct device *dev;
25762306a36Sopenharmony_ci	int sid;
25862306a36Sopenharmony_ci	bool used;
25962306a36Sopenharmony_ci	bool valid;
26062306a36Sopenharmony_ci};
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_cistruct fastrpc_channel_ctx {
26362306a36Sopenharmony_ci	int domain_id;
26462306a36Sopenharmony_ci	int sesscount;
26562306a36Sopenharmony_ci	int vmcount;
26662306a36Sopenharmony_ci	u64 perms;
26762306a36Sopenharmony_ci	struct qcom_scm_vmperm vmperms[FASTRPC_MAX_VMIDS];
26862306a36Sopenharmony_ci	struct rpmsg_device *rpdev;
26962306a36Sopenharmony_ci	struct fastrpc_session_ctx session[FASTRPC_MAX_SESSIONS];
27062306a36Sopenharmony_ci	spinlock_t lock;
27162306a36Sopenharmony_ci	struct idr ctx_idr;
27262306a36Sopenharmony_ci	struct list_head users;
27362306a36Sopenharmony_ci	struct kref refcount;
27462306a36Sopenharmony_ci	/* Flag if dsp attributes are cached */
27562306a36Sopenharmony_ci	bool valid_attributes;
27662306a36Sopenharmony_ci	u32 dsp_attributes[FASTRPC_MAX_DSP_ATTRIBUTES];
27762306a36Sopenharmony_ci	struct fastrpc_device *secure_fdevice;
27862306a36Sopenharmony_ci	struct fastrpc_device *fdevice;
27962306a36Sopenharmony_ci	struct fastrpc_buf *remote_heap;
28062306a36Sopenharmony_ci	struct list_head invoke_interrupted_mmaps;
28162306a36Sopenharmony_ci	bool secure;
28262306a36Sopenharmony_ci	bool unsigned_support;
28362306a36Sopenharmony_ci	u64 dma_mask;
28462306a36Sopenharmony_ci};
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_cistruct fastrpc_device {
28762306a36Sopenharmony_ci	struct fastrpc_channel_ctx *cctx;
28862306a36Sopenharmony_ci	struct miscdevice miscdev;
28962306a36Sopenharmony_ci	bool secure;
29062306a36Sopenharmony_ci};
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_cistruct fastrpc_user {
29362306a36Sopenharmony_ci	struct list_head user;
29462306a36Sopenharmony_ci	struct list_head maps;
29562306a36Sopenharmony_ci	struct list_head pending;
29662306a36Sopenharmony_ci	struct list_head mmaps;
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ci	struct fastrpc_channel_ctx *cctx;
29962306a36Sopenharmony_ci	struct fastrpc_session_ctx *sctx;
30062306a36Sopenharmony_ci	struct fastrpc_buf *init_mem;
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci	int tgid;
30362306a36Sopenharmony_ci	int pd;
30462306a36Sopenharmony_ci	bool is_secure_dev;
30562306a36Sopenharmony_ci	/* Lock for lists */
30662306a36Sopenharmony_ci	spinlock_t lock;
30762306a36Sopenharmony_ci	/* lock for allocations */
30862306a36Sopenharmony_ci	struct mutex mutex;
30962306a36Sopenharmony_ci};
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_cistatic void fastrpc_free_map(struct kref *ref)
31262306a36Sopenharmony_ci{
31362306a36Sopenharmony_ci	struct fastrpc_map *map;
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci	map = container_of(ref, struct fastrpc_map, refcount);
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci	if (map->table) {
31862306a36Sopenharmony_ci		if (map->attr & FASTRPC_ATTR_SECUREMAP) {
31962306a36Sopenharmony_ci			struct qcom_scm_vmperm perm;
32062306a36Sopenharmony_ci			int vmid = map->fl->cctx->vmperms[0].vmid;
32162306a36Sopenharmony_ci			u64 src_perms = BIT(QCOM_SCM_VMID_HLOS) | BIT(vmid);
32262306a36Sopenharmony_ci			int err = 0;
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci			perm.vmid = QCOM_SCM_VMID_HLOS;
32562306a36Sopenharmony_ci			perm.perm = QCOM_SCM_PERM_RWX;
32662306a36Sopenharmony_ci			err = qcom_scm_assign_mem(map->phys, map->size,
32762306a36Sopenharmony_ci				&src_perms, &perm, 1);
32862306a36Sopenharmony_ci			if (err) {
32962306a36Sopenharmony_ci				dev_err(map->fl->sctx->dev, "Failed to assign memory phys 0x%llx size 0x%llx err %d",
33062306a36Sopenharmony_ci						map->phys, map->size, err);
33162306a36Sopenharmony_ci				return;
33262306a36Sopenharmony_ci			}
33362306a36Sopenharmony_ci		}
33462306a36Sopenharmony_ci		dma_buf_unmap_attachment_unlocked(map->attach, map->table,
33562306a36Sopenharmony_ci						  DMA_BIDIRECTIONAL);
33662306a36Sopenharmony_ci		dma_buf_detach(map->buf, map->attach);
33762306a36Sopenharmony_ci		dma_buf_put(map->buf);
33862306a36Sopenharmony_ci	}
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci	if (map->fl) {
34162306a36Sopenharmony_ci		spin_lock(&map->fl->lock);
34262306a36Sopenharmony_ci		list_del(&map->node);
34362306a36Sopenharmony_ci		spin_unlock(&map->fl->lock);
34462306a36Sopenharmony_ci		map->fl = NULL;
34562306a36Sopenharmony_ci	}
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci	kfree(map);
34862306a36Sopenharmony_ci}
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_cistatic void fastrpc_map_put(struct fastrpc_map *map)
35162306a36Sopenharmony_ci{
35262306a36Sopenharmony_ci	if (map)
35362306a36Sopenharmony_ci		kref_put(&map->refcount, fastrpc_free_map);
35462306a36Sopenharmony_ci}
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_cistatic int fastrpc_map_get(struct fastrpc_map *map)
35762306a36Sopenharmony_ci{
35862306a36Sopenharmony_ci	if (!map)
35962306a36Sopenharmony_ci		return -ENOENT;
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci	return kref_get_unless_zero(&map->refcount) ? 0 : -ENOENT;
36262306a36Sopenharmony_ci}
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_cistatic int fastrpc_map_lookup(struct fastrpc_user *fl, int fd,
36662306a36Sopenharmony_ci			    struct fastrpc_map **ppmap, bool take_ref)
36762306a36Sopenharmony_ci{
36862306a36Sopenharmony_ci	struct fastrpc_session_ctx *sess = fl->sctx;
36962306a36Sopenharmony_ci	struct fastrpc_map *map = NULL;
37062306a36Sopenharmony_ci	int ret = -ENOENT;
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci	spin_lock(&fl->lock);
37362306a36Sopenharmony_ci	list_for_each_entry(map, &fl->maps, node) {
37462306a36Sopenharmony_ci		if (map->fd != fd)
37562306a36Sopenharmony_ci			continue;
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci		if (take_ref) {
37862306a36Sopenharmony_ci			ret = fastrpc_map_get(map);
37962306a36Sopenharmony_ci			if (ret) {
38062306a36Sopenharmony_ci				dev_dbg(sess->dev, "%s: Failed to get map fd=%d ret=%d\n",
38162306a36Sopenharmony_ci					__func__, fd, ret);
38262306a36Sopenharmony_ci				break;
38362306a36Sopenharmony_ci			}
38462306a36Sopenharmony_ci		}
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci		*ppmap = map;
38762306a36Sopenharmony_ci		ret = 0;
38862306a36Sopenharmony_ci		break;
38962306a36Sopenharmony_ci	}
39062306a36Sopenharmony_ci	spin_unlock(&fl->lock);
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_ci	return ret;
39362306a36Sopenharmony_ci}
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_cistatic void fastrpc_buf_free(struct fastrpc_buf *buf)
39662306a36Sopenharmony_ci{
39762306a36Sopenharmony_ci	dma_free_coherent(buf->dev, buf->size, buf->virt,
39862306a36Sopenharmony_ci			  FASTRPC_PHYS(buf->phys));
39962306a36Sopenharmony_ci	kfree(buf);
40062306a36Sopenharmony_ci}
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_cistatic int __fastrpc_buf_alloc(struct fastrpc_user *fl, struct device *dev,
40362306a36Sopenharmony_ci			     u64 size, struct fastrpc_buf **obuf)
40462306a36Sopenharmony_ci{
40562306a36Sopenharmony_ci	struct fastrpc_buf *buf;
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ci	buf = kzalloc(sizeof(*buf), GFP_KERNEL);
40862306a36Sopenharmony_ci	if (!buf)
40962306a36Sopenharmony_ci		return -ENOMEM;
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci	INIT_LIST_HEAD(&buf->attachments);
41262306a36Sopenharmony_ci	INIT_LIST_HEAD(&buf->node);
41362306a36Sopenharmony_ci	mutex_init(&buf->lock);
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci	buf->fl = fl;
41662306a36Sopenharmony_ci	buf->virt = NULL;
41762306a36Sopenharmony_ci	buf->phys = 0;
41862306a36Sopenharmony_ci	buf->size = size;
41962306a36Sopenharmony_ci	buf->dev = dev;
42062306a36Sopenharmony_ci	buf->raddr = 0;
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ci	buf->virt = dma_alloc_coherent(dev, buf->size, (dma_addr_t *)&buf->phys,
42362306a36Sopenharmony_ci				       GFP_KERNEL);
42462306a36Sopenharmony_ci	if (!buf->virt) {
42562306a36Sopenharmony_ci		mutex_destroy(&buf->lock);
42662306a36Sopenharmony_ci		kfree(buf);
42762306a36Sopenharmony_ci		return -ENOMEM;
42862306a36Sopenharmony_ci	}
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_ci	*obuf = buf;
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ci	return 0;
43362306a36Sopenharmony_ci}
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_cistatic int fastrpc_buf_alloc(struct fastrpc_user *fl, struct device *dev,
43662306a36Sopenharmony_ci			     u64 size, struct fastrpc_buf **obuf)
43762306a36Sopenharmony_ci{
43862306a36Sopenharmony_ci	int ret;
43962306a36Sopenharmony_ci	struct fastrpc_buf *buf;
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ci	ret = __fastrpc_buf_alloc(fl, dev, size, obuf);
44262306a36Sopenharmony_ci	if (ret)
44362306a36Sopenharmony_ci		return ret;
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci	buf = *obuf;
44662306a36Sopenharmony_ci
44762306a36Sopenharmony_ci	if (fl->sctx && fl->sctx->sid)
44862306a36Sopenharmony_ci		buf->phys += ((u64)fl->sctx->sid << 32);
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ci	return 0;
45162306a36Sopenharmony_ci}
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_cistatic int fastrpc_remote_heap_alloc(struct fastrpc_user *fl, struct device *dev,
45462306a36Sopenharmony_ci				     u64 size, struct fastrpc_buf **obuf)
45562306a36Sopenharmony_ci{
45662306a36Sopenharmony_ci	struct device *rdev = &fl->cctx->rpdev->dev;
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_ci	return  __fastrpc_buf_alloc(fl, rdev, size, obuf);
45962306a36Sopenharmony_ci}
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_cistatic void fastrpc_channel_ctx_free(struct kref *ref)
46262306a36Sopenharmony_ci{
46362306a36Sopenharmony_ci	struct fastrpc_channel_ctx *cctx;
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_ci	cctx = container_of(ref, struct fastrpc_channel_ctx, refcount);
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ci	kfree(cctx);
46862306a36Sopenharmony_ci}
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_cistatic void fastrpc_channel_ctx_get(struct fastrpc_channel_ctx *cctx)
47162306a36Sopenharmony_ci{
47262306a36Sopenharmony_ci	kref_get(&cctx->refcount);
47362306a36Sopenharmony_ci}
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_cistatic void fastrpc_channel_ctx_put(struct fastrpc_channel_ctx *cctx)
47662306a36Sopenharmony_ci{
47762306a36Sopenharmony_ci	kref_put(&cctx->refcount, fastrpc_channel_ctx_free);
47862306a36Sopenharmony_ci}
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_cistatic void fastrpc_context_free(struct kref *ref)
48162306a36Sopenharmony_ci{
48262306a36Sopenharmony_ci	struct fastrpc_invoke_ctx *ctx;
48362306a36Sopenharmony_ci	struct fastrpc_channel_ctx *cctx;
48462306a36Sopenharmony_ci	unsigned long flags;
48562306a36Sopenharmony_ci	int i;
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_ci	ctx = container_of(ref, struct fastrpc_invoke_ctx, refcount);
48862306a36Sopenharmony_ci	cctx = ctx->cctx;
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci	for (i = 0; i < ctx->nbufs; i++)
49162306a36Sopenharmony_ci		fastrpc_map_put(ctx->maps[i]);
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_ci	if (ctx->buf)
49462306a36Sopenharmony_ci		fastrpc_buf_free(ctx->buf);
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_ci	spin_lock_irqsave(&cctx->lock, flags);
49762306a36Sopenharmony_ci	idr_remove(&cctx->ctx_idr, ctx->ctxid >> 4);
49862306a36Sopenharmony_ci	spin_unlock_irqrestore(&cctx->lock, flags);
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_ci	kfree(ctx->maps);
50162306a36Sopenharmony_ci	kfree(ctx->olaps);
50262306a36Sopenharmony_ci	kfree(ctx);
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_ci	fastrpc_channel_ctx_put(cctx);
50562306a36Sopenharmony_ci}
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_cistatic void fastrpc_context_get(struct fastrpc_invoke_ctx *ctx)
50862306a36Sopenharmony_ci{
50962306a36Sopenharmony_ci	kref_get(&ctx->refcount);
51062306a36Sopenharmony_ci}
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_cistatic void fastrpc_context_put(struct fastrpc_invoke_ctx *ctx)
51362306a36Sopenharmony_ci{
51462306a36Sopenharmony_ci	kref_put(&ctx->refcount, fastrpc_context_free);
51562306a36Sopenharmony_ci}
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_cistatic void fastrpc_context_put_wq(struct work_struct *work)
51862306a36Sopenharmony_ci{
51962306a36Sopenharmony_ci	struct fastrpc_invoke_ctx *ctx =
52062306a36Sopenharmony_ci			container_of(work, struct fastrpc_invoke_ctx, put_work);
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_ci	fastrpc_context_put(ctx);
52362306a36Sopenharmony_ci}
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_ci#define CMP(aa, bb) ((aa) == (bb) ? 0 : (aa) < (bb) ? -1 : 1)
52662306a36Sopenharmony_cistatic int olaps_cmp(const void *a, const void *b)
52762306a36Sopenharmony_ci{
52862306a36Sopenharmony_ci	struct fastrpc_buf_overlap *pa = (struct fastrpc_buf_overlap *)a;
52962306a36Sopenharmony_ci	struct fastrpc_buf_overlap *pb = (struct fastrpc_buf_overlap *)b;
53062306a36Sopenharmony_ci	/* sort with lowest starting buffer first */
53162306a36Sopenharmony_ci	int st = CMP(pa->start, pb->start);
53262306a36Sopenharmony_ci	/* sort with highest ending buffer first */
53362306a36Sopenharmony_ci	int ed = CMP(pb->end, pa->end);
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_ci	return st == 0 ? ed : st;
53662306a36Sopenharmony_ci}
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_cistatic void fastrpc_get_buff_overlaps(struct fastrpc_invoke_ctx *ctx)
53962306a36Sopenharmony_ci{
54062306a36Sopenharmony_ci	u64 max_end = 0;
54162306a36Sopenharmony_ci	int i;
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ci	for (i = 0; i < ctx->nbufs; ++i) {
54462306a36Sopenharmony_ci		ctx->olaps[i].start = ctx->args[i].ptr;
54562306a36Sopenharmony_ci		ctx->olaps[i].end = ctx->olaps[i].start + ctx->args[i].length;
54662306a36Sopenharmony_ci		ctx->olaps[i].raix = i;
54762306a36Sopenharmony_ci	}
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_ci	sort(ctx->olaps, ctx->nbufs, sizeof(*ctx->olaps), olaps_cmp, NULL);
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_ci	for (i = 0; i < ctx->nbufs; ++i) {
55262306a36Sopenharmony_ci		/* Falling inside previous range */
55362306a36Sopenharmony_ci		if (ctx->olaps[i].start < max_end) {
55462306a36Sopenharmony_ci			ctx->olaps[i].mstart = max_end;
55562306a36Sopenharmony_ci			ctx->olaps[i].mend = ctx->olaps[i].end;
55662306a36Sopenharmony_ci			ctx->olaps[i].offset = max_end - ctx->olaps[i].start;
55762306a36Sopenharmony_ci
55862306a36Sopenharmony_ci			if (ctx->olaps[i].end > max_end) {
55962306a36Sopenharmony_ci				max_end = ctx->olaps[i].end;
56062306a36Sopenharmony_ci			} else {
56162306a36Sopenharmony_ci				ctx->olaps[i].mend = 0;
56262306a36Sopenharmony_ci				ctx->olaps[i].mstart = 0;
56362306a36Sopenharmony_ci			}
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_ci		} else  {
56662306a36Sopenharmony_ci			ctx->olaps[i].mend = ctx->olaps[i].end;
56762306a36Sopenharmony_ci			ctx->olaps[i].mstart = ctx->olaps[i].start;
56862306a36Sopenharmony_ci			ctx->olaps[i].offset = 0;
56962306a36Sopenharmony_ci			max_end = ctx->olaps[i].end;
57062306a36Sopenharmony_ci		}
57162306a36Sopenharmony_ci	}
57262306a36Sopenharmony_ci}
57362306a36Sopenharmony_ci
57462306a36Sopenharmony_cistatic struct fastrpc_invoke_ctx *fastrpc_context_alloc(
57562306a36Sopenharmony_ci			struct fastrpc_user *user, u32 kernel, u32 sc,
57662306a36Sopenharmony_ci			struct fastrpc_invoke_args *args)
57762306a36Sopenharmony_ci{
57862306a36Sopenharmony_ci	struct fastrpc_channel_ctx *cctx = user->cctx;
57962306a36Sopenharmony_ci	struct fastrpc_invoke_ctx *ctx = NULL;
58062306a36Sopenharmony_ci	unsigned long flags;
58162306a36Sopenharmony_ci	int ret;
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_ci	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
58462306a36Sopenharmony_ci	if (!ctx)
58562306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_ci	INIT_LIST_HEAD(&ctx->node);
58862306a36Sopenharmony_ci	ctx->fl = user;
58962306a36Sopenharmony_ci	ctx->nscalars = REMOTE_SCALARS_LENGTH(sc);
59062306a36Sopenharmony_ci	ctx->nbufs = REMOTE_SCALARS_INBUFS(sc) +
59162306a36Sopenharmony_ci		     REMOTE_SCALARS_OUTBUFS(sc);
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_ci	if (ctx->nscalars) {
59462306a36Sopenharmony_ci		ctx->maps = kcalloc(ctx->nscalars,
59562306a36Sopenharmony_ci				    sizeof(*ctx->maps), GFP_KERNEL);
59662306a36Sopenharmony_ci		if (!ctx->maps) {
59762306a36Sopenharmony_ci			kfree(ctx);
59862306a36Sopenharmony_ci			return ERR_PTR(-ENOMEM);
59962306a36Sopenharmony_ci		}
60062306a36Sopenharmony_ci		ctx->olaps = kcalloc(ctx->nscalars,
60162306a36Sopenharmony_ci				    sizeof(*ctx->olaps), GFP_KERNEL);
60262306a36Sopenharmony_ci		if (!ctx->olaps) {
60362306a36Sopenharmony_ci			kfree(ctx->maps);
60462306a36Sopenharmony_ci			kfree(ctx);
60562306a36Sopenharmony_ci			return ERR_PTR(-ENOMEM);
60662306a36Sopenharmony_ci		}
60762306a36Sopenharmony_ci		ctx->args = args;
60862306a36Sopenharmony_ci		fastrpc_get_buff_overlaps(ctx);
60962306a36Sopenharmony_ci	}
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_ci	/* Released in fastrpc_context_put() */
61262306a36Sopenharmony_ci	fastrpc_channel_ctx_get(cctx);
61362306a36Sopenharmony_ci
61462306a36Sopenharmony_ci	ctx->sc = sc;
61562306a36Sopenharmony_ci	ctx->retval = -1;
61662306a36Sopenharmony_ci	ctx->pid = current->pid;
61762306a36Sopenharmony_ci	ctx->tgid = user->tgid;
61862306a36Sopenharmony_ci	ctx->cctx = cctx;
61962306a36Sopenharmony_ci	init_completion(&ctx->work);
62062306a36Sopenharmony_ci	INIT_WORK(&ctx->put_work, fastrpc_context_put_wq);
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_ci	spin_lock(&user->lock);
62362306a36Sopenharmony_ci	list_add_tail(&ctx->node, &user->pending);
62462306a36Sopenharmony_ci	spin_unlock(&user->lock);
62562306a36Sopenharmony_ci
62662306a36Sopenharmony_ci	spin_lock_irqsave(&cctx->lock, flags);
62762306a36Sopenharmony_ci	ret = idr_alloc_cyclic(&cctx->ctx_idr, ctx, 1,
62862306a36Sopenharmony_ci			       FASTRPC_CTX_MAX, GFP_ATOMIC);
62962306a36Sopenharmony_ci	if (ret < 0) {
63062306a36Sopenharmony_ci		spin_unlock_irqrestore(&cctx->lock, flags);
63162306a36Sopenharmony_ci		goto err_idr;
63262306a36Sopenharmony_ci	}
63362306a36Sopenharmony_ci	ctx->ctxid = ret << 4;
63462306a36Sopenharmony_ci	spin_unlock_irqrestore(&cctx->lock, flags);
63562306a36Sopenharmony_ci
63662306a36Sopenharmony_ci	kref_init(&ctx->refcount);
63762306a36Sopenharmony_ci
63862306a36Sopenharmony_ci	return ctx;
63962306a36Sopenharmony_cierr_idr:
64062306a36Sopenharmony_ci	spin_lock(&user->lock);
64162306a36Sopenharmony_ci	list_del(&ctx->node);
64262306a36Sopenharmony_ci	spin_unlock(&user->lock);
64362306a36Sopenharmony_ci	fastrpc_channel_ctx_put(cctx);
64462306a36Sopenharmony_ci	kfree(ctx->maps);
64562306a36Sopenharmony_ci	kfree(ctx->olaps);
64662306a36Sopenharmony_ci	kfree(ctx);
64762306a36Sopenharmony_ci
64862306a36Sopenharmony_ci	return ERR_PTR(ret);
64962306a36Sopenharmony_ci}
65062306a36Sopenharmony_ci
65162306a36Sopenharmony_cistatic struct sg_table *
65262306a36Sopenharmony_cifastrpc_map_dma_buf(struct dma_buf_attachment *attachment,
65362306a36Sopenharmony_ci		    enum dma_data_direction dir)
65462306a36Sopenharmony_ci{
65562306a36Sopenharmony_ci	struct fastrpc_dma_buf_attachment *a = attachment->priv;
65662306a36Sopenharmony_ci	struct sg_table *table;
65762306a36Sopenharmony_ci	int ret;
65862306a36Sopenharmony_ci
65962306a36Sopenharmony_ci	table = &a->sgt;
66062306a36Sopenharmony_ci
66162306a36Sopenharmony_ci	ret = dma_map_sgtable(attachment->dev, table, dir, 0);
66262306a36Sopenharmony_ci	if (ret)
66362306a36Sopenharmony_ci		table = ERR_PTR(ret);
66462306a36Sopenharmony_ci	return table;
66562306a36Sopenharmony_ci}
66662306a36Sopenharmony_ci
66762306a36Sopenharmony_cistatic void fastrpc_unmap_dma_buf(struct dma_buf_attachment *attach,
66862306a36Sopenharmony_ci				  struct sg_table *table,
66962306a36Sopenharmony_ci				  enum dma_data_direction dir)
67062306a36Sopenharmony_ci{
67162306a36Sopenharmony_ci	dma_unmap_sgtable(attach->dev, table, dir, 0);
67262306a36Sopenharmony_ci}
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_cistatic void fastrpc_release(struct dma_buf *dmabuf)
67562306a36Sopenharmony_ci{
67662306a36Sopenharmony_ci	struct fastrpc_buf *buffer = dmabuf->priv;
67762306a36Sopenharmony_ci
67862306a36Sopenharmony_ci	fastrpc_buf_free(buffer);
67962306a36Sopenharmony_ci}
68062306a36Sopenharmony_ci
68162306a36Sopenharmony_cistatic int fastrpc_dma_buf_attach(struct dma_buf *dmabuf,
68262306a36Sopenharmony_ci				  struct dma_buf_attachment *attachment)
68362306a36Sopenharmony_ci{
68462306a36Sopenharmony_ci	struct fastrpc_dma_buf_attachment *a;
68562306a36Sopenharmony_ci	struct fastrpc_buf *buffer = dmabuf->priv;
68662306a36Sopenharmony_ci	int ret;
68762306a36Sopenharmony_ci
68862306a36Sopenharmony_ci	a = kzalloc(sizeof(*a), GFP_KERNEL);
68962306a36Sopenharmony_ci	if (!a)
69062306a36Sopenharmony_ci		return -ENOMEM;
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_ci	ret = dma_get_sgtable(buffer->dev, &a->sgt, buffer->virt,
69362306a36Sopenharmony_ci			      FASTRPC_PHYS(buffer->phys), buffer->size);
69462306a36Sopenharmony_ci	if (ret < 0) {
69562306a36Sopenharmony_ci		dev_err(buffer->dev, "failed to get scatterlist from DMA API\n");
69662306a36Sopenharmony_ci		kfree(a);
69762306a36Sopenharmony_ci		return -EINVAL;
69862306a36Sopenharmony_ci	}
69962306a36Sopenharmony_ci
70062306a36Sopenharmony_ci	a->dev = attachment->dev;
70162306a36Sopenharmony_ci	INIT_LIST_HEAD(&a->node);
70262306a36Sopenharmony_ci	attachment->priv = a;
70362306a36Sopenharmony_ci
70462306a36Sopenharmony_ci	mutex_lock(&buffer->lock);
70562306a36Sopenharmony_ci	list_add(&a->node, &buffer->attachments);
70662306a36Sopenharmony_ci	mutex_unlock(&buffer->lock);
70762306a36Sopenharmony_ci
70862306a36Sopenharmony_ci	return 0;
70962306a36Sopenharmony_ci}
71062306a36Sopenharmony_ci
71162306a36Sopenharmony_cistatic void fastrpc_dma_buf_detatch(struct dma_buf *dmabuf,
71262306a36Sopenharmony_ci				    struct dma_buf_attachment *attachment)
71362306a36Sopenharmony_ci{
71462306a36Sopenharmony_ci	struct fastrpc_dma_buf_attachment *a = attachment->priv;
71562306a36Sopenharmony_ci	struct fastrpc_buf *buffer = dmabuf->priv;
71662306a36Sopenharmony_ci
71762306a36Sopenharmony_ci	mutex_lock(&buffer->lock);
71862306a36Sopenharmony_ci	list_del(&a->node);
71962306a36Sopenharmony_ci	mutex_unlock(&buffer->lock);
72062306a36Sopenharmony_ci	sg_free_table(&a->sgt);
72162306a36Sopenharmony_ci	kfree(a);
72262306a36Sopenharmony_ci}
72362306a36Sopenharmony_ci
72462306a36Sopenharmony_cistatic int fastrpc_vmap(struct dma_buf *dmabuf, struct iosys_map *map)
72562306a36Sopenharmony_ci{
72662306a36Sopenharmony_ci	struct fastrpc_buf *buf = dmabuf->priv;
72762306a36Sopenharmony_ci
72862306a36Sopenharmony_ci	iosys_map_set_vaddr(map, buf->virt);
72962306a36Sopenharmony_ci
73062306a36Sopenharmony_ci	return 0;
73162306a36Sopenharmony_ci}
73262306a36Sopenharmony_ci
73362306a36Sopenharmony_cistatic int fastrpc_mmap(struct dma_buf *dmabuf,
73462306a36Sopenharmony_ci			struct vm_area_struct *vma)
73562306a36Sopenharmony_ci{
73662306a36Sopenharmony_ci	struct fastrpc_buf *buf = dmabuf->priv;
73762306a36Sopenharmony_ci	size_t size = vma->vm_end - vma->vm_start;
73862306a36Sopenharmony_ci
73962306a36Sopenharmony_ci	dma_resv_assert_held(dmabuf->resv);
74062306a36Sopenharmony_ci
74162306a36Sopenharmony_ci	return dma_mmap_coherent(buf->dev, vma, buf->virt,
74262306a36Sopenharmony_ci				 FASTRPC_PHYS(buf->phys), size);
74362306a36Sopenharmony_ci}
74462306a36Sopenharmony_ci
74562306a36Sopenharmony_cistatic const struct dma_buf_ops fastrpc_dma_buf_ops = {
74662306a36Sopenharmony_ci	.attach = fastrpc_dma_buf_attach,
74762306a36Sopenharmony_ci	.detach = fastrpc_dma_buf_detatch,
74862306a36Sopenharmony_ci	.map_dma_buf = fastrpc_map_dma_buf,
74962306a36Sopenharmony_ci	.unmap_dma_buf = fastrpc_unmap_dma_buf,
75062306a36Sopenharmony_ci	.mmap = fastrpc_mmap,
75162306a36Sopenharmony_ci	.vmap = fastrpc_vmap,
75262306a36Sopenharmony_ci	.release = fastrpc_release,
75362306a36Sopenharmony_ci};
75462306a36Sopenharmony_ci
75562306a36Sopenharmony_cistatic int fastrpc_map_create(struct fastrpc_user *fl, int fd,
75662306a36Sopenharmony_ci			      u64 len, u32 attr, struct fastrpc_map **ppmap)
75762306a36Sopenharmony_ci{
75862306a36Sopenharmony_ci	struct fastrpc_session_ctx *sess = fl->sctx;
75962306a36Sopenharmony_ci	struct fastrpc_map *map = NULL;
76062306a36Sopenharmony_ci	struct sg_table *table;
76162306a36Sopenharmony_ci	int err = 0;
76262306a36Sopenharmony_ci
76362306a36Sopenharmony_ci	if (!fastrpc_map_lookup(fl, fd, ppmap, true))
76462306a36Sopenharmony_ci		return 0;
76562306a36Sopenharmony_ci
76662306a36Sopenharmony_ci	map = kzalloc(sizeof(*map), GFP_KERNEL);
76762306a36Sopenharmony_ci	if (!map)
76862306a36Sopenharmony_ci		return -ENOMEM;
76962306a36Sopenharmony_ci
77062306a36Sopenharmony_ci	INIT_LIST_HEAD(&map->node);
77162306a36Sopenharmony_ci	kref_init(&map->refcount);
77262306a36Sopenharmony_ci
77362306a36Sopenharmony_ci	map->fl = fl;
77462306a36Sopenharmony_ci	map->fd = fd;
77562306a36Sopenharmony_ci	map->buf = dma_buf_get(fd);
77662306a36Sopenharmony_ci	if (IS_ERR(map->buf)) {
77762306a36Sopenharmony_ci		err = PTR_ERR(map->buf);
77862306a36Sopenharmony_ci		goto get_err;
77962306a36Sopenharmony_ci	}
78062306a36Sopenharmony_ci
78162306a36Sopenharmony_ci	map->attach = dma_buf_attach(map->buf, sess->dev);
78262306a36Sopenharmony_ci	if (IS_ERR(map->attach)) {
78362306a36Sopenharmony_ci		dev_err(sess->dev, "Failed to attach dmabuf\n");
78462306a36Sopenharmony_ci		err = PTR_ERR(map->attach);
78562306a36Sopenharmony_ci		goto attach_err;
78662306a36Sopenharmony_ci	}
78762306a36Sopenharmony_ci
78862306a36Sopenharmony_ci	table = dma_buf_map_attachment_unlocked(map->attach, DMA_BIDIRECTIONAL);
78962306a36Sopenharmony_ci	if (IS_ERR(table)) {
79062306a36Sopenharmony_ci		err = PTR_ERR(table);
79162306a36Sopenharmony_ci		goto map_err;
79262306a36Sopenharmony_ci	}
79362306a36Sopenharmony_ci	map->table = table;
79462306a36Sopenharmony_ci
79562306a36Sopenharmony_ci	if (attr & FASTRPC_ATTR_SECUREMAP) {
79662306a36Sopenharmony_ci		map->phys = sg_phys(map->table->sgl);
79762306a36Sopenharmony_ci	} else {
79862306a36Sopenharmony_ci		map->phys = sg_dma_address(map->table->sgl);
79962306a36Sopenharmony_ci		map->phys += ((u64)fl->sctx->sid << 32);
80062306a36Sopenharmony_ci	}
80162306a36Sopenharmony_ci	map->size = len;
80262306a36Sopenharmony_ci	map->va = sg_virt(map->table->sgl);
80362306a36Sopenharmony_ci	map->len = len;
80462306a36Sopenharmony_ci
80562306a36Sopenharmony_ci	if (attr & FASTRPC_ATTR_SECUREMAP) {
80662306a36Sopenharmony_ci		/*
80762306a36Sopenharmony_ci		 * If subsystem VMIDs are defined in DTSI, then do
80862306a36Sopenharmony_ci		 * hyp_assign from HLOS to those VM(s)
80962306a36Sopenharmony_ci		 */
81062306a36Sopenharmony_ci		u64 src_perms = BIT(QCOM_SCM_VMID_HLOS);
81162306a36Sopenharmony_ci		struct qcom_scm_vmperm dst_perms[2] = {0};
81262306a36Sopenharmony_ci
81362306a36Sopenharmony_ci		dst_perms[0].vmid = QCOM_SCM_VMID_HLOS;
81462306a36Sopenharmony_ci		dst_perms[0].perm = QCOM_SCM_PERM_RW;
81562306a36Sopenharmony_ci		dst_perms[1].vmid = fl->cctx->vmperms[0].vmid;
81662306a36Sopenharmony_ci		dst_perms[1].perm = QCOM_SCM_PERM_RWX;
81762306a36Sopenharmony_ci		map->attr = attr;
81862306a36Sopenharmony_ci		err = qcom_scm_assign_mem(map->phys, (u64)map->size, &src_perms, dst_perms, 2);
81962306a36Sopenharmony_ci		if (err) {
82062306a36Sopenharmony_ci			dev_err(sess->dev, "Failed to assign memory with phys 0x%llx size 0x%llx err %d",
82162306a36Sopenharmony_ci					map->phys, map->size, err);
82262306a36Sopenharmony_ci			goto map_err;
82362306a36Sopenharmony_ci		}
82462306a36Sopenharmony_ci	}
82562306a36Sopenharmony_ci	spin_lock(&fl->lock);
82662306a36Sopenharmony_ci	list_add_tail(&map->node, &fl->maps);
82762306a36Sopenharmony_ci	spin_unlock(&fl->lock);
82862306a36Sopenharmony_ci	*ppmap = map;
82962306a36Sopenharmony_ci
83062306a36Sopenharmony_ci	return 0;
83162306a36Sopenharmony_ci
83262306a36Sopenharmony_cimap_err:
83362306a36Sopenharmony_ci	dma_buf_detach(map->buf, map->attach);
83462306a36Sopenharmony_ciattach_err:
83562306a36Sopenharmony_ci	dma_buf_put(map->buf);
83662306a36Sopenharmony_ciget_err:
83762306a36Sopenharmony_ci	fastrpc_map_put(map);
83862306a36Sopenharmony_ci
83962306a36Sopenharmony_ci	return err;
84062306a36Sopenharmony_ci}
84162306a36Sopenharmony_ci
84262306a36Sopenharmony_ci/*
84362306a36Sopenharmony_ci * Fastrpc payload buffer with metadata looks like:
84462306a36Sopenharmony_ci *
84562306a36Sopenharmony_ci * >>>>>>  START of METADATA <<<<<<<<<
84662306a36Sopenharmony_ci * +---------------------------------+
84762306a36Sopenharmony_ci * |           Arguments             |
84862306a36Sopenharmony_ci * | type:(union fastrpc_remote_arg)|
84962306a36Sopenharmony_ci * |             (0 - N)             |
85062306a36Sopenharmony_ci * +---------------------------------+
85162306a36Sopenharmony_ci * |         Invoke Buffer list      |
85262306a36Sopenharmony_ci * | type:(struct fastrpc_invoke_buf)|
85362306a36Sopenharmony_ci * |           (0 - N)               |
85462306a36Sopenharmony_ci * +---------------------------------+
85562306a36Sopenharmony_ci * |         Page info list          |
85662306a36Sopenharmony_ci * | type:(struct fastrpc_phy_page)  |
85762306a36Sopenharmony_ci * |             (0 - N)             |
85862306a36Sopenharmony_ci * +---------------------------------+
85962306a36Sopenharmony_ci * |         Optional info           |
86062306a36Sopenharmony_ci * |(can be specific to SoC/Firmware)|
86162306a36Sopenharmony_ci * +---------------------------------+
86262306a36Sopenharmony_ci * >>>>>>>>  END of METADATA <<<<<<<<<
86362306a36Sopenharmony_ci * +---------------------------------+
86462306a36Sopenharmony_ci * |         Inline ARGS             |
86562306a36Sopenharmony_ci * |            (0-N)                |
86662306a36Sopenharmony_ci * +---------------------------------+
86762306a36Sopenharmony_ci */
86862306a36Sopenharmony_ci
86962306a36Sopenharmony_cistatic int fastrpc_get_meta_size(struct fastrpc_invoke_ctx *ctx)
87062306a36Sopenharmony_ci{
87162306a36Sopenharmony_ci	int size = 0;
87262306a36Sopenharmony_ci
87362306a36Sopenharmony_ci	size = (sizeof(struct fastrpc_remote_buf) +
87462306a36Sopenharmony_ci		sizeof(struct fastrpc_invoke_buf) +
87562306a36Sopenharmony_ci		sizeof(struct fastrpc_phy_page)) * ctx->nscalars +
87662306a36Sopenharmony_ci		sizeof(u64) * FASTRPC_MAX_FDLIST +
87762306a36Sopenharmony_ci		sizeof(u32) * FASTRPC_MAX_CRCLIST;
87862306a36Sopenharmony_ci
87962306a36Sopenharmony_ci	return size;
88062306a36Sopenharmony_ci}
88162306a36Sopenharmony_ci
88262306a36Sopenharmony_cistatic u64 fastrpc_get_payload_size(struct fastrpc_invoke_ctx *ctx, int metalen)
88362306a36Sopenharmony_ci{
88462306a36Sopenharmony_ci	u64 size = 0;
88562306a36Sopenharmony_ci	int oix;
88662306a36Sopenharmony_ci
88762306a36Sopenharmony_ci	size = ALIGN(metalen, FASTRPC_ALIGN);
88862306a36Sopenharmony_ci	for (oix = 0; oix < ctx->nbufs; oix++) {
88962306a36Sopenharmony_ci		int i = ctx->olaps[oix].raix;
89062306a36Sopenharmony_ci
89162306a36Sopenharmony_ci		if (ctx->args[i].fd == 0 || ctx->args[i].fd == -1) {
89262306a36Sopenharmony_ci
89362306a36Sopenharmony_ci			if (ctx->olaps[oix].offset == 0)
89462306a36Sopenharmony_ci				size = ALIGN(size, FASTRPC_ALIGN);
89562306a36Sopenharmony_ci
89662306a36Sopenharmony_ci			size += (ctx->olaps[oix].mend - ctx->olaps[oix].mstart);
89762306a36Sopenharmony_ci		}
89862306a36Sopenharmony_ci	}
89962306a36Sopenharmony_ci
90062306a36Sopenharmony_ci	return size;
90162306a36Sopenharmony_ci}
90262306a36Sopenharmony_ci
90362306a36Sopenharmony_cistatic int fastrpc_create_maps(struct fastrpc_invoke_ctx *ctx)
90462306a36Sopenharmony_ci{
90562306a36Sopenharmony_ci	struct device *dev = ctx->fl->sctx->dev;
90662306a36Sopenharmony_ci	int i, err;
90762306a36Sopenharmony_ci
90862306a36Sopenharmony_ci	for (i = 0; i < ctx->nscalars; ++i) {
90962306a36Sopenharmony_ci
91062306a36Sopenharmony_ci		if (ctx->args[i].fd == 0 || ctx->args[i].fd == -1 ||
91162306a36Sopenharmony_ci		    ctx->args[i].length == 0)
91262306a36Sopenharmony_ci			continue;
91362306a36Sopenharmony_ci
91462306a36Sopenharmony_ci		err = fastrpc_map_create(ctx->fl, ctx->args[i].fd,
91562306a36Sopenharmony_ci			 ctx->args[i].length, ctx->args[i].attr, &ctx->maps[i]);
91662306a36Sopenharmony_ci		if (err) {
91762306a36Sopenharmony_ci			dev_err(dev, "Error Creating map %d\n", err);
91862306a36Sopenharmony_ci			return -EINVAL;
91962306a36Sopenharmony_ci		}
92062306a36Sopenharmony_ci
92162306a36Sopenharmony_ci	}
92262306a36Sopenharmony_ci	return 0;
92362306a36Sopenharmony_ci}
92462306a36Sopenharmony_ci
92562306a36Sopenharmony_cistatic struct fastrpc_invoke_buf *fastrpc_invoke_buf_start(union fastrpc_remote_arg *pra, int len)
92662306a36Sopenharmony_ci{
92762306a36Sopenharmony_ci	return (struct fastrpc_invoke_buf *)(&pra[len]);
92862306a36Sopenharmony_ci}
92962306a36Sopenharmony_ci
93062306a36Sopenharmony_cistatic struct fastrpc_phy_page *fastrpc_phy_page_start(struct fastrpc_invoke_buf *buf, int len)
93162306a36Sopenharmony_ci{
93262306a36Sopenharmony_ci	return (struct fastrpc_phy_page *)(&buf[len]);
93362306a36Sopenharmony_ci}
93462306a36Sopenharmony_ci
93562306a36Sopenharmony_cistatic int fastrpc_get_args(u32 kernel, struct fastrpc_invoke_ctx *ctx)
93662306a36Sopenharmony_ci{
93762306a36Sopenharmony_ci	struct device *dev = ctx->fl->sctx->dev;
93862306a36Sopenharmony_ci	union fastrpc_remote_arg *rpra;
93962306a36Sopenharmony_ci	struct fastrpc_invoke_buf *list;
94062306a36Sopenharmony_ci	struct fastrpc_phy_page *pages;
94162306a36Sopenharmony_ci	int inbufs, i, oix, err = 0;
94262306a36Sopenharmony_ci	u64 len, rlen, pkt_size;
94362306a36Sopenharmony_ci	u64 pg_start, pg_end;
94462306a36Sopenharmony_ci	uintptr_t args;
94562306a36Sopenharmony_ci	int metalen;
94662306a36Sopenharmony_ci
94762306a36Sopenharmony_ci	inbufs = REMOTE_SCALARS_INBUFS(ctx->sc);
94862306a36Sopenharmony_ci	metalen = fastrpc_get_meta_size(ctx);
94962306a36Sopenharmony_ci	pkt_size = fastrpc_get_payload_size(ctx, metalen);
95062306a36Sopenharmony_ci
95162306a36Sopenharmony_ci	err = fastrpc_create_maps(ctx);
95262306a36Sopenharmony_ci	if (err)
95362306a36Sopenharmony_ci		return err;
95462306a36Sopenharmony_ci
95562306a36Sopenharmony_ci	ctx->msg_sz = pkt_size;
95662306a36Sopenharmony_ci
95762306a36Sopenharmony_ci	err = fastrpc_buf_alloc(ctx->fl, dev, pkt_size, &ctx->buf);
95862306a36Sopenharmony_ci	if (err)
95962306a36Sopenharmony_ci		return err;
96062306a36Sopenharmony_ci
96162306a36Sopenharmony_ci	memset(ctx->buf->virt, 0, pkt_size);
96262306a36Sopenharmony_ci	rpra = ctx->buf->virt;
96362306a36Sopenharmony_ci	list = fastrpc_invoke_buf_start(rpra, ctx->nscalars);
96462306a36Sopenharmony_ci	pages = fastrpc_phy_page_start(list, ctx->nscalars);
96562306a36Sopenharmony_ci	args = (uintptr_t)ctx->buf->virt + metalen;
96662306a36Sopenharmony_ci	rlen = pkt_size - metalen;
96762306a36Sopenharmony_ci	ctx->rpra = rpra;
96862306a36Sopenharmony_ci
96962306a36Sopenharmony_ci	for (oix = 0; oix < ctx->nbufs; ++oix) {
97062306a36Sopenharmony_ci		int mlen;
97162306a36Sopenharmony_ci
97262306a36Sopenharmony_ci		i = ctx->olaps[oix].raix;
97362306a36Sopenharmony_ci		len = ctx->args[i].length;
97462306a36Sopenharmony_ci
97562306a36Sopenharmony_ci		rpra[i].buf.pv = 0;
97662306a36Sopenharmony_ci		rpra[i].buf.len = len;
97762306a36Sopenharmony_ci		list[i].num = len ? 1 : 0;
97862306a36Sopenharmony_ci		list[i].pgidx = i;
97962306a36Sopenharmony_ci
98062306a36Sopenharmony_ci		if (!len)
98162306a36Sopenharmony_ci			continue;
98262306a36Sopenharmony_ci
98362306a36Sopenharmony_ci		if (ctx->maps[i]) {
98462306a36Sopenharmony_ci			struct vm_area_struct *vma = NULL;
98562306a36Sopenharmony_ci
98662306a36Sopenharmony_ci			rpra[i].buf.pv = (u64) ctx->args[i].ptr;
98762306a36Sopenharmony_ci			pages[i].addr = ctx->maps[i]->phys;
98862306a36Sopenharmony_ci
98962306a36Sopenharmony_ci			mmap_read_lock(current->mm);
99062306a36Sopenharmony_ci			vma = find_vma(current->mm, ctx->args[i].ptr);
99162306a36Sopenharmony_ci			if (vma)
99262306a36Sopenharmony_ci				pages[i].addr += ctx->args[i].ptr -
99362306a36Sopenharmony_ci						 vma->vm_start;
99462306a36Sopenharmony_ci			mmap_read_unlock(current->mm);
99562306a36Sopenharmony_ci
99662306a36Sopenharmony_ci			pg_start = (ctx->args[i].ptr & PAGE_MASK) >> PAGE_SHIFT;
99762306a36Sopenharmony_ci			pg_end = ((ctx->args[i].ptr + len - 1) & PAGE_MASK) >>
99862306a36Sopenharmony_ci				  PAGE_SHIFT;
99962306a36Sopenharmony_ci			pages[i].size = (pg_end - pg_start + 1) * PAGE_SIZE;
100062306a36Sopenharmony_ci
100162306a36Sopenharmony_ci		} else {
100262306a36Sopenharmony_ci
100362306a36Sopenharmony_ci			if (ctx->olaps[oix].offset == 0) {
100462306a36Sopenharmony_ci				rlen -= ALIGN(args, FASTRPC_ALIGN) - args;
100562306a36Sopenharmony_ci				args = ALIGN(args, FASTRPC_ALIGN);
100662306a36Sopenharmony_ci			}
100762306a36Sopenharmony_ci
100862306a36Sopenharmony_ci			mlen = ctx->olaps[oix].mend - ctx->olaps[oix].mstart;
100962306a36Sopenharmony_ci
101062306a36Sopenharmony_ci			if (rlen < mlen)
101162306a36Sopenharmony_ci				goto bail;
101262306a36Sopenharmony_ci
101362306a36Sopenharmony_ci			rpra[i].buf.pv = args - ctx->olaps[oix].offset;
101462306a36Sopenharmony_ci			pages[i].addr = ctx->buf->phys -
101562306a36Sopenharmony_ci					ctx->olaps[oix].offset +
101662306a36Sopenharmony_ci					(pkt_size - rlen);
101762306a36Sopenharmony_ci			pages[i].addr = pages[i].addr &	PAGE_MASK;
101862306a36Sopenharmony_ci
101962306a36Sopenharmony_ci			pg_start = (args & PAGE_MASK) >> PAGE_SHIFT;
102062306a36Sopenharmony_ci			pg_end = ((args + len - 1) & PAGE_MASK) >> PAGE_SHIFT;
102162306a36Sopenharmony_ci			pages[i].size = (pg_end - pg_start + 1) * PAGE_SIZE;
102262306a36Sopenharmony_ci			args = args + mlen;
102362306a36Sopenharmony_ci			rlen -= mlen;
102462306a36Sopenharmony_ci		}
102562306a36Sopenharmony_ci
102662306a36Sopenharmony_ci		if (i < inbufs && !ctx->maps[i]) {
102762306a36Sopenharmony_ci			void *dst = (void *)(uintptr_t)rpra[i].buf.pv;
102862306a36Sopenharmony_ci			void *src = (void *)(uintptr_t)ctx->args[i].ptr;
102962306a36Sopenharmony_ci
103062306a36Sopenharmony_ci			if (!kernel) {
103162306a36Sopenharmony_ci				if (copy_from_user(dst, (void __user *)src,
103262306a36Sopenharmony_ci						   len)) {
103362306a36Sopenharmony_ci					err = -EFAULT;
103462306a36Sopenharmony_ci					goto bail;
103562306a36Sopenharmony_ci				}
103662306a36Sopenharmony_ci			} else {
103762306a36Sopenharmony_ci				memcpy(dst, src, len);
103862306a36Sopenharmony_ci			}
103962306a36Sopenharmony_ci		}
104062306a36Sopenharmony_ci	}
104162306a36Sopenharmony_ci
104262306a36Sopenharmony_ci	for (i = ctx->nbufs; i < ctx->nscalars; ++i) {
104362306a36Sopenharmony_ci		list[i].num = ctx->args[i].length ? 1 : 0;
104462306a36Sopenharmony_ci		list[i].pgidx = i;
104562306a36Sopenharmony_ci		if (ctx->maps[i]) {
104662306a36Sopenharmony_ci			pages[i].addr = ctx->maps[i]->phys;
104762306a36Sopenharmony_ci			pages[i].size = ctx->maps[i]->size;
104862306a36Sopenharmony_ci		}
104962306a36Sopenharmony_ci		rpra[i].dma.fd = ctx->args[i].fd;
105062306a36Sopenharmony_ci		rpra[i].dma.len = ctx->args[i].length;
105162306a36Sopenharmony_ci		rpra[i].dma.offset = (u64) ctx->args[i].ptr;
105262306a36Sopenharmony_ci	}
105362306a36Sopenharmony_ci
105462306a36Sopenharmony_cibail:
105562306a36Sopenharmony_ci	if (err)
105662306a36Sopenharmony_ci		dev_err(dev, "Error: get invoke args failed:%d\n", err);
105762306a36Sopenharmony_ci
105862306a36Sopenharmony_ci	return err;
105962306a36Sopenharmony_ci}
106062306a36Sopenharmony_ci
106162306a36Sopenharmony_cistatic int fastrpc_put_args(struct fastrpc_invoke_ctx *ctx,
106262306a36Sopenharmony_ci			    u32 kernel)
106362306a36Sopenharmony_ci{
106462306a36Sopenharmony_ci	union fastrpc_remote_arg *rpra = ctx->rpra;
106562306a36Sopenharmony_ci	struct fastrpc_user *fl = ctx->fl;
106662306a36Sopenharmony_ci	struct fastrpc_map *mmap = NULL;
106762306a36Sopenharmony_ci	struct fastrpc_invoke_buf *list;
106862306a36Sopenharmony_ci	struct fastrpc_phy_page *pages;
106962306a36Sopenharmony_ci	u64 *fdlist;
107062306a36Sopenharmony_ci	int i, inbufs, outbufs, handles;
107162306a36Sopenharmony_ci
107262306a36Sopenharmony_ci	inbufs = REMOTE_SCALARS_INBUFS(ctx->sc);
107362306a36Sopenharmony_ci	outbufs = REMOTE_SCALARS_OUTBUFS(ctx->sc);
107462306a36Sopenharmony_ci	handles = REMOTE_SCALARS_INHANDLES(ctx->sc) + REMOTE_SCALARS_OUTHANDLES(ctx->sc);
107562306a36Sopenharmony_ci	list = fastrpc_invoke_buf_start(rpra, ctx->nscalars);
107662306a36Sopenharmony_ci	pages = fastrpc_phy_page_start(list, ctx->nscalars);
107762306a36Sopenharmony_ci	fdlist = (uint64_t *)(pages + inbufs + outbufs + handles);
107862306a36Sopenharmony_ci
107962306a36Sopenharmony_ci	for (i = inbufs; i < ctx->nbufs; ++i) {
108062306a36Sopenharmony_ci		if (!ctx->maps[i]) {
108162306a36Sopenharmony_ci			void *src = (void *)(uintptr_t)rpra[i].buf.pv;
108262306a36Sopenharmony_ci			void *dst = (void *)(uintptr_t)ctx->args[i].ptr;
108362306a36Sopenharmony_ci			u64 len = rpra[i].buf.len;
108462306a36Sopenharmony_ci
108562306a36Sopenharmony_ci			if (!kernel) {
108662306a36Sopenharmony_ci				if (copy_to_user((void __user *)dst, src, len))
108762306a36Sopenharmony_ci					return -EFAULT;
108862306a36Sopenharmony_ci			} else {
108962306a36Sopenharmony_ci				memcpy(dst, src, len);
109062306a36Sopenharmony_ci			}
109162306a36Sopenharmony_ci		}
109262306a36Sopenharmony_ci	}
109362306a36Sopenharmony_ci
109462306a36Sopenharmony_ci	/* Clean up fdlist which is updated by DSP */
109562306a36Sopenharmony_ci	for (i = 0; i < FASTRPC_MAX_FDLIST; i++) {
109662306a36Sopenharmony_ci		if (!fdlist[i])
109762306a36Sopenharmony_ci			break;
109862306a36Sopenharmony_ci		if (!fastrpc_map_lookup(fl, (int)fdlist[i], &mmap, false))
109962306a36Sopenharmony_ci			fastrpc_map_put(mmap);
110062306a36Sopenharmony_ci	}
110162306a36Sopenharmony_ci
110262306a36Sopenharmony_ci	return 0;
110362306a36Sopenharmony_ci}
110462306a36Sopenharmony_ci
110562306a36Sopenharmony_cistatic int fastrpc_invoke_send(struct fastrpc_session_ctx *sctx,
110662306a36Sopenharmony_ci			       struct fastrpc_invoke_ctx *ctx,
110762306a36Sopenharmony_ci			       u32 kernel, uint32_t handle)
110862306a36Sopenharmony_ci{
110962306a36Sopenharmony_ci	struct fastrpc_channel_ctx *cctx;
111062306a36Sopenharmony_ci	struct fastrpc_user *fl = ctx->fl;
111162306a36Sopenharmony_ci	struct fastrpc_msg *msg = &ctx->msg;
111262306a36Sopenharmony_ci	int ret;
111362306a36Sopenharmony_ci
111462306a36Sopenharmony_ci	cctx = fl->cctx;
111562306a36Sopenharmony_ci	msg->pid = fl->tgid;
111662306a36Sopenharmony_ci	msg->tid = current->pid;
111762306a36Sopenharmony_ci
111862306a36Sopenharmony_ci	if (kernel)
111962306a36Sopenharmony_ci		msg->pid = 0;
112062306a36Sopenharmony_ci
112162306a36Sopenharmony_ci	msg->ctx = ctx->ctxid | fl->pd;
112262306a36Sopenharmony_ci	msg->handle = handle;
112362306a36Sopenharmony_ci	msg->sc = ctx->sc;
112462306a36Sopenharmony_ci	msg->addr = ctx->buf ? ctx->buf->phys : 0;
112562306a36Sopenharmony_ci	msg->size = roundup(ctx->msg_sz, PAGE_SIZE);
112662306a36Sopenharmony_ci	fastrpc_context_get(ctx);
112762306a36Sopenharmony_ci
112862306a36Sopenharmony_ci	ret = rpmsg_send(cctx->rpdev->ept, (void *)msg, sizeof(*msg));
112962306a36Sopenharmony_ci
113062306a36Sopenharmony_ci	if (ret)
113162306a36Sopenharmony_ci		fastrpc_context_put(ctx);
113262306a36Sopenharmony_ci
113362306a36Sopenharmony_ci	return ret;
113462306a36Sopenharmony_ci
113562306a36Sopenharmony_ci}
113662306a36Sopenharmony_ci
113762306a36Sopenharmony_cistatic int fastrpc_internal_invoke(struct fastrpc_user *fl,  u32 kernel,
113862306a36Sopenharmony_ci				   u32 handle, u32 sc,
113962306a36Sopenharmony_ci				   struct fastrpc_invoke_args *args)
114062306a36Sopenharmony_ci{
114162306a36Sopenharmony_ci	struct fastrpc_invoke_ctx *ctx = NULL;
114262306a36Sopenharmony_ci	struct fastrpc_buf *buf, *b;
114362306a36Sopenharmony_ci
114462306a36Sopenharmony_ci	int err = 0;
114562306a36Sopenharmony_ci
114662306a36Sopenharmony_ci	if (!fl->sctx)
114762306a36Sopenharmony_ci		return -EINVAL;
114862306a36Sopenharmony_ci
114962306a36Sopenharmony_ci	if (!fl->cctx->rpdev)
115062306a36Sopenharmony_ci		return -EPIPE;
115162306a36Sopenharmony_ci
115262306a36Sopenharmony_ci	if (handle == FASTRPC_INIT_HANDLE && !kernel) {
115362306a36Sopenharmony_ci		dev_warn_ratelimited(fl->sctx->dev, "user app trying to send a kernel RPC message (%d)\n",  handle);
115462306a36Sopenharmony_ci		return -EPERM;
115562306a36Sopenharmony_ci	}
115662306a36Sopenharmony_ci
115762306a36Sopenharmony_ci	ctx = fastrpc_context_alloc(fl, kernel, sc, args);
115862306a36Sopenharmony_ci	if (IS_ERR(ctx))
115962306a36Sopenharmony_ci		return PTR_ERR(ctx);
116062306a36Sopenharmony_ci
116162306a36Sopenharmony_ci	err = fastrpc_get_args(kernel, ctx);
116262306a36Sopenharmony_ci	if (err)
116362306a36Sopenharmony_ci		goto bail;
116462306a36Sopenharmony_ci
116562306a36Sopenharmony_ci	/* make sure that all CPU memory writes are seen by DSP */
116662306a36Sopenharmony_ci	dma_wmb();
116762306a36Sopenharmony_ci	/* Send invoke buffer to remote dsp */
116862306a36Sopenharmony_ci	err = fastrpc_invoke_send(fl->sctx, ctx, kernel, handle);
116962306a36Sopenharmony_ci	if (err)
117062306a36Sopenharmony_ci		goto bail;
117162306a36Sopenharmony_ci
117262306a36Sopenharmony_ci	if (kernel) {
117362306a36Sopenharmony_ci		if (!wait_for_completion_timeout(&ctx->work, 10 * HZ))
117462306a36Sopenharmony_ci			err = -ETIMEDOUT;
117562306a36Sopenharmony_ci	} else {
117662306a36Sopenharmony_ci		err = wait_for_completion_interruptible(&ctx->work);
117762306a36Sopenharmony_ci	}
117862306a36Sopenharmony_ci
117962306a36Sopenharmony_ci	if (err)
118062306a36Sopenharmony_ci		goto bail;
118162306a36Sopenharmony_ci
118262306a36Sopenharmony_ci	/* make sure that all memory writes by DSP are seen by CPU */
118362306a36Sopenharmony_ci	dma_rmb();
118462306a36Sopenharmony_ci	/* populate all the output buffers with results */
118562306a36Sopenharmony_ci	err = fastrpc_put_args(ctx, kernel);
118662306a36Sopenharmony_ci	if (err)
118762306a36Sopenharmony_ci		goto bail;
118862306a36Sopenharmony_ci
118962306a36Sopenharmony_ci	/* Check the response from remote dsp */
119062306a36Sopenharmony_ci	err = ctx->retval;
119162306a36Sopenharmony_ci	if (err)
119262306a36Sopenharmony_ci		goto bail;
119362306a36Sopenharmony_ci
119462306a36Sopenharmony_cibail:
119562306a36Sopenharmony_ci	if (err != -ERESTARTSYS && err != -ETIMEDOUT) {
119662306a36Sopenharmony_ci		/* We are done with this compute context */
119762306a36Sopenharmony_ci		spin_lock(&fl->lock);
119862306a36Sopenharmony_ci		list_del(&ctx->node);
119962306a36Sopenharmony_ci		spin_unlock(&fl->lock);
120062306a36Sopenharmony_ci		fastrpc_context_put(ctx);
120162306a36Sopenharmony_ci	}
120262306a36Sopenharmony_ci
120362306a36Sopenharmony_ci	if (err == -ERESTARTSYS) {
120462306a36Sopenharmony_ci		list_for_each_entry_safe(buf, b, &fl->mmaps, node) {
120562306a36Sopenharmony_ci			list_del(&buf->node);
120662306a36Sopenharmony_ci			list_add_tail(&buf->node, &fl->cctx->invoke_interrupted_mmaps);
120762306a36Sopenharmony_ci		}
120862306a36Sopenharmony_ci	}
120962306a36Sopenharmony_ci
121062306a36Sopenharmony_ci	if (err)
121162306a36Sopenharmony_ci		dev_dbg(fl->sctx->dev, "Error: Invoke Failed %d\n", err);
121262306a36Sopenharmony_ci
121362306a36Sopenharmony_ci	return err;
121462306a36Sopenharmony_ci}
121562306a36Sopenharmony_ci
121662306a36Sopenharmony_cistatic bool is_session_rejected(struct fastrpc_user *fl, bool unsigned_pd_request)
121762306a36Sopenharmony_ci{
121862306a36Sopenharmony_ci	/* Check if the device node is non-secure and channel is secure*/
121962306a36Sopenharmony_ci	if (!fl->is_secure_dev && fl->cctx->secure) {
122062306a36Sopenharmony_ci		/*
122162306a36Sopenharmony_ci		 * Allow untrusted applications to offload only to Unsigned PD when
122262306a36Sopenharmony_ci		 * channel is configured as secure and block untrusted apps on channel
122362306a36Sopenharmony_ci		 * that does not support unsigned PD offload
122462306a36Sopenharmony_ci		 */
122562306a36Sopenharmony_ci		if (!fl->cctx->unsigned_support || !unsigned_pd_request) {
122662306a36Sopenharmony_ci			dev_err(&fl->cctx->rpdev->dev, "Error: Untrusted application trying to offload to signed PD");
122762306a36Sopenharmony_ci			return true;
122862306a36Sopenharmony_ci		}
122962306a36Sopenharmony_ci	}
123062306a36Sopenharmony_ci
123162306a36Sopenharmony_ci	return false;
123262306a36Sopenharmony_ci}
123362306a36Sopenharmony_ci
123462306a36Sopenharmony_cistatic int fastrpc_init_create_static_process(struct fastrpc_user *fl,
123562306a36Sopenharmony_ci					      char __user *argp)
123662306a36Sopenharmony_ci{
123762306a36Sopenharmony_ci	struct fastrpc_init_create_static init;
123862306a36Sopenharmony_ci	struct fastrpc_invoke_args *args;
123962306a36Sopenharmony_ci	struct fastrpc_phy_page pages[1];
124062306a36Sopenharmony_ci	char *name;
124162306a36Sopenharmony_ci	int err;
124262306a36Sopenharmony_ci	struct {
124362306a36Sopenharmony_ci		int pgid;
124462306a36Sopenharmony_ci		u32 namelen;
124562306a36Sopenharmony_ci		u32 pageslen;
124662306a36Sopenharmony_ci	} inbuf;
124762306a36Sopenharmony_ci	u32 sc;
124862306a36Sopenharmony_ci
124962306a36Sopenharmony_ci	args = kcalloc(FASTRPC_CREATE_STATIC_PROCESS_NARGS, sizeof(*args), GFP_KERNEL);
125062306a36Sopenharmony_ci	if (!args)
125162306a36Sopenharmony_ci		return -ENOMEM;
125262306a36Sopenharmony_ci
125362306a36Sopenharmony_ci	if (copy_from_user(&init, argp, sizeof(init))) {
125462306a36Sopenharmony_ci		err = -EFAULT;
125562306a36Sopenharmony_ci		goto err;
125662306a36Sopenharmony_ci	}
125762306a36Sopenharmony_ci
125862306a36Sopenharmony_ci	if (init.namelen > INIT_FILE_NAMELEN_MAX) {
125962306a36Sopenharmony_ci		err = -EINVAL;
126062306a36Sopenharmony_ci		goto err;
126162306a36Sopenharmony_ci	}
126262306a36Sopenharmony_ci
126362306a36Sopenharmony_ci	name = kzalloc(init.namelen, GFP_KERNEL);
126462306a36Sopenharmony_ci	if (!name) {
126562306a36Sopenharmony_ci		err = -ENOMEM;
126662306a36Sopenharmony_ci		goto err;
126762306a36Sopenharmony_ci	}
126862306a36Sopenharmony_ci
126962306a36Sopenharmony_ci	if (copy_from_user(name, (void __user *)(uintptr_t)init.name, init.namelen)) {
127062306a36Sopenharmony_ci		err = -EFAULT;
127162306a36Sopenharmony_ci		goto err_name;
127262306a36Sopenharmony_ci	}
127362306a36Sopenharmony_ci
127462306a36Sopenharmony_ci	if (!fl->cctx->remote_heap) {
127562306a36Sopenharmony_ci		err = fastrpc_remote_heap_alloc(fl, fl->sctx->dev, init.memlen,
127662306a36Sopenharmony_ci						&fl->cctx->remote_heap);
127762306a36Sopenharmony_ci		if (err)
127862306a36Sopenharmony_ci			goto err_name;
127962306a36Sopenharmony_ci
128062306a36Sopenharmony_ci		/* Map if we have any heap VMIDs associated with this ADSP Static Process. */
128162306a36Sopenharmony_ci		if (fl->cctx->vmcount) {
128262306a36Sopenharmony_ci			err = qcom_scm_assign_mem(fl->cctx->remote_heap->phys,
128362306a36Sopenharmony_ci							(u64)fl->cctx->remote_heap->size,
128462306a36Sopenharmony_ci							&fl->cctx->perms,
128562306a36Sopenharmony_ci							fl->cctx->vmperms, fl->cctx->vmcount);
128662306a36Sopenharmony_ci			if (err) {
128762306a36Sopenharmony_ci				dev_err(fl->sctx->dev, "Failed to assign memory with phys 0x%llx size 0x%llx err %d",
128862306a36Sopenharmony_ci					fl->cctx->remote_heap->phys, fl->cctx->remote_heap->size, err);
128962306a36Sopenharmony_ci				goto err_map;
129062306a36Sopenharmony_ci			}
129162306a36Sopenharmony_ci		}
129262306a36Sopenharmony_ci	}
129362306a36Sopenharmony_ci
129462306a36Sopenharmony_ci	inbuf.pgid = fl->tgid;
129562306a36Sopenharmony_ci	inbuf.namelen = init.namelen;
129662306a36Sopenharmony_ci	inbuf.pageslen = 0;
129762306a36Sopenharmony_ci	fl->pd = USER_PD;
129862306a36Sopenharmony_ci
129962306a36Sopenharmony_ci	args[0].ptr = (u64)(uintptr_t)&inbuf;
130062306a36Sopenharmony_ci	args[0].length = sizeof(inbuf);
130162306a36Sopenharmony_ci	args[0].fd = -1;
130262306a36Sopenharmony_ci
130362306a36Sopenharmony_ci	args[1].ptr = (u64)(uintptr_t)name;
130462306a36Sopenharmony_ci	args[1].length = inbuf.namelen;
130562306a36Sopenharmony_ci	args[1].fd = -1;
130662306a36Sopenharmony_ci
130762306a36Sopenharmony_ci	pages[0].addr = fl->cctx->remote_heap->phys;
130862306a36Sopenharmony_ci	pages[0].size = fl->cctx->remote_heap->size;
130962306a36Sopenharmony_ci
131062306a36Sopenharmony_ci	args[2].ptr = (u64)(uintptr_t) pages;
131162306a36Sopenharmony_ci	args[2].length = sizeof(*pages);
131262306a36Sopenharmony_ci	args[2].fd = -1;
131362306a36Sopenharmony_ci
131462306a36Sopenharmony_ci	sc = FASTRPC_SCALARS(FASTRPC_RMID_INIT_CREATE_STATIC, 3, 0);
131562306a36Sopenharmony_ci
131662306a36Sopenharmony_ci	err = fastrpc_internal_invoke(fl, true, FASTRPC_INIT_HANDLE,
131762306a36Sopenharmony_ci				      sc, args);
131862306a36Sopenharmony_ci	if (err)
131962306a36Sopenharmony_ci		goto err_invoke;
132062306a36Sopenharmony_ci
132162306a36Sopenharmony_ci	kfree(args);
132262306a36Sopenharmony_ci
132362306a36Sopenharmony_ci	return 0;
132462306a36Sopenharmony_cierr_invoke:
132562306a36Sopenharmony_ci	if (fl->cctx->vmcount) {
132662306a36Sopenharmony_ci		u64 src_perms = 0;
132762306a36Sopenharmony_ci		struct qcom_scm_vmperm dst_perms;
132862306a36Sopenharmony_ci		u32 i;
132962306a36Sopenharmony_ci
133062306a36Sopenharmony_ci		for (i = 0; i < fl->cctx->vmcount; i++)
133162306a36Sopenharmony_ci			src_perms |= BIT(fl->cctx->vmperms[i].vmid);
133262306a36Sopenharmony_ci
133362306a36Sopenharmony_ci		dst_perms.vmid = QCOM_SCM_VMID_HLOS;
133462306a36Sopenharmony_ci		dst_perms.perm = QCOM_SCM_PERM_RWX;
133562306a36Sopenharmony_ci		err = qcom_scm_assign_mem(fl->cctx->remote_heap->phys,
133662306a36Sopenharmony_ci						(u64)fl->cctx->remote_heap->size,
133762306a36Sopenharmony_ci						&src_perms, &dst_perms, 1);
133862306a36Sopenharmony_ci		if (err)
133962306a36Sopenharmony_ci			dev_err(fl->sctx->dev, "Failed to assign memory phys 0x%llx size 0x%llx err %d",
134062306a36Sopenharmony_ci				fl->cctx->remote_heap->phys, fl->cctx->remote_heap->size, err);
134162306a36Sopenharmony_ci	}
134262306a36Sopenharmony_cierr_map:
134362306a36Sopenharmony_ci	fastrpc_buf_free(fl->cctx->remote_heap);
134462306a36Sopenharmony_cierr_name:
134562306a36Sopenharmony_ci	kfree(name);
134662306a36Sopenharmony_cierr:
134762306a36Sopenharmony_ci	kfree(args);
134862306a36Sopenharmony_ci
134962306a36Sopenharmony_ci	return err;
135062306a36Sopenharmony_ci}
135162306a36Sopenharmony_ci
135262306a36Sopenharmony_cistatic int fastrpc_init_create_process(struct fastrpc_user *fl,
135362306a36Sopenharmony_ci					char __user *argp)
135462306a36Sopenharmony_ci{
135562306a36Sopenharmony_ci	struct fastrpc_init_create init;
135662306a36Sopenharmony_ci	struct fastrpc_invoke_args *args;
135762306a36Sopenharmony_ci	struct fastrpc_phy_page pages[1];
135862306a36Sopenharmony_ci	struct fastrpc_map *map = NULL;
135962306a36Sopenharmony_ci	struct fastrpc_buf *imem = NULL;
136062306a36Sopenharmony_ci	int memlen;
136162306a36Sopenharmony_ci	int err;
136262306a36Sopenharmony_ci	struct {
136362306a36Sopenharmony_ci		int pgid;
136462306a36Sopenharmony_ci		u32 namelen;
136562306a36Sopenharmony_ci		u32 filelen;
136662306a36Sopenharmony_ci		u32 pageslen;
136762306a36Sopenharmony_ci		u32 attrs;
136862306a36Sopenharmony_ci		u32 siglen;
136962306a36Sopenharmony_ci	} inbuf;
137062306a36Sopenharmony_ci	u32 sc;
137162306a36Sopenharmony_ci	bool unsigned_module = false;
137262306a36Sopenharmony_ci
137362306a36Sopenharmony_ci	args = kcalloc(FASTRPC_CREATE_PROCESS_NARGS, sizeof(*args), GFP_KERNEL);
137462306a36Sopenharmony_ci	if (!args)
137562306a36Sopenharmony_ci		return -ENOMEM;
137662306a36Sopenharmony_ci
137762306a36Sopenharmony_ci	if (copy_from_user(&init, argp, sizeof(init))) {
137862306a36Sopenharmony_ci		err = -EFAULT;
137962306a36Sopenharmony_ci		goto err;
138062306a36Sopenharmony_ci	}
138162306a36Sopenharmony_ci
138262306a36Sopenharmony_ci	if (init.attrs & FASTRPC_MODE_UNSIGNED_MODULE)
138362306a36Sopenharmony_ci		unsigned_module = true;
138462306a36Sopenharmony_ci
138562306a36Sopenharmony_ci	if (is_session_rejected(fl, unsigned_module)) {
138662306a36Sopenharmony_ci		err = -ECONNREFUSED;
138762306a36Sopenharmony_ci		goto err;
138862306a36Sopenharmony_ci	}
138962306a36Sopenharmony_ci
139062306a36Sopenharmony_ci	if (init.filelen > INIT_FILELEN_MAX) {
139162306a36Sopenharmony_ci		err = -EINVAL;
139262306a36Sopenharmony_ci		goto err;
139362306a36Sopenharmony_ci	}
139462306a36Sopenharmony_ci
139562306a36Sopenharmony_ci	inbuf.pgid = fl->tgid;
139662306a36Sopenharmony_ci	inbuf.namelen = strlen(current->comm) + 1;
139762306a36Sopenharmony_ci	inbuf.filelen = init.filelen;
139862306a36Sopenharmony_ci	inbuf.pageslen = 1;
139962306a36Sopenharmony_ci	inbuf.attrs = init.attrs;
140062306a36Sopenharmony_ci	inbuf.siglen = init.siglen;
140162306a36Sopenharmony_ci	fl->pd = USER_PD;
140262306a36Sopenharmony_ci
140362306a36Sopenharmony_ci	if (init.filelen && init.filefd) {
140462306a36Sopenharmony_ci		err = fastrpc_map_create(fl, init.filefd, init.filelen, 0, &map);
140562306a36Sopenharmony_ci		if (err)
140662306a36Sopenharmony_ci			goto err;
140762306a36Sopenharmony_ci	}
140862306a36Sopenharmony_ci
140962306a36Sopenharmony_ci	memlen = ALIGN(max(INIT_FILELEN_MAX, (int)init.filelen * 4),
141062306a36Sopenharmony_ci		       1024 * 1024);
141162306a36Sopenharmony_ci	err = fastrpc_buf_alloc(fl, fl->sctx->dev, memlen,
141262306a36Sopenharmony_ci				&imem);
141362306a36Sopenharmony_ci	if (err)
141462306a36Sopenharmony_ci		goto err_alloc;
141562306a36Sopenharmony_ci
141662306a36Sopenharmony_ci	fl->init_mem = imem;
141762306a36Sopenharmony_ci	args[0].ptr = (u64)(uintptr_t)&inbuf;
141862306a36Sopenharmony_ci	args[0].length = sizeof(inbuf);
141962306a36Sopenharmony_ci	args[0].fd = -1;
142062306a36Sopenharmony_ci
142162306a36Sopenharmony_ci	args[1].ptr = (u64)(uintptr_t)current->comm;
142262306a36Sopenharmony_ci	args[1].length = inbuf.namelen;
142362306a36Sopenharmony_ci	args[1].fd = -1;
142462306a36Sopenharmony_ci
142562306a36Sopenharmony_ci	args[2].ptr = (u64) init.file;
142662306a36Sopenharmony_ci	args[2].length = inbuf.filelen;
142762306a36Sopenharmony_ci	args[2].fd = init.filefd;
142862306a36Sopenharmony_ci
142962306a36Sopenharmony_ci	pages[0].addr = imem->phys;
143062306a36Sopenharmony_ci	pages[0].size = imem->size;
143162306a36Sopenharmony_ci
143262306a36Sopenharmony_ci	args[3].ptr = (u64)(uintptr_t) pages;
143362306a36Sopenharmony_ci	args[3].length = 1 * sizeof(*pages);
143462306a36Sopenharmony_ci	args[3].fd = -1;
143562306a36Sopenharmony_ci
143662306a36Sopenharmony_ci	args[4].ptr = (u64)(uintptr_t)&inbuf.attrs;
143762306a36Sopenharmony_ci	args[4].length = sizeof(inbuf.attrs);
143862306a36Sopenharmony_ci	args[4].fd = -1;
143962306a36Sopenharmony_ci
144062306a36Sopenharmony_ci	args[5].ptr = (u64)(uintptr_t) &inbuf.siglen;
144162306a36Sopenharmony_ci	args[5].length = sizeof(inbuf.siglen);
144262306a36Sopenharmony_ci	args[5].fd = -1;
144362306a36Sopenharmony_ci
144462306a36Sopenharmony_ci	sc = FASTRPC_SCALARS(FASTRPC_RMID_INIT_CREATE, 4, 0);
144562306a36Sopenharmony_ci	if (init.attrs)
144662306a36Sopenharmony_ci		sc = FASTRPC_SCALARS(FASTRPC_RMID_INIT_CREATE_ATTR, 4, 0);
144762306a36Sopenharmony_ci
144862306a36Sopenharmony_ci	err = fastrpc_internal_invoke(fl, true, FASTRPC_INIT_HANDLE,
144962306a36Sopenharmony_ci				      sc, args);
145062306a36Sopenharmony_ci	if (err)
145162306a36Sopenharmony_ci		goto err_invoke;
145262306a36Sopenharmony_ci
145362306a36Sopenharmony_ci	kfree(args);
145462306a36Sopenharmony_ci
145562306a36Sopenharmony_ci	return 0;
145662306a36Sopenharmony_ci
145762306a36Sopenharmony_cierr_invoke:
145862306a36Sopenharmony_ci	fl->init_mem = NULL;
145962306a36Sopenharmony_ci	fastrpc_buf_free(imem);
146062306a36Sopenharmony_cierr_alloc:
146162306a36Sopenharmony_ci	fastrpc_map_put(map);
146262306a36Sopenharmony_cierr:
146362306a36Sopenharmony_ci	kfree(args);
146462306a36Sopenharmony_ci
146562306a36Sopenharmony_ci	return err;
146662306a36Sopenharmony_ci}
146762306a36Sopenharmony_ci
146862306a36Sopenharmony_cistatic struct fastrpc_session_ctx *fastrpc_session_alloc(
146962306a36Sopenharmony_ci					struct fastrpc_channel_ctx *cctx)
147062306a36Sopenharmony_ci{
147162306a36Sopenharmony_ci	struct fastrpc_session_ctx *session = NULL;
147262306a36Sopenharmony_ci	unsigned long flags;
147362306a36Sopenharmony_ci	int i;
147462306a36Sopenharmony_ci
147562306a36Sopenharmony_ci	spin_lock_irqsave(&cctx->lock, flags);
147662306a36Sopenharmony_ci	for (i = 0; i < cctx->sesscount; i++) {
147762306a36Sopenharmony_ci		if (!cctx->session[i].used && cctx->session[i].valid) {
147862306a36Sopenharmony_ci			cctx->session[i].used = true;
147962306a36Sopenharmony_ci			session = &cctx->session[i];
148062306a36Sopenharmony_ci			break;
148162306a36Sopenharmony_ci		}
148262306a36Sopenharmony_ci	}
148362306a36Sopenharmony_ci	spin_unlock_irqrestore(&cctx->lock, flags);
148462306a36Sopenharmony_ci
148562306a36Sopenharmony_ci	return session;
148662306a36Sopenharmony_ci}
148762306a36Sopenharmony_ci
148862306a36Sopenharmony_cistatic void fastrpc_session_free(struct fastrpc_channel_ctx *cctx,
148962306a36Sopenharmony_ci				 struct fastrpc_session_ctx *session)
149062306a36Sopenharmony_ci{
149162306a36Sopenharmony_ci	unsigned long flags;
149262306a36Sopenharmony_ci
149362306a36Sopenharmony_ci	spin_lock_irqsave(&cctx->lock, flags);
149462306a36Sopenharmony_ci	session->used = false;
149562306a36Sopenharmony_ci	spin_unlock_irqrestore(&cctx->lock, flags);
149662306a36Sopenharmony_ci}
149762306a36Sopenharmony_ci
149862306a36Sopenharmony_cistatic int fastrpc_release_current_dsp_process(struct fastrpc_user *fl)
149962306a36Sopenharmony_ci{
150062306a36Sopenharmony_ci	struct fastrpc_invoke_args args[1];
150162306a36Sopenharmony_ci	int tgid = 0;
150262306a36Sopenharmony_ci	u32 sc;
150362306a36Sopenharmony_ci
150462306a36Sopenharmony_ci	tgid = fl->tgid;
150562306a36Sopenharmony_ci	args[0].ptr = (u64)(uintptr_t) &tgid;
150662306a36Sopenharmony_ci	args[0].length = sizeof(tgid);
150762306a36Sopenharmony_ci	args[0].fd = -1;
150862306a36Sopenharmony_ci	sc = FASTRPC_SCALARS(FASTRPC_RMID_INIT_RELEASE, 1, 0);
150962306a36Sopenharmony_ci
151062306a36Sopenharmony_ci	return fastrpc_internal_invoke(fl, true, FASTRPC_INIT_HANDLE,
151162306a36Sopenharmony_ci				       sc, &args[0]);
151262306a36Sopenharmony_ci}
151362306a36Sopenharmony_ci
151462306a36Sopenharmony_cistatic int fastrpc_device_release(struct inode *inode, struct file *file)
151562306a36Sopenharmony_ci{
151662306a36Sopenharmony_ci	struct fastrpc_user *fl = (struct fastrpc_user *)file->private_data;
151762306a36Sopenharmony_ci	struct fastrpc_channel_ctx *cctx = fl->cctx;
151862306a36Sopenharmony_ci	struct fastrpc_invoke_ctx *ctx, *n;
151962306a36Sopenharmony_ci	struct fastrpc_map *map, *m;
152062306a36Sopenharmony_ci	struct fastrpc_buf *buf, *b;
152162306a36Sopenharmony_ci	unsigned long flags;
152262306a36Sopenharmony_ci
152362306a36Sopenharmony_ci	fastrpc_release_current_dsp_process(fl);
152462306a36Sopenharmony_ci
152562306a36Sopenharmony_ci	spin_lock_irqsave(&cctx->lock, flags);
152662306a36Sopenharmony_ci	list_del(&fl->user);
152762306a36Sopenharmony_ci	spin_unlock_irqrestore(&cctx->lock, flags);
152862306a36Sopenharmony_ci
152962306a36Sopenharmony_ci	if (fl->init_mem)
153062306a36Sopenharmony_ci		fastrpc_buf_free(fl->init_mem);
153162306a36Sopenharmony_ci
153262306a36Sopenharmony_ci	list_for_each_entry_safe(ctx, n, &fl->pending, node) {
153362306a36Sopenharmony_ci		list_del(&ctx->node);
153462306a36Sopenharmony_ci		fastrpc_context_put(ctx);
153562306a36Sopenharmony_ci	}
153662306a36Sopenharmony_ci
153762306a36Sopenharmony_ci	list_for_each_entry_safe(map, m, &fl->maps, node)
153862306a36Sopenharmony_ci		fastrpc_map_put(map);
153962306a36Sopenharmony_ci
154062306a36Sopenharmony_ci	list_for_each_entry_safe(buf, b, &fl->mmaps, node) {
154162306a36Sopenharmony_ci		list_del(&buf->node);
154262306a36Sopenharmony_ci		fastrpc_buf_free(buf);
154362306a36Sopenharmony_ci	}
154462306a36Sopenharmony_ci
154562306a36Sopenharmony_ci	fastrpc_session_free(cctx, fl->sctx);
154662306a36Sopenharmony_ci	fastrpc_channel_ctx_put(cctx);
154762306a36Sopenharmony_ci
154862306a36Sopenharmony_ci	mutex_destroy(&fl->mutex);
154962306a36Sopenharmony_ci	kfree(fl);
155062306a36Sopenharmony_ci	file->private_data = NULL;
155162306a36Sopenharmony_ci
155262306a36Sopenharmony_ci	return 0;
155362306a36Sopenharmony_ci}
155462306a36Sopenharmony_ci
155562306a36Sopenharmony_cistatic int fastrpc_device_open(struct inode *inode, struct file *filp)
155662306a36Sopenharmony_ci{
155762306a36Sopenharmony_ci	struct fastrpc_channel_ctx *cctx;
155862306a36Sopenharmony_ci	struct fastrpc_device *fdevice;
155962306a36Sopenharmony_ci	struct fastrpc_user *fl = NULL;
156062306a36Sopenharmony_ci	unsigned long flags;
156162306a36Sopenharmony_ci
156262306a36Sopenharmony_ci	fdevice = miscdev_to_fdevice(filp->private_data);
156362306a36Sopenharmony_ci	cctx = fdevice->cctx;
156462306a36Sopenharmony_ci
156562306a36Sopenharmony_ci	fl = kzalloc(sizeof(*fl), GFP_KERNEL);
156662306a36Sopenharmony_ci	if (!fl)
156762306a36Sopenharmony_ci		return -ENOMEM;
156862306a36Sopenharmony_ci
156962306a36Sopenharmony_ci	/* Released in fastrpc_device_release() */
157062306a36Sopenharmony_ci	fastrpc_channel_ctx_get(cctx);
157162306a36Sopenharmony_ci
157262306a36Sopenharmony_ci	filp->private_data = fl;
157362306a36Sopenharmony_ci	spin_lock_init(&fl->lock);
157462306a36Sopenharmony_ci	mutex_init(&fl->mutex);
157562306a36Sopenharmony_ci	INIT_LIST_HEAD(&fl->pending);
157662306a36Sopenharmony_ci	INIT_LIST_HEAD(&fl->maps);
157762306a36Sopenharmony_ci	INIT_LIST_HEAD(&fl->mmaps);
157862306a36Sopenharmony_ci	INIT_LIST_HEAD(&fl->user);
157962306a36Sopenharmony_ci	fl->tgid = current->tgid;
158062306a36Sopenharmony_ci	fl->cctx = cctx;
158162306a36Sopenharmony_ci	fl->is_secure_dev = fdevice->secure;
158262306a36Sopenharmony_ci
158362306a36Sopenharmony_ci	fl->sctx = fastrpc_session_alloc(cctx);
158462306a36Sopenharmony_ci	if (!fl->sctx) {
158562306a36Sopenharmony_ci		dev_err(&cctx->rpdev->dev, "No session available\n");
158662306a36Sopenharmony_ci		mutex_destroy(&fl->mutex);
158762306a36Sopenharmony_ci		kfree(fl);
158862306a36Sopenharmony_ci
158962306a36Sopenharmony_ci		return -EBUSY;
159062306a36Sopenharmony_ci	}
159162306a36Sopenharmony_ci
159262306a36Sopenharmony_ci	spin_lock_irqsave(&cctx->lock, flags);
159362306a36Sopenharmony_ci	list_add_tail(&fl->user, &cctx->users);
159462306a36Sopenharmony_ci	spin_unlock_irqrestore(&cctx->lock, flags);
159562306a36Sopenharmony_ci
159662306a36Sopenharmony_ci	return 0;
159762306a36Sopenharmony_ci}
159862306a36Sopenharmony_ci
159962306a36Sopenharmony_cistatic int fastrpc_dmabuf_alloc(struct fastrpc_user *fl, char __user *argp)
160062306a36Sopenharmony_ci{
160162306a36Sopenharmony_ci	struct fastrpc_alloc_dma_buf bp;
160262306a36Sopenharmony_ci	DEFINE_DMA_BUF_EXPORT_INFO(exp_info);
160362306a36Sopenharmony_ci	struct fastrpc_buf *buf = NULL;
160462306a36Sopenharmony_ci	int err;
160562306a36Sopenharmony_ci
160662306a36Sopenharmony_ci	if (copy_from_user(&bp, argp, sizeof(bp)))
160762306a36Sopenharmony_ci		return -EFAULT;
160862306a36Sopenharmony_ci
160962306a36Sopenharmony_ci	err = fastrpc_buf_alloc(fl, fl->sctx->dev, bp.size, &buf);
161062306a36Sopenharmony_ci	if (err)
161162306a36Sopenharmony_ci		return err;
161262306a36Sopenharmony_ci	exp_info.ops = &fastrpc_dma_buf_ops;
161362306a36Sopenharmony_ci	exp_info.size = bp.size;
161462306a36Sopenharmony_ci	exp_info.flags = O_RDWR;
161562306a36Sopenharmony_ci	exp_info.priv = buf;
161662306a36Sopenharmony_ci	buf->dmabuf = dma_buf_export(&exp_info);
161762306a36Sopenharmony_ci	if (IS_ERR(buf->dmabuf)) {
161862306a36Sopenharmony_ci		err = PTR_ERR(buf->dmabuf);
161962306a36Sopenharmony_ci		fastrpc_buf_free(buf);
162062306a36Sopenharmony_ci		return err;
162162306a36Sopenharmony_ci	}
162262306a36Sopenharmony_ci
162362306a36Sopenharmony_ci	bp.fd = dma_buf_fd(buf->dmabuf, O_ACCMODE);
162462306a36Sopenharmony_ci	if (bp.fd < 0) {
162562306a36Sopenharmony_ci		dma_buf_put(buf->dmabuf);
162662306a36Sopenharmony_ci		return -EINVAL;
162762306a36Sopenharmony_ci	}
162862306a36Sopenharmony_ci
162962306a36Sopenharmony_ci	if (copy_to_user(argp, &bp, sizeof(bp))) {
163062306a36Sopenharmony_ci		/*
163162306a36Sopenharmony_ci		 * The usercopy failed, but we can't do much about it, as
163262306a36Sopenharmony_ci		 * dma_buf_fd() already called fd_install() and made the
163362306a36Sopenharmony_ci		 * file descriptor accessible for the current process. It
163462306a36Sopenharmony_ci		 * might already be closed and dmabuf no longer valid when
163562306a36Sopenharmony_ci		 * we reach this point. Therefore "leak" the fd and rely on
163662306a36Sopenharmony_ci		 * the process exit path to do any required cleanup.
163762306a36Sopenharmony_ci		 */
163862306a36Sopenharmony_ci		return -EFAULT;
163962306a36Sopenharmony_ci	}
164062306a36Sopenharmony_ci
164162306a36Sopenharmony_ci	return 0;
164262306a36Sopenharmony_ci}
164362306a36Sopenharmony_ci
164462306a36Sopenharmony_cistatic int fastrpc_init_attach(struct fastrpc_user *fl, int pd)
164562306a36Sopenharmony_ci{
164662306a36Sopenharmony_ci	struct fastrpc_invoke_args args[1];
164762306a36Sopenharmony_ci	int tgid = fl->tgid;
164862306a36Sopenharmony_ci	u32 sc;
164962306a36Sopenharmony_ci
165062306a36Sopenharmony_ci	args[0].ptr = (u64)(uintptr_t) &tgid;
165162306a36Sopenharmony_ci	args[0].length = sizeof(tgid);
165262306a36Sopenharmony_ci	args[0].fd = -1;
165362306a36Sopenharmony_ci	sc = FASTRPC_SCALARS(FASTRPC_RMID_INIT_ATTACH, 1, 0);
165462306a36Sopenharmony_ci	fl->pd = pd;
165562306a36Sopenharmony_ci
165662306a36Sopenharmony_ci	return fastrpc_internal_invoke(fl, true, FASTRPC_INIT_HANDLE,
165762306a36Sopenharmony_ci				       sc, &args[0]);
165862306a36Sopenharmony_ci}
165962306a36Sopenharmony_ci
166062306a36Sopenharmony_cistatic int fastrpc_invoke(struct fastrpc_user *fl, char __user *argp)
166162306a36Sopenharmony_ci{
166262306a36Sopenharmony_ci	struct fastrpc_invoke_args *args = NULL;
166362306a36Sopenharmony_ci	struct fastrpc_invoke inv;
166462306a36Sopenharmony_ci	u32 nscalars;
166562306a36Sopenharmony_ci	int err;
166662306a36Sopenharmony_ci
166762306a36Sopenharmony_ci	if (copy_from_user(&inv, argp, sizeof(inv)))
166862306a36Sopenharmony_ci		return -EFAULT;
166962306a36Sopenharmony_ci
167062306a36Sopenharmony_ci	/* nscalars is truncated here to max supported value */
167162306a36Sopenharmony_ci	nscalars = REMOTE_SCALARS_LENGTH(inv.sc);
167262306a36Sopenharmony_ci	if (nscalars) {
167362306a36Sopenharmony_ci		args = kcalloc(nscalars, sizeof(*args), GFP_KERNEL);
167462306a36Sopenharmony_ci		if (!args)
167562306a36Sopenharmony_ci			return -ENOMEM;
167662306a36Sopenharmony_ci
167762306a36Sopenharmony_ci		if (copy_from_user(args, (void __user *)(uintptr_t)inv.args,
167862306a36Sopenharmony_ci				   nscalars * sizeof(*args))) {
167962306a36Sopenharmony_ci			kfree(args);
168062306a36Sopenharmony_ci			return -EFAULT;
168162306a36Sopenharmony_ci		}
168262306a36Sopenharmony_ci	}
168362306a36Sopenharmony_ci
168462306a36Sopenharmony_ci	err = fastrpc_internal_invoke(fl, false, inv.handle, inv.sc, args);
168562306a36Sopenharmony_ci	kfree(args);
168662306a36Sopenharmony_ci
168762306a36Sopenharmony_ci	return err;
168862306a36Sopenharmony_ci}
168962306a36Sopenharmony_ci
169062306a36Sopenharmony_cistatic int fastrpc_get_info_from_dsp(struct fastrpc_user *fl, uint32_t *dsp_attr_buf,
169162306a36Sopenharmony_ci				     uint32_t dsp_attr_buf_len)
169262306a36Sopenharmony_ci{
169362306a36Sopenharmony_ci	struct fastrpc_invoke_args args[2] = { 0 };
169462306a36Sopenharmony_ci
169562306a36Sopenharmony_ci	/* Capability filled in userspace */
169662306a36Sopenharmony_ci	dsp_attr_buf[0] = 0;
169762306a36Sopenharmony_ci
169862306a36Sopenharmony_ci	args[0].ptr = (u64)(uintptr_t)&dsp_attr_buf_len;
169962306a36Sopenharmony_ci	args[0].length = sizeof(dsp_attr_buf_len);
170062306a36Sopenharmony_ci	args[0].fd = -1;
170162306a36Sopenharmony_ci	args[1].ptr = (u64)(uintptr_t)&dsp_attr_buf[1];
170262306a36Sopenharmony_ci	args[1].length = dsp_attr_buf_len;
170362306a36Sopenharmony_ci	args[1].fd = -1;
170462306a36Sopenharmony_ci	fl->pd = USER_PD;
170562306a36Sopenharmony_ci
170662306a36Sopenharmony_ci	return fastrpc_internal_invoke(fl, true, FASTRPC_DSP_UTILITIES_HANDLE,
170762306a36Sopenharmony_ci				       FASTRPC_SCALARS(0, 1, 1), args);
170862306a36Sopenharmony_ci}
170962306a36Sopenharmony_ci
171062306a36Sopenharmony_cistatic int fastrpc_get_info_from_kernel(struct fastrpc_ioctl_capability *cap,
171162306a36Sopenharmony_ci					struct fastrpc_user *fl)
171262306a36Sopenharmony_ci{
171362306a36Sopenharmony_ci	struct fastrpc_channel_ctx *cctx = fl->cctx;
171462306a36Sopenharmony_ci	uint32_t attribute_id = cap->attribute_id;
171562306a36Sopenharmony_ci	uint32_t *dsp_attributes;
171662306a36Sopenharmony_ci	unsigned long flags;
171762306a36Sopenharmony_ci	uint32_t domain = cap->domain;
171862306a36Sopenharmony_ci	int err;
171962306a36Sopenharmony_ci
172062306a36Sopenharmony_ci	spin_lock_irqsave(&cctx->lock, flags);
172162306a36Sopenharmony_ci	/* check if we already have queried dsp for attributes */
172262306a36Sopenharmony_ci	if (cctx->valid_attributes) {
172362306a36Sopenharmony_ci		spin_unlock_irqrestore(&cctx->lock, flags);
172462306a36Sopenharmony_ci		goto done;
172562306a36Sopenharmony_ci	}
172662306a36Sopenharmony_ci	spin_unlock_irqrestore(&cctx->lock, flags);
172762306a36Sopenharmony_ci
172862306a36Sopenharmony_ci	dsp_attributes = kzalloc(FASTRPC_MAX_DSP_ATTRIBUTES_LEN, GFP_KERNEL);
172962306a36Sopenharmony_ci	if (!dsp_attributes)
173062306a36Sopenharmony_ci		return -ENOMEM;
173162306a36Sopenharmony_ci
173262306a36Sopenharmony_ci	err = fastrpc_get_info_from_dsp(fl, dsp_attributes, FASTRPC_MAX_DSP_ATTRIBUTES_LEN);
173362306a36Sopenharmony_ci	if (err == DSP_UNSUPPORTED_API) {
173462306a36Sopenharmony_ci		dev_info(&cctx->rpdev->dev,
173562306a36Sopenharmony_ci			 "Warning: DSP capabilities not supported on domain: %d\n", domain);
173662306a36Sopenharmony_ci		kfree(dsp_attributes);
173762306a36Sopenharmony_ci		return -EOPNOTSUPP;
173862306a36Sopenharmony_ci	} else if (err) {
173962306a36Sopenharmony_ci		dev_err(&cctx->rpdev->dev, "Error: dsp information is incorrect err: %d\n", err);
174062306a36Sopenharmony_ci		kfree(dsp_attributes);
174162306a36Sopenharmony_ci		return err;
174262306a36Sopenharmony_ci	}
174362306a36Sopenharmony_ci
174462306a36Sopenharmony_ci	spin_lock_irqsave(&cctx->lock, flags);
174562306a36Sopenharmony_ci	memcpy(cctx->dsp_attributes, dsp_attributes, FASTRPC_MAX_DSP_ATTRIBUTES_LEN);
174662306a36Sopenharmony_ci	cctx->valid_attributes = true;
174762306a36Sopenharmony_ci	spin_unlock_irqrestore(&cctx->lock, flags);
174862306a36Sopenharmony_ci	kfree(dsp_attributes);
174962306a36Sopenharmony_cidone:
175062306a36Sopenharmony_ci	cap->capability = cctx->dsp_attributes[attribute_id];
175162306a36Sopenharmony_ci	return 0;
175262306a36Sopenharmony_ci}
175362306a36Sopenharmony_ci
175462306a36Sopenharmony_cistatic int fastrpc_get_dsp_info(struct fastrpc_user *fl, char __user *argp)
175562306a36Sopenharmony_ci{
175662306a36Sopenharmony_ci	struct fastrpc_ioctl_capability cap = {0};
175762306a36Sopenharmony_ci	int err = 0;
175862306a36Sopenharmony_ci
175962306a36Sopenharmony_ci	if (copy_from_user(&cap, argp, sizeof(cap)))
176062306a36Sopenharmony_ci		return  -EFAULT;
176162306a36Sopenharmony_ci
176262306a36Sopenharmony_ci	cap.capability = 0;
176362306a36Sopenharmony_ci	if (cap.domain >= FASTRPC_DEV_MAX) {
176462306a36Sopenharmony_ci		dev_err(&fl->cctx->rpdev->dev, "Error: Invalid domain id:%d, err:%d\n",
176562306a36Sopenharmony_ci			cap.domain, err);
176662306a36Sopenharmony_ci		return -ECHRNG;
176762306a36Sopenharmony_ci	}
176862306a36Sopenharmony_ci
176962306a36Sopenharmony_ci	/* Fastrpc Capablities does not support modem domain */
177062306a36Sopenharmony_ci	if (cap.domain == MDSP_DOMAIN_ID) {
177162306a36Sopenharmony_ci		dev_err(&fl->cctx->rpdev->dev, "Error: modem not supported %d\n", err);
177262306a36Sopenharmony_ci		return -ECHRNG;
177362306a36Sopenharmony_ci	}
177462306a36Sopenharmony_ci
177562306a36Sopenharmony_ci	if (cap.attribute_id >= FASTRPC_MAX_DSP_ATTRIBUTES) {
177662306a36Sopenharmony_ci		dev_err(&fl->cctx->rpdev->dev, "Error: invalid attribute: %d, err: %d\n",
177762306a36Sopenharmony_ci			cap.attribute_id, err);
177862306a36Sopenharmony_ci		return -EOVERFLOW;
177962306a36Sopenharmony_ci	}
178062306a36Sopenharmony_ci
178162306a36Sopenharmony_ci	err = fastrpc_get_info_from_kernel(&cap, fl);
178262306a36Sopenharmony_ci	if (err)
178362306a36Sopenharmony_ci		return err;
178462306a36Sopenharmony_ci
178562306a36Sopenharmony_ci	if (copy_to_user(argp, &cap.capability, sizeof(cap.capability)))
178662306a36Sopenharmony_ci		return -EFAULT;
178762306a36Sopenharmony_ci
178862306a36Sopenharmony_ci	return 0;
178962306a36Sopenharmony_ci}
179062306a36Sopenharmony_ci
179162306a36Sopenharmony_cistatic int fastrpc_req_munmap_impl(struct fastrpc_user *fl, struct fastrpc_buf *buf)
179262306a36Sopenharmony_ci{
179362306a36Sopenharmony_ci	struct fastrpc_invoke_args args[1] = { [0] = { 0 } };
179462306a36Sopenharmony_ci	struct fastrpc_munmap_req_msg req_msg;
179562306a36Sopenharmony_ci	struct device *dev = fl->sctx->dev;
179662306a36Sopenharmony_ci	int err;
179762306a36Sopenharmony_ci	u32 sc;
179862306a36Sopenharmony_ci
179962306a36Sopenharmony_ci	req_msg.pgid = fl->tgid;
180062306a36Sopenharmony_ci	req_msg.size = buf->size;
180162306a36Sopenharmony_ci	req_msg.vaddr = buf->raddr;
180262306a36Sopenharmony_ci
180362306a36Sopenharmony_ci	args[0].ptr = (u64) (uintptr_t) &req_msg;
180462306a36Sopenharmony_ci	args[0].length = sizeof(req_msg);
180562306a36Sopenharmony_ci
180662306a36Sopenharmony_ci	sc = FASTRPC_SCALARS(FASTRPC_RMID_INIT_MUNMAP, 1, 0);
180762306a36Sopenharmony_ci	err = fastrpc_internal_invoke(fl, true, FASTRPC_INIT_HANDLE, sc,
180862306a36Sopenharmony_ci				      &args[0]);
180962306a36Sopenharmony_ci	if (!err) {
181062306a36Sopenharmony_ci		dev_dbg(dev, "unmmap\tpt 0x%09lx OK\n", buf->raddr);
181162306a36Sopenharmony_ci		spin_lock(&fl->lock);
181262306a36Sopenharmony_ci		list_del(&buf->node);
181362306a36Sopenharmony_ci		spin_unlock(&fl->lock);
181462306a36Sopenharmony_ci		fastrpc_buf_free(buf);
181562306a36Sopenharmony_ci	} else {
181662306a36Sopenharmony_ci		dev_err(dev, "unmmap\tpt 0x%09lx ERROR\n", buf->raddr);
181762306a36Sopenharmony_ci	}
181862306a36Sopenharmony_ci
181962306a36Sopenharmony_ci	return err;
182062306a36Sopenharmony_ci}
182162306a36Sopenharmony_ci
182262306a36Sopenharmony_cistatic int fastrpc_req_munmap(struct fastrpc_user *fl, char __user *argp)
182362306a36Sopenharmony_ci{
182462306a36Sopenharmony_ci	struct fastrpc_buf *buf = NULL, *iter, *b;
182562306a36Sopenharmony_ci	struct fastrpc_req_munmap req;
182662306a36Sopenharmony_ci	struct device *dev = fl->sctx->dev;
182762306a36Sopenharmony_ci
182862306a36Sopenharmony_ci	if (copy_from_user(&req, argp, sizeof(req)))
182962306a36Sopenharmony_ci		return -EFAULT;
183062306a36Sopenharmony_ci
183162306a36Sopenharmony_ci	spin_lock(&fl->lock);
183262306a36Sopenharmony_ci	list_for_each_entry_safe(iter, b, &fl->mmaps, node) {
183362306a36Sopenharmony_ci		if ((iter->raddr == req.vaddrout) && (iter->size == req.size)) {
183462306a36Sopenharmony_ci			buf = iter;
183562306a36Sopenharmony_ci			break;
183662306a36Sopenharmony_ci		}
183762306a36Sopenharmony_ci	}
183862306a36Sopenharmony_ci	spin_unlock(&fl->lock);
183962306a36Sopenharmony_ci
184062306a36Sopenharmony_ci	if (!buf) {
184162306a36Sopenharmony_ci		dev_err(dev, "mmap\t\tpt 0x%09llx [len 0x%08llx] not in list\n",
184262306a36Sopenharmony_ci			req.vaddrout, req.size);
184362306a36Sopenharmony_ci		return -EINVAL;
184462306a36Sopenharmony_ci	}
184562306a36Sopenharmony_ci
184662306a36Sopenharmony_ci	return fastrpc_req_munmap_impl(fl, buf);
184762306a36Sopenharmony_ci}
184862306a36Sopenharmony_ci
184962306a36Sopenharmony_cistatic int fastrpc_req_mmap(struct fastrpc_user *fl, char __user *argp)
185062306a36Sopenharmony_ci{
185162306a36Sopenharmony_ci	struct fastrpc_invoke_args args[3] = { [0 ... 2] = { 0 } };
185262306a36Sopenharmony_ci	struct fastrpc_buf *buf = NULL;
185362306a36Sopenharmony_ci	struct fastrpc_mmap_req_msg req_msg;
185462306a36Sopenharmony_ci	struct fastrpc_mmap_rsp_msg rsp_msg;
185562306a36Sopenharmony_ci	struct fastrpc_phy_page pages;
185662306a36Sopenharmony_ci	struct fastrpc_req_mmap req;
185762306a36Sopenharmony_ci	struct device *dev = fl->sctx->dev;
185862306a36Sopenharmony_ci	int err;
185962306a36Sopenharmony_ci	u32 sc;
186062306a36Sopenharmony_ci
186162306a36Sopenharmony_ci	if (copy_from_user(&req, argp, sizeof(req)))
186262306a36Sopenharmony_ci		return -EFAULT;
186362306a36Sopenharmony_ci
186462306a36Sopenharmony_ci	if (req.flags != ADSP_MMAP_ADD_PAGES && req.flags != ADSP_MMAP_REMOTE_HEAP_ADDR) {
186562306a36Sopenharmony_ci		dev_err(dev, "flag not supported 0x%x\n", req.flags);
186662306a36Sopenharmony_ci
186762306a36Sopenharmony_ci		return -EINVAL;
186862306a36Sopenharmony_ci	}
186962306a36Sopenharmony_ci
187062306a36Sopenharmony_ci	if (req.vaddrin) {
187162306a36Sopenharmony_ci		dev_err(dev, "adding user allocated pages is not supported\n");
187262306a36Sopenharmony_ci		return -EINVAL;
187362306a36Sopenharmony_ci	}
187462306a36Sopenharmony_ci
187562306a36Sopenharmony_ci	if (req.flags == ADSP_MMAP_REMOTE_HEAP_ADDR)
187662306a36Sopenharmony_ci		err = fastrpc_remote_heap_alloc(fl, dev, req.size, &buf);
187762306a36Sopenharmony_ci	else
187862306a36Sopenharmony_ci		err = fastrpc_buf_alloc(fl, dev, req.size, &buf);
187962306a36Sopenharmony_ci
188062306a36Sopenharmony_ci	if (err) {
188162306a36Sopenharmony_ci		dev_err(dev, "failed to allocate buffer\n");
188262306a36Sopenharmony_ci		return err;
188362306a36Sopenharmony_ci	}
188462306a36Sopenharmony_ci
188562306a36Sopenharmony_ci	req_msg.pgid = fl->tgid;
188662306a36Sopenharmony_ci	req_msg.flags = req.flags;
188762306a36Sopenharmony_ci	req_msg.vaddr = req.vaddrin;
188862306a36Sopenharmony_ci	req_msg.num = sizeof(pages);
188962306a36Sopenharmony_ci
189062306a36Sopenharmony_ci	args[0].ptr = (u64) (uintptr_t) &req_msg;
189162306a36Sopenharmony_ci	args[0].length = sizeof(req_msg);
189262306a36Sopenharmony_ci
189362306a36Sopenharmony_ci	pages.addr = buf->phys;
189462306a36Sopenharmony_ci	pages.size = buf->size;
189562306a36Sopenharmony_ci
189662306a36Sopenharmony_ci	args[1].ptr = (u64) (uintptr_t) &pages;
189762306a36Sopenharmony_ci	args[1].length = sizeof(pages);
189862306a36Sopenharmony_ci
189962306a36Sopenharmony_ci	args[2].ptr = (u64) (uintptr_t) &rsp_msg;
190062306a36Sopenharmony_ci	args[2].length = sizeof(rsp_msg);
190162306a36Sopenharmony_ci
190262306a36Sopenharmony_ci	sc = FASTRPC_SCALARS(FASTRPC_RMID_INIT_MMAP, 2, 1);
190362306a36Sopenharmony_ci	err = fastrpc_internal_invoke(fl, true, FASTRPC_INIT_HANDLE, sc,
190462306a36Sopenharmony_ci				      &args[0]);
190562306a36Sopenharmony_ci	if (err) {
190662306a36Sopenharmony_ci		dev_err(dev, "mmap error (len 0x%08llx)\n", buf->size);
190762306a36Sopenharmony_ci		goto err_invoke;
190862306a36Sopenharmony_ci	}
190962306a36Sopenharmony_ci
191062306a36Sopenharmony_ci	/* update the buffer to be able to deallocate the memory on the DSP */
191162306a36Sopenharmony_ci	buf->raddr = (uintptr_t) rsp_msg.vaddr;
191262306a36Sopenharmony_ci
191362306a36Sopenharmony_ci	/* let the client know the address to use */
191462306a36Sopenharmony_ci	req.vaddrout = rsp_msg.vaddr;
191562306a36Sopenharmony_ci
191662306a36Sopenharmony_ci	/* Add memory to static PD pool, protection thru hypervisor */
191762306a36Sopenharmony_ci	if (req.flags == ADSP_MMAP_REMOTE_HEAP_ADDR && fl->cctx->vmcount) {
191862306a36Sopenharmony_ci		err = qcom_scm_assign_mem(buf->phys, (u64)buf->size,
191962306a36Sopenharmony_ci			&fl->cctx->perms, fl->cctx->vmperms, fl->cctx->vmcount);
192062306a36Sopenharmony_ci		if (err) {
192162306a36Sopenharmony_ci			dev_err(fl->sctx->dev, "Failed to assign memory phys 0x%llx size 0x%llx err %d",
192262306a36Sopenharmony_ci					buf->phys, buf->size, err);
192362306a36Sopenharmony_ci			goto err_assign;
192462306a36Sopenharmony_ci		}
192562306a36Sopenharmony_ci	}
192662306a36Sopenharmony_ci
192762306a36Sopenharmony_ci	spin_lock(&fl->lock);
192862306a36Sopenharmony_ci	list_add_tail(&buf->node, &fl->mmaps);
192962306a36Sopenharmony_ci	spin_unlock(&fl->lock);
193062306a36Sopenharmony_ci
193162306a36Sopenharmony_ci	if (copy_to_user((void __user *)argp, &req, sizeof(req))) {
193262306a36Sopenharmony_ci		err = -EFAULT;
193362306a36Sopenharmony_ci		goto err_assign;
193462306a36Sopenharmony_ci	}
193562306a36Sopenharmony_ci
193662306a36Sopenharmony_ci	dev_dbg(dev, "mmap\t\tpt 0x%09lx OK [len 0x%08llx]\n",
193762306a36Sopenharmony_ci		buf->raddr, buf->size);
193862306a36Sopenharmony_ci
193962306a36Sopenharmony_ci	return 0;
194062306a36Sopenharmony_ci
194162306a36Sopenharmony_cierr_assign:
194262306a36Sopenharmony_ci	fastrpc_req_munmap_impl(fl, buf);
194362306a36Sopenharmony_cierr_invoke:
194462306a36Sopenharmony_ci	fastrpc_buf_free(buf);
194562306a36Sopenharmony_ci
194662306a36Sopenharmony_ci	return err;
194762306a36Sopenharmony_ci}
194862306a36Sopenharmony_ci
194962306a36Sopenharmony_cistatic int fastrpc_req_mem_unmap_impl(struct fastrpc_user *fl, struct fastrpc_mem_unmap *req)
195062306a36Sopenharmony_ci{
195162306a36Sopenharmony_ci	struct fastrpc_invoke_args args[1] = { [0] = { 0 } };
195262306a36Sopenharmony_ci	struct fastrpc_map *map = NULL, *iter, *m;
195362306a36Sopenharmony_ci	struct fastrpc_mem_unmap_req_msg req_msg = { 0 };
195462306a36Sopenharmony_ci	int err = 0;
195562306a36Sopenharmony_ci	u32 sc;
195662306a36Sopenharmony_ci	struct device *dev = fl->sctx->dev;
195762306a36Sopenharmony_ci
195862306a36Sopenharmony_ci	spin_lock(&fl->lock);
195962306a36Sopenharmony_ci	list_for_each_entry_safe(iter, m, &fl->maps, node) {
196062306a36Sopenharmony_ci		if ((req->fd < 0 || iter->fd == req->fd) && (iter->raddr == req->vaddr)) {
196162306a36Sopenharmony_ci			map = iter;
196262306a36Sopenharmony_ci			break;
196362306a36Sopenharmony_ci		}
196462306a36Sopenharmony_ci	}
196562306a36Sopenharmony_ci
196662306a36Sopenharmony_ci	spin_unlock(&fl->lock);
196762306a36Sopenharmony_ci
196862306a36Sopenharmony_ci	if (!map) {
196962306a36Sopenharmony_ci		dev_err(dev, "map not in list\n");
197062306a36Sopenharmony_ci		return -EINVAL;
197162306a36Sopenharmony_ci	}
197262306a36Sopenharmony_ci
197362306a36Sopenharmony_ci	req_msg.pgid = fl->tgid;
197462306a36Sopenharmony_ci	req_msg.len = map->len;
197562306a36Sopenharmony_ci	req_msg.vaddrin = map->raddr;
197662306a36Sopenharmony_ci	req_msg.fd = map->fd;
197762306a36Sopenharmony_ci
197862306a36Sopenharmony_ci	args[0].ptr = (u64) (uintptr_t) &req_msg;
197962306a36Sopenharmony_ci	args[0].length = sizeof(req_msg);
198062306a36Sopenharmony_ci
198162306a36Sopenharmony_ci	sc = FASTRPC_SCALARS(FASTRPC_RMID_INIT_MEM_UNMAP, 1, 0);
198262306a36Sopenharmony_ci	err = fastrpc_internal_invoke(fl, true, FASTRPC_INIT_HANDLE, sc,
198362306a36Sopenharmony_ci				      &args[0]);
198462306a36Sopenharmony_ci	if (err) {
198562306a36Sopenharmony_ci		dev_err(dev, "unmmap\tpt fd = %d, 0x%09llx error\n",  map->fd, map->raddr);
198662306a36Sopenharmony_ci		return err;
198762306a36Sopenharmony_ci	}
198862306a36Sopenharmony_ci	fastrpc_map_put(map);
198962306a36Sopenharmony_ci
199062306a36Sopenharmony_ci	return 0;
199162306a36Sopenharmony_ci}
199262306a36Sopenharmony_ci
199362306a36Sopenharmony_cistatic int fastrpc_req_mem_unmap(struct fastrpc_user *fl, char __user *argp)
199462306a36Sopenharmony_ci{
199562306a36Sopenharmony_ci	struct fastrpc_mem_unmap req;
199662306a36Sopenharmony_ci
199762306a36Sopenharmony_ci	if (copy_from_user(&req, argp, sizeof(req)))
199862306a36Sopenharmony_ci		return -EFAULT;
199962306a36Sopenharmony_ci
200062306a36Sopenharmony_ci	return fastrpc_req_mem_unmap_impl(fl, &req);
200162306a36Sopenharmony_ci}
200262306a36Sopenharmony_ci
200362306a36Sopenharmony_cistatic int fastrpc_req_mem_map(struct fastrpc_user *fl, char __user *argp)
200462306a36Sopenharmony_ci{
200562306a36Sopenharmony_ci	struct fastrpc_invoke_args args[4] = { [0 ... 3] = { 0 } };
200662306a36Sopenharmony_ci	struct fastrpc_mem_map_req_msg req_msg = { 0 };
200762306a36Sopenharmony_ci	struct fastrpc_mmap_rsp_msg rsp_msg = { 0 };
200862306a36Sopenharmony_ci	struct fastrpc_mem_unmap req_unmap = { 0 };
200962306a36Sopenharmony_ci	struct fastrpc_phy_page pages = { 0 };
201062306a36Sopenharmony_ci	struct fastrpc_mem_map req;
201162306a36Sopenharmony_ci	struct device *dev = fl->sctx->dev;
201262306a36Sopenharmony_ci	struct fastrpc_map *map = NULL;
201362306a36Sopenharmony_ci	int err;
201462306a36Sopenharmony_ci	u32 sc;
201562306a36Sopenharmony_ci
201662306a36Sopenharmony_ci	if (copy_from_user(&req, argp, sizeof(req)))
201762306a36Sopenharmony_ci		return -EFAULT;
201862306a36Sopenharmony_ci
201962306a36Sopenharmony_ci	/* create SMMU mapping */
202062306a36Sopenharmony_ci	err = fastrpc_map_create(fl, req.fd, req.length, 0, &map);
202162306a36Sopenharmony_ci	if (err) {
202262306a36Sopenharmony_ci		dev_err(dev, "failed to map buffer, fd = %d\n", req.fd);
202362306a36Sopenharmony_ci		return err;
202462306a36Sopenharmony_ci	}
202562306a36Sopenharmony_ci
202662306a36Sopenharmony_ci	req_msg.pgid = fl->tgid;
202762306a36Sopenharmony_ci	req_msg.fd = req.fd;
202862306a36Sopenharmony_ci	req_msg.offset = req.offset;
202962306a36Sopenharmony_ci	req_msg.vaddrin = req.vaddrin;
203062306a36Sopenharmony_ci	map->va = (void *) (uintptr_t) req.vaddrin;
203162306a36Sopenharmony_ci	req_msg.flags = req.flags;
203262306a36Sopenharmony_ci	req_msg.num = sizeof(pages);
203362306a36Sopenharmony_ci	req_msg.data_len = 0;
203462306a36Sopenharmony_ci
203562306a36Sopenharmony_ci	args[0].ptr = (u64) (uintptr_t) &req_msg;
203662306a36Sopenharmony_ci	args[0].length = sizeof(req_msg);
203762306a36Sopenharmony_ci
203862306a36Sopenharmony_ci	pages.addr = map->phys;
203962306a36Sopenharmony_ci	pages.size = map->size;
204062306a36Sopenharmony_ci
204162306a36Sopenharmony_ci	args[1].ptr = (u64) (uintptr_t) &pages;
204262306a36Sopenharmony_ci	args[1].length = sizeof(pages);
204362306a36Sopenharmony_ci
204462306a36Sopenharmony_ci	args[2].ptr = (u64) (uintptr_t) &pages;
204562306a36Sopenharmony_ci	args[2].length = 0;
204662306a36Sopenharmony_ci
204762306a36Sopenharmony_ci	args[3].ptr = (u64) (uintptr_t) &rsp_msg;
204862306a36Sopenharmony_ci	args[3].length = sizeof(rsp_msg);
204962306a36Sopenharmony_ci
205062306a36Sopenharmony_ci	sc = FASTRPC_SCALARS(FASTRPC_RMID_INIT_MEM_MAP, 3, 1);
205162306a36Sopenharmony_ci	err = fastrpc_internal_invoke(fl, true, FASTRPC_INIT_HANDLE, sc, &args[0]);
205262306a36Sopenharmony_ci	if (err) {
205362306a36Sopenharmony_ci		dev_err(dev, "mem mmap error, fd %d, vaddr %llx, size %lld\n",
205462306a36Sopenharmony_ci			req.fd, req.vaddrin, map->size);
205562306a36Sopenharmony_ci		goto err_invoke;
205662306a36Sopenharmony_ci	}
205762306a36Sopenharmony_ci
205862306a36Sopenharmony_ci	/* update the buffer to be able to deallocate the memory on the DSP */
205962306a36Sopenharmony_ci	map->raddr = rsp_msg.vaddr;
206062306a36Sopenharmony_ci
206162306a36Sopenharmony_ci	/* let the client know the address to use */
206262306a36Sopenharmony_ci	req.vaddrout = rsp_msg.vaddr;
206362306a36Sopenharmony_ci
206462306a36Sopenharmony_ci	if (copy_to_user((void __user *)argp, &req, sizeof(req))) {
206562306a36Sopenharmony_ci		/* unmap the memory and release the buffer */
206662306a36Sopenharmony_ci		req_unmap.vaddr = (uintptr_t) rsp_msg.vaddr;
206762306a36Sopenharmony_ci		req_unmap.length = map->size;
206862306a36Sopenharmony_ci		fastrpc_req_mem_unmap_impl(fl, &req_unmap);
206962306a36Sopenharmony_ci		return -EFAULT;
207062306a36Sopenharmony_ci	}
207162306a36Sopenharmony_ci
207262306a36Sopenharmony_ci	return 0;
207362306a36Sopenharmony_ci
207462306a36Sopenharmony_cierr_invoke:
207562306a36Sopenharmony_ci	fastrpc_map_put(map);
207662306a36Sopenharmony_ci
207762306a36Sopenharmony_ci	return err;
207862306a36Sopenharmony_ci}
207962306a36Sopenharmony_ci
208062306a36Sopenharmony_cistatic long fastrpc_device_ioctl(struct file *file, unsigned int cmd,
208162306a36Sopenharmony_ci				 unsigned long arg)
208262306a36Sopenharmony_ci{
208362306a36Sopenharmony_ci	struct fastrpc_user *fl = (struct fastrpc_user *)file->private_data;
208462306a36Sopenharmony_ci	char __user *argp = (char __user *)arg;
208562306a36Sopenharmony_ci	int err;
208662306a36Sopenharmony_ci
208762306a36Sopenharmony_ci	switch (cmd) {
208862306a36Sopenharmony_ci	case FASTRPC_IOCTL_INVOKE:
208962306a36Sopenharmony_ci		err = fastrpc_invoke(fl, argp);
209062306a36Sopenharmony_ci		break;
209162306a36Sopenharmony_ci	case FASTRPC_IOCTL_INIT_ATTACH:
209262306a36Sopenharmony_ci		err = fastrpc_init_attach(fl, ROOT_PD);
209362306a36Sopenharmony_ci		break;
209462306a36Sopenharmony_ci	case FASTRPC_IOCTL_INIT_ATTACH_SNS:
209562306a36Sopenharmony_ci		err = fastrpc_init_attach(fl, SENSORS_PD);
209662306a36Sopenharmony_ci		break;
209762306a36Sopenharmony_ci	case FASTRPC_IOCTL_INIT_CREATE_STATIC:
209862306a36Sopenharmony_ci		err = fastrpc_init_create_static_process(fl, argp);
209962306a36Sopenharmony_ci		break;
210062306a36Sopenharmony_ci	case FASTRPC_IOCTL_INIT_CREATE:
210162306a36Sopenharmony_ci		err = fastrpc_init_create_process(fl, argp);
210262306a36Sopenharmony_ci		break;
210362306a36Sopenharmony_ci	case FASTRPC_IOCTL_ALLOC_DMA_BUFF:
210462306a36Sopenharmony_ci		err = fastrpc_dmabuf_alloc(fl, argp);
210562306a36Sopenharmony_ci		break;
210662306a36Sopenharmony_ci	case FASTRPC_IOCTL_MMAP:
210762306a36Sopenharmony_ci		err = fastrpc_req_mmap(fl, argp);
210862306a36Sopenharmony_ci		break;
210962306a36Sopenharmony_ci	case FASTRPC_IOCTL_MUNMAP:
211062306a36Sopenharmony_ci		err = fastrpc_req_munmap(fl, argp);
211162306a36Sopenharmony_ci		break;
211262306a36Sopenharmony_ci	case FASTRPC_IOCTL_MEM_MAP:
211362306a36Sopenharmony_ci		err = fastrpc_req_mem_map(fl, argp);
211462306a36Sopenharmony_ci		break;
211562306a36Sopenharmony_ci	case FASTRPC_IOCTL_MEM_UNMAP:
211662306a36Sopenharmony_ci		err = fastrpc_req_mem_unmap(fl, argp);
211762306a36Sopenharmony_ci		break;
211862306a36Sopenharmony_ci	case FASTRPC_IOCTL_GET_DSP_INFO:
211962306a36Sopenharmony_ci		err = fastrpc_get_dsp_info(fl, argp);
212062306a36Sopenharmony_ci		break;
212162306a36Sopenharmony_ci	default:
212262306a36Sopenharmony_ci		err = -ENOTTY;
212362306a36Sopenharmony_ci		break;
212462306a36Sopenharmony_ci	}
212562306a36Sopenharmony_ci
212662306a36Sopenharmony_ci	return err;
212762306a36Sopenharmony_ci}
212862306a36Sopenharmony_ci
212962306a36Sopenharmony_cistatic const struct file_operations fastrpc_fops = {
213062306a36Sopenharmony_ci	.open = fastrpc_device_open,
213162306a36Sopenharmony_ci	.release = fastrpc_device_release,
213262306a36Sopenharmony_ci	.unlocked_ioctl = fastrpc_device_ioctl,
213362306a36Sopenharmony_ci	.compat_ioctl = fastrpc_device_ioctl,
213462306a36Sopenharmony_ci};
213562306a36Sopenharmony_ci
213662306a36Sopenharmony_cistatic int fastrpc_cb_probe(struct platform_device *pdev)
213762306a36Sopenharmony_ci{
213862306a36Sopenharmony_ci	struct fastrpc_channel_ctx *cctx;
213962306a36Sopenharmony_ci	struct fastrpc_session_ctx *sess;
214062306a36Sopenharmony_ci	struct device *dev = &pdev->dev;
214162306a36Sopenharmony_ci	int i, sessions = 0;
214262306a36Sopenharmony_ci	unsigned long flags;
214362306a36Sopenharmony_ci	int rc;
214462306a36Sopenharmony_ci
214562306a36Sopenharmony_ci	cctx = dev_get_drvdata(dev->parent);
214662306a36Sopenharmony_ci	if (!cctx)
214762306a36Sopenharmony_ci		return -EINVAL;
214862306a36Sopenharmony_ci
214962306a36Sopenharmony_ci	of_property_read_u32(dev->of_node, "qcom,nsessions", &sessions);
215062306a36Sopenharmony_ci
215162306a36Sopenharmony_ci	spin_lock_irqsave(&cctx->lock, flags);
215262306a36Sopenharmony_ci	if (cctx->sesscount >= FASTRPC_MAX_SESSIONS) {
215362306a36Sopenharmony_ci		dev_err(&pdev->dev, "too many sessions\n");
215462306a36Sopenharmony_ci		spin_unlock_irqrestore(&cctx->lock, flags);
215562306a36Sopenharmony_ci		return -ENOSPC;
215662306a36Sopenharmony_ci	}
215762306a36Sopenharmony_ci	sess = &cctx->session[cctx->sesscount++];
215862306a36Sopenharmony_ci	sess->used = false;
215962306a36Sopenharmony_ci	sess->valid = true;
216062306a36Sopenharmony_ci	sess->dev = dev;
216162306a36Sopenharmony_ci	dev_set_drvdata(dev, sess);
216262306a36Sopenharmony_ci
216362306a36Sopenharmony_ci	if (of_property_read_u32(dev->of_node, "reg", &sess->sid))
216462306a36Sopenharmony_ci		dev_info(dev, "FastRPC Session ID not specified in DT\n");
216562306a36Sopenharmony_ci
216662306a36Sopenharmony_ci	if (sessions > 0) {
216762306a36Sopenharmony_ci		struct fastrpc_session_ctx *dup_sess;
216862306a36Sopenharmony_ci
216962306a36Sopenharmony_ci		for (i = 1; i < sessions; i++) {
217062306a36Sopenharmony_ci			if (cctx->sesscount >= FASTRPC_MAX_SESSIONS)
217162306a36Sopenharmony_ci				break;
217262306a36Sopenharmony_ci			dup_sess = &cctx->session[cctx->sesscount++];
217362306a36Sopenharmony_ci			memcpy(dup_sess, sess, sizeof(*dup_sess));
217462306a36Sopenharmony_ci		}
217562306a36Sopenharmony_ci	}
217662306a36Sopenharmony_ci	spin_unlock_irqrestore(&cctx->lock, flags);
217762306a36Sopenharmony_ci	rc = dma_set_mask(dev, DMA_BIT_MASK(32));
217862306a36Sopenharmony_ci	if (rc) {
217962306a36Sopenharmony_ci		dev_err(dev, "32-bit DMA enable failed\n");
218062306a36Sopenharmony_ci		return rc;
218162306a36Sopenharmony_ci	}
218262306a36Sopenharmony_ci
218362306a36Sopenharmony_ci	return 0;
218462306a36Sopenharmony_ci}
218562306a36Sopenharmony_ci
218662306a36Sopenharmony_cistatic int fastrpc_cb_remove(struct platform_device *pdev)
218762306a36Sopenharmony_ci{
218862306a36Sopenharmony_ci	struct fastrpc_channel_ctx *cctx = dev_get_drvdata(pdev->dev.parent);
218962306a36Sopenharmony_ci	struct fastrpc_session_ctx *sess = dev_get_drvdata(&pdev->dev);
219062306a36Sopenharmony_ci	unsigned long flags;
219162306a36Sopenharmony_ci	int i;
219262306a36Sopenharmony_ci
219362306a36Sopenharmony_ci	spin_lock_irqsave(&cctx->lock, flags);
219462306a36Sopenharmony_ci	for (i = 0; i < FASTRPC_MAX_SESSIONS; i++) {
219562306a36Sopenharmony_ci		if (cctx->session[i].sid == sess->sid) {
219662306a36Sopenharmony_ci			cctx->session[i].valid = false;
219762306a36Sopenharmony_ci			cctx->sesscount--;
219862306a36Sopenharmony_ci		}
219962306a36Sopenharmony_ci	}
220062306a36Sopenharmony_ci	spin_unlock_irqrestore(&cctx->lock, flags);
220162306a36Sopenharmony_ci
220262306a36Sopenharmony_ci	return 0;
220362306a36Sopenharmony_ci}
220462306a36Sopenharmony_ci
220562306a36Sopenharmony_cistatic const struct of_device_id fastrpc_match_table[] = {
220662306a36Sopenharmony_ci	{ .compatible = "qcom,fastrpc-compute-cb", },
220762306a36Sopenharmony_ci	{}
220862306a36Sopenharmony_ci};
220962306a36Sopenharmony_ci
221062306a36Sopenharmony_cistatic struct platform_driver fastrpc_cb_driver = {
221162306a36Sopenharmony_ci	.probe = fastrpc_cb_probe,
221262306a36Sopenharmony_ci	.remove = fastrpc_cb_remove,
221362306a36Sopenharmony_ci	.driver = {
221462306a36Sopenharmony_ci		.name = "qcom,fastrpc-cb",
221562306a36Sopenharmony_ci		.of_match_table = fastrpc_match_table,
221662306a36Sopenharmony_ci		.suppress_bind_attrs = true,
221762306a36Sopenharmony_ci	},
221862306a36Sopenharmony_ci};
221962306a36Sopenharmony_ci
222062306a36Sopenharmony_cistatic int fastrpc_device_register(struct device *dev, struct fastrpc_channel_ctx *cctx,
222162306a36Sopenharmony_ci				   bool is_secured, const char *domain)
222262306a36Sopenharmony_ci{
222362306a36Sopenharmony_ci	struct fastrpc_device *fdev;
222462306a36Sopenharmony_ci	int err;
222562306a36Sopenharmony_ci
222662306a36Sopenharmony_ci	fdev = devm_kzalloc(dev, sizeof(*fdev), GFP_KERNEL);
222762306a36Sopenharmony_ci	if (!fdev)
222862306a36Sopenharmony_ci		return -ENOMEM;
222962306a36Sopenharmony_ci
223062306a36Sopenharmony_ci	fdev->secure = is_secured;
223162306a36Sopenharmony_ci	fdev->cctx = cctx;
223262306a36Sopenharmony_ci	fdev->miscdev.minor = MISC_DYNAMIC_MINOR;
223362306a36Sopenharmony_ci	fdev->miscdev.fops = &fastrpc_fops;
223462306a36Sopenharmony_ci	fdev->miscdev.name = devm_kasprintf(dev, GFP_KERNEL, "fastrpc-%s%s",
223562306a36Sopenharmony_ci					    domain, is_secured ? "-secure" : "");
223662306a36Sopenharmony_ci	if (!fdev->miscdev.name)
223762306a36Sopenharmony_ci		return -ENOMEM;
223862306a36Sopenharmony_ci
223962306a36Sopenharmony_ci	err = misc_register(&fdev->miscdev);
224062306a36Sopenharmony_ci	if (!err) {
224162306a36Sopenharmony_ci		if (is_secured)
224262306a36Sopenharmony_ci			cctx->secure_fdevice = fdev;
224362306a36Sopenharmony_ci		else
224462306a36Sopenharmony_ci			cctx->fdevice = fdev;
224562306a36Sopenharmony_ci	}
224662306a36Sopenharmony_ci
224762306a36Sopenharmony_ci	return err;
224862306a36Sopenharmony_ci}
224962306a36Sopenharmony_ci
225062306a36Sopenharmony_cistatic int fastrpc_rpmsg_probe(struct rpmsg_device *rpdev)
225162306a36Sopenharmony_ci{
225262306a36Sopenharmony_ci	struct device *rdev = &rpdev->dev;
225362306a36Sopenharmony_ci	struct fastrpc_channel_ctx *data;
225462306a36Sopenharmony_ci	int i, err, domain_id = -1, vmcount;
225562306a36Sopenharmony_ci	const char *domain;
225662306a36Sopenharmony_ci	bool secure_dsp;
225762306a36Sopenharmony_ci	unsigned int vmids[FASTRPC_MAX_VMIDS];
225862306a36Sopenharmony_ci
225962306a36Sopenharmony_ci	err = of_property_read_string(rdev->of_node, "label", &domain);
226062306a36Sopenharmony_ci	if (err) {
226162306a36Sopenharmony_ci		dev_info(rdev, "FastRPC Domain not specified in DT\n");
226262306a36Sopenharmony_ci		return err;
226362306a36Sopenharmony_ci	}
226462306a36Sopenharmony_ci
226562306a36Sopenharmony_ci	for (i = 0; i <= CDSP_DOMAIN_ID; i++) {
226662306a36Sopenharmony_ci		if (!strcmp(domains[i], domain)) {
226762306a36Sopenharmony_ci			domain_id = i;
226862306a36Sopenharmony_ci			break;
226962306a36Sopenharmony_ci		}
227062306a36Sopenharmony_ci	}
227162306a36Sopenharmony_ci
227262306a36Sopenharmony_ci	if (domain_id < 0) {
227362306a36Sopenharmony_ci		dev_info(rdev, "FastRPC Invalid Domain ID %d\n", domain_id);
227462306a36Sopenharmony_ci		return -EINVAL;
227562306a36Sopenharmony_ci	}
227662306a36Sopenharmony_ci
227762306a36Sopenharmony_ci	if (of_reserved_mem_device_init_by_idx(rdev, rdev->of_node, 0))
227862306a36Sopenharmony_ci		dev_info(rdev, "no reserved DMA memory for FASTRPC\n");
227962306a36Sopenharmony_ci
228062306a36Sopenharmony_ci	vmcount = of_property_read_variable_u32_array(rdev->of_node,
228162306a36Sopenharmony_ci				"qcom,vmids", &vmids[0], 0, FASTRPC_MAX_VMIDS);
228262306a36Sopenharmony_ci	if (vmcount < 0)
228362306a36Sopenharmony_ci		vmcount = 0;
228462306a36Sopenharmony_ci	else if (!qcom_scm_is_available())
228562306a36Sopenharmony_ci		return -EPROBE_DEFER;
228662306a36Sopenharmony_ci
228762306a36Sopenharmony_ci	data = kzalloc(sizeof(*data), GFP_KERNEL);
228862306a36Sopenharmony_ci	if (!data)
228962306a36Sopenharmony_ci		return -ENOMEM;
229062306a36Sopenharmony_ci
229162306a36Sopenharmony_ci	if (vmcount) {
229262306a36Sopenharmony_ci		data->vmcount = vmcount;
229362306a36Sopenharmony_ci		data->perms = BIT(QCOM_SCM_VMID_HLOS);
229462306a36Sopenharmony_ci		for (i = 0; i < data->vmcount; i++) {
229562306a36Sopenharmony_ci			data->vmperms[i].vmid = vmids[i];
229662306a36Sopenharmony_ci			data->vmperms[i].perm = QCOM_SCM_PERM_RWX;
229762306a36Sopenharmony_ci		}
229862306a36Sopenharmony_ci	}
229962306a36Sopenharmony_ci
230062306a36Sopenharmony_ci	secure_dsp = !(of_property_read_bool(rdev->of_node, "qcom,non-secure-domain"));
230162306a36Sopenharmony_ci	data->secure = secure_dsp;
230262306a36Sopenharmony_ci
230362306a36Sopenharmony_ci	switch (domain_id) {
230462306a36Sopenharmony_ci	case ADSP_DOMAIN_ID:
230562306a36Sopenharmony_ci	case MDSP_DOMAIN_ID:
230662306a36Sopenharmony_ci	case SDSP_DOMAIN_ID:
230762306a36Sopenharmony_ci		/* Unsigned PD offloading is only supported on CDSP*/
230862306a36Sopenharmony_ci		data->unsigned_support = false;
230962306a36Sopenharmony_ci		err = fastrpc_device_register(rdev, data, secure_dsp, domains[domain_id]);
231062306a36Sopenharmony_ci		if (err)
231162306a36Sopenharmony_ci			goto fdev_error;
231262306a36Sopenharmony_ci		break;
231362306a36Sopenharmony_ci	case CDSP_DOMAIN_ID:
231462306a36Sopenharmony_ci		data->unsigned_support = true;
231562306a36Sopenharmony_ci		/* Create both device nodes so that we can allow both Signed and Unsigned PD */
231662306a36Sopenharmony_ci		err = fastrpc_device_register(rdev, data, true, domains[domain_id]);
231762306a36Sopenharmony_ci		if (err)
231862306a36Sopenharmony_ci			goto fdev_error;
231962306a36Sopenharmony_ci
232062306a36Sopenharmony_ci		err = fastrpc_device_register(rdev, data, false, domains[domain_id]);
232162306a36Sopenharmony_ci		if (err)
232262306a36Sopenharmony_ci			goto fdev_error;
232362306a36Sopenharmony_ci		break;
232462306a36Sopenharmony_ci	default:
232562306a36Sopenharmony_ci		err = -EINVAL;
232662306a36Sopenharmony_ci		goto fdev_error;
232762306a36Sopenharmony_ci	}
232862306a36Sopenharmony_ci
232962306a36Sopenharmony_ci	kref_init(&data->refcount);
233062306a36Sopenharmony_ci
233162306a36Sopenharmony_ci	dev_set_drvdata(&rpdev->dev, data);
233262306a36Sopenharmony_ci	rdev->dma_mask = &data->dma_mask;
233362306a36Sopenharmony_ci	dma_set_mask_and_coherent(rdev, DMA_BIT_MASK(32));
233462306a36Sopenharmony_ci	INIT_LIST_HEAD(&data->users);
233562306a36Sopenharmony_ci	INIT_LIST_HEAD(&data->invoke_interrupted_mmaps);
233662306a36Sopenharmony_ci	spin_lock_init(&data->lock);
233762306a36Sopenharmony_ci	idr_init(&data->ctx_idr);
233862306a36Sopenharmony_ci	data->domain_id = domain_id;
233962306a36Sopenharmony_ci	data->rpdev = rpdev;
234062306a36Sopenharmony_ci
234162306a36Sopenharmony_ci	err = of_platform_populate(rdev->of_node, NULL, NULL, rdev);
234262306a36Sopenharmony_ci	if (err)
234362306a36Sopenharmony_ci		goto populate_error;
234462306a36Sopenharmony_ci
234562306a36Sopenharmony_ci	return 0;
234662306a36Sopenharmony_ci
234762306a36Sopenharmony_cipopulate_error:
234862306a36Sopenharmony_ci	if (data->fdevice)
234962306a36Sopenharmony_ci		misc_deregister(&data->fdevice->miscdev);
235062306a36Sopenharmony_ci	if (data->secure_fdevice)
235162306a36Sopenharmony_ci		misc_deregister(&data->secure_fdevice->miscdev);
235262306a36Sopenharmony_ci
235362306a36Sopenharmony_cifdev_error:
235462306a36Sopenharmony_ci	kfree(data);
235562306a36Sopenharmony_ci	return err;
235662306a36Sopenharmony_ci}
235762306a36Sopenharmony_ci
235862306a36Sopenharmony_cistatic void fastrpc_notify_users(struct fastrpc_user *user)
235962306a36Sopenharmony_ci{
236062306a36Sopenharmony_ci	struct fastrpc_invoke_ctx *ctx;
236162306a36Sopenharmony_ci
236262306a36Sopenharmony_ci	spin_lock(&user->lock);
236362306a36Sopenharmony_ci	list_for_each_entry(ctx, &user->pending, node) {
236462306a36Sopenharmony_ci		ctx->retval = -EPIPE;
236562306a36Sopenharmony_ci		complete(&ctx->work);
236662306a36Sopenharmony_ci	}
236762306a36Sopenharmony_ci	spin_unlock(&user->lock);
236862306a36Sopenharmony_ci}
236962306a36Sopenharmony_ci
237062306a36Sopenharmony_cistatic void fastrpc_rpmsg_remove(struct rpmsg_device *rpdev)
237162306a36Sopenharmony_ci{
237262306a36Sopenharmony_ci	struct fastrpc_channel_ctx *cctx = dev_get_drvdata(&rpdev->dev);
237362306a36Sopenharmony_ci	struct fastrpc_buf *buf, *b;
237462306a36Sopenharmony_ci	struct fastrpc_user *user;
237562306a36Sopenharmony_ci	unsigned long flags;
237662306a36Sopenharmony_ci
237762306a36Sopenharmony_ci	/* No invocations past this point */
237862306a36Sopenharmony_ci	spin_lock_irqsave(&cctx->lock, flags);
237962306a36Sopenharmony_ci	cctx->rpdev = NULL;
238062306a36Sopenharmony_ci	list_for_each_entry(user, &cctx->users, user)
238162306a36Sopenharmony_ci		fastrpc_notify_users(user);
238262306a36Sopenharmony_ci	spin_unlock_irqrestore(&cctx->lock, flags);
238362306a36Sopenharmony_ci
238462306a36Sopenharmony_ci	if (cctx->fdevice)
238562306a36Sopenharmony_ci		misc_deregister(&cctx->fdevice->miscdev);
238662306a36Sopenharmony_ci
238762306a36Sopenharmony_ci	if (cctx->secure_fdevice)
238862306a36Sopenharmony_ci		misc_deregister(&cctx->secure_fdevice->miscdev);
238962306a36Sopenharmony_ci
239062306a36Sopenharmony_ci	list_for_each_entry_safe(buf, b, &cctx->invoke_interrupted_mmaps, node)
239162306a36Sopenharmony_ci		list_del(&buf->node);
239262306a36Sopenharmony_ci
239362306a36Sopenharmony_ci	if (cctx->remote_heap)
239462306a36Sopenharmony_ci		fastrpc_buf_free(cctx->remote_heap);
239562306a36Sopenharmony_ci
239662306a36Sopenharmony_ci	of_platform_depopulate(&rpdev->dev);
239762306a36Sopenharmony_ci
239862306a36Sopenharmony_ci	fastrpc_channel_ctx_put(cctx);
239962306a36Sopenharmony_ci}
240062306a36Sopenharmony_ci
240162306a36Sopenharmony_cistatic int fastrpc_rpmsg_callback(struct rpmsg_device *rpdev, void *data,
240262306a36Sopenharmony_ci				  int len, void *priv, u32 addr)
240362306a36Sopenharmony_ci{
240462306a36Sopenharmony_ci	struct fastrpc_channel_ctx *cctx = dev_get_drvdata(&rpdev->dev);
240562306a36Sopenharmony_ci	struct fastrpc_invoke_rsp *rsp = data;
240662306a36Sopenharmony_ci	struct fastrpc_invoke_ctx *ctx;
240762306a36Sopenharmony_ci	unsigned long flags;
240862306a36Sopenharmony_ci	unsigned long ctxid;
240962306a36Sopenharmony_ci
241062306a36Sopenharmony_ci	if (len < sizeof(*rsp))
241162306a36Sopenharmony_ci		return -EINVAL;
241262306a36Sopenharmony_ci
241362306a36Sopenharmony_ci	ctxid = ((rsp->ctx & FASTRPC_CTXID_MASK) >> 4);
241462306a36Sopenharmony_ci
241562306a36Sopenharmony_ci	spin_lock_irqsave(&cctx->lock, flags);
241662306a36Sopenharmony_ci	ctx = idr_find(&cctx->ctx_idr, ctxid);
241762306a36Sopenharmony_ci	spin_unlock_irqrestore(&cctx->lock, flags);
241862306a36Sopenharmony_ci
241962306a36Sopenharmony_ci	if (!ctx) {
242062306a36Sopenharmony_ci		dev_err(&rpdev->dev, "No context ID matches response\n");
242162306a36Sopenharmony_ci		return -ENOENT;
242262306a36Sopenharmony_ci	}
242362306a36Sopenharmony_ci
242462306a36Sopenharmony_ci	ctx->retval = rsp->retval;
242562306a36Sopenharmony_ci	complete(&ctx->work);
242662306a36Sopenharmony_ci
242762306a36Sopenharmony_ci	/*
242862306a36Sopenharmony_ci	 * The DMA buffer associated with the context cannot be freed in
242962306a36Sopenharmony_ci	 * interrupt context so schedule it through a worker thread to
243062306a36Sopenharmony_ci	 * avoid a kernel BUG.
243162306a36Sopenharmony_ci	 */
243262306a36Sopenharmony_ci	schedule_work(&ctx->put_work);
243362306a36Sopenharmony_ci
243462306a36Sopenharmony_ci	return 0;
243562306a36Sopenharmony_ci}
243662306a36Sopenharmony_ci
243762306a36Sopenharmony_cistatic const struct of_device_id fastrpc_rpmsg_of_match[] = {
243862306a36Sopenharmony_ci	{ .compatible = "qcom,fastrpc" },
243962306a36Sopenharmony_ci	{ },
244062306a36Sopenharmony_ci};
244162306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, fastrpc_rpmsg_of_match);
244262306a36Sopenharmony_ci
244362306a36Sopenharmony_cistatic struct rpmsg_driver fastrpc_driver = {
244462306a36Sopenharmony_ci	.probe = fastrpc_rpmsg_probe,
244562306a36Sopenharmony_ci	.remove = fastrpc_rpmsg_remove,
244662306a36Sopenharmony_ci	.callback = fastrpc_rpmsg_callback,
244762306a36Sopenharmony_ci	.drv = {
244862306a36Sopenharmony_ci		.name = "qcom,fastrpc",
244962306a36Sopenharmony_ci		.of_match_table = fastrpc_rpmsg_of_match,
245062306a36Sopenharmony_ci	},
245162306a36Sopenharmony_ci};
245262306a36Sopenharmony_ci
245362306a36Sopenharmony_cistatic int fastrpc_init(void)
245462306a36Sopenharmony_ci{
245562306a36Sopenharmony_ci	int ret;
245662306a36Sopenharmony_ci
245762306a36Sopenharmony_ci	ret = platform_driver_register(&fastrpc_cb_driver);
245862306a36Sopenharmony_ci	if (ret < 0) {
245962306a36Sopenharmony_ci		pr_err("fastrpc: failed to register cb driver\n");
246062306a36Sopenharmony_ci		return ret;
246162306a36Sopenharmony_ci	}
246262306a36Sopenharmony_ci
246362306a36Sopenharmony_ci	ret = register_rpmsg_driver(&fastrpc_driver);
246462306a36Sopenharmony_ci	if (ret < 0) {
246562306a36Sopenharmony_ci		pr_err("fastrpc: failed to register rpmsg driver\n");
246662306a36Sopenharmony_ci		platform_driver_unregister(&fastrpc_cb_driver);
246762306a36Sopenharmony_ci		return ret;
246862306a36Sopenharmony_ci	}
246962306a36Sopenharmony_ci
247062306a36Sopenharmony_ci	return 0;
247162306a36Sopenharmony_ci}
247262306a36Sopenharmony_cimodule_init(fastrpc_init);
247362306a36Sopenharmony_ci
247462306a36Sopenharmony_cistatic void fastrpc_exit(void)
247562306a36Sopenharmony_ci{
247662306a36Sopenharmony_ci	platform_driver_unregister(&fastrpc_cb_driver);
247762306a36Sopenharmony_ci	unregister_rpmsg_driver(&fastrpc_driver);
247862306a36Sopenharmony_ci}
247962306a36Sopenharmony_cimodule_exit(fastrpc_exit);
248062306a36Sopenharmony_ci
248162306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
248262306a36Sopenharmony_ciMODULE_IMPORT_NS(DMA_BUF);
2483