xref: /openbmc/linux/drivers/misc/fastrpc.c (revision c68cfb718c8f97b7f7a50ed66be5feb42d0c8988)
1f6f9279fSSrinivas Kandagatla // SPDX-License-Identifier: GPL-2.0
2f6f9279fSSrinivas Kandagatla // Copyright (c) 2011-2018, The Linux Foundation. All rights reserved.
3f6f9279fSSrinivas Kandagatla // Copyright (c) 2018, Linaro Limited
4f6f9279fSSrinivas Kandagatla 
5*c68cfb71SSrinivas Kandagatla #include <linux/completion.h>
6f6f9279fSSrinivas Kandagatla #include <linux/device.h>
7*c68cfb71SSrinivas Kandagatla #include <linux/dma-buf.h>
8f6f9279fSSrinivas Kandagatla #include <linux/dma-mapping.h>
9f6f9279fSSrinivas Kandagatla #include <linux/idr.h>
10f6f9279fSSrinivas Kandagatla #include <linux/list.h>
11f6f9279fSSrinivas Kandagatla #include <linux/miscdevice.h>
12f6f9279fSSrinivas Kandagatla #include <linux/module.h>
13f6f9279fSSrinivas Kandagatla #include <linux/of_address.h>
14f6f9279fSSrinivas Kandagatla #include <linux/of.h>
15f6f9279fSSrinivas Kandagatla #include <linux/of_platform.h>
16f6f9279fSSrinivas Kandagatla #include <linux/rpmsg.h>
17f6f9279fSSrinivas Kandagatla #include <linux/scatterlist.h>
18f6f9279fSSrinivas Kandagatla #include <linux/slab.h>
19*c68cfb71SSrinivas Kandagatla #include <uapi/misc/fastrpc.h>
20f6f9279fSSrinivas Kandagatla 
21f6f9279fSSrinivas Kandagatla #define ADSP_DOMAIN_ID (0)
22f6f9279fSSrinivas Kandagatla #define MDSP_DOMAIN_ID (1)
23f6f9279fSSrinivas Kandagatla #define SDSP_DOMAIN_ID (2)
24f6f9279fSSrinivas Kandagatla #define CDSP_DOMAIN_ID (3)
25f6f9279fSSrinivas Kandagatla #define FASTRPC_DEV_MAX		4 /* adsp, mdsp, slpi, cdsp*/
26f6f9279fSSrinivas Kandagatla #define FASTRPC_MAX_SESSIONS	9 /*8 compute, 1 cpz*/
27*c68cfb71SSrinivas Kandagatla #define FASTRPC_ALIGN		128
28*c68cfb71SSrinivas Kandagatla #define FASTRPC_MAX_FDLIST	16
29*c68cfb71SSrinivas Kandagatla #define FASTRPC_MAX_CRCLIST	64
30*c68cfb71SSrinivas Kandagatla #define FASTRPC_PHYS(p)	((p) & 0xffffffff)
31f6f9279fSSrinivas Kandagatla #define FASTRPC_CTX_MAX (256)
32f6f9279fSSrinivas Kandagatla #define FASTRPC_CTXID_MASK (0xFF0)
33f6f9279fSSrinivas Kandagatla #define FASTRPC_DEVICE_NAME	"fastrpc"
34f6f9279fSSrinivas Kandagatla 
35*c68cfb71SSrinivas Kandagatla /* Retrives number of input buffers from the scalars parameter */
36*c68cfb71SSrinivas Kandagatla #define REMOTE_SCALARS_INBUFS(sc)	(((sc) >> 16) & 0x0ff)
37*c68cfb71SSrinivas Kandagatla 
38*c68cfb71SSrinivas Kandagatla /* Retrives number of output buffers from the scalars parameter */
39*c68cfb71SSrinivas Kandagatla #define REMOTE_SCALARS_OUTBUFS(sc)	(((sc) >> 8) & 0x0ff)
40*c68cfb71SSrinivas Kandagatla 
41*c68cfb71SSrinivas Kandagatla /* Retrives number of input handles from the scalars parameter */
42*c68cfb71SSrinivas Kandagatla #define REMOTE_SCALARS_INHANDLES(sc)	(((sc) >> 4) & 0x0f)
43*c68cfb71SSrinivas Kandagatla 
44*c68cfb71SSrinivas Kandagatla /* Retrives number of output handles from the scalars parameter */
45*c68cfb71SSrinivas Kandagatla #define REMOTE_SCALARS_OUTHANDLES(sc)	((sc) & 0x0f)
46*c68cfb71SSrinivas Kandagatla 
47*c68cfb71SSrinivas Kandagatla #define REMOTE_SCALARS_LENGTH(sc)	(REMOTE_SCALARS_INBUFS(sc) +   \
48*c68cfb71SSrinivas Kandagatla 					 REMOTE_SCALARS_OUTBUFS(sc) +  \
49*c68cfb71SSrinivas Kandagatla 					 REMOTE_SCALARS_INHANDLES(sc)+ \
50*c68cfb71SSrinivas Kandagatla 					 REMOTE_SCALARS_OUTHANDLES(sc))
51*c68cfb71SSrinivas Kandagatla #define FASTRPC_BUILD_SCALARS(attr, method, in, out, oin, oout)  \
52*c68cfb71SSrinivas Kandagatla 				(((attr & 0x07) << 29) |		\
53*c68cfb71SSrinivas Kandagatla 				((method & 0x1f) << 24) |	\
54*c68cfb71SSrinivas Kandagatla 				((in & 0xff) << 16) |		\
55*c68cfb71SSrinivas Kandagatla 				((out & 0xff) <<  8) |		\
56*c68cfb71SSrinivas Kandagatla 				((oin & 0x0f) <<  4) |		\
57*c68cfb71SSrinivas Kandagatla 				(oout & 0x0f))
58*c68cfb71SSrinivas Kandagatla 
59*c68cfb71SSrinivas Kandagatla #define FASTRPC_SCALARS(method, in, out) \
60*c68cfb71SSrinivas Kandagatla 		FASTRPC_BUILD_SCALARS(0, method, in, out, 0, 0)
61*c68cfb71SSrinivas Kandagatla 
62f6f9279fSSrinivas Kandagatla #define miscdev_to_cctx(d) container_of(d, struct fastrpc_channel_ctx, miscdev)
63f6f9279fSSrinivas Kandagatla 
64f6f9279fSSrinivas Kandagatla static const char *domains[FASTRPC_DEV_MAX] = { "adsp", "mdsp",
65f6f9279fSSrinivas Kandagatla 						"sdsp", "cdsp"};
66*c68cfb71SSrinivas Kandagatla struct fastrpc_phy_page {
67*c68cfb71SSrinivas Kandagatla 	u64 addr;		/* physical address */
68*c68cfb71SSrinivas Kandagatla 	u64 size;		/* size of contiguous region */
69*c68cfb71SSrinivas Kandagatla };
70*c68cfb71SSrinivas Kandagatla 
71*c68cfb71SSrinivas Kandagatla struct fastrpc_invoke_buf {
72*c68cfb71SSrinivas Kandagatla 	u32 num;		/* number of contiguous regions */
73*c68cfb71SSrinivas Kandagatla 	u32 pgidx;		/* index to start of contiguous region */
74*c68cfb71SSrinivas Kandagatla };
75*c68cfb71SSrinivas Kandagatla 
76*c68cfb71SSrinivas Kandagatla struct fastrpc_remote_arg {
77*c68cfb71SSrinivas Kandagatla 	u64 pv;
78*c68cfb71SSrinivas Kandagatla 	u64 len;
79*c68cfb71SSrinivas Kandagatla };
80*c68cfb71SSrinivas Kandagatla 
81*c68cfb71SSrinivas Kandagatla struct fastrpc_msg {
82*c68cfb71SSrinivas Kandagatla 	int pid;		/* process group id */
83*c68cfb71SSrinivas Kandagatla 	int tid;		/* thread id */
84*c68cfb71SSrinivas Kandagatla 	u64 ctx;		/* invoke caller context */
85*c68cfb71SSrinivas Kandagatla 	u32 handle;	/* handle to invoke */
86*c68cfb71SSrinivas Kandagatla 	u32 sc;		/* scalars structure describing the data */
87*c68cfb71SSrinivas Kandagatla 	u64 addr;		/* physical address */
88*c68cfb71SSrinivas Kandagatla 	u64 size;		/* size of contiguous region */
89*c68cfb71SSrinivas Kandagatla };
90*c68cfb71SSrinivas Kandagatla 
91*c68cfb71SSrinivas Kandagatla struct fastrpc_invoke_rsp {
92*c68cfb71SSrinivas Kandagatla 	u64 ctx;		/* invoke caller context */
93*c68cfb71SSrinivas Kandagatla 	int retval;		/* invoke return value */
94*c68cfb71SSrinivas Kandagatla };
95*c68cfb71SSrinivas Kandagatla 
96*c68cfb71SSrinivas Kandagatla struct fastrpc_buf {
97*c68cfb71SSrinivas Kandagatla 	struct fastrpc_user *fl;
98*c68cfb71SSrinivas Kandagatla 	struct device *dev;
99*c68cfb71SSrinivas Kandagatla 	void *virt;
100*c68cfb71SSrinivas Kandagatla 	u64 phys;
101*c68cfb71SSrinivas Kandagatla 	u64 size;
102*c68cfb71SSrinivas Kandagatla };
103*c68cfb71SSrinivas Kandagatla 
104*c68cfb71SSrinivas Kandagatla struct fastrpc_map {
105*c68cfb71SSrinivas Kandagatla 	struct list_head node;
106*c68cfb71SSrinivas Kandagatla 	struct fastrpc_user *fl;
107*c68cfb71SSrinivas Kandagatla 	int fd;
108*c68cfb71SSrinivas Kandagatla 	struct dma_buf *buf;
109*c68cfb71SSrinivas Kandagatla 	struct sg_table *table;
110*c68cfb71SSrinivas Kandagatla 	struct dma_buf_attachment *attach;
111*c68cfb71SSrinivas Kandagatla 	u64 phys;
112*c68cfb71SSrinivas Kandagatla 	u64 size;
113*c68cfb71SSrinivas Kandagatla 	void *va;
114*c68cfb71SSrinivas Kandagatla 	u64 len;
115*c68cfb71SSrinivas Kandagatla 	struct kref refcount;
116*c68cfb71SSrinivas Kandagatla };
117*c68cfb71SSrinivas Kandagatla 
118*c68cfb71SSrinivas Kandagatla struct fastrpc_invoke_ctx {
119*c68cfb71SSrinivas Kandagatla 	int nscalars;
120*c68cfb71SSrinivas Kandagatla 	int nbufs;
121*c68cfb71SSrinivas Kandagatla 	int retval;
122*c68cfb71SSrinivas Kandagatla 	int pid;
123*c68cfb71SSrinivas Kandagatla 	int tgid;
124*c68cfb71SSrinivas Kandagatla 	u32 sc;
125*c68cfb71SSrinivas Kandagatla 	u32 *crc;
126*c68cfb71SSrinivas Kandagatla 	u64 ctxid;
127*c68cfb71SSrinivas Kandagatla 	u64 msg_sz;
128*c68cfb71SSrinivas Kandagatla 	struct kref refcount;
129*c68cfb71SSrinivas Kandagatla 	struct list_head node; /* list of ctxs */
130*c68cfb71SSrinivas Kandagatla 	struct completion work;
131*c68cfb71SSrinivas Kandagatla 	struct fastrpc_msg msg;
132*c68cfb71SSrinivas Kandagatla 	struct fastrpc_user *fl;
133*c68cfb71SSrinivas Kandagatla 	struct fastrpc_remote_arg *rpra;
134*c68cfb71SSrinivas Kandagatla 	struct fastrpc_map **maps;
135*c68cfb71SSrinivas Kandagatla 	struct fastrpc_buf *buf;
136*c68cfb71SSrinivas Kandagatla 	struct fastrpc_invoke_args *args;
137*c68cfb71SSrinivas Kandagatla 	struct fastrpc_channel_ctx *cctx;
138*c68cfb71SSrinivas Kandagatla };
139f6f9279fSSrinivas Kandagatla 
140f6f9279fSSrinivas Kandagatla struct fastrpc_session_ctx {
141f6f9279fSSrinivas Kandagatla 	struct device *dev;
142f6f9279fSSrinivas Kandagatla 	int sid;
143f6f9279fSSrinivas Kandagatla 	bool used;
144f6f9279fSSrinivas Kandagatla 	bool valid;
145f6f9279fSSrinivas Kandagatla };
146f6f9279fSSrinivas Kandagatla 
147f6f9279fSSrinivas Kandagatla struct fastrpc_channel_ctx {
148f6f9279fSSrinivas Kandagatla 	int domain_id;
149f6f9279fSSrinivas Kandagatla 	int sesscount;
150f6f9279fSSrinivas Kandagatla 	struct rpmsg_device *rpdev;
151f6f9279fSSrinivas Kandagatla 	struct fastrpc_session_ctx session[FASTRPC_MAX_SESSIONS];
152f6f9279fSSrinivas Kandagatla 	spinlock_t lock;
153f6f9279fSSrinivas Kandagatla 	struct idr ctx_idr;
154f6f9279fSSrinivas Kandagatla 	struct list_head users;
155f6f9279fSSrinivas Kandagatla 	struct miscdevice miscdev;
156f6f9279fSSrinivas Kandagatla };
157f6f9279fSSrinivas Kandagatla 
158f6f9279fSSrinivas Kandagatla struct fastrpc_user {
159f6f9279fSSrinivas Kandagatla 	struct list_head user;
160f6f9279fSSrinivas Kandagatla 	struct list_head maps;
161f6f9279fSSrinivas Kandagatla 	struct list_head pending;
162f6f9279fSSrinivas Kandagatla 
163f6f9279fSSrinivas Kandagatla 	struct fastrpc_channel_ctx *cctx;
164f6f9279fSSrinivas Kandagatla 	struct fastrpc_session_ctx *sctx;
165*c68cfb71SSrinivas Kandagatla 	struct fastrpc_buf *init_mem;
166f6f9279fSSrinivas Kandagatla 
167f6f9279fSSrinivas Kandagatla 	int tgid;
168f6f9279fSSrinivas Kandagatla 	int pd;
169f6f9279fSSrinivas Kandagatla 	/* Lock for lists */
170f6f9279fSSrinivas Kandagatla 	spinlock_t lock;
171f6f9279fSSrinivas Kandagatla 	/* lock for allocations */
172f6f9279fSSrinivas Kandagatla 	struct mutex mutex;
173f6f9279fSSrinivas Kandagatla };
174f6f9279fSSrinivas Kandagatla 
175*c68cfb71SSrinivas Kandagatla static void fastrpc_free_map(struct kref *ref)
176*c68cfb71SSrinivas Kandagatla {
177*c68cfb71SSrinivas Kandagatla 	struct fastrpc_map *map;
178*c68cfb71SSrinivas Kandagatla 
179*c68cfb71SSrinivas Kandagatla 	map = container_of(ref, struct fastrpc_map, refcount);
180*c68cfb71SSrinivas Kandagatla 
181*c68cfb71SSrinivas Kandagatla 	if (map->table) {
182*c68cfb71SSrinivas Kandagatla 		dma_buf_unmap_attachment(map->attach, map->table,
183*c68cfb71SSrinivas Kandagatla 					 DMA_BIDIRECTIONAL);
184*c68cfb71SSrinivas Kandagatla 		dma_buf_detach(map->buf, map->attach);
185*c68cfb71SSrinivas Kandagatla 		dma_buf_put(map->buf);
186*c68cfb71SSrinivas Kandagatla 	}
187*c68cfb71SSrinivas Kandagatla 
188*c68cfb71SSrinivas Kandagatla 	kfree(map);
189*c68cfb71SSrinivas Kandagatla }
190*c68cfb71SSrinivas Kandagatla 
191*c68cfb71SSrinivas Kandagatla static void fastrpc_map_put(struct fastrpc_map *map)
192*c68cfb71SSrinivas Kandagatla {
193*c68cfb71SSrinivas Kandagatla 	if (map)
194*c68cfb71SSrinivas Kandagatla 		kref_put(&map->refcount, fastrpc_free_map);
195*c68cfb71SSrinivas Kandagatla }
196*c68cfb71SSrinivas Kandagatla 
197*c68cfb71SSrinivas Kandagatla static void fastrpc_map_get(struct fastrpc_map *map)
198*c68cfb71SSrinivas Kandagatla {
199*c68cfb71SSrinivas Kandagatla 	if (map)
200*c68cfb71SSrinivas Kandagatla 		kref_get(&map->refcount);
201*c68cfb71SSrinivas Kandagatla }
202*c68cfb71SSrinivas Kandagatla 
203*c68cfb71SSrinivas Kandagatla static int fastrpc_map_find(struct fastrpc_user *fl, int fd,
204*c68cfb71SSrinivas Kandagatla 			    struct fastrpc_map **ppmap)
205*c68cfb71SSrinivas Kandagatla {
206*c68cfb71SSrinivas Kandagatla 	struct fastrpc_map *map = NULL;
207*c68cfb71SSrinivas Kandagatla 
208*c68cfb71SSrinivas Kandagatla 	mutex_lock(&fl->mutex);
209*c68cfb71SSrinivas Kandagatla 	list_for_each_entry(map, &fl->maps, node) {
210*c68cfb71SSrinivas Kandagatla 		if (map->fd == fd) {
211*c68cfb71SSrinivas Kandagatla 			fastrpc_map_get(map);
212*c68cfb71SSrinivas Kandagatla 			*ppmap = map;
213*c68cfb71SSrinivas Kandagatla 			mutex_unlock(&fl->mutex);
214*c68cfb71SSrinivas Kandagatla 			return 0;
215*c68cfb71SSrinivas Kandagatla 		}
216*c68cfb71SSrinivas Kandagatla 	}
217*c68cfb71SSrinivas Kandagatla 	mutex_unlock(&fl->mutex);
218*c68cfb71SSrinivas Kandagatla 
219*c68cfb71SSrinivas Kandagatla 	return -ENOENT;
220*c68cfb71SSrinivas Kandagatla }
221*c68cfb71SSrinivas Kandagatla 
222*c68cfb71SSrinivas Kandagatla static void fastrpc_buf_free(struct fastrpc_buf *buf)
223*c68cfb71SSrinivas Kandagatla {
224*c68cfb71SSrinivas Kandagatla 	dma_free_coherent(buf->dev, buf->size, buf->virt,
225*c68cfb71SSrinivas Kandagatla 			  FASTRPC_PHYS(buf->phys));
226*c68cfb71SSrinivas Kandagatla 	kfree(buf);
227*c68cfb71SSrinivas Kandagatla }
228*c68cfb71SSrinivas Kandagatla 
229*c68cfb71SSrinivas Kandagatla static int fastrpc_buf_alloc(struct fastrpc_user *fl, struct device *dev,
230*c68cfb71SSrinivas Kandagatla 			     u64 size, struct fastrpc_buf **obuf)
231*c68cfb71SSrinivas Kandagatla {
232*c68cfb71SSrinivas Kandagatla 	struct fastrpc_buf *buf;
233*c68cfb71SSrinivas Kandagatla 
234*c68cfb71SSrinivas Kandagatla 	buf = kzalloc(sizeof(*buf), GFP_KERNEL);
235*c68cfb71SSrinivas Kandagatla 	if (!buf)
236*c68cfb71SSrinivas Kandagatla 		return -ENOMEM;
237*c68cfb71SSrinivas Kandagatla 
238*c68cfb71SSrinivas Kandagatla 	buf->fl = fl;
239*c68cfb71SSrinivas Kandagatla 	buf->virt = NULL;
240*c68cfb71SSrinivas Kandagatla 	buf->phys = 0;
241*c68cfb71SSrinivas Kandagatla 	buf->size = size;
242*c68cfb71SSrinivas Kandagatla 	buf->dev = dev;
243*c68cfb71SSrinivas Kandagatla 
244*c68cfb71SSrinivas Kandagatla 	buf->virt = dma_alloc_coherent(dev, buf->size, (dma_addr_t *)&buf->phys,
245*c68cfb71SSrinivas Kandagatla 				       GFP_KERNEL);
246*c68cfb71SSrinivas Kandagatla 	if (!buf->virt)
247*c68cfb71SSrinivas Kandagatla 		return -ENOMEM;
248*c68cfb71SSrinivas Kandagatla 
249*c68cfb71SSrinivas Kandagatla 	if (fl->sctx && fl->sctx->sid)
250*c68cfb71SSrinivas Kandagatla 		buf->phys += ((u64)fl->sctx->sid << 32);
251*c68cfb71SSrinivas Kandagatla 
252*c68cfb71SSrinivas Kandagatla 	*obuf = buf;
253*c68cfb71SSrinivas Kandagatla 
254*c68cfb71SSrinivas Kandagatla 	return 0;
255*c68cfb71SSrinivas Kandagatla }
256*c68cfb71SSrinivas Kandagatla 
257*c68cfb71SSrinivas Kandagatla static void fastrpc_context_free(struct kref *ref)
258*c68cfb71SSrinivas Kandagatla {
259*c68cfb71SSrinivas Kandagatla 	struct fastrpc_invoke_ctx *ctx;
260*c68cfb71SSrinivas Kandagatla 	struct fastrpc_channel_ctx *cctx;
261*c68cfb71SSrinivas Kandagatla 	int i;
262*c68cfb71SSrinivas Kandagatla 
263*c68cfb71SSrinivas Kandagatla 	ctx = container_of(ref, struct fastrpc_invoke_ctx, refcount);
264*c68cfb71SSrinivas Kandagatla 	cctx = ctx->cctx;
265*c68cfb71SSrinivas Kandagatla 
266*c68cfb71SSrinivas Kandagatla 	for (i = 0; i < ctx->nscalars; i++)
267*c68cfb71SSrinivas Kandagatla 		fastrpc_map_put(ctx->maps[i]);
268*c68cfb71SSrinivas Kandagatla 
269*c68cfb71SSrinivas Kandagatla 	if (ctx->buf)
270*c68cfb71SSrinivas Kandagatla 		fastrpc_buf_free(ctx->buf);
271*c68cfb71SSrinivas Kandagatla 
272*c68cfb71SSrinivas Kandagatla 	spin_lock(&cctx->lock);
273*c68cfb71SSrinivas Kandagatla 	idr_remove(&cctx->ctx_idr, ctx->ctxid >> 4);
274*c68cfb71SSrinivas Kandagatla 	spin_unlock(&cctx->lock);
275*c68cfb71SSrinivas Kandagatla 
276*c68cfb71SSrinivas Kandagatla 	kfree(ctx->maps);
277*c68cfb71SSrinivas Kandagatla 	kfree(ctx);
278*c68cfb71SSrinivas Kandagatla }
279*c68cfb71SSrinivas Kandagatla 
280*c68cfb71SSrinivas Kandagatla static void fastrpc_context_get(struct fastrpc_invoke_ctx *ctx)
281*c68cfb71SSrinivas Kandagatla {
282*c68cfb71SSrinivas Kandagatla 	kref_get(&ctx->refcount);
283*c68cfb71SSrinivas Kandagatla }
284*c68cfb71SSrinivas Kandagatla 
285*c68cfb71SSrinivas Kandagatla static void fastrpc_context_put(struct fastrpc_invoke_ctx *ctx)
286*c68cfb71SSrinivas Kandagatla {
287*c68cfb71SSrinivas Kandagatla 	kref_put(&ctx->refcount, fastrpc_context_free);
288*c68cfb71SSrinivas Kandagatla }
289*c68cfb71SSrinivas Kandagatla 
290*c68cfb71SSrinivas Kandagatla static struct fastrpc_invoke_ctx *fastrpc_context_alloc(
291*c68cfb71SSrinivas Kandagatla 			struct fastrpc_user *user, u32 kernel, u32 sc,
292*c68cfb71SSrinivas Kandagatla 			struct fastrpc_invoke_args *args)
293*c68cfb71SSrinivas Kandagatla {
294*c68cfb71SSrinivas Kandagatla 	struct fastrpc_channel_ctx *cctx = user->cctx;
295*c68cfb71SSrinivas Kandagatla 	struct fastrpc_invoke_ctx *ctx = NULL;
296*c68cfb71SSrinivas Kandagatla 	int ret;
297*c68cfb71SSrinivas Kandagatla 
298*c68cfb71SSrinivas Kandagatla 	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
299*c68cfb71SSrinivas Kandagatla 	if (!ctx)
300*c68cfb71SSrinivas Kandagatla 		return ERR_PTR(-ENOMEM);
301*c68cfb71SSrinivas Kandagatla 
302*c68cfb71SSrinivas Kandagatla 	INIT_LIST_HEAD(&ctx->node);
303*c68cfb71SSrinivas Kandagatla 	ctx->fl = user;
304*c68cfb71SSrinivas Kandagatla 	ctx->nscalars = REMOTE_SCALARS_LENGTH(sc);
305*c68cfb71SSrinivas Kandagatla 	ctx->nbufs = REMOTE_SCALARS_INBUFS(sc) +
306*c68cfb71SSrinivas Kandagatla 		     REMOTE_SCALARS_OUTBUFS(sc);
307*c68cfb71SSrinivas Kandagatla 
308*c68cfb71SSrinivas Kandagatla 	if (ctx->nscalars) {
309*c68cfb71SSrinivas Kandagatla 		ctx->maps = kcalloc(ctx->nscalars,
310*c68cfb71SSrinivas Kandagatla 				    sizeof(*ctx->maps), GFP_KERNEL);
311*c68cfb71SSrinivas Kandagatla 		if (!ctx->maps) {
312*c68cfb71SSrinivas Kandagatla 			kfree(ctx);
313*c68cfb71SSrinivas Kandagatla 			return ERR_PTR(-ENOMEM);
314*c68cfb71SSrinivas Kandagatla 		}
315*c68cfb71SSrinivas Kandagatla 		ctx->args = args;
316*c68cfb71SSrinivas Kandagatla 	}
317*c68cfb71SSrinivas Kandagatla 
318*c68cfb71SSrinivas Kandagatla 	ctx->sc = sc;
319*c68cfb71SSrinivas Kandagatla 	ctx->retval = -1;
320*c68cfb71SSrinivas Kandagatla 	ctx->pid = current->pid;
321*c68cfb71SSrinivas Kandagatla 	ctx->tgid = user->tgid;
322*c68cfb71SSrinivas Kandagatla 	ctx->cctx = cctx;
323*c68cfb71SSrinivas Kandagatla 	init_completion(&ctx->work);
324*c68cfb71SSrinivas Kandagatla 
325*c68cfb71SSrinivas Kandagatla 	spin_lock(&user->lock);
326*c68cfb71SSrinivas Kandagatla 	list_add_tail(&ctx->node, &user->pending);
327*c68cfb71SSrinivas Kandagatla 	spin_unlock(&user->lock);
328*c68cfb71SSrinivas Kandagatla 
329*c68cfb71SSrinivas Kandagatla 	spin_lock(&cctx->lock);
330*c68cfb71SSrinivas Kandagatla 	ret = idr_alloc_cyclic(&cctx->ctx_idr, ctx, 1,
331*c68cfb71SSrinivas Kandagatla 			       FASTRPC_CTX_MAX, GFP_ATOMIC);
332*c68cfb71SSrinivas Kandagatla 	if (ret < 0) {
333*c68cfb71SSrinivas Kandagatla 		spin_unlock(&cctx->lock);
334*c68cfb71SSrinivas Kandagatla 		goto err_idr;
335*c68cfb71SSrinivas Kandagatla 	}
336*c68cfb71SSrinivas Kandagatla 	ctx->ctxid = ret << 4;
337*c68cfb71SSrinivas Kandagatla 	spin_unlock(&cctx->lock);
338*c68cfb71SSrinivas Kandagatla 
339*c68cfb71SSrinivas Kandagatla 	kref_init(&ctx->refcount);
340*c68cfb71SSrinivas Kandagatla 
341*c68cfb71SSrinivas Kandagatla 	return ctx;
342*c68cfb71SSrinivas Kandagatla err_idr:
343*c68cfb71SSrinivas Kandagatla 	spin_lock(&user->lock);
344*c68cfb71SSrinivas Kandagatla 	list_del(&ctx->node);
345*c68cfb71SSrinivas Kandagatla 	spin_unlock(&user->lock);
346*c68cfb71SSrinivas Kandagatla 	kfree(ctx->maps);
347*c68cfb71SSrinivas Kandagatla 	kfree(ctx);
348*c68cfb71SSrinivas Kandagatla 
349*c68cfb71SSrinivas Kandagatla 	return ERR_PTR(ret);
350*c68cfb71SSrinivas Kandagatla }
351*c68cfb71SSrinivas Kandagatla 
352*c68cfb71SSrinivas Kandagatla static int fastrpc_map_create(struct fastrpc_user *fl, int fd,
353*c68cfb71SSrinivas Kandagatla 			      u64 len, struct fastrpc_map **ppmap)
354*c68cfb71SSrinivas Kandagatla {
355*c68cfb71SSrinivas Kandagatla 	struct fastrpc_session_ctx *sess = fl->sctx;
356*c68cfb71SSrinivas Kandagatla 	struct fastrpc_map *map = NULL;
357*c68cfb71SSrinivas Kandagatla 	int err = 0;
358*c68cfb71SSrinivas Kandagatla 
359*c68cfb71SSrinivas Kandagatla 	if (!fastrpc_map_find(fl, fd, ppmap))
360*c68cfb71SSrinivas Kandagatla 		return 0;
361*c68cfb71SSrinivas Kandagatla 
362*c68cfb71SSrinivas Kandagatla 	map = kzalloc(sizeof(*map), GFP_KERNEL);
363*c68cfb71SSrinivas Kandagatla 	if (!map)
364*c68cfb71SSrinivas Kandagatla 		return -ENOMEM;
365*c68cfb71SSrinivas Kandagatla 
366*c68cfb71SSrinivas Kandagatla 	INIT_LIST_HEAD(&map->node);
367*c68cfb71SSrinivas Kandagatla 	map->fl = fl;
368*c68cfb71SSrinivas Kandagatla 	map->fd = fd;
369*c68cfb71SSrinivas Kandagatla 	map->buf = dma_buf_get(fd);
370*c68cfb71SSrinivas Kandagatla 	if (!map->buf) {
371*c68cfb71SSrinivas Kandagatla 		err = -EINVAL;
372*c68cfb71SSrinivas Kandagatla 		goto get_err;
373*c68cfb71SSrinivas Kandagatla 	}
374*c68cfb71SSrinivas Kandagatla 
375*c68cfb71SSrinivas Kandagatla 	map->attach = dma_buf_attach(map->buf, sess->dev);
376*c68cfb71SSrinivas Kandagatla 	if (IS_ERR(map->attach)) {
377*c68cfb71SSrinivas Kandagatla 		dev_err(sess->dev, "Failed to attach dmabuf\n");
378*c68cfb71SSrinivas Kandagatla 		err = PTR_ERR(map->attach);
379*c68cfb71SSrinivas Kandagatla 		goto attach_err;
380*c68cfb71SSrinivas Kandagatla 	}
381*c68cfb71SSrinivas Kandagatla 
382*c68cfb71SSrinivas Kandagatla 	map->table = dma_buf_map_attachment(map->attach, DMA_BIDIRECTIONAL);
383*c68cfb71SSrinivas Kandagatla 	if (IS_ERR(map->table)) {
384*c68cfb71SSrinivas Kandagatla 		err = PTR_ERR(map->table);
385*c68cfb71SSrinivas Kandagatla 		goto map_err;
386*c68cfb71SSrinivas Kandagatla 	}
387*c68cfb71SSrinivas Kandagatla 
388*c68cfb71SSrinivas Kandagatla 	map->phys = sg_dma_address(map->table->sgl);
389*c68cfb71SSrinivas Kandagatla 	map->phys += ((u64)fl->sctx->sid << 32);
390*c68cfb71SSrinivas Kandagatla 	map->size = len;
391*c68cfb71SSrinivas Kandagatla 	map->va = sg_virt(map->table->sgl);
392*c68cfb71SSrinivas Kandagatla 	map->len = len;
393*c68cfb71SSrinivas Kandagatla 	kref_init(&map->refcount);
394*c68cfb71SSrinivas Kandagatla 
395*c68cfb71SSrinivas Kandagatla 	spin_lock(&fl->lock);
396*c68cfb71SSrinivas Kandagatla 	list_add_tail(&map->node, &fl->maps);
397*c68cfb71SSrinivas Kandagatla 	spin_unlock(&fl->lock);
398*c68cfb71SSrinivas Kandagatla 	*ppmap = map;
399*c68cfb71SSrinivas Kandagatla 
400*c68cfb71SSrinivas Kandagatla 	return 0;
401*c68cfb71SSrinivas Kandagatla 
402*c68cfb71SSrinivas Kandagatla map_err:
403*c68cfb71SSrinivas Kandagatla 	dma_buf_detach(map->buf, map->attach);
404*c68cfb71SSrinivas Kandagatla attach_err:
405*c68cfb71SSrinivas Kandagatla 	dma_buf_put(map->buf);
406*c68cfb71SSrinivas Kandagatla get_err:
407*c68cfb71SSrinivas Kandagatla 	kfree(map);
408*c68cfb71SSrinivas Kandagatla 
409*c68cfb71SSrinivas Kandagatla 	return err;
410*c68cfb71SSrinivas Kandagatla }
411*c68cfb71SSrinivas Kandagatla 
412*c68cfb71SSrinivas Kandagatla /*
413*c68cfb71SSrinivas Kandagatla  * Fastrpc payload buffer with metadata looks like:
414*c68cfb71SSrinivas Kandagatla  *
415*c68cfb71SSrinivas Kandagatla  * >>>>>>  START of METADATA <<<<<<<<<
416*c68cfb71SSrinivas Kandagatla  * +---------------------------------+
417*c68cfb71SSrinivas Kandagatla  * |           Arguments             |
418*c68cfb71SSrinivas Kandagatla  * | type:(struct fastrpc_remote_arg)|
419*c68cfb71SSrinivas Kandagatla  * |             (0 - N)             |
420*c68cfb71SSrinivas Kandagatla  * +---------------------------------+
421*c68cfb71SSrinivas Kandagatla  * |         Invoke Buffer list      |
422*c68cfb71SSrinivas Kandagatla  * | type:(struct fastrpc_invoke_buf)|
423*c68cfb71SSrinivas Kandagatla  * |           (0 - N)               |
424*c68cfb71SSrinivas Kandagatla  * +---------------------------------+
425*c68cfb71SSrinivas Kandagatla  * |         Page info list          |
426*c68cfb71SSrinivas Kandagatla  * | type:(struct fastrpc_phy_page)  |
427*c68cfb71SSrinivas Kandagatla  * |             (0 - N)             |
428*c68cfb71SSrinivas Kandagatla  * +---------------------------------+
429*c68cfb71SSrinivas Kandagatla  * |         Optional info           |
430*c68cfb71SSrinivas Kandagatla  * |(can be specific to SoC/Firmware)|
431*c68cfb71SSrinivas Kandagatla  * +---------------------------------+
432*c68cfb71SSrinivas Kandagatla  * >>>>>>>>  END of METADATA <<<<<<<<<
433*c68cfb71SSrinivas Kandagatla  * +---------------------------------+
434*c68cfb71SSrinivas Kandagatla  * |         Inline ARGS             |
435*c68cfb71SSrinivas Kandagatla  * |            (0-N)                |
436*c68cfb71SSrinivas Kandagatla  * +---------------------------------+
437*c68cfb71SSrinivas Kandagatla  */
438*c68cfb71SSrinivas Kandagatla 
439*c68cfb71SSrinivas Kandagatla static int fastrpc_get_meta_size(struct fastrpc_invoke_ctx *ctx)
440*c68cfb71SSrinivas Kandagatla {
441*c68cfb71SSrinivas Kandagatla 	int size = 0;
442*c68cfb71SSrinivas Kandagatla 
443*c68cfb71SSrinivas Kandagatla 	size = (sizeof(struct fastrpc_remote_arg) +
444*c68cfb71SSrinivas Kandagatla 		sizeof(struct fastrpc_invoke_buf) +
445*c68cfb71SSrinivas Kandagatla 		sizeof(struct fastrpc_phy_page)) * ctx->nscalars +
446*c68cfb71SSrinivas Kandagatla 		sizeof(u64) * FASTRPC_MAX_FDLIST +
447*c68cfb71SSrinivas Kandagatla 		sizeof(u32) * FASTRPC_MAX_CRCLIST;
448*c68cfb71SSrinivas Kandagatla 
449*c68cfb71SSrinivas Kandagatla 	return size;
450*c68cfb71SSrinivas Kandagatla }
451*c68cfb71SSrinivas Kandagatla 
452*c68cfb71SSrinivas Kandagatla static u64 fastrpc_get_payload_size(struct fastrpc_invoke_ctx *ctx, int metalen)
453*c68cfb71SSrinivas Kandagatla {
454*c68cfb71SSrinivas Kandagatla 	u64 size = 0;
455*c68cfb71SSrinivas Kandagatla 	int i;
456*c68cfb71SSrinivas Kandagatla 
457*c68cfb71SSrinivas Kandagatla 	size = ALIGN(metalen, FASTRPC_ALIGN);
458*c68cfb71SSrinivas Kandagatla 	for (i = 0; i < ctx->nscalars; i++) {
459*c68cfb71SSrinivas Kandagatla 		if (ctx->args[i].fd == 0 || ctx->args[i].fd == -1) {
460*c68cfb71SSrinivas Kandagatla 			size = ALIGN(size, FASTRPC_ALIGN);
461*c68cfb71SSrinivas Kandagatla 			size += ctx->args[i].length;
462*c68cfb71SSrinivas Kandagatla 		}
463*c68cfb71SSrinivas Kandagatla 	}
464*c68cfb71SSrinivas Kandagatla 
465*c68cfb71SSrinivas Kandagatla 	return size;
466*c68cfb71SSrinivas Kandagatla }
467*c68cfb71SSrinivas Kandagatla 
468*c68cfb71SSrinivas Kandagatla static int fastrpc_create_maps(struct fastrpc_invoke_ctx *ctx)
469*c68cfb71SSrinivas Kandagatla {
470*c68cfb71SSrinivas Kandagatla 	struct device *dev = ctx->fl->sctx->dev;
471*c68cfb71SSrinivas Kandagatla 	int i, err;
472*c68cfb71SSrinivas Kandagatla 
473*c68cfb71SSrinivas Kandagatla 	for (i = 0; i < ctx->nscalars; ++i) {
474*c68cfb71SSrinivas Kandagatla 		/* Make sure reserved field is set to 0 */
475*c68cfb71SSrinivas Kandagatla 		if (ctx->args[i].reserved)
476*c68cfb71SSrinivas Kandagatla 			return -EINVAL;
477*c68cfb71SSrinivas Kandagatla 
478*c68cfb71SSrinivas Kandagatla 		if (ctx->args[i].fd == 0 || ctx->args[i].fd == -1 ||
479*c68cfb71SSrinivas Kandagatla 		    ctx->args[i].length == 0)
480*c68cfb71SSrinivas Kandagatla 			continue;
481*c68cfb71SSrinivas Kandagatla 
482*c68cfb71SSrinivas Kandagatla 		err = fastrpc_map_create(ctx->fl, ctx->args[i].fd,
483*c68cfb71SSrinivas Kandagatla 					 ctx->args[i].length, &ctx->maps[i]);
484*c68cfb71SSrinivas Kandagatla 		if (err) {
485*c68cfb71SSrinivas Kandagatla 			dev_err(dev, "Error Creating map %d\n", err);
486*c68cfb71SSrinivas Kandagatla 			return -EINVAL;
487*c68cfb71SSrinivas Kandagatla 		}
488*c68cfb71SSrinivas Kandagatla 
489*c68cfb71SSrinivas Kandagatla 	}
490*c68cfb71SSrinivas Kandagatla 	return 0;
491*c68cfb71SSrinivas Kandagatla }
492*c68cfb71SSrinivas Kandagatla 
493*c68cfb71SSrinivas Kandagatla static int fastrpc_get_args(u32 kernel, struct fastrpc_invoke_ctx *ctx)
494*c68cfb71SSrinivas Kandagatla {
495*c68cfb71SSrinivas Kandagatla 	struct device *dev = ctx->fl->sctx->dev;
496*c68cfb71SSrinivas Kandagatla 	struct fastrpc_remote_arg *rpra;
497*c68cfb71SSrinivas Kandagatla 	struct fastrpc_invoke_buf *list;
498*c68cfb71SSrinivas Kandagatla 	struct fastrpc_phy_page *pages;
499*c68cfb71SSrinivas Kandagatla 	int inbufs, i, err = 0;
500*c68cfb71SSrinivas Kandagatla 	u64 rlen, pkt_size;
501*c68cfb71SSrinivas Kandagatla 	uintptr_t args;
502*c68cfb71SSrinivas Kandagatla 	int metalen;
503*c68cfb71SSrinivas Kandagatla 
504*c68cfb71SSrinivas Kandagatla 
505*c68cfb71SSrinivas Kandagatla 	inbufs = REMOTE_SCALARS_INBUFS(ctx->sc);
506*c68cfb71SSrinivas Kandagatla 	metalen = fastrpc_get_meta_size(ctx);
507*c68cfb71SSrinivas Kandagatla 	pkt_size = fastrpc_get_payload_size(ctx, metalen);
508*c68cfb71SSrinivas Kandagatla 
509*c68cfb71SSrinivas Kandagatla 	err = fastrpc_create_maps(ctx);
510*c68cfb71SSrinivas Kandagatla 	if (err)
511*c68cfb71SSrinivas Kandagatla 		return err;
512*c68cfb71SSrinivas Kandagatla 
513*c68cfb71SSrinivas Kandagatla 	ctx->msg_sz = pkt_size;
514*c68cfb71SSrinivas Kandagatla 
515*c68cfb71SSrinivas Kandagatla 	err = fastrpc_buf_alloc(ctx->fl, dev, pkt_size, &ctx->buf);
516*c68cfb71SSrinivas Kandagatla 	if (err)
517*c68cfb71SSrinivas Kandagatla 		return err;
518*c68cfb71SSrinivas Kandagatla 
519*c68cfb71SSrinivas Kandagatla 	rpra = ctx->buf->virt;
520*c68cfb71SSrinivas Kandagatla 	list = ctx->buf->virt + ctx->nscalars * sizeof(*rpra);
521*c68cfb71SSrinivas Kandagatla 	pages = ctx->buf->virt + ctx->nscalars * (sizeof(*list) +
522*c68cfb71SSrinivas Kandagatla 		sizeof(*rpra));
523*c68cfb71SSrinivas Kandagatla 	args = (uintptr_t)ctx->buf->virt + metalen;
524*c68cfb71SSrinivas Kandagatla 	rlen = pkt_size - metalen;
525*c68cfb71SSrinivas Kandagatla 	ctx->rpra = rpra;
526*c68cfb71SSrinivas Kandagatla 
527*c68cfb71SSrinivas Kandagatla 	for (i = 0; i < ctx->nbufs; ++i) {
528*c68cfb71SSrinivas Kandagatla 		u64 len = ctx->args[i].length;
529*c68cfb71SSrinivas Kandagatla 
530*c68cfb71SSrinivas Kandagatla 		rpra[i].pv = 0;
531*c68cfb71SSrinivas Kandagatla 		rpra[i].len = len;
532*c68cfb71SSrinivas Kandagatla 		list[i].num = len ? 1 : 0;
533*c68cfb71SSrinivas Kandagatla 		list[i].pgidx = i;
534*c68cfb71SSrinivas Kandagatla 
535*c68cfb71SSrinivas Kandagatla 		if (!len)
536*c68cfb71SSrinivas Kandagatla 			continue;
537*c68cfb71SSrinivas Kandagatla 
538*c68cfb71SSrinivas Kandagatla 		pages[i].size = roundup(len, PAGE_SIZE);
539*c68cfb71SSrinivas Kandagatla 
540*c68cfb71SSrinivas Kandagatla 		if (ctx->maps[i]) {
541*c68cfb71SSrinivas Kandagatla 			rpra[i].pv = (u64) ctx->args[i].ptr;
542*c68cfb71SSrinivas Kandagatla 			pages[i].addr = ctx->maps[i]->phys;
543*c68cfb71SSrinivas Kandagatla 		} else {
544*c68cfb71SSrinivas Kandagatla 			rlen -= ALIGN(args, FASTRPC_ALIGN) - args;
545*c68cfb71SSrinivas Kandagatla 			args = ALIGN(args, FASTRPC_ALIGN);
546*c68cfb71SSrinivas Kandagatla 			if (rlen < len)
547*c68cfb71SSrinivas Kandagatla 				goto bail;
548*c68cfb71SSrinivas Kandagatla 
549*c68cfb71SSrinivas Kandagatla 			rpra[i].pv = args;
550*c68cfb71SSrinivas Kandagatla 			pages[i].addr = ctx->buf->phys + (pkt_size - rlen);
551*c68cfb71SSrinivas Kandagatla 			pages[i].addr = pages[i].addr &	PAGE_MASK;
552*c68cfb71SSrinivas Kandagatla 			args = args + len;
553*c68cfb71SSrinivas Kandagatla 			rlen -= len;
554*c68cfb71SSrinivas Kandagatla 		}
555*c68cfb71SSrinivas Kandagatla 
556*c68cfb71SSrinivas Kandagatla 		if (i < inbufs && !ctx->maps[i]) {
557*c68cfb71SSrinivas Kandagatla 			void *dst = (void *)(uintptr_t)rpra[i].pv;
558*c68cfb71SSrinivas Kandagatla 			void *src = (void *)(uintptr_t)ctx->args[i].ptr;
559*c68cfb71SSrinivas Kandagatla 
560*c68cfb71SSrinivas Kandagatla 			if (!kernel) {
561*c68cfb71SSrinivas Kandagatla 				if (copy_from_user(dst, (void __user *)src,
562*c68cfb71SSrinivas Kandagatla 						   len)) {
563*c68cfb71SSrinivas Kandagatla 					err = -EFAULT;
564*c68cfb71SSrinivas Kandagatla 					goto bail;
565*c68cfb71SSrinivas Kandagatla 				}
566*c68cfb71SSrinivas Kandagatla 			} else {
567*c68cfb71SSrinivas Kandagatla 				memcpy(dst, src, len);
568*c68cfb71SSrinivas Kandagatla 			}
569*c68cfb71SSrinivas Kandagatla 		}
570*c68cfb71SSrinivas Kandagatla 	}
571*c68cfb71SSrinivas Kandagatla 
572*c68cfb71SSrinivas Kandagatla 	for (i = ctx->nbufs; i < ctx->nscalars; ++i) {
573*c68cfb71SSrinivas Kandagatla 		rpra[i].pv = (u64) ctx->args[i].ptr;
574*c68cfb71SSrinivas Kandagatla 		rpra[i].len = ctx->args[i].length;
575*c68cfb71SSrinivas Kandagatla 		list[i].num = ctx->args[i].length ? 1 : 0;
576*c68cfb71SSrinivas Kandagatla 		list[i].pgidx = i;
577*c68cfb71SSrinivas Kandagatla 		pages[i].addr = ctx->maps[i]->phys;
578*c68cfb71SSrinivas Kandagatla 		pages[i].size = ctx->maps[i]->size;
579*c68cfb71SSrinivas Kandagatla 	}
580*c68cfb71SSrinivas Kandagatla 
581*c68cfb71SSrinivas Kandagatla bail:
582*c68cfb71SSrinivas Kandagatla 	if (err)
583*c68cfb71SSrinivas Kandagatla 		dev_err(dev, "Error: get invoke args failed:%d\n", err);
584*c68cfb71SSrinivas Kandagatla 
585*c68cfb71SSrinivas Kandagatla 	return err;
586*c68cfb71SSrinivas Kandagatla }
587*c68cfb71SSrinivas Kandagatla 
588*c68cfb71SSrinivas Kandagatla static int fastrpc_put_args(struct fastrpc_invoke_ctx *ctx,
589*c68cfb71SSrinivas Kandagatla 			    u32 kernel)
590*c68cfb71SSrinivas Kandagatla {
591*c68cfb71SSrinivas Kandagatla 	struct fastrpc_remote_arg *rpra = ctx->rpra;
592*c68cfb71SSrinivas Kandagatla 	int i, inbufs;
593*c68cfb71SSrinivas Kandagatla 
594*c68cfb71SSrinivas Kandagatla 	inbufs = REMOTE_SCALARS_INBUFS(ctx->sc);
595*c68cfb71SSrinivas Kandagatla 
596*c68cfb71SSrinivas Kandagatla 	for (i = inbufs; i < ctx->nbufs; ++i) {
597*c68cfb71SSrinivas Kandagatla 		void *src = (void *)(uintptr_t)rpra[i].pv;
598*c68cfb71SSrinivas Kandagatla 		void *dst = (void *)(uintptr_t)ctx->args[i].ptr;
599*c68cfb71SSrinivas Kandagatla 		u64 len = rpra[i].len;
600*c68cfb71SSrinivas Kandagatla 
601*c68cfb71SSrinivas Kandagatla 		if (!kernel) {
602*c68cfb71SSrinivas Kandagatla 			if (copy_to_user((void __user *)dst, src, len))
603*c68cfb71SSrinivas Kandagatla 				return -EFAULT;
604*c68cfb71SSrinivas Kandagatla 		} else {
605*c68cfb71SSrinivas Kandagatla 			memcpy(dst, src, len);
606*c68cfb71SSrinivas Kandagatla 		}
607*c68cfb71SSrinivas Kandagatla 	}
608*c68cfb71SSrinivas Kandagatla 
609*c68cfb71SSrinivas Kandagatla 	return 0;
610*c68cfb71SSrinivas Kandagatla }
611*c68cfb71SSrinivas Kandagatla 
612*c68cfb71SSrinivas Kandagatla static int fastrpc_invoke_send(struct fastrpc_session_ctx *sctx,
613*c68cfb71SSrinivas Kandagatla 			       struct fastrpc_invoke_ctx *ctx,
614*c68cfb71SSrinivas Kandagatla 			       u32 kernel, uint32_t handle)
615*c68cfb71SSrinivas Kandagatla {
616*c68cfb71SSrinivas Kandagatla 	struct fastrpc_channel_ctx *cctx;
617*c68cfb71SSrinivas Kandagatla 	struct fastrpc_user *fl = ctx->fl;
618*c68cfb71SSrinivas Kandagatla 	struct fastrpc_msg *msg = &ctx->msg;
619*c68cfb71SSrinivas Kandagatla 
620*c68cfb71SSrinivas Kandagatla 	cctx = fl->cctx;
621*c68cfb71SSrinivas Kandagatla 	msg->pid = fl->tgid;
622*c68cfb71SSrinivas Kandagatla 	msg->tid = current->pid;
623*c68cfb71SSrinivas Kandagatla 
624*c68cfb71SSrinivas Kandagatla 	if (kernel)
625*c68cfb71SSrinivas Kandagatla 		msg->pid = 0;
626*c68cfb71SSrinivas Kandagatla 
627*c68cfb71SSrinivas Kandagatla 	msg->ctx = ctx->ctxid | fl->pd;
628*c68cfb71SSrinivas Kandagatla 	msg->handle = handle;
629*c68cfb71SSrinivas Kandagatla 	msg->sc = ctx->sc;
630*c68cfb71SSrinivas Kandagatla 	msg->addr = ctx->buf ? ctx->buf->phys : 0;
631*c68cfb71SSrinivas Kandagatla 	msg->size = roundup(ctx->msg_sz, PAGE_SIZE);
632*c68cfb71SSrinivas Kandagatla 	fastrpc_context_get(ctx);
633*c68cfb71SSrinivas Kandagatla 
634*c68cfb71SSrinivas Kandagatla 	return rpmsg_send(cctx->rpdev->ept, (void *)msg, sizeof(*msg));
635*c68cfb71SSrinivas Kandagatla }
636*c68cfb71SSrinivas Kandagatla 
637*c68cfb71SSrinivas Kandagatla static int fastrpc_internal_invoke(struct fastrpc_user *fl,  u32 kernel,
638*c68cfb71SSrinivas Kandagatla 				   u32 handle, u32 sc,
639*c68cfb71SSrinivas Kandagatla 				   struct fastrpc_invoke_args *args)
640*c68cfb71SSrinivas Kandagatla {
641*c68cfb71SSrinivas Kandagatla 	struct fastrpc_invoke_ctx *ctx = NULL;
642*c68cfb71SSrinivas Kandagatla 	int err = 0;
643*c68cfb71SSrinivas Kandagatla 
644*c68cfb71SSrinivas Kandagatla 	if (!fl->sctx)
645*c68cfb71SSrinivas Kandagatla 		return -EINVAL;
646*c68cfb71SSrinivas Kandagatla 
647*c68cfb71SSrinivas Kandagatla 	ctx = fastrpc_context_alloc(fl, kernel, sc, args);
648*c68cfb71SSrinivas Kandagatla 	if (IS_ERR(ctx))
649*c68cfb71SSrinivas Kandagatla 		return PTR_ERR(ctx);
650*c68cfb71SSrinivas Kandagatla 
651*c68cfb71SSrinivas Kandagatla 	if (ctx->nscalars) {
652*c68cfb71SSrinivas Kandagatla 		err = fastrpc_get_args(kernel, ctx);
653*c68cfb71SSrinivas Kandagatla 		if (err)
654*c68cfb71SSrinivas Kandagatla 			goto bail;
655*c68cfb71SSrinivas Kandagatla 	}
656*c68cfb71SSrinivas Kandagatla 	/* Send invoke buffer to remote dsp */
657*c68cfb71SSrinivas Kandagatla 	err = fastrpc_invoke_send(fl->sctx, ctx, kernel, handle);
658*c68cfb71SSrinivas Kandagatla 	if (err)
659*c68cfb71SSrinivas Kandagatla 		goto bail;
660*c68cfb71SSrinivas Kandagatla 
661*c68cfb71SSrinivas Kandagatla 	/* Wait for remote dsp to respond or time out */
662*c68cfb71SSrinivas Kandagatla 	err = wait_for_completion_interruptible(&ctx->work);
663*c68cfb71SSrinivas Kandagatla 	if (err)
664*c68cfb71SSrinivas Kandagatla 		goto bail;
665*c68cfb71SSrinivas Kandagatla 
666*c68cfb71SSrinivas Kandagatla 	/* Check the response from remote dsp */
667*c68cfb71SSrinivas Kandagatla 	err = ctx->retval;
668*c68cfb71SSrinivas Kandagatla 	if (err)
669*c68cfb71SSrinivas Kandagatla 		goto bail;
670*c68cfb71SSrinivas Kandagatla 
671*c68cfb71SSrinivas Kandagatla 	if (ctx->nscalars) {
672*c68cfb71SSrinivas Kandagatla 		/* populate all the output buffers with results */
673*c68cfb71SSrinivas Kandagatla 		err = fastrpc_put_args(ctx, kernel);
674*c68cfb71SSrinivas Kandagatla 		if (err)
675*c68cfb71SSrinivas Kandagatla 			goto bail;
676*c68cfb71SSrinivas Kandagatla 	}
677*c68cfb71SSrinivas Kandagatla 
678*c68cfb71SSrinivas Kandagatla bail:
679*c68cfb71SSrinivas Kandagatla 	/* We are done with this compute context, remove it from pending list */
680*c68cfb71SSrinivas Kandagatla 	spin_lock(&fl->lock);
681*c68cfb71SSrinivas Kandagatla 	list_del(&ctx->node);
682*c68cfb71SSrinivas Kandagatla 	spin_unlock(&fl->lock);
683*c68cfb71SSrinivas Kandagatla 	fastrpc_context_put(ctx);
684*c68cfb71SSrinivas Kandagatla 
685*c68cfb71SSrinivas Kandagatla 	if (err)
686*c68cfb71SSrinivas Kandagatla 		dev_dbg(fl->sctx->dev, "Error: Invoke Failed %d\n", err);
687*c68cfb71SSrinivas Kandagatla 
688*c68cfb71SSrinivas Kandagatla 	return err;
689*c68cfb71SSrinivas Kandagatla }
690*c68cfb71SSrinivas Kandagatla 
691f6f9279fSSrinivas Kandagatla static struct fastrpc_session_ctx *fastrpc_session_alloc(
692f6f9279fSSrinivas Kandagatla 					struct fastrpc_channel_ctx *cctx)
693f6f9279fSSrinivas Kandagatla {
694f6f9279fSSrinivas Kandagatla 	struct fastrpc_session_ctx *session = NULL;
695f6f9279fSSrinivas Kandagatla 	int i;
696f6f9279fSSrinivas Kandagatla 
697f6f9279fSSrinivas Kandagatla 	spin_lock(&cctx->lock);
698f6f9279fSSrinivas Kandagatla 	for (i = 0; i < cctx->sesscount; i++) {
699f6f9279fSSrinivas Kandagatla 		if (!cctx->session[i].used && cctx->session[i].valid) {
700f6f9279fSSrinivas Kandagatla 			cctx->session[i].used = true;
701f6f9279fSSrinivas Kandagatla 			session = &cctx->session[i];
702f6f9279fSSrinivas Kandagatla 			break;
703f6f9279fSSrinivas Kandagatla 		}
704f6f9279fSSrinivas Kandagatla 	}
705f6f9279fSSrinivas Kandagatla 	spin_unlock(&cctx->lock);
706f6f9279fSSrinivas Kandagatla 
707f6f9279fSSrinivas Kandagatla 	return session;
708f6f9279fSSrinivas Kandagatla }
709f6f9279fSSrinivas Kandagatla 
710f6f9279fSSrinivas Kandagatla static void fastrpc_session_free(struct fastrpc_channel_ctx *cctx,
711f6f9279fSSrinivas Kandagatla 				 struct fastrpc_session_ctx *session)
712f6f9279fSSrinivas Kandagatla {
713f6f9279fSSrinivas Kandagatla 	spin_lock(&cctx->lock);
714f6f9279fSSrinivas Kandagatla 	session->used = false;
715f6f9279fSSrinivas Kandagatla 	spin_unlock(&cctx->lock);
716f6f9279fSSrinivas Kandagatla }
717f6f9279fSSrinivas Kandagatla 
718f6f9279fSSrinivas Kandagatla static int fastrpc_device_release(struct inode *inode, struct file *file)
719f6f9279fSSrinivas Kandagatla {
720f6f9279fSSrinivas Kandagatla 	struct fastrpc_user *fl = (struct fastrpc_user *)file->private_data;
721f6f9279fSSrinivas Kandagatla 	struct fastrpc_channel_ctx *cctx = fl->cctx;
722*c68cfb71SSrinivas Kandagatla 	struct fastrpc_invoke_ctx *ctx, *n;
723*c68cfb71SSrinivas Kandagatla 	struct fastrpc_map *map, *m;
724f6f9279fSSrinivas Kandagatla 
725f6f9279fSSrinivas Kandagatla 	spin_lock(&cctx->lock);
726f6f9279fSSrinivas Kandagatla 	list_del(&fl->user);
727f6f9279fSSrinivas Kandagatla 	spin_unlock(&cctx->lock);
728f6f9279fSSrinivas Kandagatla 
729*c68cfb71SSrinivas Kandagatla 	if (fl->init_mem)
730*c68cfb71SSrinivas Kandagatla 		fastrpc_buf_free(fl->init_mem);
731*c68cfb71SSrinivas Kandagatla 
732*c68cfb71SSrinivas Kandagatla 	list_for_each_entry_safe(ctx, n, &fl->pending, node) {
733*c68cfb71SSrinivas Kandagatla 		list_del(&ctx->node);
734*c68cfb71SSrinivas Kandagatla 		fastrpc_context_put(ctx);
735*c68cfb71SSrinivas Kandagatla 	}
736*c68cfb71SSrinivas Kandagatla 
737*c68cfb71SSrinivas Kandagatla 	list_for_each_entry_safe(map, m, &fl->maps, node) {
738*c68cfb71SSrinivas Kandagatla 		list_del(&map->node);
739*c68cfb71SSrinivas Kandagatla 		fastrpc_map_put(map);
740*c68cfb71SSrinivas Kandagatla 	}
741*c68cfb71SSrinivas Kandagatla 
742f6f9279fSSrinivas Kandagatla 	fastrpc_session_free(cctx, fl->sctx);
743f6f9279fSSrinivas Kandagatla 
744f6f9279fSSrinivas Kandagatla 	mutex_destroy(&fl->mutex);
745f6f9279fSSrinivas Kandagatla 	kfree(fl);
746f6f9279fSSrinivas Kandagatla 	file->private_data = NULL;
747f6f9279fSSrinivas Kandagatla 
748f6f9279fSSrinivas Kandagatla 	return 0;
749f6f9279fSSrinivas Kandagatla }
750f6f9279fSSrinivas Kandagatla 
751f6f9279fSSrinivas Kandagatla static int fastrpc_device_open(struct inode *inode, struct file *filp)
752f6f9279fSSrinivas Kandagatla {
753f6f9279fSSrinivas Kandagatla 	struct fastrpc_channel_ctx *cctx = miscdev_to_cctx(filp->private_data);
754f6f9279fSSrinivas Kandagatla 	struct fastrpc_user *fl = NULL;
755f6f9279fSSrinivas Kandagatla 
756f6f9279fSSrinivas Kandagatla 	fl = kzalloc(sizeof(*fl), GFP_KERNEL);
757f6f9279fSSrinivas Kandagatla 	if (!fl)
758f6f9279fSSrinivas Kandagatla 		return -ENOMEM;
759f6f9279fSSrinivas Kandagatla 
760f6f9279fSSrinivas Kandagatla 	filp->private_data = fl;
761f6f9279fSSrinivas Kandagatla 	spin_lock_init(&fl->lock);
762f6f9279fSSrinivas Kandagatla 	mutex_init(&fl->mutex);
763f6f9279fSSrinivas Kandagatla 	INIT_LIST_HEAD(&fl->pending);
764f6f9279fSSrinivas Kandagatla 	INIT_LIST_HEAD(&fl->maps);
765f6f9279fSSrinivas Kandagatla 	INIT_LIST_HEAD(&fl->user);
766f6f9279fSSrinivas Kandagatla 	fl->tgid = current->tgid;
767f6f9279fSSrinivas Kandagatla 	fl->cctx = cctx;
768f6f9279fSSrinivas Kandagatla 	spin_lock(&cctx->lock);
769f6f9279fSSrinivas Kandagatla 	list_add_tail(&fl->user, &cctx->users);
770f6f9279fSSrinivas Kandagatla 	spin_unlock(&cctx->lock);
771f6f9279fSSrinivas Kandagatla 	fl->sctx = fastrpc_session_alloc(cctx);
772f6f9279fSSrinivas Kandagatla 
773f6f9279fSSrinivas Kandagatla 	return 0;
774f6f9279fSSrinivas Kandagatla }
775f6f9279fSSrinivas Kandagatla 
776*c68cfb71SSrinivas Kandagatla static int fastrpc_invoke(struct fastrpc_user *fl, char __user *argp)
777*c68cfb71SSrinivas Kandagatla {
778*c68cfb71SSrinivas Kandagatla 	struct fastrpc_invoke_args *args = NULL;
779*c68cfb71SSrinivas Kandagatla 	struct fastrpc_invoke inv;
780*c68cfb71SSrinivas Kandagatla 	u32 nscalars;
781*c68cfb71SSrinivas Kandagatla 	int err;
782*c68cfb71SSrinivas Kandagatla 
783*c68cfb71SSrinivas Kandagatla 	if (copy_from_user(&inv, argp, sizeof(inv)))
784*c68cfb71SSrinivas Kandagatla 		return -EFAULT;
785*c68cfb71SSrinivas Kandagatla 
786*c68cfb71SSrinivas Kandagatla 	/* nscalars is truncated here to max supported value */
787*c68cfb71SSrinivas Kandagatla 	nscalars = REMOTE_SCALARS_LENGTH(inv.sc);
788*c68cfb71SSrinivas Kandagatla 	if (nscalars) {
789*c68cfb71SSrinivas Kandagatla 		args = kcalloc(nscalars, sizeof(*args), GFP_KERNEL);
790*c68cfb71SSrinivas Kandagatla 		if (!args)
791*c68cfb71SSrinivas Kandagatla 			return -ENOMEM;
792*c68cfb71SSrinivas Kandagatla 
793*c68cfb71SSrinivas Kandagatla 		if (copy_from_user(args, (void __user *)(uintptr_t)inv.args,
794*c68cfb71SSrinivas Kandagatla 				   nscalars * sizeof(*args))) {
795*c68cfb71SSrinivas Kandagatla 			kfree(args);
796*c68cfb71SSrinivas Kandagatla 			return -EFAULT;
797*c68cfb71SSrinivas Kandagatla 		}
798*c68cfb71SSrinivas Kandagatla 	}
799*c68cfb71SSrinivas Kandagatla 
800*c68cfb71SSrinivas Kandagatla 	err = fastrpc_internal_invoke(fl, false, inv.handle, inv.sc, args);
801*c68cfb71SSrinivas Kandagatla 	kfree(args);
802*c68cfb71SSrinivas Kandagatla 
803*c68cfb71SSrinivas Kandagatla 	return err;
804*c68cfb71SSrinivas Kandagatla }
805*c68cfb71SSrinivas Kandagatla 
806*c68cfb71SSrinivas Kandagatla static long fastrpc_device_ioctl(struct file *file, unsigned int cmd,
807*c68cfb71SSrinivas Kandagatla 				 unsigned long arg)
808*c68cfb71SSrinivas Kandagatla {
809*c68cfb71SSrinivas Kandagatla 	struct fastrpc_user *fl = (struct fastrpc_user *)file->private_data;
810*c68cfb71SSrinivas Kandagatla 	char __user *argp = (char __user *)arg;
811*c68cfb71SSrinivas Kandagatla 	int err;
812*c68cfb71SSrinivas Kandagatla 
813*c68cfb71SSrinivas Kandagatla 	switch (cmd) {
814*c68cfb71SSrinivas Kandagatla 	case FASTRPC_IOCTL_INVOKE:
815*c68cfb71SSrinivas Kandagatla 		err = fastrpc_invoke(fl, argp);
816*c68cfb71SSrinivas Kandagatla 		break;
817*c68cfb71SSrinivas Kandagatla 	default:
818*c68cfb71SSrinivas Kandagatla 		err = -ENOTTY;
819*c68cfb71SSrinivas Kandagatla 		break;
820*c68cfb71SSrinivas Kandagatla 	}
821*c68cfb71SSrinivas Kandagatla 
822*c68cfb71SSrinivas Kandagatla 	return err;
823*c68cfb71SSrinivas Kandagatla }
824*c68cfb71SSrinivas Kandagatla 
825f6f9279fSSrinivas Kandagatla static const struct file_operations fastrpc_fops = {
826f6f9279fSSrinivas Kandagatla 	.open = fastrpc_device_open,
827f6f9279fSSrinivas Kandagatla 	.release = fastrpc_device_release,
828*c68cfb71SSrinivas Kandagatla 	.unlocked_ioctl = fastrpc_device_ioctl,
829*c68cfb71SSrinivas Kandagatla 	.compat_ioctl = fastrpc_device_ioctl,
830f6f9279fSSrinivas Kandagatla };
831f6f9279fSSrinivas Kandagatla 
832f6f9279fSSrinivas Kandagatla static int fastrpc_cb_probe(struct platform_device *pdev)
833f6f9279fSSrinivas Kandagatla {
834f6f9279fSSrinivas Kandagatla 	struct fastrpc_channel_ctx *cctx;
835f6f9279fSSrinivas Kandagatla 	struct fastrpc_session_ctx *sess;
836f6f9279fSSrinivas Kandagatla 	struct device *dev = &pdev->dev;
837f6f9279fSSrinivas Kandagatla 	int i, sessions = 0;
838f6f9279fSSrinivas Kandagatla 
839f6f9279fSSrinivas Kandagatla 	cctx = dev_get_drvdata(dev->parent);
840f6f9279fSSrinivas Kandagatla 	if (!cctx)
841f6f9279fSSrinivas Kandagatla 		return -EINVAL;
842f6f9279fSSrinivas Kandagatla 
843f6f9279fSSrinivas Kandagatla 	of_property_read_u32(dev->of_node, "qcom,nsessions", &sessions);
844f6f9279fSSrinivas Kandagatla 
845f6f9279fSSrinivas Kandagatla 	spin_lock(&cctx->lock);
846f6f9279fSSrinivas Kandagatla 	sess = &cctx->session[cctx->sesscount];
847f6f9279fSSrinivas Kandagatla 	sess->used = false;
848f6f9279fSSrinivas Kandagatla 	sess->valid = true;
849f6f9279fSSrinivas Kandagatla 	sess->dev = dev;
850f6f9279fSSrinivas Kandagatla 	dev_set_drvdata(dev, sess);
851f6f9279fSSrinivas Kandagatla 
852f6f9279fSSrinivas Kandagatla 	if (of_property_read_u32(dev->of_node, "reg", &sess->sid))
853f6f9279fSSrinivas Kandagatla 		dev_info(dev, "FastRPC Session ID not specified in DT\n");
854f6f9279fSSrinivas Kandagatla 
855f6f9279fSSrinivas Kandagatla 	if (sessions > 0) {
856f6f9279fSSrinivas Kandagatla 		struct fastrpc_session_ctx *dup_sess;
857f6f9279fSSrinivas Kandagatla 
858f6f9279fSSrinivas Kandagatla 		for (i = 1; i < sessions; i++) {
859f6f9279fSSrinivas Kandagatla 			if (cctx->sesscount++ >= FASTRPC_MAX_SESSIONS)
860f6f9279fSSrinivas Kandagatla 				break;
861f6f9279fSSrinivas Kandagatla 			dup_sess = &cctx->session[cctx->sesscount];
862f6f9279fSSrinivas Kandagatla 			memcpy(dup_sess, sess, sizeof(*dup_sess));
863f6f9279fSSrinivas Kandagatla 		}
864f6f9279fSSrinivas Kandagatla 	}
865f6f9279fSSrinivas Kandagatla 	cctx->sesscount++;
866f6f9279fSSrinivas Kandagatla 	spin_unlock(&cctx->lock);
867f6f9279fSSrinivas Kandagatla 	dma_set_mask(dev, DMA_BIT_MASK(32));
868f6f9279fSSrinivas Kandagatla 
869f6f9279fSSrinivas Kandagatla 	return 0;
870f6f9279fSSrinivas Kandagatla }
871f6f9279fSSrinivas Kandagatla 
872f6f9279fSSrinivas Kandagatla static int fastrpc_cb_remove(struct platform_device *pdev)
873f6f9279fSSrinivas Kandagatla {
874f6f9279fSSrinivas Kandagatla 	struct fastrpc_channel_ctx *cctx = dev_get_drvdata(pdev->dev.parent);
875f6f9279fSSrinivas Kandagatla 	struct fastrpc_session_ctx *sess = dev_get_drvdata(&pdev->dev);
876f6f9279fSSrinivas Kandagatla 	int i;
877f6f9279fSSrinivas Kandagatla 
878f6f9279fSSrinivas Kandagatla 	spin_lock(&cctx->lock);
879f6f9279fSSrinivas Kandagatla 	for (i = 1; i < FASTRPC_MAX_SESSIONS; i++) {
880f6f9279fSSrinivas Kandagatla 		if (cctx->session[i].sid == sess->sid) {
881f6f9279fSSrinivas Kandagatla 			cctx->session[i].valid = false;
882f6f9279fSSrinivas Kandagatla 			cctx->sesscount--;
883f6f9279fSSrinivas Kandagatla 		}
884f6f9279fSSrinivas Kandagatla 	}
885f6f9279fSSrinivas Kandagatla 	spin_unlock(&cctx->lock);
886f6f9279fSSrinivas Kandagatla 
887f6f9279fSSrinivas Kandagatla 	return 0;
888f6f9279fSSrinivas Kandagatla }
889f6f9279fSSrinivas Kandagatla 
890f6f9279fSSrinivas Kandagatla static const struct of_device_id fastrpc_match_table[] = {
891f6f9279fSSrinivas Kandagatla 	{ .compatible = "qcom,fastrpc-compute-cb", },
892f6f9279fSSrinivas Kandagatla 	{}
893f6f9279fSSrinivas Kandagatla };
894f6f9279fSSrinivas Kandagatla 
895f6f9279fSSrinivas Kandagatla static struct platform_driver fastrpc_cb_driver = {
896f6f9279fSSrinivas Kandagatla 	.probe = fastrpc_cb_probe,
897f6f9279fSSrinivas Kandagatla 	.remove = fastrpc_cb_remove,
898f6f9279fSSrinivas Kandagatla 	.driver = {
899f6f9279fSSrinivas Kandagatla 		.name = "qcom,fastrpc-cb",
900f6f9279fSSrinivas Kandagatla 		.of_match_table = fastrpc_match_table,
901f6f9279fSSrinivas Kandagatla 		.suppress_bind_attrs = true,
902f6f9279fSSrinivas Kandagatla 	},
903f6f9279fSSrinivas Kandagatla };
904f6f9279fSSrinivas Kandagatla 
905f6f9279fSSrinivas Kandagatla static int fastrpc_rpmsg_probe(struct rpmsg_device *rpdev)
906f6f9279fSSrinivas Kandagatla {
907f6f9279fSSrinivas Kandagatla 	struct device *rdev = &rpdev->dev;
908f6f9279fSSrinivas Kandagatla 	struct fastrpc_channel_ctx *data;
909f6f9279fSSrinivas Kandagatla 	int i, err, domain_id = -1;
910f6f9279fSSrinivas Kandagatla 	const char *domain;
911f6f9279fSSrinivas Kandagatla 
912f6f9279fSSrinivas Kandagatla 	data = devm_kzalloc(rdev, sizeof(*data), GFP_KERNEL);
913f6f9279fSSrinivas Kandagatla 	if (!data)
914f6f9279fSSrinivas Kandagatla 		return -ENOMEM;
915f6f9279fSSrinivas Kandagatla 
916f6f9279fSSrinivas Kandagatla 	err = of_property_read_string(rdev->of_node, "label", &domain);
917f6f9279fSSrinivas Kandagatla 	if (err) {
918f6f9279fSSrinivas Kandagatla 		dev_info(rdev, "FastRPC Domain not specified in DT\n");
919f6f9279fSSrinivas Kandagatla 		return err;
920f6f9279fSSrinivas Kandagatla 	}
921f6f9279fSSrinivas Kandagatla 
922f6f9279fSSrinivas Kandagatla 	for (i = 0; i <= CDSP_DOMAIN_ID; i++) {
923f6f9279fSSrinivas Kandagatla 		if (!strcmp(domains[i], domain)) {
924f6f9279fSSrinivas Kandagatla 			domain_id = i;
925f6f9279fSSrinivas Kandagatla 			break;
926f6f9279fSSrinivas Kandagatla 		}
927f6f9279fSSrinivas Kandagatla 	}
928f6f9279fSSrinivas Kandagatla 
929f6f9279fSSrinivas Kandagatla 	if (domain_id < 0) {
930f6f9279fSSrinivas Kandagatla 		dev_info(rdev, "FastRPC Invalid Domain ID %d\n", domain_id);
931f6f9279fSSrinivas Kandagatla 		return -EINVAL;
932f6f9279fSSrinivas Kandagatla 	}
933f6f9279fSSrinivas Kandagatla 
934f6f9279fSSrinivas Kandagatla 	data->miscdev.minor = MISC_DYNAMIC_MINOR;
935f6f9279fSSrinivas Kandagatla 	data->miscdev.name = kasprintf(GFP_KERNEL, "fastrpc-%s",
936f6f9279fSSrinivas Kandagatla 				domains[domain_id]);
937f6f9279fSSrinivas Kandagatla 	data->miscdev.fops = &fastrpc_fops;
938f6f9279fSSrinivas Kandagatla 	err = misc_register(&data->miscdev);
939f6f9279fSSrinivas Kandagatla 	if (err)
940f6f9279fSSrinivas Kandagatla 		return err;
941f6f9279fSSrinivas Kandagatla 
942f6f9279fSSrinivas Kandagatla 	dev_set_drvdata(&rpdev->dev, data);
943f6f9279fSSrinivas Kandagatla 	dma_set_mask_and_coherent(rdev, DMA_BIT_MASK(32));
944f6f9279fSSrinivas Kandagatla 	INIT_LIST_HEAD(&data->users);
945f6f9279fSSrinivas Kandagatla 	spin_lock_init(&data->lock);
946f6f9279fSSrinivas Kandagatla 	idr_init(&data->ctx_idr);
947f6f9279fSSrinivas Kandagatla 	data->domain_id = domain_id;
948f6f9279fSSrinivas Kandagatla 	data->rpdev = rpdev;
949f6f9279fSSrinivas Kandagatla 
950f6f9279fSSrinivas Kandagatla 	return of_platform_populate(rdev->of_node, NULL, NULL, rdev);
951f6f9279fSSrinivas Kandagatla }
952f6f9279fSSrinivas Kandagatla 
953*c68cfb71SSrinivas Kandagatla static void fastrpc_notify_users(struct fastrpc_user *user)
954*c68cfb71SSrinivas Kandagatla {
955*c68cfb71SSrinivas Kandagatla 	struct fastrpc_invoke_ctx *ctx;
956*c68cfb71SSrinivas Kandagatla 
957*c68cfb71SSrinivas Kandagatla 	spin_lock(&user->lock);
958*c68cfb71SSrinivas Kandagatla 	list_for_each_entry(ctx, &user->pending, node)
959*c68cfb71SSrinivas Kandagatla 		complete(&ctx->work);
960*c68cfb71SSrinivas Kandagatla 	spin_unlock(&user->lock);
961*c68cfb71SSrinivas Kandagatla }
962*c68cfb71SSrinivas Kandagatla 
963f6f9279fSSrinivas Kandagatla static void fastrpc_rpmsg_remove(struct rpmsg_device *rpdev)
964f6f9279fSSrinivas Kandagatla {
965f6f9279fSSrinivas Kandagatla 	struct fastrpc_channel_ctx *cctx = dev_get_drvdata(&rpdev->dev);
966*c68cfb71SSrinivas Kandagatla 	struct fastrpc_user *user;
967*c68cfb71SSrinivas Kandagatla 
968*c68cfb71SSrinivas Kandagatla 	spin_lock(&cctx->lock);
969*c68cfb71SSrinivas Kandagatla 	list_for_each_entry(user, &cctx->users, user)
970*c68cfb71SSrinivas Kandagatla 		fastrpc_notify_users(user);
971*c68cfb71SSrinivas Kandagatla 	spin_unlock(&cctx->lock);
972f6f9279fSSrinivas Kandagatla 
973f6f9279fSSrinivas Kandagatla 	misc_deregister(&cctx->miscdev);
974f6f9279fSSrinivas Kandagatla 	of_platform_depopulate(&rpdev->dev);
975f6f9279fSSrinivas Kandagatla 	kfree(cctx);
976f6f9279fSSrinivas Kandagatla }
977f6f9279fSSrinivas Kandagatla 
978f6f9279fSSrinivas Kandagatla static int fastrpc_rpmsg_callback(struct rpmsg_device *rpdev, void *data,
979f6f9279fSSrinivas Kandagatla 				  int len, void *priv, u32 addr)
980f6f9279fSSrinivas Kandagatla {
981*c68cfb71SSrinivas Kandagatla 	struct fastrpc_channel_ctx *cctx = dev_get_drvdata(&rpdev->dev);
982*c68cfb71SSrinivas Kandagatla 	struct fastrpc_invoke_rsp *rsp = data;
983*c68cfb71SSrinivas Kandagatla 	struct fastrpc_invoke_ctx *ctx;
984*c68cfb71SSrinivas Kandagatla 	unsigned long flags;
985*c68cfb71SSrinivas Kandagatla 	unsigned long ctxid;
986*c68cfb71SSrinivas Kandagatla 
987*c68cfb71SSrinivas Kandagatla 	if (len < sizeof(*rsp))
988*c68cfb71SSrinivas Kandagatla 		return -EINVAL;
989*c68cfb71SSrinivas Kandagatla 
990*c68cfb71SSrinivas Kandagatla 	ctxid = ((rsp->ctx & FASTRPC_CTXID_MASK) >> 4);
991*c68cfb71SSrinivas Kandagatla 
992*c68cfb71SSrinivas Kandagatla 	spin_lock_irqsave(&cctx->lock, flags);
993*c68cfb71SSrinivas Kandagatla 	ctx = idr_find(&cctx->ctx_idr, ctxid);
994*c68cfb71SSrinivas Kandagatla 	spin_unlock_irqrestore(&cctx->lock, flags);
995*c68cfb71SSrinivas Kandagatla 
996*c68cfb71SSrinivas Kandagatla 	if (!ctx) {
997*c68cfb71SSrinivas Kandagatla 		dev_err(&rpdev->dev, "No context ID matches response\n");
998*c68cfb71SSrinivas Kandagatla 		return -ENOENT;
999*c68cfb71SSrinivas Kandagatla 	}
1000*c68cfb71SSrinivas Kandagatla 
1001*c68cfb71SSrinivas Kandagatla 	ctx->retval = rsp->retval;
1002*c68cfb71SSrinivas Kandagatla 	complete(&ctx->work);
1003*c68cfb71SSrinivas Kandagatla 	fastrpc_context_put(ctx);
1004*c68cfb71SSrinivas Kandagatla 
1005f6f9279fSSrinivas Kandagatla 	return 0;
1006f6f9279fSSrinivas Kandagatla }
1007f6f9279fSSrinivas Kandagatla 
1008f6f9279fSSrinivas Kandagatla static const struct of_device_id fastrpc_rpmsg_of_match[] = {
1009f6f9279fSSrinivas Kandagatla 	{ .compatible = "qcom,fastrpc" },
1010f6f9279fSSrinivas Kandagatla 	{ },
1011f6f9279fSSrinivas Kandagatla };
1012f6f9279fSSrinivas Kandagatla MODULE_DEVICE_TABLE(of, fastrpc_rpmsg_of_match);
1013f6f9279fSSrinivas Kandagatla 
1014f6f9279fSSrinivas Kandagatla static struct rpmsg_driver fastrpc_driver = {
1015f6f9279fSSrinivas Kandagatla 	.probe = fastrpc_rpmsg_probe,
1016f6f9279fSSrinivas Kandagatla 	.remove = fastrpc_rpmsg_remove,
1017f6f9279fSSrinivas Kandagatla 	.callback = fastrpc_rpmsg_callback,
1018f6f9279fSSrinivas Kandagatla 	.drv = {
1019f6f9279fSSrinivas Kandagatla 		.name = "qcom,fastrpc",
1020f6f9279fSSrinivas Kandagatla 		.of_match_table = fastrpc_rpmsg_of_match,
1021f6f9279fSSrinivas Kandagatla 	},
1022f6f9279fSSrinivas Kandagatla };
1023f6f9279fSSrinivas Kandagatla 
1024f6f9279fSSrinivas Kandagatla static int fastrpc_init(void)
1025f6f9279fSSrinivas Kandagatla {
1026f6f9279fSSrinivas Kandagatla 	int ret;
1027f6f9279fSSrinivas Kandagatla 
1028f6f9279fSSrinivas Kandagatla 	ret = platform_driver_register(&fastrpc_cb_driver);
1029f6f9279fSSrinivas Kandagatla 	if (ret < 0) {
1030f6f9279fSSrinivas Kandagatla 		pr_err("fastrpc: failed to register cb driver\n");
1031f6f9279fSSrinivas Kandagatla 		return ret;
1032f6f9279fSSrinivas Kandagatla 	}
1033f6f9279fSSrinivas Kandagatla 
1034f6f9279fSSrinivas Kandagatla 	ret = register_rpmsg_driver(&fastrpc_driver);
1035f6f9279fSSrinivas Kandagatla 	if (ret < 0) {
1036f6f9279fSSrinivas Kandagatla 		pr_err("fastrpc: failed to register rpmsg driver\n");
1037f6f9279fSSrinivas Kandagatla 		platform_driver_unregister(&fastrpc_cb_driver);
1038f6f9279fSSrinivas Kandagatla 		return ret;
1039f6f9279fSSrinivas Kandagatla 	}
1040f6f9279fSSrinivas Kandagatla 
1041f6f9279fSSrinivas Kandagatla 	return 0;
1042f6f9279fSSrinivas Kandagatla }
1043f6f9279fSSrinivas Kandagatla module_init(fastrpc_init);
1044f6f9279fSSrinivas Kandagatla 
1045f6f9279fSSrinivas Kandagatla static void fastrpc_exit(void)
1046f6f9279fSSrinivas Kandagatla {
1047f6f9279fSSrinivas Kandagatla 	platform_driver_unregister(&fastrpc_cb_driver);
1048f6f9279fSSrinivas Kandagatla 	unregister_rpmsg_driver(&fastrpc_driver);
1049f6f9279fSSrinivas Kandagatla }
1050f6f9279fSSrinivas Kandagatla module_exit(fastrpc_exit);
1051f6f9279fSSrinivas Kandagatla 
1052f6f9279fSSrinivas Kandagatla MODULE_LICENSE("GPL v2");
1053