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