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