]> bbs.cooldavid.org Git - net-next-2.6.git/blob - drivers/staging/dream/qdsp5/adsp_driver.c
Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jwessel...
[net-next-2.6.git] / drivers / staging / dream / qdsp5 / adsp_driver.c
1 /* arch/arm/mach-msm/qdsp5/adsp_driver.c
2  *
3  * Copyright (C) 2008 Google, Inc.
4  * Author: Iliyan Malchev <ibm@android.com>
5  *
6  * This software is licensed under the terms of the GNU General Public
7  * License version 2, as published by the Free Software Foundation, and
8  * may be copied, distributed, and modified under those terms.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  */
16
17 #include <linux/cdev.h>
18 #include <linux/fs.h>
19 #include <linux/list.h>
20 #include <linux/platform_device.h>
21 #include <linux/sched.h>
22 #include <linux/slab.h>
23 #include <linux/uaccess.h>
24
25 #include "adsp.h"
26
27 #include <linux/msm_adsp.h>
28 #include <linux/android_pmem.h>
29
30 struct adsp_pmem_region {
31         struct hlist_node list;
32         void *vaddr;
33         unsigned long paddr;
34         unsigned long kvaddr;
35         unsigned long len;
36         struct file *file;
37 };
38
39 struct adsp_device {
40         struct msm_adsp_module *module;
41
42         spinlock_t event_queue_lock;
43         wait_queue_head_t event_wait;
44         struct list_head event_queue;
45         int abort;
46
47         const char *name;
48         struct device *device;
49         struct cdev cdev;
50 };
51
52 static struct adsp_device *inode_to_device(struct inode *inode);
53
54 #define __CONTAINS(r, v, l) ({                                  \
55         typeof(r) __r = r;                                      \
56         typeof(v) __v = v;                                      \
57         typeof(v) __e = __v + l;                                \
58         int res = __v >= __r->vaddr &&                          \
59                 __e <= __r->vaddr + __r->len;                   \
60         res;                                                    \
61 })
62
63 #define CONTAINS(r1, r2) ({                                     \
64         typeof(r2) __r2 = r2;                                   \
65         __CONTAINS(r1, __r2->vaddr, __r2->len);                 \
66 })
67
68 #define IN_RANGE(r, v) ({                                       \
69         typeof(r) __r = r;                                      \
70         typeof(v) __vv = v;                                     \
71         int res = ((__vv >= __r->vaddr) &&                      \
72                 (__vv < (__r->vaddr + __r->len)));              \
73         res;                                                    \
74 })
75
76 #define OVERLAPS(r1, r2) ({                                     \
77         typeof(r1) __r1 = r1;                                   \
78         typeof(r2) __r2 = r2;                                   \
79         typeof(__r2->vaddr) __v = __r2->vaddr;                  \
80         typeof(__v) __e = __v + __r2->len - 1;                  \
81         int res = (IN_RANGE(__r1, __v) || IN_RANGE(__r1, __e)); \
82         res;                                                    \
83 })
84
85 static int adsp_pmem_check(struct msm_adsp_module *module,
86                 void *vaddr, unsigned long len)
87 {
88         struct adsp_pmem_region *region_elt;
89         struct hlist_node *node;
90         struct adsp_pmem_region t = { .vaddr = vaddr, .len = len };
91
92         hlist_for_each_entry(region_elt, node, &module->pmem_regions, list) {
93                 if (CONTAINS(region_elt, &t) || CONTAINS(&t, region_elt) ||
94                     OVERLAPS(region_elt, &t)) {
95                         printk(KERN_ERR "adsp: module %s:"
96                                 " region (vaddr %p len %ld)"
97                                 " clashes with registered region"
98                                 " (vaddr %p paddr %p len %ld)\n",
99                                 module->name,
100                                 vaddr, len,
101                                 region_elt->vaddr,
102                                 (void *)region_elt->paddr,
103                                 region_elt->len);
104                         return -EINVAL;
105                 }
106         }
107
108         return 0;
109 }
110
111 static int adsp_pmem_add(struct msm_adsp_module *module,
112                          struct adsp_pmem_info *info)
113 {
114         unsigned long paddr, kvaddr, len;
115         struct file *file;
116         struct adsp_pmem_region *region;
117         int rc = -EINVAL;
118
119         mutex_lock(&module->pmem_regions_lock);
120         region = kmalloc(sizeof(*region), GFP_KERNEL);
121         if (!region) {
122                 rc = -ENOMEM;
123                 goto end;
124         }
125         INIT_HLIST_NODE(&region->list);
126         if (get_pmem_file(info->fd, &paddr, &kvaddr, &len, &file)) {
127                 kfree(region);
128                 goto end;
129         }
130
131         rc = adsp_pmem_check(module, info->vaddr, len);
132         if (rc < 0) {
133                 put_pmem_file(file);
134                 kfree(region);
135                 goto end;
136         }
137
138         region->vaddr = info->vaddr;
139         region->paddr = paddr;
140         region->kvaddr = kvaddr;
141         region->len = len;
142         region->file = file;
143
144         hlist_add_head(&region->list, &module->pmem_regions);
145 end:
146         mutex_unlock(&module->pmem_regions_lock);
147         return rc;
148 }
149
150 static int adsp_pmem_lookup_vaddr(struct msm_adsp_module *module, void **addr,
151                      unsigned long len, struct adsp_pmem_region **region)
152 {
153         struct hlist_node *node;
154         void *vaddr = *addr;
155         struct adsp_pmem_region *region_elt;
156
157         int match_count = 0;
158
159         *region = NULL;
160
161         /* returns physical address or zero */
162         hlist_for_each_entry(region_elt, node, &module->pmem_regions, list) {
163                 if (vaddr >= region_elt->vaddr &&
164                     vaddr < region_elt->vaddr + region_elt->len &&
165                     vaddr + len <= region_elt->vaddr + region_elt->len) {
166                         /* offset since we could pass vaddr inside a registerd
167                          * pmem buffer
168                          */
169
170                         match_count++;
171                         if (!*region)
172                                 *region = region_elt;
173                 }
174         }
175
176         if (match_count > 1) {
177                 printk(KERN_ERR "adsp: module %s: "
178                         "multiple hits for vaddr %p, len %ld\n",
179                         module->name, vaddr, len);
180                 hlist_for_each_entry(region_elt, node,
181                                 &module->pmem_regions, list) {
182                         if (vaddr >= region_elt->vaddr &&
183                             vaddr < region_elt->vaddr + region_elt->len &&
184                             vaddr + len <= region_elt->vaddr + region_elt->len)
185                                 printk(KERN_ERR "\t%p, %ld --> %p\n",
186                                         region_elt->vaddr,
187                                         region_elt->len,
188                                         (void *)region_elt->paddr);
189                 }
190         }
191
192         return *region ? 0 : -1;
193 }
194
195 int adsp_pmem_fixup_kvaddr(struct msm_adsp_module *module, void **addr,
196                            unsigned long *kvaddr, unsigned long len)
197 {
198         struct adsp_pmem_region *region;
199         void *vaddr = *addr;
200         unsigned long *paddr = (unsigned long *)addr;
201         int ret;
202
203         ret = adsp_pmem_lookup_vaddr(module, addr, len, &region);
204         if (ret) {
205                 printk(KERN_ERR "adsp: not patching %s (paddr & kvaddr),"
206                         " lookup (%p, %ld) failed\n",
207                         module->name, vaddr, len);
208                 return ret;
209         }
210         *paddr = region->paddr + (vaddr - region->vaddr);
211         *kvaddr = region->kvaddr + (vaddr - region->vaddr);
212         return 0;
213 }
214
215 int adsp_pmem_fixup(struct msm_adsp_module *module, void **addr,
216                     unsigned long len)
217 {
218         struct adsp_pmem_region *region;
219         void *vaddr = *addr;
220         unsigned long *paddr = (unsigned long *)addr;
221         int ret;
222
223         ret = adsp_pmem_lookup_vaddr(module, addr, len, &region);
224         if (ret) {
225                 printk(KERN_ERR "adsp: not patching %s, lookup (%p, %ld) failed\n",
226                         module->name, vaddr, len);
227                 return ret;
228         }
229
230         *paddr = region->paddr + (vaddr - region->vaddr);
231         return 0;
232 }
233
234 static int adsp_verify_cmd(struct msm_adsp_module *module,
235                            unsigned int queue_id, void *cmd_data,
236                            size_t cmd_size)
237 {
238         /* call the per module verifier */
239         if (module->verify_cmd)
240                 return module->verify_cmd(module, queue_id, cmd_data,
241                                              cmd_size);
242         else
243                 printk(KERN_INFO "adsp: no packet verifying function "
244                                  "for task %s\n", module->name);
245         return 0;
246 }
247
248 static long adsp_write_cmd(struct adsp_device *adev, void __user *arg)
249 {
250         struct adsp_command_t cmd;
251         unsigned char buf[256];
252         void *cmd_data;
253         long rc;
254
255         if (copy_from_user(&cmd, (void __user *)arg, sizeof(cmd)))
256                 return -EFAULT;
257
258         if (cmd.len > 256) {
259                 cmd_data = kmalloc(cmd.len, GFP_USER);
260                 if (!cmd_data)
261                         return -ENOMEM;
262         } else {
263                 cmd_data = buf;
264         }
265
266         if (copy_from_user(cmd_data, (void __user *)(cmd.data), cmd.len)) {
267                 rc = -EFAULT;
268                 goto end;
269         }
270
271         mutex_lock(&adev->module->pmem_regions_lock);
272         if (adsp_verify_cmd(adev->module, cmd.queue, cmd_data, cmd.len)) {
273                 printk(KERN_ERR "module %s: verify failed.\n",
274                         adev->module->name);
275                 rc = -EINVAL;
276                 goto end;
277         }
278         rc = msm_adsp_write(adev->module, cmd.queue, cmd_data, cmd.len);
279 end:
280         mutex_unlock(&adev->module->pmem_regions_lock);
281
282         if (cmd.len > 256)
283                 kfree(cmd_data);
284
285         return rc;
286 }
287
288 static int adsp_events_pending(struct adsp_device *adev)
289 {
290         unsigned long flags;
291         int yes;
292         spin_lock_irqsave(&adev->event_queue_lock, flags);
293         yes = !list_empty(&adev->event_queue);
294         spin_unlock_irqrestore(&adev->event_queue_lock, flags);
295         return yes || adev->abort;
296 }
297
298 static int adsp_pmem_lookup_paddr(struct msm_adsp_module *module, void **addr,
299                      struct adsp_pmem_region **region)
300 {
301         struct hlist_node *node;
302         unsigned long paddr = (unsigned long)(*addr);
303         struct adsp_pmem_region *region_elt;
304
305         hlist_for_each_entry(region_elt, node, &module->pmem_regions, list) {
306                 if (paddr >= region_elt->paddr &&
307                     paddr < region_elt->paddr + region_elt->len) {
308                         *region = region_elt;
309                         return 0;
310                 }
311         }
312         return -1;
313 }
314
315 int adsp_pmem_paddr_fixup(struct msm_adsp_module *module, void **addr)
316 {
317         struct adsp_pmem_region *region;
318         unsigned long paddr = (unsigned long)(*addr);
319         unsigned long *vaddr = (unsigned long *)addr;
320         int ret;
321
322         ret = adsp_pmem_lookup_paddr(module, addr, &region);
323         if (ret) {
324                 printk(KERN_ERR "adsp: not patching %s, paddr %p lookup failed\n",
325                         module->name, vaddr);
326                 return ret;
327         }
328
329         *vaddr = (unsigned long)region->vaddr + (paddr - region->paddr);
330         return 0;
331 }
332
333 static int adsp_patch_event(struct msm_adsp_module *module,
334                                 struct adsp_event *event)
335 {
336         /* call the per-module msg verifier */
337         if (module->patch_event)
338                 return module->patch_event(module, event);
339         return 0;
340 }
341
342 static long adsp_get_event(struct adsp_device *adev, void __user *arg)
343 {
344         unsigned long flags;
345         struct adsp_event *data = NULL;
346         struct adsp_event_t evt;
347         int timeout;
348         long rc = 0;
349
350         if (copy_from_user(&evt, arg, sizeof(struct adsp_event_t)))
351                 return -EFAULT;
352
353         timeout = (int)evt.timeout_ms;
354
355         if (timeout > 0) {
356                 rc = wait_event_interruptible_timeout(
357                         adev->event_wait, adsp_events_pending(adev),
358                         msecs_to_jiffies(timeout));
359                 if (rc == 0)
360                         return -ETIMEDOUT;
361         } else {
362                 rc = wait_event_interruptible(
363                         adev->event_wait, adsp_events_pending(adev));
364         }
365         if (rc < 0)
366                 return rc;
367
368         if (adev->abort)
369                 return -ENODEV;
370
371         spin_lock_irqsave(&adev->event_queue_lock, flags);
372         if (!list_empty(&adev->event_queue)) {
373                 data = list_first_entry(&adev->event_queue,
374                                         struct adsp_event, list);
375                 list_del(&data->list);
376         }
377         spin_unlock_irqrestore(&adev->event_queue_lock, flags);
378
379         if (!data)
380                 return -EAGAIN;
381
382         /* DSP messages are type 0; they may contain physical addresses */
383         if (data->type == 0)
384                 adsp_patch_event(adev->module, data);
385
386         /* map adsp_event --> adsp_event_t */
387         if (evt.len < data->size) {
388                 rc = -ETOOSMALL;
389                 goto end;
390         }
391         if (data->msg_id != EVENT_MSG_ID) {
392                 if (copy_to_user((void *)(evt.data), data->data.msg16,
393                                         data->size)) {
394                         rc = -EFAULT;
395                         goto end;
396         }
397         } else {
398                 if (copy_to_user((void *)(evt.data), data->data.msg32,
399                                         data->size)) {
400                         rc = -EFAULT;
401                         goto end;
402                 }
403         }
404
405         evt.type = data->type; /* 0 --> from aDSP, 1 --> from ARM9 */
406         evt.msg_id = data->msg_id;
407         evt.flags = data->is16;
408         evt.len = data->size;
409         if (copy_to_user(arg, &evt, sizeof(evt)))
410                 rc = -EFAULT;
411 end:
412         kfree(data);
413         return rc;
414 }
415
416 static long adsp_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
417 {
418         struct adsp_device *adev = filp->private_data;
419
420         switch (cmd) {
421         case ADSP_IOCTL_ENABLE:
422                 return msm_adsp_enable(adev->module);
423
424         case ADSP_IOCTL_DISABLE:
425                 return msm_adsp_disable(adev->module);
426
427         case ADSP_IOCTL_DISABLE_EVENT_RSP:
428                 return 0;
429
430         case ADSP_IOCTL_DISABLE_ACK:
431                 pr_err("adsp: ADSP_IOCTL_DISABLE_ACK is not implemented.\n");
432                 break;
433
434         case ADSP_IOCTL_WRITE_COMMAND:
435                 return adsp_write_cmd(adev, (void __user *) arg);
436
437         case ADSP_IOCTL_GET_EVENT:
438                 return adsp_get_event(adev, (void __user *) arg);
439
440         case ADSP_IOCTL_SET_CLKRATE: {
441 #if CONFIG_MSM_AMSS_VERSION==6350
442                 unsigned long clk_rate;
443                 if (copy_from_user(&clk_rate, (void *) arg, sizeof(clk_rate)))
444                         return -EFAULT;
445                 return adsp_set_clkrate(adev->module, clk_rate);
446 #endif
447         }
448
449         case ADSP_IOCTL_REGISTER_PMEM: {
450                 struct adsp_pmem_info info;
451                 if (copy_from_user(&info, (void *) arg, sizeof(info)))
452                         return -EFAULT;
453                 return adsp_pmem_add(adev->module, &info);
454         }
455
456         case ADSP_IOCTL_ABORT_EVENT_READ:
457                 adev->abort = 1;
458                 wake_up(&adev->event_wait);
459                 break;
460
461         default:
462                 break;
463         }
464         return -EINVAL;
465 }
466
467 static int adsp_release(struct inode *inode, struct file *filp)
468 {
469         struct adsp_device *adev = filp->private_data;
470         struct msm_adsp_module *module = adev->module;
471         struct hlist_node *node, *tmp;
472         struct adsp_pmem_region *region;
473
474         pr_info("adsp_release() '%s'\n", adev->name);
475
476         /* clear module before putting it to avoid race with open() */
477         adev->module = NULL;
478
479         mutex_lock(&module->pmem_regions_lock);
480         hlist_for_each_safe(node, tmp, &module->pmem_regions) {
481                 region = hlist_entry(node, struct adsp_pmem_region, list);
482                 hlist_del(node);
483                 put_pmem_file(region->file);
484                 kfree(region);
485         }
486         mutex_unlock(&module->pmem_regions_lock);
487         BUG_ON(!hlist_empty(&module->pmem_regions));
488
489         msm_adsp_put(module);
490         return 0;
491 }
492
493 static void adsp_event(void *driver_data, unsigned id, size_t len,
494                        void (*getevent)(void *ptr, size_t len))
495 {
496         struct adsp_device *adev = driver_data;
497         struct adsp_event *event;
498         unsigned long flags;
499
500         if (len > ADSP_EVENT_MAX_SIZE) {
501                 pr_err("adsp_event: event too large (%d bytes)\n", len);
502                 return;
503         }
504
505         event = kmalloc(sizeof(*event), GFP_ATOMIC);
506         if (!event) {
507                 pr_err("adsp_event: cannot allocate buffer\n");
508                 return;
509         }
510
511         if (id != EVENT_MSG_ID) {
512                 event->type = 0;
513                 event->is16 = 0;
514                 event->msg_id = id;
515                 event->size = len;
516
517                 getevent(event->data.msg16, len);
518         } else {
519                 event->type = 1;
520                 event->is16 = 1;
521                 event->msg_id = id;
522                 event->size = len;
523                 getevent(event->data.msg32, len);
524         }
525
526         spin_lock_irqsave(&adev->event_queue_lock, flags);
527         list_add_tail(&event->list, &adev->event_queue);
528         spin_unlock_irqrestore(&adev->event_queue_lock, flags);
529         wake_up(&adev->event_wait);
530 }
531
532 static struct msm_adsp_ops adsp_ops = {
533         .event = adsp_event,
534 };
535
536 static int adsp_open(struct inode *inode, struct file *filp)
537 {
538         struct adsp_device *adev;
539         int rc;
540
541         rc = nonseekable_open(inode, filp);
542         if (rc < 0)
543                 return rc;
544
545         adev = inode_to_device(inode);
546         if (!adev)
547                 return -ENODEV;
548
549         pr_info("adsp_open() name = '%s'\n", adev->name);
550
551         rc = msm_adsp_get(adev->name, &adev->module, &adsp_ops, adev);
552         if (rc)
553                 return rc;
554
555         pr_info("adsp_open() module '%s' adev %p\n", adev->name, adev);
556         filp->private_data = adev;
557         adev->abort = 0;
558         INIT_HLIST_HEAD(&adev->module->pmem_regions);
559         mutex_init(&adev->module->pmem_regions_lock);
560
561         return 0;
562 }
563
564 static unsigned adsp_device_count;
565 static struct adsp_device *adsp_devices;
566
567 static struct adsp_device *inode_to_device(struct inode *inode)
568 {
569         unsigned n = MINOR(inode->i_rdev);
570         if (n < adsp_device_count) {
571                 if (adsp_devices[n].device)
572                         return adsp_devices + n;
573         }
574         return NULL;
575 }
576
577 static dev_t adsp_devno;
578 static struct class *adsp_class;
579
580 static struct file_operations adsp_fops = {
581         .owner = THIS_MODULE,
582         .open = adsp_open,
583         .unlocked_ioctl = adsp_ioctl,
584         .release = adsp_release,
585         .llseek = no_llseek,
586 };
587
588 static void adsp_create(struct adsp_device *adev, const char *name,
589                         struct device *parent, dev_t devt)
590 {
591         struct device *dev;
592         int rc;
593
594         dev = device_create(adsp_class, parent, devt, "%s", name);
595         if (IS_ERR(dev))
596                 return;
597
598         init_waitqueue_head(&adev->event_wait);
599         INIT_LIST_HEAD(&adev->event_queue);
600         spin_lock_init(&adev->event_queue_lock);
601
602         cdev_init(&adev->cdev, &adsp_fops);
603         adev->cdev.owner = THIS_MODULE;
604
605         rc = cdev_add(&adev->cdev, devt, 1);
606         if (rc < 0) {
607                 device_destroy(adsp_class, devt);
608         } else {
609                 adev->device = dev;
610                 adev->name = name;
611         }
612 }
613
614 void msm_adsp_publish_cdevs(struct msm_adsp_module *modules, unsigned n)
615 {
616         int rc;
617
618         adsp_devices = kzalloc(sizeof(struct adsp_device) * n, GFP_KERNEL);
619         if (!adsp_devices)
620                 return;
621
622         adsp_class = class_create(THIS_MODULE, "adsp");
623         if (IS_ERR(adsp_class))
624                 goto fail_create_class;
625
626         rc = alloc_chrdev_region(&adsp_devno, 0, n, "adsp");
627         if (rc < 0)
628                 goto fail_alloc_region;
629
630         adsp_device_count = n;
631         for (n = 0; n < adsp_device_count; n++) {
632                 adsp_create(adsp_devices + n,
633                             modules[n].name, &modules[n].pdev.dev,
634                             MKDEV(MAJOR(adsp_devno), n));
635         }
636
637         return;
638
639 fail_alloc_region:
640         class_unregister(adsp_class);
641 fail_create_class:
642         kfree(adsp_devices);
643 }