brcm2708: add linux 4.19 support
[oweals/openwrt.git] / target / linux / brcm2708 / patches-4.19 / 950-0275-staging-vc04_services-Add-new-vc-sm-cma-driver.patch
1 From b9607d33b3efa9a85268961cadc6df5b5c9b042b Mon Sep 17 00:00:00 2001
2 From: Dave Stevenson <dave.stevenson@raspberrypi.org>
3 Date: Tue, 25 Sep 2018 10:27:11 +0100
4 Subject: [PATCH 275/703] staging: vc04_services: Add new vc-sm-cma driver
5
6 This new driver allows contiguous memory blocks to be imported
7 into the VideoCore VPU memory map, and manages the lifetime of
8 those objects, only releasing the source dmabuf once the VPU has
9 confirmed it has finished with it.
10
11 Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
12 ---
13  drivers/staging/vc04_services/Kconfig         |   1 +
14  drivers/staging/vc04_services/Makefile        |   1 +
15  .../staging/vc04_services/vc-sm-cma/Kconfig   |  10 +
16  .../staging/vc04_services/vc-sm-cma/Makefile  |   8 +
17  drivers/staging/vc04_services/vc-sm-cma/TODO  |   2 +
18  .../staging/vc04_services/vc-sm-cma/vc_sm.c   | 838 ++++++++++++++++++
19  .../staging/vc04_services/vc-sm-cma/vc_sm.h   |  59 ++
20  .../vc04_services/vc-sm-cma/vc_sm_cma_vchi.c  | 498 +++++++++++
21  .../vc04_services/vc-sm-cma/vc_sm_cma_vchi.h  |  59 ++
22  .../vc04_services/vc-sm-cma/vc_sm_defs.h      | 298 +++++++
23  .../vc04_services/vc-sm-cma/vc_sm_knl.h       |  28 +
24  11 files changed, 1802 insertions(+)
25  create mode 100644 drivers/staging/vc04_services/vc-sm-cma/Kconfig
26  create mode 100644 drivers/staging/vc04_services/vc-sm-cma/Makefile
27  create mode 100644 drivers/staging/vc04_services/vc-sm-cma/TODO
28  create mode 100644 drivers/staging/vc04_services/vc-sm-cma/vc_sm.c
29  create mode 100644 drivers/staging/vc04_services/vc-sm-cma/vc_sm.h
30  create mode 100644 drivers/staging/vc04_services/vc-sm-cma/vc_sm_cma_vchi.c
31  create mode 100644 drivers/staging/vc04_services/vc-sm-cma/vc_sm_cma_vchi.h
32  create mode 100644 drivers/staging/vc04_services/vc-sm-cma/vc_sm_defs.h
33  create mode 100644 drivers/staging/vc04_services/vc-sm-cma/vc_sm_knl.h
34
35 --- a/drivers/staging/vc04_services/Kconfig
36 +++ b/drivers/staging/vc04_services/Kconfig
37 @@ -22,6 +22,7 @@ source "drivers/staging/vc04_services/bc
38  
39  source "drivers/staging/vc04_services/bcm2835-camera/Kconfig"
40  source "drivers/staging/vc04_services/vchiq-mmal/Kconfig"
41 +source "drivers/staging/vc04_services/vc-sm-cma/Kconfig"
42  
43  endif
44  
45 --- a/drivers/staging/vc04_services/Makefile
46 +++ b/drivers/staging/vc04_services/Makefile
47 @@ -13,6 +13,7 @@ vchiq-objs := \
48  obj-$(CONFIG_SND_BCM2835)      += bcm2835-audio/
49  obj-$(CONFIG_VIDEO_BCM2835)    += bcm2835-camera/
50  obj-$(CONFIG_BCM2835_VCHIQ_MMAL) += vchiq-mmal/
51 +obj-$(CONFIG_BCM_VC_SM_CMA)    += vc-sm-cma/
52  
53  ccflags-y += -Idrivers/staging/vc04_services -D__VCCOREVER__=0x04000000
54  
55 --- /dev/null
56 +++ b/drivers/staging/vc04_services/vc-sm-cma/Kconfig
57 @@ -0,0 +1,10 @@
58 +config BCM_VC_SM_CMA
59 +       tristate "VideoCore Shared Memory (CMA) driver"
60 +       depends on BCM2835_VCHIQ
61 +       select RBTREE
62 +       select DMA_SHARED_BUFFER
63 +       help
64 +         Say Y here to enable the shared memory interface that
65 +         supports sharing dmabufs with VideoCore.
66 +         This operates over the VCHIQ interface to a service
67 +         running on VideoCore.
68 --- /dev/null
69 +++ b/drivers/staging/vc04_services/vc-sm-cma/Makefile
70 @@ -0,0 +1,8 @@
71 +ccflags-y += -Idrivers/staging/vc04_services -Idrivers/staging/vc04_services/interface/vchi -Idrivers/staging/vc04_services/interface/vchiq_arm
72 +# -I"drivers/staging/android/ion/" -I"$(srctree)/fs/"
73 +ccflags-y += -D__VCCOREVER__=0
74 +
75 +vc-sm-cma-$(CONFIG_BCM_VC_SM_CMA) := \
76 +       vc_sm.o vc_sm_cma_vchi.o
77 +
78 +obj-$(CONFIG_BCM_VC_SM_CMA) += vc-sm-cma.o
79 --- /dev/null
80 +++ b/drivers/staging/vc04_services/vc-sm-cma/TODO
81 @@ -0,0 +1,2 @@
82 +1) Convert to a platform driver.
83 +
84 --- /dev/null
85 +++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm.c
86 @@ -0,0 +1,838 @@
87 +// SPDX-License-Identifier: GPL-2.0
88 +/*
89 + * VideoCore Shared Memory driver using CMA.
90 + *
91 + * Copyright: 2018, Raspberry Pi (Trading) Ltd
92 + * Dave Stevenson <dave.stevenson@raspberrypi.org>
93 + *
94 + * Based on vmcs_sm driver from Broadcom Corporation for some API,
95 + * and taking some code for CMA/dmabuf handling from the Android Ion
96 + * driver (Google/Linaro).
97 + *
98 + * This is cut down version to only support import of dma_bufs from
99 + * other kernel drivers. A more complete implementation of the old
100 + * vmcs_sm functionality can follow later.
101 + *
102 + */
103 +
104 +/* ---- Include Files ----------------------------------------------------- */
105 +#include <linux/cdev.h>
106 +#include <linux/device.h>
107 +#include <linux/debugfs.h>
108 +#include <linux/dma-mapping.h>
109 +#include <linux/dma-buf.h>
110 +#include <linux/errno.h>
111 +#include <linux/fs.h>
112 +#include <linux/kernel.h>
113 +#include <linux/list.h>
114 +#include <linux/miscdevice.h>
115 +#include <linux/module.h>
116 +#include <linux/mm.h>
117 +#include <linux/of_device.h>
118 +#include <linux/platform_device.h>
119 +#include <linux/proc_fs.h>
120 +#include <linux/slab.h>
121 +#include <linux/seq_file.h>
122 +#include <linux/syscalls.h>
123 +#include <linux/types.h>
124 +
125 +#include "vchiq_connected.h"
126 +#include "vc_sm_cma_vchi.h"
127 +
128 +#include "vc_sm.h"
129 +#include "vc_sm_knl.h"
130 +
131 +/* ---- Private Constants and Types --------------------------------------- */
132 +
133 +#define DEVICE_NAME            "vcsm-cma"
134 +#define DEVICE_MINOR           0
135 +
136 +#define VC_SM_RESOURCE_NAME_DEFAULT       "sm-host-resource"
137 +
138 +#define VC_SM_DIR_ROOT_NAME    "vcsm-cma"
139 +#define VC_SM_STATE            "state"
140 +
141 +/* Private file data associated with each opened device. */
142 +struct vc_sm_privdata_t {
143 +       pid_t pid;                      /* PID of creator. */
144 +
145 +       int restart_sys;                /* Tracks restart on interrupt. */
146 +       enum vc_sm_msg_type int_action; /* Interrupted action. */
147 +       u32 int_trans_id;               /* Interrupted transaction. */
148 +};
149 +
150 +typedef int (*VC_SM_SHOW) (struct seq_file *s, void *v);
151 +struct sm_pde_t {
152 +       VC_SM_SHOW show;          /* Debug fs function hookup. */
153 +       struct dentry *dir_entry; /* Debug fs directory entry. */
154 +       void *priv_data;          /* Private data */
155 +};
156 +
157 +/* Global state information. */
158 +struct sm_state_t {
159 +       struct platform_device *pdev;
160 +
161 +       struct miscdevice dev;
162 +       struct sm_instance *sm_handle;  /* Handle for videocore service. */
163 +
164 +       struct mutex map_lock;          /* Global map lock. */
165 +       struct list_head buffer_list;   /* List of buffer. */
166 +
167 +       struct vc_sm_privdata_t *data_knl;  /* Kernel internal data tracking. */
168 +       struct dentry *dir_root;        /* Debug fs entries root. */
169 +       struct sm_pde_t dir_state;      /* Debug fs entries state sub-tree. */
170 +
171 +       bool require_released_callback; /* VPU will send a released msg when it
172 +                                        * has finished with a resource.
173 +                                        */
174 +       u32 int_trans_id;               /* Interrupted transaction. */
175 +};
176 +
177 +/* ---- Private Variables ----------------------------------------------- */
178 +
179 +static struct sm_state_t *sm_state;
180 +static int sm_inited;
181 +
182 +/* ---- Private Function Prototypes -------------------------------------- */
183 +
184 +/* ---- Private Functions ------------------------------------------------ */
185 +
186 +static int vc_sm_cma_seq_file_show(struct seq_file *s, void *v)
187 +{
188 +       struct sm_pde_t *sm_pde;
189 +
190 +       sm_pde = (struct sm_pde_t *)(s->private);
191 +
192 +       if (sm_pde && sm_pde->show)
193 +               sm_pde->show(s, v);
194 +
195 +       return 0;
196 +}
197 +
198 +static int vc_sm_cma_single_open(struct inode *inode, struct file *file)
199 +{
200 +       return single_open(file, vc_sm_cma_seq_file_show, inode->i_private);
201 +}
202 +
203 +static const struct file_operations vc_sm_cma_debug_fs_fops = {
204 +       .open = vc_sm_cma_single_open,
205 +       .read = seq_read,
206 +       .llseek = seq_lseek,
207 +       .release = single_release,
208 +};
209 +
210 +static int vc_sm_cma_global_state_show(struct seq_file *s, void *v)
211 +{
212 +       struct vc_sm_buffer *resource = NULL;
213 +       int resource_count = 0;
214 +
215 +       if (!sm_state)
216 +               return 0;
217 +
218 +       seq_printf(s, "\nVC-ServiceHandle     0x%x\n",
219 +                  (unsigned int)sm_state->sm_handle);
220 +
221 +       /* Log all applicable mapping(s). */
222 +
223 +       mutex_lock(&sm_state->map_lock);
224 +       seq_puts(s, "\nResources\n");
225 +       if (!list_empty(&sm_state->buffer_list)) {
226 +               list_for_each_entry(resource, &sm_state->buffer_list,
227 +                                   global_buffer_list) {
228 +                       resource_count++;
229 +
230 +                       seq_printf(s, "\nResource                %p\n",
231 +                                  resource);
232 +                       seq_printf(s, "           NAME         %s\n",
233 +                                  resource->name);
234 +                       seq_printf(s, "           SIZE         %d\n",
235 +                                  resource->size);
236 +                       seq_printf(s, "           DMABUF       %p\n",
237 +                                  resource->dma_buf);
238 +                       seq_printf(s, "           ATTACH       %p\n",
239 +                                  resource->attach);
240 +                       seq_printf(s, "           SG_TABLE     %p\n",
241 +                                  resource->sg_table);
242 +                       seq_printf(s, "           SGT          %p\n",
243 +                                  resource->sgt);
244 +                       seq_printf(s, "           DMA_ADDR     %pad\n",
245 +                                  &resource->dma_addr);
246 +                       seq_printf(s, "           VC_HANDLE     %08x\n",
247 +                                  resource->vc_handle);
248 +                       seq_printf(s, "           VC_MAPPING    %d\n",
249 +                                  resource->vpu_state);
250 +               }
251 +       }
252 +       seq_printf(s, "\n\nTotal resource count:   %d\n\n", resource_count);
253 +
254 +       mutex_unlock(&sm_state->map_lock);
255 +
256 +       return 0;
257 +}
258 +
259 +/*
260 + * Adds a buffer to the private data list which tracks all the allocated
261 + * data.
262 + */
263 +static void vc_sm_add_resource(struct vc_sm_privdata_t *privdata,
264 +                              struct vc_sm_buffer *buffer)
265 +{
266 +       mutex_lock(&sm_state->map_lock);
267 +       list_add(&buffer->global_buffer_list, &sm_state->buffer_list);
268 +       mutex_unlock(&sm_state->map_lock);
269 +
270 +       pr_debug("[%s]: added buffer %p (name %s, size %d)\n",
271 +                __func__, buffer, buffer->name, buffer->size);
272 +}
273 +
274 +/*
275 + * Release an allocation.
276 + * All refcounting is done via the dma buf object.
277 + */
278 +static void vc_sm_release_resource(struct vc_sm_buffer *buffer, int force)
279 +{
280 +       mutex_lock(&sm_state->map_lock);
281 +       mutex_lock(&buffer->lock);
282 +
283 +       pr_debug("[%s]: buffer %p (name %s, size %d)\n",
284 +                __func__, buffer, buffer->name, buffer->size);
285 +
286 +       if (buffer->vc_handle && buffer->vpu_state == VPU_MAPPED) {
287 +               struct vc_sm_free_t free = { buffer->vc_handle, 0 };
288 +               int status = vc_sm_cma_vchi_free(sm_state->sm_handle, &free,
289 +                                            &sm_state->int_trans_id);
290 +               if (status != 0 && status != -EINTR) {
291 +                       pr_err("[%s]: failed to free memory on videocore (status: %u, trans_id: %u)\n",
292 +                              __func__, status, sm_state->int_trans_id);
293 +               }
294 +
295 +               if (sm_state->require_released_callback) {
296 +                       /* Need to wait for the VPU to confirm the free */
297 +
298 +                       /* Retain a reference on this until the VPU has
299 +                        * released it
300 +                        */
301 +                       buffer->vpu_state = VPU_UNMAPPING;
302 +                       goto defer;
303 +               }
304 +               buffer->vpu_state = VPU_NOT_MAPPED;
305 +               buffer->vc_handle = 0;
306 +       }
307 +       if (buffer->vc_handle) {
308 +               /* We've sent the unmap request but not had the response. */
309 +               pr_err("[%s]: Waiting for VPU unmap response on %p\n",
310 +                      __func__, buffer);
311 +               goto defer;
312 +       }
313 +       if (buffer->in_use) {
314 +               /* Don't release dmabuf here - we await the release */
315 +               pr_err("[%s]: buffer %p is still in use\n",
316 +                      __func__, buffer);
317 +               goto defer;
318 +       }
319 +
320 +       /* Handle cleaning up imported dmabufs */
321 +       if (buffer->sgt) {
322 +               dma_buf_unmap_attachment(buffer->attach, buffer->sgt,
323 +                                        DMA_BIDIRECTIONAL);
324 +               buffer->sgt = NULL;
325 +       }
326 +       if (buffer->attach) {
327 +               dma_buf_detach(buffer->dma_buf, buffer->attach);
328 +               buffer->attach = NULL;
329 +       }
330 +
331 +       /* Release the dma_buf (whether ours or imported) */
332 +       if (buffer->import_dma_buf) {
333 +               dma_buf_put(buffer->import_dma_buf);
334 +               buffer->import_dma_buf = NULL;
335 +               buffer->dma_buf = NULL;
336 +       } else if (buffer->dma_buf) {
337 +               dma_buf_put(buffer->dma_buf);
338 +               buffer->dma_buf = NULL;
339 +       }
340 +
341 +       if (buffer->sg_table && !buffer->import_dma_buf) {
342 +               /* Our own allocation that we need to dma_unmap_sg */
343 +               dma_unmap_sg(&sm_state->pdev->dev, buffer->sg_table->sgl,
344 +                            buffer->sg_table->nents, DMA_BIDIRECTIONAL);
345 +       }
346 +
347 +       /* Free the local resource. Start by removing it from the list */
348 +       buffer->private = NULL;
349 +       list_del(&buffer->global_buffer_list);
350 +
351 +       mutex_unlock(&buffer->lock);
352 +       mutex_unlock(&sm_state->map_lock);
353 +
354 +       mutex_destroy(&buffer->lock);
355 +
356 +       kfree(buffer);
357 +       return;
358 +
359 +defer:
360 +       mutex_unlock(&buffer->lock);
361 +       mutex_unlock(&sm_state->map_lock);
362 +}
363 +
364 +/* Create support for private data tracking. */
365 +static struct vc_sm_privdata_t *vc_sm_cma_create_priv_data(pid_t id)
366 +{
367 +       char alloc_name[32];
368 +       struct vc_sm_privdata_t *file_data = NULL;
369 +
370 +       /* Allocate private structure. */
371 +       file_data = kzalloc(sizeof(*file_data), GFP_KERNEL);
372 +
373 +       if (!file_data)
374 +               return NULL;
375 +
376 +       snprintf(alloc_name, sizeof(alloc_name), "%d", id);
377 +
378 +       file_data->pid = id;
379 +
380 +       return file_data;
381 +}
382 +
383 +/* Dma_buf operations for chaining through to an imported dma_buf */
384 +static
385 +int vc_sm_import_dma_buf_attach(struct dma_buf *dmabuf,
386 +                               struct dma_buf_attachment *attachment)
387 +{
388 +       struct vc_sm_buffer *res = dmabuf->priv;
389 +
390 +       if (!res->import_dma_buf)
391 +               return -EINVAL;
392 +       return res->import_dma_buf->ops->attach(res->import_dma_buf,
393 +                                               attachment);
394 +}
395 +
396 +static
397 +void vc_sm_import_dma_buf_detatch(struct dma_buf *dmabuf,
398 +                                 struct dma_buf_attachment *attachment)
399 +{
400 +       struct vc_sm_buffer *res = dmabuf->priv;
401 +
402 +       if (!res->import_dma_buf)
403 +               return;
404 +       res->import_dma_buf->ops->detach(res->import_dma_buf, attachment);
405 +}
406 +
407 +static
408 +struct sg_table *vc_sm_import_map_dma_buf(struct dma_buf_attachment *attachment,
409 +                                         enum dma_data_direction direction)
410 +{
411 +       struct vc_sm_buffer *res = attachment->dmabuf->priv;
412 +
413 +       if (!res->import_dma_buf)
414 +               return NULL;
415 +       return res->import_dma_buf->ops->map_dma_buf(attachment, direction);
416 +}
417 +
418 +static
419 +void vc_sm_import_unmap_dma_buf(struct dma_buf_attachment *attachment,
420 +                               struct sg_table *table,
421 +                               enum dma_data_direction direction)
422 +{
423 +       struct vc_sm_buffer *res = attachment->dmabuf->priv;
424 +
425 +       if (!res->import_dma_buf)
426 +               return;
427 +       res->import_dma_buf->ops->unmap_dma_buf(attachment, table, direction);
428 +}
429 +
430 +static
431 +int vc_sm_import_dmabuf_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma)
432 +{
433 +       struct vc_sm_buffer *res = dmabuf->priv;
434 +
435 +       pr_debug("%s: mmap dma_buf %p, res %p, imported db %p\n", __func__,
436 +                dmabuf, res, res->import_dma_buf);
437 +       if (!res->import_dma_buf) {
438 +               pr_err("%s: mmap dma_buf %p- not an imported buffer\n",
439 +                      __func__, dmabuf);
440 +               return -EINVAL;
441 +       }
442 +       return res->import_dma_buf->ops->mmap(res->import_dma_buf, vma);
443 +}
444 +
445 +static
446 +void vc_sm_import_dma_buf_release(struct dma_buf *dmabuf)
447 +{
448 +       struct vc_sm_buffer *res = dmabuf->priv;
449 +
450 +       pr_debug("%s: Relasing dma_buf %p\n", __func__, dmabuf);
451 +       if (!res->import_dma_buf)
452 +               return;
453 +
454 +       res->in_use = 0;
455 +
456 +       vc_sm_release_resource(res, 0);
457 +}
458 +
459 +static
460 +void *vc_sm_import_dma_buf_kmap(struct dma_buf *dmabuf,
461 +                               unsigned long offset)
462 +{
463 +       struct vc_sm_buffer *res = dmabuf->priv;
464 +
465 +       if (!res->import_dma_buf)
466 +               return NULL;
467 +       return res->import_dma_buf->ops->map(res->import_dma_buf,
468 +                                                     offset);
469 +}
470 +
471 +static
472 +void vc_sm_import_dma_buf_kunmap(struct dma_buf *dmabuf,
473 +                                unsigned long offset, void *ptr)
474 +{
475 +       struct vc_sm_buffer *res = dmabuf->priv;
476 +
477 +       if (!res->import_dma_buf)
478 +               return;
479 +       res->import_dma_buf->ops->unmap(res->import_dma_buf,
480 +                                              offset, ptr);
481 +}
482 +
483 +static
484 +int vc_sm_import_dma_buf_begin_cpu_access(struct dma_buf *dmabuf,
485 +                                         enum dma_data_direction direction)
486 +{
487 +       struct vc_sm_buffer *res = dmabuf->priv;
488 +
489 +       if (!res->import_dma_buf)
490 +               return -EINVAL;
491 +       return res->import_dma_buf->ops->begin_cpu_access(res->import_dma_buf,
492 +                                                           direction);
493 +}
494 +
495 +static
496 +int vc_sm_import_dma_buf_end_cpu_access(struct dma_buf *dmabuf,
497 +                                       enum dma_data_direction direction)
498 +{
499 +       struct vc_sm_buffer *res = dmabuf->priv;
500 +
501 +       if (!res->import_dma_buf)
502 +               return -EINVAL;
503 +       return res->import_dma_buf->ops->end_cpu_access(res->import_dma_buf,
504 +                                                         direction);
505 +}
506 +
507 +static const struct dma_buf_ops dma_buf_import_ops = {
508 +       .map_dma_buf = vc_sm_import_map_dma_buf,
509 +       .unmap_dma_buf = vc_sm_import_unmap_dma_buf,
510 +       .mmap = vc_sm_import_dmabuf_mmap,
511 +       .release = vc_sm_import_dma_buf_release,
512 +       .attach = vc_sm_import_dma_buf_attach,
513 +       .detach = vc_sm_import_dma_buf_detatch,
514 +       .begin_cpu_access = vc_sm_import_dma_buf_begin_cpu_access,
515 +       .end_cpu_access = vc_sm_import_dma_buf_end_cpu_access,
516 +       .map = vc_sm_import_dma_buf_kmap,
517 +       .unmap = vc_sm_import_dma_buf_kunmap,
518 +};
519 +
520 +/* Import a dma_buf to be shared with VC. */
521 +int
522 +vc_sm_cma_import_dmabuf_internal(struct vc_sm_privdata_t *private,
523 +                                struct dma_buf *dma_buf,
524 +                                struct dma_buf **imported_buf)
525 +{
526 +       DEFINE_DMA_BUF_EXPORT_INFO(exp_info);
527 +       struct vc_sm_buffer *buffer = NULL;
528 +       struct vc_sm_import import = { };
529 +       struct vc_sm_import_result result = { };
530 +       struct dma_buf_attachment *attach = NULL;
531 +       struct sg_table *sgt = NULL;
532 +       int ret = 0;
533 +       int status;
534 +
535 +       /* Setup our allocation parameters */
536 +       pr_debug("%s: importing dma_buf %p\n", __func__, dma_buf);
537 +
538 +       get_dma_buf(dma_buf);
539 +       dma_buf = dma_buf;
540 +
541 +       attach = dma_buf_attach(dma_buf, &sm_state->pdev->dev);
542 +       if (IS_ERR(attach)) {
543 +               ret = PTR_ERR(attach);
544 +               goto error;
545 +       }
546 +
547 +       sgt = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL);
548 +       if (IS_ERR(sgt)) {
549 +               ret = PTR_ERR(sgt);
550 +               goto error;
551 +       }
552 +
553 +       /* Verify that the address block is contiguous */
554 +       if (sgt->nents != 1) {
555 +               ret = -ENOMEM;
556 +               goto error;
557 +       }
558 +
559 +       /* Allocate local buffer to track this allocation. */
560 +       buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
561 +       if (!buffer) {
562 +               ret = -ENOMEM;
563 +               goto error;
564 +       }
565 +
566 +       import.type = VC_SM_ALLOC_NON_CACHED;
567 +       import.addr = (uint32_t)sg_dma_address(sgt->sgl);
568 +       if ((import.addr & 0xC0000000) != 0xC0000000) {
569 +               pr_err("%s: Expecting an uncached alias for dma_addr %08x\n",
570 +                      __func__, import.addr);
571 +               import.addr |= 0xC0000000;
572 +       }
573 +       import.size = sg_dma_len(sgt->sgl);
574 +       import.allocator = current->tgid;
575 +       import.kernel_id = (uint32_t)buffer;    //FIXME: 64 bit support needed.
576 +
577 +       memcpy(import.name, VC_SM_RESOURCE_NAME_DEFAULT,
578 +              sizeof(VC_SM_RESOURCE_NAME_DEFAULT));
579 +
580 +       pr_debug("[%s]: attempt to import \"%s\" data - type %u, addr %p, size %u\n",
581 +                __func__, import.name, import.type, (void *)import.addr,
582 +                import.size);
583 +
584 +       /* Allocate the videocore buffer. */
585 +       status = vc_sm_cma_vchi_import(sm_state->sm_handle, &import, &result,
586 +                                      &sm_state->int_trans_id);
587 +       if (status == -EINTR) {
588 +               pr_debug("[%s]: requesting import memory action restart (trans_id: %u)\n",
589 +                        __func__, sm_state->int_trans_id);
590 +               ret = -ERESTARTSYS;
591 +               private->restart_sys = -EINTR;
592 +               private->int_action = VC_SM_MSG_TYPE_IMPORT;
593 +               goto error;
594 +       } else if (status || !result.res_handle) {
595 +               pr_debug("[%s]: failed to import memory on videocore (status: %u, trans_id: %u)\n",
596 +                        __func__, status, sm_state->int_trans_id);
597 +               ret = -ENOMEM;
598 +               goto error;
599 +       }
600 +
601 +       mutex_init(&buffer->lock);
602 +       INIT_LIST_HEAD(&buffer->attachments);
603 +       memcpy(buffer->name, import.name,
604 +              min(sizeof(buffer->name), sizeof(import.name) - 1));
605 +
606 +       /* Keep track of the buffer we created. */
607 +       buffer->private = private;
608 +       buffer->vc_handle = result.res_handle;
609 +       buffer->size = import.size;
610 +       buffer->vpu_state = VPU_MAPPED;
611 +
612 +       buffer->import_dma_buf = dma_buf;
613 +
614 +       buffer->attach = attach;
615 +       buffer->sgt = sgt;
616 +       buffer->dma_addr = sg_dma_address(sgt->sgl);
617 +       buffer->in_use = 1;
618 +
619 +       /*
620 +        * We're done - we need to export a new dmabuf chaining through most
621 +        * functions, but enabling us to release our own internal references
622 +        * here.
623 +        */
624 +       exp_info.ops = &dma_buf_import_ops;
625 +       exp_info.size = import.size;
626 +       exp_info.flags = O_RDWR;
627 +       exp_info.priv = buffer;
628 +
629 +       buffer->dma_buf = dma_buf_export(&exp_info);
630 +       if (IS_ERR(buffer->dma_buf)) {
631 +               ret = PTR_ERR(buffer->dma_buf);
632 +               goto error;
633 +       }
634 +
635 +       vc_sm_add_resource(private, buffer);
636 +
637 +       *imported_buf = buffer->dma_buf;
638 +
639 +       return 0;
640 +
641 +error:
642 +       if (result.res_handle) {
643 +               struct vc_sm_free_t free = { result.res_handle, 0 };
644 +
645 +               vc_sm_cma_vchi_free(sm_state->sm_handle, &free,
646 +                                   &sm_state->int_trans_id);
647 +       }
648 +       kfree(buffer);
649 +       if (sgt)
650 +               dma_buf_unmap_attachment(attach, sgt, DMA_BIDIRECTIONAL);
651 +       if (attach)
652 +               dma_buf_detach(dma_buf, attach);
653 +       dma_buf_put(dma_buf);
654 +       return ret;
655 +}
656 +
657 +/* FIXME: Pass a function pointer to this into vc_vchi_sm.c */
658 +void
659 +vc_sm_vpu_event(struct sm_instance *instance, struct vc_sm_result_t *reply,
660 +               int reply_len)
661 +{
662 +       switch (reply->trans_id & ~0x80000000) {
663 +       case VC_SM_MSG_TYPE_CLIENT_VERSION:
664 +       {
665 +               /* Acknowledge that the firmware supports the version command */
666 +               pr_debug("%s: firmware acked version msg. Require release cb\n",
667 +                        __func__);
668 +               sm_state->require_released_callback = true;
669 +       }
670 +       break;
671 +       case VC_SM_MSG_TYPE_RELEASED:
672 +       {
673 +               struct vc_sm_released *release = (struct vc_sm_released *)reply;
674 +               struct vc_sm_buffer *buffer =
675 +                               (struct vc_sm_buffer *)release->kernel_id;
676 +
677 +               /*
678 +                * FIXME: Need to check buffer is still valid and allocated
679 +                * before continuing
680 +                */
681 +               pr_debug("%s: Released addr %08x, size %u, id %08x, mem_handle %08x\n",
682 +                        __func__, release->addr, release->size,
683 +                        release->kernel_id, release->vc_handle);
684 +               mutex_lock(&buffer->lock);
685 +               buffer->vc_handle = 0;
686 +               buffer->vpu_state = VPU_NOT_MAPPED;
687 +               mutex_unlock(&buffer->lock);
688 +
689 +               vc_sm_release_resource(buffer, 0);
690 +       }
691 +       break;
692 +       default:
693 +               pr_err("%s: Unknown vpu cmd %x\n", __func__, reply->trans_id);
694 +               break;
695 +       }
696 +}
697 +
698 +/* Videocore connected.  */
699 +static void vc_sm_connected_init(void)
700 +{
701 +       int ret;
702 +       VCHI_INSTANCE_T vchi_instance;
703 +       struct vc_sm_version version;
704 +       struct vc_sm_result_t version_result;
705 +
706 +       pr_info("[%s]: start\n", __func__);
707 +
708 +       /*
709 +        * Initialize and create a VCHI connection for the shared memory service
710 +        * running on videocore.
711 +        */
712 +       ret = vchi_initialise(&vchi_instance);
713 +       if (ret) {
714 +               pr_err("[%s]: failed to initialise VCHI instance (ret=%d)\n",
715 +                      __func__, ret);
716 +
717 +               ret = -EIO;
718 +               goto err_free_mem;
719 +       }
720 +
721 +       ret = vchi_connect(vchi_instance);
722 +       if (ret) {
723 +               pr_err("[%s]: failed to connect VCHI instance (ret=%d)\n",
724 +                      __func__, ret);
725 +
726 +               ret = -EIO;
727 +               goto err_free_mem;
728 +       }
729 +
730 +       /* Initialize an instance of the shared memory service. */
731 +       sm_state->sm_handle = vc_sm_cma_vchi_init(vchi_instance, 1,
732 +                                                 vc_sm_vpu_event);
733 +       if (!sm_state->sm_handle) {
734 +               pr_err("[%s]: failed to initialize shared memory service\n",
735 +                      __func__);
736 +
737 +               ret = -EPERM;
738 +               goto err_free_mem;
739 +       }
740 +
741 +       /* Create a debug fs directory entry (root). */
742 +       sm_state->dir_root = debugfs_create_dir(VC_SM_DIR_ROOT_NAME, NULL);
743 +       if (!sm_state->dir_root) {
744 +               pr_err("[%s]: failed to create \'%s\' directory entry\n",
745 +                      __func__, VC_SM_DIR_ROOT_NAME);
746 +
747 +               ret = -EPERM;
748 +               goto err_stop_sm_service;
749 +       }
750 +
751 +       sm_state->dir_state.show = &vc_sm_cma_global_state_show;
752 +       sm_state->dir_state.dir_entry =
753 +               debugfs_create_file(VC_SM_STATE, 0444, sm_state->dir_root,
754 +                                   &sm_state->dir_state,
755 +                                   &vc_sm_cma_debug_fs_fops);
756 +
757 +       INIT_LIST_HEAD(&sm_state->buffer_list);
758 +
759 +       sm_state->data_knl = vc_sm_cma_create_priv_data(0);
760 +       if (!sm_state->data_knl) {
761 +               pr_err("[%s]: failed to create kernel private data tracker\n",
762 +                      __func__);
763 +               goto err_remove_shared_memory;
764 +       }
765 +
766 +       version.version = 1;
767 +       ret = vc_sm_cma_vchi_client_version(sm_state->sm_handle, &version,
768 +                                           &version_result,
769 +                                           &sm_state->int_trans_id);
770 +       if (ret) {
771 +               pr_err("[%s]: Failed to send version request %d\n", __func__,
772 +                      ret);
773 +       }
774 +
775 +       /* Done! */
776 +       sm_inited = 1;
777 +       pr_info("[%s]: installed successfully\n", __func__);
778 +       return;
779 +
780 +err_remove_shared_memory:
781 +       debugfs_remove_recursive(sm_state->dir_root);
782 +err_stop_sm_service:
783 +       vc_sm_cma_vchi_stop(&sm_state->sm_handle);
784 +err_free_mem:
785 +       kfree(sm_state);
786 +       pr_info("[%s]: failed, ret %d\n", __func__, ret);
787 +}
788 +
789 +/* Driver loading. */
790 +static int bcm2835_vc_sm_cma_probe(struct platform_device *pdev)
791 +{
792 +       struct device *dev = &pdev->dev;
793 +       int err;
794 +
795 +       pr_info("%s: Videocore shared memory driver\n", __func__);
796 +
797 +       sm_state = kzalloc(sizeof(*sm_state), GFP_KERNEL);
798 +       if (!sm_state)
799 +               return -ENOMEM;
800 +       sm_state->pdev = pdev;
801 +       mutex_init(&sm_state->map_lock);
802 +
803 +       dev->coherent_dma_mask = DMA_BIT_MASK(32);
804 +       dev->dma_mask = &dev->coherent_dma_mask;
805 +       err = of_dma_configure(dev, NULL, true);
806 +       if (err) {
807 +               dev_err(dev, "Unable to setup DMA: %d\n", err);
808 +               return err;
809 +       }
810 +
811 +       vchiq_add_connected_callback(vc_sm_connected_init);
812 +       return 0;
813 +}
814 +
815 +/* Driver unloading. */
816 +static int bcm2835_vc_sm_cma_remove(struct platform_device *pdev)
817 +{
818 +       pr_debug("[%s]: start\n", __func__);
819 +       if (sm_inited) {
820 +               /* Remove shared memory device. */
821 +               misc_deregister(&sm_state->dev);
822 +
823 +               /* Remove all proc entries. */
824 +               //debugfs_remove_recursive(sm_state->dir_root);
825 +
826 +               /* Stop the videocore shared memory service. */
827 +               vc_sm_cma_vchi_stop(&sm_state->sm_handle);
828 +
829 +               /* Free the memory for the state structure. */
830 +               mutex_destroy(&sm_state->map_lock);
831 +               kfree(sm_state);
832 +       }
833 +
834 +       pr_debug("[%s]: end\n", __func__);
835 +       return 0;
836 +}
837 +
838 +/* Get an internal resource handle mapped from the external one. */
839 +int vc_sm_cma_int_handle(int handle)
840 +{
841 +       struct dma_buf *dma_buf = (struct dma_buf *)handle;
842 +       struct vc_sm_buffer *res;
843 +
844 +       /* Validate we can work with this device. */
845 +       if (!sm_state || !handle) {
846 +               pr_err("[%s]: invalid input\n", __func__);
847 +               return 0;
848 +       }
849 +
850 +       res = (struct vc_sm_buffer *)dma_buf->priv;
851 +       return res->vc_handle;
852 +}
853 +EXPORT_SYMBOL_GPL(vc_sm_cma_int_handle);
854 +
855 +/* Free a previously allocated shared memory handle and block. */
856 +int vc_sm_cma_free(int handle)
857 +{
858 +       struct dma_buf *dma_buf = (struct dma_buf *)handle;
859 +
860 +       /* Validate we can work with this device. */
861 +       if (!sm_state || !handle) {
862 +               pr_err("[%s]: invalid input\n", __func__);
863 +               return -EPERM;
864 +       }
865 +
866 +       pr_debug("%s: handle %08x/dmabuf %p\n", __func__, handle, dma_buf);
867 +
868 +       dma_buf_put(dma_buf);
869 +
870 +       return 0;
871 +}
872 +EXPORT_SYMBOL_GPL(vc_sm_cma_free);
873 +
874 +/* Import a dmabuf to be shared with VC. */
875 +int vc_sm_cma_import_dmabuf(struct dma_buf *src_dmabuf, int *handle)
876 +{
877 +       struct dma_buf *new_dma_buf;
878 +       struct vc_sm_buffer *res;
879 +       int ret;
880 +
881 +       /* Validate we can work with this device. */
882 +       if (!sm_state || !src_dmabuf || !handle) {
883 +               pr_err("[%s]: invalid input\n", __func__);
884 +               return -EPERM;
885 +       }
886 +
887 +       ret = vc_sm_cma_import_dmabuf_internal(sm_state->data_knl, src_dmabuf,
888 +                                              &new_dma_buf);
889 +
890 +       if (!ret) {
891 +               pr_debug("%s: imported to ptr %p\n", __func__, new_dma_buf);
892 +               res = (struct vc_sm_buffer *)new_dma_buf->priv;
893 +
894 +               /* Assign valid handle at this time.*/
895 +               *handle = (int)new_dma_buf;
896 +       } else {
897 +               /*
898 +                * succeeded in importing the dma_buf, but then
899 +                * failed to look it up again. How?
900 +                * Release the fd again.
901 +                */
902 +               pr_err("%s: imported vc_sm_cma_get_buffer failed %d\n",
903 +                      __func__, ret);
904 +       }
905 +
906 +       return ret;
907 +}
908 +EXPORT_SYMBOL_GPL(vc_sm_cma_import_dmabuf);
909 +
910 +static struct platform_driver bcm2835_vcsm_cma_driver = {
911 +       .probe = bcm2835_vc_sm_cma_probe,
912 +       .remove = bcm2835_vc_sm_cma_remove,
913 +       .driver = {
914 +                  .name = DEVICE_NAME,
915 +                  .owner = THIS_MODULE,
916 +                  },
917 +};
918 +
919 +module_platform_driver(bcm2835_vcsm_cma_driver);
920 +
921 +MODULE_AUTHOR("Dave Stevenson");
922 +MODULE_DESCRIPTION("VideoCore CMA Shared Memory Driver");
923 +MODULE_LICENSE("GPL v2");
924 +MODULE_ALIAS("platform:vcsm-cma");
925 --- /dev/null
926 +++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm.h
927 @@ -0,0 +1,59 @@
928 +/* SPDX-License-Identifier: GPL-2.0 */
929 +
930 +/*
931 + * VideoCore Shared Memory driver using CMA.
932 + *
933 + * Copyright: 2018, Raspberry Pi (Trading) Ltd
934 + *
935 + */
936 +
937 +#ifndef VC_SM_H
938 +#define VC_SM_H
939 +
940 +#include <linux/device.h>
941 +#include <linux/dma-direction.h>
942 +#include <linux/kref.h>
943 +#include <linux/mm_types.h>
944 +#include <linux/mutex.h>
945 +#include <linux/rbtree.h>
946 +#include <linux/sched.h>
947 +#include <linux/shrinker.h>
948 +#include <linux/types.h>
949 +#include <linux/miscdevice.h>
950 +
951 +#define VC_SM_MAX_NAME_LEN 32
952 +
953 +enum vc_sm_vpu_mapping_state {
954 +       VPU_NOT_MAPPED,
955 +       VPU_MAPPED,
956 +       VPU_UNMAPPING
957 +};
958 +
959 +struct vc_sm_buffer {
960 +       struct list_head global_buffer_list;    /* Global list of buffers. */
961 +
962 +       size_t size;
963 +
964 +       /* Lock over all the following state for this buffer */
965 +       struct mutex lock;
966 +       struct sg_table *sg_table;
967 +       struct list_head attachments;
968 +
969 +       char name[VC_SM_MAX_NAME_LEN];
970 +
971 +       int in_use:1;   /* Kernel is still using this resource */
972 +
973 +       enum vc_sm_vpu_mapping_state vpu_state;
974 +       u32 vc_handle;  /* VideoCore handle for this buffer */
975 +
976 +       /* DMABUF related fields */
977 +       struct dma_buf *import_dma_buf;
978 +       struct dma_buf *dma_buf;
979 +       struct dma_buf_attachment *attach;
980 +       struct sg_table *sgt;
981 +       dma_addr_t dma_addr;
982 +
983 +       struct vc_sm_privdata_t *private;
984 +};
985 +
986 +#endif
987 --- /dev/null
988 +++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm_cma_vchi.c
989 @@ -0,0 +1,498 @@
990 +// SPDX-License-Identifier: GPL-2.0
991 +/*
992 + * VideoCore Shared Memory CMA allocator
993 + *
994 + * Copyright: 2018, Raspberry Pi (Trading) Ltd
995 + * Copyright 2011-2012 Broadcom Corporation.  All rights reserved.
996 + *
997 + * Based on vmcs_sm driver from Broadcom Corporation.
998 + *
999 + */
1000 +
1001 +/* ---- Include Files ----------------------------------------------------- */
1002 +#include <linux/completion.h>
1003 +#include <linux/kernel.h>
1004 +#include <linux/kthread.h>
1005 +#include <linux/list.h>
1006 +#include <linux/mutex.h>
1007 +#include <linux/semaphore.h>
1008 +#include <linux/slab.h>
1009 +#include <linux/types.h>
1010 +
1011 +#include "vc_sm_cma_vchi.h"
1012 +
1013 +#define VC_SM_VER  1
1014 +#define VC_SM_MIN_VER 0
1015 +
1016 +/* ---- Private Constants and Types -------------------------------------- */
1017 +
1018 +/* Command blocks come from a pool */
1019 +#define SM_MAX_NUM_CMD_RSP_BLKS 32
1020 +
1021 +struct sm_cmd_rsp_blk {
1022 +       struct list_head head;  /* To create lists */
1023 +       /* To be signaled when the response is there */
1024 +       struct completion cmplt;
1025 +
1026 +       u16 id;
1027 +       u16 length;
1028 +
1029 +       u8 msg[VC_SM_MAX_MSG_LEN];
1030 +
1031 +       uint32_t wait:1;
1032 +       uint32_t sent:1;
1033 +       uint32_t alloc:1;
1034 +
1035 +};
1036 +
1037 +struct sm_instance {
1038 +       u32 num_connections;
1039 +       VCHI_SERVICE_HANDLE_T vchi_handle[VCHI_MAX_NUM_CONNECTIONS];
1040 +       struct task_struct *io_thread;
1041 +       struct completion io_cmplt;
1042 +
1043 +       vpu_event_cb vpu_event;
1044 +
1045 +       /* Mutex over the following lists */
1046 +       struct mutex lock;
1047 +       u32 trans_id;
1048 +       struct list_head cmd_list;
1049 +       struct list_head rsp_list;
1050 +       struct list_head dead_list;
1051 +
1052 +       struct sm_cmd_rsp_blk free_blk[SM_MAX_NUM_CMD_RSP_BLKS];
1053 +
1054 +       /* Mutex over the free_list */
1055 +       struct mutex free_lock;
1056 +       struct list_head free_list;
1057 +
1058 +       struct semaphore free_sema;
1059 +
1060 +};
1061 +
1062 +/* ---- Private Variables ------------------------------------------------ */
1063 +
1064 +/* ---- Private Function Prototypes -------------------------------------- */
1065 +
1066 +/* ---- Private Functions ------------------------------------------------ */
1067 +static int
1068 +bcm2835_vchi_msg_queue(VCHI_SERVICE_HANDLE_T handle,
1069 +                      void *data,
1070 +                      unsigned int size)
1071 +{
1072 +       return vchi_queue_kernel_message(handle,
1073 +                                        data,
1074 +                                        size);
1075 +}
1076 +
1077 +static struct
1078 +sm_cmd_rsp_blk *vc_vchi_cmd_create(struct sm_instance *instance,
1079 +                                  enum vc_sm_msg_type id, void *msg,
1080 +                                  u32 size, int wait)
1081 +{
1082 +       struct sm_cmd_rsp_blk *blk;
1083 +       struct vc_sm_msg_hdr_t *hdr;
1084 +
1085 +       if (down_interruptible(&instance->free_sema)) {
1086 +               blk = kmalloc(sizeof(*blk), GFP_KERNEL);
1087 +               if (!blk)
1088 +                       return NULL;
1089 +
1090 +               blk->alloc = 1;
1091 +               init_completion(&blk->cmplt);
1092 +       } else {
1093 +               mutex_lock(&instance->free_lock);
1094 +               blk =
1095 +                   list_first_entry(&instance->free_list,
1096 +                                    struct sm_cmd_rsp_blk, head);
1097 +               list_del(&blk->head);
1098 +               mutex_unlock(&instance->free_lock);
1099 +       }
1100 +
1101 +       blk->sent = 0;
1102 +       blk->wait = wait;
1103 +       blk->length = sizeof(*hdr) + size;
1104 +
1105 +       hdr = (struct vc_sm_msg_hdr_t *)blk->msg;
1106 +       hdr->type = id;
1107 +       mutex_lock(&instance->lock);
1108 +       instance->trans_id++;
1109 +       /*
1110 +        * Retain the top bit for identifying asynchronous events, or VPU cmds.
1111 +        */
1112 +       instance->trans_id &= ~0x80000000;
1113 +       hdr->trans_id = instance->trans_id;
1114 +       blk->id = instance->trans_id;
1115 +       mutex_unlock(&instance->lock);
1116 +
1117 +       if (size)
1118 +               memcpy(hdr->body, msg, size);
1119 +
1120 +       return blk;
1121 +}
1122 +
1123 +static void
1124 +vc_vchi_cmd_delete(struct sm_instance *instance, struct sm_cmd_rsp_blk *blk)
1125 +{
1126 +       if (blk->alloc) {
1127 +               kfree(blk);
1128 +               return;
1129 +       }
1130 +
1131 +       mutex_lock(&instance->free_lock);
1132 +       list_add(&blk->head, &instance->free_list);
1133 +       mutex_unlock(&instance->free_lock);
1134 +       up(&instance->free_sema);
1135 +}
1136 +
1137 +static void vc_sm_cma_vchi_rx_ack(struct sm_instance *instance,
1138 +                                 struct sm_cmd_rsp_blk *cmd,
1139 +                                 struct vc_sm_result_t *reply,
1140 +                                 u32 reply_len)
1141 +{
1142 +       mutex_lock(&instance->lock);
1143 +       list_for_each_entry(cmd,
1144 +                           &instance->rsp_list,
1145 +                           head) {
1146 +               if (cmd->id == reply->trans_id)
1147 +                       break;
1148 +       }
1149 +       mutex_unlock(&instance->lock);
1150 +
1151 +       if (&cmd->head == &instance->rsp_list) {
1152 +               //pr_debug("%s: received response %u, throw away...",
1153 +               pr_err("%s: received response %u, throw away...",
1154 +                      __func__,
1155 +                      reply->trans_id);
1156 +       } else if (reply_len > sizeof(cmd->msg)) {
1157 +               pr_err("%s: reply too big (%u) %u, throw away...",
1158 +                      __func__, reply_len,
1159 +                    reply->trans_id);
1160 +       } else {
1161 +               memcpy(cmd->msg, reply,
1162 +                      reply_len);
1163 +               complete(&cmd->cmplt);
1164 +       }
1165 +}
1166 +
1167 +static int vc_sm_cma_vchi_videocore_io(void *arg)
1168 +{
1169 +       struct sm_instance *instance = arg;
1170 +       struct sm_cmd_rsp_blk *cmd = NULL, *cmd_tmp;
1171 +       struct vc_sm_result_t *reply;
1172 +       u32 reply_len;
1173 +       s32 status;
1174 +       int svc_use = 1;
1175 +
1176 +       while (1) {
1177 +               if (svc_use)
1178 +                       vchi_service_release(instance->vchi_handle[0]);
1179 +               svc_use = 0;
1180 +               if (!wait_for_completion_interruptible(&instance->io_cmplt)) {
1181 +                       vchi_service_use(instance->vchi_handle[0]);
1182 +                       svc_use = 1;
1183 +
1184 +                       do {
1185 +                               /*
1186 +                                * Get new command and move it to response list
1187 +                                */
1188 +                               mutex_lock(&instance->lock);
1189 +                               if (list_empty(&instance->cmd_list)) {
1190 +                                       /* no more commands to process */
1191 +                                       mutex_unlock(&instance->lock);
1192 +                                       break;
1193 +                               }
1194 +                               cmd =
1195 +                                   list_first_entry(&instance->cmd_list,
1196 +                                                    struct sm_cmd_rsp_blk,
1197 +                                                    head);
1198 +                               list_move(&cmd->head, &instance->rsp_list);
1199 +                               cmd->sent = 1;
1200 +                               mutex_unlock(&instance->lock);
1201 +
1202 +                               /* Send the command */
1203 +                               status = bcm2835_vchi_msg_queue(
1204 +                                               instance->vchi_handle[0],
1205 +                                               cmd->msg, cmd->length);
1206 +                               if (status) {
1207 +                                       pr_err("%s: failed to queue message (%d)",
1208 +                                              __func__, status);
1209 +                               }
1210 +
1211 +                               /* If no reply is needed then we're done */
1212 +                               if (!cmd->wait) {
1213 +                                       mutex_lock(&instance->lock);
1214 +                                       list_del(&cmd->head);
1215 +                                       mutex_unlock(&instance->lock);
1216 +                                       vc_vchi_cmd_delete(instance, cmd);
1217 +                                       continue;
1218 +                               }
1219 +
1220 +                               if (status) {
1221 +                                       complete(&cmd->cmplt);
1222 +                                       continue;
1223 +                               }
1224 +
1225 +                       } while (1);
1226 +
1227 +                       while (!vchi_msg_peek(instance->vchi_handle[0],
1228 +                                             (void **)&reply, &reply_len,
1229 +                                             VCHI_FLAGS_NONE)) {
1230 +                               if (reply->trans_id & 0x80000000) {
1231 +                                       /* Async event or cmd from the VPU */
1232 +                                       if (instance->vpu_event)
1233 +                                               instance->vpu_event(
1234 +                                                       instance, reply,
1235 +                                                       reply_len);
1236 +                               } else {
1237 +                                       vc_sm_cma_vchi_rx_ack(instance, cmd,
1238 +                                                             reply, reply_len);
1239 +                               }
1240 +
1241 +                               vchi_msg_remove(instance->vchi_handle[0]);
1242 +                       }
1243 +
1244 +                       /* Go through the dead list and free them */
1245 +                       mutex_lock(&instance->lock);
1246 +                       list_for_each_entry_safe(cmd, cmd_tmp,
1247 +                                                &instance->dead_list, head) {
1248 +                               list_del(&cmd->head);
1249 +                               vc_vchi_cmd_delete(instance, cmd);
1250 +                       }
1251 +                       mutex_unlock(&instance->lock);
1252 +               }
1253 +       }
1254 +
1255 +       return 0;
1256 +}
1257 +
1258 +static void vc_sm_cma_vchi_callback(void *param,
1259 +                                   const VCHI_CALLBACK_REASON_T reason,
1260 +                                   void *msg_handle)
1261 +{
1262 +       struct sm_instance *instance = param;
1263 +
1264 +       (void)msg_handle;
1265 +
1266 +       switch (reason) {
1267 +       case VCHI_CALLBACK_MSG_AVAILABLE:
1268 +               complete(&instance->io_cmplt);
1269 +               break;
1270 +
1271 +       case VCHI_CALLBACK_SERVICE_CLOSED:
1272 +               pr_info("%s: service CLOSED!!", __func__);
1273 +       default:
1274 +               break;
1275 +       }
1276 +}
1277 +
1278 +struct sm_instance *vc_sm_cma_vchi_init(VCHI_INSTANCE_T vchi_instance,
1279 +                                       unsigned int num_connections,
1280 +                                       vpu_event_cb vpu_event)
1281 +{
1282 +       u32 i;
1283 +       struct sm_instance *instance;
1284 +       int status;
1285 +
1286 +       pr_debug("%s: start", __func__);
1287 +
1288 +       if (num_connections > VCHI_MAX_NUM_CONNECTIONS) {
1289 +               pr_err("%s: unsupported number of connections %u (max=%u)",
1290 +                      __func__, num_connections, VCHI_MAX_NUM_CONNECTIONS);
1291 +
1292 +               goto err_null;
1293 +       }
1294 +       /* Allocate memory for this instance */
1295 +       instance = kzalloc(sizeof(*instance), GFP_KERNEL);
1296 +
1297 +       /* Misc initialisations */
1298 +       mutex_init(&instance->lock);
1299 +       init_completion(&instance->io_cmplt);
1300 +       INIT_LIST_HEAD(&instance->cmd_list);
1301 +       INIT_LIST_HEAD(&instance->rsp_list);
1302 +       INIT_LIST_HEAD(&instance->dead_list);
1303 +       INIT_LIST_HEAD(&instance->free_list);
1304 +       sema_init(&instance->free_sema, SM_MAX_NUM_CMD_RSP_BLKS);
1305 +       mutex_init(&instance->free_lock);
1306 +       for (i = 0; i < SM_MAX_NUM_CMD_RSP_BLKS; i++) {
1307 +               init_completion(&instance->free_blk[i].cmplt);
1308 +               list_add(&instance->free_blk[i].head, &instance->free_list);
1309 +       }
1310 +
1311 +       /* Open the VCHI service connections */
1312 +       instance->num_connections = num_connections;
1313 +       for (i = 0; i < num_connections; i++) {
1314 +               SERVICE_CREATION_T params = {
1315 +                       .version = VCHI_VERSION_EX(VC_SM_VER, VC_SM_MIN_VER),
1316 +                       .service_id = VC_SM_SERVER_NAME,
1317 +                       .callback = vc_sm_cma_vchi_callback,
1318 +                       .callback_param = instance,
1319 +               };
1320 +
1321 +               status = vchi_service_open(vchi_instance,
1322 +                                          &params, &instance->vchi_handle[i]);
1323 +               if (status) {
1324 +                       pr_err("%s: failed to open VCHI service (%d)",
1325 +                              __func__, status);
1326 +
1327 +                       goto err_close_services;
1328 +               }
1329 +       }
1330 +
1331 +       /* Create the thread which takes care of all io to/from videoocore. */
1332 +       instance->io_thread = kthread_create(&vc_sm_cma_vchi_videocore_io,
1333 +                                            (void *)instance, "SMIO");
1334 +       if (!instance->io_thread) {
1335 +               pr_err("%s: failed to create SMIO thread", __func__);
1336 +
1337 +               goto err_close_services;
1338 +       }
1339 +       instance->vpu_event = vpu_event;
1340 +       set_user_nice(instance->io_thread, -10);
1341 +       wake_up_process(instance->io_thread);
1342 +
1343 +       pr_debug("%s: success - instance 0x%x", __func__,
1344 +                (unsigned int)instance);
1345 +       return instance;
1346 +
1347 +err_close_services:
1348 +       for (i = 0; i < instance->num_connections; i++) {
1349 +               if (instance->vchi_handle[i])
1350 +                       vchi_service_close(instance->vchi_handle[i]);
1351 +       }
1352 +       kfree(instance);
1353 +err_null:
1354 +       pr_debug("%s: FAILED", __func__);
1355 +       return NULL;
1356 +}
1357 +
1358 +int vc_sm_cma_vchi_stop(struct sm_instance **handle)
1359 +{
1360 +       struct sm_instance *instance;
1361 +       u32 i;
1362 +
1363 +       if (!handle) {
1364 +               pr_err("%s: invalid pointer to handle %p", __func__, handle);
1365 +               goto lock;
1366 +       }
1367 +
1368 +       if (!*handle) {
1369 +               pr_err("%s: invalid handle %p", __func__, *handle);
1370 +               goto lock;
1371 +       }
1372 +
1373 +       instance = *handle;
1374 +
1375 +       /* Close all VCHI service connections */
1376 +       for (i = 0; i < instance->num_connections; i++) {
1377 +               s32 success;
1378 +
1379 +               vchi_service_use(instance->vchi_handle[i]);
1380 +
1381 +               success = vchi_service_close(instance->vchi_handle[i]);
1382 +       }
1383 +
1384 +       kfree(instance);
1385 +
1386 +       *handle = NULL;
1387 +       return 0;
1388 +
1389 +lock:
1390 +       return -EINVAL;
1391 +}
1392 +
1393 +static int vc_sm_cma_vchi_send_msg(struct sm_instance *handle,
1394 +                                  enum vc_sm_msg_type msg_id, void *msg,
1395 +                                  u32 msg_size, void *result, u32 result_size,
1396 +                                  u32 *cur_trans_id, u8 wait_reply)
1397 +{
1398 +       int status = 0;
1399 +       struct sm_instance *instance = handle;
1400 +       struct sm_cmd_rsp_blk *cmd_blk;
1401 +
1402 +       if (!handle) {
1403 +               pr_err("%s: invalid handle", __func__);
1404 +               return -EINVAL;
1405 +       }
1406 +       if (!msg) {
1407 +               pr_err("%s: invalid msg pointer", __func__);
1408 +               return -EINVAL;
1409 +       }
1410 +
1411 +       cmd_blk =
1412 +           vc_vchi_cmd_create(instance, msg_id, msg, msg_size, wait_reply);
1413 +       if (!cmd_blk) {
1414 +               pr_err("[%s]: failed to allocate global tracking resource",
1415 +                      __func__);
1416 +               return -ENOMEM;
1417 +       }
1418 +
1419 +       if (cur_trans_id)
1420 +               *cur_trans_id = cmd_blk->id;
1421 +
1422 +       mutex_lock(&instance->lock);
1423 +       list_add_tail(&cmd_blk->head, &instance->cmd_list);
1424 +       mutex_unlock(&instance->lock);
1425 +       complete(&instance->io_cmplt);
1426 +
1427 +       if (!wait_reply)
1428 +               /* We're done */
1429 +               return 0;
1430 +
1431 +       /* Wait for the response */
1432 +       if (wait_for_completion_interruptible(&cmd_blk->cmplt)) {
1433 +               mutex_lock(&instance->lock);
1434 +               if (!cmd_blk->sent) {
1435 +                       list_del(&cmd_blk->head);
1436 +                       mutex_unlock(&instance->lock);
1437 +                       vc_vchi_cmd_delete(instance, cmd_blk);
1438 +                       return -ENXIO;
1439 +               }
1440 +
1441 +               list_move(&cmd_blk->head, &instance->dead_list);
1442 +               mutex_unlock(&instance->lock);
1443 +               complete(&instance->io_cmplt);
1444 +               return -EINTR;  /* We're done */
1445 +       }
1446 +
1447 +       if (result && result_size) {
1448 +               memcpy(result, cmd_blk->msg, result_size);
1449 +       } else {
1450 +               struct vc_sm_result_t *res =
1451 +                       (struct vc_sm_result_t *)cmd_blk->msg;
1452 +               status = (res->success == 0) ? 0 : -ENXIO;
1453 +       }
1454 +
1455 +       mutex_lock(&instance->lock);
1456 +       list_del(&cmd_blk->head);
1457 +       mutex_unlock(&instance->lock);
1458 +       vc_vchi_cmd_delete(instance, cmd_blk);
1459 +       return status;
1460 +}
1461 +
1462 +int vc_sm_cma_vchi_free(struct sm_instance *handle, struct vc_sm_free_t *msg,
1463 +                       u32 *cur_trans_id)
1464 +{
1465 +       return vc_sm_cma_vchi_send_msg(handle, VC_SM_MSG_TYPE_FREE,
1466 +                                  msg, sizeof(*msg), 0, 0, cur_trans_id, 0);
1467 +}
1468 +
1469 +int vc_sm_cma_vchi_import(struct sm_instance *handle, struct vc_sm_import *msg,
1470 +                         struct vc_sm_import_result *result, u32 *cur_trans_id)
1471 +{
1472 +       return vc_sm_cma_vchi_send_msg(handle, VC_SM_MSG_TYPE_IMPORT,
1473 +                                  msg, sizeof(*msg), result, sizeof(*result),
1474 +                                  cur_trans_id, 1);
1475 +}
1476 +
1477 +int vc_sm_cma_vchi_client_version(struct sm_instance *handle,
1478 +                                 struct vc_sm_version *msg,
1479 +                                 struct vc_sm_result_t *result,
1480 +                                 u32 *cur_trans_id)
1481 +{
1482 +       return vc_sm_cma_vchi_send_msg(handle, VC_SM_MSG_TYPE_CLIENT_VERSION,
1483 +                                  //msg, sizeof(*msg), result, sizeof(*result),
1484 +                                  //cur_trans_id, 1);
1485 +                                  msg, sizeof(*msg), NULL, 0,
1486 +                                  cur_trans_id, 0);
1487 +}
1488 --- /dev/null
1489 +++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm_cma_vchi.h
1490 @@ -0,0 +1,59 @@
1491 +/* SPDX-License-Identifier: GPL-2.0 */
1492 +
1493 +/*
1494 + * VideoCore Shared Memory CMA allocator
1495 + *
1496 + * Copyright: 2018, Raspberry Pi (Trading) Ltd
1497 + * Copyright 2011-2012 Broadcom Corporation.  All rights reserved.
1498 + *
1499 + * Based on vmcs_sm driver from Broadcom Corporation.
1500 + *
1501 + */
1502 +
1503 +#ifndef __VC_SM_CMA_VCHI_H__INCLUDED__
1504 +#define __VC_SM_CMA_VCHI_H__INCLUDED__
1505 +
1506 +#include "interface/vchi/vchi.h"
1507 +
1508 +#include "vc_sm_defs.h"
1509 +
1510 +/*
1511 + * Forward declare.
1512 + */
1513 +struct sm_instance;
1514 +
1515 +typedef void (*vpu_event_cb)(struct sm_instance *instance,
1516 +                            struct vc_sm_result_t *reply, int reply_len);
1517 +
1518 +/*
1519 + * Initialize the shared memory service, opens up vchi connection to talk to it.
1520 + */
1521 +struct sm_instance *vc_sm_cma_vchi_init(VCHI_INSTANCE_T vchi_instance,
1522 +                                       unsigned int num_connections,
1523 +                                       vpu_event_cb vpu_event);
1524 +
1525 +/*
1526 + * Terminates the shared memory service.
1527 + */
1528 +int vc_sm_cma_vchi_stop(struct sm_instance **handle);
1529 +
1530 +/*
1531 + * Ask the shared memory service to free up some memory that was previously
1532 + * allocated by the vc_sm_cma_vchi_alloc function call.
1533 + */
1534 +int vc_sm_cma_vchi_free(struct sm_instance *handle, struct vc_sm_free_t *msg,
1535 +                       u32 *cur_trans_id);
1536 +
1537 +/*
1538 + * Import a contiguous block of memory and wrap it in a GPU MEM_HANDLE_T.
1539 + */
1540 +int vc_sm_cma_vchi_import(struct sm_instance *handle, struct vc_sm_import *msg,
1541 +                         struct vc_sm_import_result *result,
1542 +                         u32 *cur_trans_id);
1543 +
1544 +int vc_sm_cma_vchi_client_version(struct sm_instance *handle,
1545 +                                 struct vc_sm_version *msg,
1546 +                                 struct vc_sm_result_t *result,
1547 +                                 u32 *cur_trans_id);
1548 +
1549 +#endif /* __VC_SM_CMA_VCHI_H__INCLUDED__ */
1550 --- /dev/null
1551 +++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm_defs.h
1552 @@ -0,0 +1,298 @@
1553 +/* SPDX-License-Identifier: GPL-2.0 */
1554 +
1555 +/*
1556 + * VideoCore Shared Memory CMA allocator
1557 + *
1558 + * Copyright: 2018, Raspberry Pi (Trading) Ltd
1559 + *
1560 + * Based on vc_sm_defs.h from the vmcs_sm driver Copyright Broadcom Corporation.
1561 + * All IPC messages are copied across to this file, even if the vc-sm-cma
1562 + * driver is not currently using them.
1563 + *
1564 + ****************************************************************************
1565 + */
1566 +
1567 +#ifndef __VC_SM_DEFS_H__INCLUDED__
1568 +#define __VC_SM_DEFS_H__INCLUDED__
1569 +
1570 +/* FourCC code used for VCHI connection */
1571 +#define VC_SM_SERVER_NAME MAKE_FOURCC("SMEM")
1572 +
1573 +/* Maximum message length */
1574 +#define VC_SM_MAX_MSG_LEN (sizeof(union vc_sm_msg_union_t) + \
1575 +       sizeof(struct vc_sm_msg_hdr_t))
1576 +#define VC_SM_MAX_RSP_LEN (sizeof(union vc_sm_msg_union_t))
1577 +
1578 +/* Resource name maximum size */
1579 +#define VC_SM_RESOURCE_NAME 32
1580 +
1581 +/*
1582 + * Version to be reported to the VPU
1583 + * VPU assumes 0 (aka 1) which does not require the released callback, nor
1584 + * expect the client to handle VC_MEM_REQUESTS.
1585 + * Version 2 requires the released callback, and must support VC_MEM_REQUESTS.
1586 + */
1587 +#define VC_SM_PROTOCOL_VERSION 2
1588 +
1589 +enum vc_sm_msg_type {
1590 +       /* Message types supported for HOST->VC direction */
1591 +
1592 +       /* Allocate shared memory block */
1593 +       VC_SM_MSG_TYPE_ALLOC,
1594 +       /* Lock allocated shared memory block */
1595 +       VC_SM_MSG_TYPE_LOCK,
1596 +       /* Unlock allocated shared memory block */
1597 +       VC_SM_MSG_TYPE_UNLOCK,
1598 +       /* Unlock allocated shared memory block, do not answer command */
1599 +       VC_SM_MSG_TYPE_UNLOCK_NOANS,
1600 +       /* Free shared memory block */
1601 +       VC_SM_MSG_TYPE_FREE,
1602 +       /* Resize a shared memory block */
1603 +       VC_SM_MSG_TYPE_RESIZE,
1604 +       /* Walk the allocated shared memory block(s) */
1605 +       VC_SM_MSG_TYPE_WALK_ALLOC,
1606 +
1607 +       /* A previously applied action will need to be reverted */
1608 +       VC_SM_MSG_TYPE_ACTION_CLEAN,
1609 +
1610 +       /*
1611 +        * Import a physical address and wrap into a MEM_HANDLE_T.
1612 +        * Release with VC_SM_MSG_TYPE_FREE.
1613 +        */
1614 +       VC_SM_MSG_TYPE_IMPORT,
1615 +       /*
1616 +        *Tells VC the protocol version supported by this client.
1617 +        * 2 supports the async/cmd messages from the VPU for final release
1618 +        * of memory, and for VC allocations.
1619 +        */
1620 +       VC_SM_MSG_TYPE_CLIENT_VERSION,
1621 +       /* Response to VC request for memory */
1622 +       VC_SM_MSG_TYPE_VC_MEM_REQUEST_REPLY,
1623 +
1624 +       /*
1625 +        * Asynchronous/cmd messages supported for VC->HOST direction.
1626 +        * Signalled by setting the top bit in vc_sm_result_t trans_id.
1627 +        */
1628 +
1629 +       /*
1630 +        * VC has finished with an imported memory allocation.
1631 +        * Release any Linux reference counts on the underlying block.
1632 +        */
1633 +       VC_SM_MSG_TYPE_RELEASED,
1634 +       /* VC request for memory */
1635 +       VC_SM_MSG_TYPE_VC_MEM_REQUEST,
1636 +
1637 +       VC_SM_MSG_TYPE_MAX
1638 +};
1639 +
1640 +/* Type of memory to be allocated */
1641 +enum vc_sm_alloc_type_t {
1642 +       VC_SM_ALLOC_CACHED,
1643 +       VC_SM_ALLOC_NON_CACHED,
1644 +};
1645 +
1646 +/* Message header for all messages in HOST->VC direction */
1647 +struct vc_sm_msg_hdr_t {
1648 +       u32 type;
1649 +       u32 trans_id;
1650 +       u8 body[0];
1651 +
1652 +};
1653 +
1654 +/* Request to allocate memory (HOST->VC) */
1655 +struct vc_sm_alloc_t {
1656 +       /* type of memory to allocate */
1657 +       enum vc_sm_alloc_type_t type;
1658 +       /* byte amount of data to allocate per unit */
1659 +       u32 base_unit;
1660 +       /* number of unit to allocate */
1661 +       u32 num_unit;
1662 +       /* alignment to be applied on allocation */
1663 +       u32 alignment;
1664 +       /* identity of who allocated this block */
1665 +       u32 allocator;
1666 +       /* resource name (for easier tracking on vc side) */
1667 +       char name[VC_SM_RESOURCE_NAME];
1668 +
1669 +};
1670 +
1671 +/* Result of a requested memory allocation (VC->HOST) */
1672 +struct vc_sm_alloc_result_t {
1673 +       /* Transaction identifier */
1674 +       u32 trans_id;
1675 +
1676 +       /* Resource handle */
1677 +       u32 res_handle;
1678 +       /* Pointer to resource buffer */
1679 +       u32 res_mem;
1680 +       /* Resource base size (bytes) */
1681 +       u32 res_base_size;
1682 +       /* Resource number */
1683 +       u32 res_num;
1684 +
1685 +};
1686 +
1687 +/* Request to free a previously allocated memory (HOST->VC) */
1688 +struct vc_sm_free_t {
1689 +       /* Resource handle (returned from alloc) */
1690 +       u32 res_handle;
1691 +       /* Resource buffer (returned from alloc) */
1692 +       u32 res_mem;
1693 +
1694 +};
1695 +
1696 +/* Request to lock a previously allocated memory (HOST->VC) */
1697 +struct vc_sm_lock_unlock_t {
1698 +       /* Resource handle (returned from alloc) */
1699 +       u32 res_handle;
1700 +       /* Resource buffer (returned from alloc) */
1701 +       u32 res_mem;
1702 +
1703 +};
1704 +
1705 +/* Request to resize a previously allocated memory (HOST->VC) */
1706 +struct vc_sm_resize_t {
1707 +       /* Resource handle (returned from alloc) */
1708 +       u32 res_handle;
1709 +       /* Resource buffer (returned from alloc) */
1710 +       u32 res_mem;
1711 +       /* Resource *new* size requested (bytes) */
1712 +       u32 res_new_size;
1713 +
1714 +};
1715 +
1716 +/* Result of a requested memory lock (VC->HOST) */
1717 +struct vc_sm_lock_result_t {
1718 +       /* Transaction identifier */
1719 +       u32 trans_id;
1720 +
1721 +       /* Resource handle */
1722 +       u32 res_handle;
1723 +       /* Pointer to resource buffer */
1724 +       u32 res_mem;
1725 +       /*
1726 +        * Pointer to former resource buffer if the memory
1727 +        * was reallocated
1728 +        */
1729 +       u32 res_old_mem;
1730 +
1731 +};
1732 +
1733 +/* Generic result for a request (VC->HOST) */
1734 +struct vc_sm_result_t {
1735 +       /* Transaction identifier */
1736 +       u32 trans_id;
1737 +
1738 +       s32 success;
1739 +
1740 +};
1741 +
1742 +/* Request to revert a previously applied action (HOST->VC) */
1743 +struct vc_sm_action_clean_t {
1744 +       /* Action of interest */
1745 +       enum vc_sm_msg_type res_action;
1746 +       /* Transaction identifier for the action of interest */
1747 +       u32 action_trans_id;
1748 +
1749 +};
1750 +
1751 +/* Request to remove all data associated with a given allocator (HOST->VC) */
1752 +struct vc_sm_free_all_t {
1753 +       /* Allocator identifier */
1754 +       u32 allocator;
1755 +};
1756 +
1757 +/* Request to import memory (HOST->VC) */
1758 +struct vc_sm_import {
1759 +       /* type of memory to allocate */
1760 +       enum vc_sm_alloc_type_t type;
1761 +       /* pointer to the VC (ie physical) address of the allocated memory */
1762 +       u32 addr;
1763 +       /* size of buffer */
1764 +       u32 size;
1765 +       /* opaque handle returned in RELEASED messages */
1766 +       u32 kernel_id;
1767 +       /* Allocator identifier */
1768 +       u32 allocator;
1769 +       /* resource name (for easier tracking on vc side) */
1770 +       char     name[VC_SM_RESOURCE_NAME];
1771 +};
1772 +
1773 +/* Result of a requested memory import (VC->HOST) */
1774 +struct vc_sm_import_result {
1775 +       /* Transaction identifier */
1776 +       u32 trans_id;
1777 +
1778 +       /* Resource handle */
1779 +       u32 res_handle;
1780 +};
1781 +
1782 +/* Notification that VC has finished with an allocation (VC->HOST) */
1783 +struct vc_sm_released {
1784 +       /* cmd type / trans_id */
1785 +       u32 cmd;
1786 +
1787 +       /* pointer to the VC (ie physical) address of the allocated memory */
1788 +       u32 addr;
1789 +       /* size of buffer */
1790 +       u32 size;
1791 +       /* opaque handle returned in RELEASED messages */
1792 +       u32 kernel_id;
1793 +       u32 vc_handle;
1794 +};
1795 +
1796 +/*
1797 + * Client informing VC as to the protocol version it supports.
1798 + * >=2 requires the released callback, and supports VC asking for memory.
1799 + * Failure means that the firmware doesn't support this call, and therefore the
1800 + * client should either fail, or NOT rely on getting the released callback.
1801 + */
1802 +struct vc_sm_version {
1803 +       u32 version;
1804 +};
1805 +
1806 +/* Request FROM VideoCore for some memory */
1807 +struct vc_sm_vc_mem_request {
1808 +       /* cmd type */
1809 +       u32 cmd;
1810 +
1811 +       /* trans_id (from VPU) */
1812 +       u32 trans_id;
1813 +       /* size of buffer */
1814 +       u32 size;
1815 +       /* alignment of buffer */
1816 +       u32 align;
1817 +       /* resource name (for easier tracking) */
1818 +       char     name[VC_SM_RESOURCE_NAME];
1819 +};
1820 +
1821 +/* Response from the kernel to provide the VPU with some memory */
1822 +struct vc_sm_vc_mem_request_result {
1823 +       /* Transaction identifier for the VPU */
1824 +       u32 trans_id;
1825 +       /* pointer to the physical address of the allocated memory */
1826 +       u32 addr;
1827 +       /* opaque handle returned in RELEASED messages */
1828 +       u32 kernel_id;
1829 +};
1830 +
1831 +/* Union of ALL messages */
1832 +union vc_sm_msg_union_t {
1833 +       struct vc_sm_alloc_t alloc;
1834 +       struct vc_sm_alloc_result_t alloc_result;
1835 +       struct vc_sm_free_t free;
1836 +       struct vc_sm_lock_unlock_t lock_unlock;
1837 +       struct vc_sm_action_clean_t action_clean;
1838 +       struct vc_sm_resize_t resize;
1839 +       struct vc_sm_lock_result_t lock_result;
1840 +       struct vc_sm_result_t result;
1841 +       struct vc_sm_free_all_t free_all;
1842 +       struct vc_sm_import import;
1843 +       struct vc_sm_import_result import_result;
1844 +       struct vc_sm_version version;
1845 +       struct vc_sm_released released;
1846 +       struct vc_sm_vc_mem_request vc_request;
1847 +       struct vc_sm_vc_mem_request_result vc_request_result;
1848 +};
1849 +
1850 +#endif /* __VC_SM_DEFS_H__INCLUDED__ */
1851 --- /dev/null
1852 +++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm_knl.h
1853 @@ -0,0 +1,28 @@
1854 +/* SPDX-License-Identifier: GPL-2.0 */
1855 +
1856 +/*
1857 + * VideoCore Shared Memory CMA allocator
1858 + *
1859 + * Copyright: 2018, Raspberry Pi (Trading) Ltd
1860 + *
1861 + * Based on vc_sm_defs.h from the vmcs_sm driver Copyright Broadcom Corporation.
1862 + *
1863 + */
1864 +
1865 +#ifndef __VC_SM_KNL_H__INCLUDED__
1866 +#define __VC_SM_KNL_H__INCLUDED__
1867 +
1868 +#if !defined(__KERNEL__)
1869 +#error "This interface is for kernel use only..."
1870 +#endif
1871 +
1872 +/* Free a previously allocated or imported shared memory handle and block. */
1873 +int vc_sm_cma_free(int handle);
1874 +
1875 +/* Get an internal resource handle mapped from the external one. */
1876 +int vc_sm_cma_int_handle(int handle);
1877 +
1878 +/* Import a block of memory into the GPU space. */
1879 +int vc_sm_cma_import_dmabuf(struct dma_buf *dmabuf, int *handle);
1880 +
1881 +#endif /* __VC_SM_KNL_H__INCLUDED__ */