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