Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(376)

Side by Side Diff: arch/arm/mach-tegra/nv/nvos_user.c

Issue 3256004: [ARM] tegra: add nvos/nvrm/nvmap drivers (Closed) Base URL: ssh://git@gitrw.chromium.org/kernel.git
Patch Set: remove ap15 headers Created 10 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « arch/arm/mach-tegra/nv/nvos/nvustring.c ('k') | arch/arm/mach-tegra/nv/nvreftrack/Makefile » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /*
2 * arch/arm/mach-tegra/nvos_user.c
3 *
4 * User-land access to NvOs APIs
5 *
6 * Copyright (c) 2008-2009, NVIDIA Corporation.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but WITHOUT
14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
16 * more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 */
22
23 #include <linux/interrupt.h>
24 #include <linux/io.h>
25 #include <linux/miscdevice.h>
26 #include <linux/module.h>
27 #include <linux/mm.h>
28 #include <linux/mutex.h>
29 #include <linux/proc_fs.h>
30 #include <linux/spinlock.h>
31 #include <linux/uaccess.h>
32 #include <linux/rwsem.h>
33 #include <mach/irqs.h>
34 #include "nvos.h"
35 #include "linux/nvos_ioctl.h"
36 #include "nvassert.h"
37
38 int nvos_open(struct inode *inode, struct file *file);
39 int nvos_close(struct inode *inode, struct file *file);
40 static long nvos_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
41 int nvos_mmap(struct file *file, struct vm_area_struct *vma);
42 int NvOsSemaphoreWaitInterruptible(NvOsSemaphoreHandle semaphore);
43
44 #define DEVICE_NAME "nvos"
45
46 static const struct file_operations nvos_fops =
47 {
48 .owner = THIS_MODULE,
49 .open = nvos_open,
50 .release = nvos_close,
51 .unlocked_ioctl = nvos_ioctl,
52 .mmap = nvos_mmap
53 };
54
55 static struct miscdevice nvosDevice =
56 {
57 .name = DEVICE_NAME,
58 .fops = &nvos_fops,
59 .minor = MISC_DYNAMIC_MINOR,
60 };
61
62 typedef struct NvOsIrqListNodeRec
63 {
64 struct list_head list;
65 NvOsInterruptHandle h;
66 } NvOsIrqListNode;
67
68 typedef struct NvOsInstanceRec
69 {
70 struct rw_semaphore RwLock;
71 struct vm_area_struct *Vma;
72 NvOsMemRangeParams *MemRange;
73 struct task_struct *tsk;
74 spinlock_t Lock;
75 struct list_head IrqHandles;
76 int pid;
77 } NvOsInstance;
78
79 static int __init nvos_init( void )
80 {
81 int retVal = 0;
82
83 retVal = misc_register(&nvosDevice);
84
85 if (retVal < 0)
86 {
87 printk("nvos init failure\n" );
88 }
89
90 return retVal;
91 }
92
93 static void __exit nvos_deinit( void )
94 {
95 misc_deregister (&nvosDevice);
96 }
97
98 int nvos_open(struct inode *inode, struct file *filp)
99 {
100 NvOsInstance *Instance = NULL;
101
102 filp->private_data = NULL;
103
104 Instance = NvOsAlloc(sizeof(NvOsInstance));
105 if (!Instance)
106 {
107 printk(KERN_INFO __FILE__ ": nvos_open failed\n");
108 return -ENOMEM;
109 }
110 init_rwsem(&Instance->RwLock);
111 Instance->tsk = current;
112 Instance->pid = current->group_leader->pid;
113 Instance->MemRange = NULL;
114 spin_lock_init(&Instance->Lock);
115 INIT_LIST_HEAD(&Instance->IrqHandles);
116 filp->private_data = (void*)Instance;
117
118 return 0;
119 }
120
121 int nvos_close(struct inode *inode, struct file *filp)
122 {
123 NvOsIrqListNode *LeakedIrq;
124
125 if (filp->private_data)
126 {
127 NvOsInstance *Instance = (NvOsInstance *)filp->private_data;
128 filp->private_data = NULL;
129 while (!list_empty(&Instance->IrqHandles))
130 {
131 LeakedIrq = list_first_entry(&Instance->IrqHandles,
132 NvOsIrqListNode, list);
133 list_del_init(&LeakedIrq->list);
134 printk(__FILE__": leaked NvOsInterruptHandle %p\n",
135 LeakedIrq->h);
136 NvOsInterruptUnregister(LeakedIrq->h);
137 NvOsFree(LeakedIrq);
138 }
139
140 if (Instance->MemRange)
141 NvOsFree(Instance->MemRange);
142 NvOsFree(Instance);
143 }
144
145 return 0;
146 }
147
148 extern NvError NvOsInterruptRegisterInternal(
149 NvU32 IrqListSize,
150 const NvU32 *pIrqList,
151 const void *pIrqHandlerList,
152 void* context,
153 NvOsInterruptHandle *handle,
154 NvBool InterruptEnable,
155 NvBool IsUser);
156
157 static int interrupt_op(
158 NvOsInstance *Instance,
159 unsigned int cmd,
160 unsigned long arg)
161 {
162 NvOsInterruptOpParams p;
163 NvOsInterruptOpParams *user = (NvOsInterruptOpParams*)arg;
164 NvError e;
165
166 e = NvOsCopyIn(&p, user, sizeof(NvOsInterruptOpParams));
167 if (e != NvSuccess)
168 return -EINVAL;
169
170 switch(cmd) {
171 case NV_IOCTL_INTERRUPT_ENABLE:
172 e = NvOsInterruptEnable((NvOsInterruptHandle)p.handle);
173 break;
174 case NV_IOCTL_INTERRUPT_DONE:
175 NvOsInterruptDone((NvOsInterruptHandle)p.handle);
176 e = NvSuccess;
177 break;
178 case NV_IOCTL_INTERRUPT_UNREGISTER:
179 {
180 NvOsIrqListNode *IrqNode;
181 if (Instance)
182 {
183 e = NvError_CountMismatch;
184 spin_lock(&Instance->Lock);
185 list_for_each_entry(IrqNode, &Instance->IrqHandles, list)
186 {
187 if (IrqNode->h == (NvOsInterruptHandle)p.handle)
188 {
189 list_del(&IrqNode->list);
190 NvOsInterruptUnregister(IrqNode->h);
191 NvOsFree(IrqNode);
192 e = NvSuccess;
193 break;
194 }
195 }
196 spin_unlock(&Instance->Lock);
197 }
198 else
199 {
200 NvOsInterruptUnregister((NvOsInterruptHandle)p.handle);
201 }
202 e = NvSuccess;
203 break;
204 }
205 case NV_IOCTL_INTERRUPT_MASK:
206 NvOsInterruptMask((NvOsInterruptHandle)p.handle,
207 p.arg ? NV_TRUE : NV_FALSE);
208 e = NvSuccess;
209 break;
210 default:
211 return -EINVAL;
212 }
213
214 if (NvOsCopyOut(&user->errCode, &e, sizeof(e))!=NvSuccess)
215 return -EINVAL;
216 return 0;
217 }
218
219 static int interrupt_register(
220 NvOsInstance *Instance,
221 unsigned long arg)
222 {
223 NvOsInterruptRegisterParams k;
224 NvOsInterruptHandle h = NULL;
225 NvError e;
226 NvU32 *irqList = NULL;
227 NvOsSemaphoreHandle *semList = NULL;
228 NvOsIrqListNode *node = NULL;
229
230 e = NvOsCopyIn(&k, (void *)arg, sizeof(NvOsInterruptRegisterParams));
231 if (e!=NvSuccess)
232 return -EINVAL;
233
234 irqList = NvOsAlloc(k.nIrqs * sizeof(NvU32));
235 semList = NvOsAlloc(k.nIrqs * sizeof(NvOsSemaphoreHandle));
236 node = NvOsAlloc(sizeof(NvOsIrqListNode));
237 if (!node)
238 {
239 e = NvError_InsufficientMemory;
240 goto fail;
241 }
242
243 if (!irqList || !semList)
244 {
245 e = NvError_InsufficientMemory;
246 goto fail;
247 }
248 NV_CHECK_ERROR_CLEANUP(NvOsCopyIn(irqList, k.Irqs, k.nIrqs*sizeof(NvU32)));
249
250 NV_CHECK_ERROR_CLEANUP(
251 NvOsCopyIn(semList, k.SemaphoreList,
252 k.nIrqs*sizeof(NvOsSemaphoreHandle))
253 );
254
255 /* To ensure that the kernel handle is safely stored in the user-space
256 * wrapper before any interrupts are processed, interrupts must be
257 * registered and enabled in two separate ioctls.
258 */
259 e = NvOsInterruptRegisterInternal(k.nIrqs, irqList,
260 (const void*)semList, NULL, &h, NV_FALSE, NV_TRUE);
261
262 if (e==NvSuccess && Instance)
263 {
264 spin_lock(&Instance->Lock);
265 node->h = h;
266 list_add_tail(&node->list, &Instance->IrqHandles);
267 spin_unlock(&Instance->Lock);
268 }
269
270 fail:
271
272 NvOsFree(irqList);
273 NvOsFree(semList);
274 if (e!=NvSuccess)
275 {
276 NvOsFree(node);
277 h = NULL;
278 }
279
280 k.errCode = e;
281 k.kernelHandle = (NvUPtr)h;
282 e = NvOsCopyOut((void*)arg, &k, sizeof(k));
283
284 return (e==NvSuccess) ? 0 : -EINVAL;
285 }
286
287 static int sem_unmarshal(unsigned long arg)
288 {
289 NvOsSemaphoreUnmarshalParams *p = (NvOsSemaphoreUnmarshalParams *)arg;
290 NvOsSemaphoreUnmarshalParams l;
291 NvError e;
292
293 l.hNew = NULL;
294 e = NvOsCopyIn(&l, p, sizeof(l));
295 if (e!=NvSuccess)
296 return -EINVAL;
297
298 e = NvOsSemaphoreUnmarshal(l.hOrig, &l.hNew);
299 l.Error = e;
300
301 e = NvOsCopyOut(p, &l, sizeof(l));
302 if (e!=NvSuccess)
303 {
304 if (l.hNew)
305 NvOsSemaphoreDestroy(l.hNew);
306 return -EINVAL;
307 }
308 return 0;
309 }
310
311 static int sem_clone(unsigned long arg)
312 {
313 NvOsSemaphoreCloneParams *p = (NvOsSemaphoreCloneParams *)arg;
314 NvOsSemaphoreCloneParams l;
315 NvError e;
316
317 l.hNew = NULL;
318 e = NvOsCopyIn(&l, p, sizeof(l));
319 if (e!=NvSuccess)
320 return -EINVAL;
321
322 e = NvOsSemaphoreClone(l.hOrig, &l.hNew);
323 l.Error = e;
324 e = NvOsCopyOut(p, &l, sizeof(l));
325
326 if (e!=NvSuccess)
327 {
328 if (l.hNew)
329 NvOsSemaphoreDestroy(l.hNew);
330 return -EINVAL;
331 }
332
333 return 0;
334 }
335
336 static int sem_create(unsigned long arg)
337 {
338 NvOsSemaphoreIoctlParams *p = (NvOsSemaphoreIoctlParams *)arg;
339 NvOsSemaphoreIoctlParams l;
340
341 if (NvOsCopyIn(&l, p, sizeof(l))!=NvSuccess)
342 return -EINVAL;
343
344 l.sem = NULL;
345 l.error = NvOsSemaphoreCreate(&l.sem, l.value);
346
347 if (NvOsCopyOut(p, &l, sizeof(l))!=NvSuccess)
348 {
349 if (l.sem)
350 NvOsSemaphoreDestroy(l.sem);
351 return -EINVAL;
352 }
353
354 return 0;
355 }
356
357 static long nvos_ioctl(struct file *filp,
358 unsigned int cmd, unsigned long arg) {
359 int e = 0;
360 NvError err;
361 NvOsSemaphoreHandle kernelSem;
362 NvOsInstance *Instance = (NvOsInstance *)filp->private_data;
363
364 #define DO_CLEANUP( code ) \
365 do { \
366 err = code; \
367 if( err != NvSuccess ) \
368 { \
369 e = -EINVAL; \
370 goto clean; \
371 } \
372 } while( 0 )
373
374 switch( cmd ) {
375 case NV_IOCTL_SEMAPHORE_CREATE:
376 return sem_create(arg);
377
378 case NV_IOCTL_SEMAPHORE_DESTROY:
379 DO_CLEANUP(
380 NvOsCopyIn( &kernelSem, (void *)arg, sizeof(kernelSem) )
381 );
382
383 NvOsSemaphoreDestroy(kernelSem);
384 break;
385 case NV_IOCTL_SEMAPHORE_CLONE:
386 return sem_clone(arg);
387
388 case NV_IOCTL_SEMAPHORE_UNMARSHAL:
389 return sem_unmarshal(arg);
390
391 case NV_IOCTL_SEMAPHORE_SIGNAL:
392 DO_CLEANUP(
393 NvOsCopyIn( &kernelSem, (void *)arg, sizeof(kernelSem) )
394 );
395
396 NvOsSemaphoreSignal(kernelSem);
397 break;
398 case NV_IOCTL_SEMAPHORE_WAIT:
399 DO_CLEANUP(
400 NvOsCopyIn( &kernelSem, (void *)arg, sizeof(kernelSem) )
401 );
402 e = NvOsSemaphoreWaitInterruptible(kernelSem);
403 break;
404 case NV_IOCTL_SEMAPHORE_WAIT_TIMEOUT:
405 {
406 NvOsSemaphoreIoctlParams *p = (NvOsSemaphoreIoctlParams *)arg;
407 NvOsSemaphoreIoctlParams k;
408
409 DO_CLEANUP(
410 NvOsCopyIn( &k, p, sizeof(k) )
411 );
412
413 if (k.value == NV_WAIT_INFINITE)
414 {
415 k.error = NvSuccess;
416 e = NvOsSemaphoreWaitInterruptible(kernelSem);
417 }
418 else
419 {
420 k.error = NvOsSemaphoreWaitTimeout(k.sem, k.value);
421 }
422
423 DO_CLEANUP(
424 NvOsCopyOut( &p->error, &k.error, sizeof(k.error) )
425 );
426
427 break;
428 }
429 case NV_IOCTL_INTERRUPT_REGISTER:
430 lock_kernel();
431 e = interrupt_register(Instance, arg);
432 unlock_kernel();
433 return e;
434
435 case NV_IOCTL_INTERRUPT_UNREGISTER:
436 case NV_IOCTL_INTERRUPT_DONE:
437 case NV_IOCTL_INTERRUPT_ENABLE:
438 case NV_IOCTL_INTERRUPT_MASK:
439 lock_kernel();
440 e = interrupt_op(Instance, cmd, arg);
441 unlock_kernel();
442 return (e) ? -EINVAL : 0;
443
444 case NV_IOCTL_MEMORY_RANGE:
445 {
446 NvOsMemRangeParams *p;
447
448 p = NvOsAlloc( sizeof(NvOsMemRangeParams) );
449 if( !p )
450 {
451 e = -ENOMEM;
452 goto clean;
453 }
454
455 DO_CLEANUP(
456 NvOsCopyIn( p, (void *)arg, sizeof(NvOsMemRangeParams) );
457 );
458
459 if (!Instance)
460 printk(KERN_INFO __FILE__"(%d): No instance!\n", __LINE__);
461
462 if (Instance)
463 {
464 down_write(&Instance->RwLock);
465 Instance->MemRange = p;
466 up_write(&Instance->RwLock);
467 }
468 return 0;
469 }
470 default:
471 pr_err("Unknown IOCTL: %x\n", _IOC_NR(cmd));
472 e = -1;
473 }
474
475 #undef DO_CLEANUP
476
477 clean:
478 return e;
479 }
480
481 static void nvos_vma_open (struct vm_area_struct *vma)
482 {
483 }
484
485 static void nvos_vma_close (struct vm_area_struct *vma)
486 {
487 }
488
489 static struct vm_operations_struct nvos_vm_ops =
490 {
491 .open = nvos_vma_open,
492 .close = nvos_vma_close,
493 };
494
495 int nvos_mmap(struct file *filp, struct vm_area_struct *vma)
496 {
497 unsigned long addr;
498 unsigned long size;
499 unsigned long pfn;
500 NvOsInstance *Instance = (NvOsInstance *)filp->private_data;
501
502 size = vma->vm_end - vma->vm_start;
503 pfn = vma->vm_pgoff;
504 addr = pfn << PAGE_SHIFT;
505
506 if (!Instance)
507 printk(KERN_INFO __FILE__"(%d): No instance!\n", __LINE__);
508
509 if (Instance)
510 {
511 down_read(&Instance->RwLock);
512 if (Instance->MemRange)
513 {
514 /* addr is an offset */
515 if( size > Instance->MemRange->size )
516 {
517 printk( "nvos_mmap: size too big for restricted mapping: %lu "
518 "max %lu\n", size,
519 (unsigned long)Instance->MemRange->size );
520 up_read(&Instance->RwLock);
521 return -EAGAIN;
522 }
523 addr += Instance->MemRange->base;
524 pfn = addr >> PAGE_SHIFT;
525 }
526 up_read(&Instance->RwLock);
527 }
528
529 vma->vm_flags |= (VM_IO | VM_DONTCOPY | VM_DONTEXPAND);
530
531 // FIXME: This is a major hack
532 #ifdef CONFIG_ARCH_TEGRA_A9
533 if (addr < 0x40000000UL)
534 vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
535 else
536 #endif
537 vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
538
539 if (io_remap_pfn_range(vma, vma->vm_start, pfn, size, vma->vm_page_prot))
540 {
541 printk( "nvos_mmap failed\n" );
542 return -EAGAIN;
543 }
544
545 vma->vm_ops = &nvos_vm_ops;
546 vma->vm_private_data = Instance;
547
548 return 0;
549 }
550
551 module_init(nvos_init);
552 module_exit(nvos_deinit);
OLDNEW
« no previous file with comments | « arch/arm/mach-tegra/nv/nvos/nvustring.c ('k') | arch/arm/mach-tegra/nv/nvreftrack/Makefile » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698