8c68e64087c4d631fa028e3619c2027d0467cdc4
[openwrt/openwrt.git] / target / linux / brcm2708 / patches-4.4 / 0038-vcsm-VideoCore-shared-memory-service-for-BCM2835.patch
1 From cd630a79b98d0406559589a658c0d0b206e523bc Mon Sep 17 00:00:00 2001
2 From: Tim Gover <tgover@broadcom.com>
3 Date: Tue, 22 Jul 2014 15:41:04 +0100
4 Subject: [PATCH 038/304] vcsm: VideoCore shared memory service for BCM2835
5 MIME-Version: 1.0
6 Content-Type: text/plain; charset=UTF-8
7 Content-Transfer-Encoding: 8bit
8
9 Add experimental support for the VideoCore shared memory service.
10 This allows user processes to allocate memory from VideoCore's
11 GPU relocatable heap and mmap the buffers. Additionally, the memory
12 handles can passed to other VideoCore services such as MMAL, OpenMax
13 and DispmanX
14
15 TODO
16 * This driver was originally released for BCM28155 which has a different
17 cache architecture to BCM2835. Consequently, in this release only
18 uncached mappings are supported. However, there's no fundamental
19 reason which cached mappings cannot be support or BCM2835
20 * More refactoring is required to remove the typedefs.
21 * Re-enable the some of the commented out debug-fs statistics which were
22 disabled when migrating code from proc-fs.
23 * There's a lot of code to support sharing of VCSM in order to support
24 Android. This could probably done more cleanly or perhaps just
25 removed.
26
27 Signed-off-by: Tim Gover <timgover@gmail.com>
28
29 config: Disable VC_SM for now to fix hang with cutdown kernel
30
31 vcsm: Use boolean as it cannot be built as module
32
33 On building the bcm_vc_sm as a module we get the following error:
34
35 v7_dma_flush_range and do_munmap are undefined in vc-sm.ko.
36
37 Fix by making it not an option to build as module
38
39 vcsm: Add ioctl for custom cache flushing
40
41 vc-sm: Move headers out of arch directory
42
43 Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
44 ---
45 drivers/char/broadcom/Kconfig | 9 +
46 drivers/char/broadcom/Makefile | 1 +
47 drivers/char/broadcom/vc_sm/Makefile | 20 +
48 drivers/char/broadcom/vc_sm/vc_sm_defs.h | 181 ++
49 drivers/char/broadcom/vc_sm/vc_sm_knl.h | 55 +
50 drivers/char/broadcom/vc_sm/vc_vchi_sm.c | 492 +++++
51 drivers/char/broadcom/vc_sm/vc_vchi_sm.h | 82 +
52 drivers/char/broadcom/vc_sm/vmcs_sm.c | 3211 ++++++++++++++++++++++++++++++
53 include/linux/broadcom/vmcs_sm_ioctl.h | 248 +++
54 9 files changed, 4299 insertions(+)
55 create mode 100644 drivers/char/broadcom/vc_sm/Makefile
56 create mode 100644 drivers/char/broadcom/vc_sm/vc_sm_defs.h
57 create mode 100644 drivers/char/broadcom/vc_sm/vc_sm_knl.h
58 create mode 100644 drivers/char/broadcom/vc_sm/vc_vchi_sm.c
59 create mode 100644 drivers/char/broadcom/vc_sm/vc_vchi_sm.h
60 create mode 100644 drivers/char/broadcom/vc_sm/vmcs_sm.c
61 create mode 100644 include/linux/broadcom/vmcs_sm_ioctl.h
62
63 --- a/drivers/char/broadcom/Kconfig
64 +++ b/drivers/char/broadcom/Kconfig
65 @@ -23,3 +23,12 @@ config BCM2708_VCMEM
66 Helper for videocore memory access and total size allocation.
67
68 endif
69 +
70 +config BCM_VC_SM
71 + bool "VMCS Shared Memory"
72 + depends on BCM2708_VCHIQ
73 + select BCM2708_VCMEM
74 + default n
75 + help
76 + Support for the VC shared memory on the Broadcom reference
77 + design. Uses the VCHIQ stack.
78 --- a/drivers/char/broadcom/Makefile
79 +++ b/drivers/char/broadcom/Makefile
80 @@ -1,2 +1,3 @@
81 obj-$(CONFIG_BCM_VC_CMA) += vc_cma/
82 obj-$(CONFIG_BCM2708_VCMEM) += vc_mem.o
83 +obj-$(CONFIG_BCM_VC_SM) += vc_sm/
84 --- /dev/null
85 +++ b/drivers/char/broadcom/vc_sm/Makefile
86 @@ -0,0 +1,20 @@
87 +EXTRA_CFLAGS += -Wall -Wstrict-prototypes -Wno-trigraphs -O2
88 +
89 +EXTRA_CFLAGS += -I"drivers/misc/vc04_services"
90 +EXTRA_CFLAGS += -I"drivers/misc/vc04_services/interface/vchi"
91 +EXTRA_CFLAGS += -I"drivers/misc/vc04_services/interface/vchiq_arm"
92 +EXTRA_CFLAGS += -I"$(srctree)/fs/"
93 +
94 +EXTRA_CFLAGS += -DOS_ASSERT_FAILURE
95 +EXTRA_CFLAGS += -D__STDC_VERSION=199901L
96 +EXTRA_CFLAGS += -D__STDC_VERSION__=199901L
97 +EXTRA_CFLAGS += -D__VCCOREVER__=0
98 +EXTRA_CFLAGS += -D__KERNEL__
99 +EXTRA_CFLAGS += -D__linux__
100 +EXTRA_CFLAGS += -Werror
101 +
102 +obj-$(CONFIG_BCM_VC_SM) := vc-sm.o
103 +
104 +vc-sm-objs := \
105 + vmcs_sm.o \
106 + vc_vchi_sm.o
107 --- /dev/null
108 +++ b/drivers/char/broadcom/vc_sm/vc_sm_defs.h
109 @@ -0,0 +1,181 @@
110 +/*****************************************************************************
111 +* Copyright 2011 Broadcom Corporation. All rights reserved.
112 +*
113 +* Unless you and Broadcom execute a separate written software license
114 +* agreement governing use of this software, this software is licensed to you
115 +* under the terms of the GNU General Public License version 2, available at
116 +* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
117 +*
118 +* Notwithstanding the above, under no circumstances may you combine this
119 +* software in any way with any other Broadcom software provided under a
120 +* license other than the GPL, without Broadcom's express prior written
121 +* consent.
122 +*****************************************************************************/
123 +
124 +#ifndef __VC_SM_DEFS_H__INCLUDED__
125 +#define __VC_SM_DEFS_H__INCLUDED__
126 +
127 +/* FourCC code used for VCHI connection */
128 +#define VC_SM_SERVER_NAME MAKE_FOURCC("SMEM")
129 +
130 +/* Maximum message length */
131 +#define VC_SM_MAX_MSG_LEN (sizeof(VC_SM_MSG_UNION_T) + \
132 + sizeof(VC_SM_MSG_HDR_T))
133 +#define VC_SM_MAX_RSP_LEN (sizeof(VC_SM_MSG_UNION_T))
134 +
135 +/* Resource name maximum size */
136 +#define VC_SM_RESOURCE_NAME 32
137 +
138 +/* All message types supported for HOST->VC direction */
139 +typedef enum {
140 + /* Allocate shared memory block */
141 + VC_SM_MSG_TYPE_ALLOC,
142 + /* Lock allocated shared memory block */
143 + VC_SM_MSG_TYPE_LOCK,
144 + /* Unlock allocated shared memory block */
145 + VC_SM_MSG_TYPE_UNLOCK,
146 + /* Unlock allocated shared memory block, do not answer command */
147 + VC_SM_MSG_TYPE_UNLOCK_NOANS,
148 + /* Free shared memory block */
149 + VC_SM_MSG_TYPE_FREE,
150 + /* Resize a shared memory block */
151 + VC_SM_MSG_TYPE_RESIZE,
152 + /* Walk the allocated shared memory block(s) */
153 + VC_SM_MSG_TYPE_WALK_ALLOC,
154 +
155 + /* A previously applied action will need to be reverted */
156 + VC_SM_MSG_TYPE_ACTION_CLEAN,
157 + VC_SM_MSG_TYPE_MAX
158 +} VC_SM_MSG_TYPE;
159 +
160 +/* Type of memory to be allocated */
161 +typedef enum {
162 + VC_SM_ALLOC_CACHED,
163 + VC_SM_ALLOC_NON_CACHED,
164 +
165 +} VC_SM_ALLOC_TYPE_T;
166 +
167 +/* Message header for all messages in HOST->VC direction */
168 +typedef struct {
169 + int32_t type;
170 + uint32_t trans_id;
171 + uint8_t body[0];
172 +
173 +} VC_SM_MSG_HDR_T;
174 +
175 +/* Request to allocate memory (HOST->VC) */
176 +typedef struct {
177 + /* type of memory to allocate */
178 + VC_SM_ALLOC_TYPE_T type;
179 + /* byte amount of data to allocate per unit */
180 + uint32_t base_unit;
181 + /* number of unit to allocate */
182 + uint32_t num_unit;
183 + /* alignement to be applied on allocation */
184 + uint32_t alignement;
185 + /* identity of who allocated this block */
186 + uint32_t allocator;
187 + /* resource name (for easier tracking on vc side) */
188 + char name[VC_SM_RESOURCE_NAME];
189 +
190 +} VC_SM_ALLOC_T;
191 +
192 +/* Result of a requested memory allocation (VC->HOST) */
193 +typedef struct {
194 + /* Transaction identifier */
195 + uint32_t trans_id;
196 +
197 + /* Resource handle */
198 + uint32_t res_handle;
199 + /* Pointer to resource buffer */
200 + void *res_mem;
201 + /* Resource base size (bytes) */
202 + uint32_t res_base_size;
203 + /* Resource number */
204 + uint32_t res_num;
205 +
206 +} VC_SM_ALLOC_RESULT_T;
207 +
208 +/* Request to free a previously allocated memory (HOST->VC) */
209 +typedef struct {
210 + /* Resource handle (returned from alloc) */
211 + uint32_t res_handle;
212 + /* Resource buffer (returned from alloc) */
213 + void *res_mem;
214 +
215 +} VC_SM_FREE_T;
216 +
217 +/* Request to lock a previously allocated memory (HOST->VC) */
218 +typedef struct {
219 + /* Resource handle (returned from alloc) */
220 + uint32_t res_handle;
221 + /* Resource buffer (returned from alloc) */
222 + void *res_mem;
223 +
224 +} VC_SM_LOCK_UNLOCK_T;
225 +
226 +/* Request to resize a previously allocated memory (HOST->VC) */
227 +typedef struct {
228 + /* Resource handle (returned from alloc) */
229 + uint32_t res_handle;
230 + /* Resource buffer (returned from alloc) */
231 + void *res_mem;
232 + /* Resource *new* size requested (bytes) */
233 + uint32_t res_new_size;
234 +
235 +} VC_SM_RESIZE_T;
236 +
237 +/* Result of a requested memory lock (VC->HOST) */
238 +typedef struct {
239 + /* Transaction identifier */
240 + uint32_t trans_id;
241 +
242 + /* Resource handle */
243 + uint32_t res_handle;
244 + /* Pointer to resource buffer */
245 + void *res_mem;
246 + /* Pointer to former resource buffer if the memory
247 + * was reallocated */
248 + void *res_old_mem;
249 +
250 +} VC_SM_LOCK_RESULT_T;
251 +
252 +/* Generic result for a request (VC->HOST) */
253 +typedef struct {
254 + /* Transaction identifier */
255 + uint32_t trans_id;
256 +
257 + int32_t success;
258 +
259 +} VC_SM_RESULT_T;
260 +
261 +/* Request to revert a previously applied action (HOST->VC) */
262 +typedef struct {
263 + /* Action of interest */
264 + VC_SM_MSG_TYPE res_action;
265 + /* Transaction identifier for the action of interest */
266 + uint32_t action_trans_id;
267 +
268 +} VC_SM_ACTION_CLEAN_T;
269 +
270 +/* Request to remove all data associated with a given allocator (HOST->VC) */
271 +typedef struct {
272 + /* Allocator identifier */
273 + uint32_t allocator;
274 +
275 +} VC_SM_FREE_ALL_T;
276 +
277 +/* Union of ALL messages */
278 +typedef union {
279 + VC_SM_ALLOC_T alloc;
280 + VC_SM_ALLOC_RESULT_T alloc_result;
281 + VC_SM_FREE_T free;
282 + VC_SM_ACTION_CLEAN_T action_clean;
283 + VC_SM_RESIZE_T resize;
284 + VC_SM_LOCK_RESULT_T lock_result;
285 + VC_SM_RESULT_T result;
286 + VC_SM_FREE_ALL_T free_all;
287 +
288 +} VC_SM_MSG_UNION_T;
289 +
290 +#endif /* __VC_SM_DEFS_H__INCLUDED__ */
291 --- /dev/null
292 +++ b/drivers/char/broadcom/vc_sm/vc_sm_knl.h
293 @@ -0,0 +1,55 @@
294 +/*****************************************************************************
295 +* Copyright 2011 Broadcom Corporation. All rights reserved.
296 +*
297 +* Unless you and Broadcom execute a separate written software license
298 +* agreement governing use of this software, this software is licensed to you
299 +* under the terms of the GNU General Public License version 2, available at
300 +* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
301 +*
302 +* Notwithstanding the above, under no circumstances may you combine this
303 +* software in any way with any other Broadcom software provided under a
304 +* license other than the GPL, without Broadcom's express prior written
305 +* consent.
306 +*****************************************************************************/
307 +
308 +#ifndef __VC_SM_KNL_H__INCLUDED__
309 +#define __VC_SM_KNL_H__INCLUDED__
310 +
311 +#if !defined(__KERNEL__)
312 +#error "This interface is for kernel use only..."
313 +#endif
314 +
315 +/* Type of memory to be locked (ie mapped) */
316 +typedef enum {
317 + VC_SM_LOCK_CACHED,
318 + VC_SM_LOCK_NON_CACHED,
319 +
320 +} VC_SM_LOCK_CACHE_MODE_T;
321 +
322 +/* Allocate a shared memory handle and block.
323 +*/
324 +int vc_sm_alloc(VC_SM_ALLOC_T *alloc, int *handle);
325 +
326 +/* Free a previously allocated shared memory handle and block.
327 +*/
328 +int vc_sm_free(int handle);
329 +
330 +/* Lock a memory handle for use by kernel.
331 +*/
332 +int vc_sm_lock(int handle, VC_SM_LOCK_CACHE_MODE_T mode,
333 + long unsigned int *data);
334 +
335 +/* Unlock a memory handle in use by kernel.
336 +*/
337 +int vc_sm_unlock(int handle, int flush, int no_vc_unlock);
338 +
339 +/* Get an internal resource handle mapped from the external one.
340 +*/
341 +int vc_sm_int_handle(int handle);
342 +
343 +/* Map a shared memory region for use by kernel.
344 +*/
345 +int vc_sm_map(int handle, unsigned int sm_addr, VC_SM_LOCK_CACHE_MODE_T mode,
346 + long unsigned int *data);
347 +
348 +#endif /* __VC_SM_KNL_H__INCLUDED__ */
349 --- /dev/null
350 +++ b/drivers/char/broadcom/vc_sm/vc_vchi_sm.c
351 @@ -0,0 +1,492 @@
352 +/*****************************************************************************
353 +* Copyright 2011-2012 Broadcom Corporation. All rights reserved.
354 +*
355 +* Unless you and Broadcom execute a separate written software license
356 +* agreement governing use of this software, this software is licensed to you
357 +* under the terms of the GNU General Public License version 2, available at
358 +* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
359 +*
360 +* Notwithstanding the above, under no circumstances may you combine this
361 +* software in any way with any other Broadcom software provided under a
362 +* license other than the GPL, without Broadcom's express prior written
363 +* consent.
364 +*****************************************************************************/
365 +
366 +/* ---- Include Files ----------------------------------------------------- */
367 +#include <linux/types.h>
368 +#include <linux/kernel.h>
369 +#include <linux/list.h>
370 +#include <linux/semaphore.h>
371 +#include <linux/mutex.h>
372 +#include <linux/slab.h>
373 +#include <linux/kthread.h>
374 +
375 +#include "vc_vchi_sm.h"
376 +
377 +#define VC_SM_VER 1
378 +#define VC_SM_MIN_VER 0
379 +
380 +/* ---- Private Constants and Types -------------------------------------- */
381 +
382 +/* Command blocks come from a pool */
383 +#define SM_MAX_NUM_CMD_RSP_BLKS 32
384 +
385 +struct sm_cmd_rsp_blk {
386 + struct list_head head; /* To create lists */
387 + struct semaphore sema; /* To be signaled when the response is there */
388 +
389 + uint16_t id;
390 + uint16_t length;
391 +
392 + uint8_t msg[VC_SM_MAX_MSG_LEN];
393 +
394 + uint32_t wait:1;
395 + uint32_t sent:1;
396 + uint32_t alloc:1;
397 +
398 +};
399 +
400 +struct sm_instance {
401 + uint32_t num_connections;
402 + VCHI_SERVICE_HANDLE_T vchi_handle[VCHI_MAX_NUM_CONNECTIONS];
403 + struct task_struct *io_thread;
404 + struct semaphore io_sema;
405 +
406 + uint32_t trans_id;
407 +
408 + struct mutex lock;
409 + struct list_head cmd_list;
410 + struct list_head rsp_list;
411 + struct list_head dead_list;
412 +
413 + struct sm_cmd_rsp_blk free_blk[SM_MAX_NUM_CMD_RSP_BLKS];
414 + struct list_head free_list;
415 + struct mutex free_lock;
416 + struct semaphore free_sema;
417 +
418 +};
419 +
420 +/* ---- Private Variables ------------------------------------------------ */
421 +
422 +/* ---- Private Function Prototypes -------------------------------------- */
423 +
424 +/* ---- Private Functions ------------------------------------------------ */
425 +static struct
426 +sm_cmd_rsp_blk *vc_vchi_cmd_create(struct sm_instance *instance,
427 + VC_SM_MSG_TYPE id, void *msg,
428 + uint32_t size, int wait)
429 +{
430 + struct sm_cmd_rsp_blk *blk;
431 + VC_SM_MSG_HDR_T *hdr;
432 +
433 + if (down_interruptible(&instance->free_sema)) {
434 + blk = kmalloc(sizeof(*blk), GFP_KERNEL);
435 + if (!blk)
436 + return NULL;
437 +
438 + blk->alloc = 1;
439 + sema_init(&blk->sema, 0);
440 + } else {
441 + mutex_lock(&instance->free_lock);
442 + blk =
443 + list_first_entry(&instance->free_list,
444 + struct sm_cmd_rsp_blk, head);
445 + list_del(&blk->head);
446 + mutex_unlock(&instance->free_lock);
447 + }
448 +
449 + blk->sent = 0;
450 + blk->wait = wait;
451 + blk->length = sizeof(*hdr) + size;
452 +
453 + hdr = (VC_SM_MSG_HDR_T *) blk->msg;
454 + hdr->type = id;
455 + mutex_lock(&instance->lock);
456 + hdr->trans_id = blk->id = ++instance->trans_id;
457 + mutex_unlock(&instance->lock);
458 +
459 + if (size)
460 + memcpy(hdr->body, msg, size);
461 +
462 + return blk;
463 +}
464 +
465 +static void
466 +vc_vchi_cmd_delete(struct sm_instance *instance, struct sm_cmd_rsp_blk *blk)
467 +{
468 + if (blk->alloc) {
469 + kfree(blk);
470 + return;
471 + }
472 +
473 + mutex_lock(&instance->free_lock);
474 + list_add(&blk->head, &instance->free_list);
475 + mutex_unlock(&instance->free_lock);
476 + up(&instance->free_sema);
477 +}
478 +
479 +static int vc_vchi_sm_videocore_io(void *arg)
480 +{
481 + struct sm_instance *instance = arg;
482 + struct sm_cmd_rsp_blk *cmd = NULL, *cmd_tmp;
483 + VC_SM_RESULT_T *reply;
484 + uint32_t reply_len;
485 + int32_t status;
486 + int svc_use = 1;
487 +
488 + while (1) {
489 + if (svc_use)
490 + vchi_service_release(instance->vchi_handle[0]);
491 + svc_use = 0;
492 + if (!down_interruptible(&instance->io_sema)) {
493 + vchi_service_use(instance->vchi_handle[0]);
494 + svc_use = 1;
495 +
496 + do {
497 + unsigned int flags;
498 + /*
499 + * Get new command and move it to response list
500 + */
501 + mutex_lock(&instance->lock);
502 + if (list_empty(&instance->cmd_list)) {
503 + /* no more commands to process */
504 + mutex_unlock(&instance->lock);
505 + break;
506 + }
507 + cmd =
508 + list_first_entry(&instance->cmd_list,
509 + struct sm_cmd_rsp_blk,
510 + head);
511 + list_move(&cmd->head, &instance->rsp_list);
512 + cmd->sent = 1;
513 + mutex_unlock(&instance->lock);
514 +
515 + /* Send the command */
516 + flags = VCHI_FLAGS_BLOCK_UNTIL_QUEUED;
517 + status = vchi_msg_queue(
518 + instance->vchi_handle[0],
519 + cmd->msg, cmd->length,
520 + flags, NULL);
521 + if (status) {
522 + pr_err("%s: failed to queue message (%d)",
523 + __func__, status);
524 + }
525 +
526 + /* If no reply is needed then we're done */
527 + if (!cmd->wait) {
528 + mutex_lock(&instance->lock);
529 + list_del(&cmd->head);
530 + mutex_unlock(&instance->lock);
531 + vc_vchi_cmd_delete(instance, cmd);
532 + continue;
533 + }
534 +
535 + if (status) {
536 + up(&cmd->sema);
537 + continue;
538 + }
539 +
540 + } while (1);
541 +
542 + while (!vchi_msg_peek
543 + (instance->vchi_handle[0], (void **)&reply,
544 + &reply_len, VCHI_FLAGS_NONE)) {
545 + mutex_lock(&instance->lock);
546 + list_for_each_entry(cmd, &instance->rsp_list,
547 + head) {
548 + if (cmd->id == reply->trans_id)
549 + break;
550 + }
551 + mutex_unlock(&instance->lock);
552 +
553 + if (&cmd->head == &instance->rsp_list) {
554 + pr_debug("%s: received response %u, throw away...",
555 + __func__, reply->trans_id);
556 + } else if (reply_len > sizeof(cmd->msg)) {
557 + pr_err("%s: reply too big (%u) %u, throw away...",
558 + __func__, reply_len,
559 + reply->trans_id);
560 + } else {
561 + memcpy(cmd->msg, reply, reply_len);
562 + up(&cmd->sema);
563 + }
564 +
565 + vchi_msg_remove(instance->vchi_handle[0]);
566 + }
567 +
568 + /* Go through the dead list and free them */
569 + mutex_lock(&instance->lock);
570 + list_for_each_entry_safe(cmd, cmd_tmp,
571 + &instance->dead_list, head) {
572 + list_del(&cmd->head);
573 + vc_vchi_cmd_delete(instance, cmd);
574 + }
575 + mutex_unlock(&instance->lock);
576 + }
577 + }
578 +
579 + return 0;
580 +}
581 +
582 +static void vc_sm_vchi_callback(void *param,
583 + const VCHI_CALLBACK_REASON_T reason,
584 + void *msg_handle)
585 +{
586 + struct sm_instance *instance = param;
587 +
588 + (void)msg_handle;
589 +
590 + switch (reason) {
591 + case VCHI_CALLBACK_MSG_AVAILABLE:
592 + up(&instance->io_sema);
593 + break;
594 +
595 + case VCHI_CALLBACK_SERVICE_CLOSED:
596 + pr_info("%s: service CLOSED!!", __func__);
597 + default:
598 + break;
599 + }
600 +}
601 +
602 +VC_VCHI_SM_HANDLE_T vc_vchi_sm_init(VCHI_INSTANCE_T vchi_instance,
603 + VCHI_CONNECTION_T **vchi_connections,
604 + uint32_t num_connections)
605 +{
606 + uint32_t i;
607 + struct sm_instance *instance;
608 + int status;
609 +
610 + pr_debug("%s: start", __func__);
611 +
612 + if (num_connections > VCHI_MAX_NUM_CONNECTIONS) {
613 + pr_err("%s: unsupported number of connections %u (max=%u)",
614 + __func__, num_connections, VCHI_MAX_NUM_CONNECTIONS);
615 +
616 + goto err_null;
617 + }
618 + /* Allocate memory for this instance */
619 + instance = kzalloc(sizeof(*instance), GFP_KERNEL);
620 +
621 + /* Misc initialisations */
622 + mutex_init(&instance->lock);
623 + sema_init(&instance->io_sema, 0);
624 + INIT_LIST_HEAD(&instance->cmd_list);
625 + INIT_LIST_HEAD(&instance->rsp_list);
626 + INIT_LIST_HEAD(&instance->dead_list);
627 + INIT_LIST_HEAD(&instance->free_list);
628 + sema_init(&instance->free_sema, SM_MAX_NUM_CMD_RSP_BLKS);
629 + mutex_init(&instance->free_lock);
630 + for (i = 0; i < SM_MAX_NUM_CMD_RSP_BLKS; i++) {
631 + sema_init(&instance->free_blk[i].sema, 0);
632 + list_add(&instance->free_blk[i].head, &instance->free_list);
633 + }
634 +
635 + /* Open the VCHI service connections */
636 + instance->num_connections = num_connections;
637 + for (i = 0; i < num_connections; i++) {
638 + SERVICE_CREATION_T params = {
639 + VCHI_VERSION_EX(VC_SM_VER, VC_SM_MIN_VER),
640 + VC_SM_SERVER_NAME,
641 + vchi_connections[i],
642 + 0,
643 + 0,
644 + vc_sm_vchi_callback,
645 + instance,
646 + 0,
647 + 0,
648 + 0,
649 + };
650 +
651 + status = vchi_service_open(vchi_instance,
652 + &params, &instance->vchi_handle[i]);
653 + if (status) {
654 + pr_err("%s: failed to open VCHI service (%d)",
655 + __func__, status);
656 +
657 + goto err_close_services;
658 + }
659 + }
660 +
661 + /* Create the thread which takes care of all io to/from videoocore. */
662 + instance->io_thread = kthread_create(&vc_vchi_sm_videocore_io,
663 + (void *)instance, "SMIO");
664 + if (instance->io_thread == NULL) {
665 + pr_err("%s: failed to create SMIO thread", __func__);
666 +
667 + goto err_close_services;
668 + }
669 + set_user_nice(instance->io_thread, -10);
670 + wake_up_process(instance->io_thread);
671 +
672 + pr_debug("%s: success - instance 0x%x", __func__, (unsigned)instance);
673 + return instance;
674 +
675 +err_close_services:
676 + for (i = 0; i < instance->num_connections; i++) {
677 + if (instance->vchi_handle[i] != NULL)
678 + vchi_service_close(instance->vchi_handle[i]);
679 + }
680 + kfree(instance);
681 +err_null:
682 + pr_debug("%s: FAILED", __func__);
683 + return NULL;
684 +}
685 +
686 +int vc_vchi_sm_stop(VC_VCHI_SM_HANDLE_T *handle)
687 +{
688 + struct sm_instance *instance;
689 + uint32_t i;
690 +
691 + if (handle == NULL) {
692 + pr_err("%s: invalid pointer to handle %p", __func__, handle);
693 + goto lock;
694 + }
695 +
696 + if (*handle == NULL) {
697 + pr_err("%s: invalid handle %p", __func__, *handle);
698 + goto lock;
699 + }
700 +
701 + instance = *handle;
702 +
703 + /* Close all VCHI service connections */
704 + for (i = 0; i < instance->num_connections; i++) {
705 + int32_t success;
706 + vchi_service_use(instance->vchi_handle[i]);
707 +
708 + success = vchi_service_close(instance->vchi_handle[i]);
709 + }
710 +
711 + kfree(instance);
712 +
713 + *handle = NULL;
714 + return 0;
715 +
716 +lock:
717 + return -EINVAL;
718 +}
719 +
720 +int vc_vchi_sm_send_msg(VC_VCHI_SM_HANDLE_T handle,
721 + VC_SM_MSG_TYPE msg_id,
722 + void *msg, uint32_t msg_size,
723 + void *result, uint32_t result_size,
724 + uint32_t *cur_trans_id, uint8_t wait_reply)
725 +{
726 + int status = 0;
727 + struct sm_instance *instance = handle;
728 + struct sm_cmd_rsp_blk *cmd_blk;
729 +
730 + if (handle == NULL) {
731 + pr_err("%s: invalid handle", __func__);
732 + return -EINVAL;
733 + }
734 + if (msg == NULL) {
735 + pr_err("%s: invalid msg pointer", __func__);
736 + return -EINVAL;
737 + }
738 +
739 + cmd_blk =
740 + vc_vchi_cmd_create(instance, msg_id, msg, msg_size, wait_reply);
741 + if (cmd_blk == NULL) {
742 + pr_err("[%s]: failed to allocate global tracking resource",
743 + __func__);
744 + return -ENOMEM;
745 + }
746 +
747 + if (cur_trans_id != NULL)
748 + *cur_trans_id = cmd_blk->id;
749 +
750 + mutex_lock(&instance->lock);
751 + list_add_tail(&cmd_blk->head, &instance->cmd_list);
752 + mutex_unlock(&instance->lock);
753 + up(&instance->io_sema);
754 +
755 + if (!wait_reply)
756 + /* We're done */
757 + return 0;
758 +
759 + /* Wait for the response */
760 + if (down_interruptible(&cmd_blk->sema)) {
761 + mutex_lock(&instance->lock);
762 + if (!cmd_blk->sent) {
763 + list_del(&cmd_blk->head);
764 + mutex_unlock(&instance->lock);
765 + vc_vchi_cmd_delete(instance, cmd_blk);
766 + return -ENXIO;
767 + }
768 + mutex_unlock(&instance->lock);
769 +
770 + mutex_lock(&instance->lock);
771 + list_move(&cmd_blk->head, &instance->dead_list);
772 + mutex_unlock(&instance->lock);
773 + up(&instance->io_sema);
774 + return -EINTR; /* We're done */
775 + }
776 +
777 + if (result && result_size) {
778 + memcpy(result, cmd_blk->msg, result_size);
779 + } else {
780 + VC_SM_RESULT_T *res = (VC_SM_RESULT_T *) cmd_blk->msg;
781 + status = (res->success == 0) ? 0 : -ENXIO;
782 + }
783 +
784 + mutex_lock(&instance->lock);
785 + list_del(&cmd_blk->head);
786 + mutex_unlock(&instance->lock);
787 + vc_vchi_cmd_delete(instance, cmd_blk);
788 + return status;
789 +}
790 +
791 +int vc_vchi_sm_alloc(VC_VCHI_SM_HANDLE_T handle, VC_SM_ALLOC_T *msg,
792 + VC_SM_ALLOC_RESULT_T *result, uint32_t *cur_trans_id)
793 +{
794 + return vc_vchi_sm_send_msg(handle, VC_SM_MSG_TYPE_ALLOC,
795 + msg, sizeof(*msg), result, sizeof(*result),
796 + cur_trans_id, 1);
797 +}
798 +
799 +int vc_vchi_sm_free(VC_VCHI_SM_HANDLE_T handle,
800 + VC_SM_FREE_T *msg, uint32_t *cur_trans_id)
801 +{
802 + return vc_vchi_sm_send_msg(handle, VC_SM_MSG_TYPE_FREE,
803 + msg, sizeof(*msg), 0, 0, cur_trans_id, 0);
804 +}
805 +
806 +int vc_vchi_sm_lock(VC_VCHI_SM_HANDLE_T handle,
807 + VC_SM_LOCK_UNLOCK_T *msg,
808 + VC_SM_LOCK_RESULT_T *result, uint32_t *cur_trans_id)
809 +{
810 + return vc_vchi_sm_send_msg(handle, VC_SM_MSG_TYPE_LOCK,
811 + msg, sizeof(*msg), result, sizeof(*result),
812 + cur_trans_id, 1);
813 +}
814 +
815 +int vc_vchi_sm_unlock(VC_VCHI_SM_HANDLE_T handle,
816 + VC_SM_LOCK_UNLOCK_T *msg,
817 + uint32_t *cur_trans_id, uint8_t wait_reply)
818 +{
819 + return vc_vchi_sm_send_msg(handle, wait_reply ?
820 + VC_SM_MSG_TYPE_UNLOCK :
821 + VC_SM_MSG_TYPE_UNLOCK_NOANS, msg,
822 + sizeof(*msg), 0, 0, cur_trans_id,
823 + wait_reply);
824 +}
825 +
826 +int vc_vchi_sm_resize(VC_VCHI_SM_HANDLE_T handle, VC_SM_RESIZE_T *msg,
827 + uint32_t *cur_trans_id)
828 +{
829 + return vc_vchi_sm_send_msg(handle, VC_SM_MSG_TYPE_RESIZE,
830 + msg, sizeof(*msg), 0, 0, cur_trans_id, 1);
831 +}
832 +
833 +int vc_vchi_sm_walk_alloc(VC_VCHI_SM_HANDLE_T handle)
834 +{
835 + return vc_vchi_sm_send_msg(handle, VC_SM_MSG_TYPE_WALK_ALLOC,
836 + 0, 0, 0, 0, 0, 0);
837 +}
838 +
839 +int vc_vchi_sm_clean_up(VC_VCHI_SM_HANDLE_T handle, VC_SM_ACTION_CLEAN_T *msg)
840 +{
841 + return vc_vchi_sm_send_msg(handle, VC_SM_MSG_TYPE_ACTION_CLEAN,
842 + msg, sizeof(*msg), 0, 0, 0, 0);
843 +}
844 --- /dev/null
845 +++ b/drivers/char/broadcom/vc_sm/vc_vchi_sm.h
846 @@ -0,0 +1,82 @@
847 +/*****************************************************************************
848 +* Copyright 2011 Broadcom Corporation. All rights reserved.
849 +*
850 +* Unless you and Broadcom execute a separate written software license
851 +* agreement governing use of this software, this software is licensed to you
852 +* under the terms of the GNU General Public License version 2, available at
853 +* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
854 +*
855 +* Notwithstanding the above, under no circumstances may you combine this
856 +* software in any way with any other Broadcom software provided under a
857 +* license other than the GPL, without Broadcom's express prior written
858 +* consent.
859 +*****************************************************************************/
860 +
861 +#ifndef __VC_VCHI_SM_H__INCLUDED__
862 +#define __VC_VCHI_SM_H__INCLUDED__
863 +
864 +#include "interface/vchi/vchi.h"
865 +
866 +#include "vc_sm_defs.h"
867 +
868 +/* Forward declare.
869 +*/
870 +typedef struct sm_instance *VC_VCHI_SM_HANDLE_T;
871 +
872 +/* Initialize the shared memory service, opens up vchi connection to talk to it.
873 +*/
874 +VC_VCHI_SM_HANDLE_T vc_vchi_sm_init(VCHI_INSTANCE_T vchi_instance,
875 + VCHI_CONNECTION_T **vchi_connections,
876 + uint32_t num_connections);
877 +
878 +/* Terminates the shared memory service.
879 +*/
880 +int vc_vchi_sm_stop(VC_VCHI_SM_HANDLE_T *handle);
881 +
882 +/* Ask the shared memory service to allocate some memory on videocre and
883 +** return the result of this allocation (which upon success will be a pointer
884 +** to some memory in videocore space).
885 +*/
886 +int vc_vchi_sm_alloc(VC_VCHI_SM_HANDLE_T handle,
887 + VC_SM_ALLOC_T *alloc,
888 + VC_SM_ALLOC_RESULT_T *alloc_result, uint32_t *trans_id);
889 +
890 +/* Ask the shared memory service to free up some memory that was previously
891 +** allocated by the vc_vchi_sm_alloc function call.
892 +*/
893 +int vc_vchi_sm_free(VC_VCHI_SM_HANDLE_T handle,
894 + VC_SM_FREE_T *free, uint32_t *trans_id);
895 +
896 +/* Ask the shared memory service to lock up some memory that was previously
897 +** allocated by the vc_vchi_sm_alloc function call.
898 +*/
899 +int vc_vchi_sm_lock(VC_VCHI_SM_HANDLE_T handle,
900 + VC_SM_LOCK_UNLOCK_T *lock_unlock,
901 + VC_SM_LOCK_RESULT_T *lock_result, uint32_t *trans_id);
902 +
903 +/* Ask the shared memory service to unlock some memory that was previously
904 +** allocated by the vc_vchi_sm_alloc function call.
905 +*/
906 +int vc_vchi_sm_unlock(VC_VCHI_SM_HANDLE_T handle,
907 + VC_SM_LOCK_UNLOCK_T *lock_unlock,
908 + uint32_t *trans_id, uint8_t wait_reply);
909 +
910 +/* Ask the shared memory service to resize some memory that was previously
911 +** allocated by the vc_vchi_sm_alloc function call.
912 +*/
913 +int vc_vchi_sm_resize(VC_VCHI_SM_HANDLE_T handle,
914 + VC_SM_RESIZE_T *resize, uint32_t *trans_id);
915 +
916 +/* Walk the allocated resources on the videocore side, the allocation will
917 +** show up in the log. This is purely for debug/information and takes no
918 +** specific actions.
919 +*/
920 +int vc_vchi_sm_walk_alloc(VC_VCHI_SM_HANDLE_T handle);
921 +
922 +/* Clean up following a previously interrupted action which left the system
923 +** in a bad state of some sort.
924 +*/
925 +int vc_vchi_sm_clean_up(VC_VCHI_SM_HANDLE_T handle,
926 + VC_SM_ACTION_CLEAN_T *action_clean);
927 +
928 +#endif /* __VC_VCHI_SM_H__INCLUDED__ */
929 --- /dev/null
930 +++ b/drivers/char/broadcom/vc_sm/vmcs_sm.c
931 @@ -0,0 +1,3211 @@
932 +/*****************************************************************************
933 +* Copyright 2011-2012 Broadcom Corporation. All rights reserved.
934 +*
935 +* Unless you and Broadcom execute a separate written software license
936 +* agreement governing use of this software, this software is licensed to you
937 +* under the terms of the GNU General Public License version 2, available at
938 +* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
939 +*
940 +* Notwithstanding the above, under no circumstances may you combine this
941 +* software in any way with any other Broadcom software provided under a
942 +* license other than the GPL, without Broadcom's express prior written
943 +* consent.
944 +*****************************************************************************/
945 +
946 +/* ---- Include Files ----------------------------------------------------- */
947 +
948 +#include <linux/cdev.h>
949 +#include <linux/broadcom/vc_mem.h>
950 +#include <linux/device.h>
951 +#include <linux/debugfs.h>
952 +#include <linux/dma-mapping.h>
953 +#include <linux/errno.h>
954 +#include <linux/fs.h>
955 +#include <linux/hugetlb.h>
956 +#include <linux/ioctl.h>
957 +#include <linux/kernel.h>
958 +#include <linux/list.h>
959 +#include <linux/module.h>
960 +#include <linux/mm.h>
961 +#include <linux/pfn.h>
962 +#include <linux/proc_fs.h>
963 +#include <linux/pagemap.h>
964 +#include <linux/semaphore.h>
965 +#include <linux/slab.h>
966 +#include <linux/seq_file.h>
967 +#include <linux/types.h>
968 +#include <asm/cacheflush.h>
969 +
970 +#include "vchiq_connected.h"
971 +#include "vc_vchi_sm.h"
972 +
973 +#include <linux/broadcom/vmcs_sm_ioctl.h>
974 +#include "vc_sm_knl.h"
975 +
976 +/* ---- Private Constants and Types --------------------------------------- */
977 +
978 +#define DEVICE_NAME "vcsm"
979 +#define DEVICE_MINOR 0
980 +
981 +#define VC_SM_DIR_ROOT_NAME "vc-smem"
982 +#define VC_SM_DIR_ALLOC_NAME "alloc"
983 +#define VC_SM_STATE "state"
984 +#define VC_SM_STATS "statistics"
985 +#define VC_SM_RESOURCES "resources"
986 +#define VC_SM_DEBUG "debug"
987 +#define VC_SM_WRITE_BUF_SIZE 128
988 +
989 +/* Statistics tracked per resource and globally.
990 +*/
991 +enum SM_STATS_T {
992 + /* Attempt. */
993 + ALLOC,
994 + FREE,
995 + LOCK,
996 + UNLOCK,
997 + MAP,
998 + FLUSH,
999 + INVALID,
1000 +
1001 + END_ATTEMPT,
1002 +
1003 + /* Failure. */
1004 + ALLOC_FAIL,
1005 + FREE_FAIL,
1006 + LOCK_FAIL,
1007 + UNLOCK_FAIL,
1008 + MAP_FAIL,
1009 + FLUSH_FAIL,
1010 + INVALID_FAIL,
1011 +
1012 + END_ALL,
1013 +
1014 +};
1015 +
1016 +static const char *const sm_stats_human_read[] = {
1017 + "Alloc",
1018 + "Free",
1019 + "Lock",
1020 + "Unlock",
1021 + "Map",
1022 + "Cache Flush",
1023 + "Cache Invalidate",
1024 +};
1025 +
1026 +typedef int (*VC_SM_SHOW) (struct seq_file *s, void *v);
1027 +struct SM_PDE_T {
1028 + VC_SM_SHOW show; /* Debug fs function hookup. */
1029 + struct dentry *dir_entry; /* Debug fs directory entry. */
1030 + void *priv_data; /* Private data */
1031 +
1032 +};
1033 +
1034 +/* Single resource allocation tracked for all devices.
1035 +*/
1036 +struct sm_mmap {
1037 + struct list_head map_list; /* Linked list of maps. */
1038 +
1039 + struct SM_RESOURCE_T *resource; /* Pointer to the resource. */
1040 +
1041 + pid_t res_pid; /* PID owning that resource. */
1042 + unsigned int res_vc_hdl; /* Resource handle (videocore). */
1043 + unsigned int res_usr_hdl; /* Resource handle (user). */
1044 +
1045 + long unsigned int res_addr; /* Mapped virtual address. */
1046 + struct vm_area_struct *vma; /* VM area for this mapping. */
1047 + unsigned int ref_count; /* Reference count to this vma. */
1048 +
1049 + /* Used to link maps associated with a resource. */
1050 + struct list_head resource_map_list;
1051 +};
1052 +
1053 +/* Single resource allocation tracked for each opened device.
1054 +*/
1055 +struct SM_RESOURCE_T {
1056 + struct list_head resource_list; /* List of resources. */
1057 + struct list_head global_resource_list; /* Global list of resources. */
1058 +
1059 + pid_t pid; /* PID owning that resource. */
1060 + uint32_t res_guid; /* Unique identifier. */
1061 + uint32_t lock_count; /* Lock count for this resource. */
1062 + uint32_t ref_count; /* Ref count for this resource. */
1063 +
1064 + uint32_t res_handle; /* Resource allocation handle. */
1065 + void *res_base_mem; /* Resource base memory address. */
1066 + uint32_t res_size; /* Resource size allocated. */
1067 + enum vmcs_sm_cache_e res_cached; /* Resource cache type. */
1068 + struct SM_RESOURCE_T *res_shared; /* Shared resource */
1069 +
1070 + enum SM_STATS_T res_stats[END_ALL]; /* Resource statistics. */
1071 +
1072 + uint8_t map_count; /* Counter of mappings for this resource. */
1073 + struct list_head map_list; /* Maps associated with a resource. */
1074 +
1075 + struct SM_PRIV_DATA_T *private;
1076 +};
1077 +
1078 +/* Private file data associated with each opened device.
1079 +*/
1080 +struct SM_PRIV_DATA_T {
1081 + struct list_head resource_list; /* List of resources. */
1082 +
1083 + pid_t pid; /* PID of creator. */
1084 +
1085 + struct dentry *dir_pid; /* Debug fs entries root. */
1086 + struct SM_PDE_T dir_stats; /* Debug fs entries statistics sub-tree. */
1087 + struct SM_PDE_T dir_res; /* Debug fs resource sub-tree. */
1088 +
1089 + int restart_sys; /* Tracks restart on interrupt. */
1090 + VC_SM_MSG_TYPE int_action; /* Interrupted action. */
1091 + uint32_t int_trans_id; /* Interrupted transaction. */
1092 +
1093 +};
1094 +
1095 +/* Global state information.
1096 +*/
1097 +struct SM_STATE_T {
1098 + VC_VCHI_SM_HANDLE_T sm_handle; /* Handle for videocore service. */
1099 + struct dentry *dir_root; /* Debug fs entries root. */
1100 + struct dentry *dir_alloc; /* Debug fs entries allocations. */
1101 + struct SM_PDE_T dir_stats; /* Debug fs entries statistics sub-tree. */
1102 + struct SM_PDE_T dir_state; /* Debug fs entries state sub-tree. */
1103 + struct dentry *debug; /* Debug fs entries debug. */
1104 +
1105 + struct mutex map_lock; /* Global map lock. */
1106 + struct list_head map_list; /* List of maps. */
1107 + struct list_head resource_list; /* List of resources. */
1108 +
1109 + enum SM_STATS_T deceased[END_ALL]; /* Natural termination stats. */
1110 + enum SM_STATS_T terminated[END_ALL]; /* Forced termination stats. */
1111 + uint32_t res_deceased_cnt; /* Natural termination counter. */
1112 + uint32_t res_terminated_cnt; /* Forced termination counter. */
1113 +
1114 + struct cdev sm_cdev; /* Device. */
1115 + dev_t sm_devid; /* Device identifier. */
1116 + struct class *sm_class; /* Class. */
1117 + struct device *sm_dev; /* Device. */
1118 +
1119 + struct SM_PRIV_DATA_T *data_knl; /* Kernel internal data tracking. */
1120 +
1121 + struct mutex lock; /* Global lock. */
1122 + uint32_t guid; /* GUID (next) tracker. */
1123 +
1124 +};
1125 +
1126 +/* ---- Private Variables ----------------------------------------------- */
1127 +
1128 +static struct SM_STATE_T *sm_state;
1129 +static int sm_inited;
1130 +
1131 +static const char *const sm_cache_map_vector[] = {
1132 + "(null)",
1133 + "host",
1134 + "videocore",
1135 + "host+videocore",
1136 +};
1137 +
1138 +/* ---- Private Function Prototypes -------------------------------------- */
1139 +
1140 +/* ---- Private Functions ------------------------------------------------ */
1141 +
1142 +static inline unsigned vcaddr_to_pfn(unsigned long vc_addr)
1143 +{
1144 + unsigned long pfn = vc_addr & 0x3FFFFFFF;
1145 + pfn += mm_vc_mem_phys_addr;
1146 + pfn >>= PAGE_SHIFT;
1147 + return pfn;
1148 +}
1149 +
1150 +/* Carries over to the state statistics the statistics once owned by a deceased
1151 +** resource.
1152 +*/
1153 +static void vc_sm_resource_deceased(struct SM_RESOURCE_T *p_res, int terminated)
1154 +{
1155 + if (sm_state != NULL) {
1156 + if (p_res != NULL) {
1157 + int ix;
1158 +
1159 + if (terminated)
1160 + sm_state->res_terminated_cnt++;
1161 + else
1162 + sm_state->res_deceased_cnt++;
1163 +
1164 + for (ix = 0; ix < END_ALL; ix++) {
1165 + if (terminated)
1166 + sm_state->terminated[ix] +=
1167 + p_res->res_stats[ix];
1168 + else
1169 + sm_state->deceased[ix] +=
1170 + p_res->res_stats[ix];
1171 + }
1172 + }
1173 + }
1174 +}
1175 +
1176 +/* Fetch a videocore handle corresponding to a mapping of the pid+address
1177 +** returns 0 (ie NULL) if no such handle exists in the global map.
1178 +*/
1179 +static unsigned int vmcs_sm_vc_handle_from_pid_and_address(unsigned int pid,
1180 + unsigned int addr)
1181 +{
1182 + struct sm_mmap *map = NULL;
1183 + unsigned int handle = 0;
1184 +
1185 + if (!sm_state || addr == 0)
1186 + goto out;
1187 +
1188 + mutex_lock(&(sm_state->map_lock));
1189 +
1190 + /* Lookup the resource.
1191 + */
1192 + if (!list_empty(&sm_state->map_list)) {
1193 + list_for_each_entry(map, &sm_state->map_list, map_list) {
1194 + if (map->res_pid != pid || map->res_addr != addr)
1195 + continue;
1196 +
1197 + pr_debug("[%s]: global map %p (pid %u, addr %lx) -> vc-hdl %x (usr-hdl %x)\n",
1198 + __func__, map, map->res_pid, map->res_addr,
1199 + map->res_vc_hdl, map->res_usr_hdl);
1200 +
1201 + handle = map->res_vc_hdl;
1202 + break;
1203 + }
1204 + }
1205 +
1206 + mutex_unlock(&(sm_state->map_lock));
1207 +
1208 +out:
1209 + /* Use a debug log here as it may be a valid situation that we query
1210 + ** for something that is not mapped, we do not want a kernel log each
1211 + ** time around.
1212 + **
1213 + ** There are other error log that would pop up accordingly if someone
1214 + ** subsequently tries to use something invalid after being told not to
1215 + ** use it...
1216 + */
1217 + if (handle == 0) {
1218 + pr_debug("[%s]: not a valid map (pid %u, addr %x)\n",
1219 + __func__, pid, addr);
1220 + }
1221 +
1222 + return handle;
1223 +}
1224 +
1225 +/* Fetch a user handle corresponding to a mapping of the pid+address
1226 +** returns 0 (ie NULL) if no such handle exists in the global map.
1227 +*/
1228 +static unsigned int vmcs_sm_usr_handle_from_pid_and_address(unsigned int pid,
1229 + unsigned int addr)
1230 +{
1231 + struct sm_mmap *map = NULL;
1232 + unsigned int handle = 0;
1233 +
1234 + if (!sm_state || addr == 0)
1235 + goto out;
1236 +
1237 + mutex_lock(&(sm_state->map_lock));
1238 +
1239 + /* Lookup the resource.
1240 + */
1241 + if (!list_empty(&sm_state->map_list)) {
1242 + list_for_each_entry(map, &sm_state->map_list, map_list) {
1243 + if (map->res_pid != pid || map->res_addr != addr)
1244 + continue;
1245 +
1246 + pr_debug("[%s]: global map %p (pid %u, addr %lx) -> usr-hdl %x (vc-hdl %x)\n",
1247 + __func__, map, map->res_pid, map->res_addr,
1248 + map->res_usr_hdl, map->res_vc_hdl);
1249 +
1250 + handle = map->res_usr_hdl;
1251 + break;
1252 + }
1253 + }
1254 +
1255 + mutex_unlock(&(sm_state->map_lock));
1256 +
1257 +out:
1258 + /* Use a debug log here as it may be a valid situation that we query
1259 + * for something that is not mapped yet.
1260 + *
1261 + * There are other error log that would pop up accordingly if someone
1262 + * subsequently tries to use something invalid after being told not to
1263 + * use it...
1264 + */
1265 + if (handle == 0)
1266 + pr_debug("[%s]: not a valid map (pid %u, addr %x)\n",
1267 + __func__, pid, addr);
1268 +
1269 + return handle;
1270 +}
1271 +
1272 +#if defined(DO_NOT_USE)
1273 +/* Fetch an address corresponding to a mapping of the pid+handle
1274 +** returns 0 (ie NULL) if no such address exists in the global map.
1275 +*/
1276 +static unsigned int vmcs_sm_usr_address_from_pid_and_vc_handle(unsigned int pid,
1277 + unsigned int hdl)
1278 +{
1279 + struct sm_mmap *map = NULL;
1280 + unsigned int addr = 0;
1281 +
1282 + if (sm_state == NULL || hdl == 0)
1283 + goto out;
1284 +
1285 + mutex_lock(&(sm_state->map_lock));
1286 +
1287 + /* Lookup the resource.
1288 + */
1289 + if (!list_empty(&sm_state->map_list)) {
1290 + list_for_each_entry(map, &sm_state->map_list, map_list) {
1291 + if (map->res_pid != pid || map->res_vc_hdl != hdl)
1292 + continue;
1293 +
1294 + pr_debug("[%s]: global map %p (pid %u, vc-hdl %x, usr-hdl %x) -> addr %lx\n",
1295 + __func__, map, map->res_pid, map->res_vc_hdl,
1296 + map->res_usr_hdl, map->res_addr);
1297 +
1298 + addr = map->res_addr;
1299 + break;
1300 + }
1301 + }
1302 +
1303 + mutex_unlock(&(sm_state->map_lock));
1304 +
1305 +out:
1306 + /* Use a debug log here as it may be a valid situation that we query
1307 + ** for something that is not mapped, we do not want a kernel log each
1308 + ** time around.
1309 + **
1310 + ** There are other error log that would pop up accordingly if someone
1311 + ** subsequently tries to use something invalid after being told not to
1312 + ** use it...
1313 + */
1314 + if (addr == 0)
1315 + pr_debug("[%s]: not a valid map (pid %u, hdl %x)\n",
1316 + __func__, pid, hdl);
1317 +
1318 + return addr;
1319 +}
1320 +#endif
1321 +
1322 +/* Fetch an address corresponding to a mapping of the pid+handle
1323 +** returns 0 (ie NULL) if no such address exists in the global map.
1324 +*/
1325 +static unsigned int vmcs_sm_usr_address_from_pid_and_usr_handle(unsigned int
1326 + pid,
1327 + unsigned int
1328 + hdl)
1329 +{
1330 + struct sm_mmap *map = NULL;
1331 + unsigned int addr = 0;
1332 +
1333 + if (sm_state == NULL || hdl == 0)
1334 + goto out;
1335 +
1336 + mutex_lock(&(sm_state->map_lock));
1337 +
1338 + /* Lookup the resource.
1339 + */
1340 + if (!list_empty(&sm_state->map_list)) {
1341 + list_for_each_entry(map, &sm_state->map_list, map_list) {
1342 + if (map->res_pid != pid || map->res_usr_hdl != hdl)
1343 + continue;
1344 +
1345 + pr_debug("[%s]: global map %p (pid %u, vc-hdl %x, usr-hdl %x) -> addr %lx\n",
1346 + __func__, map, map->res_pid, map->res_vc_hdl,
1347 + map->res_usr_hdl, map->res_addr);
1348 +
1349 + addr = map->res_addr;
1350 + break;
1351 + }
1352 + }
1353 +
1354 + mutex_unlock(&(sm_state->map_lock));
1355 +
1356 +out:
1357 + /* Use a debug log here as it may be a valid situation that we query
1358 + * for something that is not mapped, we do not want a kernel log each
1359 + * time around.
1360 + *
1361 + * There are other error log that would pop up accordingly if someone
1362 + * subsequently tries to use something invalid after being told not to
1363 + * use it...
1364 + */
1365 + if (addr == 0)
1366 + pr_debug("[%s]: not a valid map (pid %u, hdl %x)\n", __func__,
1367 + pid, hdl);
1368 +
1369 + return addr;
1370 +}
1371 +
1372 +/* Adds a resource mapping to the global data list.
1373 +*/
1374 +static void vmcs_sm_add_map(struct SM_STATE_T *state,
1375 + struct SM_RESOURCE_T *resource, struct sm_mmap *map)
1376 +{
1377 + mutex_lock(&(state->map_lock));
1378 +
1379 + /* Add to the global list of mappings
1380 + */
1381 + list_add(&map->map_list, &state->map_list);
1382 +
1383 + /* Add to the list of mappings for this resource
1384 + */
1385 + list_add(&map->resource_map_list, &resource->map_list);
1386 + resource->map_count++;
1387 +
1388 + mutex_unlock(&(state->map_lock));
1389 +
1390 + pr_debug("[%s]: added map %p (pid %u, vc-hdl %x, usr-hdl %x, addr %lx)\n",
1391 + __func__, map, map->res_pid, map->res_vc_hdl,
1392 + map->res_usr_hdl, map->res_addr);
1393 +}
1394 +
1395 +/* Removes a resource mapping from the global data list.
1396 +*/
1397 +static void vmcs_sm_remove_map(struct SM_STATE_T *state,
1398 + struct SM_RESOURCE_T *resource,
1399 + struct sm_mmap *map)
1400 +{
1401 + mutex_lock(&(state->map_lock));
1402 +
1403 + /* Remove from the global list of mappings
1404 + */
1405 + list_del(&map->map_list);
1406 +
1407 + /* Remove from the list of mapping for this resource
1408 + */
1409 + list_del(&map->resource_map_list);
1410 + if (resource->map_count > 0)
1411 + resource->map_count--;
1412 +
1413 + mutex_unlock(&(state->map_lock));
1414 +
1415 + pr_debug("[%s]: removed map %p (pid %d, vc-hdl %x, usr-hdl %x, addr %lx)\n",
1416 + __func__, map, map->res_pid, map->res_vc_hdl, map->res_usr_hdl,
1417 + map->res_addr);
1418 +
1419 + kfree(map);
1420 +}
1421 +
1422 +/* Read callback for the global state proc entry.
1423 +*/
1424 +static int vc_sm_global_state_show(struct seq_file *s, void *v)
1425 +{
1426 + struct sm_mmap *map = NULL;
1427 + int map_count = 0;
1428 +
1429 + if (sm_state == NULL)
1430 + return 0;
1431 +
1432 + seq_printf(s, "\nVC-ServiceHandle 0x%x\n",
1433 + (unsigned int)sm_state->sm_handle);
1434 +
1435 + /* Log all applicable mapping(s).
1436 + */
1437 +
1438 + mutex_lock(&(sm_state->map_lock));
1439 +
1440 + if (!list_empty(&sm_state->map_list)) {
1441 + list_for_each_entry(map, &sm_state->map_list, map_list) {
1442 + map_count++;
1443 +
1444 + seq_printf(s, "\nMapping 0x%x\n",
1445 + (unsigned int)map);
1446 + seq_printf(s, " TGID %u\n",
1447 + map->res_pid);
1448 + seq_printf(s, " VC-HDL 0x%x\n",
1449 + map->res_vc_hdl);
1450 + seq_printf(s, " USR-HDL 0x%x\n",
1451 + map->res_usr_hdl);
1452 + seq_printf(s, " USR-ADDR 0x%lx\n",
1453 + map->res_addr);
1454 + }
1455 + }
1456 +
1457 + mutex_unlock(&(sm_state->map_lock));
1458 + seq_printf(s, "\n\nTotal map count: %d\n\n", map_count);
1459 +
1460 + return 0;
1461 +}
1462 +
1463 +static int vc_sm_global_statistics_show(struct seq_file *s, void *v)
1464 +{
1465 + int ix;
1466 +
1467 + /* Global state tracked statistics.
1468 + */
1469 + if (sm_state != NULL) {
1470 + seq_puts(s, "\nDeceased Resources Statistics\n");
1471 +
1472 + seq_printf(s, "\nNatural Cause (%u occurences)\n",
1473 + sm_state->res_deceased_cnt);
1474 + for (ix = 0; ix < END_ATTEMPT; ix++) {
1475 + if (sm_state->deceased[ix] > 0) {
1476 + seq_printf(s, " %u\t%s\n",
1477 + sm_state->deceased[ix],
1478 + sm_stats_human_read[ix]);
1479 + }
1480 + }
1481 + seq_puts(s, "\n");
1482 + for (ix = 0; ix < END_ATTEMPT; ix++) {
1483 + if (sm_state->deceased[ix + END_ATTEMPT] > 0) {
1484 + seq_printf(s, " %u\tFAILED %s\n",
1485 + sm_state->deceased[ix + END_ATTEMPT],
1486 + sm_stats_human_read[ix]);
1487 + }
1488 + }
1489 +
1490 + seq_printf(s, "\nForcefull (%u occurences)\n",
1491 + sm_state->res_terminated_cnt);
1492 + for (ix = 0; ix < END_ATTEMPT; ix++) {
1493 + if (sm_state->terminated[ix] > 0) {
1494 + seq_printf(s, " %u\t%s\n",
1495 + sm_state->terminated[ix],
1496 + sm_stats_human_read[ix]);
1497 + }
1498 + }
1499 + seq_puts(s, "\n");
1500 + for (ix = 0; ix < END_ATTEMPT; ix++) {
1501 + if (sm_state->terminated[ix + END_ATTEMPT] > 0) {
1502 + seq_printf(s, " %u\tFAILED %s\n",
1503 + sm_state->terminated[ix +
1504 + END_ATTEMPT],
1505 + sm_stats_human_read[ix]);
1506 + }
1507 + }
1508 + }
1509 +
1510 + return 0;
1511 +}
1512 +
1513 +#if 0
1514 +/* Read callback for the statistics proc entry.
1515 +*/
1516 +static int vc_sm_statistics_show(struct seq_file *s, void *v)
1517 +{
1518 + int ix;
1519 + struct SM_PRIV_DATA_T *file_data;
1520 + struct SM_RESOURCE_T *resource;
1521 + int res_count = 0;
1522 + struct SM_PDE_T *p_pde;
1523 +
1524 + p_pde = (struct SM_PDE_T *)(s->private);
1525 + file_data = (struct SM_PRIV_DATA_T *)(p_pde->priv_data);
1526 +
1527 + if (file_data == NULL)
1528 + return 0;
1529 +
1530 + /* Per process statistics.
1531 + */
1532 +
1533 + seq_printf(s, "\nStatistics for TGID %d\n", file_data->pid);
1534 +
1535 + mutex_lock(&(sm_state->map_lock));
1536 +
1537 + if (!list_empty(&file_data->resource_list)) {
1538 + list_for_each_entry(resource, &file_data->resource_list,
1539 + resource_list) {
1540 + res_count++;
1541 +
1542 + seq_printf(s, "\nGUID: 0x%x\n\n",
1543 + resource->res_guid);
1544 + for (ix = 0; ix < END_ATTEMPT; ix++) {
1545 + if (resource->res_stats[ix] > 0) {
1546 + seq_printf(s,
1547 + " %u\t%s\n",
1548 + resource->res_stats[ix],
1549 + sm_stats_human_read[ix]);
1550 + }
1551 + }
1552 + seq_puts(s, "\n");
1553 + for (ix = 0; ix < END_ATTEMPT; ix++) {
1554 + if (resource->res_stats[ix + END_ATTEMPT] > 0) {
1555 + seq_printf(s,
1556 + " %u\tFAILED %s\n",
1557 + resource->res_stats[
1558 + ix + END_ATTEMPT],
1559 + sm_stats_human_read[ix]);
1560 + }
1561 + }
1562 + }
1563 + }
1564 +
1565 + mutex_unlock(&(sm_state->map_lock));
1566 +
1567 + seq_printf(s, "\nResources Count %d\n", res_count);
1568 +
1569 + return 0;
1570 +}
1571 +#endif
1572 +
1573 +#if 0
1574 +/* Read callback for the allocation proc entry. */
1575 +static int vc_sm_alloc_show(struct seq_file *s, void *v)
1576 +{
1577 + struct SM_PRIV_DATA_T *file_data;
1578 + struct SM_RESOURCE_T *resource;
1579 + int alloc_count = 0;
1580 + struct SM_PDE_T *p_pde;
1581 +
1582 + p_pde = (struct SM_PDE_T *)(s->private);
1583 + file_data = (struct SM_PRIV_DATA_T *)(p_pde->priv_data);
1584 +
1585 + if (!file_data)
1586 + return 0;
1587 +
1588 + /* Per process statistics. */
1589 + seq_printf(s, "\nAllocation for TGID %d\n", file_data->pid);
1590 +
1591 + mutex_lock(&(sm_state->map_lock));
1592 +
1593 + if (!list_empty(&file_data->resource_list)) {
1594 + list_for_each_entry(resource, &file_data->resource_list,
1595 + resource_list) {
1596 + alloc_count++;
1597 +
1598 + seq_printf(s, "\nGUID: 0x%x\n",
1599 + resource->res_guid);
1600 + seq_printf(s, "Lock Count: %u\n",
1601 + resource->lock_count);
1602 + seq_printf(s, "Mapped: %s\n",
1603 + (resource->map_count ? "yes" : "no"));
1604 + seq_printf(s, "VC-handle: 0x%x\n",
1605 + resource->res_handle);
1606 + seq_printf(s, "VC-address: 0x%p\n",
1607 + resource->res_base_mem);
1608 + seq_printf(s, "VC-size (bytes): %u\n",
1609 + resource->res_size);
1610 + seq_printf(s, "Cache: %s\n",
1611 + sm_cache_map_vector[resource->res_cached]);
1612 + }
1613 + }
1614 +
1615 + mutex_unlock(&(sm_state->map_lock));
1616 +
1617 + seq_printf(s, "\n\nTotal allocation count: %d\n\n", alloc_count);
1618 +
1619 + return 0;
1620 +}
1621 +#endif
1622 +
1623 +static int vc_sm_seq_file_show(struct seq_file *s, void *v)
1624 +{
1625 + struct SM_PDE_T *sm_pde;
1626 +
1627 + sm_pde = (struct SM_PDE_T *)(s->private);
1628 +
1629 + if (sm_pde && sm_pde->show)
1630 + sm_pde->show(s, v);
1631 +
1632 + return 0;
1633 +}
1634 +
1635 +static int vc_sm_single_open(struct inode *inode, struct file *file)
1636 +{
1637 + return single_open(file, vc_sm_seq_file_show, inode->i_private);
1638 +}
1639 +
1640 +static const struct file_operations vc_sm_debug_fs_fops = {
1641 + .open = vc_sm_single_open,
1642 + .read = seq_read,
1643 + .llseek = seq_lseek,
1644 + .release = single_release,
1645 +};
1646 +
1647 +/* Adds a resource to the private data list which tracks all the allocated
1648 +** data.
1649 +*/
1650 +static void vmcs_sm_add_resource(struct SM_PRIV_DATA_T *privdata,
1651 + struct SM_RESOURCE_T *resource)
1652 +{
1653 + mutex_lock(&(sm_state->map_lock));
1654 + list_add(&resource->resource_list, &privdata->resource_list);
1655 + list_add(&resource->global_resource_list, &sm_state->resource_list);
1656 + mutex_unlock(&(sm_state->map_lock));
1657 +
1658 + pr_debug("[%s]: added resource %p (base addr %p, hdl %x, size %u, cache %u)\n",
1659 + __func__, resource, resource->res_base_mem,
1660 + resource->res_handle, resource->res_size, resource->res_cached);
1661 +}
1662 +
1663 +/* Locates a resource and acquire a reference on it.
1664 +** The resource won't be deleted while there is a reference on it.
1665 +*/
1666 +static struct SM_RESOURCE_T *vmcs_sm_acquire_resource(struct SM_PRIV_DATA_T
1667 + *private,
1668 + unsigned int res_guid)
1669 +{
1670 + struct SM_RESOURCE_T *resource, *ret = NULL;
1671 +
1672 + mutex_lock(&(sm_state->map_lock));
1673 +
1674 + list_for_each_entry(resource, &private->resource_list, resource_list) {
1675 + if (resource->res_guid != res_guid)
1676 + continue;
1677 +
1678 + pr_debug("[%s]: located resource %p (guid: %x, base addr %p, hdl %x, size %u, cache %u)\n",
1679 + __func__, resource, resource->res_guid,
1680 + resource->res_base_mem, resource->res_handle,
1681 + resource->res_size, resource->res_cached);
1682 + resource->ref_count++;
1683 + ret = resource;
1684 + break;
1685 + }
1686 +
1687 + mutex_unlock(&(sm_state->map_lock));
1688 +
1689 + return ret;
1690 +}
1691 +
1692 +/* Locates a resource and acquire a reference on it.
1693 +** The resource won't be deleted while there is a reference on it.
1694 +*/
1695 +static struct SM_RESOURCE_T *vmcs_sm_acquire_first_resource(
1696 + struct SM_PRIV_DATA_T *private)
1697 +{
1698 + struct SM_RESOURCE_T *resource, *ret = NULL;
1699 +
1700 + mutex_lock(&(sm_state->map_lock));
1701 +
1702 + list_for_each_entry(resource, &private->resource_list, resource_list) {
1703 + pr_debug("[%s]: located resource %p (guid: %x, base addr %p, hdl %x, size %u, cache %u)\n",
1704 + __func__, resource, resource->res_guid,
1705 + resource->res_base_mem, resource->res_handle,
1706 + resource->res_size, resource->res_cached);
1707 + resource->ref_count++;
1708 + ret = resource;
1709 + break;
1710 + }
1711 +
1712 + mutex_unlock(&(sm_state->map_lock));
1713 +
1714 + return ret;
1715 +}
1716 +
1717 +/* Locates a resource and acquire a reference on it.
1718 +** The resource won't be deleted while there is a reference on it.
1719 +*/
1720 +static struct SM_RESOURCE_T *vmcs_sm_acquire_global_resource(unsigned int
1721 + res_guid)
1722 +{
1723 + struct SM_RESOURCE_T *resource, *ret = NULL;
1724 +
1725 + mutex_lock(&(sm_state->map_lock));
1726 +
1727 + list_for_each_entry(resource, &sm_state->resource_list,
1728 + global_resource_list) {
1729 + if (resource->res_guid != res_guid)
1730 + continue;
1731 +
1732 + pr_debug("[%s]: located resource %p (guid: %x, base addr %p, hdl %x, size %u, cache %u)\n",
1733 + __func__, resource, resource->res_guid,
1734 + resource->res_base_mem, resource->res_handle,
1735 + resource->res_size, resource->res_cached);
1736 + resource->ref_count++;
1737 + ret = resource;
1738 + break;
1739 + }
1740 +
1741 + mutex_unlock(&(sm_state->map_lock));
1742 +
1743 + return ret;
1744 +}
1745 +
1746 +/* Release a previously acquired resource.
1747 +** The resource will be deleted when its refcount reaches 0.
1748 +*/
1749 +static void vmcs_sm_release_resource(struct SM_RESOURCE_T *resource, int force)
1750 +{
1751 + struct SM_PRIV_DATA_T *private = resource->private;
1752 + struct sm_mmap *map, *map_tmp;
1753 + struct SM_RESOURCE_T *res_tmp;
1754 + int ret;
1755 +
1756 + mutex_lock(&(sm_state->map_lock));
1757 +
1758 + if (--resource->ref_count) {
1759 + if (force)
1760 + pr_err("[%s]: resource %p in use\n", __func__, resource);
1761 +
1762 + mutex_unlock(&(sm_state->map_lock));
1763 + return;
1764 + }
1765 +
1766 + /* Time to free the resource. Start by removing it from the list */
1767 + list_del(&resource->resource_list);
1768 + list_del(&resource->global_resource_list);
1769 +
1770 + /* Walk the global resource list, find out if the resource is used
1771 + * somewhere else. In which case we don't want to delete it.
1772 + */
1773 + list_for_each_entry(res_tmp, &sm_state->resource_list,
1774 + global_resource_list) {
1775 + if (res_tmp->res_handle == resource->res_handle) {
1776 + resource->res_handle = 0;
1777 + break;
1778 + }
1779 + }
1780 +
1781 + mutex_unlock(&(sm_state->map_lock));
1782 +
1783 + pr_debug("[%s]: freeing data - guid %x, hdl %x, base address %p\n",
1784 + __func__, resource->res_guid, resource->res_handle,
1785 + resource->res_base_mem);
1786 + resource->res_stats[FREE]++;
1787 +
1788 + /* Make sure the resource we're removing is unmapped first */
1789 + if (resource->map_count && !list_empty(&resource->map_list)) {
1790 + down_write(&current->mm->mmap_sem);
1791 + list_for_each_entry_safe(map, map_tmp, &resource->map_list,
1792 + resource_map_list) {
1793 + ret =
1794 + do_munmap(current->mm, map->res_addr,
1795 + resource->res_size);
1796 + if (ret) {
1797 + pr_err("[%s]: could not unmap resource %p\n",
1798 + __func__, resource);
1799 + }
1800 + }
1801 + up_write(&current->mm->mmap_sem);
1802 + }
1803 +
1804 + /* Free up the videocore allocated resource.
1805 + */
1806 + if (resource->res_handle) {
1807 + VC_SM_FREE_T free = {
1808 + resource->res_handle, resource->res_base_mem
1809 + };
1810 + int status = vc_vchi_sm_free(sm_state->sm_handle, &free,
1811 + &private->int_trans_id);
1812 + if (status != 0 && status != -EINTR) {
1813 + pr_err("[%s]: failed to free memory on videocore (status: %u, trans_id: %u)\n",
1814 + __func__, status, private->int_trans_id);
1815 + resource->res_stats[FREE_FAIL]++;
1816 + ret = -EPERM;
1817 + }
1818 + }
1819 +
1820 + /* Free up the shared resource.
1821 + */
1822 + if (resource->res_shared)
1823 + vmcs_sm_release_resource(resource->res_shared, 0);
1824 +
1825 + /* Free up the local resource tracking this allocation.
1826 + */
1827 + vc_sm_resource_deceased(resource, force);
1828 + kfree(resource);
1829 +}
1830 +
1831 +/* Dump the map table for the driver. If process is -1, dumps the whole table,
1832 +** if process is a valid pid (non -1) dump only the entries associated with the
1833 +** pid of interest.
1834 +*/
1835 +static void vmcs_sm_host_walk_map_per_pid(int pid)
1836 +{
1837 + struct sm_mmap *map = NULL;
1838 +
1839 + /* Make sure the device was started properly.
1840 + */
1841 + if (sm_state == NULL) {
1842 + pr_err("[%s]: invalid device\n", __func__);
1843 + return;
1844 + }
1845 +
1846 + mutex_lock(&(sm_state->map_lock));
1847 +
1848 + /* Log all applicable mapping(s).
1849 + */
1850 + if (!list_empty(&sm_state->map_list)) {
1851 + list_for_each_entry(map, &sm_state->map_list, map_list) {
1852 + if (pid == -1 || map->res_pid == pid) {
1853 + pr_info("[%s]: tgid: %u - vc-hdl: %x, usr-hdl: %x, usr-addr: %lx\n",
1854 + __func__, map->res_pid, map->res_vc_hdl,
1855 + map->res_usr_hdl, map->res_addr);
1856 + }
1857 + }
1858 + }
1859 +
1860 + mutex_unlock(&(sm_state->map_lock));
1861 +
1862 + return;
1863 +}
1864 +
1865 +/* Dump the allocation table from host side point of view. This only dumps the
1866 +** data allocated for this process/device referenced by the file_data.
1867 +*/
1868 +static void vmcs_sm_host_walk_alloc(struct SM_PRIV_DATA_T *file_data)
1869 +{
1870 + struct SM_RESOURCE_T *resource = NULL;
1871 +
1872 + /* Make sure the device was started properly.
1873 + */
1874 + if ((sm_state == NULL) || (file_data == NULL)) {
1875 + pr_err("[%s]: invalid device\n", __func__);
1876 + return;
1877 + }
1878 +
1879 + mutex_lock(&(sm_state->map_lock));
1880 +
1881 + if (!list_empty(&file_data->resource_list)) {
1882 + list_for_each_entry(resource, &file_data->resource_list,
1883 + resource_list) {
1884 + pr_info("[%s]: guid: %x - hdl: %x, vc-mem: %p, size: %u, cache: %u\n",
1885 + __func__, resource->res_guid, resource->res_handle,
1886 + resource->res_base_mem, resource->res_size,
1887 + resource->res_cached);
1888 + }
1889 + }
1890 +
1891 + mutex_unlock(&(sm_state->map_lock));
1892 +
1893 + return;
1894 +}
1895 +
1896 +/* Create support for private data tracking.
1897 +*/
1898 +static struct SM_PRIV_DATA_T *vc_sm_create_priv_data(pid_t id)
1899 +{
1900 + char alloc_name[32];
1901 + struct SM_PRIV_DATA_T *file_data = NULL;
1902 +
1903 + /* Allocate private structure. */
1904 + file_data = kzalloc(sizeof(*file_data), GFP_KERNEL);
1905 +
1906 + if (!file_data) {
1907 + pr_err("[%s]: cannot allocate file data\n", __func__);
1908 + goto out;
1909 + }
1910 +
1911 + snprintf(alloc_name, sizeof(alloc_name), "%d", id);
1912 +
1913 + INIT_LIST_HEAD(&file_data->resource_list);
1914 + file_data->pid = id;
1915 + file_data->dir_pid = debugfs_create_dir(alloc_name,
1916 + sm_state->dir_alloc);
1917 +#if 0
1918 + /* TODO: fix this to support querying statistics per pid */
1919 +
1920 + if (IS_ERR_OR_NULL(file_data->dir_pid)) {
1921 + file_data->dir_pid = NULL;
1922 + } else {
1923 + struct dentry *dir_entry;
1924 +
1925 + dir_entry = debugfs_create_file(VC_SM_RESOURCES, S_IRUGO,
1926 + file_data->dir_pid, file_data,
1927 + vc_sm_debug_fs_fops);
1928 +
1929 + file_data->dir_res.dir_entry = dir_entry;
1930 + file_data->dir_res.priv_data = file_data;
1931 + file_data->dir_res.show = &vc_sm_alloc_show;
1932 +
1933 + dir_entry = debugfs_create_file(VC_SM_STATS, S_IRUGO,
1934 + file_data->dir_pid, file_data,
1935 + vc_sm_debug_fs_fops);
1936 +
1937 + file_data->dir_res.dir_entry = dir_entry;
1938 + file_data->dir_res.priv_data = file_data;
1939 + file_data->dir_res.show = &vc_sm_statistics_show;
1940 + }
1941 + pr_debug("[%s]: private data allocated %p\n", __func__, file_data);
1942 +
1943 +#endif
1944 +out:
1945 + return file_data;
1946 +}
1947 +
1948 +/* Open the device. Creates a private state to help track all allocation
1949 +** associated with this device.
1950 +*/
1951 +static int vc_sm_open(struct inode *inode, struct file *file)
1952 +{
1953 + int ret = 0;
1954 +
1955 + /* Make sure the device was started properly.
1956 + */
1957 + if (!sm_state) {
1958 + pr_err("[%s]: invalid device\n", __func__);
1959 + ret = -EPERM;
1960 + goto out;
1961 + }
1962 +
1963 + file->private_data = vc_sm_create_priv_data(current->tgid);
1964 + if (file->private_data == NULL) {
1965 + pr_err("[%s]: failed to create data tracker\n", __func__);
1966 +
1967 + ret = -ENOMEM;
1968 + goto out;
1969 + }
1970 +
1971 +out:
1972 + return ret;
1973 +}
1974 +
1975 +/* Close the device. Free up all resources still associated with this device
1976 +** at the time.
1977 +*/
1978 +static int vc_sm_release(struct inode *inode, struct file *file)
1979 +{
1980 + struct SM_PRIV_DATA_T *file_data =
1981 + (struct SM_PRIV_DATA_T *)file->private_data;
1982 + struct SM_RESOURCE_T *resource;
1983 + int ret = 0;
1984 +
1985 + /* Make sure the device was started properly.
1986 + */
1987 + if (sm_state == NULL || file_data == NULL) {
1988 + pr_err("[%s]: invalid device\n", __func__);
1989 + ret = -EPERM;
1990 + goto out;
1991 + }
1992 +
1993 + pr_debug("[%s]: using private data %p\n", __func__, file_data);
1994 +
1995 + if (file_data->restart_sys == -EINTR) {
1996 + VC_SM_ACTION_CLEAN_T action_clean;
1997 +
1998 + pr_debug("[%s]: releasing following EINTR on %u (trans_id: %u) (likely due to signal)...\n",
1999 + __func__, file_data->int_action,
2000 + file_data->int_trans_id);
2001 +
2002 + action_clean.res_action = file_data->int_action;
2003 + action_clean.action_trans_id = file_data->int_trans_id;
2004 +
2005 + vc_vchi_sm_clean_up(sm_state->sm_handle, &action_clean);
2006 + }
2007 +
2008 + while ((resource = vmcs_sm_acquire_first_resource(file_data)) != NULL) {
2009 + vmcs_sm_release_resource(resource, 0);
2010 + vmcs_sm_release_resource(resource, 1);
2011 + }
2012 +
2013 + /* Remove the corresponding proc entry. */
2014 + debugfs_remove_recursive(file_data->dir_pid);
2015 +
2016 + /* Terminate the private data.
2017 + */
2018 + kfree(file_data);
2019 +
2020 +out:
2021 + return ret;
2022 +}
2023 +
2024 +static void vcsm_vma_open(struct vm_area_struct *vma)
2025 +{
2026 + struct sm_mmap *map = (struct sm_mmap *)vma->vm_private_data;
2027 +
2028 + pr_debug("[%s]: virt %lx-%lx, pid %i, pfn %i\n",
2029 + __func__, vma->vm_start, vma->vm_end, (int)current->tgid,
2030 + (int)vma->vm_pgoff);
2031 +
2032 + map->ref_count++;
2033 +}
2034 +
2035 +static void vcsm_vma_close(struct vm_area_struct *vma)
2036 +{
2037 + struct sm_mmap *map = (struct sm_mmap *)vma->vm_private_data;
2038 +
2039 + pr_debug("[%s]: virt %lx-%lx, pid %i, pfn %i\n",
2040 + __func__, vma->vm_start, vma->vm_end, (int)current->tgid,
2041 + (int)vma->vm_pgoff);
2042 +
2043 + map->ref_count--;
2044 +
2045 + /* Remove from the map table.
2046 + */
2047 + if (map->ref_count == 0)
2048 + vmcs_sm_remove_map(sm_state, map->resource, map);
2049 +}
2050 +
2051 +static int vcsm_vma_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
2052 +{
2053 + struct sm_mmap *map = (struct sm_mmap *)vma->vm_private_data;
2054 + struct SM_RESOURCE_T *resource = map->resource;
2055 + pgoff_t page_offset;
2056 + unsigned long pfn;
2057 + int ret = 0;
2058 +
2059 + /* Lock the resource if necessary.
2060 + */
2061 + if (!resource->lock_count) {
2062 + VC_SM_LOCK_UNLOCK_T lock_unlock;
2063 + VC_SM_LOCK_RESULT_T lock_result;
2064 + int status;
2065 +
2066 + lock_unlock.res_handle = resource->res_handle;
2067 + lock_unlock.res_mem = resource->res_base_mem;
2068 +
2069 + pr_debug("[%s]: attempt to lock data - hdl %x, base address %p\n",
2070 + __func__, lock_unlock.res_handle, lock_unlock.res_mem);
2071 +
2072 + /* Lock the videocore allocated resource.
2073 + */
2074 + status = vc_vchi_sm_lock(sm_state->sm_handle,
2075 + &lock_unlock, &lock_result, 0);
2076 + if ((status != 0) ||
2077 + ((status == 0) && (lock_result.res_mem == NULL))) {
2078 + pr_err("[%s]: failed to lock memory on videocore (status: %u)\n",
2079 + __func__, status);
2080 + resource->res_stats[LOCK_FAIL]++;
2081 + return VM_FAULT_SIGBUS;
2082 + }
2083 +
2084 + pfn = vcaddr_to_pfn((unsigned long)resource->res_base_mem);
2085 + outer_inv_range(__pfn_to_phys(pfn),
2086 + __pfn_to_phys(pfn) + resource->res_size);
2087 +
2088 + resource->res_stats[LOCK]++;
2089 + resource->lock_count++;
2090 +
2091 + /* Keep track of the new base memory.
2092 + */
2093 + if ((lock_result.res_mem != NULL) &&
2094 + (lock_result.res_old_mem != NULL) &&
2095 + (lock_result.res_mem != lock_result.res_old_mem)) {
2096 + resource->res_base_mem = lock_result.res_mem;
2097 + }
2098 + }
2099 +
2100 + /* We don't use vmf->pgoff since that has the fake offset */
2101 + page_offset = ((unsigned long)vmf->virtual_address - vma->vm_start);
2102 + pfn = (uint32_t)resource->res_base_mem & 0x3FFFFFFF;
2103 + pfn += mm_vc_mem_phys_addr;
2104 + pfn += page_offset;
2105 + pfn >>= PAGE_SHIFT;
2106 +
2107 + /* Finally, remap it */
2108 + ret = vm_insert_pfn(vma, (unsigned long)vmf->virtual_address, pfn);
2109 +
2110 + switch (ret) {
2111 + case 0:
2112 + case -ERESTARTSYS:
2113 + return VM_FAULT_NOPAGE;
2114 + case -ENOMEM:
2115 + case -EAGAIN:
2116 + return VM_FAULT_OOM;
2117 + default:
2118 + return VM_FAULT_SIGBUS;
2119 + }
2120 +}
2121 +
2122 +static struct vm_operations_struct vcsm_vm_ops = {
2123 + .open = vcsm_vma_open,
2124 + .close = vcsm_vma_close,
2125 + .fault = vcsm_vma_fault,
2126 +};
2127 +
2128 +/* Walks a VMA and clean each valid page from the cache */
2129 +static void vcsm_vma_cache_clean_page_range(unsigned long addr,
2130 + unsigned long end)
2131 +{
2132 + pgd_t *pgd;
2133 + pud_t *pud;
2134 + pmd_t *pmd;
2135 + pte_t *pte;
2136 + unsigned long pgd_next, pud_next, pmd_next;
2137 +
2138 + if (addr >= end)
2139 + return;
2140 +
2141 + /* Walk PGD */
2142 + pgd = pgd_offset(current->mm, addr);
2143 + do {
2144 + pgd_next = pgd_addr_end(addr, end);
2145 +
2146 + if (pgd_none(*pgd) || pgd_bad(*pgd))
2147 + continue;
2148 +
2149 + /* Walk PUD */
2150 + pud = pud_offset(pgd, addr);
2151 + do {
2152 + pud_next = pud_addr_end(addr, pgd_next);
2153 + if (pud_none(*pud) || pud_bad(*pud))
2154 + continue;
2155 +
2156 + /* Walk PMD */
2157 + pmd = pmd_offset(pud, addr);
2158 + do {
2159 + pmd_next = pmd_addr_end(addr, pud_next);
2160 + if (pmd_none(*pmd) || pmd_bad(*pmd))
2161 + continue;
2162 +
2163 + /* Walk PTE */
2164 + pte = pte_offset_map(pmd, addr);
2165 + do {
2166 + if (pte_none(*pte)
2167 + || !pte_present(*pte))
2168 + continue;
2169 +
2170 + /* Clean + invalidate */
2171 + dmac_flush_range((const void *) addr,
2172 + (const void *)
2173 + (addr + PAGE_SIZE));
2174 +
2175 + } while (pte++, addr +=
2176 + PAGE_SIZE, addr != pmd_next);
2177 + pte_unmap(pte);
2178 +
2179 + } while (pmd++, addr = pmd_next, addr != pud_next);
2180 +
2181 + } while (pud++, addr = pud_next, addr != pgd_next);
2182 + } while (pgd++, addr = pgd_next, addr != end);
2183 +}
2184 +
2185 +/* Map an allocated data into something that the user space.
2186 +*/
2187 +static int vc_sm_mmap(struct file *file, struct vm_area_struct *vma)
2188 +{
2189 + int ret = 0;
2190 + struct SM_PRIV_DATA_T *file_data =
2191 + (struct SM_PRIV_DATA_T *)file->private_data;
2192 + struct SM_RESOURCE_T *resource = NULL;
2193 + struct sm_mmap *map = NULL;
2194 +
2195 + /* Make sure the device was started properly.
2196 + */
2197 + if ((sm_state == NULL) || (file_data == NULL)) {
2198 + pr_err("[%s]: invalid device\n", __func__);
2199 + return -EPERM;
2200 + }
2201 +
2202 + pr_debug("[%s]: private data %p, guid %x\n", __func__, file_data,
2203 + ((unsigned int)vma->vm_pgoff << PAGE_SHIFT));
2204 +
2205 + /* We lookup to make sure that the data we are being asked to mmap is
2206 + ** something that we allocated.
2207 + **
2208 + ** We use the offset information as the key to tell us which resource
2209 + ** we are mapping.
2210 + */
2211 + resource = vmcs_sm_acquire_resource(file_data,
2212 + ((unsigned int)vma->vm_pgoff <<
2213 + PAGE_SHIFT));
2214 + if (resource == NULL) {
2215 + pr_err("[%s]: failed to locate resource for guid %x\n", __func__,
2216 + ((unsigned int)vma->vm_pgoff << PAGE_SHIFT));
2217 + return -ENOMEM;
2218 + }
2219 +
2220 + pr_debug("[%s]: guid %x, tgid %u, %u, %u\n",
2221 + __func__, resource->res_guid, current->tgid, resource->pid,
2222 + file_data->pid);
2223 +
2224 + /* Check permissions.
2225 + */
2226 + if (resource->pid && (resource->pid != current->tgid)) {
2227 + pr_err("[%s]: current tgid %u != %u owner\n",
2228 + __func__, current->tgid, resource->pid);
2229 + ret = -EPERM;
2230 + goto error;
2231 + }
2232 +
2233 + /* Verify that what we are asked to mmap is proper.
2234 + */
2235 + if (resource->res_size != (unsigned int)(vma->vm_end - vma->vm_start)) {
2236 + pr_err("[%s]: size inconsistency (resource: %u - mmap: %u)\n",
2237 + __func__,
2238 + resource->res_size,
2239 + (unsigned int)(vma->vm_end - vma->vm_start));
2240 +
2241 + ret = -EINVAL;
2242 + goto error;
2243 + }
2244 +
2245 + /* Keep track of the tuple in the global resource list such that one
2246 + * can do a mapping lookup for address/memory handle.
2247 + */
2248 + map = kzalloc(sizeof(*map), GFP_KERNEL);
2249 + if (map == NULL) {
2250 + pr_err("[%s]: failed to allocate global tracking resource\n",
2251 + __func__);
2252 + ret = -ENOMEM;
2253 + goto error;
2254 + }
2255 +
2256 + map->res_pid = current->tgid;
2257 + map->res_vc_hdl = resource->res_handle;
2258 + map->res_usr_hdl = resource->res_guid;
2259 + map->res_addr = (long unsigned int)vma->vm_start;
2260 + map->resource = resource;
2261 + map->vma = vma;
2262 + vmcs_sm_add_map(sm_state, resource, map);
2263 +
2264 + /* We are not actually mapping the pages, we just provide a fault
2265 + ** handler to allow pages to be mapped when accessed
2266 + */
2267 + vma->vm_flags |=
2268 + VM_IO | VM_PFNMAP | VM_DONTCOPY | VM_DONTEXPAND;
2269 + vma->vm_ops = &vcsm_vm_ops;
2270 + vma->vm_private_data = map;
2271 +
2272 + /* vm_pgoff is the first PFN of the mapped memory */
2273 + vma->vm_pgoff = (unsigned long)resource->res_base_mem & 0x3FFFFFFF;
2274 + vma->vm_pgoff += mm_vc_mem_phys_addr;
2275 + vma->vm_pgoff >>= PAGE_SHIFT;
2276 +
2277 + if ((resource->res_cached == VMCS_SM_CACHE_NONE) ||
2278 + (resource->res_cached == VMCS_SM_CACHE_VC)) {
2279 + /* Allocated non host cached memory, honour it.
2280 + */
2281 + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
2282 + }
2283 +
2284 + pr_debug("[%s]: resource %p (guid %x) - cnt %u, base address %p, handle %x, size %u (%u), cache %u\n",
2285 + __func__,
2286 + resource, resource->res_guid, resource->lock_count,
2287 + resource->res_base_mem, resource->res_handle,
2288 + resource->res_size, (unsigned int)(vma->vm_end - vma->vm_start),
2289 + resource->res_cached);
2290 +
2291 + pr_debug("[%s]: resource %p (base address %p, handle %x) - map-count %d, usr-addr %x\n",
2292 + __func__, resource, resource->res_base_mem,
2293 + resource->res_handle, resource->map_count,
2294 + (unsigned int)vma->vm_start);
2295 +
2296 + vcsm_vma_open(vma);
2297 + resource->res_stats[MAP]++;
2298 + vmcs_sm_release_resource(resource, 0);
2299 + return 0;
2300 +
2301 +error:
2302 + resource->res_stats[MAP_FAIL]++;
2303 + vmcs_sm_release_resource(resource, 0);
2304 + return ret;
2305 +}
2306 +
2307 +/* Allocate a shared memory handle and block.
2308 +*/
2309 +int vc_sm_ioctl_alloc(struct SM_PRIV_DATA_T *private,
2310 + struct vmcs_sm_ioctl_alloc *ioparam)
2311 +{
2312 + int ret = 0;
2313 + int status;
2314 + struct SM_RESOURCE_T *resource;
2315 + VC_SM_ALLOC_T alloc = { 0 };
2316 + VC_SM_ALLOC_RESULT_T result = { 0 };
2317 +
2318 + /* Setup our allocation parameters */
2319 + alloc.type = ((ioparam->cached == VMCS_SM_CACHE_VC)
2320 + || (ioparam->cached ==
2321 + VMCS_SM_CACHE_BOTH)) ? VC_SM_ALLOC_CACHED :
2322 + VC_SM_ALLOC_NON_CACHED;
2323 + alloc.base_unit = ioparam->size;
2324 + alloc.num_unit = ioparam->num;
2325 + alloc.allocator = current->tgid;
2326 + /* Align to kernel page size */
2327 + alloc.alignement = 4096;
2328 + /* Align the size to the kernel page size */
2329 + alloc.base_unit =
2330 + (alloc.base_unit + alloc.alignement - 1) & ~(alloc.alignement - 1);
2331 + if (*ioparam->name) {
2332 + memcpy(alloc.name, ioparam->name, sizeof(alloc.name) - 1);
2333 + } else {
2334 + memcpy(alloc.name, VMCS_SM_RESOURCE_NAME_DEFAULT,
2335 + sizeof(VMCS_SM_RESOURCE_NAME_DEFAULT));
2336 + }
2337 +
2338 + pr_debug("[%s]: attempt to allocate \"%s\" data - type %u, base %u (%u), num %u, alignement %u\n",
2339 + __func__, alloc.name, alloc.type, ioparam->size,
2340 + alloc.base_unit, alloc.num_unit, alloc.alignement);
2341 +
2342 + /* Allocate local resource to track this allocation.
2343 + */
2344 + resource = kzalloc(sizeof(*resource), GFP_KERNEL);
2345 + if (!resource) {
2346 + ret = -ENOMEM;
2347 + goto error;
2348 + }
2349 + INIT_LIST_HEAD(&resource->map_list);
2350 + resource->ref_count++;
2351 + resource->pid = current->tgid;
2352 +
2353 + /* Allocate the videocore resource.
2354 + */
2355 + status = vc_vchi_sm_alloc(sm_state->sm_handle, &alloc, &result,
2356 + &private->int_trans_id);
2357 + if (status == -EINTR) {
2358 + pr_debug("[%s]: requesting allocate memory action restart (trans_id: %u)\n",
2359 + __func__, private->int_trans_id);
2360 + ret = -ERESTARTSYS;
2361 + private->restart_sys = -EINTR;
2362 + private->int_action = VC_SM_MSG_TYPE_ALLOC;
2363 + goto error;
2364 + } else if (status != 0 || (status == 0 && result.res_mem == NULL)) {
2365 + pr_err("[%s]: failed to allocate memory on videocore (status: %u, trans_id: %u)\n",
2366 + __func__, status, private->int_trans_id);
2367 + ret = -ENOMEM;
2368 + resource->res_stats[ALLOC_FAIL]++;
2369 + goto error;
2370 + }
2371 +
2372 + /* Keep track of the resource we created.
2373 + */
2374 + resource->private = private;
2375 + resource->res_handle = result.res_handle;
2376 + resource->res_base_mem = result.res_mem;
2377 + resource->res_size = alloc.base_unit * alloc.num_unit;
2378 + resource->res_cached = ioparam->cached;
2379 +
2380 + /* Kernel/user GUID. This global identifier is used for mmap'ing the
2381 + * allocated region from user space, it is passed as the mmap'ing
2382 + * offset, we use it to 'hide' the videocore handle/address.
2383 + */
2384 + mutex_lock(&sm_state->lock);
2385 + resource->res_guid = ++sm_state->guid;
2386 + mutex_unlock(&sm_state->lock);
2387 + resource->res_guid <<= PAGE_SHIFT;
2388 +
2389 + vmcs_sm_add_resource(private, resource);
2390 +
2391 + pr_debug("[%s]: allocated data - guid %x, hdl %x, base address %p, size %d, cache %d\n",
2392 + __func__, resource->res_guid, resource->res_handle,
2393 + resource->res_base_mem, resource->res_size,
2394 + resource->res_cached);
2395 +
2396 + /* We're done */
2397 + resource->res_stats[ALLOC]++;
2398 + ioparam->handle = resource->res_guid;
2399 + return 0;
2400 +
2401 +error:
2402 + pr_err("[%s]: failed to allocate \"%s\" data (%i) - type %u, base %u (%u), num %u, alignment %u\n",
2403 + __func__, alloc.name, ret, alloc.type, ioparam->size,
2404 + alloc.base_unit, alloc.num_unit, alloc.alignement);
2405 + if (resource != NULL) {
2406 + vc_sm_resource_deceased(resource, 1);
2407 + kfree(resource);
2408 + }
2409 + return ret;
2410 +}
2411 +
2412 +/* Share an allocate memory handle and block.
2413 +*/
2414 +int vc_sm_ioctl_alloc_share(struct SM_PRIV_DATA_T *private,
2415 + struct vmcs_sm_ioctl_alloc_share *ioparam)
2416 +{
2417 + struct SM_RESOURCE_T *resource, *shared_resource;
2418 + int ret = 0;
2419 +
2420 + pr_debug("[%s]: attempt to share resource %u\n", __func__,
2421 + ioparam->handle);
2422 +
2423 + shared_resource = vmcs_sm_acquire_global_resource(ioparam->handle);
2424 + if (shared_resource == NULL) {
2425 + ret = -ENOMEM;
2426 + goto error;
2427 + }
2428 +
2429 + /* Allocate local resource to track this allocation.
2430 + */
2431 + resource = kzalloc(sizeof(*resource), GFP_KERNEL);
2432 + if (resource == NULL) {
2433 + pr_err("[%s]: failed to allocate local tracking resource\n",
2434 + __func__);
2435 + ret = -ENOMEM;
2436 + goto error;
2437 + }
2438 + INIT_LIST_HEAD(&resource->map_list);
2439 + resource->ref_count++;
2440 + resource->pid = current->tgid;
2441 +
2442 + /* Keep track of the resource we created.
2443 + */
2444 + resource->private = private;
2445 + resource->res_handle = shared_resource->res_handle;
2446 + resource->res_base_mem = shared_resource->res_base_mem;
2447 + resource->res_size = shared_resource->res_size;
2448 + resource->res_cached = shared_resource->res_cached;
2449 + resource->res_shared = shared_resource;
2450 +
2451 + mutex_lock(&sm_state->lock);
2452 + resource->res_guid = ++sm_state->guid;
2453 + mutex_unlock(&sm_state->lock);
2454 + resource->res_guid <<= PAGE_SHIFT;
2455 +
2456 + vmcs_sm_add_resource(private, resource);
2457 +
2458 + pr_debug("[%s]: allocated data - guid %x, hdl %x, base address %p, size %d, cache %d\n",
2459 + __func__, resource->res_guid, resource->res_handle,
2460 + resource->res_base_mem, resource->res_size,
2461 + resource->res_cached);
2462 +
2463 + /* We're done */
2464 + resource->res_stats[ALLOC]++;
2465 + ioparam->handle = resource->res_guid;
2466 + ioparam->size = resource->res_size;
2467 + return 0;
2468 +
2469 +error:
2470 + pr_err("[%s]: failed to share %u\n", __func__, ioparam->handle);
2471 + if (shared_resource != NULL)
2472 + vmcs_sm_release_resource(shared_resource, 0);
2473 +
2474 + return ret;
2475 +}
2476 +
2477 +/* Free a previously allocated shared memory handle and block.
2478 +*/
2479 +static int vc_sm_ioctl_free(struct SM_PRIV_DATA_T *private,
2480 + struct vmcs_sm_ioctl_free *ioparam)
2481 +{
2482 + struct SM_RESOURCE_T *resource =
2483 + vmcs_sm_acquire_resource(private, ioparam->handle);
2484 +
2485 + if (resource == NULL) {
2486 + pr_err("[%s]: resource for guid %u does not exist\n", __func__,
2487 + ioparam->handle);
2488 + return -EINVAL;
2489 + }
2490 +
2491 + /* Check permissions.
2492 + */
2493 + if (resource->pid && (resource->pid != current->tgid)) {
2494 + pr_err("[%s]: current tgid %u != %u owner\n",
2495 + __func__, current->tgid, resource->pid);
2496 + vmcs_sm_release_resource(resource, 0);
2497 + return -EPERM;
2498 + }
2499 +
2500 + vmcs_sm_release_resource(resource, 0);
2501 + vmcs_sm_release_resource(resource, 0);
2502 + return 0;
2503 +}
2504 +
2505 +/* Resize a previously allocated shared memory handle and block.
2506 +*/
2507 +static int vc_sm_ioctl_resize(struct SM_PRIV_DATA_T *private,
2508 + struct vmcs_sm_ioctl_resize *ioparam)
2509 +{
2510 + int ret = 0;
2511 + int status;
2512 + VC_SM_RESIZE_T resize;
2513 + struct SM_RESOURCE_T *resource;
2514 +
2515 + /* Locate resource from GUID.
2516 + */
2517 + resource = vmcs_sm_acquire_resource(private, ioparam->handle);
2518 + if (!resource) {
2519 + pr_err("[%s]: failed resource - guid %x\n",
2520 + __func__, ioparam->handle);
2521 + ret = -EFAULT;
2522 + goto error;
2523 + }
2524 +
2525 + /* If the resource is locked, its reference count will be not NULL,
2526 + ** in which case we will not be allowed to resize it anyways, so
2527 + ** reject the attempt here.
2528 + */
2529 + if (resource->lock_count != 0) {
2530 + pr_err("[%s]: cannot resize - guid %x, ref-cnt %d\n",
2531 + __func__, ioparam->handle, resource->lock_count);
2532 + ret = -EFAULT;
2533 + goto error;
2534 + }
2535 +
2536 + /* Check permissions.
2537 + */
2538 + if (resource->pid && (resource->pid != current->tgid)) {
2539 + pr_err("[%s]: current tgid %u != %u owner\n", __func__,
2540 + current->tgid, resource->pid);
2541 + ret = -EPERM;
2542 + goto error;
2543 + }
2544 +
2545 + if (resource->map_count != 0) {
2546 + pr_err("[%s]: cannot resize - guid %x, ref-cnt %d\n",
2547 + __func__, ioparam->handle, resource->map_count);
2548 + ret = -EFAULT;
2549 + goto error;
2550 + }
2551 +
2552 + resize.res_handle = resource->res_handle;
2553 + resize.res_mem = resource->res_base_mem;
2554 + resize.res_new_size = ioparam->new_size;
2555 +
2556 + pr_debug("[%s]: attempt to resize data - guid %x, hdl %x, base address %p\n",
2557 + __func__, ioparam->handle, resize.res_handle, resize.res_mem);
2558 +
2559 + /* Resize the videocore allocated resource.
2560 + */
2561 + status = vc_vchi_sm_resize(sm_state->sm_handle, &resize,
2562 + &private->int_trans_id);
2563 + if (status == -EINTR) {
2564 + pr_debug("[%s]: requesting resize memory action restart (trans_id: %u)\n",
2565 + __func__, private->int_trans_id);
2566 + ret = -ERESTARTSYS;
2567 + private->restart_sys = -EINTR;
2568 + private->int_action = VC_SM_MSG_TYPE_RESIZE;
2569 + goto error;
2570 + } else if (status != 0) {
2571 + pr_err("[%s]: failed to resize memory on videocore (status: %u, trans_id: %u)\n",
2572 + __func__, status, private->int_trans_id);
2573 + ret = -EPERM;
2574 + goto error;
2575 + }
2576 +
2577 + pr_debug("[%s]: success to resize data - hdl %x, size %d -> %d\n",
2578 + __func__, resize.res_handle, resource->res_size,
2579 + resize.res_new_size);
2580 +
2581 + /* Successfully resized, save the information and inform the user.
2582 + */
2583 + ioparam->old_size = resource->res_size;
2584 + resource->res_size = resize.res_new_size;
2585 +
2586 +error:
2587 + if (resource)
2588 + vmcs_sm_release_resource(resource, 0);
2589 +
2590 + return ret;
2591 +}
2592 +
2593 +/* Lock a previously allocated shared memory handle and block.
2594 +*/
2595 +static int vc_sm_ioctl_lock(struct SM_PRIV_DATA_T *private,
2596 + struct vmcs_sm_ioctl_lock_unlock *ioparam,
2597 + int change_cache, enum vmcs_sm_cache_e cache_type,
2598 + unsigned int vc_addr)
2599 +{
2600 + int status;
2601 + VC_SM_LOCK_UNLOCK_T lock;
2602 + VC_SM_LOCK_RESULT_T result;
2603 + struct SM_RESOURCE_T *resource;
2604 + int ret = 0;
2605 + struct sm_mmap *map, *map_tmp;
2606 + long unsigned int phys_addr;
2607 +
2608 + map = NULL;
2609 +
2610 + /* Locate resource from GUID.
2611 + */
2612 + resource = vmcs_sm_acquire_resource(private, ioparam->handle);
2613 + if (resource == NULL) {
2614 + ret = -EINVAL;
2615 + goto error;
2616 + }
2617 +
2618 + /* Check permissions.
2619 + */
2620 + if (resource->pid && (resource->pid != current->tgid)) {
2621 + pr_err("[%s]: current tgid %u != %u owner\n", __func__,
2622 + current->tgid, resource->pid);
2623 + ret = -EPERM;
2624 + goto error;
2625 + }
2626 +
2627 + lock.res_handle = resource->res_handle;
2628 + lock.res_mem = resource->res_base_mem;
2629 +
2630 + /* Take the lock and get the address to be mapped.
2631 + */
2632 + if (vc_addr == 0) {
2633 + pr_debug("[%s]: attempt to lock data - guid %x, hdl %x, base address %p\n",
2634 + __func__, ioparam->handle, lock.res_handle,
2635 + lock.res_mem);
2636 +
2637 + /* Lock the videocore allocated resource.
2638 + */
2639 + status = vc_vchi_sm_lock(sm_state->sm_handle, &lock, &result,
2640 + &private->int_trans_id);
2641 + if (status == -EINTR) {
2642 + pr_debug("[%s]: requesting lock memory action restart (trans_id: %u)\n",
2643 + __func__, private->int_trans_id);
2644 + ret = -ERESTARTSYS;
2645 + private->restart_sys = -EINTR;
2646 + private->int_action = VC_SM_MSG_TYPE_LOCK;
2647 + goto error;
2648 + } else if (status != 0 ||
2649 + (status == 0 && result.res_mem == NULL)) {
2650 + pr_err("[%s]: failed to lock memory on videocore (status: %u, trans_id: %u)\n",
2651 + __func__, status, private->int_trans_id);
2652 + ret = -EPERM;
2653 + resource->res_stats[LOCK_FAIL]++;
2654 + goto error;
2655 + }
2656 +
2657 + pr_debug("[%s]: succeed to lock data - hdl %x, base address %p (%p), ref-cnt %d\n",
2658 + __func__, lock.res_handle, result.res_mem,
2659 + lock.res_mem, resource->lock_count);
2660 + }
2661 + /* Lock assumed taken already, address to be mapped is known.
2662 + */
2663 + else
2664 + resource->res_base_mem = (void *)vc_addr;
2665 +
2666 + resource->res_stats[LOCK]++;
2667 + resource->lock_count++;
2668 +
2669 + /* Keep track of the new base memory allocation if it has changed.
2670 + */
2671 + if ((vc_addr == 0) &&
2672 + (result.res_mem != NULL) &&
2673 + (result.res_old_mem != NULL) &&
2674 + (result.res_mem != result.res_old_mem)) {
2675 + resource->res_base_mem = result.res_mem;
2676 +
2677 + /* Kernel allocated resources.
2678 + */
2679 + if (resource->pid == 0) {
2680 + if (!list_empty(&resource->map_list)) {
2681 + list_for_each_entry_safe(map, map_tmp,
2682 + &resource->map_list,
2683 + resource_map_list) {
2684 + if (map->res_addr) {
2685 + iounmap((void *)map->res_addr);
2686 + map->res_addr = 0;
2687 +
2688 + vmcs_sm_remove_map(sm_state,
2689 + map->resource,
2690 + map);
2691 + break;
2692 + }
2693 + }
2694 + }
2695 + }
2696 + }
2697 +
2698 + if (change_cache)
2699 + resource->res_cached = cache_type;
2700 +
2701 + if (resource->map_count) {
2702 + ioparam->addr =
2703 + vmcs_sm_usr_address_from_pid_and_usr_handle(
2704 + current->tgid, ioparam->handle);
2705 +
2706 + pr_debug("[%s] map_count %d private->pid %d current->tgid %d hnd %x addr %u\n",
2707 + __func__, resource->map_count, private->pid,
2708 + current->tgid, ioparam->handle, ioparam->addr);
2709 + } else {
2710 + /* Kernel allocated resources.
2711 + */
2712 + if (resource->pid == 0) {
2713 + pr_debug("[%s]: attempt mapping kernel resource - guid %x, hdl %x\n",
2714 + __func__, ioparam->handle, lock.res_handle);
2715 +
2716 + ioparam->addr = 0;
2717 +
2718 + map = kzalloc(sizeof(*map), GFP_KERNEL);
2719 + if (map == NULL) {
2720 + pr_err("[%s]: failed allocating tracker\n",
2721 + __func__);
2722 + ret = -ENOMEM;
2723 + goto error;
2724 + } else {
2725 + phys_addr = (uint32_t)resource->res_base_mem &
2726 + 0x3FFFFFFF;
2727 + phys_addr += mm_vc_mem_phys_addr;
2728 + if (resource->res_cached
2729 + == VMCS_SM_CACHE_HOST) {
2730 + ioparam->addr = (long unsigned int)
2731 + /* TODO - make cached work */
2732 + ioremap_nocache(phys_addr,
2733 + resource->res_size);
2734 +
2735 + pr_debug("[%s]: mapping kernel - guid %x, hdl %x - cached mapping %u\n",
2736 + __func__, ioparam->handle,
2737 + lock.res_handle, ioparam->addr);
2738 + } else {
2739 + ioparam->addr = (long unsigned int)
2740 + ioremap_nocache(phys_addr,
2741 + resource->res_size);
2742 +
2743 + pr_debug("[%s]: mapping kernel- guid %x, hdl %x - non cached mapping %u\n",
2744 + __func__, ioparam->handle,
2745 + lock.res_handle, ioparam->addr);
2746 + }
2747 +
2748 + map->res_pid = 0;
2749 + map->res_vc_hdl = resource->res_handle;
2750 + map->res_usr_hdl = resource->res_guid;
2751 + map->res_addr = ioparam->addr;
2752 + map->resource = resource;
2753 + map->vma = NULL;
2754 +
2755 + vmcs_sm_add_map(sm_state, resource, map);
2756 + }
2757 + } else
2758 + ioparam->addr = 0;
2759 + }
2760 +
2761 +error:
2762 + if (resource)
2763 + vmcs_sm_release_resource(resource, 0);
2764 +
2765 + return ret;
2766 +}
2767 +
2768 +/* Unlock a previously allocated shared memory handle and block.
2769 +*/
2770 +static int vc_sm_ioctl_unlock(struct SM_PRIV_DATA_T *private,
2771 + struct vmcs_sm_ioctl_lock_unlock *ioparam,
2772 + int flush, int wait_reply, int no_vc_unlock)
2773 +{
2774 + int status;
2775 + VC_SM_LOCK_UNLOCK_T unlock;
2776 + struct sm_mmap *map, *map_tmp;
2777 + struct SM_RESOURCE_T *resource;
2778 + int ret = 0;
2779 +
2780 + map = NULL;
2781 +
2782 + /* Locate resource from GUID.
2783 + */
2784 + resource = vmcs_sm_acquire_resource(private, ioparam->handle);
2785 + if (resource == NULL) {
2786 + ret = -EINVAL;
2787 + goto error;
2788 + }
2789 +
2790 + /* Check permissions.
2791 + */
2792 + if (resource->pid && (resource->pid != current->tgid)) {
2793 + pr_err("[%s]: current tgid %u != %u owner\n",
2794 + __func__, current->tgid, resource->pid);
2795 + ret = -EPERM;
2796 + goto error;
2797 + }
2798 +
2799 + unlock.res_handle = resource->res_handle;
2800 + unlock.res_mem = resource->res_base_mem;
2801 +
2802 + pr_debug("[%s]: attempt to unlock data - guid %x, hdl %x, base address %p\n",
2803 + __func__, ioparam->handle, unlock.res_handle, unlock.res_mem);
2804 +
2805 + /* User space allocated resources.
2806 + */
2807 + if (resource->pid) {
2808 + /* Flush if requested */
2809 + if (resource->res_cached && flush) {
2810 + dma_addr_t phys_addr = 0;
2811 + resource->res_stats[FLUSH]++;
2812 +
2813 + phys_addr =
2814 + (dma_addr_t)((uint32_t)resource->res_base_mem &
2815 + 0x3FFFFFFF);
2816 + phys_addr += (dma_addr_t)mm_vc_mem_phys_addr;
2817 +
2818 + /* L1 cache flush */
2819 + down_read(&current->mm->mmap_sem);
2820 + list_for_each_entry(map, &resource->map_list,
2821 + resource_map_list) {
2822 + if (map->vma) {
2823 + unsigned long start;
2824 + unsigned long end;
2825 + start = map->vma->vm_start;
2826 + end = map->vma->vm_end;
2827 +
2828 + vcsm_vma_cache_clean_page_range(
2829 + start, end);
2830 + }
2831 + }
2832 + up_read(&current->mm->mmap_sem);
2833 +
2834 + /* L2 cache flush */
2835 + outer_clean_range(phys_addr,
2836 + phys_addr +
2837 + (size_t) resource->res_size);
2838 + }
2839 +
2840 + /* We need to zap all the vmas associated with this resource */
2841 + if (resource->lock_count == 1) {
2842 + down_read(&current->mm->mmap_sem);
2843 + list_for_each_entry(map, &resource->map_list,
2844 + resource_map_list) {
2845 + if (map->vma) {
2846 + zap_vma_ptes(map->vma,
2847 + map->vma->vm_start,
2848 + map->vma->vm_end -
2849 + map->vma->vm_start);
2850 + }
2851 + }
2852 + up_read(&current->mm->mmap_sem);
2853 + }
2854 + }
2855 + /* Kernel allocated resources. */
2856 + else {
2857 + /* Global + Taken in this context */
2858 + if (resource->ref_count == 2) {
2859 + if (!list_empty(&resource->map_list)) {
2860 + list_for_each_entry_safe(map, map_tmp,
2861 + &resource->map_list,
2862 + resource_map_list) {
2863 + if (map->res_addr) {
2864 + if (flush &&
2865 + (resource->res_cached ==
2866 + VMCS_SM_CACHE_HOST)) {
2867 + long unsigned int
2868 + phys_addr;
2869 + phys_addr = (uint32_t)
2870 + resource->res_base_mem & 0x3FFFFFFF;
2871 + phys_addr +=
2872 + mm_vc_mem_phys_addr;
2873 +
2874 + /* L1 cache flush */
2875 + dmac_flush_range((const
2876 + void
2877 + *)
2878 + map->res_addr, (const void *)
2879 + (map->res_addr + resource->res_size));
2880 +
2881 + /* L2 cache flush */
2882 + outer_clean_range
2883 + (phys_addr,
2884 + phys_addr +
2885 + (size_t)
2886 + resource->res_size);
2887 + }
2888 +
2889 + iounmap((void *)map->res_addr);
2890 + map->res_addr = 0;
2891 +
2892 + vmcs_sm_remove_map(sm_state,
2893 + map->resource,
2894 + map);
2895 + break;
2896 + }
2897 + }
2898 + }
2899 + }
2900 + }
2901 +
2902 + if (resource->lock_count) {
2903 + /* Bypass the videocore unlock.
2904 + */
2905 + if (no_vc_unlock)
2906 + status = 0;
2907 + /* Unlock the videocore allocated resource.
2908 + */
2909 + else {
2910 + status =
2911 + vc_vchi_sm_unlock(sm_state->sm_handle, &unlock,
2912 + &private->int_trans_id,
2913 + wait_reply);
2914 + if (status == -EINTR) {
2915 + pr_debug("[%s]: requesting unlock memory action restart (trans_id: %u)\n",
2916 + __func__, private->int_trans_id);
2917 +
2918 + ret = -ERESTARTSYS;
2919 + resource->res_stats[UNLOCK]--;
2920 + private->restart_sys = -EINTR;
2921 + private->int_action = VC_SM_MSG_TYPE_UNLOCK;
2922 + goto error;
2923 + } else if (status != 0) {
2924 + pr_err("[%s]: failed to unlock vc mem (status: %u, trans_id: %u)\n",
2925 + __func__, status, private->int_trans_id);
2926 +
2927 + ret = -EPERM;
2928 + resource->res_stats[UNLOCK_FAIL]++;
2929 + goto error;
2930 + }
2931 + }
2932 +
2933 + resource->res_stats[UNLOCK]++;
2934 + resource->lock_count--;
2935 + }
2936 +
2937 + pr_debug("[%s]: success to unlock data - hdl %x, base address %p, ref-cnt %d\n",
2938 + __func__, unlock.res_handle, unlock.res_mem,
2939 + resource->lock_count);
2940 +
2941 +error:
2942 + if (resource)
2943 + vmcs_sm_release_resource(resource, 0);
2944 +
2945 + return ret;
2946 +}
2947 +
2948 +/* Handle control from host. */
2949 +static long vc_sm_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
2950 +{
2951 + int ret = 0;
2952 + unsigned int cmdnr = _IOC_NR(cmd);
2953 + struct SM_PRIV_DATA_T *file_data =
2954 + (struct SM_PRIV_DATA_T *)file->private_data;
2955 + struct SM_RESOURCE_T *resource = NULL;
2956 +
2957 + /* Validate we can work with this device. */
2958 + if ((sm_state == NULL) || (file_data == NULL)) {
2959 + pr_err("[%s]: invalid device\n", __func__);
2960 + ret = -EPERM;
2961 + goto out;
2962 + }
2963 +
2964 + pr_debug("[%s]: cmd %x tgid %u, owner %u\n", __func__, cmdnr,
2965 + current->tgid, file_data->pid);
2966 +
2967 + /* Action is a re-post of a previously interrupted action? */
2968 + if (file_data->restart_sys == -EINTR) {
2969 + VC_SM_ACTION_CLEAN_T action_clean;
2970 +
2971 + pr_debug("[%s]: clean up of action %u (trans_id: %u) following EINTR\n",
2972 + __func__, file_data->int_action,
2973 + file_data->int_trans_id);
2974 +
2975 + action_clean.res_action = file_data->int_action;
2976 + action_clean.action_trans_id = file_data->int_trans_id;
2977 +
2978 + vc_vchi_sm_clean_up(sm_state->sm_handle, &action_clean);
2979 +
2980 + file_data->restart_sys = 0;
2981 + }
2982 +
2983 + /* Now process the command.
2984 + */
2985 + switch (cmdnr) {
2986 + /* New memory allocation.
2987 + */
2988 + case VMCS_SM_CMD_ALLOC:
2989 + {
2990 + struct vmcs_sm_ioctl_alloc ioparam;
2991 +
2992 + /* Get the parameter data.
2993 + */
2994 + if (copy_from_user
2995 + (&ioparam, (void *)arg, sizeof(ioparam)) != 0) {
2996 + pr_err("[%s]: failed to copy-from-user for cmd %x\n",
2997 + __func__, cmdnr);
2998 + ret = -EFAULT;
2999 + goto out;
3000 + }
3001 +
3002 + ret = vc_sm_ioctl_alloc(file_data, &ioparam);
3003 + if (!ret &&
3004 + (copy_to_user((void *)arg,
3005 + &ioparam, sizeof(ioparam)) != 0)) {
3006 + struct vmcs_sm_ioctl_free freeparam = {
3007 + ioparam.handle
3008 + };
3009 + pr_err("[%s]: failed to copy-to-user for cmd %x\n",
3010 + __func__, cmdnr);
3011 + vc_sm_ioctl_free(file_data, &freeparam);
3012 + ret = -EFAULT;
3013 + }
3014 +
3015 + /* Done.
3016 + */
3017 + goto out;
3018 + }
3019 + break;
3020 +
3021 + /* Share existing memory allocation.
3022 + */
3023 + case VMCS_SM_CMD_ALLOC_SHARE:
3024 + {
3025 + struct vmcs_sm_ioctl_alloc_share ioparam;
3026 +
3027 + /* Get the parameter data.
3028 + */
3029 + if (copy_from_user
3030 + (&ioparam, (void *)arg, sizeof(ioparam)) != 0) {
3031 + pr_err("[%s]: failed to copy-from-user for cmd %x\n",
3032 + __func__, cmdnr);
3033 + ret = -EFAULT;
3034 + goto out;
3035 + }
3036 +
3037 + ret = vc_sm_ioctl_alloc_share(file_data, &ioparam);
3038 +
3039 + /* Copy result back to user.
3040 + */
3041 + if (!ret
3042 + && copy_to_user((void *)arg, &ioparam,
3043 + sizeof(ioparam)) != 0) {
3044 + struct vmcs_sm_ioctl_free freeparam = {
3045 + ioparam.handle
3046 + };
3047 + pr_err("[%s]: failed to copy-to-user for cmd %x\n",
3048 + __func__, cmdnr);
3049 + vc_sm_ioctl_free(file_data, &freeparam);
3050 + ret = -EFAULT;
3051 + }
3052 +
3053 + /* Done.
3054 + */
3055 + goto out;
3056 + }
3057 + break;
3058 +
3059 + /* Lock (attempt to) *and* register a cache behavior change.
3060 + */
3061 + case VMCS_SM_CMD_LOCK_CACHE:
3062 + {
3063 + struct vmcs_sm_ioctl_lock_cache ioparam;
3064 + struct vmcs_sm_ioctl_lock_unlock lock;
3065 +
3066 + /* Get parameter data.
3067 + */
3068 + if (copy_from_user
3069 + (&ioparam, (void *)arg, sizeof(ioparam)) != 0) {
3070 + pr_err("[%s]: failed to copy-from-user for cmd %x\n",
3071 + __func__, cmdnr);
3072 + ret = -EFAULT;
3073 + goto out;
3074 + }
3075 +
3076 + lock.handle = ioparam.handle;
3077 + ret =
3078 + vc_sm_ioctl_lock(file_data, &lock, 1,
3079 + ioparam.cached, 0);
3080 +
3081 + /* Done.
3082 + */
3083 + goto out;
3084 + }
3085 + break;
3086 +
3087 + /* Lock (attempt to) existing memory allocation.
3088 + */
3089 + case VMCS_SM_CMD_LOCK:
3090 + {
3091 + struct vmcs_sm_ioctl_lock_unlock ioparam;
3092 +
3093 + /* Get parameter data.
3094 + */
3095 + if (copy_from_user
3096 + (&ioparam, (void *)arg, sizeof(ioparam)) != 0) {
3097 + pr_err("[%s]: failed to copy-from-user for cmd %x\n",
3098 + __func__, cmdnr);
3099 + ret = -EFAULT;
3100 + goto out;
3101 + }
3102 +
3103 + ret = vc_sm_ioctl_lock(file_data, &ioparam, 0, 0, 0);
3104 +
3105 + /* Copy result back to user.
3106 + */
3107 + if (copy_to_user((void *)arg, &ioparam, sizeof(ioparam))
3108 + != 0) {
3109 + pr_err("[%s]: failed to copy-to-user for cmd %x\n",
3110 + __func__, cmdnr);
3111 + ret = -EFAULT;
3112 + }
3113 +
3114 + /* Done.
3115 + */
3116 + goto out;
3117 + }
3118 + break;
3119 +
3120 + /* Unlock (attempt to) existing memory allocation.
3121 + */
3122 + case VMCS_SM_CMD_UNLOCK:
3123 + {
3124 + struct vmcs_sm_ioctl_lock_unlock ioparam;
3125 +
3126 + /* Get parameter data.
3127 + */
3128 + if (copy_from_user
3129 + (&ioparam, (void *)arg, sizeof(ioparam)) != 0) {
3130 + pr_err("[%s]: failed to copy-from-user for cmd %x\n",
3131 + __func__, cmdnr);
3132 + ret = -EFAULT;
3133 + goto out;
3134 + }
3135 +
3136 + ret = vc_sm_ioctl_unlock(file_data, &ioparam, 0, 1, 0);
3137 +
3138 + /* Done.
3139 + */
3140 + goto out;
3141 + }
3142 + break;
3143 +
3144 + /* Resize (attempt to) existing memory allocation.
3145 + */
3146 + case VMCS_SM_CMD_RESIZE:
3147 + {
3148 + struct vmcs_sm_ioctl_resize ioparam;
3149 +
3150 + /* Get parameter data.
3151 + */
3152 + if (copy_from_user
3153 + (&ioparam, (void *)arg, sizeof(ioparam)) != 0) {
3154 + pr_err("[%s]: failed to copy-from-user for cmd %x\n",
3155 + __func__, cmdnr);
3156 + ret = -EFAULT;
3157 + goto out;
3158 + }
3159 +
3160 + ret = vc_sm_ioctl_resize(file_data, &ioparam);
3161 +
3162 + /* Copy result back to user.
3163 + */
3164 + if (copy_to_user((void *)arg, &ioparam, sizeof(ioparam))
3165 + != 0) {
3166 + pr_err("[%s]: failed to copy-to-user for cmd %x\n",
3167 + __func__, cmdnr);
3168 + ret = -EFAULT;
3169 + }
3170 +
3171 + /* Done.
3172 + */
3173 + goto out;
3174 + }
3175 + break;
3176 +
3177 + /* Terminate existing memory allocation.
3178 + */
3179 + case VMCS_SM_CMD_FREE:
3180 + {
3181 + struct vmcs_sm_ioctl_free ioparam;
3182 +
3183 + /* Get parameter data.
3184 + */
3185 + if (copy_from_user
3186 + (&ioparam, (void *)arg, sizeof(ioparam)) != 0) {
3187 + pr_err("[%s]: failed to copy-from-user for cmd %x\n",
3188 + __func__, cmdnr);
3189 + ret = -EFAULT;
3190 + goto out;
3191 + }
3192 +
3193 + ret = vc_sm_ioctl_free(file_data, &ioparam);
3194 +
3195 + /* Done.
3196 + */
3197 + goto out;
3198 + }
3199 + break;
3200 +
3201 + /* Walk allocation on videocore, information shows up in the
3202 + ** videocore log.
3203 + */
3204 + case VMCS_SM_CMD_VC_WALK_ALLOC:
3205 + {
3206 + pr_debug("[%s]: invoking walk alloc\n", __func__);
3207 +
3208 + if (vc_vchi_sm_walk_alloc(sm_state->sm_handle) != 0)
3209 + pr_err("[%s]: failed to walk-alloc on videocore\n",
3210 + __func__);
3211 +
3212 + /* Done.
3213 + */
3214 + goto out;
3215 + }
3216 + break;
3217 +/* Walk mapping table on host, information shows up in the
3218 + ** kernel log.
3219 + */
3220 + case VMCS_SM_CMD_HOST_WALK_MAP:
3221 + {
3222 + /* Use pid of -1 to tell to walk the whole map. */
3223 + vmcs_sm_host_walk_map_per_pid(-1);
3224 +
3225 + /* Done. */
3226 + goto out;
3227 + }
3228 + break;
3229 +
3230 + /* Walk mapping table per process on host. */
3231 + case VMCS_SM_CMD_HOST_WALK_PID_ALLOC:
3232 + {
3233 + struct vmcs_sm_ioctl_walk ioparam;
3234 +
3235 + /* Get parameter data. */
3236 + if (copy_from_user(&ioparam,
3237 + (void *)arg, sizeof(ioparam)) != 0) {
3238 + pr_err("[%s]: failed to copy-from-user for cmd %x\n",
3239 + __func__, cmdnr);
3240 + ret = -EFAULT;
3241 + goto out;
3242 + }
3243 +
3244 + vmcs_sm_host_walk_alloc(file_data);
3245 +
3246 + /* Done. */
3247 + goto out;
3248 + }
3249 + break;
3250 +
3251 + /* Walk allocation per process on host. */
3252 + case VMCS_SM_CMD_HOST_WALK_PID_MAP:
3253 + {
3254 + struct vmcs_sm_ioctl_walk ioparam;
3255 +
3256 + /* Get parameter data. */
3257 + if (copy_from_user(&ioparam,
3258 + (void *)arg, sizeof(ioparam)) != 0) {
3259 + pr_err("[%s]: failed to copy-from-user for cmd %x\n",
3260 + __func__, cmdnr);
3261 + ret = -EFAULT;
3262 + goto out;
3263 + }
3264 +
3265 + vmcs_sm_host_walk_map_per_pid(ioparam.pid);
3266 +
3267 + /* Done. */
3268 + goto out;
3269 + }
3270 + break;
3271 +
3272 + /* Gets the size of the memory associated with a user handle. */
3273 + case VMCS_SM_CMD_SIZE_USR_HANDLE:
3274 + {
3275 + struct vmcs_sm_ioctl_size ioparam;
3276 +
3277 + /* Get parameter data. */
3278 + if (copy_from_user(&ioparam,
3279 + (void *)arg, sizeof(ioparam)) != 0) {
3280 + pr_err("[%s]: failed to copy-from-user for cmd %x\n",
3281 + __func__, cmdnr);
3282 + ret = -EFAULT;
3283 + goto out;
3284 + }
3285 +
3286 + /* Locate resource from GUID. */
3287 + resource =
3288 + vmcs_sm_acquire_resource(file_data, ioparam.handle);
3289 + if (resource != NULL) {
3290 + ioparam.size = resource->res_size;
3291 + vmcs_sm_release_resource(resource, 0);
3292 + } else {
3293 + ioparam.size = 0;
3294 + }
3295 +
3296 + if (copy_to_user((void *)arg,
3297 + &ioparam, sizeof(ioparam)) != 0) {
3298 + pr_err("[%s]: failed to copy-to-user for cmd %x\n",
3299 + __func__, cmdnr);
3300 + ret = -EFAULT;
3301 + }
3302 +
3303 + /* Done. */
3304 + goto out;
3305 + }
3306 + break;
3307 +
3308 + /* Verify we are dealing with a valid resource. */
3309 + case VMCS_SM_CMD_CHK_USR_HANDLE:
3310 + {
3311 + struct vmcs_sm_ioctl_chk ioparam;
3312 +
3313 + /* Get parameter data.
3314 + */
3315 + if (copy_from_user(&ioparam,
3316 + (void *)arg, sizeof(ioparam)) != 0) {
3317 + pr_err("[%s]: failed to copy-from-user for cmd %x\n",
3318 + __func__, cmdnr);
3319 +
3320 + ret = -EFAULT;
3321 + goto out;
3322 + }
3323 +
3324 + /* Locate resource from GUID. */
3325 + resource =
3326 + vmcs_sm_acquire_resource(file_data, ioparam.handle);
3327 + if (resource == NULL)
3328 + ret = -EINVAL;
3329 + /* If the resource is cacheable, return additional
3330 + * information that may be needed to flush the cache.
3331 + */
3332 + else if ((resource->res_cached == VMCS_SM_CACHE_HOST) ||
3333 + (resource->res_cached == VMCS_SM_CACHE_BOTH)) {
3334 + ioparam.addr =
3335 + vmcs_sm_usr_address_from_pid_and_usr_handle
3336 + (current->tgid, ioparam.handle);
3337 + ioparam.size = resource->res_size;
3338 + ioparam.cache = resource->res_cached;
3339 + } else {
3340 + ioparam.addr = 0;
3341 + ioparam.size = 0;
3342 + ioparam.cache = resource->res_cached;
3343 + }
3344 +
3345 + if (resource)
3346 + vmcs_sm_release_resource(resource, 0);
3347 +
3348 + if (copy_to_user((void *)arg,
3349 + &ioparam, sizeof(ioparam)) != 0) {
3350 + pr_err("[%s]: failed to copy-to-user for cmd %x\n",
3351 + __func__, cmdnr);
3352 + ret = -EFAULT;
3353 + }
3354 +
3355 + /* Done.
3356 + */
3357 + goto out;
3358 + }
3359 + break;
3360 +
3361 + /*
3362 + * Maps a user handle given the process and the virtual address.
3363 + */
3364 + case VMCS_SM_CMD_MAPPED_USR_HANDLE:
3365 + {
3366 + struct vmcs_sm_ioctl_map ioparam;
3367 +
3368 + /* Get parameter data. */
3369 + if (copy_from_user(&ioparam,
3370 + (void *)arg, sizeof(ioparam)) != 0) {
3371 + pr_err("[%s]: failed to copy-from-user for cmd %x\n",
3372 + __func__, cmdnr);
3373 +
3374 + ret = -EFAULT;
3375 + goto out;
3376 + }
3377 +
3378 + ioparam.handle =
3379 + vmcs_sm_usr_handle_from_pid_and_address(
3380 + ioparam.pid, ioparam.addr);
3381 +
3382 + resource =
3383 + vmcs_sm_acquire_resource(file_data, ioparam.handle);
3384 + if ((resource != NULL)
3385 + && ((resource->res_cached == VMCS_SM_CACHE_HOST)
3386 + || (resource->res_cached ==
3387 + VMCS_SM_CACHE_BOTH))) {
3388 + ioparam.size = resource->res_size;
3389 + } else {
3390 + ioparam.size = 0;
3391 + }
3392 +
3393 + if (resource)
3394 + vmcs_sm_release_resource(resource, 0);
3395 +
3396 + if (copy_to_user((void *)arg,
3397 + &ioparam, sizeof(ioparam)) != 0) {
3398 + pr_err("[%s]: failed to copy-to-user for cmd %x\n",
3399 + __func__, cmdnr);
3400 + ret = -EFAULT;
3401 + }
3402 +
3403 + /* Done. */
3404 + goto out;
3405 + }
3406 + break;
3407 +
3408 + /*
3409 + * Maps a videocore handle given process and virtual address.
3410 + */
3411 + case VMCS_SM_CMD_MAPPED_VC_HDL_FROM_ADDR:
3412 + {
3413 + struct vmcs_sm_ioctl_map ioparam;
3414 +
3415 + /* Get parameter data. */
3416 + if (copy_from_user(&ioparam,
3417 + (void *)arg, sizeof(ioparam)) != 0) {
3418 + pr_err("[%s]: failed to copy-from-user for cmd %x\n",
3419 + __func__, cmdnr);
3420 + ret = -EFAULT;
3421 + goto out;
3422 + }
3423 +
3424 + ioparam.handle = vmcs_sm_vc_handle_from_pid_and_address(
3425 + ioparam.pid, ioparam.addr);
3426 +
3427 + if (copy_to_user((void *)arg,
3428 + &ioparam, sizeof(ioparam)) != 0) {
3429 + pr_err("[%s]: failed to copy-to-user for cmd %x\n",
3430 + __func__, cmdnr);
3431 +
3432 + ret = -EFAULT;
3433 + }
3434 +
3435 + /* Done.
3436 + */
3437 + goto out;
3438 + }
3439 + break;
3440 +
3441 + /* Maps a videocore handle given process and user handle. */
3442 + case VMCS_SM_CMD_MAPPED_VC_HDL_FROM_HDL:
3443 + {
3444 + struct vmcs_sm_ioctl_map ioparam;
3445 +
3446 + /* Get parameter data. */
3447 + if (copy_from_user(&ioparam,
3448 + (void *)arg, sizeof(ioparam)) != 0) {
3449 + pr_err("[%s]: failed to copy-from-user for cmd %x\n",
3450 + __func__, cmdnr);
3451 + ret = -EFAULT;
3452 + goto out;
3453 + }
3454 +
3455 + /* Locate resource from GUID. */
3456 + resource =
3457 + vmcs_sm_acquire_resource(file_data, ioparam.handle);
3458 + if (resource != NULL) {
3459 + ioparam.handle = resource->res_handle;
3460 + vmcs_sm_release_resource(resource, 0);
3461 + } else {
3462 + ioparam.handle = 0;
3463 + }
3464 +
3465 + if (copy_to_user((void *)arg,
3466 + &ioparam, sizeof(ioparam)) != 0) {
3467 + pr_err("[%s]: failed to copy-to-user for cmd %x\n",
3468 + __func__, cmdnr);
3469 +
3470 + ret = -EFAULT;
3471 + }
3472 +
3473 + /* Done. */
3474 + goto out;
3475 + }
3476 + break;
3477 +
3478 + /*
3479 + * Maps a videocore address given process and videocore handle.
3480 + */
3481 + case VMCS_SM_CMD_MAPPED_VC_ADDR_FROM_HDL:
3482 + {
3483 + struct vmcs_sm_ioctl_map ioparam;
3484 +
3485 + /* Get parameter data. */
3486 + if (copy_from_user(&ioparam,
3487 + (void *)arg, sizeof(ioparam)) != 0) {
3488 + pr_err("[%s]: failed to copy-from-user for cmd %x\n",
3489 + __func__, cmdnr);
3490 +
3491 + ret = -EFAULT;
3492 + goto out;
3493 + }
3494 +
3495 + /* Locate resource from GUID. */
3496 + resource =
3497 + vmcs_sm_acquire_resource(file_data, ioparam.handle);
3498 + if (resource != NULL) {
3499 + ioparam.addr =
3500 + (unsigned int)resource->res_base_mem;
3501 + vmcs_sm_release_resource(resource, 0);
3502 + } else {
3503 + ioparam.addr = 0;
3504 + }
3505 +
3506 + if (copy_to_user((void *)arg,
3507 + &ioparam, sizeof(ioparam)) != 0) {
3508 + pr_err("[%s]: failed to copy-to-user for cmd %x\n",
3509 + __func__, cmdnr);
3510 + ret = -EFAULT;
3511 + }
3512 +
3513 + /* Done. */
3514 + goto out;
3515 + }
3516 + break;
3517 +
3518 + /* Maps a user address given process and vc handle.
3519 + */
3520 + case VMCS_SM_CMD_MAPPED_USR_ADDRESS:
3521 + {
3522 + struct vmcs_sm_ioctl_map ioparam;
3523 +
3524 + /* Get parameter data. */
3525 + if (copy_from_user(&ioparam,
3526 + (void *)arg, sizeof(ioparam)) != 0) {
3527 + pr_err("[%s]: failed to copy-from-user for cmd %x\n",
3528 + __func__, cmdnr);
3529 + ret = -EFAULT;
3530 + goto out;
3531 + }
3532 +
3533 + /*
3534 + * Return the address information from the mapping,
3535 + * 0 (ie NULL) if it cannot locate the actual mapping.
3536 + */
3537 + ioparam.addr =
3538 + vmcs_sm_usr_address_from_pid_and_usr_handle
3539 + (ioparam.pid, ioparam.handle);
3540 +
3541 + if (copy_to_user((void *)arg,
3542 + &ioparam, sizeof(ioparam)) != 0) {
3543 + pr_err("[%s]: failed to copy-to-user for cmd %x\n",
3544 + __func__, cmdnr);
3545 + ret = -EFAULT;
3546 + }
3547 +
3548 + /* Done. */
3549 + goto out;
3550 + }
3551 + break;
3552 +
3553 + /* Flush the cache for a given mapping. */
3554 + case VMCS_SM_CMD_FLUSH:
3555 + {
3556 + struct vmcs_sm_ioctl_cache ioparam;
3557 +
3558 + /* Get parameter data. */
3559 + if (copy_from_user(&ioparam,
3560 + (void *)arg, sizeof(ioparam)) != 0) {
3561 + pr_err("[%s]: failed to copy-from-user for cmd %x\n",
3562 + __func__, cmdnr);
3563 + ret = -EFAULT;
3564 + goto out;
3565 + }
3566 +
3567 + /* Locate resource from GUID. */
3568 + resource =
3569 + vmcs_sm_acquire_resource(file_data, ioparam.handle);
3570 +
3571 + if ((resource != NULL) && resource->res_cached) {
3572 + dma_addr_t phys_addr = 0;
3573 +
3574 + resource->res_stats[FLUSH]++;
3575 +
3576 + phys_addr =
3577 + (dma_addr_t)((uint32_t)
3578 + resource->res_base_mem &
3579 + 0x3FFFFFFF);
3580 + phys_addr += (dma_addr_t)mm_vc_mem_phys_addr;
3581 +
3582 + /* L1 cache flush */
3583 + down_read(&current->mm->mmap_sem);
3584 + vcsm_vma_cache_clean_page_range((unsigned long)
3585 + ioparam.addr,
3586 + (unsigned long)
3587 + ioparam.addr +
3588 + ioparam.size);
3589 + up_read(&current->mm->mmap_sem);
3590 +
3591 + /* L2 cache flush */
3592 + outer_clean_range(phys_addr,
3593 + phys_addr +
3594 + (size_t) ioparam.size);
3595 + } else if (resource == NULL) {
3596 + ret = -EINVAL;
3597 + goto out;
3598 + }
3599 +
3600 + if (resource)
3601 + vmcs_sm_release_resource(resource, 0);
3602 +
3603 + /* Done. */
3604 + goto out;
3605 + }
3606 + break;
3607 +
3608 + /* Invalidate the cache for a given mapping. */
3609 + case VMCS_SM_CMD_INVALID:
3610 + {
3611 + struct vmcs_sm_ioctl_cache ioparam;
3612 +
3613 + /* Get parameter data. */
3614 + if (copy_from_user(&ioparam,
3615 + (void *)arg, sizeof(ioparam)) != 0) {
3616 + pr_err("[%s]: failed to copy-from-user for cmd %x\n",
3617 + __func__, cmdnr);
3618 + ret = -EFAULT;
3619 + goto out;
3620 + }
3621 +
3622 + /* Locate resource from GUID.
3623 + */
3624 + resource =
3625 + vmcs_sm_acquire_resource(file_data, ioparam.handle);
3626 +
3627 + if ((resource != NULL) && resource->res_cached) {
3628 + dma_addr_t phys_addr = 0;
3629 +
3630 + resource->res_stats[INVALID]++;
3631 +
3632 + phys_addr =
3633 + (dma_addr_t)((uint32_t)
3634 + resource->res_base_mem &
3635 + 0x3FFFFFFF);
3636 + phys_addr += (dma_addr_t)mm_vc_mem_phys_addr;
3637 +
3638 + /* L2 cache invalidate */
3639 + outer_inv_range(phys_addr,
3640 + phys_addr +
3641 + (size_t) ioparam.size);
3642 +
3643 + /* L1 cache invalidate */
3644 + down_read(&current->mm->mmap_sem);
3645 + vcsm_vma_cache_clean_page_range((unsigned long)
3646 + ioparam.addr,
3647 + (unsigned long)
3648 + ioparam.addr +
3649 + ioparam.size);
3650 + up_read(&current->mm->mmap_sem);
3651 + } else if (resource == NULL) {
3652 + ret = -EINVAL;
3653 + goto out;
3654 + }
3655 +
3656 + if (resource)
3657 + vmcs_sm_release_resource(resource, 0);
3658 +
3659 + /* Done.
3660 + */
3661 + goto out;
3662 + }
3663 + break;
3664 +
3665 + /* Flush/Invalidate the cache for a given mapping. */
3666 + case VMCS_SM_CMD_CLEAN_INVALID:
3667 + {
3668 + int i;
3669 + struct vmcs_sm_ioctl_clean_invalid ioparam;
3670 +
3671 + /* Get parameter data. */
3672 + if (copy_from_user(&ioparam,
3673 + (void *)arg, sizeof(ioparam)) != 0) {
3674 + pr_err("[%s]: failed to copy-from-user for cmd %x\n",
3675 + __func__, cmdnr);
3676 + ret = -EFAULT;
3677 + goto out;
3678 + }
3679 + for (i=0; i<sizeof ioparam.s/sizeof *ioparam.s; i++) {
3680 + switch (ioparam.s[i].cmd) {
3681 + default: case 0: break; /* NOOP */
3682 + case 1: /* L1/L2 invalidate virtual range */
3683 + case 2: /* L1/L2 clean physical range */
3684 + case 3: /* L1/L2 clean+invalidate all */
3685 + {
3686 + /* Locate resource from GUID.
3687 + */
3688 + resource =
3689 + vmcs_sm_acquire_resource(file_data, ioparam.s[i].handle);
3690 +
3691 + if ((resource != NULL) && resource->res_cached) {
3692 + unsigned long base = ioparam.s[i].addr & ~(PAGE_SIZE-1);
3693 + unsigned long end = (ioparam.s[i].addr + ioparam.s[i].size + PAGE_SIZE-1) & ~(PAGE_SIZE-1);
3694 + resource->res_stats[ioparam.s[i].cmd == 1 ? INVALID:FLUSH]++;
3695 +
3696 + /* L1/L2 cache flush */
3697 + down_read(&current->mm->mmap_sem);
3698 + vcsm_vma_cache_clean_page_range(base, end);
3699 + up_read(&current->mm->mmap_sem);
3700 + } else if (resource == NULL) {
3701 + ret = -EINVAL;
3702 + goto out;
3703 + }
3704 +
3705 + if (resource)
3706 + vmcs_sm_release_resource(resource, 0);
3707 + }
3708 + break;
3709 + }
3710 + }
3711 + }
3712 + break;
3713 +
3714 + default:
3715 + {
3716 + ret = -EINVAL;
3717 + goto out;
3718 + }
3719 + break;
3720 + }
3721 +
3722 +out:
3723 + return ret;
3724 +}
3725 +
3726 +/* Device operations that we managed in this driver.
3727 +*/
3728 +static const struct file_operations vmcs_sm_ops = {
3729 + .owner = THIS_MODULE,
3730 + .unlocked_ioctl = vc_sm_ioctl,
3731 + .open = vc_sm_open,
3732 + .release = vc_sm_release,
3733 + .mmap = vc_sm_mmap,
3734 +};
3735 +
3736 +/* Creation of device.
3737 +*/
3738 +static int vc_sm_create_sharedmemory(void)
3739 +{
3740 + int ret;
3741 +
3742 + if (sm_state == NULL) {
3743 + ret = -ENOMEM;
3744 + goto out;
3745 + }
3746 +
3747 + /* Create a device class for creating dev nodes.
3748 + */
3749 + sm_state->sm_class = class_create(THIS_MODULE, "vc-sm");
3750 + if (IS_ERR(sm_state->sm_class)) {
3751 + pr_err("[%s]: unable to create device class\n", __func__);
3752 + ret = PTR_ERR(sm_state->sm_class);
3753 + goto out;
3754 + }
3755 +
3756 + /* Create a character driver.
3757 + */
3758 + ret = alloc_chrdev_region(&sm_state->sm_devid,
3759 + DEVICE_MINOR, 1, DEVICE_NAME);
3760 + if (ret != 0) {
3761 + pr_err("[%s]: unable to allocate device number\n", __func__);
3762 + goto out_dev_class_destroy;
3763 + }
3764 +
3765 + cdev_init(&sm_state->sm_cdev, &vmcs_sm_ops);
3766 + ret = cdev_add(&sm_state->sm_cdev, sm_state->sm_devid, 1);
3767 + if (ret != 0) {
3768 + pr_err("[%s]: unable to register device\n", __func__);
3769 + goto out_chrdev_unreg;
3770 + }
3771 +
3772 + /* Create a device node.
3773 + */
3774 + sm_state->sm_dev = device_create(sm_state->sm_class,
3775 + NULL,
3776 + MKDEV(MAJOR(sm_state->sm_devid),
3777 + DEVICE_MINOR), NULL,
3778 + DEVICE_NAME);
3779 + if (IS_ERR(sm_state->sm_dev)) {
3780 + pr_err("[%s]: unable to create device node\n", __func__);
3781 + ret = PTR_ERR(sm_state->sm_dev);
3782 + goto out_chrdev_del;
3783 + }
3784 +
3785 + goto out;
3786 +
3787 +out_chrdev_del:
3788 + cdev_del(&sm_state->sm_cdev);
3789 +out_chrdev_unreg:
3790 + unregister_chrdev_region(sm_state->sm_devid, 1);
3791 +out_dev_class_destroy:
3792 + class_destroy(sm_state->sm_class);
3793 + sm_state->sm_class = NULL;
3794 +out:
3795 + return ret;
3796 +}
3797 +
3798 +/* Termination of the device.
3799 +*/
3800 +static int vc_sm_remove_sharedmemory(void)
3801 +{
3802 + int ret;
3803 +
3804 + if (sm_state == NULL) {
3805 + /* Nothing to do.
3806 + */
3807 + ret = 0;
3808 + goto out;
3809 + }
3810 +
3811 + /* Remove the sharedmemory character driver.
3812 + */
3813 + cdev_del(&sm_state->sm_cdev);
3814 +
3815 + /* Unregister region.
3816 + */
3817 + unregister_chrdev_region(sm_state->sm_devid, 1);
3818 +
3819 + ret = 0;
3820 + goto out;
3821 +
3822 +out:
3823 + return ret;
3824 +}
3825 +
3826 +/* Videocore connected. */
3827 +static void vc_sm_connected_init(void)
3828 +{
3829 + int ret;
3830 + VCHI_INSTANCE_T vchi_instance;
3831 + VCHI_CONNECTION_T *vchi_connection = NULL;
3832 +
3833 + pr_info("[%s]: start\n", __func__);
3834 +
3835 + /* Allocate memory for the state structure.
3836 + */
3837 + sm_state = kzalloc(sizeof(struct SM_STATE_T), GFP_KERNEL);
3838 + if (sm_state == NULL) {
3839 + pr_err("[%s]: failed to allocate memory\n", __func__);
3840 + ret = -ENOMEM;
3841 + goto out;
3842 + }
3843 +
3844 + mutex_init(&sm_state->lock);
3845 + mutex_init(&sm_state->map_lock);
3846 +
3847 + /* Initialize and create a VCHI connection for the shared memory service
3848 + ** running on videocore.
3849 + */
3850 + ret = vchi_initialise(&vchi_instance);
3851 + if (ret != 0) {
3852 + pr_err("[%s]: failed to initialise VCHI instance (ret=%d)\n",
3853 + __func__, ret);
3854 +
3855 + ret = -EIO;
3856 + goto err_free_mem;
3857 + }
3858 +
3859 + ret = vchi_connect(NULL, 0, vchi_instance);
3860 + if (ret != 0) {
3861 + pr_err("[%s]: failed to connect VCHI instance (ret=%d)\n",
3862 + __func__, ret);
3863 +
3864 + ret = -EIO;
3865 + goto err_free_mem;
3866 + }
3867 +
3868 + /* Initialize an instance of the shared memory service. */
3869 + sm_state->sm_handle =
3870 + vc_vchi_sm_init(vchi_instance, &vchi_connection, 1);
3871 + if (sm_state->sm_handle == NULL) {
3872 + pr_err("[%s]: failed to initialize shared memory service\n",
3873 + __func__);
3874 +
3875 + ret = -EPERM;
3876 + goto err_free_mem;
3877 + }
3878 +
3879 + /* Create a debug fs directory entry (root). */
3880 + sm_state->dir_root = debugfs_create_dir(VC_SM_DIR_ROOT_NAME, NULL);
3881 + if (!sm_state->dir_root) {
3882 + pr_err("[%s]: failed to create \'%s\' directory entry\n",
3883 + __func__, VC_SM_DIR_ROOT_NAME);
3884 +
3885 + ret = -EPERM;
3886 + goto err_stop_sm_service;
3887 + }
3888 +
3889 + sm_state->dir_state.show = &vc_sm_global_state_show;
3890 + sm_state->dir_state.dir_entry = debugfs_create_file(VC_SM_STATE,
3891 + S_IRUGO, sm_state->dir_root, &sm_state->dir_state,
3892 + &vc_sm_debug_fs_fops);
3893 +
3894 + sm_state->dir_stats.show = &vc_sm_global_statistics_show;
3895 + sm_state->dir_stats.dir_entry = debugfs_create_file(VC_SM_STATS,
3896 + S_IRUGO, sm_state->dir_root, &sm_state->dir_stats,
3897 + &vc_sm_debug_fs_fops);
3898 +
3899 + /* Create the proc entry children. */
3900 + sm_state->dir_alloc = debugfs_create_dir(VC_SM_DIR_ALLOC_NAME,
3901 + sm_state->dir_root);
3902 +
3903 + /* Create a shared memory device. */
3904 + ret = vc_sm_create_sharedmemory();
3905 + if (ret != 0) {
3906 + pr_err("[%s]: failed to create shared memory device\n",
3907 + __func__);
3908 + goto err_remove_debugfs;
3909 + }
3910 +
3911 + INIT_LIST_HEAD(&sm_state->map_list);
3912 + INIT_LIST_HEAD(&sm_state->resource_list);
3913 +
3914 + sm_state->data_knl = vc_sm_create_priv_data(0);
3915 + if (sm_state->data_knl == NULL) {
3916 + pr_err("[%s]: failed to create kernel private data tracker\n",
3917 + __func__);
3918 + goto err_remove_shared_memory;
3919 + }
3920 +
3921 + /* Done!
3922 + */
3923 + sm_inited = 1;
3924 + goto out;
3925 +
3926 +err_remove_shared_memory:
3927 + vc_sm_remove_sharedmemory();
3928 +err_remove_debugfs:
3929 + debugfs_remove_recursive(sm_state->dir_root);
3930 +err_stop_sm_service:
3931 + vc_vchi_sm_stop(&sm_state->sm_handle);
3932 +err_free_mem:
3933 + kfree(sm_state);
3934 +out:
3935 + pr_info("[%s]: end - returning %d\n", __func__, ret);
3936 +}
3937 +
3938 +/* Driver loading. */
3939 +static int __init vc_sm_init(void)
3940 +{
3941 + pr_info("vc-sm: Videocore shared memory driver\n");
3942 + vchiq_add_connected_callback(vc_sm_connected_init);
3943 + return 0;
3944 +}
3945 +
3946 +/* Driver unloading. */
3947 +static void __exit vc_sm_exit(void)
3948 +{
3949 + pr_debug("[%s]: start\n", __func__);
3950 + if (sm_inited) {
3951 + /* Remove shared memory device.
3952 + */
3953 + vc_sm_remove_sharedmemory();
3954 +
3955 + /* Remove all proc entries.
3956 + */
3957 + debugfs_remove_recursive(sm_state->dir_root);
3958 +
3959 + /* Stop the videocore shared memory service.
3960 + */
3961 + vc_vchi_sm_stop(&sm_state->sm_handle);
3962 +
3963 + /* Free the memory for the state structure.
3964 + */
3965 + mutex_destroy(&(sm_state->map_lock));
3966 + kfree(sm_state);
3967 + }
3968 +
3969 + pr_debug("[%s]: end\n", __func__);
3970 +}
3971 +
3972 +#if defined(__KERNEL__)
3973 +/* Allocate a shared memory handle and block. */
3974 +int vc_sm_alloc(VC_SM_ALLOC_T *alloc, int *handle)
3975 +{
3976 + struct vmcs_sm_ioctl_alloc ioparam = { 0 };
3977 + int ret;
3978 + struct SM_RESOURCE_T *resource;
3979 +
3980 + /* Validate we can work with this device.
3981 + */
3982 + if (sm_state == NULL || alloc == NULL || handle == NULL) {
3983 + pr_err("[%s]: invalid input\n", __func__);
3984 + return -EPERM;
3985 + }
3986 +
3987 + ioparam.size = alloc->base_unit;
3988 + ioparam.num = alloc->num_unit;
3989 + ioparam.cached =
3990 + alloc->type == VC_SM_ALLOC_CACHED ? VMCS_SM_CACHE_VC : 0;
3991 +
3992 + ret = vc_sm_ioctl_alloc(sm_state->data_knl, &ioparam);
3993 +
3994 + if (ret == 0) {
3995 + resource =
3996 + vmcs_sm_acquire_resource(sm_state->data_knl,
3997 + ioparam.handle);
3998 + if (resource) {
3999 + resource->pid = 0;
4000 + vmcs_sm_release_resource(resource, 0);
4001 +
4002 + /* Assign valid handle at this time.
4003 + */
4004 + *handle = ioparam.handle;
4005 + } else {
4006 + ret = -ENOMEM;
4007 + }
4008 + }
4009 +
4010 + return ret;
4011 +}
4012 +EXPORT_SYMBOL_GPL(vc_sm_alloc);
4013 +
4014 +/* Get an internal resource handle mapped from the external one.
4015 +*/
4016 +int vc_sm_int_handle(int handle)
4017 +{
4018 + struct SM_RESOURCE_T *resource;
4019 + int ret = 0;
4020 +
4021 + /* Validate we can work with this device.
4022 + */
4023 + if (sm_state == NULL || handle == 0) {
4024 + pr_err("[%s]: invalid input\n", __func__);
4025 + return 0;
4026 + }
4027 +
4028 + /* Locate resource from GUID.
4029 + */
4030 + resource = vmcs_sm_acquire_resource(sm_state->data_knl, handle);
4031 + if (resource) {
4032 + ret = resource->res_handle;
4033 + vmcs_sm_release_resource(resource, 0);
4034 + }
4035 +
4036 + return ret;
4037 +}
4038 +EXPORT_SYMBOL_GPL(vc_sm_int_handle);
4039 +
4040 +/* Free a previously allocated shared memory handle and block.
4041 +*/
4042 +int vc_sm_free(int handle)
4043 +{
4044 + struct vmcs_sm_ioctl_free ioparam = { handle };
4045 +
4046 + /* Validate we can work with this device.
4047 + */
4048 + if (sm_state == NULL || handle == 0) {
4049 + pr_err("[%s]: invalid input\n", __func__);
4050 + return -EPERM;
4051 + }
4052 +
4053 + return vc_sm_ioctl_free(sm_state->data_knl, &ioparam);
4054 +}
4055 +EXPORT_SYMBOL_GPL(vc_sm_free);
4056 +
4057 +/* Lock a memory handle for use by kernel.
4058 +*/
4059 +int vc_sm_lock(int handle, VC_SM_LOCK_CACHE_MODE_T mode,
4060 + long unsigned int *data)
4061 +{
4062 + struct vmcs_sm_ioctl_lock_unlock ioparam;
4063 + int ret;
4064 +
4065 + /* Validate we can work with this device.
4066 + */
4067 + if (sm_state == NULL || handle == 0 || data == NULL) {
4068 + pr_err("[%s]: invalid input\n", __func__);
4069 + return -EPERM;
4070 + }
4071 +
4072 + *data = 0;
4073 +
4074 + ioparam.handle = handle;
4075 + ret = vc_sm_ioctl_lock(sm_state->data_knl,
4076 + &ioparam,
4077 + 1,
4078 + ((mode ==
4079 + VC_SM_LOCK_CACHED) ? VMCS_SM_CACHE_HOST :
4080 + VMCS_SM_CACHE_NONE), 0);
4081 +
4082 + *data = ioparam.addr;
4083 + return ret;
4084 +}
4085 +EXPORT_SYMBOL_GPL(vc_sm_lock);
4086 +
4087 +/* Unlock a memory handle in use by kernel.
4088 +*/
4089 +int vc_sm_unlock(int handle, int flush, int no_vc_unlock)
4090 +{
4091 + struct vmcs_sm_ioctl_lock_unlock ioparam;
4092 +
4093 + /* Validate we can work with this device.
4094 + */
4095 + if (sm_state == NULL || handle == 0) {
4096 + pr_err("[%s]: invalid input\n", __func__);
4097 + return -EPERM;
4098 + }
4099 +
4100 + ioparam.handle = handle;
4101 + return vc_sm_ioctl_unlock(sm_state->data_knl,
4102 + &ioparam, flush, 0, no_vc_unlock);
4103 +}
4104 +EXPORT_SYMBOL_GPL(vc_sm_unlock);
4105 +
4106 +/* Map a shared memory region for use by kernel.
4107 +*/
4108 +int vc_sm_map(int handle, unsigned int sm_addr, VC_SM_LOCK_CACHE_MODE_T mode,
4109 + long unsigned int *data)
4110 +{
4111 + struct vmcs_sm_ioctl_lock_unlock ioparam;
4112 + int ret;
4113 +
4114 + /* Validate we can work with this device.
4115 + */
4116 + if (sm_state == NULL || handle == 0 || data == NULL || sm_addr == 0) {
4117 + pr_err("[%s]: invalid input\n", __func__);
4118 + return -EPERM;
4119 + }
4120 +
4121 + *data = 0;
4122 +
4123 + ioparam.handle = handle;
4124 + ret = vc_sm_ioctl_lock(sm_state->data_knl,
4125 + &ioparam,
4126 + 1,
4127 + ((mode ==
4128 + VC_SM_LOCK_CACHED) ? VMCS_SM_CACHE_HOST :
4129 + VMCS_SM_CACHE_NONE), sm_addr);
4130 +
4131 + *data = ioparam.addr;
4132 + return ret;
4133 +}
4134 +EXPORT_SYMBOL_GPL(vc_sm_map);
4135 +#endif
4136 +
4137 +late_initcall(vc_sm_init);
4138 +module_exit(vc_sm_exit);
4139 +
4140 +MODULE_AUTHOR("Broadcom");
4141 +MODULE_DESCRIPTION("VideoCore SharedMemory Driver");
4142 +MODULE_LICENSE("GPL v2");
4143 --- /dev/null
4144 +++ b/include/linux/broadcom/vmcs_sm_ioctl.h
4145 @@ -0,0 +1,248 @@
4146 +/*****************************************************************************
4147 +* Copyright 2011 Broadcom Corporation. All rights reserved.
4148 +*
4149 +* Unless you and Broadcom execute a separate written software license
4150 +* agreement governing use of this software, this software is licensed to you
4151 +* under the terms of the GNU General Public License version 2, available at
4152 +* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
4153 +*
4154 +* Notwithstanding the above, under no circumstances may you combine this
4155 +* software in any way with any other Broadcom software provided under a
4156 +* license other than the GPL, without Broadcom's express prior written
4157 +* consent.
4158 +*
4159 +*****************************************************************************/
4160 +
4161 +#if !defined(__VMCS_SM_IOCTL_H__INCLUDED__)
4162 +#define __VMCS_SM_IOCTL_H__INCLUDED__
4163 +
4164 +/* ---- Include Files ---------------------------------------------------- */
4165 +
4166 +#if defined(__KERNEL__)
4167 +#include <linux/types.h> /* Needed for standard types */
4168 +#else
4169 +#include <stdint.h>
4170 +#endif
4171 +
4172 +#include <linux/ioctl.h>
4173 +
4174 +/* ---- Constants and Types ---------------------------------------------- */
4175 +
4176 +#define VMCS_SM_RESOURCE_NAME 32
4177 +#define VMCS_SM_RESOURCE_NAME_DEFAULT "sm-host-resource"
4178 +
4179 +/* Type define used to create unique IOCTL number */
4180 +#define VMCS_SM_MAGIC_TYPE 'I'
4181 +
4182 +/* IOCTL commands */
4183 +enum vmcs_sm_cmd_e {
4184 + VMCS_SM_CMD_ALLOC = 0x5A, /* Start at 0x5A arbitrarily */
4185 + VMCS_SM_CMD_ALLOC_SHARE,
4186 + VMCS_SM_CMD_LOCK,
4187 + VMCS_SM_CMD_LOCK_CACHE,
4188 + VMCS_SM_CMD_UNLOCK,
4189 + VMCS_SM_CMD_RESIZE,
4190 + VMCS_SM_CMD_UNMAP,
4191 + VMCS_SM_CMD_FREE,
4192 + VMCS_SM_CMD_FLUSH,
4193 + VMCS_SM_CMD_INVALID,
4194 +
4195 + VMCS_SM_CMD_SIZE_USR_HANDLE,
4196 + VMCS_SM_CMD_CHK_USR_HANDLE,
4197 +
4198 + VMCS_SM_CMD_MAPPED_USR_HANDLE,
4199 + VMCS_SM_CMD_MAPPED_USR_ADDRESS,
4200 + VMCS_SM_CMD_MAPPED_VC_HDL_FROM_ADDR,
4201 + VMCS_SM_CMD_MAPPED_VC_HDL_FROM_HDL,
4202 + VMCS_SM_CMD_MAPPED_VC_ADDR_FROM_HDL,
4203 +
4204 + VMCS_SM_CMD_VC_WALK_ALLOC,
4205 + VMCS_SM_CMD_HOST_WALK_MAP,
4206 + VMCS_SM_CMD_HOST_WALK_PID_ALLOC,
4207 + VMCS_SM_CMD_HOST_WALK_PID_MAP,
4208 +
4209 + VMCS_SM_CMD_CLEAN_INVALID,
4210 +
4211 + VMCS_SM_CMD_LAST /* Do no delete */
4212 +};
4213 +
4214 +/* Cache type supported, conveniently matches the user space definition in
4215 +** user-vcsm.h.
4216 +*/
4217 +enum vmcs_sm_cache_e {
4218 + VMCS_SM_CACHE_NONE,
4219 + VMCS_SM_CACHE_HOST,
4220 + VMCS_SM_CACHE_VC,
4221 + VMCS_SM_CACHE_BOTH,
4222 +};
4223 +
4224 +/* IOCTL Data structures */
4225 +struct vmcs_sm_ioctl_alloc {
4226 + /* user -> kernel */
4227 + unsigned int size;
4228 + unsigned int num;
4229 + enum vmcs_sm_cache_e cached;
4230 + char name[VMCS_SM_RESOURCE_NAME];
4231 +
4232 + /* kernel -> user */
4233 + unsigned int handle;
4234 + /* unsigned int base_addr; */
4235 +};
4236 +
4237 +struct vmcs_sm_ioctl_alloc_share {
4238 + /* user -> kernel */
4239 + unsigned int handle;
4240 + unsigned int size;
4241 +};
4242 +
4243 +struct vmcs_sm_ioctl_free {
4244 + /* user -> kernel */
4245 + unsigned int handle;
4246 + /* unsigned int base_addr; */
4247 +};
4248 +
4249 +struct vmcs_sm_ioctl_lock_unlock {
4250 + /* user -> kernel */
4251 + unsigned int handle;
4252 +
4253 + /* kernel -> user */
4254 + unsigned int addr;
4255 +};
4256 +
4257 +struct vmcs_sm_ioctl_lock_cache {
4258 + /* user -> kernel */
4259 + unsigned int handle;
4260 + enum vmcs_sm_cache_e cached;
4261 +};
4262 +
4263 +struct vmcs_sm_ioctl_resize {
4264 + /* user -> kernel */
4265 + unsigned int handle;
4266 + unsigned int new_size;
4267 +
4268 + /* kernel -> user */
4269 + unsigned int old_size;
4270 +};
4271 +
4272 +struct vmcs_sm_ioctl_map {
4273 + /* user -> kernel */
4274 + /* and kernel -> user */
4275 + unsigned int pid;
4276 + unsigned int handle;
4277 + unsigned int addr;
4278 +
4279 + /* kernel -> user */
4280 + unsigned int size;
4281 +};
4282 +
4283 +struct vmcs_sm_ioctl_walk {
4284 + /* user -> kernel */
4285 + unsigned int pid;
4286 +};
4287 +
4288 +struct vmcs_sm_ioctl_chk {
4289 + /* user -> kernel */
4290 + unsigned int handle;
4291 +
4292 + /* kernel -> user */
4293 + unsigned int addr;
4294 + unsigned int size;
4295 + enum vmcs_sm_cache_e cache;
4296 +};
4297 +
4298 +struct vmcs_sm_ioctl_size {
4299 + /* user -> kernel */
4300 + unsigned int handle;
4301 +
4302 + /* kernel -> user */
4303 + unsigned int size;
4304 +};
4305 +
4306 +struct vmcs_sm_ioctl_cache {
4307 + /* user -> kernel */
4308 + unsigned int handle;
4309 + unsigned int addr;
4310 + unsigned int size;
4311 +};
4312 +
4313 +struct vmcs_sm_ioctl_clean_invalid {
4314 + /* user -> kernel */
4315 + struct {
4316 + unsigned int cmd;
4317 + unsigned int handle;
4318 + unsigned int addr;
4319 + unsigned int size;
4320 + } s[8];
4321 +};
4322 +
4323 +/* IOCTL numbers */
4324 +#define VMCS_SM_IOCTL_MEM_ALLOC\
4325 + _IOR(VMCS_SM_MAGIC_TYPE, VMCS_SM_CMD_ALLOC,\
4326 + struct vmcs_sm_ioctl_alloc)
4327 +#define VMCS_SM_IOCTL_MEM_ALLOC_SHARE\
4328 + _IOR(VMCS_SM_MAGIC_TYPE, VMCS_SM_CMD_ALLOC_SHARE,\
4329 + struct vmcs_sm_ioctl_alloc_share)
4330 +#define VMCS_SM_IOCTL_MEM_LOCK\
4331 + _IOR(VMCS_SM_MAGIC_TYPE, VMCS_SM_CMD_LOCK,\
4332 + struct vmcs_sm_ioctl_lock_unlock)
4333 +#define VMCS_SM_IOCTL_MEM_LOCK_CACHE\
4334 + _IOR(VMCS_SM_MAGIC_TYPE, VMCS_SM_CMD_LOCK_CACHE,\
4335 + struct vmcs_sm_ioctl_lock_cache)
4336 +#define VMCS_SM_IOCTL_MEM_UNLOCK\
4337 + _IOR(VMCS_SM_MAGIC_TYPE, VMCS_SM_CMD_UNLOCK,\
4338 + struct vmcs_sm_ioctl_lock_unlock)
4339 +#define VMCS_SM_IOCTL_MEM_RESIZE\
4340 + _IOR(VMCS_SM_MAGIC_TYPE, VMCS_SM_CMD_RESIZE,\
4341 + struct vmcs_sm_ioctl_resize)
4342 +#define VMCS_SM_IOCTL_MEM_FREE\
4343 + _IOR(VMCS_SM_MAGIC_TYPE, VMCS_SM_CMD_FREE,\
4344 + struct vmcs_sm_ioctl_free)
4345 +#define VMCS_SM_IOCTL_MEM_FLUSH\
4346 + _IOR(VMCS_SM_MAGIC_TYPE, VMCS_SM_CMD_FLUSH,\
4347 + struct vmcs_sm_ioctl_cache)
4348 +#define VMCS_SM_IOCTL_MEM_INVALID\
4349 + _IOR(VMCS_SM_MAGIC_TYPE, VMCS_SM_CMD_INVALID,\
4350 + struct vmcs_sm_ioctl_cache)
4351 +#define VMCS_SM_IOCTL_MEM_CLEAN_INVALID\
4352 + _IOR(VMCS_SM_MAGIC_TYPE, VMCS_SM_CMD_CLEAN_INVALID,\
4353 + struct vmcs_sm_ioctl_clean_invalid)
4354 +
4355 +#define VMCS_SM_IOCTL_SIZE_USR_HDL\
4356 + _IOR(VMCS_SM_MAGIC_TYPE, VMCS_SM_CMD_SIZE_USR_HANDLE,\
4357 + struct vmcs_sm_ioctl_size)
4358 +#define VMCS_SM_IOCTL_CHK_USR_HDL\
4359 + _IOR(VMCS_SM_MAGIC_TYPE, VMCS_SM_CMD_CHK_USR_HANDLE,\
4360 + struct vmcs_sm_ioctl_chk)
4361 +
4362 +#define VMCS_SM_IOCTL_MAP_USR_HDL\
4363 + _IOR(VMCS_SM_MAGIC_TYPE, VMCS_SM_CMD_MAPPED_USR_HANDLE,\
4364 + struct vmcs_sm_ioctl_map)
4365 +#define VMCS_SM_IOCTL_MAP_USR_ADDRESS\
4366 + _IOR(VMCS_SM_MAGIC_TYPE, VMCS_SM_CMD_MAPPED_USR_ADDRESS,\
4367 + struct vmcs_sm_ioctl_map)
4368 +#define VMCS_SM_IOCTL_MAP_VC_HDL_FR_ADDR\
4369 + _IOR(VMCS_SM_MAGIC_TYPE, VMCS_SM_CMD_MAPPED_VC_HDL_FROM_ADDR,\
4370 + struct vmcs_sm_ioctl_map)
4371 +#define VMCS_SM_IOCTL_MAP_VC_HDL_FR_HDL\
4372 + _IOR(VMCS_SM_MAGIC_TYPE, VMCS_SM_CMD_MAPPED_VC_HDL_FROM_HDL,\
4373 + struct vmcs_sm_ioctl_map)
4374 +#define VMCS_SM_IOCTL_MAP_VC_ADDR_FR_HDL\
4375 + _IOR(VMCS_SM_MAGIC_TYPE, VMCS_SM_CMD_MAPPED_VC_ADDR_FROM_HDL,\
4376 + struct vmcs_sm_ioctl_map)
4377 +
4378 +#define VMCS_SM_IOCTL_VC_WALK_ALLOC\
4379 + _IO(VMCS_SM_MAGIC_TYPE, VMCS_SM_CMD_VC_WALK_ALLOC)
4380 +#define VMCS_SM_IOCTL_HOST_WALK_MAP\
4381 + _IO(VMCS_SM_MAGIC_TYPE, VMCS_SM_CMD_HOST_WALK_MAP)
4382 +#define VMCS_SM_IOCTL_HOST_WALK_PID_ALLOC\
4383 + _IOR(VMCS_SM_MAGIC_TYPE, VMCS_SM_CMD_HOST_WALK_PID_ALLOC,\
4384 + struct vmcs_sm_ioctl_walk)
4385 +#define VMCS_SM_IOCTL_HOST_WALK_PID_MAP\
4386 + _IOR(VMCS_SM_MAGIC_TYPE, VMCS_SM_CMD_HOST_WALK_PID_MAP,\
4387 + struct vmcs_sm_ioctl_walk)
4388 +
4389 +/* ---- Variable Externs ------------------------------------------------- */
4390 +
4391 +/* ---- Function Prototypes ---------------------------------------------- */
4392 +
4393 +#endif /* __VMCS_SM_IOCTL_H__INCLUDED__ */