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