UPSTREAM: DT/arm,gic-v3: Documment PPI partition support
[firefly-linux-kernel-4.4.55.git] / drivers / gpu / arm / mali400 / umplock / umplock_driver.c
1 /*
2  * Copyright (C) 2012-2014 ARM Limited. All rights reserved.
3  * 
4  * This program is free software and is provided to you under the terms of the GNU General Public License version 2
5  * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
6  * 
7  * A copy of the licence is included with the program, and can also be obtained from Free Software
8  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
9  */
10
11 #include <linux/init.h>
12 #include <linux/module.h>
13 #include <linux/fs.h>
14 #include <linux/slab.h>
15 #include <linux/cdev.h>
16 #include <linux/device.h>
17 #include <asm/uaccess.h>
18 #include "umplock_ioctl.h"
19 #include <linux/sched.h>
20
21 #define MAX_ITEMS 1024
22 #define MAX_PIDS 128
23
24 typedef struct lock_cmd_priv {
25         uint32_t msg[128];    /*ioctl args*/
26         u32 pid;              /*process id*/
27 } _lock_cmd_priv;
28
29 typedef struct lock_ref {
30         int ref_count;
31         u32 pid;
32 } _lock_ref;
33
34 typedef struct umplock_item {
35         u32 secure_id;
36         u32 id_ref_count;
37         u32 owner;
38         _lock_access_usage usage;
39         _lock_ref references[MAX_PIDS];
40         struct semaphore item_lock;
41 } umplock_item;
42
43 typedef struct umplock_device_private {
44         struct mutex item_list_lock;
45         atomic_t sessions;
46         umplock_item items[MAX_ITEMS];
47         u32 pids[MAX_PIDS];
48 } umplock_device_private;
49
50 struct umplock_device {
51         struct cdev cdev;
52         struct class *umplock_class;
53 };
54
55 static struct umplock_device umplock_device;
56 static umplock_device_private device;
57 static dev_t umplock_dev;
58 static char umplock_dev_name[] = "umplock";
59
60 int umplock_debug_level = 0;
61 module_param(umplock_debug_level, int, S_IRUSR | S_IWUSR | S_IWGRP | S_IRGRP | S_IROTH); /* rw-rw-r-- */
62 MODULE_PARM_DESC(umplock_debug_level, "set umplock_debug_level to print debug messages");
63
64 #define PDEBUG(level, fmt, args...) do { if ((level) <= umplock_debug_level) printk(KERN_DEBUG "umplock: " fmt, ##args); } while (0)
65 #define PERROR(fmt, args...) do { printk(KERN_ERR "umplock: " fmt, ##args); } while (0)
66
67 int umplock_find_item(u32 secure_id)
68 {
69         int i;
70         for (i = 0; i < MAX_ITEMS; i++) {
71                 if (device.items[i].secure_id == secure_id) {
72                         return i;
73                 }
74         }
75
76         return -1;
77 }
78
79 static int umplock_find_item_by_pid(_lock_cmd_priv *lock_cmd, int *item_slot, int *ref_slot)
80 {
81         _lock_item_s *lock_item;
82         int i, j;
83
84         lock_item = (_lock_item_s *)&lock_cmd->msg;
85
86         i = umplock_find_item(lock_item->secure_id);
87
88         if (i < 0) {
89                 return -1;
90         }
91
92         for (j = 0; j < MAX_PIDS; j++) {
93                 if (device.items[i].references[j].pid == lock_cmd->pid) {
94                         *item_slot = i;
95                         *ref_slot = j;
96                         return 0;
97                 }
98         }
99         return -1 ;
100 }
101
102 static int umplock_find_client_valid(u32 pid)
103 {
104         int i;
105
106         if (pid == 0) {
107                 return -1;
108         }
109
110         for (i = 0; i < MAX_PIDS; i++) {
111                 if (device.pids[i] == pid) {
112                         return i;
113                 }
114         }
115
116         return -1;
117 }
118
119 static int do_umplock_create_locked(_lock_cmd_priv *lock_cmd)
120 {
121         int i_index, ref_index;
122         int ret;
123         _lock_item_s *lock_item = (_lock_item_s *)&lock_cmd->msg;
124
125         i_index = ref_index = -1;
126
127         ret = umplock_find_client_valid(lock_cmd->pid);
128         if (ret < 0) {
129                 /*lock request from an invalid client pid, do nothing*/
130                 return -EINVAL;
131         }
132
133         ret = umplock_find_item_by_pid(lock_cmd, &i_index, &ref_index);
134         if (ret >= 0) {
135         } else if ((i_index = umplock_find_item(lock_item->secure_id)) >= 0) {
136                 for (ref_index = 0; ref_index < MAX_PIDS; ref_index++) {
137                         if (device.items[i_index].references[ref_index].pid == 0) {
138                                 break;
139                         }
140                 }
141                 if (ref_index < MAX_PIDS) {
142                         device.items[i_index].references[ref_index].pid = lock_cmd->pid;
143                         device.items[i_index].references[ref_index].ref_count = 0;
144                 } else {
145                         PERROR("whoops, item ran out of available reference slots\n");
146                         return -EINVAL;
147
148                 }
149         } else {
150                 i_index = umplock_find_item(0);
151
152                 if (i_index >= 0) {
153                         device.items[i_index].secure_id = lock_item->secure_id;
154                         device.items[i_index].id_ref_count = 0;
155                         device.items[i_index].usage = lock_item->usage;
156                         device.items[i_index].references[0].pid = lock_cmd->pid;
157                         device.items[i_index].references[0].ref_count = 0;
158                         sema_init(&device.items[i_index].item_lock, 1);
159                 } else {
160                         PERROR("whoops, ran out of available slots\n");
161                         return -EINVAL;
162                 }
163         }
164
165         return 0;
166 }
167 /** IOCTLs **/
168
169 static int do_umplock_create(_lock_cmd_priv *lock_cmd)
170 {
171         return 0;
172 }
173
174 static int do_umplock_process(_lock_cmd_priv *lock_cmd)
175 {
176         int ret, i_index, ref_index;
177         _lock_item_s *lock_item = (_lock_item_s *)&lock_cmd->msg;
178
179         mutex_lock(&device.item_list_lock);
180
181         if (0 == lock_item->secure_id) {
182                 PERROR("IOCTL_UMPLOCK_PROCESS called with secure_id is 0, pid: %d\n", lock_cmd->pid);
183                 mutex_unlock(&device.item_list_lock);
184                 return -EINVAL;
185         }
186
187         ret = do_umplock_create_locked(lock_cmd);
188         if (ret < 0) {
189                 mutex_unlock(&device.item_list_lock);
190                 return -EINVAL;
191         }
192
193         ret = umplock_find_item_by_pid(lock_cmd, &i_index, &ref_index);
194         if (ret < 0) {
195                 /*fail to find a item*/
196                 PERROR("IOCTL_UMPLOCK_PROCESS called with invalid parameter, pid: %d\n", lock_cmd->pid);
197                 mutex_unlock(&device.item_list_lock);
198                 return -EINVAL;
199         }
200         device.items[i_index].references[ref_index].ref_count++;
201         device.items[i_index].id_ref_count++;
202         PDEBUG(1, "try to lock, pid: %d, secure_id: 0x%x, ref_count: %d\n", lock_cmd->pid, lock_item->secure_id, device.items[i_index].references[ref_index].ref_count);
203
204         if (lock_cmd->pid == device.items[i_index].owner) {
205                 PDEBUG(1, "already own the lock, pid: %d, secure_id: 0x%x, ref_count: %d\n", lock_cmd->pid, lock_item->secure_id, device.items[i_index].references[ref_index].ref_count);
206                 mutex_unlock(&device.item_list_lock);
207                 return 0;
208         }
209
210         mutex_unlock(&device.item_list_lock);
211         if (down_interruptible(&device.items[i_index].item_lock)) {
212                 /*wait up without hold the umplock. restore previous state and return*/
213                 mutex_lock(&device.item_list_lock);
214                 device.items[i_index].references[ref_index].ref_count--;
215                 device.items[i_index].id_ref_count--;
216                 if (0 == device.items[i_index].references[ref_index].ref_count) {
217                         device.items[i_index].references[ref_index].pid = 0;
218                         if (0 == device.items[i_index].id_ref_count) {
219                                 PDEBUG(1, "release item, pid: %d, secure_id: 0x%x\n", lock_cmd->pid, lock_item->secure_id);
220                                 device.items[i_index].secure_id = 0;
221                         }
222                 }
223
224                 PERROR("failed lock, pid: %d, secure_id: 0x%x, ref_count: %d\n", lock_cmd->pid, lock_item->secure_id, device.items[i_index].references[ref_index].ref_count);
225
226                 mutex_unlock(&device.item_list_lock);
227                 return -ERESTARTSYS;
228         }
229
230         mutex_lock(&device.item_list_lock);
231         PDEBUG(1, "got lock, pid: %d, secure_id: 0x%x, ref_count: %d\n", lock_cmd->pid, lock_item->secure_id, device.items[i_index].references[ref_index].ref_count);
232         device.items[i_index].owner = lock_cmd->pid;
233         mutex_unlock(&device.item_list_lock);
234
235         return 0;
236 }
237
238 static int do_umplock_release(_lock_cmd_priv *lock_cmd)
239 {
240         int ret, i_index, ref_index;
241         _lock_item_s *lock_item = (_lock_item_s *)&lock_cmd->msg;
242
243         mutex_lock(&device.item_list_lock);
244
245         if (0 == lock_item->secure_id) {
246                 PERROR("IOCTL_UMPLOCK_RELEASE called with secure_id is 0, pid: %d\n", lock_cmd->pid);
247                 mutex_unlock(&device.item_list_lock);
248                 return -EINVAL;
249         }
250
251         ret = umplock_find_client_valid(lock_cmd->pid);
252         if (ret < 0) {
253                 /*lock request from an invalid client pid, do nothing*/
254                 mutex_unlock(&device.item_list_lock);
255                 return -EPERM;
256         }
257
258         i_index = ref_index = -1;
259
260         ret = umplock_find_item_by_pid(lock_cmd, &i_index, &ref_index);
261         if (ret < 0) {
262                 /*fail to find item*/
263                 PERROR("IOCTL_UMPLOCK_RELEASE called with invalid parameter pid: %d, secid: 0x%x\n", lock_cmd->pid, lock_item->secure_id);
264                 mutex_unlock(&device.item_list_lock);
265                 return -EINVAL;
266         }
267
268         /* if the lock is not owned by this process */
269         if (lock_cmd->pid != device.items[i_index].owner) {
270                 mutex_unlock(&device.item_list_lock);
271                 return -EPERM;
272         }
273
274         /* if the ref_count is 0, that means nothing to unlock, just return */
275         if (0 == device.items[i_index].references[ref_index].ref_count) {
276                 mutex_unlock(&device.item_list_lock);
277                 return 0;
278         }
279
280         device.items[i_index].references[ref_index].ref_count--;
281         device.items[i_index].id_ref_count--;
282         PDEBUG(1, "unlock, pid: %d, secure_id: 0x%x, ref_count: %d\n", lock_cmd->pid, lock_item->secure_id, device.items[i_index].references[ref_index].ref_count);
283
284         if (0 == device.items[i_index].references[ref_index].ref_count) {
285                 device.items[i_index].references[ref_index].pid = 0;
286                 if (0 == device.items[i_index].id_ref_count) {
287                         PDEBUG(1, "release item, pid: %d, secure_id: 0x%x\n", lock_cmd->pid, lock_item->secure_id);
288                         device.items[i_index].secure_id = 0;
289                 }
290                 device.items[i_index].owner = 0;
291                 up(&device.items[i_index].item_lock);
292         }
293         mutex_unlock(&device.item_list_lock);
294
295         return 0;
296 }
297
298 static int do_umplock_zap(void)
299 {
300         int i;
301
302         PDEBUG(1, "ZAP ALL ENTRIES!\n");
303
304         mutex_lock(&device.item_list_lock);
305
306         for (i = 0; i < MAX_ITEMS; i++) {
307                 device.items[i].secure_id = 0;
308                 memset(&device.items[i].references, 0, sizeof(_lock_ref) * MAX_PIDS);
309                 sema_init(&device.items[i].item_lock, 1);
310         }
311
312         for (i = 0; i < MAX_PIDS; i++) {
313                 device.pids[i] = 0;
314         }
315         mutex_unlock(&device.item_list_lock);
316
317         return 0;
318 }
319
320 static int do_umplock_dump(void)
321 {
322         int i, j;
323
324         mutex_lock(&device.item_list_lock);
325         PERROR("dump all the items begin\n");
326         for (i = 0; i < MAX_ITEMS; i++) {
327                 for (j = 0; j < MAX_PIDS; j++) {
328                         if (device.items[i].secure_id != 0 && device.items[i].references[j].pid != 0) {
329                                 PERROR("item[%d]->secure_id=0x%x, owner=%d\t reference[%d].ref_count=%d.pid=%d\n",
330                                        i,
331                                        device.items[i].secure_id,
332                                        device.items[i].owner,
333                                        j,
334                                        device.items[i].references[j].ref_count,
335                                        device.items[i].references[j].pid);
336                         }
337                 }
338         }
339         PERROR("dump all the items end\n");
340         mutex_unlock(&device.item_list_lock);
341
342         return 0;
343 }
344
345 int do_umplock_client_add(_lock_cmd_priv *lock_cmd)
346 {
347         int i;
348         mutex_lock(&device.item_list_lock);
349         for (i = 0; i < MAX_PIDS; i++) {
350                 if (device.pids[i] == lock_cmd->pid) {
351                         mutex_unlock(&device.item_list_lock);
352                         return 0;
353                 }
354         }
355         for (i = 0; i < MAX_PIDS; i++) {
356                 if (device.pids[i] == 0) {
357                         device.pids[i] = lock_cmd->pid;
358                         break;
359                 }
360         }
361         mutex_unlock(&device.item_list_lock);
362         if (i == MAX_PIDS) {
363                 PERROR("Oops, Run out of client slots\n ");
364                 return -EINVAL;
365         }
366         return 0;
367 }
368
369 int do_umplock_client_delete(_lock_cmd_priv *lock_cmd)
370 {
371         int p_index = -1, i_index = -1, ref_index = -1;
372         int ret;
373         _lock_item_s *lock_item;
374         lock_item = (_lock_item_s *)&lock_cmd->msg;
375
376         mutex_lock(&device.item_list_lock);
377         p_index = umplock_find_client_valid(lock_cmd->pid);
378         /*lock item pid is not valid.*/
379         if (p_index < 0) {
380                 mutex_unlock(&device.item_list_lock);
381                 return 0;
382         }
383
384         /*walk through umplock item list and release reference attached to this client*/
385         for (i_index = 0; i_index < MAX_ITEMS; i_index++) {
386                 lock_item->secure_id = device.items[i_index].secure_id;
387
388                 /*find the item index and reference slot for the lock_item*/
389                 ret = umplock_find_item_by_pid(lock_cmd, &i_index, &ref_index);
390
391                 if (ret < 0) {
392                         /*client has no reference on this umplock item, skip*/
393                         continue;
394                 }
395                 while (device.items[i_index].references[ref_index].ref_count) {
396                         /*release references on this client*/
397
398                         PDEBUG(1, "delete client, pid: %d, ref_count: %d\n", lock_cmd->pid, device.items[i_index].references[ref_index].ref_count);
399
400                         mutex_unlock(&device.item_list_lock);
401                         do_umplock_release(lock_cmd);
402                         mutex_lock(&device.item_list_lock);
403                 }
404         }
405
406         /*remove the pid from umplock valid pid list*/
407         device.pids[p_index] = 0;
408         mutex_unlock(&device.item_list_lock);
409
410         return 0;
411 }
412
413 static long umplock_driver_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
414 {
415         int ret;
416         uint32_t size = _IOC_SIZE(cmd);
417         _lock_cmd_priv lock_cmd ;
418
419         if (_IOC_TYPE(cmd) != LOCK_IOCTL_GROUP) {
420                 return -ENOTTY;
421         }
422
423         if (_IOC_NR(cmd) >= LOCK_IOCTL_MAX_CMDS) {
424                 return -ENOTTY;
425         }
426
427         switch (cmd) {
428         case LOCK_IOCTL_CREATE:
429                 if (size != sizeof(_lock_item_s)) {
430                         return -ENOTTY;
431                 }
432
433                 if (copy_from_user(&lock_cmd.msg, (void __user *)arg, size)) {
434                         return -EFAULT;
435                 }
436                 lock_cmd.pid = (u32)current->tgid;
437                 ret = do_umplock_create(&lock_cmd);
438                 if (ret) {
439                         return ret;
440                 }
441                 return 0;
442
443         case LOCK_IOCTL_PROCESS:
444                 if (size != sizeof(_lock_item_s)) {
445                         return -ENOTTY;
446                 }
447
448                 if (copy_from_user(&lock_cmd.msg, (void __user *)arg, size)) {
449                         return -EFAULT;
450                 }
451                 lock_cmd.pid = (u32)current->tgid;
452                 return do_umplock_process(&lock_cmd);
453
454         case LOCK_IOCTL_RELEASE:
455                 if (size != sizeof(_lock_item_s)) {
456                         return -ENOTTY;
457                 }
458
459                 if (copy_from_user(&lock_cmd.msg, (void __user *)arg, size)) {
460                         return -EFAULT;
461                 }
462                 lock_cmd.pid = (u32)current->tgid;
463                 ret = do_umplock_release(&lock_cmd);
464                 if (ret) {
465                         return ret;
466                 }
467                 return 0;
468
469         case LOCK_IOCTL_ZAP:
470                 do_umplock_zap();
471                 return 0;
472
473         case LOCK_IOCTL_DUMP:
474                 do_umplock_dump();
475                 return 0;
476         }
477
478         return -ENOIOCTLCMD;
479 }
480
481 static int umplock_driver_open(struct inode *inode, struct file *filp)
482 {
483         _lock_cmd_priv lock_cmd;
484
485         atomic_inc(&device.sessions);
486         PDEBUG(1, "OPEN SESSION (%i references)\n", atomic_read(&device.sessions));
487
488         lock_cmd.pid = (u32)current->tgid;
489         do_umplock_client_add(&lock_cmd);
490
491         return 0;
492 }
493
494 static int umplock_driver_release(struct inode *inode, struct file *filp)
495 {
496         int sessions = 0;
497         _lock_cmd_priv lock_cmd;
498
499         lock_cmd.pid = (u32)current->tgid;
500         do_umplock_client_delete(&lock_cmd);
501
502         mutex_lock(&device.item_list_lock);
503         atomic_dec(&device.sessions);
504         sessions = atomic_read(&device.sessions);
505         PDEBUG(1, "CLOSE SESSION (%i references)\n", sessions);
506         mutex_unlock(&device.item_list_lock);
507         if (sessions == 0) {
508                 do_umplock_zap();
509         }
510
511         return 0;
512 }
513
514 static struct file_operations umplock_fops = {
515         .owner   = THIS_MODULE,
516         .open    = umplock_driver_open,
517         .release = umplock_driver_release,
518         .unlocked_ioctl = umplock_driver_ioctl,
519 };
520
521 int umplock_device_initialize(void)
522 {
523         int err;
524
525         err = alloc_chrdev_region(&umplock_dev, 0, 1, umplock_dev_name);
526
527         if (0 == err) {
528                 memset(&umplock_device, 0, sizeof(umplock_device));
529                 cdev_init(&umplock_device.cdev, &umplock_fops);
530                 umplock_device.cdev.owner = THIS_MODULE;
531                 umplock_device.cdev.ops = &umplock_fops;
532
533                 err = cdev_add(&umplock_device.cdev, umplock_dev, 1);
534                 if (0 == err) {
535                         umplock_device.umplock_class = class_create(THIS_MODULE, umplock_dev_name);
536                         if (IS_ERR(umplock_device.umplock_class)) {
537                                 err = PTR_ERR(umplock_device.umplock_class);
538                         } else {
539                                 struct device *mdev;
540                                 mdev = device_create(umplock_device.umplock_class, NULL, umplock_dev, NULL, umplock_dev_name);
541                                 if (!IS_ERR(mdev)) {
542                                         return 0; /* all ok */
543                                 }
544
545                                 err = PTR_ERR(mdev);
546                                 class_destroy(umplock_device.umplock_class);
547                         }
548                         cdev_del(&umplock_device.cdev);
549                 }
550
551                 unregister_chrdev_region(umplock_dev, 1);
552         } else {
553                 PERROR("alloc chardev region failed\n");
554         }
555
556         return err;
557 }
558
559 void umplock_device_terminate(void)
560 {
561         device_destroy(umplock_device.umplock_class, umplock_dev);
562         class_destroy(umplock_device.umplock_class);
563
564         cdev_del(&umplock_device.cdev);
565         unregister_chrdev_region(umplock_dev, 1);
566 }
567
568 static int __init umplock_initialize_module(void)
569 {
570         PDEBUG(1, "Inserting UMP lock device driver. Compiled: %s, time: %s\n", __DATE__, __TIME__);
571
572         mutex_init(&device.item_list_lock);
573         if (umplock_device_initialize() != 0) {
574                 PERROR("UMP lock device driver init failed\n");
575                 return -ENOTTY;
576         }
577         memset(&device.items, 0, sizeof(umplock_item) * MAX_ITEMS);
578         memset(&device.pids, 0, sizeof(u32) * MAX_PIDS);
579         atomic_set(&device.sessions, 0);
580
581         PDEBUG(1, "UMP lock device driver loaded\n");
582
583         return 0;
584 }
585
586 static void __exit umplock_cleanup_module(void)
587 {
588         PDEBUG(1, "unloading UMP lock module\n");
589
590         memset(&device.items, 0, sizeof(umplock_item) * MAX_ITEMS);
591         memset(&device.pids, 0, sizeof(u32) * MAX_PIDS);
592         umplock_device_terminate();
593         mutex_destroy(&device.item_list_lock);
594
595         PDEBUG(1, "UMP lock module unloaded\n");
596 }
597
598 module_init(umplock_initialize_module);
599 module_exit(umplock_cleanup_module);
600
601
602 MODULE_LICENSE("GPL");
603 MODULE_AUTHOR("ARM Ltd.");
604 MODULE_DESCRIPTION("ARM UMP locker");