1 /* arch/arm/mach-msm/qdsp5/adsp_driver.c
3 * Copyright (C) 2008 Google, Inc.
4 * Author: Iliyan Malchev <ibm@android.com>
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.
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.
17 #include <linux/cdev.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>
27 #include <linux/msm_adsp.h>
28 #include <linux/android_pmem.h>
30 struct adsp_pmem_region
{
31 struct hlist_node list
;
40 struct msm_adsp_module
*module
;
42 spinlock_t event_queue_lock
;
43 wait_queue_head_t event_wait
;
44 struct list_head event_queue
;
48 struct device
*device
;
52 static struct adsp_device
*inode_to_device(struct inode
*inode
);
54 #define __CONTAINS(r, v, l) ({ \
57 typeof(v) __e = __v + l; \
58 int res = __v >= __r->vaddr && \
59 __e <= __r->vaddr + __r->len; \
63 #define CONTAINS(r1, r2) ({ \
64 typeof(r2) __r2 = r2; \
65 __CONTAINS(r1, __r2->vaddr, __r2->len); \
68 #define IN_RANGE(r, v) ({ \
71 int res = ((__vv >= __r->vaddr) && \
72 (__vv < (__r->vaddr + __r->len))); \
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)); \
85 static int adsp_pmem_check(struct msm_adsp_module
*module
,
86 void *vaddr
, unsigned long len
)
88 struct adsp_pmem_region
*region_elt
;
89 struct hlist_node
*node
;
90 struct adsp_pmem_region t
= { .vaddr
= vaddr
, .len
= len
};
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",
102 (void *)region_elt
->paddr
,
111 static int adsp_pmem_add(struct msm_adsp_module
*module
,
112 struct adsp_pmem_info
*info
)
114 unsigned long paddr
, kvaddr
, len
;
116 struct adsp_pmem_region
*region
;
119 mutex_lock(&module
->pmem_regions_lock
);
120 region
= kmalloc(sizeof(*region
), GFP_KERNEL
);
125 INIT_HLIST_NODE(®ion
->list
);
126 if (get_pmem_file(info
->fd
, &paddr
, &kvaddr
, &len
, &file
)) {
131 rc
= adsp_pmem_check(module
, info
->vaddr
, len
);
138 region
->vaddr
= info
->vaddr
;
139 region
->paddr
= paddr
;
140 region
->kvaddr
= kvaddr
;
144 hlist_add_head(®ion
->list
, &module
->pmem_regions
);
146 mutex_unlock(&module
->pmem_regions_lock
);
150 static int adsp_pmem_lookup_vaddr(struct msm_adsp_module
*module
, void **addr
,
151 unsigned long len
, struct adsp_pmem_region
**region
)
153 struct hlist_node
*node
;
155 struct adsp_pmem_region
*region_elt
;
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
172 *region
= region_elt
;
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",
188 (void *)region_elt
->paddr
);
192 return *region
? 0 : -1;
195 int adsp_pmem_fixup_kvaddr(struct msm_adsp_module
*module
, void **addr
,
196 unsigned long *kvaddr
, unsigned long len
)
198 struct adsp_pmem_region
*region
;
200 unsigned long *paddr
= (unsigned long *)addr
;
203 ret
= adsp_pmem_lookup_vaddr(module
, addr
, len
, ®ion
);
205 printk(KERN_ERR
"adsp: not patching %s (paddr & kvaddr),"
206 " lookup (%p, %ld) failed\n",
207 module
->name
, vaddr
, len
);
210 *paddr
= region
->paddr
+ (vaddr
- region
->vaddr
);
211 *kvaddr
= region
->kvaddr
+ (vaddr
- region
->vaddr
);
215 int adsp_pmem_fixup(struct msm_adsp_module
*module
, void **addr
,
218 struct adsp_pmem_region
*region
;
220 unsigned long *paddr
= (unsigned long *)addr
;
223 ret
= adsp_pmem_lookup_vaddr(module
, addr
, len
, ®ion
);
225 printk(KERN_ERR
"adsp: not patching %s, lookup (%p, %ld) failed\n",
226 module
->name
, vaddr
, len
);
230 *paddr
= region
->paddr
+ (vaddr
- region
->vaddr
);
234 static int adsp_verify_cmd(struct msm_adsp_module
*module
,
235 unsigned int queue_id
, void *cmd_data
,
238 /* call the per module verifier */
239 if (module
->verify_cmd
)
240 return module
->verify_cmd(module
, queue_id
, cmd_data
,
243 printk(KERN_INFO
"adsp: no packet verifying function "
244 "for task %s\n", module
->name
);
248 static long adsp_write_cmd(struct adsp_device
*adev
, void __user
*arg
)
250 struct adsp_command_t cmd
;
251 unsigned char buf
[256];
255 if (copy_from_user(&cmd
, (void __user
*)arg
, sizeof(cmd
)))
259 cmd_data
= kmalloc(cmd
.len
, GFP_USER
);
266 if (copy_from_user(cmd_data
, (void __user
*)(cmd
.data
), cmd
.len
)) {
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",
278 rc
= msm_adsp_write(adev
->module
, cmd
.queue
, cmd_data
, cmd
.len
);
280 mutex_unlock(&adev
->module
->pmem_regions_lock
);
288 static int adsp_events_pending(struct adsp_device
*adev
)
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
;
298 static int adsp_pmem_lookup_paddr(struct msm_adsp_module
*module
, void **addr
,
299 struct adsp_pmem_region
**region
)
301 struct hlist_node
*node
;
302 unsigned long paddr
= (unsigned long)(*addr
);
303 struct adsp_pmem_region
*region_elt
;
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
;
315 int adsp_pmem_paddr_fixup(struct msm_adsp_module
*module
, void **addr
)
317 struct adsp_pmem_region
*region
;
318 unsigned long paddr
= (unsigned long)(*addr
);
319 unsigned long *vaddr
= (unsigned long *)addr
;
322 ret
= adsp_pmem_lookup_paddr(module
, addr
, ®ion
);
324 printk(KERN_ERR
"adsp: not patching %s, paddr %p lookup failed\n",
325 module
->name
, vaddr
);
329 *vaddr
= (unsigned long)region
->vaddr
+ (paddr
- region
->paddr
);
333 static int adsp_patch_event(struct msm_adsp_module
*module
,
334 struct adsp_event
*event
)
336 /* call the per-module msg verifier */
337 if (module
->patch_event
)
338 return module
->patch_event(module
, event
);
342 static long adsp_get_event(struct adsp_device
*adev
, void __user
*arg
)
345 struct adsp_event
*data
= NULL
;
346 struct adsp_event_t evt
;
350 if (copy_from_user(&evt
, arg
, sizeof(struct adsp_event_t
)))
353 timeout
= (int)evt
.timeout_ms
;
356 rc
= wait_event_interruptible_timeout(
357 adev
->event_wait
, adsp_events_pending(adev
),
358 msecs_to_jiffies(timeout
));
362 rc
= wait_event_interruptible(
363 adev
->event_wait
, adsp_events_pending(adev
));
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
);
377 spin_unlock_irqrestore(&adev
->event_queue_lock
, flags
);
382 /* DSP messages are type 0; they may contain physical addresses */
384 adsp_patch_event(adev
->module
, data
);
386 /* map adsp_event --> adsp_event_t */
387 if (evt
.len
< data
->size
) {
391 if (data
->msg_id
!= EVENT_MSG_ID
) {
392 if (copy_to_user((void *)(evt
.data
), data
->data
.msg16
,
398 if (copy_to_user((void *)(evt
.data
), data
->data
.msg32
,
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
)))
416 static long adsp_ioctl(struct file
*filp
, unsigned int cmd
, unsigned long arg
)
418 struct adsp_device
*adev
= filp
->private_data
;
421 case ADSP_IOCTL_ENABLE
:
422 return msm_adsp_enable(adev
->module
);
424 case ADSP_IOCTL_DISABLE
:
425 return msm_adsp_disable(adev
->module
);
427 case ADSP_IOCTL_DISABLE_EVENT_RSP
:
430 case ADSP_IOCTL_DISABLE_ACK
:
431 pr_err("adsp: ADSP_IOCTL_DISABLE_ACK is not implemented.\n");
434 case ADSP_IOCTL_WRITE_COMMAND
:
435 return adsp_write_cmd(adev
, (void __user
*) arg
);
437 case ADSP_IOCTL_GET_EVENT
:
438 return adsp_get_event(adev
, (void __user
*) arg
);
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
)))
445 return adsp_set_clkrate(adev
->module
, clk_rate
);
449 case ADSP_IOCTL_REGISTER_PMEM
: {
450 struct adsp_pmem_info info
;
451 if (copy_from_user(&info
, (void *) arg
, sizeof(info
)))
453 return adsp_pmem_add(adev
->module
, &info
);
456 case ADSP_IOCTL_ABORT_EVENT_READ
:
458 wake_up(&adev
->event_wait
);
467 static int adsp_release(struct inode
*inode
, struct file
*filp
)
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
;
474 pr_info("adsp_release() '%s'\n", adev
->name
);
476 /* clear module before putting it to avoid race with open() */
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
);
483 put_pmem_file(region
->file
);
486 mutex_unlock(&module
->pmem_regions_lock
);
487 BUG_ON(!hlist_empty(&module
->pmem_regions
));
489 msm_adsp_put(module
);
493 static void adsp_event(void *driver_data
, unsigned id
, size_t len
,
494 void (*getevent
)(void *ptr
, size_t len
))
496 struct adsp_device
*adev
= driver_data
;
497 struct adsp_event
*event
;
500 if (len
> ADSP_EVENT_MAX_SIZE
) {
501 pr_err("adsp_event: event too large (%d bytes)\n", len
);
505 event
= kmalloc(sizeof(*event
), GFP_ATOMIC
);
507 pr_err("adsp_event: cannot allocate buffer\n");
511 if (id
!= EVENT_MSG_ID
) {
517 getevent(event
->data
.msg16
, len
);
523 getevent(event
->data
.msg32
, len
);
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
);
532 static struct msm_adsp_ops adsp_ops
= {
536 static int adsp_open(struct inode
*inode
, struct file
*filp
)
538 struct adsp_device
*adev
;
541 rc
= nonseekable_open(inode
, filp
);
545 adev
= inode_to_device(inode
);
549 pr_info("adsp_open() name = '%s'\n", adev
->name
);
551 rc
= msm_adsp_get(adev
->name
, &adev
->module
, &adsp_ops
, adev
);
555 pr_info("adsp_open() module '%s' adev %p\n", adev
->name
, adev
);
556 filp
->private_data
= adev
;
558 INIT_HLIST_HEAD(&adev
->module
->pmem_regions
);
559 mutex_init(&adev
->module
->pmem_regions_lock
);
564 static unsigned adsp_device_count
;
565 static struct adsp_device
*adsp_devices
;
567 static struct adsp_device
*inode_to_device(struct inode
*inode
)
569 unsigned n
= MINOR(inode
->i_rdev
);
570 if (n
< adsp_device_count
) {
571 if (adsp_devices
[n
].device
)
572 return adsp_devices
+ n
;
577 static dev_t adsp_devno
;
578 static struct class *adsp_class
;
580 static struct file_operations adsp_fops
= {
581 .owner
= THIS_MODULE
,
583 .unlocked_ioctl
= adsp_ioctl
,
584 .release
= adsp_release
,
588 static void adsp_create(struct adsp_device
*adev
, const char *name
,
589 struct device
*parent
, dev_t devt
)
594 dev
= device_create(adsp_class
, parent
, devt
, "%s", name
);
598 init_waitqueue_head(&adev
->event_wait
);
599 INIT_LIST_HEAD(&adev
->event_queue
);
600 spin_lock_init(&adev
->event_queue_lock
);
602 cdev_init(&adev
->cdev
, &adsp_fops
);
603 adev
->cdev
.owner
= THIS_MODULE
;
605 rc
= cdev_add(&adev
->cdev
, devt
, 1);
607 device_destroy(adsp_class
, devt
);
614 void msm_adsp_publish_cdevs(struct msm_adsp_module
*modules
, unsigned n
)
618 adsp_devices
= kzalloc(sizeof(struct adsp_device
) * n
, GFP_KERNEL
);
622 adsp_class
= class_create(THIS_MODULE
, "adsp");
623 if (IS_ERR(adsp_class
))
624 goto fail_create_class
;
626 rc
= alloc_chrdev_region(&adsp_devno
, 0, n
, "adsp");
628 goto fail_alloc_region
;
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
));
640 class_unregister(adsp_class
);