1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (C) STMicroelectronics SA 2015
4 * Author: Hugues Fruchet <hugues.fruchet@st.com> for STMicroelectronics.
5 */
6
7#include <linux/rpmsg.h>
8
9#include "delta.h"
10#include "delta-ipc.h"
11#include "delta-mem.h"
12
13#define IPC_TIMEOUT 100
14#define IPC_SANITY_TAG 0xDEADBEEF
15
16enum delta_ipc_fw_command {
17	DELTA_IPC_OPEN,
18	DELTA_IPC_SET_STREAM,
19	DELTA_IPC_DECODE,
20	DELTA_IPC_CLOSE
21};
22
23#define to_rpmsg_driver(__drv) container_of(__drv, struct rpmsg_driver, drv)
24#define to_delta(__d) container_of(__d, struct delta_dev, rpmsg_driver)
25
26#define to_ctx(hdl) ((struct delta_ipc_ctx *)hdl)
27#define to_pctx(ctx) container_of(ctx, struct delta_ctx, ipc_ctx)
28
29struct delta_ipc_header_msg {
30	u32 tag;
31	void *host_hdl;
32	u32 copro_hdl;
33	u32 command;
34};
35
36#define to_host_hdl(ctx) ((void *)ctx)
37
38#define msg_to_ctx(msg) ((struct delta_ipc_ctx *)(msg)->header.host_hdl)
39#define msg_to_copro_hdl(msg) ((msg)->header.copro_hdl)
40
41static inline dma_addr_t to_paddr(struct delta_ipc_ctx *ctx, void *vaddr)
42{
43	return (ctx->ipc_buf->paddr + (vaddr - ctx->ipc_buf->vaddr));
44}
45
46static inline bool is_valid_data(struct delta_ipc_ctx *ctx,
47				 void *data, u32 size)
48{
49	return ((data >= ctx->ipc_buf->vaddr) &&
50		((data + size) <= (ctx->ipc_buf->vaddr + ctx->ipc_buf->size)));
51}
52
53/*
54 * IPC shared memory (@ipc_buf_size, @ipc_buf_paddr) is sent to copro
55 * at each instance opening. This memory is allocated by IPC client
56 * and given through delta_ipc_open(). All messages parameters
57 * (open, set_stream, decode) will have their phy address within
58 * this IPC shared memory, avoiding de-facto recopies inside delta-ipc.
59 * All the below messages structures are used on both host and firmware
60 * side and are packed (use only of 32 bits size fields in messages
61 * structures to ensure packing):
62 * - struct delta_ipc_open_msg
63 * - struct delta_ipc_set_stream_msg
64 * - struct delta_ipc_decode_msg
65 * - struct delta_ipc_close_msg
66 * - struct delta_ipc_cb_msg
67 */
68struct delta_ipc_open_msg {
69	struct delta_ipc_header_msg header;
70	u32 ipc_buf_size;
71	dma_addr_t ipc_buf_paddr;
72	char name[32];
73	u32 param_size;
74	dma_addr_t param_paddr;
75};
76
77struct delta_ipc_set_stream_msg {
78	struct delta_ipc_header_msg header;
79	u32 param_size;
80	dma_addr_t param_paddr;
81};
82
83struct delta_ipc_decode_msg {
84	struct delta_ipc_header_msg header;
85	u32 param_size;
86	dma_addr_t param_paddr;
87	u32 status_size;
88	dma_addr_t status_paddr;
89};
90
91struct delta_ipc_close_msg {
92	struct delta_ipc_header_msg header;
93};
94
95struct delta_ipc_cb_msg {
96	struct delta_ipc_header_msg header;
97	int err;
98};
99
100static void build_msg_header(struct delta_ipc_ctx *ctx,
101			     enum delta_ipc_fw_command command,
102			     struct delta_ipc_header_msg *header)
103{
104	header->tag = IPC_SANITY_TAG;
105	header->host_hdl = to_host_hdl(ctx);
106	header->copro_hdl = ctx->copro_hdl;
107	header->command = command;
108}
109
110int delta_ipc_open(struct delta_ctx *pctx, const char *name,
111		   struct delta_ipc_param *param, u32 ipc_buf_size,
112		   struct delta_buf **ipc_buf, void **hdl)
113{
114	struct delta_dev *delta = pctx->dev;
115	struct rpmsg_device *rpmsg_device = delta->rpmsg_device;
116	struct delta_ipc_ctx *ctx = &pctx->ipc_ctx;
117	struct delta_ipc_open_msg msg;
118	struct delta_buf *buf = &ctx->ipc_buf_struct;
119	int ret;
120
121	if (!rpmsg_device) {
122		dev_err(delta->dev,
123			"%s   ipc: failed to open, rpmsg is not initialized\n",
124			pctx->name);
125		pctx->sys_errors++;
126		return -EINVAL;
127	}
128
129	if (!name) {
130		dev_err(delta->dev,
131			"%s   ipc: failed to open, no name given\n",
132			pctx->name);
133		return -EINVAL;
134	}
135
136	if (!param || !param->data || !param->size) {
137		dev_err(delta->dev,
138			"%s  ipc: failed to open, empty parameter\n",
139			pctx->name);
140		return -EINVAL;
141	}
142
143	if (!ipc_buf_size) {
144		dev_err(delta->dev,
145			"%s   ipc: failed to open, no size given for ipc buffer\n",
146			pctx->name);
147		return -EINVAL;
148	}
149
150	if (param->size > ipc_buf_size) {
151		dev_err(delta->dev,
152			"%s   ipc: failed to open, too large ipc parameter (%d bytes while max %d expected)\n",
153			pctx->name,
154			param->size, ctx->ipc_buf->size);
155		return -EINVAL;
156	}
157
158	/* init */
159	init_completion(&ctx->done);
160
161	/*
162	 * allocation of contiguous buffer for
163	 * data of commands exchanged between
164	 * host and firmware coprocessor
165	 */
166	ret = hw_alloc(pctx, ipc_buf_size,
167		       "ipc data buffer", buf);
168	if (ret)
169		return ret;
170	ctx->ipc_buf = buf;
171
172	/* build rpmsg message */
173	build_msg_header(ctx, DELTA_IPC_OPEN, &msg.header);
174
175	msg.ipc_buf_size = ipc_buf_size;
176	msg.ipc_buf_paddr = ctx->ipc_buf->paddr;
177
178	memcpy(msg.name, name, sizeof(msg.name));
179	msg.name[sizeof(msg.name) - 1] = 0;
180
181	msg.param_size = param->size;
182	memcpy(ctx->ipc_buf->vaddr, param->data, msg.param_size);
183	msg.param_paddr = ctx->ipc_buf->paddr;
184
185	/* send it */
186	ret = rpmsg_send(rpmsg_device->ept, &msg, sizeof(msg));
187	if (ret) {
188		dev_err(delta->dev,
189			"%s   ipc: failed to open, rpmsg_send failed (%d) for DELTA_IPC_OPEN (name=%s, size=%d, data=%p)\n",
190			pctx->name,
191			ret, name, param->size, param->data);
192		goto err;
193	}
194
195	/* wait for acknowledge */
196	if (!wait_for_completion_timeout
197	    (&ctx->done, msecs_to_jiffies(IPC_TIMEOUT))) {
198		dev_err(delta->dev,
199			"%s   ipc: failed to open, timeout waiting for DELTA_IPC_OPEN callback (name=%s, size=%d, data=%p)\n",
200			pctx->name,
201			name, param->size, param->data);
202		ret = -ETIMEDOUT;
203		goto err;
204	}
205
206	/* command completed, check error */
207	if (ctx->cb_err) {
208		dev_err(delta->dev,
209			"%s   ipc: failed to open, DELTA_IPC_OPEN completed but with error (%d) (name=%s, size=%d, data=%p)\n",
210			pctx->name,
211			ctx->cb_err, name, param->size, param->data);
212		ret = -EIO;
213		goto err;
214	}
215
216	*ipc_buf = ctx->ipc_buf;
217	*hdl = (void *)ctx;
218
219	return 0;
220
221err:
222	pctx->sys_errors++;
223	hw_free(pctx, ctx->ipc_buf);
224	ctx->ipc_buf = NULL;
225
226	return ret;
227};
228
229int delta_ipc_set_stream(void *hdl, struct delta_ipc_param *param)
230{
231	struct delta_ipc_ctx *ctx = to_ctx(hdl);
232	struct delta_ctx *pctx = to_pctx(ctx);
233	struct delta_dev *delta = pctx->dev;
234	struct rpmsg_device *rpmsg_device = delta->rpmsg_device;
235	struct delta_ipc_set_stream_msg msg;
236	int ret;
237
238	if (!hdl) {
239		dev_err(delta->dev,
240			"%s   ipc: failed to set stream, invalid ipc handle\n",
241			pctx->name);
242		return -EINVAL;
243	}
244
245	if (!rpmsg_device) {
246		dev_err(delta->dev,
247			"%s   ipc: failed to set stream, rpmsg is not initialized\n",
248			pctx->name);
249		return -EINVAL;
250	}
251
252	if (!param || !param->data || !param->size) {
253		dev_err(delta->dev,
254			"%s  ipc: failed to set stream, empty parameter\n",
255			pctx->name);
256		return -EINVAL;
257	}
258
259	if (param->size > ctx->ipc_buf->size) {
260		dev_err(delta->dev,
261			"%s   ipc: failed to set stream, too large ipc parameter(%d bytes while max %d expected)\n",
262			pctx->name,
263			param->size, ctx->ipc_buf->size);
264		return -EINVAL;
265	}
266
267	if (!is_valid_data(ctx, param->data, param->size)) {
268		dev_err(delta->dev,
269			"%s   ipc: failed to set stream, parameter is not in expected address range (size=%d, data=%p not in %p..%p)\n",
270			pctx->name,
271			param->size,
272			param->data,
273			ctx->ipc_buf->vaddr,
274			ctx->ipc_buf->vaddr + ctx->ipc_buf->size - 1);
275		return -EINVAL;
276	}
277
278	/* build rpmsg message */
279	build_msg_header(ctx, DELTA_IPC_SET_STREAM, &msg.header);
280
281	msg.param_size = param->size;
282	msg.param_paddr = to_paddr(ctx, param->data);
283
284	/* send it */
285	ret = rpmsg_send(rpmsg_device->ept, &msg, sizeof(msg));
286	if (ret) {
287		dev_err(delta->dev,
288			"%s   ipc: failed to set stream, rpmsg_send failed (%d) for DELTA_IPC_SET_STREAM (size=%d, data=%p)\n",
289			pctx->name,
290			ret, param->size, param->data);
291		pctx->sys_errors++;
292		return ret;
293	}
294
295	/* wait for acknowledge */
296	if (!wait_for_completion_timeout
297	    (&ctx->done, msecs_to_jiffies(IPC_TIMEOUT))) {
298		dev_err(delta->dev,
299			"%s   ipc: failed to set stream, timeout waiting for DELTA_IPC_SET_STREAM callback (size=%d, data=%p)\n",
300			pctx->name,
301			param->size, param->data);
302		pctx->sys_errors++;
303		return -ETIMEDOUT;
304	}
305
306	/* command completed, check status */
307	if (ctx->cb_err) {
308		dev_err(delta->dev,
309			"%s   ipc: failed to set stream, DELTA_IPC_SET_STREAM completed but with error (%d) (size=%d, data=%p)\n",
310			pctx->name,
311			ctx->cb_err, param->size, param->data);
312		pctx->sys_errors++;
313		return -EIO;
314	}
315
316	return 0;
317}
318
319int delta_ipc_decode(void *hdl, struct delta_ipc_param *param,
320		     struct delta_ipc_param *status)
321{
322	struct delta_ipc_ctx *ctx = to_ctx(hdl);
323	struct delta_ctx *pctx = to_pctx(ctx);
324	struct delta_dev *delta = pctx->dev;
325	struct rpmsg_device *rpmsg_device = delta->rpmsg_device;
326	struct delta_ipc_decode_msg msg;
327	int ret;
328
329	if (!hdl) {
330		dev_err(delta->dev,
331			"%s   ipc: failed to decode, invalid ipc handle\n",
332			pctx->name);
333		return -EINVAL;
334	}
335
336	if (!rpmsg_device) {
337		dev_err(delta->dev,
338			"%s   ipc: failed to decode, rpmsg is not initialized\n",
339			pctx->name);
340		return -EINVAL;
341	}
342
343	if (!param || !param->data || !param->size) {
344		dev_err(delta->dev,
345			"%s  ipc: failed to decode, empty parameter\n",
346			pctx->name);
347		return -EINVAL;
348	}
349
350	if (!status || !status->data || !status->size) {
351		dev_err(delta->dev,
352			"%s  ipc: failed to decode, empty status\n",
353			pctx->name);
354		return -EINVAL;
355	}
356
357	if (param->size + status->size > ctx->ipc_buf->size) {
358		dev_err(delta->dev,
359			"%s   ipc: failed to decode, too large ipc parameter (%d bytes (param) + %d bytes (status) while max %d expected)\n",
360			pctx->name,
361			param->size,
362			status->size,
363			ctx->ipc_buf->size);
364		return -EINVAL;
365	}
366
367	if (!is_valid_data(ctx, param->data, param->size)) {
368		dev_err(delta->dev,
369			"%s   ipc: failed to decode, parameter is not in expected address range (size=%d, data=%p not in %p..%p)\n",
370			pctx->name,
371			param->size,
372			param->data,
373			ctx->ipc_buf->vaddr,
374			ctx->ipc_buf->vaddr + ctx->ipc_buf->size - 1);
375		return -EINVAL;
376	}
377
378	if (!is_valid_data(ctx, status->data, status->size)) {
379		dev_err(delta->dev,
380			"%s   ipc: failed to decode, status is not in expected address range (size=%d, data=%p not in %p..%p)\n",
381			pctx->name,
382			status->size,
383			status->data,
384			ctx->ipc_buf->vaddr,
385			ctx->ipc_buf->vaddr + ctx->ipc_buf->size - 1);
386		return -EINVAL;
387	}
388
389	/* build rpmsg message */
390	build_msg_header(ctx, DELTA_IPC_DECODE, &msg.header);
391
392	msg.param_size = param->size;
393	msg.param_paddr = to_paddr(ctx, param->data);
394
395	msg.status_size = status->size;
396	msg.status_paddr = to_paddr(ctx, status->data);
397
398	/* send it */
399	ret = rpmsg_send(rpmsg_device->ept, &msg, sizeof(msg));
400	if (ret) {
401		dev_err(delta->dev,
402			"%s   ipc: failed to decode, rpmsg_send failed (%d) for DELTA_IPC_DECODE (size=%d, data=%p)\n",
403			pctx->name,
404			ret, param->size, param->data);
405		pctx->sys_errors++;
406		return ret;
407	}
408
409	/* wait for acknowledge */
410	if (!wait_for_completion_timeout
411	    (&ctx->done, msecs_to_jiffies(IPC_TIMEOUT))) {
412		dev_err(delta->dev,
413			"%s   ipc: failed to decode, timeout waiting for DELTA_IPC_DECODE callback (size=%d, data=%p)\n",
414			pctx->name,
415			param->size, param->data);
416		pctx->sys_errors++;
417		return -ETIMEDOUT;
418	}
419
420	/* command completed, check status */
421	if (ctx->cb_err) {
422		dev_err(delta->dev,
423			"%s   ipc: failed to decode, DELTA_IPC_DECODE completed but with error (%d) (size=%d, data=%p)\n",
424			pctx->name,
425			ctx->cb_err, param->size, param->data);
426		pctx->sys_errors++;
427		return -EIO;
428	}
429
430	return 0;
431};
432
433void delta_ipc_close(void *hdl)
434{
435	struct delta_ipc_ctx *ctx = to_ctx(hdl);
436	struct delta_ctx *pctx = to_pctx(ctx);
437	struct delta_dev *delta = pctx->dev;
438	struct rpmsg_device *rpmsg_device = delta->rpmsg_device;
439	struct delta_ipc_close_msg msg;
440	int ret;
441
442	if (!hdl) {
443		dev_err(delta->dev,
444			"%s   ipc: failed to close, invalid ipc handle\n",
445			pctx->name);
446		return;
447	}
448
449	if (ctx->ipc_buf) {
450		hw_free(pctx, ctx->ipc_buf);
451		ctx->ipc_buf = NULL;
452	}
453
454	if (!rpmsg_device) {
455		dev_err(delta->dev,
456			"%s   ipc: failed to close, rpmsg is not initialized\n",
457			pctx->name);
458		return;
459	}
460
461	/* build rpmsg message */
462	build_msg_header(ctx, DELTA_IPC_CLOSE, &msg.header);
463
464	/* send it */
465	ret = rpmsg_send(rpmsg_device->ept, &msg, sizeof(msg));
466	if (ret) {
467		dev_err(delta->dev,
468			"%s   ipc: failed to close, rpmsg_send failed (%d) for DELTA_IPC_CLOSE\n",
469			pctx->name, ret);
470		pctx->sys_errors++;
471		return;
472	}
473
474	/* wait for acknowledge */
475	if (!wait_for_completion_timeout
476	    (&ctx->done, msecs_to_jiffies(IPC_TIMEOUT))) {
477		dev_err(delta->dev,
478			"%s   ipc: failed to close, timeout waiting for DELTA_IPC_CLOSE callback\n",
479			pctx->name);
480		pctx->sys_errors++;
481		return;
482	}
483
484	/* command completed, check status */
485	if (ctx->cb_err) {
486		dev_err(delta->dev,
487			"%s   ipc: failed to close, DELTA_IPC_CLOSE completed but with error (%d)\n",
488			pctx->name, ctx->cb_err);
489		pctx->sys_errors++;
490	}
491};
492
493static int delta_ipc_cb(struct rpmsg_device *rpdev, void *data,
494			int len, void *priv, u32 src)
495{
496	struct delta_ipc_ctx *ctx;
497	struct delta_ipc_cb_msg *msg;
498
499	/* sanity check */
500	if (!rpdev) {
501		dev_err(NULL, "rpdev is NULL\n");
502		return -EINVAL;
503	}
504
505	if (!data || !len) {
506		dev_err(&rpdev->dev,
507			"unexpected empty message received from src=%d\n", src);
508		return -EINVAL;
509	}
510
511	if (len != sizeof(*msg)) {
512		dev_err(&rpdev->dev,
513			"unexpected message length received from src=%d (received %d bytes while %zu bytes expected)\n",
514			len, src, sizeof(*msg));
515		return -EINVAL;
516	}
517
518	msg = (struct delta_ipc_cb_msg *)data;
519	if (msg->header.tag != IPC_SANITY_TAG) {
520		dev_err(&rpdev->dev,
521			"unexpected message tag received from src=%d (received %x tag while %x expected)\n",
522			src, msg->header.tag, IPC_SANITY_TAG);
523		return -EINVAL;
524	}
525
526	ctx = msg_to_ctx(msg);
527	if (!ctx) {
528		dev_err(&rpdev->dev,
529			"unexpected message with NULL host_hdl received from src=%d\n",
530			src);
531		return -EINVAL;
532	}
533
534	/*
535	 * if not already known, save copro instance context
536	 * to ensure re-entrance on copro side
537	 */
538	if (!ctx->copro_hdl)
539		ctx->copro_hdl = msg_to_copro_hdl(msg);
540
541	/*
542	 * all is fine,
543	 * update status & complete command
544	 */
545	ctx->cb_err = msg->err;
546	complete(&ctx->done);
547
548	return 0;
549}
550
551static int delta_ipc_probe(struct rpmsg_device *rpmsg_device)
552{
553	struct rpmsg_driver *rpdrv = to_rpmsg_driver(rpmsg_device->dev.driver);
554	struct delta_dev *delta = to_delta(rpdrv);
555
556	delta->rpmsg_device = rpmsg_device;
557
558	return 0;
559}
560
561static void delta_ipc_remove(struct rpmsg_device *rpmsg_device)
562{
563	struct rpmsg_driver *rpdrv = to_rpmsg_driver(rpmsg_device->dev.driver);
564	struct delta_dev *delta = to_delta(rpdrv);
565
566	delta->rpmsg_device = NULL;
567}
568
569static struct rpmsg_device_id delta_ipc_device_id_table[] = {
570	{.name = "rpmsg-delta"},
571	{},
572};
573
574static struct rpmsg_driver delta_rpmsg_driver = {
575	.drv = {.name = KBUILD_MODNAME},
576	.id_table = delta_ipc_device_id_table,
577	.probe = delta_ipc_probe,
578	.callback = delta_ipc_cb,
579	.remove = delta_ipc_remove,
580};
581
582int delta_ipc_init(struct delta_dev *delta)
583{
584	delta->rpmsg_driver = delta_rpmsg_driver;
585
586	return register_rpmsg_driver(&delta->rpmsg_driver);
587}
588
589void delta_ipc_exit(struct delta_dev *delta)
590{
591	unregister_rpmsg_driver(&delta->rpmsg_driver);
592}
593