]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_os.c
gpu: vivante: Update driver from Freescale 3.10.53-1.1-ga BSP
[karo-tx-linux.git] / drivers / mxc / gpu-viv / hal / os / linux / kernel / gc_hal_kernel_os.c
1 /****************************************************************************
2 *
3 *    Copyright (C) 2005 - 2014 by Vivante Corp.
4 *
5 *    This program is free software; you can redistribute it and/or modify
6 *    it under the terms of the GNU General Public License as published by
7 *    the Free Software Foundation; either version 2 of the license, or
8 *    (at your option) any later version.
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 *    You should have received a copy of the GNU General Public License
16 *    along with this program; if not write to the Free Software
17 *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 *
19 *****************************************************************************/
20
21
22 #include "gc_hal_kernel_linux.h"
23
24 #include <linux/pagemap.h>
25 #include <linux/seq_file.h>
26 #include <linux/mman.h>
27 #include <asm/atomic.h>
28 #include <linux/dma-mapping.h>
29 #include <linux/slab.h>
30 #include <linux/workqueue.h>
31 #include <linux/irqflags.h>
32 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,23)
33 #include <linux/math64.h>
34 #endif
35 #include <linux/delay.h>
36
37 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
38 #include <linux/anon_inodes.h>
39 #endif
40
41 #if gcdANDROID_NATIVE_FENCE_SYNC
42 #include <linux/file.h>
43 #include "gc_hal_kernel_sync.h"
44 #endif
45
46 #define _GC_OBJ_ZONE    gcvZONE_OS
47
48 #include "gc_hal_kernel_allocator.h"
49
50 #define MEMORY_LOCK(os) \
51     gcmkVERIFY_OK(gckOS_AcquireMutex( \
52                                 (os), \
53                                 (os)->memoryLock, \
54                                 gcvINFINITE))
55
56 #define MEMORY_UNLOCK(os) \
57     gcmkVERIFY_OK(gckOS_ReleaseMutex((os), (os)->memoryLock))
58
59 #define MEMORY_MAP_LOCK(os) \
60     gcmkVERIFY_OK(gckOS_AcquireMutex( \
61                                 (os), \
62                                 (os)->memoryMapLock, \
63                                 gcvINFINITE))
64
65 #define MEMORY_MAP_UNLOCK(os) \
66     gcmkVERIFY_OK(gckOS_ReleaseMutex((os), (os)->memoryMapLock))
67
68
69 /******************************************************************************\
70 ******************************* Private Functions ******************************
71 \******************************************************************************/
72 static gctINT
73 _GetThreadID(
74     void
75     )
76 {
77 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
78     return task_pid_vnr(current);
79 #else
80     return current->pid;
81 #endif
82 }
83
84 static PLINUX_MDL
85 _CreateMdl(
86     void
87     )
88 {
89     PLINUX_MDL  mdl;
90
91     gcmkHEADER();
92
93     mdl = (PLINUX_MDL)kzalloc(sizeof(struct _LINUX_MDL), GFP_KERNEL | gcdNOWARN);
94
95     gcmkFOOTER_ARG("0x%X", mdl);
96     return mdl;
97 }
98
99 static gceSTATUS
100 _DestroyMdlMap(
101     IN PLINUX_MDL Mdl,
102     IN PLINUX_MDL_MAP MdlMap
103     );
104
105 static gceSTATUS
106 _DestroyMdl(
107     IN PLINUX_MDL Mdl
108     )
109 {
110     PLINUX_MDL_MAP mdlMap, next;
111
112     gcmkHEADER_ARG("Mdl=0x%X", Mdl);
113
114     /* Verify the arguments. */
115     gcmkVERIFY_ARGUMENT(Mdl != gcvNULL);
116
117     mdlMap = Mdl->maps;
118
119     while (mdlMap != gcvNULL)
120     {
121         next = mdlMap->next;
122
123         gcmkVERIFY_OK(_DestroyMdlMap(Mdl, mdlMap));
124
125         mdlMap = next;
126     }
127
128     kfree(Mdl);
129
130     gcmkFOOTER_NO();
131     return gcvSTATUS_OK;
132 }
133
134 static PLINUX_MDL_MAP
135 _CreateMdlMap(
136     IN PLINUX_MDL Mdl,
137     IN gctINT ProcessID
138     )
139 {
140     PLINUX_MDL_MAP  mdlMap;
141
142     gcmkHEADER_ARG("Mdl=0x%X ProcessID=%d", Mdl, ProcessID);
143
144     mdlMap = (PLINUX_MDL_MAP)kmalloc(sizeof(struct _LINUX_MDL_MAP), GFP_KERNEL | gcdNOWARN);
145     if (mdlMap == gcvNULL)
146     {
147         gcmkFOOTER_NO();
148         return gcvNULL;
149     }
150
151     mdlMap->pid     = ProcessID;
152     mdlMap->vmaAddr = gcvNULL;
153     mdlMap->vma     = gcvNULL;
154     mdlMap->count   = 0;
155
156     mdlMap->next    = Mdl->maps;
157     Mdl->maps       = mdlMap;
158
159     gcmkFOOTER_ARG("0x%X", mdlMap);
160     return mdlMap;
161 }
162
163 static gceSTATUS
164 _DestroyMdlMap(
165     IN PLINUX_MDL Mdl,
166     IN PLINUX_MDL_MAP MdlMap
167     )
168 {
169     PLINUX_MDL_MAP  prevMdlMap;
170
171     gcmkHEADER_ARG("Mdl=0x%X MdlMap=0x%X", Mdl, MdlMap);
172
173     /* Verify the arguments. */
174     gcmkVERIFY_ARGUMENT(MdlMap != gcvNULL);
175     gcmkASSERT(Mdl->maps != gcvNULL);
176
177     if (Mdl->maps == MdlMap)
178     {
179         Mdl->maps = MdlMap->next;
180     }
181     else
182     {
183         prevMdlMap = Mdl->maps;
184
185         while (prevMdlMap->next != MdlMap)
186         {
187             prevMdlMap = prevMdlMap->next;
188
189             gcmkASSERT(prevMdlMap != gcvNULL);
190         }
191
192         prevMdlMap->next = MdlMap->next;
193     }
194
195     kfree(MdlMap);
196
197     gcmkFOOTER_NO();
198     return gcvSTATUS_OK;
199 }
200
201 extern PLINUX_MDL_MAP
202 FindMdlMap(
203     IN PLINUX_MDL Mdl,
204     IN gctINT ProcessID
205     )
206 {
207     PLINUX_MDL_MAP  mdlMap;
208
209     gcmkHEADER_ARG("Mdl=0x%X ProcessID=%d", Mdl, ProcessID);
210     if(Mdl == gcvNULL)
211     {
212         gcmkFOOTER_NO();
213         return gcvNULL;
214     }
215     mdlMap = Mdl->maps;
216
217     while (mdlMap != gcvNULL)
218     {
219         if (mdlMap->pid == ProcessID)
220         {
221             gcmkFOOTER_ARG("0x%X", mdlMap);
222             return mdlMap;
223         }
224
225         mdlMap = mdlMap->next;
226     }
227
228     gcmkFOOTER_NO();
229     return gcvNULL;
230 }
231
232 /*******************************************************************************
233 ** Integer Id Management.
234 */
235 gceSTATUS
236 _AllocateIntegerId(
237     IN gcsINTEGER_DB_PTR Database,
238     IN gctPOINTER KernelPointer,
239     OUT gctUINT32 *Id
240     )
241 {
242     int result;
243     gctINT next;
244
245 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)
246     idr_preload(GFP_KERNEL | gcdNOWARN);
247
248     spin_lock(&Database->lock);
249
250     next = (Database->curr + 1 <= 0) ? 1 : Database->curr + 1;
251
252     result = idr_alloc(&Database->idr, KernelPointer, next, 0, GFP_ATOMIC);
253
254     /* ID allocated should not be 0. */
255     gcmkASSERT(result != 0);
256
257     if (result > 0)
258     {
259         Database->curr = *Id = result;
260     }
261
262     spin_unlock(&Database->lock);
263
264     idr_preload_end();
265
266     if (result < 0)
267     {
268         return gcvSTATUS_OUT_OF_RESOURCES;
269     }
270 #else
271 again:
272     if (idr_pre_get(&Database->idr, GFP_KERNEL | gcdNOWARN) == 0)
273     {
274         return gcvSTATUS_OUT_OF_MEMORY;
275     }
276
277     spin_lock(&Database->lock);
278
279     next = (Database->curr + 1 <= 0) ? 1 : Database->curr + 1;
280
281     /* Try to get a id greater than 0. */
282     result = idr_get_new_above(&Database->idr, KernelPointer, next, Id);
283
284     if (!result)
285     {
286         Database->curr = *Id;
287     }
288
289     spin_unlock(&Database->lock);
290
291     if (result == -EAGAIN)
292     {
293         goto again;
294     }
295
296     if (result != 0)
297     {
298         return gcvSTATUS_OUT_OF_RESOURCES;
299     }
300 #endif
301
302     return gcvSTATUS_OK;
303 }
304
305 gceSTATUS
306 _QueryIntegerId(
307     IN gcsINTEGER_DB_PTR Database,
308     IN gctUINT32  Id,
309     OUT gctPOINTER * KernelPointer
310     )
311 {
312     gctPOINTER pointer;
313
314     spin_lock(&Database->lock);
315
316     pointer = idr_find(&Database->idr, Id);
317
318     spin_unlock(&Database->lock);
319
320     if(pointer)
321     {
322         *KernelPointer = pointer;
323         return gcvSTATUS_OK;
324     }
325     else
326     {
327         gcmkTRACE_ZONE(
328                 gcvLEVEL_ERROR, gcvZONE_OS,
329                 "%s(%d) Id = %d is not found",
330                 __FUNCTION__, __LINE__, Id);
331
332         return gcvSTATUS_NOT_FOUND;
333     }
334 }
335
336 gceSTATUS
337 _DestroyIntegerId(
338     IN gcsINTEGER_DB_PTR Database,
339     IN gctUINT32 Id
340     )
341 {
342     spin_lock(&Database->lock);
343
344     idr_remove(&Database->idr, Id);
345
346     spin_unlock(&Database->lock);
347
348     return gcvSTATUS_OK;
349 }
350
351 gceSTATUS
352 _QueryProcessPageTable(
353     IN gctPOINTER Logical,
354     OUT gctUINT32 * Address
355     )
356 {
357     spinlock_t *lock;
358     gctUINTPTR_T logical = (gctUINTPTR_T)Logical;
359     pgd_t *pgd;
360     pud_t *pud;
361     pmd_t *pmd;
362     pte_t *pte;
363
364     if (!current->mm)
365     {
366         return gcvSTATUS_NOT_FOUND;
367     }
368
369     pgd = pgd_offset(current->mm, logical);
370     if (pgd_none(*pgd) || pgd_bad(*pgd))
371     {
372         return gcvSTATUS_NOT_FOUND;
373     }
374
375     pud = pud_offset(pgd, logical);
376     if (pud_none(*pud) || pud_bad(*pud))
377     {
378         return gcvSTATUS_NOT_FOUND;
379     }
380
381     pmd = pmd_offset(pud, logical);
382     if (pmd_none(*pmd) || pmd_bad(*pmd))
383     {
384         return gcvSTATUS_NOT_FOUND;
385     }
386
387     pte = pte_offset_map_lock(current->mm, pmd, logical, &lock);
388     if (!pte)
389     {
390         return gcvSTATUS_NOT_FOUND;
391     }
392
393     if (!pte_present(*pte))
394     {
395         pte_unmap_unlock(pte, lock);
396         return gcvSTATUS_NOT_FOUND;
397     }
398
399     *Address = (pte_pfn(*pte) << PAGE_SHIFT) | (logical & ~PAGE_MASK);
400     pte_unmap_unlock(pte, lock);
401
402     return gcvSTATUS_OK;
403 }
404
405 #if !gcdCACHE_FUNCTION_UNIMPLEMENTED && defined(CONFIG_OUTER_CACHE)
406 static inline gceSTATUS
407 outer_func(
408     gceCACHEOPERATION Type,
409     unsigned long Start,
410     unsigned long End
411     )
412 {
413     switch (Type)
414     {
415         case gcvCACHE_CLEAN:
416             outer_clean_range(Start, End);
417             break;
418         case gcvCACHE_INVALIDATE:
419             outer_inv_range(Start, End);
420             break;
421         case gcvCACHE_FLUSH:
422             outer_flush_range(Start, End);
423             break;
424         default:
425             return gcvSTATUS_INVALID_ARGUMENT;
426             break;
427     }
428     return gcvSTATUS_OK;
429 }
430
431 #if gcdENABLE_OUTER_CACHE_PATCH
432 /*******************************************************************************
433 **  _HandleOuterCache
434 **
435 **  Handle the outer cache for the specified addresses.
436 **
437 **  ARGUMENTS:
438 **
439 **      gckOS Os
440 **          Pointer to gckOS object.
441 **
442 **      gctPOINTER Physical
443 **          Physical address to flush.
444 **
445 **      gctPOINTER Logical
446 **          Logical address to flush.
447 **
448 **      gctSIZE_T Bytes
449 **          Size of the address range in bytes to flush.
450 **
451 **      gceOUTERCACHE_OPERATION Type
452 **          Operation need to be execute.
453 */
454 gceSTATUS
455 _HandleOuterCache(
456     IN gckOS Os,
457     IN gctUINT32 Physical,
458     IN gctPOINTER Logical,
459     IN gctSIZE_T Bytes,
460     IN gceCACHEOPERATION Type
461     )
462 {
463     gceSTATUS status;
464     unsigned long paddr;
465     gctPOINTER vaddr;
466     gctUINT32 offset, bytes, left;
467
468     gcmkHEADER_ARG("Os=0x%X Logical=0x%X Bytes=%lu",
469                    Os, Logical, Bytes);
470
471     if (Physical != gcvINVALID_ADDRESS)
472     {
473         /* Non paged memory or gcvPOOL_USER surface */
474         paddr = (unsigned long) Physical;
475         gcmkONERROR(outer_func(Type, paddr, paddr + Bytes));
476     }
477     else
478     {
479         /* Non contiguous virtual memory */
480         vaddr = Logical;
481         left = Bytes;
482
483         while (left)
484         {
485             /* Handle (part of) current page. */
486             offset = (gctUINTPTR_T)vaddr & ~PAGE_MASK;
487
488             bytes = gcmMIN(left, PAGE_SIZE - offset);
489
490             gcmkONERROR(_QueryProcessPageTable(vaddr, (gctUINT32*)&paddr));
491             gcmkONERROR(outer_func(Type, paddr, paddr + bytes));
492
493             vaddr = (gctUINT8_PTR)vaddr + bytes;
494             left -= bytes;
495         }
496     }
497
498     mb();
499
500     /* Success. */
501     gcmkFOOTER_NO();
502     return gcvSTATUS_OK;
503
504 OnError:
505     /* Return the status. */
506     gcmkFOOTER();
507     return status;
508 }
509 #endif
510 #endif
511
512 gctBOOL
513 _AllowAccess(
514     IN gckOS Os,
515     IN gceCORE Core,
516     IN gctUINT32 Address
517     )
518 {
519     gctUINT32 data;
520
521     /* Check external clock state. */
522     if (Os->clockStates[Core] == gcvFALSE)
523     {
524         gcmkPRINT("[galcore]: %s(%d) External clock off", __FUNCTION__, __LINE__);
525         return gcvFALSE;
526     }
527
528     /* Check internal clock state. */
529     if (Address == 0)
530     {
531         return gcvTRUE;
532     }
533
534 #if gcdMULTI_GPU
535     if (Core == gcvCORE_MAJOR)
536     {
537         data = readl((gctUINT8 *)Os->device->registerBases[gcvCORE_3D_0_ID] + 0x0);
538     }
539     else
540 #endif
541     {
542         data = readl((gctUINT8 *)Os->device->registerBases[Core] + 0x0);
543     }
544
545     if ((data & 0x3) == 0x3)
546     {
547         gcmkPRINT("[galcore]: %s(%d) Internal clock off", __FUNCTION__, __LINE__);
548         return gcvFALSE;
549     }
550
551     return gcvTRUE;
552 }
553
554 static gceSTATUS
555 _ShrinkMemory(
556     IN gckOS Os
557     )
558 {
559     gcsPLATFORM * platform;
560
561     gcmkHEADER_ARG("Os=0x%X", Os);
562     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
563
564     platform = Os->device->platform;
565
566     if (platform && platform->ops->shrinkMemory)
567     {
568         platform->ops->shrinkMemory(platform);
569     }
570     else
571     {
572         gcmkFOOTER_NO();
573         return gcvSTATUS_NOT_SUPPORTED;
574     }
575
576     gcmkFOOTER_NO();
577     return gcvSTATUS_OK;
578 }
579
580 /*******************************************************************************
581 **
582 **  gckOS_Construct
583 **
584 **  Construct a new gckOS object.
585 **
586 **  INPUT:
587 **
588 **      gctPOINTER Context
589 **          Pointer to the gckGALDEVICE class.
590 **
591 **  OUTPUT:
592 **
593 **      gckOS * Os
594 **          Pointer to a variable that will hold the pointer to the gckOS object.
595 */
596 gceSTATUS
597 gckOS_Construct(
598     IN gctPOINTER Context,
599     OUT gckOS * Os
600     )
601 {
602     gckOS os;
603     gceSTATUS status;
604     gctINT i;
605
606     gcmkHEADER_ARG("Context=0x%X", Context);
607
608     /* Verify the arguments. */
609     gcmkVERIFY_ARGUMENT(Os != gcvNULL);
610
611     /* Allocate the gckOS object. */
612     os = (gckOS) kmalloc(gcmSIZEOF(struct _gckOS), GFP_KERNEL | gcdNOWARN);
613
614     if (os == gcvNULL)
615     {
616         /* Out of memory. */
617         gcmkFOOTER_ARG("status=%d", gcvSTATUS_OUT_OF_MEMORY);
618         return gcvSTATUS_OUT_OF_MEMORY;
619     }
620
621     /* Zero the memory. */
622     gckOS_ZeroMemory(os, gcmSIZEOF(struct _gckOS));
623
624     /* Initialize the gckOS object. */
625     os->object.type = gcvOBJ_OS;
626
627     /* Set device device. */
628     os->device = Context;
629
630     /* Set allocateCount to 0, gckOS_Allocate has not been used yet. */
631     atomic_set(&os->allocateCount, 0);
632
633     /* Initialize the memory lock. */
634     gcmkONERROR(gckOS_CreateMutex(os, &os->memoryLock));
635     gcmkONERROR(gckOS_CreateMutex(os, &os->memoryMapLock));
636
637     /* Create debug lock mutex. */
638     gcmkONERROR(gckOS_CreateMutex(os, &os->debugLock));
639
640     os->mdlHead = os->mdlTail = gcvNULL;
641
642     /* Get the kernel process ID. */
643     gcmkONERROR(gckOS_GetProcessID(&os->kernelProcessID));
644
645     /*
646      * Initialize the signal manager.
647      */
648
649     /* Initialize mutex. */
650     gcmkONERROR(gckOS_CreateMutex(os, &os->signalMutex));
651
652     /* Initialize signal id database lock. */
653     spin_lock_init(&os->signalDB.lock);
654
655     /* Initialize signal id database. */
656     idr_init(&os->signalDB.idr);
657
658 #if gcdANDROID_NATIVE_FENCE_SYNC
659     /*
660      * Initialize the sync point manager.
661      */
662
663     /* Initialize mutex. */
664     gcmkONERROR(gckOS_CreateMutex(os, &os->syncPointMutex));
665
666     /* Initialize sync point id database lock. */
667     spin_lock_init(&os->syncPointDB.lock);
668
669     /* Initialize sync point id database. */
670     idr_init(&os->syncPointDB.idr);
671 #endif
672
673     /* Create a workqueue for os timer. */
674     os->workqueue = create_singlethread_workqueue("galcore workqueue");
675
676     if (os->workqueue == gcvNULL)
677     {
678         /* Out of memory. */
679         gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
680     }
681
682     os->paddingPage = alloc_page(GFP_KERNEL | __GFP_HIGHMEM | gcdNOWARN);
683     if (os->paddingPage == gcvNULL)
684     {
685         /* Out of memory. */
686         gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
687     }
688     else
689     {
690         SetPageReserved(os->paddingPage);
691     }
692
693     for (i = 0; i < gcdMAX_GPU_COUNT; i++)
694     {
695         mutex_init(&os->registerAccessLocks[i]);
696     }
697
698     gckOS_ImportAllocators(os);
699
700 #ifdef CONFIG_IOMMU_SUPPORT
701     if (((gckGALDEVICE)(os->device))->mmu == gcvFALSE)
702     {
703         /* Only use IOMMU when internal MMU is not enabled. */
704         status = gckIOMMU_Construct(os, &os->iommu);
705
706         if (gcmIS_ERROR(status))
707         {
708             gcmkTRACE_ZONE(
709                 gcvLEVEL_INFO, gcvZONE_OS,
710                 "%s(%d): Fail to setup IOMMU",
711                 __FUNCTION__, __LINE__
712                 );
713         }
714     }
715 #endif
716
717     /* Return pointer to the gckOS object. */
718     *Os = os;
719
720     /* Success. */
721     gcmkFOOTER_ARG("*Os=0x%X", *Os);
722     return gcvSTATUS_OK;
723
724 OnError:
725
726 #if gcdANDROID_NATIVE_FENCE_SYNC
727     if (os->syncPointMutex != gcvNULL)
728     {
729         gcmkVERIFY_OK(
730             gckOS_DeleteMutex(os, os->syncPointMutex));
731     }
732 #endif
733
734     if (os->signalMutex != gcvNULL)
735     {
736         gcmkVERIFY_OK(
737             gckOS_DeleteMutex(os, os->signalMutex));
738     }
739
740     if (os->memoryMapLock != gcvNULL)
741     {
742         gcmkVERIFY_OK(
743             gckOS_DeleteMutex(os, os->memoryMapLock));
744     }
745
746     if (os->memoryLock != gcvNULL)
747     {
748         gcmkVERIFY_OK(
749             gckOS_DeleteMutex(os, os->memoryLock));
750     }
751
752     if (os->debugLock != gcvNULL)
753     {
754         gcmkVERIFY_OK(
755             gckOS_DeleteMutex(os, os->debugLock));
756     }
757
758     if (os->workqueue != gcvNULL)
759     {
760         destroy_workqueue(os->workqueue);
761     }
762
763     kfree(os);
764
765     /* Return the error. */
766     gcmkFOOTER();
767     return status;
768 }
769
770 /*******************************************************************************
771 **
772 **  gckOS_Destroy
773 **
774 **  Destroy an gckOS object.
775 **
776 **  INPUT:
777 **
778 **      gckOS Os
779 **          Pointer to an gckOS object that needs to be destroyed.
780 **
781 **  OUTPUT:
782 **
783 **      Nothing.
784 */
785 gceSTATUS
786 gckOS_Destroy(
787     IN gckOS Os
788     )
789 {
790     gcmkHEADER_ARG("Os=0x%X", Os);
791
792     /* Verify the arguments. */
793     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
794
795     if (Os->paddingPage != gcvNULL)
796     {
797         ClearPageReserved(Os->paddingPage);
798         __free_page(Os->paddingPage);
799         Os->paddingPage = gcvNULL;
800     }
801
802 #if gcdANDROID_NATIVE_FENCE_SYNC
803     /*
804      * Destroy the sync point manager.
805      */
806
807     /* Destroy the mutex. */
808     gcmkVERIFY_OK(gckOS_DeleteMutex(Os, Os->syncPointMutex));
809 #endif
810
811     /*
812      * Destroy the signal manager.
813      */
814
815     /* Destroy the mutex. */
816     gcmkVERIFY_OK(gckOS_DeleteMutex(Os, Os->signalMutex));
817
818     /* Destroy the memory lock. */
819     gcmkVERIFY_OK(gckOS_DeleteMutex(Os, Os->memoryMapLock));
820     gcmkVERIFY_OK(gckOS_DeleteMutex(Os, Os->memoryLock));
821
822     /* Destroy debug lock mutex. */
823     gcmkVERIFY_OK(gckOS_DeleteMutex(Os, Os->debugLock));
824
825     /* Wait for all works done. */
826     flush_workqueue(Os->workqueue);
827
828     /* Destory work queue. */
829     destroy_workqueue(Os->workqueue);
830
831     gckOS_FreeAllocators(Os);
832
833 #ifdef CONFIG_IOMMU_SUPPORT
834     if (Os->iommu)
835     {
836         gckIOMMU_Destory(Os, Os->iommu);
837     }
838 #endif
839
840     /* Flush the debug cache. */
841     gcmkDEBUGFLUSH(~0U);
842
843     /* Mark the gckOS object as unknown. */
844     Os->object.type = gcvOBJ_UNKNOWN;
845
846
847     /* Free the gckOS object. */
848     kfree(Os);
849
850     /* Success. */
851     gcmkFOOTER_NO();
852     return gcvSTATUS_OK;
853 }
854
855 gceSTATUS
856 gckOS_CreateKernelVirtualMapping(
857     IN gckOS Os,
858     IN gctPHYS_ADDR Physical,
859     IN gctSIZE_T Bytes,
860     OUT gctPOINTER * Logical,
861     OUT gctSIZE_T * PageCount
862     )
863 {
864     gceSTATUS status;
865     PLINUX_MDL mdl = (PLINUX_MDL)Physical;
866     gckALLOCATOR allocator = mdl->allocator;
867
868     gcmkHEADER();
869
870     *PageCount = mdl->numPages;
871
872     gcmkONERROR(allocator->ops->MapKernel(allocator, mdl, Logical));
873
874     gcmkFOOTER_NO();
875     return gcvSTATUS_OK;
876
877 OnError:
878     gcmkFOOTER();
879     return status;
880 }
881
882 gceSTATUS
883 gckOS_DestroyKernelVirtualMapping(
884     IN gckOS Os,
885     IN gctPHYS_ADDR Physical,
886     IN gctSIZE_T Bytes,
887     IN gctPOINTER Logical
888     )
889 {
890     PLINUX_MDL mdl = (PLINUX_MDL)Physical;
891     gckALLOCATOR allocator = mdl->allocator;
892
893     gcmkHEADER();
894
895     allocator->ops->UnmapKernel(allocator, mdl, Logical);
896
897     gcmkFOOTER_NO();
898     return gcvSTATUS_OK;
899 }
900
901 gceSTATUS
902 gckOS_CreateUserVirtualMapping(
903     IN gckOS Os,
904     IN gctPHYS_ADDR Physical,
905     IN gctSIZE_T Bytes,
906     OUT gctPOINTER * Logical,
907     OUT gctSIZE_T * PageCount
908     )
909 {
910     return gckOS_LockPages(Os, Physical, Bytes, gcvFALSE, Logical, PageCount);
911 }
912
913 gceSTATUS
914 gckOS_DestroyUserVirtualMapping(
915     IN gckOS Os,
916     IN gctPHYS_ADDR Physical,
917     IN gctSIZE_T Bytes,
918     IN gctPOINTER Logical
919     )
920 {
921     return gckOS_UnlockPages(Os, Physical, Bytes, Logical);
922 }
923
924 /*******************************************************************************
925 **
926 **  gckOS_Allocate
927 **
928 **  Allocate memory.
929 **
930 **  INPUT:
931 **
932 **      gckOS Os
933 **          Pointer to an gckOS object.
934 **
935 **      gctSIZE_T Bytes
936 **          Number of bytes to allocate.
937 **
938 **  OUTPUT:
939 **
940 **      gctPOINTER * Memory
941 **          Pointer to a variable that will hold the allocated memory location.
942 */
943 gceSTATUS
944 gckOS_Allocate(
945     IN gckOS Os,
946     IN gctSIZE_T Bytes,
947     OUT gctPOINTER * Memory
948     )
949 {
950     gceSTATUS status;
951
952     gcmkHEADER_ARG("Os=0x%X Bytes=%lu", Os, Bytes);
953
954     /* Verify the arguments. */
955     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
956     gcmkVERIFY_ARGUMENT(Bytes > 0);
957     gcmkVERIFY_ARGUMENT(Memory != gcvNULL);
958
959     gcmkONERROR(gckOS_AllocateMemory(Os, Bytes, Memory));
960
961     /* Success. */
962     gcmkFOOTER_ARG("*Memory=0x%X", *Memory);
963     return gcvSTATUS_OK;
964
965 OnError:
966     /* Return the status. */
967     gcmkFOOTER();
968     return status;
969 }
970
971 /*******************************************************************************
972 **
973 **  gckOS_Free
974 **
975 **  Free allocated memory.
976 **
977 **  INPUT:
978 **
979 **      gckOS Os
980 **          Pointer to an gckOS object.
981 **
982 **      gctPOINTER Memory
983 **          Pointer to memory allocation to free.
984 **
985 **  OUTPUT:
986 **
987 **      Nothing.
988 */
989 gceSTATUS
990 gckOS_Free(
991     IN gckOS Os,
992     IN gctPOINTER Memory
993     )
994 {
995     gceSTATUS status;
996
997     gcmkHEADER_ARG("Os=0x%X Memory=0x%X", Os, Memory);
998
999     /* Verify the arguments. */
1000     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
1001     gcmkVERIFY_ARGUMENT(Memory != gcvNULL);
1002
1003     gcmkONERROR(gckOS_FreeMemory(Os, Memory));
1004
1005     /* Success. */
1006     gcmkFOOTER_NO();
1007     return gcvSTATUS_OK;
1008
1009 OnError:
1010     /* Return the status. */
1011     gcmkFOOTER();
1012     return status;
1013 }
1014
1015 /*******************************************************************************
1016 **
1017 **  gckOS_AllocateMemory
1018 **
1019 **  Allocate memory wrapper.
1020 **
1021 **  INPUT:
1022 **
1023 **      gctSIZE_T Bytes
1024 **          Number of bytes to allocate.
1025 **
1026 **  OUTPUT:
1027 **
1028 **      gctPOINTER * Memory
1029 **          Pointer to a variable that will hold the allocated memory location.
1030 */
1031 gceSTATUS
1032 gckOS_AllocateMemory(
1033     IN gckOS Os,
1034     IN gctSIZE_T Bytes,
1035     OUT gctPOINTER * Memory
1036     )
1037 {
1038     gctPOINTER memory;
1039     gceSTATUS status;
1040
1041     gcmkHEADER_ARG("Os=0x%X Bytes=%lu", Os, Bytes);
1042
1043     /* Verify the arguments. */
1044     gcmkVERIFY_ARGUMENT(Bytes > 0);
1045     gcmkVERIFY_ARGUMENT(Memory != gcvNULL);
1046
1047     if (Bytes > PAGE_SIZE)
1048     {
1049         memory = (gctPOINTER) vmalloc(Bytes);
1050     }
1051     else
1052     {
1053         memory = (gctPOINTER) kmalloc(Bytes, GFP_KERNEL | gcdNOWARN);
1054     }
1055
1056     if (memory == gcvNULL)
1057     {
1058         /* Out of memory. */
1059         gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
1060     }
1061
1062     /* Increase count. */
1063     atomic_inc(&Os->allocateCount);
1064
1065     /* Return pointer to the memory allocation. */
1066     *Memory = memory;
1067
1068     /* Success. */
1069     gcmkFOOTER_ARG("*Memory=0x%X", *Memory);
1070     return gcvSTATUS_OK;
1071
1072 OnError:
1073     /* Return the status. */
1074     gcmkFOOTER();
1075     return status;
1076 }
1077
1078 /*******************************************************************************
1079 **
1080 **  gckOS_FreeMemory
1081 **
1082 **  Free allocated memory wrapper.
1083 **
1084 **  INPUT:
1085 **
1086 **      gctPOINTER Memory
1087 **          Pointer to memory allocation to free.
1088 **
1089 **  OUTPUT:
1090 **
1091 **      Nothing.
1092 */
1093 gceSTATUS
1094 gckOS_FreeMemory(
1095     IN gckOS Os,
1096     IN gctPOINTER Memory
1097     )
1098 {
1099     gcmkHEADER_ARG("Memory=0x%X", Memory);
1100
1101     /* Verify the arguments. */
1102     gcmkVERIFY_ARGUMENT(Memory != gcvNULL);
1103
1104     /* Free the memory from the OS pool. */
1105     if (is_vmalloc_addr(Memory))
1106     {
1107         vfree(Memory);
1108     }
1109     else
1110     {
1111         kfree(Memory);
1112     }
1113
1114     /* Decrease count. */
1115     atomic_dec(&Os->allocateCount);
1116
1117     /* Success. */
1118     gcmkFOOTER_NO();
1119     return gcvSTATUS_OK;
1120 }
1121
1122 /*******************************************************************************
1123 **
1124 **  gckOS_MapMemory
1125 **
1126 **  Map physical memory into the current process.
1127 **
1128 **  INPUT:
1129 **
1130 **      gckOS Os
1131 **          Pointer to an gckOS object.
1132 **
1133 **      gctPHYS_ADDR Physical
1134 **          Start of physical address memory.
1135 **
1136 **      gctSIZE_T Bytes
1137 **          Number of bytes to map.
1138 **
1139 **  OUTPUT:
1140 **
1141 **      gctPOINTER * Memory
1142 **          Pointer to a variable that will hold the logical address of the
1143 **          mapped memory.
1144 */
1145 gceSTATUS
1146 gckOS_MapMemory(
1147     IN gckOS Os,
1148     IN gctPHYS_ADDR Physical,
1149     IN gctSIZE_T Bytes,
1150     OUT gctPOINTER * Logical
1151     )
1152 {
1153     PLINUX_MDL_MAP  mdlMap;
1154     PLINUX_MDL      mdl = (PLINUX_MDL)Physical;
1155
1156     gcmkHEADER_ARG("Os=0x%X Physical=0x%X Bytes=%lu", Os, Physical, Bytes);
1157
1158     /* Verify the arguments. */
1159     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
1160     gcmkVERIFY_ARGUMENT(Physical != 0);
1161     gcmkVERIFY_ARGUMENT(Bytes > 0);
1162     gcmkVERIFY_ARGUMENT(Logical != gcvNULL);
1163
1164     MEMORY_LOCK(Os);
1165
1166     mdlMap = FindMdlMap(mdl, _GetProcessID());
1167
1168     if (mdlMap == gcvNULL)
1169     {
1170         mdlMap = _CreateMdlMap(mdl, _GetProcessID());
1171
1172         if (mdlMap == gcvNULL)
1173         {
1174             MEMORY_UNLOCK(Os);
1175
1176             gcmkFOOTER_ARG("status=%d", gcvSTATUS_OUT_OF_MEMORY);
1177             return gcvSTATUS_OUT_OF_MEMORY;
1178         }
1179     }
1180
1181     if (mdlMap->vmaAddr == gcvNULL)
1182     {
1183 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)
1184         mdlMap->vmaAddr = (char *)vm_mmap(gcvNULL,
1185                     0L,
1186                     mdl->numPages * PAGE_SIZE,
1187                     PROT_READ | PROT_WRITE,
1188                     MAP_SHARED,
1189                     0);
1190 #else
1191         down_write(&current->mm->mmap_sem);
1192
1193         mdlMap->vmaAddr = (char *)do_mmap_pgoff(gcvNULL,
1194                     0L,
1195                     mdl->numPages * PAGE_SIZE,
1196                     PROT_READ | PROT_WRITE,
1197                     MAP_SHARED,
1198                     0);
1199
1200         up_write(&current->mm->mmap_sem);
1201 #endif
1202
1203         if (IS_ERR(mdlMap->vmaAddr))
1204         {
1205             gcmkTRACE(
1206                 gcvLEVEL_ERROR,
1207                 "%s(%d): do_mmap_pgoff error",
1208                 __FUNCTION__, __LINE__
1209                 );
1210
1211             gcmkTRACE(
1212                 gcvLEVEL_ERROR,
1213                 "%s(%d): mdl->numPages: %d mdl->vmaAddr: 0x%X",
1214                 __FUNCTION__, __LINE__,
1215                 mdl->numPages,
1216                 mdlMap->vmaAddr
1217                 );
1218
1219             mdlMap->vmaAddr = gcvNULL;
1220
1221             MEMORY_UNLOCK(Os);
1222
1223             gcmkFOOTER_ARG("status=%d", gcvSTATUS_OUT_OF_MEMORY);
1224             return gcvSTATUS_OUT_OF_MEMORY;
1225         }
1226
1227         down_write(&current->mm->mmap_sem);
1228
1229         mdlMap->vma = find_vma(current->mm, (unsigned long)mdlMap->vmaAddr);
1230
1231         if (!mdlMap->vma)
1232         {
1233             gcmkTRACE(
1234                 gcvLEVEL_ERROR,
1235                 "%s(%d): find_vma error.",
1236                 __FUNCTION__, __LINE__
1237                 );
1238
1239             mdlMap->vmaAddr = gcvNULL;
1240
1241             up_write(&current->mm->mmap_sem);
1242
1243             MEMORY_UNLOCK(Os);
1244
1245             gcmkFOOTER_ARG("status=%d", gcvSTATUS_OUT_OF_RESOURCES);
1246             return gcvSTATUS_OUT_OF_RESOURCES;
1247         }
1248
1249 #ifndef NO_DMA_COHERENT
1250         if (dma_mmap_writecombine(gcvNULL,
1251                     mdlMap->vma,
1252                     mdl->addr,
1253                     mdl->dmaHandle,
1254                     mdl->numPages * PAGE_SIZE) < 0)
1255         {
1256             up_write(&current->mm->mmap_sem);
1257
1258             gcmkTRACE(
1259                 gcvLEVEL_ERROR,
1260                 "%s(%d): dma_mmap_coherent error.",
1261                 __FUNCTION__, __LINE__
1262                 );
1263
1264             mdlMap->vmaAddr = gcvNULL;
1265
1266             MEMORY_UNLOCK(Os);
1267
1268             gcmkFOOTER_ARG("status=%d", gcvSTATUS_OUT_OF_RESOURCES);
1269             return gcvSTATUS_OUT_OF_RESOURCES;
1270         }
1271 #else
1272 #if !gcdPAGED_MEMORY_CACHEABLE
1273         mdlMap->vma->vm_page_prot = gcmkPAGED_MEMROY_PROT(mdlMap->vma->vm_page_prot);
1274         mdlMap->vma->vm_flags |= gcdVM_FLAGS;
1275 #   endif
1276         mdlMap->vma->vm_pgoff = 0;
1277
1278         if (remap_pfn_range(mdlMap->vma,
1279                             mdlMap->vma->vm_start,
1280                             mdl->dmaHandle >> PAGE_SHIFT,
1281                             mdl->numPages*PAGE_SIZE,
1282                             mdlMap->vma->vm_page_prot) < 0)
1283         {
1284             up_write(&current->mm->mmap_sem);
1285
1286             gcmkTRACE(
1287                 gcvLEVEL_ERROR,
1288                 "%s(%d): remap_pfn_range error.",
1289                 __FUNCTION__, __LINE__
1290                 );
1291
1292             mdlMap->vmaAddr = gcvNULL;
1293
1294             MEMORY_UNLOCK(Os);
1295
1296             gcmkFOOTER_ARG("status=%d", gcvSTATUS_OUT_OF_RESOURCES);
1297             return gcvSTATUS_OUT_OF_RESOURCES;
1298         }
1299 #endif
1300
1301         up_write(&current->mm->mmap_sem);
1302     }
1303
1304     MEMORY_UNLOCK(Os);
1305
1306     *Logical = mdlMap->vmaAddr;
1307
1308     gcmkFOOTER_ARG("*Logical=0x%X", *Logical);
1309     return gcvSTATUS_OK;
1310 }
1311
1312 /*******************************************************************************
1313 **
1314 **  gckOS_UnmapMemory
1315 **
1316 **  Unmap physical memory out of the current process.
1317 **
1318 **  INPUT:
1319 **
1320 **      gckOS Os
1321 **          Pointer to an gckOS object.
1322 **
1323 **      gctPHYS_ADDR Physical
1324 **          Start of physical address memory.
1325 **
1326 **      gctSIZE_T Bytes
1327 **          Number of bytes to unmap.
1328 **
1329 **      gctPOINTER Memory
1330 **          Pointer to a previously mapped memory region.
1331 **
1332 **  OUTPUT:
1333 **
1334 **      Nothing.
1335 */
1336 gceSTATUS
1337 gckOS_UnmapMemory(
1338     IN gckOS Os,
1339     IN gctPHYS_ADDR Physical,
1340     IN gctSIZE_T Bytes,
1341     IN gctPOINTER Logical
1342     )
1343 {
1344     gcmkHEADER_ARG("Os=0x%X Physical=0x%X Bytes=%lu Logical=0x%X",
1345                    Os, Physical, Bytes, Logical);
1346
1347     /* Verify the arguments. */
1348     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
1349     gcmkVERIFY_ARGUMENT(Physical != 0);
1350     gcmkVERIFY_ARGUMENT(Bytes > 0);
1351     gcmkVERIFY_ARGUMENT(Logical != gcvNULL);
1352
1353     gckOS_UnmapMemoryEx(Os, Physical, Bytes, Logical, _GetProcessID());
1354
1355     /* Success. */
1356     gcmkFOOTER_NO();
1357     return gcvSTATUS_OK;
1358 }
1359
1360
1361 /*******************************************************************************
1362 **
1363 **  gckOS_UnmapMemoryEx
1364 **
1365 **  Unmap physical memory in the specified process.
1366 **
1367 **  INPUT:
1368 **
1369 **      gckOS Os
1370 **          Pointer to an gckOS object.
1371 **
1372 **      gctPHYS_ADDR Physical
1373 **          Start of physical address memory.
1374 **
1375 **      gctSIZE_T Bytes
1376 **          Number of bytes to unmap.
1377 **
1378 **      gctPOINTER Memory
1379 **          Pointer to a previously mapped memory region.
1380 **
1381 **      gctUINT32 PID
1382 **          Pid of the process that opened the device and mapped this memory.
1383 **
1384 **  OUTPUT:
1385 **
1386 **      Nothing.
1387 */
1388 gceSTATUS
1389 gckOS_UnmapMemoryEx(
1390     IN gckOS Os,
1391     IN gctPHYS_ADDR Physical,
1392     IN gctSIZE_T Bytes,
1393     IN gctPOINTER Logical,
1394     IN gctUINT32 PID
1395     )
1396 {
1397     PLINUX_MDL_MAP          mdlMap;
1398     PLINUX_MDL              mdl = (PLINUX_MDL)Physical;
1399
1400     gcmkHEADER_ARG("Os=0x%X Physical=0x%X Bytes=%lu Logical=0x%X PID=%d",
1401                    Os, Physical, Bytes, Logical, PID);
1402
1403     /* Verify the arguments. */
1404     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
1405     gcmkVERIFY_ARGUMENT(Physical != 0);
1406     gcmkVERIFY_ARGUMENT(Bytes > 0);
1407     gcmkVERIFY_ARGUMENT(Logical != gcvNULL);
1408     gcmkVERIFY_ARGUMENT(PID != 0);
1409
1410     MEMORY_LOCK(Os);
1411
1412     if (Logical)
1413     {
1414         mdlMap = FindMdlMap(mdl, PID);
1415
1416         if (mdlMap == gcvNULL || mdlMap->vmaAddr == gcvNULL)
1417         {
1418             MEMORY_UNLOCK(Os);
1419
1420             gcmkFOOTER_ARG("status=%d", gcvSTATUS_INVALID_ARGUMENT);
1421             return gcvSTATUS_INVALID_ARGUMENT;
1422         }
1423
1424         _UnmapUserLogical(mdlMap->vmaAddr, mdl->numPages * PAGE_SIZE);
1425
1426         gcmkVERIFY_OK(_DestroyMdlMap(mdl, mdlMap));
1427     }
1428
1429     MEMORY_UNLOCK(Os);
1430
1431     /* Success. */
1432     gcmkFOOTER_NO();
1433     return gcvSTATUS_OK;
1434 }
1435
1436 /*******************************************************************************
1437 **
1438 **  gckOS_UnmapUserLogical
1439 **
1440 **  Unmap user logical memory out of physical memory.
1441 **
1442 **  INPUT:
1443 **
1444 **      gckOS Os
1445 **          Pointer to an gckOS object.
1446 **
1447 **      gctPHYS_ADDR Physical
1448 **          Start of physical address memory.
1449 **
1450 **      gctSIZE_T Bytes
1451 **          Number of bytes to unmap.
1452 **
1453 **      gctPOINTER Memory
1454 **          Pointer to a previously mapped memory region.
1455 **
1456 **  OUTPUT:
1457 **
1458 **      Nothing.
1459 */
1460 gceSTATUS
1461 gckOS_UnmapUserLogical(
1462     IN gckOS Os,
1463     IN gctPHYS_ADDR Physical,
1464     IN gctSIZE_T Bytes,
1465     IN gctPOINTER Logical
1466     )
1467 {
1468     gcmkHEADER_ARG("Os=0x%X Physical=0x%X Bytes=%lu Logical=0x%X",
1469                    Os, Physical, Bytes, Logical);
1470
1471     /* Verify the arguments. */
1472     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
1473     gcmkVERIFY_ARGUMENT(Physical != 0);
1474     gcmkVERIFY_ARGUMENT(Bytes > 0);
1475     gcmkVERIFY_ARGUMENT(Logical != gcvNULL);
1476
1477     gckOS_UnmapMemory(Os, Physical, Bytes, Logical);
1478
1479     /* Success. */
1480     gcmkFOOTER_NO();
1481     return gcvSTATUS_OK;
1482
1483 }
1484
1485 /*******************************************************************************
1486 **
1487 **  gckOS_AllocateNonPagedMemory
1488 **
1489 **  Allocate a number of pages from non-paged memory.
1490 **
1491 **  INPUT:
1492 **
1493 **      gckOS Os
1494 **          Pointer to an gckOS object.
1495 **
1496 **      gctBOOL InUserSpace
1497 **          gcvTRUE if the pages need to be mapped into user space.
1498 **
1499 **      gctSIZE_T * Bytes
1500 **          Pointer to a variable that holds the number of bytes to allocate.
1501 **
1502 **  OUTPUT:
1503 **
1504 **      gctSIZE_T * Bytes
1505 **          Pointer to a variable that hold the number of bytes allocated.
1506 **
1507 **      gctPHYS_ADDR * Physical
1508 **          Pointer to a variable that will hold the physical address of the
1509 **          allocation.
1510 **
1511 **      gctPOINTER * Logical
1512 **          Pointer to a variable that will hold the logical address of the
1513 **          allocation.
1514 */
1515 gceSTATUS
1516 gckOS_AllocateNonPagedMemory(
1517     IN gckOS Os,
1518     IN gctBOOL InUserSpace,
1519     IN OUT gctSIZE_T * Bytes,
1520     OUT gctPHYS_ADDR * Physical,
1521     OUT gctPOINTER * Logical
1522     )
1523 {
1524     gctSIZE_T bytes;
1525     gctINT numPages;
1526     PLINUX_MDL mdl = gcvNULL;
1527     PLINUX_MDL_MAP mdlMap = gcvNULL;
1528     gctSTRING addr;
1529     gckKERNEL kernel;
1530 #ifdef NO_DMA_COHERENT
1531     struct page * page;
1532     long size, order;
1533     gctPOINTER vaddr;
1534 #endif
1535     gctBOOL locked = gcvFALSE;
1536     gceSTATUS status;
1537
1538     gcmkHEADER_ARG("Os=0x%X InUserSpace=%d *Bytes=%lu",
1539                    Os, InUserSpace, gcmOPT_VALUE(Bytes));
1540
1541     /* Verify the arguments. */
1542     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
1543     gcmkVERIFY_ARGUMENT(Bytes != gcvNULL);
1544     gcmkVERIFY_ARGUMENT(*Bytes > 0);
1545     gcmkVERIFY_ARGUMENT(Physical != gcvNULL);
1546     gcmkVERIFY_ARGUMENT(Logical != gcvNULL);
1547
1548     /* Align number of bytes to page size. */
1549     bytes = gcmALIGN(*Bytes, PAGE_SIZE);
1550
1551     /* Get total number of pages.. */
1552     numPages = GetPageCount(bytes, 0);
1553
1554     /* Allocate mdl+vector structure */
1555     mdl = _CreateMdl();
1556     if (mdl == gcvNULL)
1557     {
1558         gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
1559     }
1560
1561     mdl->pagedMem = 0;
1562     mdl->numPages = numPages;
1563
1564     MEMORY_LOCK(Os);
1565     locked = gcvTRUE;
1566
1567 #ifndef NO_DMA_COHERENT
1568 #ifdef CONFIG_ARM64
1569     addr = dma_alloc_coherent(gcvNULL,
1570 #else
1571     addr = dma_alloc_writecombine(gcvNULL,
1572 #endif
1573             mdl->numPages * PAGE_SIZE,
1574             &mdl->dmaHandle,
1575             GFP_KERNEL | gcdNOWARN);
1576 #else
1577     size    = mdl->numPages * PAGE_SIZE;
1578     order   = get_order(size);
1579
1580     page = alloc_pages(GFP_KERNEL | gcdNOWARN, order);
1581
1582     if (page == gcvNULL)
1583     {
1584         gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
1585     }
1586
1587     vaddr           = (gctPOINTER)page_address(page);
1588     mdl->contiguous = gcvTRUE;
1589     mdl->u.contiguousPages = page;
1590     addr            = _CreateKernelVirtualMapping(mdl);
1591     mdl->dmaHandle  = virt_to_phys(vaddr);
1592     mdl->kaddr      = vaddr;
1593
1594     /* Trigger a page fault. */
1595     memset(addr, 0, numPages * PAGE_SIZE);
1596
1597 #if !defined(CONFIG_PPC)
1598     /* Cache invalidate. */
1599     dma_sync_single_for_device(
1600                 gcvNULL,
1601                 page_to_phys(page),
1602                 bytes,
1603                 DMA_FROM_DEVICE);
1604 #endif
1605
1606     while (size > 0)
1607     {
1608         SetPageReserved(virt_to_page(vaddr));
1609
1610         vaddr   += PAGE_SIZE;
1611         size    -= PAGE_SIZE;
1612     }
1613 #endif
1614
1615     if (addr == gcvNULL)
1616     {
1617         gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
1618     }
1619
1620     kernel = Os->device->kernels[gcvCORE_MAJOR] != gcvNULL ?
1621                 Os->device->kernels[gcvCORE_MAJOR] : Os->device->kernels[gcvCORE_2D];
1622     if (((Os->device->baseAddress & 0x80000000) != (mdl->dmaHandle & 0x80000000)) &&
1623           kernel->hardware->mmuVersion == 0)
1624     {
1625         mdl->dmaHandle = (mdl->dmaHandle & ~0x80000000)
1626                        | (Os->device->baseAddress & 0x80000000);
1627     }
1628
1629     mdl->addr = addr;
1630
1631     /* Return allocated memory. */
1632     *Bytes = bytes;
1633     *Physical = (gctPHYS_ADDR) mdl;
1634
1635     if (InUserSpace)
1636     {
1637         mdlMap = _CreateMdlMap(mdl, _GetProcessID());
1638
1639         if (mdlMap == gcvNULL)
1640         {
1641             gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
1642         }
1643
1644         /* Only after mmap this will be valid. */
1645
1646         /* We need to map this to user space. */
1647 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)
1648         mdlMap->vmaAddr = (gctSTRING) vm_mmap(gcvNULL,
1649                 0L,
1650                 mdl->numPages * PAGE_SIZE,
1651                 PROT_READ | PROT_WRITE,
1652                 MAP_SHARED,
1653                 0);
1654 #else
1655         down_write(&current->mm->mmap_sem);
1656
1657         mdlMap->vmaAddr = (gctSTRING) do_mmap_pgoff(gcvNULL,
1658                 0L,
1659                 mdl->numPages * PAGE_SIZE,
1660                 PROT_READ | PROT_WRITE,
1661                 MAP_SHARED,
1662                 0);
1663
1664         up_write(&current->mm->mmap_sem);
1665 #endif
1666
1667         if (IS_ERR(mdlMap->vmaAddr))
1668         {
1669             gcmkTRACE_ZONE(
1670                 gcvLEVEL_WARNING, gcvZONE_OS,
1671                 "%s(%d): do_mmap_pgoff error",
1672                 __FUNCTION__, __LINE__
1673                 );
1674
1675             mdlMap->vmaAddr = gcvNULL;
1676
1677             gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
1678         }
1679
1680         down_write(&current->mm->mmap_sem);
1681
1682         mdlMap->vma = find_vma(current->mm, (unsigned long)mdlMap->vmaAddr);
1683
1684         if (mdlMap->vma == gcvNULL)
1685         {
1686             gcmkTRACE_ZONE(
1687                 gcvLEVEL_WARNING, gcvZONE_OS,
1688                 "%s(%d): find_vma error",
1689                 __FUNCTION__, __LINE__
1690                 );
1691
1692             up_write(&current->mm->mmap_sem);
1693
1694             gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES);
1695         }
1696
1697 #ifndef NO_DMA_COHERENT
1698         if (dma_mmap_coherent(gcvNULL,
1699                 mdlMap->vma,
1700                 mdl->addr,
1701                 mdl->dmaHandle,
1702                 mdl->numPages * PAGE_SIZE) < 0)
1703         {
1704             gcmkTRACE_ZONE(
1705                 gcvLEVEL_WARNING, gcvZONE_OS,
1706                 "%s(%d): dma_mmap_coherent error",
1707                 __FUNCTION__, __LINE__
1708                 );
1709
1710             up_write(&current->mm->mmap_sem);
1711
1712             gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES);
1713         }
1714 #else
1715 #if !gcdSECURITY
1716         mdlMap->vma->vm_page_prot = gcmkNONPAGED_MEMROY_PROT(mdlMap->vma->vm_page_prot);
1717 #endif
1718         mdlMap->vma->vm_flags |= gcdVM_FLAGS;
1719         mdlMap->vma->vm_pgoff = 0;
1720
1721         if (remap_pfn_range(mdlMap->vma,
1722                             mdlMap->vma->vm_start,
1723                             mdl->dmaHandle >> PAGE_SHIFT,
1724                             mdl->numPages * PAGE_SIZE,
1725                             mdlMap->vma->vm_page_prot))
1726         {
1727             gcmkTRACE_ZONE(
1728                 gcvLEVEL_WARNING, gcvZONE_OS,
1729                 "%s(%d): remap_pfn_range error",
1730                 __FUNCTION__, __LINE__
1731                 );
1732
1733             up_write(&current->mm->mmap_sem);
1734
1735             gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES);
1736         }
1737 #endif /* NO_DMA_COHERENT */
1738
1739         up_write(&current->mm->mmap_sem);
1740
1741         *Logical = mdlMap->vmaAddr;
1742     }
1743     else
1744     {
1745 #if gcdSECURITY
1746         *Logical = (gctPOINTER)mdl->kaddr;
1747 #else
1748         *Logical = (gctPOINTER)mdl->addr;
1749 #endif
1750     }
1751
1752     /*
1753      * Add this to a global list.
1754      * Will be used by get physical address
1755      * and mapuser pointer functions.
1756      */
1757
1758     if (!Os->mdlHead)
1759     {
1760         /* Initialize the queue. */
1761         Os->mdlHead = Os->mdlTail = mdl;
1762     }
1763     else
1764     {
1765         /* Add to the tail. */
1766         mdl->prev = Os->mdlTail;
1767         Os->mdlTail->next = mdl;
1768         Os->mdlTail = mdl;
1769     }
1770
1771     MEMORY_UNLOCK(Os);
1772
1773     /* Success. */
1774     gcmkFOOTER_ARG("*Bytes=%lu *Physical=0x%X *Logical=0x%X",
1775                    *Bytes, *Physical, *Logical);
1776     return gcvSTATUS_OK;
1777
1778 OnError:
1779     if (mdlMap != gcvNULL)
1780     {
1781         /* Free LINUX_MDL_MAP. */
1782         gcmkVERIFY_OK(_DestroyMdlMap(mdl, mdlMap));
1783     }
1784
1785     if (mdl != gcvNULL)
1786     {
1787         /* Free LINUX_MDL. */
1788         gcmkVERIFY_OK(_DestroyMdl(mdl));
1789     }
1790     *Physical = gcvNULL;
1791     *Bytes = 0;
1792
1793     if (locked)
1794     {
1795         /* Unlock memory. */
1796         MEMORY_UNLOCK(Os);
1797     }
1798
1799     /* Return the status. */
1800     gcmkFOOTER();
1801     return status;
1802 }
1803
1804 /*******************************************************************************
1805 **
1806 **  gckOS_FreeNonPagedMemory
1807 **
1808 **  Free previously allocated and mapped pages from non-paged memory.
1809 **
1810 **  INPUT:
1811 **
1812 **      gckOS Os
1813 **          Pointer to an gckOS object.
1814 **
1815 **      gctSIZE_T Bytes
1816 **          Number of bytes allocated.
1817 **
1818 **      gctPHYS_ADDR Physical
1819 **          Physical address of the allocated memory.
1820 **
1821 **      gctPOINTER Logical
1822 **          Logical address of the allocated memory.
1823 **
1824 **  OUTPUT:
1825 **
1826 **      Nothing.
1827 */
1828 gceSTATUS gckOS_FreeNonPagedMemory(
1829     IN gckOS Os,
1830     IN gctSIZE_T Bytes,
1831     IN gctPHYS_ADDR Physical,
1832     IN gctPOINTER Logical
1833     )
1834 {
1835     PLINUX_MDL mdl;
1836     PLINUX_MDL_MAP mdlMap;
1837 #ifdef NO_DMA_COHERENT
1838     unsigned size;
1839     gctPOINTER vaddr;
1840 #endif /* NO_DMA_COHERENT */
1841
1842     gcmkHEADER_ARG("Os=0x%X Bytes=%lu Physical=0x%X Logical=0x%X",
1843                    Os, Bytes, Physical, Logical);
1844
1845     /* Verify the arguments. */
1846     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
1847     gcmkVERIFY_ARGUMENT(Bytes > 0);
1848     gcmkVERIFY_ARGUMENT(Physical != 0);
1849     gcmkVERIFY_ARGUMENT(Logical != gcvNULL);
1850
1851     /* Convert physical address into a pointer to a MDL. */
1852     mdl = (PLINUX_MDL) Physical;
1853
1854     MEMORY_LOCK(Os);
1855
1856 #ifndef NO_DMA_COHERENT
1857 #ifdef CONFIG_ARM64
1858     dma_free_coherent(gcvNULL,
1859 #else
1860     dma_free_writecombine(gcvNULL,
1861 #endif
1862             mdl->numPages * PAGE_SIZE,
1863             mdl->addr,
1864             mdl->dmaHandle);
1865 #else
1866     size    = mdl->numPages * PAGE_SIZE;
1867     vaddr   = mdl->kaddr;
1868
1869     while (size > 0)
1870     {
1871         ClearPageReserved(virt_to_page(vaddr));
1872
1873         vaddr   += PAGE_SIZE;
1874         size    -= PAGE_SIZE;
1875     }
1876
1877     free_pages((unsigned long)mdl->kaddr, get_order(mdl->numPages * PAGE_SIZE));
1878
1879     _DestoryKernelVirtualMapping(mdl->addr);
1880 #endif /* NO_DMA_COHERENT */
1881
1882     mdlMap = mdl->maps;
1883
1884     while (mdlMap != gcvNULL)
1885     {
1886         /* No mapped memory exists when free nonpaged memory */
1887         gcmkASSERT(mdlMap->vmaAddr == gcvNULL);
1888
1889         mdlMap = mdlMap->next;
1890     }
1891
1892     /* Remove the node from global list.. */
1893     if (mdl == Os->mdlHead)
1894     {
1895         if ((Os->mdlHead = mdl->next) == gcvNULL)
1896         {
1897             Os->mdlTail = gcvNULL;
1898         }
1899     }
1900     else
1901     {
1902         mdl->prev->next = mdl->next;
1903         if (mdl == Os->mdlTail)
1904         {
1905             Os->mdlTail = mdl->prev;
1906         }
1907         else
1908         {
1909             mdl->next->prev = mdl->prev;
1910         }
1911     }
1912
1913     MEMORY_UNLOCK(Os);
1914
1915     gcmkVERIFY_OK(_DestroyMdl(mdl));
1916
1917     /* Success. */
1918     gcmkFOOTER_NO();
1919     return gcvSTATUS_OK;
1920 }
1921
1922 /*******************************************************************************
1923 **
1924 **  gckOS_ReadRegister
1925 **
1926 **  Read data from a register.
1927 **
1928 **  INPUT:
1929 **
1930 **      gckOS Os
1931 **          Pointer to an gckOS object.
1932 **
1933 **      gctUINT32 Address
1934 **          Address of register.
1935 **
1936 **  OUTPUT:
1937 **
1938 **      gctUINT32 * Data
1939 **          Pointer to a variable that receives the data read from the register.
1940 */
1941 gceSTATUS
1942 gckOS_ReadRegister(
1943     IN gckOS Os,
1944     IN gctUINT32 Address,
1945     OUT gctUINT32 * Data
1946     )
1947 {
1948     return gckOS_ReadRegisterEx(Os, gcvCORE_MAJOR, Address, Data);
1949 }
1950
1951 gceSTATUS
1952 gckOS_ReadRegisterEx(
1953     IN gckOS Os,
1954     IN gceCORE Core,
1955     IN gctUINT32 Address,
1956     OUT gctUINT32 * Data
1957     )
1958 {
1959     gcmkHEADER_ARG("Os=0x%X Core=%d Address=0x%X", Os, Core, Address);
1960
1961     /* Verify the arguments. */
1962     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
1963 #if !gcdMULTI_GPU
1964     gcmkVERIFY_ARGUMENT(Address < Os->device->requestedRegisterMemSizes[Core]);
1965 #endif
1966     gcmkVERIFY_ARGUMENT(Data != gcvNULL);
1967
1968     if (!in_interrupt())
1969     {
1970         mutex_lock(&Os->registerAccessLocks[Core]);
1971     }
1972
1973     BUG_ON(!_AllowAccess(Os, Core, Address));
1974
1975 #if gcdMULTI_GPU
1976     if (Core == gcvCORE_MAJOR)
1977     {
1978        *Data = readl((gctUINT8 *)Os->device->registerBase3D[gcvCORE_3D_0_ID] + Address);
1979     }
1980     else
1981 #endif
1982     {
1983         *Data = readl((gctUINT8 *)Os->device->registerBases[Core] + Address);
1984     }
1985
1986     if (!in_interrupt())
1987     {
1988         mutex_unlock(&Os->registerAccessLocks[Core]);
1989     }
1990
1991     /* Success. */
1992     gcmkFOOTER_ARG("*Data=0x%08x", *Data);
1993     return gcvSTATUS_OK;
1994 }
1995
1996 #if gcdMULTI_GPU
1997 gceSTATUS
1998 gckOS_ReadRegisterByCoreId(
1999     IN gckOS Os,
2000     IN gceCORE Core,
2001     IN gctUINT32 CoreId,
2002     IN gctUINT32 Address,
2003     OUT gctUINT32 * Data
2004     )
2005 {
2006     gcmkHEADER_ARG("Os=0x%X Core=%d CoreId=%d Address=0x%X",
2007                    Os, Core, CoreId, Address);
2008
2009     /* Verify the arguments. */
2010     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
2011     gcmkVERIFY_ARGUMENT(Data != gcvNULL);
2012
2013     *Data = readl((gctUINT8 *)Os->device->registerBase3D[CoreId] + Address);
2014
2015     /* Success. */
2016     gcmkFOOTER_ARG("*Data=0x%08x", *Data);
2017     return gcvSTATUS_OK;
2018 }
2019 #endif
2020
2021 /*******************************************************************************
2022 **
2023 **  gckOS_WriteRegister
2024 **
2025 **  Write data to a register.
2026 **
2027 **  INPUT:
2028 **
2029 **      gckOS Os
2030 **          Pointer to an gckOS object.
2031 **
2032 **      gctUINT32 Address
2033 **          Address of register.
2034 **
2035 **      gctUINT32 Data
2036 **          Data for register.
2037 **
2038 **  OUTPUT:
2039 **
2040 **      Nothing.
2041 */
2042 gceSTATUS
2043 gckOS_WriteRegister(
2044     IN gckOS Os,
2045     IN gctUINT32 Address,
2046     IN gctUINT32 Data
2047     )
2048 {
2049     return gckOS_WriteRegisterEx(Os, gcvCORE_MAJOR, Address, Data);
2050 }
2051
2052 gceSTATUS
2053 gckOS_WriteRegisterEx(
2054     IN gckOS Os,
2055     IN gceCORE Core,
2056     IN gctUINT32 Address,
2057     IN gctUINT32 Data
2058     )
2059 {
2060     gcmkHEADER_ARG("Os=0x%X Core=%d Address=0x%X Data=0x%08x", Os, Core, Address, Data);
2061
2062 #if !gcdMULTI_GPU
2063     gcmkVERIFY_ARGUMENT(Address < Os->device->requestedRegisterMemSizes[Core]);
2064 #endif
2065
2066     if (!in_interrupt())
2067     {
2068         mutex_lock(&Os->registerAccessLocks[Core]);
2069     }
2070
2071     BUG_ON(!_AllowAccess(Os, Core, Address));
2072
2073 #if gcdMULTI_GPU
2074     if (Core == gcvCORE_MAJOR)
2075     {
2076         writel(Data, (gctUINT8 *)Os->device->registerBase3D[gcvCORE_3D_0_ID] + Address);
2077 #if gcdMULTI_GPU > 1
2078         writel(Data, (gctUINT8 *)Os->device->registerBase3D[gcvCORE_3D_1_ID] + Address);
2079 #endif
2080     }
2081     else
2082 #endif
2083     {
2084         writel(Data, (gctUINT8 *)Os->device->registerBases[Core] + Address);
2085     }
2086
2087     if (!in_interrupt())
2088     {
2089         mutex_unlock(&Os->registerAccessLocks[Core]);
2090     }
2091
2092     /* Success. */
2093     gcmkFOOTER_NO();
2094     return gcvSTATUS_OK;
2095 }
2096
2097 #if gcdMULTI_GPU
2098 gceSTATUS
2099 gckOS_WriteRegisterByCoreId(
2100     IN gckOS Os,
2101     IN gceCORE Core,
2102     IN gctUINT32 CoreId,
2103     IN gctUINT32 Address,
2104     IN gctUINT32 Data
2105     )
2106 {
2107     gcmkHEADER_ARG("Os=0x%X Core=%d CoreId=%d Address=0x%X Data=0x%08x",
2108                    Os, Core, CoreId, Address, Data);
2109
2110     writel(Data, (gctUINT8 *)Os->device->registerBase3D[CoreId] + Address);
2111
2112     /* Success. */
2113     gcmkFOOTER_NO();
2114     return gcvSTATUS_OK;
2115 }
2116 #endif
2117
2118 /*******************************************************************************
2119 **
2120 **  gckOS_GetPageSize
2121 **
2122 **  Get the system's page size.
2123 **
2124 **  INPUT:
2125 **
2126 **      gckOS Os
2127 **          Pointer to an gckOS object.
2128 **
2129 **  OUTPUT:
2130 **
2131 **      gctSIZE_T * PageSize
2132 **          Pointer to a variable that will receive the system's page size.
2133 */
2134 gceSTATUS gckOS_GetPageSize(
2135     IN gckOS Os,
2136     OUT gctSIZE_T * PageSize
2137     )
2138 {
2139     gcmkHEADER_ARG("Os=0x%X", Os);
2140
2141     /* Verify the arguments. */
2142     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
2143     gcmkVERIFY_ARGUMENT(PageSize != gcvNULL);
2144
2145     /* Return the page size. */
2146     *PageSize = (gctSIZE_T) PAGE_SIZE;
2147
2148     /* Success. */
2149     gcmkFOOTER_ARG("*PageSize", *PageSize);
2150     return gcvSTATUS_OK;
2151 }
2152
2153 /*******************************************************************************
2154 **
2155 **  gckOS_GetPhysicalAddress
2156 **
2157 **  Get the physical system address of a corresponding virtual address.
2158 **
2159 **  INPUT:
2160 **
2161 **      gckOS Os
2162 **          Pointer to an gckOS object.
2163 **
2164 **      gctPOINTER Logical
2165 **          Logical address.
2166 **
2167 **  OUTPUT:
2168 **
2169 **      gctUINT32 * Address
2170 **          Poinetr to a variable that receives the 32-bit physical adress.
2171 */
2172 gceSTATUS
2173 gckOS_GetPhysicalAddress(
2174     IN gckOS Os,
2175     IN gctPOINTER Logical,
2176     OUT gctUINT32 * Address
2177     )
2178 {
2179     gceSTATUS status;
2180     gctUINT32 processID;
2181
2182     gcmkHEADER_ARG("Os=0x%X Logical=0x%X", Os, Logical);
2183
2184     /* Verify the arguments. */
2185     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
2186     gcmkVERIFY_ARGUMENT(Address != gcvNULL);
2187
2188     /* Query page table of current process first. */
2189     status = _QueryProcessPageTable(Logical, Address);
2190
2191     if (gcmIS_ERROR(status))
2192     {
2193         /* Get current process ID. */
2194         processID = _GetProcessID();
2195
2196         /* Route through other function. */
2197         gcmkONERROR(
2198             gckOS_GetPhysicalAddressProcess(Os, Logical, processID, Address));
2199     }
2200
2201     gcmkVERIFY_OK(gckOS_CPUPhysicalToGPUPhysical(Os, *Address, Address));
2202
2203     /* Success. */
2204     gcmkFOOTER_ARG("*Address=0x%08x", *Address);
2205     return gcvSTATUS_OK;
2206
2207 OnError:
2208     /* Return the status. */
2209     gcmkFOOTER();
2210     return status;
2211 }
2212
2213 /*******************************************************************************
2214 **
2215 **  gckOS_UserLogicalToPhysical
2216 **
2217 **  Get the physical system address of a corresponding user virtual address.
2218 **
2219 **  INPUT:
2220 **
2221 **      gckOS Os
2222 **          Pointer to an gckOS object.
2223 **
2224 **      gctPOINTER Logical
2225 **          Logical address.
2226 **
2227 **  OUTPUT:
2228 **
2229 **      gctUINT32 * Address
2230 **          Pointer to a variable that receives the 32-bit physical address.
2231 */
2232 gceSTATUS gckOS_UserLogicalToPhysical(
2233     IN gckOS Os,
2234     IN gctPOINTER Logical,
2235     OUT gctUINT32 * Address
2236     )
2237 {
2238     return gckOS_GetPhysicalAddress(Os, Logical, Address);
2239 }
2240
2241 #if gcdSECURE_USER
2242 static gceSTATUS
2243 gckOS_AddMapping(
2244     IN gckOS Os,
2245     IN gctUINT32 Physical,
2246     IN gctPOINTER Logical,
2247     IN gctSIZE_T Bytes
2248     )
2249 {
2250     gceSTATUS status;
2251     gcsUSER_MAPPING_PTR map;
2252
2253     gcmkHEADER_ARG("Os=0x%X Physical=0x%X Logical=0x%X Bytes=%lu",
2254                    Os, Physical, Logical, Bytes);
2255
2256     gcmkONERROR(gckOS_Allocate(Os,
2257                                gcmSIZEOF(gcsUSER_MAPPING),
2258                                (gctPOINTER *) &map));
2259
2260     map->next     = Os->userMap;
2261     map->physical = Physical - Os->device->baseAddress;
2262     map->logical  = Logical;
2263     map->bytes    = Bytes;
2264     map->start    = (gctINT8_PTR) Logical;
2265     map->end      = map->start + Bytes;
2266
2267     Os->userMap = map;
2268
2269     gcmkFOOTER_NO();
2270     return gcvSTATUS_OK;
2271
2272 OnError:
2273     gcmkFOOTER();
2274     return status;
2275 }
2276
2277 static gceSTATUS
2278 gckOS_RemoveMapping(
2279     IN gckOS Os,
2280     IN gctPOINTER Logical,
2281     IN gctSIZE_T Bytes
2282     )
2283 {
2284     gceSTATUS status;
2285     gcsUSER_MAPPING_PTR map, prev;
2286
2287     gcmkHEADER_ARG("Os=0x%X Logical=0x%X Bytes=%lu", Os, Logical, Bytes);
2288
2289     for (map = Os->userMap, prev = gcvNULL; map != gcvNULL; map = map->next)
2290     {
2291         if ((map->logical == Logical)
2292         &&  (map->bytes   == Bytes)
2293         )
2294         {
2295             break;
2296         }
2297
2298         prev = map;
2299     }
2300
2301     if (map == gcvNULL)
2302     {
2303         gcmkONERROR(gcvSTATUS_INVALID_ADDRESS);
2304     }
2305
2306     if (prev == gcvNULL)
2307     {
2308         Os->userMap = map->next;
2309     }
2310     else
2311     {
2312         prev->next = map->next;
2313     }
2314
2315     gcmkONERROR(gcmkOS_SAFE_FREE(Os, map));
2316
2317     gcmkFOOTER_NO();
2318     return gcvSTATUS_OK;
2319
2320 OnError:
2321     gcmkFOOTER();
2322     return status;
2323 }
2324 #endif
2325
2326 gceSTATUS
2327 _ConvertLogical2Physical(
2328     IN gckOS Os,
2329     IN gctPOINTER Logical,
2330     IN gctUINT32 ProcessID,
2331     IN PLINUX_MDL Mdl,
2332     OUT gctUINT32_PTR Physical
2333     )
2334 {
2335     gctINT8_PTR base, vBase;
2336     gctUINT32 offset;
2337     PLINUX_MDL_MAP map;
2338     gcsUSER_MAPPING_PTR userMap;
2339
2340 #if gcdSECURITY
2341     base = (Mdl == gcvNULL) ? gcvNULL : (gctINT8_PTR) Mdl->kaddr;
2342 #else
2343     base = (Mdl == gcvNULL) ? gcvNULL : (gctINT8_PTR) Mdl->addr;
2344 #endif
2345
2346     /* Check for the logical address match. */
2347     if ((base != gcvNULL)
2348     &&  ((gctINT8_PTR) Logical >= base)
2349     &&  ((gctINT8_PTR) Logical <  base + Mdl->numPages * PAGE_SIZE)
2350     )
2351     {
2352         offset = (gctINT8_PTR) Logical - base;
2353
2354         if (Mdl->dmaHandle != 0)
2355         {
2356             /* The memory was from coherent area. */
2357             *Physical = (gctUINT32) Mdl->dmaHandle + offset;
2358         }
2359         else if (Mdl->pagedMem && !Mdl->contiguous)
2360         {
2361             /* paged memory is not mapped to kernel space. */
2362             return gcvSTATUS_INVALID_ADDRESS;
2363         }
2364         else
2365         {
2366             *Physical = gcmPTR2INT32(virt_to_phys(base)) + offset;
2367         }
2368
2369         return gcvSTATUS_OK;
2370     }
2371
2372     /* Walk user maps. */
2373     for (userMap = Os->userMap; userMap != gcvNULL; userMap = userMap->next)
2374     {
2375         if (((gctINT8_PTR) Logical >= userMap->start)
2376         &&  ((gctINT8_PTR) Logical <  userMap->end)
2377         )
2378         {
2379             *Physical = userMap->physical
2380                       + (gctUINT32) ((gctINT8_PTR) Logical - userMap->start);
2381
2382             return gcvSTATUS_OK;
2383         }
2384     }
2385
2386     if (ProcessID != Os->kernelProcessID)
2387     {
2388         map   = FindMdlMap(Mdl, (gctINT) ProcessID);
2389         vBase = (map == gcvNULL) ? gcvNULL : (gctINT8_PTR) map->vmaAddr;
2390
2391         /* Is the given address within that range. */
2392         if ((vBase != gcvNULL)
2393         &&  ((gctINT8_PTR) Logical >= vBase)
2394         &&  ((gctINT8_PTR) Logical <  vBase + Mdl->numPages * PAGE_SIZE)
2395         )
2396         {
2397             offset = (gctINT8_PTR) Logical - vBase;
2398
2399             if (Mdl->dmaHandle != 0)
2400             {
2401                 /* The memory was from coherent area. */
2402                 *Physical = (gctUINT32) Mdl->dmaHandle + offset;
2403             }
2404             else if (Mdl->pagedMem && !Mdl->contiguous)
2405             {
2406                 *Physical = _NonContiguousToPhys(Mdl->u.nonContiguousPages, offset/PAGE_SIZE);
2407             }
2408             else
2409             {
2410                 *Physical = page_to_phys(Mdl->u.contiguousPages) + offset;
2411             }
2412
2413             return gcvSTATUS_OK;
2414         }
2415     }
2416
2417     /* Address not yet found. */
2418     return gcvSTATUS_INVALID_ADDRESS;
2419 }
2420
2421 /*******************************************************************************
2422 **
2423 **  gckOS_GetPhysicalAddressProcess
2424 **
2425 **  Get the physical system address of a corresponding virtual address for a
2426 **  given process.
2427 **
2428 **  INPUT:
2429 **
2430 **      gckOS Os
2431 **          Pointer to gckOS object.
2432 **
2433 **      gctPOINTER Logical
2434 **          Logical address.
2435 **
2436 **      gctUINT32 ProcessID
2437 **          Process ID.
2438 **
2439 **  OUTPUT:
2440 **
2441 **      gctUINT32 * Address
2442 **          Poinetr to a variable that receives the 32-bit physical adress.
2443 */
2444 gceSTATUS
2445 gckOS_GetPhysicalAddressProcess(
2446     IN gckOS Os,
2447     IN gctPOINTER Logical,
2448     IN gctUINT32 ProcessID,
2449     OUT gctUINT32 * Address
2450     )
2451 {
2452     PLINUX_MDL mdl;
2453     gctINT8_PTR base;
2454     gckALLOCATOR allocator = gcvNULL;
2455     gceSTATUS status = gcvSTATUS_INVALID_ADDRESS;
2456
2457     gcmkHEADER_ARG("Os=0x%X Logical=0x%X ProcessID=%d", Os, Logical, ProcessID);
2458
2459     /* Verify the arguments. */
2460     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
2461     gcmkVERIFY_ARGUMENT(Address != gcvNULL);
2462
2463     MEMORY_LOCK(Os);
2464
2465     /* First try the contiguous memory pool. */
2466     if (Os->device->contiguousMapped)
2467     {
2468         base = (gctINT8_PTR) Os->device->contiguousBase;
2469
2470         if (((gctINT8_PTR) Logical >= base)
2471         &&  ((gctINT8_PTR) Logical <  base + Os->device->contiguousSize)
2472         )
2473         {
2474             /* Convert logical address into physical. */
2475             *Address = Os->device->contiguousVidMem->baseAddress
2476                      + (gctINT8_PTR) Logical - base;
2477             status   = gcvSTATUS_OK;
2478         }
2479     }
2480     else
2481     {
2482         /* Try the contiguous memory pool. */
2483         mdl = (PLINUX_MDL) Os->device->contiguousPhysical;
2484         status = _ConvertLogical2Physical(Os,
2485                                           Logical,
2486                                           ProcessID,
2487                                           mdl,
2488                                           Address);
2489     }
2490
2491     if (gcmIS_ERROR(status))
2492     {
2493         /* Walk all MDLs. */
2494         for (mdl = Os->mdlHead; mdl != gcvNULL; mdl = mdl->next)
2495         {
2496             /* Try this MDL. */
2497             allocator = mdl->allocator;
2498
2499             if (allocator)
2500             {
2501                 status = allocator->ops->LogicalToPhysical(
2502                             allocator,
2503                             mdl,
2504                             Logical,
2505                             ProcessID,
2506                             Address
2507                             );
2508             }
2509             else
2510             {
2511                 status = _ConvertLogical2Physical(Os,
2512                             Logical,
2513                             ProcessID,
2514                             mdl,
2515                             Address);
2516             }
2517
2518             if (gcmIS_SUCCESS(status))
2519             {
2520                 break;
2521             }
2522         }
2523     }
2524
2525     MEMORY_UNLOCK(Os);
2526
2527     gcmkONERROR(status);
2528
2529     /* Success. */
2530     gcmkFOOTER_ARG("*Address=0x%08x", *Address);
2531     return gcvSTATUS_OK;
2532
2533 OnError:
2534     /* Return the status. */
2535     gcmkFOOTER();
2536     return status;
2537 }
2538
2539 /*******************************************************************************
2540 **
2541 **  gckOS_MapPhysical
2542 **
2543 **  Map a physical address into kernel space.
2544 **
2545 **  INPUT:
2546 **
2547 **      gckOS Os
2548 **          Pointer to an gckOS object.
2549 **
2550 **      gctUINT32 Physical
2551 **          Physical address of the memory to map.
2552 **
2553 **      gctSIZE_T Bytes
2554 **          Number of bytes to map.
2555 **
2556 **  OUTPUT:
2557 **
2558 **      gctPOINTER * Logical
2559 **          Pointer to a variable that receives the base address of the mapped
2560 **          memory.
2561 */
2562 gceSTATUS
2563 gckOS_MapPhysical(
2564     IN gckOS Os,
2565     IN gctUINT32 Physical,
2566     IN gctSIZE_T Bytes,
2567     OUT gctPOINTER * Logical
2568     )
2569 {
2570     gctPOINTER logical;
2571     PLINUX_MDL mdl;
2572     gctUINT32 physical = Physical;
2573
2574     gcmkHEADER_ARG("Os=0x%X Physical=0x%X Bytes=%lu", Os, Physical, Bytes);
2575
2576     /* Verify the arguments. */
2577     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
2578     gcmkVERIFY_ARGUMENT(Bytes > 0);
2579     gcmkVERIFY_ARGUMENT(Logical != gcvNULL);
2580
2581     MEMORY_LOCK(Os);
2582
2583     /* Go through our mapping to see if we know this physical address already. */
2584     mdl = Os->mdlHead;
2585
2586     while (mdl != gcvNULL)
2587     {
2588         if (mdl->dmaHandle != 0)
2589         {
2590             if ((physical >= mdl->dmaHandle)
2591             &&  (physical < mdl->dmaHandle + mdl->numPages * PAGE_SIZE)
2592             )
2593             {
2594                 *Logical = mdl->addr + (physical - mdl->dmaHandle);
2595                 break;
2596             }
2597         }
2598
2599         mdl = mdl->next;
2600     }
2601
2602     MEMORY_UNLOCK(Os);
2603
2604     if (mdl == gcvNULL)
2605     {
2606         struct page * page = pfn_to_page(physical >> PAGE_SHIFT);
2607
2608         if (pfn_valid(page_to_pfn(page)))
2609         {
2610             gctUINT32 offset = physical & ~PAGE_MASK;
2611             struct page ** pages;
2612             gctUINT numPages;
2613             gctINT i;
2614
2615             numPages = GetPageCount(PAGE_ALIGN(offset + Bytes), 0);
2616
2617             pages = kmalloc(sizeof(struct page *) * numPages, GFP_KERNEL | gcdNOWARN);
2618
2619             if (!pages)
2620             {
2621                 gcmkFOOTER_ARG("status=%d", gcvSTATUS_OUT_OF_MEMORY);
2622                 return gcvSTATUS_OUT_OF_MEMORY;
2623             }
2624
2625             for (i = 0; i < numPages; i++)
2626             {
2627                 pages[i] = nth_page(page, i);
2628             }
2629
2630             logical = vmap(pages, numPages, 0, gcmkNONPAGED_MEMROY_PROT(PAGE_KERNEL));
2631
2632             kfree(pages);
2633
2634             if (logical == gcvNULL)
2635             {
2636                 gcmkTRACE_ZONE(
2637                     gcvLEVEL_INFO, gcvZONE_OS,
2638                     "%s(%d): Failed to vmap",
2639                     __FUNCTION__, __LINE__
2640                     );
2641
2642                 /* Out of resources. */
2643                 gcmkFOOTER_ARG("status=%d", gcvSTATUS_OUT_OF_RESOURCES);
2644                 return gcvSTATUS_OUT_OF_RESOURCES;
2645             }
2646
2647             logical += offset;
2648         }
2649         else
2650         {
2651             /* Map memory as cached memory. */
2652             request_mem_region(physical, Bytes, "MapRegion");
2653             logical = (gctPOINTER) ioremap_nocache(physical, Bytes);
2654
2655             if (logical == gcvNULL)
2656             {
2657                 gcmkTRACE_ZONE(
2658                     gcvLEVEL_INFO, gcvZONE_OS,
2659                     "%s(%d): Failed to ioremap",
2660                     __FUNCTION__, __LINE__
2661                     );
2662
2663                 /* Out of resources. */
2664                 gcmkFOOTER_ARG("status=%d", gcvSTATUS_OUT_OF_RESOURCES);
2665                 return gcvSTATUS_OUT_OF_RESOURCES;
2666             }
2667         }
2668
2669         /* Return pointer to mapped memory. */
2670         *Logical = logical;
2671     }
2672
2673
2674     /* Success. */
2675     gcmkFOOTER_ARG("*Logical=0x%X", *Logical);
2676     return gcvSTATUS_OK;
2677 }
2678
2679 /*******************************************************************************
2680 **
2681 **  gckOS_UnmapPhysical
2682 **
2683 **  Unmap a previously mapped memory region from kernel memory.
2684 **
2685 **  INPUT:
2686 **
2687 **      gckOS Os
2688 **          Pointer to an gckOS object.
2689 **
2690 **      gctPOINTER Logical
2691 **          Pointer to the base address of the memory to unmap.
2692 **
2693 **      gctSIZE_T Bytes
2694 **          Number of bytes to unmap.
2695 **
2696 **  OUTPUT:
2697 **
2698 **      Nothing.
2699 */
2700 gceSTATUS
2701 gckOS_UnmapPhysical(
2702     IN gckOS Os,
2703     IN gctPOINTER Logical,
2704     IN gctSIZE_T Bytes
2705     )
2706 {
2707     PLINUX_MDL  mdl;
2708
2709     gcmkHEADER_ARG("Os=0x%X Logical=0x%X Bytes=%lu", Os, Logical, Bytes);
2710
2711     /* Verify the arguments. */
2712     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
2713     gcmkVERIFY_ARGUMENT(Logical != gcvNULL);
2714     gcmkVERIFY_ARGUMENT(Bytes > 0);
2715
2716     MEMORY_LOCK(Os);
2717
2718     mdl = Os->mdlHead;
2719
2720     while (mdl != gcvNULL)
2721     {
2722         if (mdl->addr != gcvNULL)
2723         {
2724             if (Logical >= (gctPOINTER)mdl->addr
2725                     && Logical < (gctPOINTER)((gctSTRING)mdl->addr + mdl->numPages * PAGE_SIZE))
2726             {
2727                 break;
2728             }
2729         }
2730
2731         mdl = mdl->next;
2732     }
2733
2734     if (mdl == gcvNULL)
2735     {
2736         /* Unmap the memory. */
2737         vunmap((void *)((unsigned long)Logical & PAGE_MASK));
2738     }
2739
2740     MEMORY_UNLOCK(Os);
2741
2742     /* Success. */
2743     gcmkFOOTER_NO();
2744     return gcvSTATUS_OK;
2745 }
2746
2747 /*******************************************************************************
2748 **
2749 **  gckOS_CreateMutex
2750 **
2751 **  Create a new mutex.
2752 **
2753 **  INPUT:
2754 **
2755 **      gckOS Os
2756 **          Pointer to an gckOS object.
2757 **
2758 **  OUTPUT:
2759 **
2760 **      gctPOINTER * Mutex
2761 **          Pointer to a variable that will hold a pointer to the mutex.
2762 */
2763 gceSTATUS
2764 gckOS_CreateMutex(
2765     IN gckOS Os,
2766     OUT gctPOINTER * Mutex
2767     )
2768 {
2769     gceSTATUS status;
2770
2771     gcmkHEADER_ARG("Os=0x%X", Os);
2772
2773     /* Validate the arguments. */
2774     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
2775     gcmkVERIFY_ARGUMENT(Mutex != gcvNULL);
2776
2777     /* Allocate the mutex structure. */
2778     gcmkONERROR(gckOS_Allocate(Os, gcmSIZEOF(struct mutex), Mutex));
2779
2780     /* Initialize the mutex. */
2781     mutex_init(*Mutex);
2782
2783     /* Return status. */
2784     gcmkFOOTER_ARG("*Mutex=0x%X", *Mutex);
2785     return gcvSTATUS_OK;
2786
2787 OnError:
2788     /* Return status. */
2789     gcmkFOOTER();
2790     return status;
2791 }
2792
2793 /*******************************************************************************
2794 **
2795 **  gckOS_DeleteMutex
2796 **
2797 **  Delete a mutex.
2798 **
2799 **  INPUT:
2800 **
2801 **      gckOS Os
2802 **          Pointer to an gckOS object.
2803 **
2804 **      gctPOINTER Mutex
2805 **          Pointer to the mute to be deleted.
2806 **
2807 **  OUTPUT:
2808 **
2809 **      Nothing.
2810 */
2811 gceSTATUS
2812 gckOS_DeleteMutex(
2813     IN gckOS Os,
2814     IN gctPOINTER Mutex
2815     )
2816 {
2817     gceSTATUS status;
2818
2819     gcmkHEADER_ARG("Os=0x%X Mutex=0x%X", Os, Mutex);
2820
2821     /* Validate the arguments. */
2822     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
2823     gcmkVERIFY_ARGUMENT(Mutex != gcvNULL);
2824
2825     /* Destroy the mutex. */
2826     mutex_destroy((struct mutex *)Mutex);
2827
2828     /* Free the mutex structure. */
2829     gcmkONERROR(gckOS_Free(Os, Mutex));
2830
2831     gcmkFOOTER_NO();
2832     return gcvSTATUS_OK;
2833
2834 OnError:
2835     /* Return status. */
2836     gcmkFOOTER();
2837     return status;
2838 }
2839
2840 /*******************************************************************************
2841 **
2842 **  gckOS_AcquireMutex
2843 **
2844 **  Acquire a mutex.
2845 **
2846 **  INPUT:
2847 **
2848 **      gckOS Os
2849 **          Pointer to an gckOS object.
2850 **
2851 **      gctPOINTER Mutex
2852 **          Pointer to the mutex to be acquired.
2853 **
2854 **      gctUINT32 Timeout
2855 **          Timeout value specified in milliseconds.
2856 **          Specify the value of gcvINFINITE to keep the thread suspended
2857 **          until the mutex has been acquired.
2858 **
2859 **  OUTPUT:
2860 **
2861 **      Nothing.
2862 */
2863 gceSTATUS
2864 gckOS_AcquireMutex(
2865     IN gckOS Os,
2866     IN gctPOINTER Mutex,
2867     IN gctUINT32 Timeout
2868     )
2869 {
2870     gcmkHEADER_ARG("Os=0x%X Mutex=0x%0x Timeout=%u", Os, Mutex, Timeout);
2871
2872     /* Validate the arguments. */
2873     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
2874     gcmkVERIFY_ARGUMENT(Mutex != gcvNULL);
2875
2876     if (Timeout == gcvINFINITE)
2877     {
2878         /* Lock the mutex. */
2879         mutex_lock(Mutex);
2880
2881         /* Success. */
2882         gcmkFOOTER_NO();
2883         return gcvSTATUS_OK;
2884     }
2885
2886     for (;;)
2887     {
2888         /* Try to acquire the mutex. */
2889         if (mutex_trylock(Mutex))
2890         {
2891             /* Success. */
2892             gcmkFOOTER_NO();
2893             return gcvSTATUS_OK;
2894         }
2895
2896         if (Timeout-- == 0)
2897         {
2898             break;
2899         }
2900
2901         /* Wait for 1 millisecond. */
2902         gcmkVERIFY_OK(gckOS_Delay(Os, 1));
2903     }
2904
2905     /* Timeout. */
2906     gcmkFOOTER_ARG("status=%d", gcvSTATUS_TIMEOUT);
2907     return gcvSTATUS_TIMEOUT;
2908 }
2909
2910 /*******************************************************************************
2911 **
2912 **  gckOS_ReleaseMutex
2913 **
2914 **  Release an acquired mutex.
2915 **
2916 **  INPUT:
2917 **
2918 **      gckOS Os
2919 **          Pointer to an gckOS object.
2920 **
2921 **      gctPOINTER Mutex
2922 **          Pointer to the mutex to be released.
2923 **
2924 **  OUTPUT:
2925 **
2926 **      Nothing.
2927 */
2928 gceSTATUS
2929 gckOS_ReleaseMutex(
2930     IN gckOS Os,
2931     IN gctPOINTER Mutex
2932     )
2933 {
2934     gcmkHEADER_ARG("Os=0x%X Mutex=0x%0x", Os, Mutex);
2935
2936     /* Validate the arguments. */
2937     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
2938     gcmkVERIFY_ARGUMENT(Mutex != gcvNULL);
2939
2940     /* Release the mutex. */
2941     mutex_unlock(Mutex);
2942
2943     /* Success. */
2944     gcmkFOOTER_NO();
2945     return gcvSTATUS_OK;
2946 }
2947
2948 /*******************************************************************************
2949 **
2950 **  gckOS_AtomicExchange
2951 **
2952 **  Atomically exchange a pair of 32-bit values.
2953 **
2954 **  INPUT:
2955 **
2956 **      gckOS Os
2957 **          Pointer to an gckOS object.
2958 **
2959 **      IN OUT gctINT32_PTR Target
2960 **          Pointer to the 32-bit value to exchange.
2961 **
2962 **      IN gctINT32 NewValue
2963 **          Specifies a new value for the 32-bit value pointed to by Target.
2964 **
2965 **      OUT gctINT32_PTR OldValue
2966 **          The old value of the 32-bit value pointed to by Target.
2967 **
2968 **  OUTPUT:
2969 **
2970 **      Nothing.
2971 */
2972 gceSTATUS
2973 gckOS_AtomicExchange(
2974     IN gckOS Os,
2975     IN OUT gctUINT32_PTR Target,
2976     IN gctUINT32 NewValue,
2977     OUT gctUINT32_PTR OldValue
2978     )
2979 {
2980     gcmkHEADER_ARG("Os=0x%X Target=0x%X NewValue=%u", Os, Target, NewValue);
2981
2982     /* Verify the arguments. */
2983     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
2984     gcmkVERIFY_ARGUMENT(OldValue != gcvNULL);
2985
2986     /* Exchange the pair of 32-bit values. */
2987     *OldValue = (gctUINT32) atomic_xchg((atomic_t *) Target, (int) NewValue);
2988
2989     /* Success. */
2990     gcmkFOOTER_ARG("*OldValue=%u", *OldValue);
2991     return gcvSTATUS_OK;
2992 }
2993
2994 /*******************************************************************************
2995 **
2996 **  gckOS_AtomicExchangePtr
2997 **
2998 **  Atomically exchange a pair of pointers.
2999 **
3000 **  INPUT:
3001 **
3002 **      gckOS Os
3003 **          Pointer to an gckOS object.
3004 **
3005 **      IN OUT gctPOINTER * Target
3006 **          Pointer to the 32-bit value to exchange.
3007 **
3008 **      IN gctPOINTER NewValue
3009 **          Specifies a new value for the pointer pointed to by Target.
3010 **
3011 **      OUT gctPOINTER * OldValue
3012 **          The old value of the pointer pointed to by Target.
3013 **
3014 **  OUTPUT:
3015 **
3016 **      Nothing.
3017 */
3018 gceSTATUS
3019 gckOS_AtomicExchangePtr(
3020     IN gckOS Os,
3021     IN OUT gctPOINTER * Target,
3022     IN gctPOINTER NewValue,
3023     OUT gctPOINTER * OldValue
3024     )
3025 {
3026     gcmkHEADER_ARG("Os=0x%X Target=0x%X NewValue=0x%X", Os, Target, NewValue);
3027
3028     /* Verify the arguments. */
3029     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
3030     gcmkVERIFY_ARGUMENT(OldValue != gcvNULL);
3031
3032     /* Exchange the pair of pointers. */
3033     *OldValue = (gctPOINTER)(gctUINTPTR_T) atomic_xchg((atomic_t *) Target, (int)(gctUINTPTR_T) NewValue);
3034
3035     /* Success. */
3036     gcmkFOOTER_ARG("*OldValue=0x%X", *OldValue);
3037     return gcvSTATUS_OK;
3038 }
3039
3040 /*******************************************************************************
3041 **
3042 **  gckOS_AtomicSetMask
3043 **
3044 **  Atomically set mask to Atom
3045 **
3046 **  INPUT:
3047 **      IN OUT gctPOINTER Atom
3048 **          Pointer to the atom to set.
3049 **
3050 **      IN gctUINT32 Mask
3051 **          Mask to set.
3052 **
3053 **  OUTPUT:
3054 **
3055 **      Nothing.
3056 */
3057 gceSTATUS
3058 gckOS_AtomSetMask(
3059     IN gctPOINTER Atom,
3060     IN gctUINT32 Mask
3061     )
3062 {
3063     gctUINT32 oval, nval;
3064
3065     gcmkHEADER_ARG("Atom=0x%0x", Atom);
3066     gcmkVERIFY_ARGUMENT(Atom != gcvNULL);
3067
3068     do
3069     {
3070         oval = atomic_read((atomic_t *) Atom);
3071         nval = oval | Mask;
3072     } while (atomic_cmpxchg((atomic_t *) Atom, oval, nval) != oval);
3073
3074     gcmkFOOTER_NO();
3075     return gcvSTATUS_OK;
3076 }
3077
3078 /*******************************************************************************
3079 **
3080 **  gckOS_AtomClearMask
3081 **
3082 **  Atomically clear mask from Atom
3083 **
3084 **  INPUT:
3085 **      IN OUT gctPOINTER Atom
3086 **          Pointer to the atom to clear.
3087 **
3088 **      IN gctUINT32 Mask
3089 **          Mask to clear.
3090 **
3091 **  OUTPUT:
3092 **
3093 **      Nothing.
3094 */
3095 gceSTATUS
3096 gckOS_AtomClearMask(
3097     IN gctPOINTER Atom,
3098     IN gctUINT32 Mask
3099     )
3100 {
3101     gctUINT32 oval, nval;
3102
3103     gcmkHEADER_ARG("Atom=0x%0x", Atom);
3104     gcmkVERIFY_ARGUMENT(Atom != gcvNULL);
3105
3106     do
3107     {
3108         oval = atomic_read((atomic_t *) Atom);
3109         nval = oval & ~Mask;
3110     } while (atomic_cmpxchg((atomic_t *) Atom, oval, nval) != oval);
3111
3112     gcmkFOOTER_NO();
3113     return gcvSTATUS_OK;
3114 }
3115
3116 /*******************************************************************************
3117 **
3118 **  gckOS_AtomConstruct
3119 **
3120 **  Create an atom.
3121 **
3122 **  INPUT:
3123 **
3124 **      gckOS Os
3125 **          Pointer to a gckOS object.
3126 **
3127 **  OUTPUT:
3128 **
3129 **      gctPOINTER * Atom
3130 **          Pointer to a variable receiving the constructed atom.
3131 */
3132 gceSTATUS
3133 gckOS_AtomConstruct(
3134     IN gckOS Os,
3135     OUT gctPOINTER * Atom
3136     )
3137 {
3138     gceSTATUS status;
3139
3140     gcmkHEADER_ARG("Os=0x%X", Os);
3141
3142     /* Verify the arguments. */
3143     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
3144     gcmkVERIFY_ARGUMENT(Atom != gcvNULL);
3145
3146     /* Allocate the atom. */
3147     gcmkONERROR(gckOS_Allocate(Os, gcmSIZEOF(atomic_t), Atom));
3148
3149     /* Initialize the atom. */
3150     atomic_set((atomic_t *) *Atom, 0);
3151
3152     /* Success. */
3153     gcmkFOOTER_ARG("*Atom=0x%X", *Atom);
3154     return gcvSTATUS_OK;
3155
3156 OnError:
3157     /* Return the status. */
3158     gcmkFOOTER();
3159     return status;
3160 }
3161
3162 /*******************************************************************************
3163 **
3164 **  gckOS_AtomDestroy
3165 **
3166 **  Destroy an atom.
3167 **
3168 **  INPUT:
3169 **
3170 **      gckOS Os
3171 **          Pointer to a gckOS object.
3172 **
3173 **      gctPOINTER Atom
3174 **          Pointer to the atom to destroy.
3175 **
3176 **  OUTPUT:
3177 **
3178 **      Nothing.
3179 */
3180 gceSTATUS
3181 gckOS_AtomDestroy(
3182     IN gckOS Os,
3183     OUT gctPOINTER Atom
3184     )
3185 {
3186     gceSTATUS status;
3187
3188     gcmkHEADER_ARG("Os=0x%X Atom=0x%0x", Os, Atom);
3189
3190     /* Verify the arguments. */
3191     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
3192     gcmkVERIFY_ARGUMENT(Atom != gcvNULL);
3193
3194     /* Free the atom. */
3195     gcmkONERROR(gcmkOS_SAFE_FREE(Os, Atom));
3196
3197     /* Success. */
3198     gcmkFOOTER_NO();
3199     return gcvSTATUS_OK;
3200
3201 OnError:
3202     /* Return the status. */
3203     gcmkFOOTER();
3204     return status;
3205 }
3206
3207 /*******************************************************************************
3208 **
3209 **  gckOS_AtomGet
3210 **
3211 **  Get the 32-bit value protected by an atom.
3212 **
3213 **  INPUT:
3214 **
3215 **      gckOS Os
3216 **          Pointer to a gckOS object.
3217 **
3218 **      gctPOINTER Atom
3219 **          Pointer to the atom.
3220 **
3221 **  OUTPUT:
3222 **
3223 **      gctINT32_PTR Value
3224 **          Pointer to a variable the receives the value of the atom.
3225 */
3226 gceSTATUS
3227 gckOS_AtomGet(
3228     IN gckOS Os,
3229     IN gctPOINTER Atom,
3230     OUT gctINT32_PTR Value
3231     )
3232 {
3233     gcmkHEADER_ARG("Os=0x%X Atom=0x%0x", Os, Atom);
3234
3235     /* Verify the arguments. */
3236     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
3237     gcmkVERIFY_ARGUMENT(Atom != gcvNULL);
3238
3239     /* Return the current value of atom. */
3240     *Value = atomic_read((atomic_t *) Atom);
3241
3242     /* Success. */
3243     gcmkFOOTER_ARG("*Value=%d", *Value);
3244     return gcvSTATUS_OK;
3245 }
3246
3247 /*******************************************************************************
3248 **
3249 **  gckOS_AtomSet
3250 **
3251 **  Set the 32-bit value protected by an atom.
3252 **
3253 **  INPUT:
3254 **
3255 **      gckOS Os
3256 **          Pointer to a gckOS object.
3257 **
3258 **      gctPOINTER Atom
3259 **          Pointer to the atom.
3260 **
3261 **      gctINT32 Value
3262 **          The value of the atom.
3263 **
3264 **  OUTPUT:
3265 **
3266 **      Nothing.
3267 */
3268 gceSTATUS
3269 gckOS_AtomSet(
3270     IN gckOS Os,
3271     IN gctPOINTER Atom,
3272     IN gctINT32 Value
3273     )
3274 {
3275     gcmkHEADER_ARG("Os=0x%X Atom=0x%0x Value=%d", Os, Atom);
3276
3277     /* Verify the arguments. */
3278     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
3279     gcmkVERIFY_ARGUMENT(Atom != gcvNULL);
3280
3281     /* Set the current value of atom. */
3282     atomic_set((atomic_t *) Atom, Value);
3283
3284     /* Success. */
3285     gcmkFOOTER_NO();
3286     return gcvSTATUS_OK;
3287 }
3288
3289 /*******************************************************************************
3290 **
3291 **  gckOS_AtomIncrement
3292 **
3293 **  Atomically increment the 32-bit integer value inside an atom.
3294 **
3295 **  INPUT:
3296 **
3297 **      gckOS Os
3298 **          Pointer to a gckOS object.
3299 **
3300 **      gctPOINTER Atom
3301 **          Pointer to the atom.
3302 **
3303 **  OUTPUT:
3304 **
3305 **      gctINT32_PTR Value
3306 **          Pointer to a variable that receives the original value of the atom.
3307 */
3308 gceSTATUS
3309 gckOS_AtomIncrement(
3310     IN gckOS Os,
3311     IN gctPOINTER Atom,
3312     OUT gctINT32_PTR Value
3313     )
3314 {
3315     gcmkHEADER_ARG("Os=0x%X Atom=0x%0x", Os, Atom);
3316
3317     /* Verify the arguments. */
3318     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
3319     gcmkVERIFY_ARGUMENT(Atom != gcvNULL);
3320
3321     /* Increment the atom. */
3322     *Value = atomic_inc_return((atomic_t *) Atom) - 1;
3323
3324     /* Success. */
3325     gcmkFOOTER_ARG("*Value=%d", *Value);
3326     return gcvSTATUS_OK;
3327 }
3328
3329 /*******************************************************************************
3330 **
3331 **  gckOS_AtomDecrement
3332 **
3333 **  Atomically decrement the 32-bit integer value inside an atom.
3334 **
3335 **  INPUT:
3336 **
3337 **      gckOS Os
3338 **          Pointer to a gckOS object.
3339 **
3340 **      gctPOINTER Atom
3341 **          Pointer to the atom.
3342 **
3343 **  OUTPUT:
3344 **
3345 **      gctINT32_PTR Value
3346 **          Pointer to a variable that receives the original value of the atom.
3347 */
3348 gceSTATUS
3349 gckOS_AtomDecrement(
3350     IN gckOS Os,
3351     IN gctPOINTER Atom,
3352     OUT gctINT32_PTR Value
3353     )
3354 {
3355     gcmkHEADER_ARG("Os=0x%X Atom=0x%0x", Os, Atom);
3356
3357     /* Verify the arguments. */
3358     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
3359     gcmkVERIFY_ARGUMENT(Atom != gcvNULL);
3360
3361     /* Decrement the atom. */
3362     *Value = atomic_dec_return((atomic_t *) Atom) + 1;
3363
3364     /* Success. */
3365     gcmkFOOTER_ARG("*Value=%d", *Value);
3366     return gcvSTATUS_OK;
3367 }
3368
3369 /*******************************************************************************
3370 **
3371 **  gckOS_Delay
3372 **
3373 **  Delay execution of the current thread for a number of milliseconds.
3374 **
3375 **  INPUT:
3376 **
3377 **      gckOS Os
3378 **          Pointer to an gckOS object.
3379 **
3380 **      gctUINT32 Delay
3381 **          Delay to sleep, specified in milliseconds.
3382 **
3383 **  OUTPUT:
3384 **
3385 **      Nothing.
3386 */
3387 gceSTATUS
3388 gckOS_Delay(
3389     IN gckOS Os,
3390     IN gctUINT32 Delay
3391     )
3392 {
3393     gcmkHEADER_ARG("Os=0x%X Delay=%u", Os, Delay);
3394
3395     if (Delay > 0)
3396     {
3397 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28)
3398         ktime_t delay = ktime_set((Delay / MSEC_PER_SEC), (Delay % MSEC_PER_SEC) * NSEC_PER_MSEC);
3399         __set_current_state(TASK_UNINTERRUPTIBLE);
3400         schedule_hrtimeout(&delay, HRTIMER_MODE_REL);
3401 #else
3402         msleep(Delay);
3403 #endif
3404     }
3405
3406     /* Success. */
3407     gcmkFOOTER_NO();
3408     return gcvSTATUS_OK;
3409 }
3410
3411 /*******************************************************************************
3412 **
3413 **  gckOS_GetTicks
3414 **
3415 **  Get the number of milliseconds since the system started.
3416 **
3417 **  INPUT:
3418 **
3419 **  OUTPUT:
3420 **
3421 **      gctUINT32_PTR Time
3422 **          Pointer to a variable to get time.
3423 **
3424 */
3425 gceSTATUS
3426 gckOS_GetTicks(
3427     OUT gctUINT32_PTR Time
3428     )
3429 {
3430      gcmkHEADER();
3431
3432     *Time = jiffies_to_msecs(jiffies);
3433
3434     gcmkFOOTER_NO();
3435     return gcvSTATUS_OK;
3436 }
3437
3438 /*******************************************************************************
3439 **
3440 **  gckOS_TicksAfter
3441 **
3442 **  Compare time values got from gckOS_GetTicks.
3443 **
3444 **  INPUT:
3445 **      gctUINT32 Time1
3446 **          First time value to be compared.
3447 **
3448 **      gctUINT32 Time2
3449 **          Second time value to be compared.
3450 **
3451 **  OUTPUT:
3452 **
3453 **      gctBOOL_PTR IsAfter
3454 **          Pointer to a variable to result.
3455 **
3456 */
3457 gceSTATUS
3458 gckOS_TicksAfter(
3459     IN gctUINT32 Time1,
3460     IN gctUINT32 Time2,
3461     OUT gctBOOL_PTR IsAfter
3462     )
3463 {
3464     gcmkHEADER();
3465
3466     *IsAfter = time_after((unsigned long)Time1, (unsigned long)Time2);
3467
3468     gcmkFOOTER_NO();
3469     return gcvSTATUS_OK;
3470 }
3471
3472 /*******************************************************************************
3473 **
3474 **  gckOS_GetTime
3475 **
3476 **  Get the number of microseconds since the system started.
3477 **
3478 **  INPUT:
3479 **
3480 **  OUTPUT:
3481 **
3482 **      gctUINT64_PTR Time
3483 **          Pointer to a variable to get time.
3484 **
3485 */
3486 gceSTATUS
3487 gckOS_GetTime(
3488     OUT gctUINT64_PTR Time
3489     )
3490 {
3491     struct timeval tv;
3492     gcmkHEADER();
3493
3494     /* Return the time of day in microseconds. */
3495     do_gettimeofday(&tv);
3496     *Time = (tv.tv_sec * 1000000ULL) + tv.tv_usec;
3497
3498     gcmkFOOTER_NO();
3499     return gcvSTATUS_OK;
3500 }
3501
3502 /*******************************************************************************
3503 **
3504 **  gckOS_MemoryBarrier
3505 **
3506 **  Make sure the CPU has executed everything up to this point and the data got
3507 **  written to the specified pointer.
3508 **
3509 **  INPUT:
3510 **
3511 **      gckOS Os
3512 **          Pointer to an gckOS object.
3513 **
3514 **      gctPOINTER Address
3515 **          Address of memory that needs to be barriered.
3516 **
3517 **  OUTPUT:
3518 **
3519 **      Nothing.
3520 */
3521 gceSTATUS
3522 gckOS_MemoryBarrier(
3523     IN gckOS Os,
3524     IN gctPOINTER Address
3525     )
3526 {
3527     gcmkHEADER_ARG("Os=0x%X Address=0x%X", Os, Address);
3528
3529     /* Verify the arguments. */
3530     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
3531
3532 #if gcdNONPAGED_MEMORY_BUFFERABLE \
3533     && defined (CONFIG_ARM) \
3534     && (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,34))
3535     /* drain write buffer */
3536     dsb();
3537
3538     /* drain outer cache's write buffer? */
3539 #else
3540     mb();
3541 #endif
3542
3543     /* Success. */
3544     gcmkFOOTER_NO();
3545     return gcvSTATUS_OK;
3546 }
3547
3548 /*******************************************************************************
3549 **
3550 **  gckOS_AllocatePagedMemory
3551 **
3552 **  Allocate memory from the paged pool.
3553 **
3554 **  INPUT:
3555 **
3556 **      gckOS Os
3557 **          Pointer to an gckOS object.
3558 **
3559 **      gctSIZE_T Bytes
3560 **          Number of bytes to allocate.
3561 **
3562 **  OUTPUT:
3563 **
3564 **      gctPHYS_ADDR * Physical
3565 **          Pointer to a variable that receives the physical address of the
3566 **          memory allocation.
3567 */
3568 gceSTATUS
3569 gckOS_AllocatePagedMemory(
3570     IN gckOS Os,
3571     IN gctSIZE_T Bytes,
3572     OUT gctPHYS_ADDR * Physical
3573     )
3574 {
3575     gceSTATUS status;
3576
3577     gcmkHEADER_ARG("Os=0x%X Bytes=%lu", Os, Bytes);
3578
3579     /* Verify the arguments. */
3580     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
3581     gcmkVERIFY_ARGUMENT(Bytes > 0);
3582     gcmkVERIFY_ARGUMENT(Physical != gcvNULL);
3583
3584     /* Allocate the memory. */
3585     gcmkONERROR(gckOS_AllocatePagedMemoryEx(Os, gcvALLOC_FLAG_NONE, Bytes, gcvNULL, Physical));
3586
3587     /* Success. */
3588     gcmkFOOTER_ARG("*Physical=0x%X", *Physical);
3589     return gcvSTATUS_OK;
3590
3591 OnError:
3592     /* Return the status. */
3593     gcmkFOOTER();
3594     return status;
3595 }
3596
3597 /*******************************************************************************
3598 **
3599 **  gckOS_AllocatePagedMemoryEx
3600 **
3601 **  Allocate memory from the paged pool.
3602 **
3603 **  INPUT:
3604 **
3605 **      gckOS Os
3606 **          Pointer to an gckOS object.
3607 **
3608 **      gctUINT32 Flag
3609 **          Allocation attribute.
3610 **
3611 **      gctSIZE_T Bytes
3612 **          Number of bytes to allocate.
3613 **
3614 **  OUTPUT:
3615 **
3616 **      gctUINT32 * Gid
3617 **          Save the global ID for the piece of allocated memory.
3618 **
3619 **      gctPHYS_ADDR * Physical
3620 **          Pointer to a variable that receives the physical address of the
3621 **          memory allocation.
3622 */
3623 gceSTATUS
3624 gckOS_AllocatePagedMemoryEx(
3625     IN gckOS Os,
3626     IN gctUINT32 Flag,
3627     IN gctSIZE_T Bytes,
3628     OUT gctUINT32 * Gid,
3629     OUT gctPHYS_ADDR * Physical
3630     )
3631 {
3632     gctINT numPages;
3633     PLINUX_MDL mdl = gcvNULL;
3634     gctSIZE_T bytes;
3635     gceSTATUS status = gcvSTATUS_OUT_OF_MEMORY;
3636     gckALLOCATOR allocator;
3637
3638     gcmkHEADER_ARG("Os=0x%X Flag=%x Bytes=%lu", Os, Flag, Bytes);
3639
3640     /* Verify the arguments. */
3641     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
3642     gcmkVERIFY_ARGUMENT(Bytes > 0);
3643     gcmkVERIFY_ARGUMENT(Physical != gcvNULL);
3644
3645     bytes = gcmALIGN(Bytes, PAGE_SIZE);
3646
3647     numPages = GetPageCount(bytes, 0);
3648
3649     mdl = _CreateMdl();
3650     if (mdl == gcvNULL)
3651     {
3652         gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
3653     }
3654
3655     /* Walk all allocators. */
3656     list_for_each_entry(allocator, &Os->allocatorList, head)
3657     {
3658         gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_OS,
3659                        "%s(%d) flag = %x allocator->capability = %x",
3660                         __FUNCTION__, __LINE__, Flag, allocator->capability);
3661
3662         if ((Flag & allocator->capability) != Flag)
3663         {
3664             continue;
3665         }
3666
3667         status = allocator->ops->Alloc(allocator, mdl, numPages, Flag);
3668
3669         if (gcmIS_SUCCESS(status))
3670         {
3671             mdl->allocator = allocator;
3672             break;
3673         }
3674     }
3675
3676     /* Check status. */
3677     gcmkONERROR(status);
3678
3679     mdl->dmaHandle  = 0;
3680     mdl->addr       = 0;
3681     mdl->numPages   = numPages;
3682     mdl->pagedMem   = 1;
3683     mdl->contiguous = Flag & gcvALLOC_FLAG_CONTIGUOUS;
3684
3685     /* Return physical address. */
3686     *Physical = (gctPHYS_ADDR) mdl;
3687
3688     if (Gid != gcvNULL)
3689     {
3690         *Gid = mdl->gid;
3691     }
3692
3693     MEMORY_LOCK(Os);
3694
3695     /*
3696      * Add this to a global list.
3697      * Will be used by get physical address
3698      * and mapuser pointer functions.
3699      */
3700     if (!Os->mdlHead)
3701     {
3702         /* Initialize the queue. */
3703         Os->mdlHead = Os->mdlTail = mdl;
3704     }
3705     else
3706     {
3707         /* Add to tail. */
3708         mdl->prev           = Os->mdlTail;
3709         Os->mdlTail->next   = mdl;
3710         Os->mdlTail         = mdl;
3711     }
3712
3713     MEMORY_UNLOCK(Os);
3714
3715     /* Success. */
3716     gcmkFOOTER_ARG("*Physical=0x%X", *Physical);
3717     return gcvSTATUS_OK;
3718
3719 OnError:
3720     if (mdl != gcvNULL)
3721     {
3722         /* Free the memory. */
3723         _DestroyMdl(mdl);
3724     }
3725     *Physical = gcvNULL;
3726
3727     /* Return the status. */
3728     gcmkFOOTER_ARG("Os=0x%X Flag=%x Bytes=%lu", Os, Flag, Bytes);
3729     return status;
3730 }
3731
3732 /*******************************************************************************
3733 **
3734 **  gckOS_FreePagedMemory
3735 **
3736 **  Free memory allocated from the paged pool.
3737 **
3738 **  INPUT:
3739 **
3740 **      gckOS Os
3741 **          Pointer to an gckOS object.
3742 **
3743 **      gctPHYS_ADDR Physical
3744 **          Physical address of the allocation.
3745 **
3746 **      gctSIZE_T Bytes
3747 **          Number of bytes of the allocation.
3748 **
3749 **  OUTPUT:
3750 **
3751 **      Nothing.
3752 */
3753 gceSTATUS
3754 gckOS_FreePagedMemory(
3755     IN gckOS Os,
3756     IN gctPHYS_ADDR Physical,
3757     IN gctSIZE_T Bytes
3758     )
3759 {
3760     PLINUX_MDL mdl = (PLINUX_MDL) Physical;
3761     gckALLOCATOR allocator = (gckALLOCATOR)mdl->allocator;
3762
3763     gcmkHEADER_ARG("Os=0x%X Physical=0x%X Bytes=%lu", Os, Physical, Bytes);
3764
3765     /* Verify the arguments. */
3766     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
3767     gcmkVERIFY_ARGUMENT(Physical != gcvNULL);
3768     gcmkVERIFY_ARGUMENT(Bytes > 0);
3769
3770     MEMORY_LOCK(Os);
3771
3772     /* Remove the node from global list. */
3773     if (mdl == Os->mdlHead)
3774     {
3775         if ((Os->mdlHead = mdl->next) == gcvNULL)
3776         {
3777             Os->mdlTail = gcvNULL;
3778         }
3779     }
3780     else
3781     {
3782         mdl->prev->next = mdl->next;
3783
3784         if (mdl == Os->mdlTail)
3785         {
3786             Os->mdlTail = mdl->prev;
3787         }
3788         else
3789         {
3790             mdl->next->prev = mdl->prev;
3791         }
3792     }
3793
3794     MEMORY_UNLOCK(Os);
3795
3796     allocator->ops->Free(allocator, mdl);
3797
3798     /* Free the structure... */
3799     gcmkVERIFY_OK(_DestroyMdl(mdl));
3800
3801     /* Success. */
3802     gcmkFOOTER_NO();
3803     return gcvSTATUS_OK;
3804 }
3805
3806 /*******************************************************************************
3807 **
3808 **  gckOS_LockPages
3809 **
3810 **  Lock memory allocated from the paged pool.
3811 **
3812 **  INPUT:
3813 **
3814 **      gckOS Os
3815 **          Pointer to an gckOS object.
3816 **
3817 **      gctPHYS_ADDR Physical
3818 **          Physical address of the allocation.
3819 **
3820 **      gctSIZE_T Bytes
3821 **          Number of bytes of the allocation.
3822 **
3823 **      gctBOOL Cacheable
3824 **          Cache mode of mapping.
3825 **
3826 **  OUTPUT:
3827 **
3828 **      gctPOINTER * Logical
3829 **          Pointer to a variable that receives the address of the mapped
3830 **          memory.
3831 **
3832 **      gctSIZE_T * PageCount
3833 **          Pointer to a variable that receives the number of pages required for
3834 **          the page table according to the GPU page size.
3835 */
3836 gceSTATUS
3837 gckOS_LockPages(
3838     IN gckOS Os,
3839     IN gctPHYS_ADDR Physical,
3840     IN gctSIZE_T Bytes,
3841     IN gctBOOL Cacheable,
3842     OUT gctPOINTER * Logical,
3843     OUT gctSIZE_T * PageCount
3844     )
3845 {
3846     gceSTATUS       status;
3847     PLINUX_MDL      mdl;
3848     PLINUX_MDL_MAP  mdlMap;
3849     gckALLOCATOR    allocator;
3850
3851     gcmkHEADER_ARG("Os=0x%X Physical=0x%X Bytes=%lu", Os, Physical, Logical);
3852
3853     /* Verify the arguments. */
3854     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
3855     gcmkVERIFY_ARGUMENT(Physical != gcvNULL);
3856     gcmkVERIFY_ARGUMENT(Logical != gcvNULL);
3857     gcmkVERIFY_ARGUMENT(PageCount != gcvNULL);
3858
3859     mdl = (PLINUX_MDL) Physical;
3860     allocator = mdl->allocator;
3861
3862     MEMORY_LOCK(Os);
3863
3864     mdlMap = FindMdlMap(mdl, _GetProcessID());
3865
3866     if (mdlMap == gcvNULL)
3867     {
3868         mdlMap = _CreateMdlMap(mdl, _GetProcessID());
3869
3870         if (mdlMap == gcvNULL)
3871         {
3872             MEMORY_UNLOCK(Os);
3873
3874             gcmkFOOTER_ARG("*status=%d", gcvSTATUS_OUT_OF_MEMORY);
3875             return gcvSTATUS_OUT_OF_MEMORY;
3876         }
3877     }
3878
3879     if (mdlMap->vmaAddr == gcvNULL)
3880     {
3881         status = allocator->ops->MapUser(allocator, mdl, mdlMap, Cacheable);
3882
3883         if (gcmIS_ERROR(status))
3884         {
3885             MEMORY_UNLOCK(Os);
3886
3887             gcmkFOOTER_ARG("*status=%d", status);
3888             return status;
3889         }
3890     }
3891
3892     mdlMap->count++;
3893
3894     /* Convert pointer to MDL. */
3895     *Logical = mdlMap->vmaAddr;
3896
3897     /* Return the page number according to the GPU page size. */
3898     gcmkASSERT((PAGE_SIZE % 4096) == 0);
3899     gcmkASSERT((PAGE_SIZE / 4096) >= 1);
3900
3901     *PageCount = mdl->numPages * (PAGE_SIZE / 4096);
3902
3903     MEMORY_UNLOCK(Os);
3904
3905     gcmkVERIFY_OK(gckOS_CacheFlush(
3906         Os,
3907         _GetProcessID(),
3908         Physical,
3909         gcvINVALID_ADDRESS,
3910         (gctPOINTER)mdlMap->vmaAddr,
3911         mdl->numPages * PAGE_SIZE
3912         ));
3913
3914     /* Success. */
3915     gcmkFOOTER_ARG("*Logical=0x%X *PageCount=%lu", *Logical, *PageCount);
3916     return gcvSTATUS_OK;
3917 }
3918
3919 /*******************************************************************************
3920 **
3921 **  gckOS_MapPages
3922 **
3923 **  Map paged memory into a page table.
3924 **
3925 **  INPUT:
3926 **
3927 **      gckOS Os
3928 **          Pointer to an gckOS object.
3929 **
3930 **      gctPHYS_ADDR Physical
3931 **          Physical address of the allocation.
3932 **
3933 **      gctSIZE_T PageCount
3934 **          Number of pages required for the physical address.
3935 **
3936 **      gctPOINTER PageTable
3937 **          Pointer to the page table to fill in.
3938 **
3939 **  OUTPUT:
3940 **
3941 **      Nothing.
3942 */
3943 gceSTATUS
3944 gckOS_MapPages(
3945     IN gckOS Os,
3946     IN gctPHYS_ADDR Physical,
3947     IN gctSIZE_T PageCount,
3948     IN gctPOINTER PageTable
3949     )
3950 {
3951     return gckOS_MapPagesEx(Os,
3952                             gcvCORE_MAJOR,
3953                             Physical,
3954                             PageCount,
3955                             0,
3956                             PageTable);
3957 }
3958
3959 gceSTATUS
3960 gckOS_MapPagesEx(
3961     IN gckOS Os,
3962     IN gceCORE Core,
3963     IN gctPHYS_ADDR Physical,
3964     IN gctSIZE_T PageCount,
3965     IN gctUINT32 Address,
3966     IN gctPOINTER PageTable
3967     )
3968 {
3969     gceSTATUS status = gcvSTATUS_OK;
3970     PLINUX_MDL  mdl;
3971     gctUINT32*  table;
3972     gctUINT32   offset;
3973 #if gcdNONPAGED_MEMORY_CACHEABLE
3974     gckMMU      mmu;
3975     PLINUX_MDL  mmuMdl;
3976     gctUINT32   bytes;
3977     gctPHYS_ADDR pageTablePhysical;
3978 #endif
3979
3980 #if gcdPROCESS_ADDRESS_SPACE
3981     gckKERNEL kernel = Os->device->kernels[Core];
3982     gckMMU      mmu;
3983 #endif
3984     gckALLOCATOR allocator;
3985
3986     gcmkHEADER_ARG("Os=0x%X Core=%d Physical=0x%X PageCount=%u PageTable=0x%X",
3987                    Os, Core, Physical, PageCount, PageTable);
3988
3989     /* Verify the arguments. */
3990     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
3991     gcmkVERIFY_ARGUMENT(Physical != gcvNULL);
3992     gcmkVERIFY_ARGUMENT(PageCount > 0);
3993     gcmkVERIFY_ARGUMENT(PageTable != gcvNULL);
3994
3995     /* Convert pointer to MDL. */
3996     mdl = (PLINUX_MDL)Physical;
3997
3998     allocator = mdl->allocator;
3999
4000     gcmkTRACE_ZONE(
4001         gcvLEVEL_INFO, gcvZONE_OS,
4002         "%s(%d): Physical->0x%X PageCount->0x%X PagedMemory->?%d",
4003         __FUNCTION__, __LINE__,
4004         (gctUINT32)(gctUINTPTR_T)Physical,
4005         (gctUINT32)(gctUINTPTR_T)PageCount,
4006         mdl->pagedMem
4007         );
4008
4009 #if gcdPROCESS_ADDRESS_SPACE
4010     gcmkONERROR(gckKERNEL_GetProcessMMU(kernel, &mmu));
4011 #endif
4012
4013     table = (gctUINT32 *)PageTable;
4014 #if gcdNONPAGED_MEMORY_CACHEABLE
4015     mmu = Os->device->kernels[Core]->mmu;
4016     bytes = PageCount * sizeof(*table);
4017     mmuMdl = (PLINUX_MDL)mmu->pageTablePhysical;
4018 #endif
4019
4020      /* Get all the physical addresses and store them in the page table. */
4021
4022     offset = 0;
4023     PageCount = PageCount / (PAGE_SIZE / 4096);
4024
4025     /* Try to get the user pages so DMA can happen. */
4026     while (PageCount-- > 0)
4027     {
4028         gctUINT i;
4029         gctUINT32 phys = ~0;
4030
4031         if (mdl->pagedMem && !mdl->contiguous)
4032         {
4033             allocator->ops->Physical(allocator, mdl, offset, &phys);
4034         }
4035         else
4036         {
4037             if (!mdl->pagedMem)
4038             {
4039                 gcmkTRACE_ZONE(
4040                     gcvLEVEL_INFO, gcvZONE_OS,
4041                     "%s(%d): we should not get this call for Non Paged Memory!",
4042                     __FUNCTION__, __LINE__
4043                     );
4044             }
4045
4046             phys = page_to_phys(nth_page(mdl->u.contiguousPages, offset));
4047         }
4048
4049         gcmkVERIFY_OK(gckOS_CPUPhysicalToGPUPhysical(Os, phys, &phys));
4050
4051 #ifdef CONFIG_IOMMU_SUPPORT
4052         if (Os->iommu)
4053         {
4054             gcmkTRACE_ZONE(
4055                 gcvLEVEL_INFO, gcvZONE_OS,
4056                 "%s(%d): Setup mapping in IOMMU %x => %x",
4057                 __FUNCTION__, __LINE__,
4058                 Address + (offset * PAGE_SIZE), phys
4059                 );
4060
4061             /* When use IOMMU, GPU use system PAGE_SIZE. */
4062             gcmkONERROR(gckIOMMU_Map(
4063                 Os->iommu, Address + (offset * PAGE_SIZE), phys, PAGE_SIZE));
4064         }
4065         else
4066 #endif
4067         {
4068
4069 #if gcdENABLE_VG
4070             if (Core == gcvCORE_VG)
4071             {
4072                 for (i = 0; i < (PAGE_SIZE / 4096); i++)
4073                 {
4074                     gcmkONERROR(
4075                         gckVGMMU_SetPage(Os->device->kernels[Core]->vg->mmu,
4076                             phys + (i * 4096),
4077                             table++));
4078                 }
4079             }
4080             else
4081 #endif
4082             {
4083                 for (i = 0; i < (PAGE_SIZE / 4096); i++)
4084                 {
4085 #if gcdPROCESS_ADDRESS_SPACE
4086                     gctUINT32_PTR pageTableEntry;
4087                     gckMMU_GetPageEntry(mmu, Address + (offset * 4096), &pageTableEntry);
4088                     gcmkONERROR(
4089                         gckMMU_SetPage(mmu,
4090                             phys + (i * 4096),
4091                             pageTableEntry));
4092 #else
4093                     gcmkONERROR(
4094                         gckMMU_SetPage(Os->device->kernels[Core]->mmu,
4095                             phys + (i * 4096),
4096                             table++));
4097 #endif
4098                 }
4099             }
4100         }
4101
4102         offset += 1;
4103     }
4104
4105 #if gcdNONPAGED_MEMORY_CACHEABLE
4106     /* Get physical address of pageTable */
4107     pageTablePhysical = (gctPHYS_ADDR)(mmuMdl->dmaHandle +
4108                         ((gctUINT32 *)PageTable - mmu->pageTableLogical));
4109
4110     /* Flush the mmu page table cache. */
4111     gcmkONERROR(gckOS_CacheClean(
4112         Os,
4113         _GetProcessID(),
4114         gcvNULL,
4115         pageTablePhysical,
4116         PageTable,
4117         bytes
4118         ));
4119 #endif
4120
4121 OnError:
4122
4123     /* Return the status. */
4124     gcmkFOOTER();
4125     return status;
4126 }
4127
4128 gceSTATUS
4129 gckOS_UnmapPages(
4130     IN gckOS Os,
4131     IN gctSIZE_T PageCount,
4132     IN gctUINT32 Address
4133     )
4134 {
4135 #ifdef CONFIG_IOMMU_SUPPORT
4136     if (Os->iommu)
4137     {
4138         gcmkVERIFY_OK(gckIOMMU_Unmap(
4139             Os->iommu, Address, PageCount * PAGE_SIZE));
4140     }
4141 #endif
4142
4143     return gcvSTATUS_OK;
4144 }
4145
4146 /*******************************************************************************
4147 **
4148 **  gckOS_UnlockPages
4149 **
4150 **  Unlock memory allocated from the paged pool.
4151 **
4152 **  INPUT:
4153 **
4154 **      gckOS Os
4155 **          Pointer to an gckOS object.
4156 **
4157 **      gctPHYS_ADDR Physical
4158 **          Physical address of the allocation.
4159 **
4160 **      gctSIZE_T Bytes
4161 **          Number of bytes of the allocation.
4162 **
4163 **      gctPOINTER Logical
4164 **          Address of the mapped memory.
4165 **
4166 **  OUTPUT:
4167 **
4168 **      Nothing.
4169 */
4170 gceSTATUS
4171 gckOS_UnlockPages(
4172     IN gckOS Os,
4173     IN gctPHYS_ADDR Physical,
4174     IN gctSIZE_T Bytes,
4175     IN gctPOINTER Logical
4176     )
4177 {
4178     PLINUX_MDL_MAP          mdlMap;
4179     PLINUX_MDL              mdl = (PLINUX_MDL)Physical;
4180     gckALLOCATOR            allocator = mdl->allocator;
4181
4182     gcmkHEADER_ARG("Os=0x%X Physical=0x%X Bytes=%u Logical=0x%X",
4183                    Os, Physical, Bytes, Logical);
4184
4185     /* Verify the arguments. */
4186     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
4187     gcmkVERIFY_ARGUMENT(Physical != gcvNULL);
4188     gcmkVERIFY_ARGUMENT(Logical != gcvNULL);
4189
4190     MEMORY_LOCK(Os);
4191
4192     mdlMap = mdl->maps;
4193
4194     while (mdlMap != gcvNULL)
4195     {
4196         if ((mdlMap->vmaAddr != gcvNULL) && (_GetProcessID() == mdlMap->pid))
4197         {
4198             if (--mdlMap->count == 0)
4199             {
4200                 allocator->ops->UnmapUser(
4201                     allocator,
4202                     mdlMap->vmaAddr,
4203                     mdl->numPages * PAGE_SIZE);
4204
4205                 mdlMap->vmaAddr = gcvNULL;
4206             }
4207         }
4208
4209         mdlMap = mdlMap->next;
4210     }
4211
4212     MEMORY_UNLOCK(Os);
4213
4214     /* Success. */
4215     gcmkFOOTER_NO();
4216     return gcvSTATUS_OK;
4217 }
4218
4219
4220 /*******************************************************************************
4221 **
4222 **  gckOS_AllocateContiguous
4223 **
4224 **  Allocate memory from the contiguous pool.
4225 **
4226 **  INPUT:
4227 **
4228 **      gckOS Os
4229 **          Pointer to an gckOS object.
4230 **
4231 **      gctBOOL InUserSpace
4232 **          gcvTRUE if the pages need to be mapped into user space.
4233 **
4234 **      gctSIZE_T * Bytes
4235 **          Pointer to the number of bytes to allocate.
4236 **
4237 **  OUTPUT:
4238 **
4239 **      gctSIZE_T * Bytes
4240 **          Pointer to a variable that receives the number of bytes allocated.
4241 **
4242 **      gctPHYS_ADDR * Physical
4243 **          Pointer to a variable that receives the physical address of the
4244 **          memory allocation.
4245 **
4246 **      gctPOINTER * Logical
4247 **          Pointer to a variable that receives the logical address of the
4248 **          memory allocation.
4249 */
4250 gceSTATUS
4251 gckOS_AllocateContiguous(
4252     IN gckOS Os,
4253     IN gctBOOL InUserSpace,
4254     IN OUT gctSIZE_T * Bytes,
4255     OUT gctPHYS_ADDR * Physical,
4256     OUT gctPOINTER * Logical
4257     )
4258 {
4259     gceSTATUS status;
4260
4261     gcmkHEADER_ARG("Os=0x%X InUserSpace=%d *Bytes=%lu",
4262                    Os, InUserSpace, gcmOPT_VALUE(Bytes));
4263
4264     /* Verify the arguments. */
4265     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
4266     gcmkVERIFY_ARGUMENT(Bytes != gcvNULL);
4267     gcmkVERIFY_ARGUMENT(*Bytes > 0);
4268     gcmkVERIFY_ARGUMENT(Physical != gcvNULL);
4269     gcmkVERIFY_ARGUMENT(Logical != gcvNULL);
4270
4271     /* Same as non-paged memory for now. */
4272     gcmkONERROR(gckOS_AllocateNonPagedMemory(Os,
4273                                              InUserSpace,
4274                                              Bytes,
4275                                              Physical,
4276                                              Logical));
4277
4278     /* Success. */
4279     gcmkFOOTER_ARG("*Bytes=%lu *Physical=0x%X *Logical=0x%X",
4280                    *Bytes, *Physical, *Logical);
4281     return gcvSTATUS_OK;
4282
4283 OnError:
4284     /* Return the status. */
4285     gcmkFOOTER();
4286     return status;
4287 }
4288
4289 /*******************************************************************************
4290 **
4291 **  gckOS_FreeContiguous
4292 **
4293 **  Free memory allocated from the contiguous pool.
4294 **
4295 **  INPUT:
4296 **
4297 **      gckOS Os
4298 **          Pointer to an gckOS object.
4299 **
4300 **      gctPHYS_ADDR Physical
4301 **          Physical address of the allocation.
4302 **
4303 **      gctPOINTER Logical
4304 **          Logicval address of the allocation.
4305 **
4306 **      gctSIZE_T Bytes
4307 **          Number of bytes of the allocation.
4308 **
4309 **  OUTPUT:
4310 **
4311 **      Nothing.
4312 */
4313 gceSTATUS
4314 gckOS_FreeContiguous(
4315     IN gckOS Os,
4316     IN gctPHYS_ADDR Physical,
4317     IN gctPOINTER Logical,
4318     IN gctSIZE_T Bytes
4319     )
4320 {
4321     gceSTATUS status;
4322
4323     gcmkHEADER_ARG("Os=0x%X Physical=0x%X Logical=0x%X Bytes=%lu",
4324                    Os, Physical, Logical, Bytes);
4325
4326     /* Verify the arguments. */
4327     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
4328     gcmkVERIFY_ARGUMENT(Physical != gcvNULL);
4329     gcmkVERIFY_ARGUMENT(Logical != gcvNULL);
4330     gcmkVERIFY_ARGUMENT(Bytes > 0);
4331
4332     /* Same of non-paged memory for now. */
4333     gcmkONERROR(gckOS_FreeNonPagedMemory(Os, Bytes, Physical, Logical));
4334
4335     /* Success. */
4336     gcmkFOOTER_NO();
4337     return gcvSTATUS_OK;
4338
4339 OnError:
4340     /* Return the status. */
4341     gcmkFOOTER();
4342     return status;
4343 }
4344
4345 #if gcdENABLE_VG
4346 /******************************************************************************
4347 **
4348 **  gckOS_GetKernelLogical
4349 **
4350 **  Return the kernel logical pointer that corresponods to the specified
4351 **  hardware address.
4352 **
4353 **  INPUT:
4354 **
4355 **      gckOS Os
4356 **          Pointer to an gckOS object.
4357 **
4358 **      gctUINT32 Address
4359 **          Hardware physical address.
4360 **
4361 **  OUTPUT:
4362 **
4363 **      gctPOINTER * KernelPointer
4364 **          Pointer to a variable receiving the pointer in kernel address space.
4365 */
4366 gceSTATUS
4367 gckOS_GetKernelLogical(
4368     IN gckOS Os,
4369     IN gctUINT32 Address,
4370     OUT gctPOINTER * KernelPointer
4371     )
4372 {
4373     return gckOS_GetKernelLogicalEx(Os, gcvCORE_MAJOR, Address, KernelPointer);
4374 }
4375
4376 gceSTATUS
4377 gckOS_GetKernelLogicalEx(
4378     IN gckOS Os,
4379     IN gceCORE Core,
4380     IN gctUINT32 Address,
4381     OUT gctPOINTER * KernelPointer
4382     )
4383 {
4384     gceSTATUS status;
4385
4386     gcmkHEADER_ARG("Os=0x%X Core=%d Address=0x%08x", Os, Core, Address);
4387
4388     do
4389     {
4390         gckGALDEVICE device;
4391         gckKERNEL kernel;
4392         gcePOOL pool;
4393         gctUINT32 offset;
4394         gctPOINTER logical;
4395
4396         /* Extract the pointer to the gckGALDEVICE class. */
4397         device = (gckGALDEVICE) Os->device;
4398
4399         /* Kernel shortcut. */
4400         kernel = device->kernels[Core];
4401 #if gcdENABLE_VG
4402        if (Core == gcvCORE_VG)
4403        {
4404            gcmkERR_BREAK(gckVGHARDWARE_SplitMemory(
4405                 kernel->vg->hardware, Address, &pool, &offset
4406                 ));
4407        }
4408        else
4409 #endif
4410        {
4411         /* Split the memory address into a pool type and offset. */
4412             gcmkERR_BREAK(gckHARDWARE_SplitMemory(
4413                 kernel->hardware, Address, &pool, &offset
4414                 ));
4415        }
4416
4417         /* Dispatch on pool. */
4418         switch (pool)
4419         {
4420         case gcvPOOL_LOCAL_INTERNAL:
4421             /* Internal memory. */
4422             logical = device->internalLogical;
4423             break;
4424
4425         case gcvPOOL_LOCAL_EXTERNAL:
4426             /* External memory. */
4427             logical = device->externalLogical;
4428             break;
4429
4430         case gcvPOOL_SYSTEM:
4431             /* System memory. */
4432             logical = device->contiguousBase;
4433             break;
4434
4435         default:
4436             /* Invalid memory pool. */
4437             gcmkFOOTER();
4438             return gcvSTATUS_INVALID_ARGUMENT;
4439         }
4440
4441         /* Build logical address of specified address. */
4442         * KernelPointer = ((gctUINT8_PTR) logical) + offset;
4443
4444         /* Success. */
4445         gcmkFOOTER_ARG("*KernelPointer=0x%X", *KernelPointer);
4446         return gcvSTATUS_OK;
4447     }
4448     while (gcvFALSE);
4449
4450     /* Return status. */
4451     gcmkFOOTER();
4452     return status;
4453 }
4454 #endif
4455
4456 /*******************************************************************************
4457 **
4458 **  gckOS_MapUserPointer
4459 **
4460 **  Map a pointer from the user process into the kernel address space.
4461 **
4462 **  INPUT:
4463 **
4464 **      gckOS Os
4465 **          Pointer to an gckOS object.
4466 **
4467 **      gctPOINTER Pointer
4468 **          Pointer in user process space that needs to be mapped.
4469 **
4470 **      gctSIZE_T Size
4471 **          Number of bytes that need to be mapped.
4472 **
4473 **  OUTPUT:
4474 **
4475 **      gctPOINTER * KernelPointer
4476 **          Pointer to a variable receiving the mapped pointer in kernel address
4477 **          space.
4478 */
4479 gceSTATUS
4480 gckOS_MapUserPointer(
4481     IN gckOS Os,
4482     IN gctPOINTER Pointer,
4483     IN gctSIZE_T Size,
4484     OUT gctPOINTER * KernelPointer
4485     )
4486 {
4487     gctPOINTER buf = gcvNULL;
4488     gctUINT32 len;
4489
4490     gcmkHEADER_ARG("Os=0x%X Pointer=0x%X Size=%lu", Os, Pointer, Size);
4491
4492     /* Verify the arguments. */
4493     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
4494     gcmkVERIFY_ARGUMENT(Pointer != gcvNULL);
4495     gcmkVERIFY_ARGUMENT(Size > 0);
4496     gcmkVERIFY_ARGUMENT(KernelPointer != gcvNULL);
4497
4498     buf = kmalloc(Size, GFP_KERNEL | gcdNOWARN);
4499     if (buf == gcvNULL)
4500     {
4501         gcmkTRACE(
4502             gcvLEVEL_ERROR,
4503             "%s(%d): Failed to allocate memory.",
4504             __FUNCTION__, __LINE__
4505             );
4506
4507         gcmkFOOTER_ARG("*status=%d", gcvSTATUS_OUT_OF_MEMORY);
4508         return gcvSTATUS_OUT_OF_MEMORY;
4509     }
4510
4511     len = copy_from_user(buf, Pointer, Size);
4512     if (len != 0)
4513     {
4514         gcmkTRACE(
4515             gcvLEVEL_ERROR,
4516             "%s(%d): Failed to copy data from user.",
4517             __FUNCTION__, __LINE__
4518             );
4519
4520         if (buf != gcvNULL)
4521         {
4522             kfree(buf);
4523         }
4524
4525         gcmkFOOTER_ARG("*status=%d", gcvSTATUS_GENERIC_IO);
4526         return gcvSTATUS_GENERIC_IO;
4527     }
4528
4529     *KernelPointer = buf;
4530
4531     gcmkFOOTER_ARG("*KernelPointer=0x%X", *KernelPointer);
4532     return gcvSTATUS_OK;
4533 }
4534
4535 /*******************************************************************************
4536 **
4537 **  gckOS_UnmapUserPointer
4538 **
4539 **  Unmap a user process pointer from the kernel address space.
4540 **
4541 **  INPUT:
4542 **
4543 **      gckOS Os
4544 **          Pointer to an gckOS object.
4545 **
4546 **      gctPOINTER Pointer
4547 **          Pointer in user process space that needs to be unmapped.
4548 **
4549 **      gctSIZE_T Size
4550 **          Number of bytes that need to be unmapped.
4551 **
4552 **      gctPOINTER KernelPointer
4553 **          Pointer in kernel address space that needs to be unmapped.
4554 **
4555 **  OUTPUT:
4556 **
4557 **      Nothing.
4558 */
4559 gceSTATUS
4560 gckOS_UnmapUserPointer(
4561     IN gckOS Os,
4562     IN gctPOINTER Pointer,
4563     IN gctSIZE_T Size,
4564     IN gctPOINTER KernelPointer
4565     )
4566 {
4567     gctUINT32 len;
4568
4569     gcmkHEADER_ARG("Os=0x%X Pointer=0x%X Size=%lu KernelPointer=0x%X",
4570                    Os, Pointer, Size, KernelPointer);
4571
4572
4573     /* Verify the arguments. */
4574     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
4575     gcmkVERIFY_ARGUMENT(Pointer != gcvNULL);
4576     gcmkVERIFY_ARGUMENT(Size > 0);
4577     gcmkVERIFY_ARGUMENT(KernelPointer != gcvNULL);
4578
4579     len = copy_to_user(Pointer, KernelPointer, Size);
4580
4581     kfree(KernelPointer);
4582
4583     if (len != 0)
4584     {
4585         gcmkTRACE(
4586             gcvLEVEL_ERROR,
4587             "%s(%d): Failed to copy data to user.",
4588             __FUNCTION__, __LINE__
4589             );
4590
4591         gcmkFOOTER_ARG("status=%d", gcvSTATUS_GENERIC_IO);
4592         return gcvSTATUS_GENERIC_IO;
4593     }
4594
4595     gcmkFOOTER_NO();
4596     return gcvSTATUS_OK;
4597 }
4598
4599 /*******************************************************************************
4600 **
4601 **  gckOS_QueryNeedCopy
4602 **
4603 **  Query whether the memory can be accessed or mapped directly or it has to be
4604 **  copied.
4605 **
4606 **  INPUT:
4607 **
4608 **      gckOS Os
4609 **          Pointer to an gckOS object.
4610 **
4611 **      gctUINT32 ProcessID
4612 **          Process ID of the current process.
4613 **
4614 **  OUTPUT:
4615 **
4616 **      gctBOOL_PTR NeedCopy
4617 **          Pointer to a boolean receiving gcvTRUE if the memory needs a copy or
4618 **          gcvFALSE if the memory can be accessed or mapped dircetly.
4619 */
4620 gceSTATUS
4621 gckOS_QueryNeedCopy(
4622     IN gckOS Os,
4623     IN gctUINT32 ProcessID,
4624     OUT gctBOOL_PTR NeedCopy
4625     )
4626 {
4627     gcmkHEADER_ARG("Os=0x%X ProcessID=%d", Os, ProcessID);
4628
4629     /* Verify the arguments. */
4630     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
4631     gcmkVERIFY_ARGUMENT(NeedCopy != gcvNULL);
4632
4633     /* We need to copy data. */
4634     *NeedCopy = gcvTRUE;
4635
4636     /* Success. */
4637     gcmkFOOTER_ARG("*NeedCopy=%d", *NeedCopy);
4638     return gcvSTATUS_OK;
4639 }
4640
4641 /*******************************************************************************
4642 **
4643 **  gckOS_CopyFromUserData
4644 **
4645 **  Copy data from user to kernel memory.
4646 **
4647 **  INPUT:
4648 **
4649 **      gckOS Os
4650 **          Pointer to an gckOS object.
4651 **
4652 **      gctPOINTER KernelPointer
4653 **          Pointer to kernel memory.
4654 **
4655 **      gctPOINTER Pointer
4656 **          Pointer to user memory.
4657 **
4658 **      gctSIZE_T Size
4659 **          Number of bytes to copy.
4660 **
4661 **  OUTPUT:
4662 **
4663 **      Nothing.
4664 */
4665 gceSTATUS
4666 gckOS_CopyFromUserData(
4667     IN gckOS Os,
4668     IN gctPOINTER KernelPointer,
4669     IN gctPOINTER Pointer,
4670     IN gctSIZE_T Size
4671     )
4672 {
4673     gceSTATUS status;
4674
4675     gcmkHEADER_ARG("Os=0x%X KernelPointer=0x%X Pointer=0x%X Size=%lu",
4676                    Os, KernelPointer, Pointer, Size);
4677
4678     /* Verify the arguments. */
4679     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
4680     gcmkVERIFY_ARGUMENT(KernelPointer != gcvNULL);
4681     gcmkVERIFY_ARGUMENT(Pointer != gcvNULL);
4682     gcmkVERIFY_ARGUMENT(Size > 0);
4683
4684     /* Copy data from user. */
4685     if (copy_from_user(KernelPointer, Pointer, Size) != 0)
4686     {
4687         /* Could not copy all the bytes. */
4688         gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES);
4689     }
4690
4691     /* Success. */
4692     gcmkFOOTER_NO();
4693     return gcvSTATUS_OK;
4694
4695 OnError:
4696     /* Return the status. */
4697     gcmkFOOTER();
4698     return status;
4699 }
4700
4701 /*******************************************************************************
4702 **
4703 **  gckOS_CopyToUserData
4704 **
4705 **  Copy data from kernel to user memory.
4706 **
4707 **  INPUT:
4708 **
4709 **      gckOS Os
4710 **          Pointer to an gckOS object.
4711 **
4712 **      gctPOINTER KernelPointer
4713 **          Pointer to kernel memory.
4714 **
4715 **      gctPOINTER Pointer
4716 **          Pointer to user memory.
4717 **
4718 **      gctSIZE_T Size
4719 **          Number of bytes to copy.
4720 **
4721 **  OUTPUT:
4722 **
4723 **      Nothing.
4724 */
4725 gceSTATUS
4726 gckOS_CopyToUserData(
4727     IN gckOS Os,
4728     IN gctPOINTER KernelPointer,
4729     IN gctPOINTER Pointer,
4730     IN gctSIZE_T Size
4731     )
4732 {
4733     gceSTATUS status;
4734
4735     gcmkHEADER_ARG("Os=0x%X KernelPointer=0x%X Pointer=0x%X Size=%lu",
4736                    Os, KernelPointer, Pointer, Size);
4737
4738     /* Verify the arguments. */
4739     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
4740     gcmkVERIFY_ARGUMENT(KernelPointer != gcvNULL);
4741     gcmkVERIFY_ARGUMENT(Pointer != gcvNULL);
4742     gcmkVERIFY_ARGUMENT(Size > 0);
4743
4744     /* Copy data to user. */
4745     if (copy_to_user(Pointer, KernelPointer, Size) != 0)
4746     {
4747         /* Could not copy all the bytes. */
4748         gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES);
4749     }
4750
4751     /* Success. */
4752     gcmkFOOTER_NO();
4753     return gcvSTATUS_OK;
4754
4755 OnError:
4756     /* Return the status. */
4757     gcmkFOOTER();
4758     return status;
4759 }
4760
4761 /*******************************************************************************
4762 **
4763 **  gckOS_WriteMemory
4764 **
4765 **  Write data to a memory.
4766 **
4767 **  INPUT:
4768 **
4769 **      gckOS Os
4770 **          Pointer to an gckOS object.
4771 **
4772 **      gctPOINTER Address
4773 **          Address of the memory to write to.
4774 **
4775 **      gctUINT32 Data
4776 **          Data for register.
4777 **
4778 **  OUTPUT:
4779 **
4780 **      Nothing.
4781 */
4782 gceSTATUS
4783 gckOS_WriteMemory(
4784     IN gckOS Os,
4785     IN gctPOINTER Address,
4786     IN gctUINT32 Data
4787     )
4788 {
4789     gceSTATUS status;
4790     gcmkHEADER_ARG("Os=0x%X Address=0x%X Data=%u", Os, Address, Data);
4791
4792     /* Verify the arguments. */
4793     gcmkVERIFY_ARGUMENT(Address != gcvNULL);
4794
4795     /* Write memory. */
4796     if (access_ok(VERIFY_WRITE, Address, 4))
4797     {
4798         /* User address. */
4799         if(put_user(Data, (gctUINT32*)Address))
4800         {
4801             gcmkONERROR(gcvSTATUS_INVALID_ADDRESS);
4802         }
4803     }
4804     else
4805     {
4806         /* Kernel address. */
4807         *(gctUINT32 *)Address = Data;
4808     }
4809
4810     /* Success. */
4811     gcmkFOOTER_NO();
4812     return gcvSTATUS_OK;
4813
4814 OnError:
4815     gcmkFOOTER();
4816     return status;
4817 }
4818
4819 /*******************************************************************************
4820 **
4821 **  gckOS_MapUserMemory
4822 **
4823 **  Lock down a user buffer and return an DMA'able address to be used by the
4824 **  hardware to access it.
4825 **
4826 **  INPUT:
4827 **
4828 **      gctPOINTER Memory
4829 **          Pointer to memory to lock down.
4830 **
4831 **      gctSIZE_T Size
4832 **          Size in bytes of the memory to lock down.
4833 **
4834 **  OUTPUT:
4835 **
4836 **      gctPOINTER * Info
4837 **          Pointer to variable receiving the information record required by
4838 **          gckOS_UnmapUserMemory.
4839 **
4840 **      gctUINT32_PTR Address
4841 **          Pointer to a variable that will receive the address DMA'able by the
4842 **          hardware.
4843 */
4844 gceSTATUS
4845 gckOS_MapUserMemory(
4846     IN gckOS Os,
4847     IN gceCORE Core,
4848     IN gctPOINTER Memory,
4849     IN gctUINT32 Physical,
4850     IN gctSIZE_T Size,
4851     OUT gctPOINTER * Info,
4852     OUT gctUINT32_PTR Address
4853     )
4854 {
4855     gceSTATUS status;
4856
4857     gcmkHEADER_ARG("Os=0x%x Core=%d Memory=0x%x Size=%lu", Os, Core, Memory, Size);
4858
4859 #if gcdSECURE_USER
4860     gcmkONERROR(gckOS_AddMapping(Os, *Address, Memory, Size));
4861
4862     gcmkFOOTER_NO();
4863     return gcvSTATUS_OK;
4864
4865 OnError:
4866     gcmkFOOTER();
4867     return status;
4868 #else
4869 {
4870     gctSIZE_T pageCount, i, j;
4871     gctUINT32_PTR pageTable;
4872     gctUINT32 address = 0, physical = ~0U;
4873     gctUINTPTR_T start, end, memory;
4874     gctUINT32 offset;
4875     gctINT result = 0;
4876 #if gcdPROCESS_ADDRESS_SPACE
4877     gckMMU mmu;
4878 #endif
4879
4880     gcsPageInfo_PTR info = gcvNULL;
4881     struct page **pages = gcvNULL;
4882
4883     /* Verify the arguments. */
4884     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
4885     gcmkVERIFY_ARGUMENT(Memory != gcvNULL || Physical != ~0U);
4886     gcmkVERIFY_ARGUMENT(Size > 0);
4887     gcmkVERIFY_ARGUMENT(Info != gcvNULL);
4888     gcmkVERIFY_ARGUMENT(Address != gcvNULL);
4889
4890     do
4891     {
4892         gctSIZE_T extraPage;
4893
4894         memory = (gctUINTPTR_T) Memory;
4895
4896         /* Get the number of required pages. */
4897         end = (memory + Size + PAGE_SIZE - 1) >> PAGE_SHIFT;
4898         start = memory >> PAGE_SHIFT;
4899         pageCount = end - start;
4900
4901         /* Allocate extra 64 bytes to avoid cache overflow */
4902         extraPage = (((memory + gcmALIGN(Size + 64, 64) + PAGE_SIZE - 1) >> PAGE_SHIFT) > end) ? 1 : 0;
4903
4904         gcmkTRACE_ZONE(
4905             gcvLEVEL_INFO, gcvZONE_OS,
4906             "%s(%d): pageCount: %d.",
4907             __FUNCTION__, __LINE__,
4908             pageCount
4909             );
4910
4911         /* Overflow. */
4912         if ((memory + Size) < memory)
4913         {
4914             gcmkFOOTER_ARG("status=%d", gcvSTATUS_INVALID_ARGUMENT);
4915             return gcvSTATUS_INVALID_ARGUMENT;
4916         }
4917
4918         MEMORY_MAP_LOCK(Os);
4919
4920         /* Allocate the Info struct. */
4921         info = (gcsPageInfo_PTR)kmalloc(sizeof(gcsPageInfo), GFP_KERNEL | gcdNOWARN);
4922
4923         if (info == gcvNULL)
4924         {
4925             status = gcvSTATUS_OUT_OF_MEMORY;
4926             break;
4927         }
4928
4929         info->extraPage = 0;
4930
4931         /* Allocate the array of page addresses. */
4932         pages = (struct page **)kmalloc((pageCount + extraPage) * sizeof(struct page *), GFP_KERNEL | gcdNOWARN);
4933
4934         if (pages == gcvNULL)
4935         {
4936             status = gcvSTATUS_OUT_OF_MEMORY;
4937             break;
4938         }
4939
4940         if (Physical != ~0U)
4941         {
4942             for (i = 0; i < pageCount; i++)
4943             {
4944                 pages[i] = pfn_to_page((Physical >> PAGE_SHIFT) + i);
4945
4946                 if (pfn_valid(page_to_pfn(pages[i])))
4947                 {
4948                     get_page(pages[i]);
4949                 }
4950             }
4951         }
4952         else
4953         {
4954             /* Get the user pages. */
4955             down_read(&current->mm->mmap_sem);
4956
4957             result = get_user_pages(current,
4958                     current->mm,
4959                     memory & PAGE_MASK,
4960                     pageCount,
4961                     1,
4962                     0,
4963                     pages,
4964                     gcvNULL
4965                     );
4966
4967             up_read(&current->mm->mmap_sem);
4968
4969             if (result <=0 || result < pageCount)
4970             {
4971                 struct vm_area_struct *vma;
4972
4973                 /* Release the pages if any. */
4974                 if (result > 0)
4975                 {
4976                     for (i = 0; i < result; i++)
4977                     {
4978                         if (pages[i] == gcvNULL)
4979                         {
4980                             break;
4981                         }
4982
4983                         page_cache_release(pages[i]);
4984                         pages[i] = gcvNULL;
4985                     }
4986
4987                     result = 0;
4988                 }
4989
4990                 vma = find_vma(current->mm, memory);
4991
4992                 if (vma && (vma->vm_flags & VM_PFNMAP))
4993                 {
4994                     pte_t       * pte;
4995                     spinlock_t  * ptl;
4996                     gctUINTPTR_T logical = memory;
4997
4998                     for (i = 0; i < pageCount; i++)
4999                     {
5000                         pgd_t * pgd = pgd_offset(current->mm, logical);
5001                         pud_t * pud = pud_offset(pgd, logical);
5002
5003                         if (pud)
5004                         {
5005                             pmd_t * pmd = pmd_offset(pud, logical);
5006                             pte = pte_offset_map_lock(current->mm, pmd, logical, &ptl);
5007                             if (!pte)
5008                             {
5009                                 gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES);
5010                             }
5011                         }
5012                         else
5013                         {
5014                             gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES);
5015                         }
5016
5017                         pages[i] = pte_page(*pte);
5018                         pte_unmap_unlock(pte, ptl);
5019
5020                         /* Advance to next. */
5021                         logical += PAGE_SIZE;
5022                     }
5023                 }
5024                 else
5025                 {
5026                     gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES);
5027                 }
5028
5029                 /* Check if this memory is contiguous for old mmu. */
5030                 if (Os->device->kernels[Core]->hardware->mmuVersion == 0)
5031                 {
5032                     for (i = 1; i < pageCount; i++)
5033                     {
5034                         if (pages[i] != nth_page(pages[0], i))
5035                         {
5036                             /* Non-contiguous. */
5037                             break;
5038                         }
5039                     }
5040
5041                     if (i == pageCount)
5042                     {
5043                         /* Contiguous memory. */
5044                         physical = page_to_phys(pages[0]) | (memory & ~PAGE_MASK);
5045
5046                         if (!((physical - Os->device->baseAddress) & 0x80000000))
5047                         {
5048                             kfree(pages);
5049                             pages = gcvNULL;
5050
5051                             info->pages = gcvNULL;
5052                             info->pageTable = gcvNULL;
5053
5054                             MEMORY_MAP_UNLOCK(Os);
5055
5056                             *Address = physical - Os->device->baseAddress;
5057                             *Info    = info;
5058
5059                             gcmkVERIFY_OK(
5060                                 gckOS_CPUPhysicalToGPUPhysical(Os, *Address, Address));
5061
5062                             gcmkFOOTER_ARG("*Info=0x%X *Address=0x%08x",
5063                                            *Info, *Address);
5064
5065                             return gcvSTATUS_OK;
5066                         }
5067                     }
5068                 }
5069
5070                 /* Reference pages. */
5071                 for (i = 0; i < pageCount; i++)
5072                 {
5073                     if (pfn_valid(page_to_pfn(pages[i])))
5074                     {
5075                         get_page(pages[i]);
5076                     }
5077                 }
5078             }
5079         }
5080
5081         for (i = 0; i < pageCount; i++)
5082         {
5083 #ifdef CONFIG_ARM
5084             gctUINT32 data;
5085             get_user(data, (gctUINT32*)((memory & PAGE_MASK) + i * PAGE_SIZE));
5086 #endif
5087
5088             /* Flush(clean) the data cache. */
5089             gcmkONERROR(gckOS_CacheFlush(Os, _GetProcessID(), gcvNULL,
5090                              page_to_phys(pages[i]),
5091                              (gctPOINTER)(memory & PAGE_MASK) + i*PAGE_SIZE,
5092                              PAGE_SIZE));
5093         }
5094
5095 #if gcdPROCESS_ADDRESS_SPACE
5096         gcmkONERROR(gckKERNEL_GetProcessMMU(Os->device->kernels[Core], &mmu));
5097 #endif
5098
5099         if (extraPage)
5100         {
5101             pages[pageCount++] = Os->paddingPage;
5102             info->extraPage = 1;
5103         }
5104
5105 #if gcdSECURITY
5106     {
5107         gctPHYS_ADDR physicalArrayPhysical;
5108         gctPOINTER physicalArrayLogical;
5109         gctUINT32_PTR logical;
5110         gctSIZE_T bytes = pageCount * gcmSIZEOF(gctUINT32);
5111         pageTable = gcvNULL;
5112
5113         gcmkONERROR(gckOS_AllocateNonPagedMemory(
5114             Os,
5115             gcvFALSE,
5116             &bytes,
5117             &physicalArrayPhysical,
5118             &physicalArrayLogical
5119             ));
5120
5121         logical = physicalArrayLogical;
5122
5123         /* Fill the page table. */
5124         for (i = 0; i < pageCount; i++)
5125         {
5126             gctUINT32 phys;
5127             phys = page_to_phys(pages[i]);
5128
5129             logical[i] = phys;
5130         }
5131         j = 0;
5132
5133
5134         gcmkONERROR(gckKERNEL_SecurityMapMemory(
5135             Os->device->kernels[Core],
5136             physicalArrayLogical,
5137             pageCount,
5138             &address
5139             ));
5140
5141         gcmkONERROR(gckOS_FreeNonPagedMemory(
5142             Os,
5143             1,
5144             physicalArrayPhysical,
5145             physicalArrayLogical
5146             ));
5147     }
5148
5149 #else
5150 #if gcdENABLE_VG
5151         if (Core == gcvCORE_VG)
5152         {
5153             /* Allocate pages inside the page table. */
5154             gcmkERR_BREAK(gckVGMMU_AllocatePages(Os->device->kernels[Core]->vg->mmu,
5155                                               pageCount * (PAGE_SIZE/4096),
5156                                               (gctPOINTER *) &pageTable,
5157                                               &address));
5158         }
5159         else
5160 #endif
5161         {
5162 #if gcdPROCESS_ADDRESS_SPACE
5163             /* Allocate pages inside the page table. */
5164             gcmkERR_BREAK(gckMMU_AllocatePages(mmu,
5165                                               pageCount * (PAGE_SIZE/4096),
5166                                               (gctPOINTER *) &pageTable,
5167                                               &address));
5168 #else
5169             /* Allocate pages inside the page table. */
5170             gcmkERR_BREAK(gckMMU_AllocatePages(Os->device->kernels[Core]->mmu,
5171                                               pageCount * (PAGE_SIZE/4096),
5172                                               (gctPOINTER *) &pageTable,
5173                                               &address));
5174 #endif
5175         }
5176
5177         /* Fill the page table. */
5178         for (i = 0; i < pageCount; i++)
5179         {
5180             gctUINT32 phys;
5181             gctUINT32_PTR tab = pageTable + i * (PAGE_SIZE/4096);
5182
5183 #if gcdPROCESS_ADDRESS_SPACE
5184             gckMMU_GetPageEntry(mmu, address + i * 4096, &tab);
5185 #endif
5186             phys = page_to_phys(pages[i]);
5187
5188 #ifdef CONFIG_IOMMU_SUPPORT
5189             if (Os->iommu)
5190             {
5191                 gcmkTRACE_ZONE(
5192                     gcvLEVEL_INFO, gcvZONE_OS,
5193                     "%s(%d): Setup mapping in IOMMU %x => %x",
5194                     __FUNCTION__, __LINE__,
5195                     Address + (i * PAGE_SIZE), phys
5196                     );
5197
5198                 gcmkONERROR(gckIOMMU_Map(
5199                     Os->iommu, address + i * PAGE_SIZE, phys, PAGE_SIZE));
5200             }
5201             else
5202 #endif
5203             {
5204
5205 #if gcdENABLE_VG
5206                 if (Core == gcvCORE_VG)
5207                 {
5208                     gcmkVERIFY_OK(
5209                         gckOS_CPUPhysicalToGPUPhysical(Os, phys, &phys));
5210
5211                     /* Get the physical address from page struct. */
5212                     gcmkONERROR(
5213                         gckVGMMU_SetPage(Os->device->kernels[Core]->vg->mmu,
5214                                        phys,
5215                                        tab));
5216                 }
5217                 else
5218 #endif
5219                 {
5220                     /* Get the physical address from page struct. */
5221                     gcmkONERROR(
5222                         gckMMU_SetPage(Os->device->kernels[Core]->mmu,
5223                                        phys,
5224                                        tab));
5225                 }
5226
5227                 for (j = 1; j < (PAGE_SIZE/4096); j++)
5228                 {
5229                     pageTable[i * (PAGE_SIZE/4096) + j] = pageTable[i * (PAGE_SIZE/4096)] + 4096 * j;
5230                 }
5231             }
5232
5233 #if !gcdPROCESS_ADDRESS_SPACE
5234             gcmkTRACE_ZONE(
5235                 gcvLEVEL_INFO, gcvZONE_OS,
5236                 "%s(%d): pageTable[%d]: 0x%X 0x%X.",
5237                 __FUNCTION__, __LINE__,
5238                 i, phys, pageTable[i]);
5239 #endif
5240         }
5241
5242 #if gcdENABLE_VG
5243         if (Core == gcvCORE_VG)
5244         {
5245             gcmkONERROR(gckVGMMU_Flush(Os->device->kernels[Core]->vg->mmu));
5246         }
5247         else
5248 #endif
5249         {
5250 #if gcdPROCESS_ADDRESS_SPACE
5251             info->mmu = mmu;
5252             gcmkONERROR(gckMMU_Flush(mmu));
5253 #else
5254             gcmkONERROR(gckMMU_Flush(Os->device->kernels[Core]->mmu, gcvSURF_TYPE_UNKNOWN));
5255 #endif
5256         }
5257 #endif
5258         info->address = address;
5259
5260         /* Save pointer to page table. */
5261         info->pageTable = pageTable;
5262         info->pages = pages;
5263
5264         *Info = (gctPOINTER) info;
5265
5266         gcmkTRACE_ZONE(
5267             gcvLEVEL_INFO, gcvZONE_OS,
5268             "%s(%d): info->pages: 0x%X, info->pageTable: 0x%X, info: 0x%X.",
5269             __FUNCTION__, __LINE__,
5270             info->pages,
5271             info->pageTable,
5272             info
5273             );
5274
5275         offset = (Physical != ~0U)
5276                ? (Physical & ~PAGE_MASK)
5277                : (memory & ~PAGE_MASK);
5278
5279         /* Return address. */
5280         *Address = address + offset;
5281
5282         gcmkTRACE_ZONE(
5283             gcvLEVEL_INFO, gcvZONE_OS,
5284             "%s(%d): Address: 0x%X.",
5285             __FUNCTION__, __LINE__,
5286             *Address
5287             );
5288
5289         /* Success. */
5290         status = gcvSTATUS_OK;
5291     }
5292     while (gcvFALSE);
5293
5294 OnError:
5295
5296     if (gcmIS_ERROR(status))
5297     {
5298         gcmkTRACE(
5299             gcvLEVEL_ERROR,
5300             "%s(%d): error occured: %d.",
5301             __FUNCTION__, __LINE__,
5302             status
5303             );
5304
5305         /* Release page array. */
5306         if (result > 0 && pages != gcvNULL)
5307         {
5308             gcmkTRACE(
5309                 gcvLEVEL_ERROR,
5310                 "%s(%d): error: page table is freed.",
5311                 __FUNCTION__, __LINE__
5312                 );
5313
5314             for (i = 0; i < result; i++)
5315             {
5316                 if (pages[i] == gcvNULL)
5317                 {
5318                     break;
5319                 }
5320                 page_cache_release(pages[i]);
5321             }
5322         }
5323
5324         if (info!= gcvNULL && pages != gcvNULL)
5325         {
5326             gcmkTRACE(
5327                 gcvLEVEL_ERROR,
5328                 "%s(%d): error: pages is freed.",
5329                 __FUNCTION__, __LINE__
5330                 );
5331
5332             /* Free the page table. */
5333             kfree(pages);
5334             info->pages = gcvNULL;
5335         }
5336
5337         /* Release page info struct. */
5338         if (info != gcvNULL)
5339         {
5340             gcmkTRACE(
5341                 gcvLEVEL_ERROR,
5342                 "%s(%d): error: info is freed.",
5343                 __FUNCTION__, __LINE__
5344                 );
5345
5346             /* Free the page info struct. */
5347             kfree(info);
5348             *Info = gcvNULL;
5349         }
5350     }
5351
5352     MEMORY_MAP_UNLOCK(Os);
5353
5354     /* Return the status. */
5355     if (gcmIS_SUCCESS(status))
5356     {
5357         gcmkFOOTER_ARG("*Info=0x%X *Address=0x%08x", *Info, *Address);
5358     }
5359     else
5360     {
5361         gcmkFOOTER();
5362     }
5363
5364     return status;
5365 }
5366 #endif
5367 }
5368
5369 /*******************************************************************************
5370 **
5371 **  gckOS_UnmapUserMemory
5372 **
5373 **  Unlock a user buffer and that was previously locked down by
5374 **  gckOS_MapUserMemory.
5375 **
5376 **  INPUT:
5377 **
5378 **      gctPOINTER Memory
5379 **          Pointer to memory to unlock.
5380 **
5381 **      gctSIZE_T Size
5382 **          Size in bytes of the memory to unlock.
5383 **
5384 **      gctPOINTER Info
5385 **          Information record returned by gckOS_MapUserMemory.
5386 **
5387 **      gctUINT32_PTR Address
5388 **          The address returned by gckOS_MapUserMemory.
5389 **
5390 **  OUTPUT:
5391 **
5392 **      Nothing.
5393 */
5394 gceSTATUS
5395 gckOS_UnmapUserMemory(
5396     IN gckOS Os,
5397     IN gceCORE Core,
5398     IN gctPOINTER Memory,
5399     IN gctSIZE_T Size,
5400     IN gctPOINTER Info,
5401     IN gctUINT32 Address
5402     )
5403 {
5404     gceSTATUS status;
5405
5406     gcmkHEADER_ARG("Os=0x%X Core=%d Memory=0x%X Size=%lu Info=0x%X Address0x%08x",
5407                    Os, Core, Memory, Size, Info, Address);
5408
5409 #if gcdSECURE_USER
5410     gcmkONERROR(gckOS_RemoveMapping(Os, Memory, Size));
5411
5412     gcmkFOOTER_NO();
5413     return gcvSTATUS_OK;
5414
5415 OnError:
5416     gcmkFOOTER();
5417     return status;
5418 #else
5419 {
5420     gctUINTPTR_T memory, start, end;
5421     gcsPageInfo_PTR info;
5422     gctSIZE_T pageCount, i;
5423     struct page **pages;
5424
5425     /* Verify the arguments. */
5426     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
5427     gcmkVERIFY_ARGUMENT(Memory != gcvNULL);
5428     gcmkVERIFY_ARGUMENT(Size > 0);
5429     gcmkVERIFY_ARGUMENT(Info != gcvNULL);
5430
5431     do
5432     {
5433         info = (gcsPageInfo_PTR) Info;
5434
5435         pages = info->pages;
5436
5437         gcmkTRACE_ZONE(
5438             gcvLEVEL_INFO, gcvZONE_OS,
5439             "%s(%d): info=0x%X, pages=0x%X.",
5440             __FUNCTION__, __LINE__,
5441             info, pages
5442             );
5443
5444         /* Invalid page array. */
5445         if (pages == gcvNULL && info->pageTable == gcvNULL)
5446         {
5447             kfree(info);
5448
5449             gcmkFOOTER_NO();
5450             return gcvSTATUS_OK;
5451         }
5452
5453         memory = (gctUINTPTR_T)Memory;
5454         end = (memory + Size + PAGE_SIZE - 1) >> PAGE_SHIFT;
5455         start = memory >> PAGE_SHIFT;
5456         pageCount = end - start;
5457
5458         /* Overflow. */
5459         if ((memory + Size) < memory)
5460         {
5461             gcmkFOOTER_ARG("status=%d", gcvSTATUS_INVALID_ARGUMENT);
5462             return gcvSTATUS_INVALID_ARGUMENT;
5463         }
5464
5465         gcmkTRACE_ZONE(
5466             gcvLEVEL_INFO, gcvZONE_OS,
5467             "%s(%d): memory: 0x%X, pageCount: %d, pageTable: 0x%X.",
5468             __FUNCTION__, __LINE__,
5469             memory, pageCount, info->pageTable
5470             );
5471
5472         MEMORY_MAP_LOCK(Os);
5473
5474 #if !gcdSECURITY
5475         gcmkASSERT(info->pageTable != gcvNULL);
5476 #endif
5477
5478         if (info->extraPage)
5479         {
5480             pageCount += 1;
5481         }
5482
5483 #if gcdSECURITY
5484         if (info->address > 0x80000000)
5485         {
5486             gckKERNEL_SecurityUnmapMemory(
5487                 Os->device->kernels[Core],
5488                 info->address,
5489                 pageCount
5490                 );
5491         }
5492         else
5493         {
5494             gcmkPRINT("Wrong address %s(%d) %x", __FUNCTION__, __LINE__, info->address);
5495         }
5496 #else
5497 #if gcdENABLE_VG
5498         if (Core == gcvCORE_VG)
5499         {
5500             /* Free the pages from the MMU. */
5501             gcmkERR_BREAK(gckVGMMU_FreePages(Os->device->kernels[Core]->vg->mmu,
5502                                           info->pageTable,
5503                                           pageCount * (PAGE_SIZE/4096)
5504                                           ));
5505         }
5506         else
5507 #endif
5508         {
5509             /* Free the pages from the MMU. */
5510 #if gcdPROCESS_ADDRESS_SPACE
5511             gcmkERR_BREAK(gckMMU_FreePagesEx(info->mmu,
5512                 info->address,
5513                 pageCount * (PAGE_SIZE/4096)
5514                 ));
5515
5516 #else
5517             gcmkERR_BREAK(gckMMU_FreePages(Os->device->kernels[Core]->mmu,
5518                                           info->pageTable,
5519                                           pageCount * (PAGE_SIZE/4096)
5520                                           ));
5521 #endif
5522
5523             gcmkERR_BREAK(gckOS_UnmapPages(
5524                 Os,
5525                 pageCount * (PAGE_SIZE/4096),
5526                 info->address
5527                 ));
5528         }
5529 #endif
5530
5531         if (info->extraPage)
5532         {
5533             pageCount -= 1;
5534             info->extraPage = 0;
5535         }
5536
5537         /* Release the page cache. */
5538         if (pages)
5539         {
5540             for (i = 0; i < pageCount; i++)
5541             {
5542                 gcmkTRACE_ZONE(
5543                     gcvLEVEL_INFO, gcvZONE_OS,
5544                     "%s(%d): pages[%d]: 0x%X.",
5545                     __FUNCTION__, __LINE__,
5546                     i, pages[i]
5547                     );
5548
5549                 if (!PageReserved(pages[i]))
5550                 {
5551                      SetPageDirty(pages[i]);
5552                 }
5553
5554                 if (pfn_valid(page_to_pfn(pages[i])))
5555                 {
5556                     page_cache_release(pages[i]);
5557                 }
5558             }
5559         }
5560
5561         /* Success. */
5562         status = gcvSTATUS_OK;
5563     }
5564     while (gcvFALSE);
5565
5566     if (info != gcvNULL)
5567     {
5568         /* Free the page array. */
5569         if (info->pages != gcvNULL)
5570         {
5571             kfree(info->pages);
5572         }
5573
5574         kfree(info);
5575     }
5576
5577     MEMORY_MAP_UNLOCK(Os);
5578
5579     /* Return the status. */
5580     gcmkFOOTER();
5581     return status;
5582 }
5583 #endif
5584 }
5585
5586 /*******************************************************************************
5587 **
5588 **  gckOS_GetBaseAddress
5589 **
5590 **  Get the base address for the physical memory.
5591 **
5592 **  INPUT:
5593 **
5594 **      gckOS Os
5595 **          Pointer to the gckOS object.
5596 **
5597 **  OUTPUT:
5598 **
5599 **      gctUINT32_PTR BaseAddress
5600 **          Pointer to a variable that will receive the base address.
5601 */
5602 gceSTATUS
5603 gckOS_GetBaseAddress(
5604     IN gckOS Os,
5605     OUT gctUINT32_PTR BaseAddress
5606     )
5607 {
5608     gcmkHEADER_ARG("Os=0x%X", Os);
5609
5610     /* Verify the arguments. */
5611     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
5612     gcmkVERIFY_ARGUMENT(BaseAddress != gcvNULL);
5613
5614     /* Return base address. */
5615     *BaseAddress = Os->device->baseAddress;
5616
5617     /* Success. */
5618     gcmkFOOTER_ARG("*BaseAddress=0x%08x", *BaseAddress);
5619     return gcvSTATUS_OK;
5620 }
5621
5622 gceSTATUS
5623 gckOS_SuspendInterrupt(
5624     IN gckOS Os
5625     )
5626 {
5627     return gckOS_SuspendInterruptEx(Os, gcvCORE_MAJOR);
5628 }
5629
5630 #if gcdMULTI_GPU
5631 gceSTATUS
5632 gckOS_SuspendInterruptEx(
5633     IN gckOS Os,
5634     IN gceCORE Core
5635     )
5636 {
5637     gcmkHEADER_ARG("Os=0x%X Core=%d", Os, Core);
5638
5639     /* Verify the arguments. */
5640     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
5641
5642     if (Core == gcvCORE_MAJOR)
5643     {
5644         disable_irq(Os->device->irqLine3D[gcvCORE_3D_0_ID]);
5645         disable_irq(Os->device->irqLine3D[gcvCORE_3D_1_ID]);
5646     }
5647     else
5648     {
5649         disable_irq(Os->device->irqLines[Core]);
5650     }
5651
5652     gcmkFOOTER_NO();
5653     return gcvSTATUS_OK;
5654 }
5655 #else
5656 gceSTATUS
5657 gckOS_SuspendInterruptEx(
5658     IN gckOS Os,
5659     IN gceCORE Core
5660     )
5661 {
5662     gcmkHEADER_ARG("Os=0x%X Core=%d", Os, Core);
5663
5664     /* Verify the arguments. */
5665     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
5666
5667     disable_irq(Os->device->irqLines[Core]);
5668
5669     gcmkFOOTER_NO();
5670     return gcvSTATUS_OK;
5671 }
5672 #endif
5673
5674 gceSTATUS
5675 gckOS_ResumeInterrupt(
5676     IN gckOS Os
5677     )
5678 {
5679     return gckOS_ResumeInterruptEx(Os, gcvCORE_MAJOR);
5680 }
5681
5682 #if gcdMULTI_GPU
5683 gceSTATUS
5684 gckOS_ResumeInterruptEx(
5685     IN gckOS Os,
5686     IN gceCORE Core
5687     )
5688 {
5689     gcmkHEADER_ARG("Os=0x%X Core=%d", Os, Core);
5690
5691     /* Verify the arguments. */
5692     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
5693
5694     if (Core == gcvCORE_MAJOR)
5695     {
5696         enable_irq(Os->device->irqLine3D[gcvCORE_3D_0_ID]);
5697         enable_irq(Os->device->irqLine3D[gcvCORE_3D_1_ID]);
5698     }
5699     else
5700     {
5701         enable_irq(Os->device->irqLines[Core]);
5702     }
5703
5704     gcmkFOOTER_NO();
5705     return gcvSTATUS_OK;
5706 }
5707 #else
5708 gceSTATUS
5709 gckOS_ResumeInterruptEx(
5710     IN gckOS Os,
5711     IN gceCORE Core
5712     )
5713 {
5714     gcmkHEADER_ARG("Os=0x%X Core=%d", Os, Core);
5715
5716     /* Verify the arguments. */
5717     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
5718
5719     enable_irq(Os->device->irqLines[Core]);
5720
5721     gcmkFOOTER_NO();
5722     return gcvSTATUS_OK;
5723 }
5724 #endif
5725
5726 gceSTATUS
5727 gckOS_MemCopy(
5728     IN gctPOINTER Destination,
5729     IN gctCONST_POINTER Source,
5730     IN gctSIZE_T Bytes
5731     )
5732 {
5733     gcmkHEADER_ARG("Destination=0x%X Source=0x%X Bytes=%lu",
5734                    Destination, Source, Bytes);
5735
5736     gcmkVERIFY_ARGUMENT(Destination != gcvNULL);
5737     gcmkVERIFY_ARGUMENT(Source != gcvNULL);
5738     gcmkVERIFY_ARGUMENT(Bytes > 0);
5739
5740     memcpy(Destination, Source, Bytes);
5741
5742     gcmkFOOTER_NO();
5743     return gcvSTATUS_OK;
5744 }
5745
5746 gceSTATUS
5747 gckOS_ZeroMemory(
5748     IN gctPOINTER Memory,
5749     IN gctSIZE_T Bytes
5750     )
5751 {
5752     gcmkHEADER_ARG("Memory=0x%X Bytes=%lu", Memory, Bytes);
5753
5754     gcmkVERIFY_ARGUMENT(Memory != gcvNULL);
5755     gcmkVERIFY_ARGUMENT(Bytes > 0);
5756
5757     memset(Memory, 0, Bytes);
5758
5759     gcmkFOOTER_NO();
5760     return gcvSTATUS_OK;
5761 }
5762
5763 /*******************************************************************************
5764 ********************************* Cache Control ********************************
5765 *******************************************************************************/
5766
5767 /*******************************************************************************
5768 **  gckOS_CacheClean
5769 **
5770 **  Clean the cache for the specified addresses.  The GPU is going to need the
5771 **  data.  If the system is allocating memory as non-cachable, this function can
5772 **  be ignored.
5773 **
5774 **  ARGUMENTS:
5775 **
5776 **      gckOS Os
5777 **          Pointer to gckOS object.
5778 **
5779 **      gctUINT32 ProcessID
5780 **          Process ID Logical belongs.
5781 **
5782 **      gctPHYS_ADDR Handle
5783 **          Physical address handle.  If gcvNULL it is video memory.
5784 **
5785 **      gctPOINTER Physical
5786 **          Physical address to flush.
5787 **
5788 **      gctPOINTER Logical
5789 **          Logical address to flush.
5790 **
5791 **      gctSIZE_T Bytes
5792 **          Size of the address range in bytes to flush.
5793 */
5794 gceSTATUS
5795 gckOS_CacheClean(
5796     IN gckOS Os,
5797     IN gctUINT32 ProcessID,
5798     IN gctPHYS_ADDR Handle,
5799     IN gctUINT32 Physical,
5800     IN gctPOINTER Logical,
5801     IN gctSIZE_T Bytes
5802     )
5803 {
5804     gcsPLATFORM * platform;
5805
5806     gcmkHEADER_ARG("Os=0x%X ProcessID=%d Handle=0x%X Logical=0x%X Bytes=%lu",
5807                    Os, ProcessID, Handle, Logical, Bytes);
5808
5809     /* Verify the arguments. */
5810     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
5811     gcmkVERIFY_ARGUMENT(Logical != gcvNULL);
5812     gcmkVERIFY_ARGUMENT(Bytes > 0);
5813
5814     platform = Os->device->platform;
5815
5816     if (platform && platform->ops->cache)
5817     {
5818         platform->ops->cache(
5819             platform,
5820             ProcessID,
5821             Handle,
5822             Physical,
5823             Logical,
5824             Bytes,
5825             gcvCACHE_CLEAN
5826             );
5827
5828         /* Success. */
5829         gcmkFOOTER_NO();
5830         return gcvSTATUS_OK;
5831     }
5832
5833 #if !gcdCACHE_FUNCTION_UNIMPLEMENTED
5834 #ifdef CONFIG_ARM
5835
5836     /* Inner cache. */
5837 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35)
5838     dmac_map_area(Logical, Bytes, DMA_TO_DEVICE);
5839 #      else
5840     dmac_clean_range(Logical, Logical + Bytes);
5841 #      endif
5842
5843 #if defined(CONFIG_OUTER_CACHE)
5844     /* Outer cache. */
5845 #if gcdENABLE_OUTER_CACHE_PATCH
5846     _HandleOuterCache(Os, Physical, Logical, Bytes, gcvCACHE_CLEAN);
5847 #else
5848     outer_clean_range((unsigned long) Handle, (unsigned long) Handle + Bytes);
5849 #endif
5850 #endif
5851
5852 #elif defined(CONFIG_MIPS)
5853
5854     dma_cache_wback((unsigned long) Logical, Bytes);
5855
5856 #elif defined(CONFIG_PPC)
5857
5858     /* TODO */
5859
5860 #else
5861     dma_sync_single_for_device(
5862               gcvNULL,
5863               (dma_addr_t)Physical,
5864               Bytes,
5865               DMA_TO_DEVICE);
5866 #endif
5867 #endif
5868
5869     /* Success. */
5870     gcmkFOOTER_NO();
5871     return gcvSTATUS_OK;
5872 }
5873
5874 /*******************************************************************************
5875 **  gckOS_CacheInvalidate
5876 **
5877 **  Invalidate the cache for the specified addresses. The GPU is going to need
5878 **  data.  If the system is allocating memory as non-cachable, this function can
5879 **  be ignored.
5880 **
5881 **  ARGUMENTS:
5882 **
5883 **      gckOS Os
5884 **          Pointer to gckOS object.
5885 **
5886 **      gctUINT32 ProcessID
5887 **          Process ID Logical belongs.
5888 **
5889 **      gctPHYS_ADDR Handle
5890 **          Physical address handle.  If gcvNULL it is video memory.
5891 **
5892 **      gctPOINTER Logical
5893 **          Logical address to flush.
5894 **
5895 **      gctSIZE_T Bytes
5896 **          Size of the address range in bytes to flush.
5897 */
5898 gceSTATUS
5899 gckOS_CacheInvalidate(
5900     IN gckOS Os,
5901     IN gctUINT32 ProcessID,
5902     IN gctPHYS_ADDR Handle,
5903     IN gctUINT32 Physical,
5904     IN gctPOINTER Logical,
5905     IN gctSIZE_T Bytes
5906     )
5907 {
5908     gcsPLATFORM * platform;
5909
5910     gcmkHEADER_ARG("Os=0x%X ProcessID=%d Handle=0x%X Logical=0x%X Bytes=%lu",
5911                    Os, ProcessID, Handle, Logical, Bytes);
5912
5913     /* Verify the arguments. */
5914     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
5915     gcmkVERIFY_ARGUMENT(Logical != gcvNULL);
5916     gcmkVERIFY_ARGUMENT(Bytes > 0);
5917
5918     platform = Os->device->platform;
5919
5920     if (platform && platform->ops->cache)
5921     {
5922         platform->ops->cache(
5923             platform,
5924             ProcessID,
5925             Handle,
5926             Physical,
5927             Logical,
5928             Bytes,
5929             gcvCACHE_INVALIDATE
5930             );
5931
5932         /* Success. */
5933         gcmkFOOTER_NO();
5934         return gcvSTATUS_OK;
5935     }
5936
5937 #if !gcdCACHE_FUNCTION_UNIMPLEMENTED
5938 #ifdef CONFIG_ARM
5939
5940     /* Inner cache. */
5941 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35)
5942     dmac_map_area(Logical, Bytes, DMA_FROM_DEVICE);
5943 #      else
5944     dmac_inv_range(Logical, Logical + Bytes);
5945 #      endif
5946
5947 #if defined(CONFIG_OUTER_CACHE)
5948     /* Outer cache. */
5949 #if gcdENABLE_OUTER_CACHE_PATCH
5950     _HandleOuterCache(Os, Physical, Logical, Bytes, gcvCACHE_INVALIDATE);
5951 #else
5952     outer_inv_range((unsigned long) Handle, (unsigned long) Handle + Bytes);
5953 #endif
5954 #endif
5955
5956 #elif defined(CONFIG_MIPS)
5957     dma_cache_inv((unsigned long) Logical, Bytes);
5958 #elif defined(CONFIG_PPC)
5959     /* TODO */
5960 #else
5961     dma_sync_single_for_device(
5962               gcvNULL,
5963               (dma_addr_t)Physical,
5964               Bytes,
5965               DMA_FROM_DEVICE);
5966 #endif
5967 #endif
5968
5969     /* Success. */
5970     gcmkFOOTER_NO();
5971     return gcvSTATUS_OK;
5972 }
5973
5974 /*******************************************************************************
5975 **  gckOS_CacheFlush
5976 **
5977 **  Clean the cache for the specified addresses and invalidate the lines as
5978 **  well.  The GPU is going to need and modify the data.  If the system is
5979 **  allocating memory as non-cachable, this function can be ignored.
5980 **
5981 **  ARGUMENTS:
5982 **
5983 **      gckOS Os
5984 **          Pointer to gckOS object.
5985 **
5986 **      gctUINT32 ProcessID
5987 **          Process ID Logical belongs.
5988 **
5989 **      gctPHYS_ADDR Handle
5990 **          Physical address handle.  If gcvNULL it is video memory.
5991 **
5992 **      gctPOINTER Logical
5993 **          Logical address to flush.
5994 **
5995 **      gctSIZE_T Bytes
5996 **          Size of the address range in bytes to flush.
5997 */
5998 gceSTATUS
5999 gckOS_CacheFlush(
6000     IN gckOS Os,
6001     IN gctUINT32 ProcessID,
6002     IN gctPHYS_ADDR Handle,
6003     IN gctUINT32 Physical,
6004     IN gctPOINTER Logical,
6005     IN gctSIZE_T Bytes
6006     )
6007 {
6008     gcsPLATFORM * platform;
6009
6010     gcmkHEADER_ARG("Os=0x%X ProcessID=%d Handle=0x%X Logical=0x%X Bytes=%lu",
6011                    Os, ProcessID, Handle, Logical, Bytes);
6012
6013     /* Verify the arguments. */
6014     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
6015     gcmkVERIFY_ARGUMENT(Logical != gcvNULL);
6016     gcmkVERIFY_ARGUMENT(Bytes > 0);
6017
6018     platform = Os->device->platform;
6019
6020     if (platform && platform->ops->cache)
6021     {
6022         platform->ops->cache(
6023             platform,
6024             ProcessID,
6025             Handle,
6026             Physical,
6027             Logical,
6028             Bytes,
6029             gcvCACHE_FLUSH
6030             );
6031
6032         /* Success. */
6033         gcmkFOOTER_NO();
6034         return gcvSTATUS_OK;
6035     }
6036
6037 #if !gcdCACHE_FUNCTION_UNIMPLEMENTED
6038 #ifdef CONFIG_ARM
6039     /* Inner cache. */
6040     dmac_flush_range(Logical, Logical + Bytes);
6041
6042 #if defined(CONFIG_OUTER_CACHE)
6043     /* Outer cache. */
6044 #if gcdENABLE_OUTER_CACHE_PATCH
6045     _HandleOuterCache(Os, Physical, Logical, Bytes, gcvCACHE_FLUSH);
6046 #else
6047     outer_flush_range((unsigned long) Handle, (unsigned long) Handle + Bytes);
6048 #endif
6049 #endif
6050
6051 #elif defined(CONFIG_MIPS)
6052     dma_cache_wback_inv((unsigned long) Logical, Bytes);
6053 #elif defined(CONFIG_PPC)
6054     /* TODO */
6055 #else
6056     dma_sync_single_for_device(
6057               gcvNULL,
6058               (dma_addr_t)Physical,
6059               Bytes,
6060               DMA_BIDIRECTIONAL);
6061 #endif
6062 #endif
6063
6064     /* Success. */
6065     gcmkFOOTER_NO();
6066     return gcvSTATUS_OK;
6067 }
6068
6069 /*******************************************************************************
6070 ********************************* Broadcasting *********************************
6071 *******************************************************************************/
6072
6073 /*******************************************************************************
6074 **
6075 **  gckOS_Broadcast
6076 **
6077 **  System hook for broadcast events from the kernel driver.
6078 **
6079 **  INPUT:
6080 **
6081 **      gckOS Os
6082 **          Pointer to the gckOS object.
6083 **
6084 **      gckHARDWARE Hardware
6085 **          Pointer to the gckHARDWARE object.
6086 **
6087 **      gceBROADCAST Reason
6088 **          Reason for the broadcast.  Can be one of the following values:
6089 **
6090 **              gcvBROADCAST_GPU_IDLE
6091 **                  Broadcasted when the kernel driver thinks the GPU might be
6092 **                  idle.  This can be used to handle power management.
6093 **
6094 **              gcvBROADCAST_GPU_COMMIT
6095 **                  Broadcasted when any client process commits a command
6096 **                  buffer.  This can be used to handle power management.
6097 **
6098 **              gcvBROADCAST_GPU_STUCK
6099 **                  Broadcasted when the kernel driver hits the timeout waiting
6100 **                  for the GPU.
6101 **
6102 **              gcvBROADCAST_FIRST_PROCESS
6103 **                  First process is trying to connect to the kernel.
6104 **
6105 **              gcvBROADCAST_LAST_PROCESS
6106 **                  Last process has detached from the kernel.
6107 **
6108 **  OUTPUT:
6109 **
6110 **      Nothing.
6111 */
6112 gceSTATUS
6113 gckOS_Broadcast(
6114     IN gckOS Os,
6115     IN gckHARDWARE Hardware,
6116     IN gceBROADCAST Reason
6117     )
6118 {
6119     gceSTATUS status;
6120
6121     gcmkHEADER_ARG("Os=0x%X Hardware=0x%X Reason=%d", Os, Hardware, Reason);
6122
6123     /* Verify the arguments. */
6124     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
6125     gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
6126
6127     switch (Reason)
6128     {
6129     case gcvBROADCAST_FIRST_PROCESS:
6130         gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_OS, "First process has attached");
6131         break;
6132
6133     case gcvBROADCAST_LAST_PROCESS:
6134         gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_OS, "Last process has detached");
6135
6136         /* Put GPU OFF. */
6137         gcmkONERROR(
6138             gckHARDWARE_SetPowerManagementState(Hardware,
6139                                                 gcvPOWER_OFF_BROADCAST));
6140         break;
6141
6142     case gcvBROADCAST_GPU_IDLE:
6143         gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_OS, "GPU idle.");
6144
6145         /* Put GPU IDLE. */
6146         gcmkONERROR(
6147             gckHARDWARE_SetPowerManagementState(Hardware,
6148 #if gcdPOWER_SUSPEND_WHEN_IDLE
6149                                                 gcvPOWER_SUSPEND_BROADCAST));
6150 #else
6151                                                 gcvPOWER_IDLE_BROADCAST));
6152 #endif
6153
6154         /* Add idle process DB. */
6155         gcmkONERROR(gckKERNEL_AddProcessDB(Hardware->kernel,
6156                                            1,
6157                                            gcvDB_IDLE,
6158                                            gcvNULL, gcvNULL, 0));
6159         break;
6160
6161     case gcvBROADCAST_GPU_COMMIT:
6162         gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_OS, "COMMIT has arrived.");
6163
6164         /* Add busy process DB. */
6165         gcmkONERROR(gckKERNEL_AddProcessDB(Hardware->kernel,
6166                                            0,
6167                                            gcvDB_IDLE,
6168                                            gcvNULL, gcvNULL, 0));
6169
6170         /* Put GPU ON. */
6171         gcmkONERROR(
6172             gckHARDWARE_SetPowerManagementState(Hardware, gcvPOWER_ON_AUTO));
6173         break;
6174
6175     case gcvBROADCAST_GPU_STUCK:
6176         gcmkTRACE_N(gcvLEVEL_ERROR, 0, "gcvBROADCAST_GPU_STUCK\n");
6177         gcmkONERROR(gckKERNEL_Recovery(Hardware->kernel));
6178         break;
6179
6180     case gcvBROADCAST_AXI_BUS_ERROR:
6181         gcmkTRACE_N(gcvLEVEL_ERROR, 0, "gcvBROADCAST_AXI_BUS_ERROR\n");
6182         gcmkONERROR(gckHARDWARE_DumpGPUState(Hardware));
6183         gcmkONERROR(gckKERNEL_Recovery(Hardware->kernel));
6184         break;
6185
6186     case gcvBROADCAST_OUT_OF_MEMORY:
6187         gcmkTRACE_N(gcvLEVEL_INFO, 0, "gcvBROADCAST_OUT_OF_MEMORY\n");
6188
6189         status = _ShrinkMemory(Os);
6190
6191         if (status == gcvSTATUS_NOT_SUPPORTED)
6192         {
6193             goto OnError;
6194         }
6195
6196         gcmkONERROR(status);
6197
6198         break;
6199
6200     default:
6201         /* Skip unimplemented broadcast. */
6202         break;
6203     }
6204
6205     /* Success. */
6206     gcmkFOOTER_NO();
6207     return gcvSTATUS_OK;
6208
6209 OnError:
6210     /* Return the status. */
6211     gcmkFOOTER();
6212     return status;
6213 }
6214
6215 /*******************************************************************************
6216 **
6217 **  gckOS_BroadcastHurry
6218 **
6219 **  The GPU is running too slow.
6220 **
6221 **  INPUT:
6222 **
6223 **      gckOS Os
6224 **          Pointer to the gckOS object.
6225 **
6226 **      gckHARDWARE Hardware
6227 **          Pointer to the gckHARDWARE object.
6228 **
6229 **      gctUINT Urgency
6230 **          The higher the number, the higher the urgency to speed up the GPU.
6231 **          The maximum value is defined by the gcdDYNAMIC_EVENT_THRESHOLD.
6232 **
6233 **  OUTPUT:
6234 **
6235 **      Nothing.
6236 */
6237 gceSTATUS
6238 gckOS_BroadcastHurry(
6239     IN gckOS Os,
6240     IN gckHARDWARE Hardware,
6241     IN gctUINT Urgency
6242     )
6243 {
6244     gcmkHEADER_ARG("Os=0x%x Hardware=0x%x Urgency=%u", Os, Hardware, Urgency);
6245
6246     /* Do whatever you need to do to speed up the GPU now. */
6247
6248     /* Success. */
6249     gcmkFOOTER_NO();
6250     return gcvSTATUS_OK;
6251 }
6252
6253 /*******************************************************************************
6254 **
6255 **  gckOS_BroadcastCalibrateSpeed
6256 **
6257 **  Calibrate the speed of the GPU.
6258 **
6259 **  INPUT:
6260 **
6261 **      gckOS Os
6262 **          Pointer to the gckOS object.
6263 **
6264 **      gckHARDWARE Hardware
6265 **          Pointer to the gckHARDWARE object.
6266 **
6267 **      gctUINT Idle, Time
6268 **          Idle/Time will give the percentage the GPU is idle, so you can use
6269 **          this to calibrate the working point of the GPU.
6270 **
6271 **  OUTPUT:
6272 **
6273 **      Nothing.
6274 */
6275 gceSTATUS
6276 gckOS_BroadcastCalibrateSpeed(
6277     IN gckOS Os,
6278     IN gckHARDWARE Hardware,
6279     IN gctUINT Idle,
6280     IN gctUINT Time
6281     )
6282 {
6283     gcmkHEADER_ARG("Os=0x%x Hardware=0x%x Idle=%u Time=%u",
6284                    Os, Hardware, Idle, Time);
6285
6286     /* Do whatever you need to do to callibrate the GPU speed. */
6287
6288     /* Success. */
6289     gcmkFOOTER_NO();
6290     return gcvSTATUS_OK;
6291 }
6292
6293 /*******************************************************************************
6294 ********************************** Semaphores **********************************
6295 *******************************************************************************/
6296
6297 /*******************************************************************************
6298 **
6299 **  gckOS_CreateSemaphore
6300 **
6301 **  Create a semaphore.
6302 **
6303 **  INPUT:
6304 **
6305 **      gckOS Os
6306 **          Pointer to the gckOS object.
6307 **
6308 **  OUTPUT:
6309 **
6310 **      gctPOINTER * Semaphore
6311 **          Pointer to the variable that will receive the created semaphore.
6312 */
6313 gceSTATUS
6314 gckOS_CreateSemaphore(
6315     IN gckOS Os,
6316     OUT gctPOINTER * Semaphore
6317     )
6318 {
6319     gceSTATUS status;
6320     struct semaphore *sem = gcvNULL;
6321
6322     gcmkHEADER_ARG("Os=0x%X", Os);
6323
6324     /* Verify the arguments. */
6325     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
6326     gcmkVERIFY_ARGUMENT(Semaphore != gcvNULL);
6327
6328     /* Allocate the semaphore structure. */
6329     sem = (struct semaphore *)kmalloc(gcmSIZEOF(struct semaphore), GFP_KERNEL | gcdNOWARN);
6330     if (sem == gcvNULL)
6331     {
6332         gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
6333     }
6334
6335     /* Initialize the semaphore. */
6336     sema_init(sem, 1);
6337
6338     /* Return to caller. */
6339     *Semaphore = (gctPOINTER) sem;
6340
6341     /* Success. */
6342     gcmkFOOTER_NO();
6343     return gcvSTATUS_OK;
6344
6345 OnError:
6346     /* Return the status. */
6347     gcmkFOOTER();
6348     return status;
6349 }
6350
6351 /*******************************************************************************
6352 **
6353 **  gckOS_AcquireSemaphore
6354 **
6355 **  Acquire a semaphore.
6356 **
6357 **  INPUT:
6358 **
6359 **      gckOS Os
6360 **          Pointer to the gckOS object.
6361 **
6362 **      gctPOINTER Semaphore
6363 **          Pointer to the semaphore thet needs to be acquired.
6364 **
6365 **  OUTPUT:
6366 **
6367 **      Nothing.
6368 */
6369 gceSTATUS
6370 gckOS_AcquireSemaphore(
6371     IN gckOS Os,
6372     IN gctPOINTER Semaphore
6373     )
6374 {
6375     gceSTATUS status;
6376
6377     gcmkHEADER_ARG("Os=0x%08X Semaphore=0x%08X", Os, Semaphore);
6378
6379     /* Verify the arguments. */
6380     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
6381     gcmkVERIFY_ARGUMENT(Semaphore != gcvNULL);
6382
6383     /* Acquire the semaphore. */
6384     if (down_interruptible((struct semaphore *) Semaphore))
6385     {
6386         gcmkONERROR(gcvSTATUS_INTERRUPTED);
6387     }
6388
6389     /* Success. */
6390     gcmkFOOTER_NO();
6391     return gcvSTATUS_OK;
6392
6393 OnError:
6394     /* Return the status. */
6395     gcmkFOOTER();
6396     return status;
6397 }
6398
6399 /*******************************************************************************
6400 **
6401 **  gckOS_TryAcquireSemaphore
6402 **
6403 **  Try to acquire a semaphore.
6404 **
6405 **  INPUT:
6406 **
6407 **      gckOS Os
6408 **          Pointer to the gckOS object.
6409 **
6410 **      gctPOINTER Semaphore
6411 **          Pointer to the semaphore thet needs to be acquired.
6412 **
6413 **  OUTPUT:
6414 **
6415 **      Nothing.
6416 */
6417 gceSTATUS
6418 gckOS_TryAcquireSemaphore(
6419     IN gckOS Os,
6420     IN gctPOINTER Semaphore
6421     )
6422 {
6423     gceSTATUS status;
6424
6425     gcmkHEADER_ARG("Os=0x%x", Os);
6426
6427     /* Verify the arguments. */
6428     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
6429     gcmkVERIFY_ARGUMENT(Semaphore != gcvNULL);
6430
6431     /* Acquire the semaphore. */
6432     if (down_trylock((struct semaphore *) Semaphore))
6433     {
6434         /* Timeout. */
6435         status = gcvSTATUS_TIMEOUT;
6436         gcmkFOOTER();
6437         return status;
6438     }
6439
6440     /* Success. */
6441     gcmkFOOTER_NO();
6442     return gcvSTATUS_OK;
6443 }
6444
6445 /*******************************************************************************
6446 **
6447 **  gckOS_ReleaseSemaphore
6448 **
6449 **  Release a previously acquired semaphore.
6450 **
6451 **  INPUT:
6452 **
6453 **      gckOS Os
6454 **          Pointer to the gckOS object.
6455 **
6456 **      gctPOINTER Semaphore
6457 **          Pointer to the semaphore thet needs to be released.
6458 **
6459 **  OUTPUT:
6460 **
6461 **      Nothing.
6462 */
6463 gceSTATUS
6464 gckOS_ReleaseSemaphore(
6465     IN gckOS Os,
6466     IN gctPOINTER Semaphore
6467     )
6468 {
6469     gcmkHEADER_ARG("Os=0x%X Semaphore=0x%X", Os, Semaphore);
6470
6471     /* Verify the arguments. */
6472     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
6473     gcmkVERIFY_ARGUMENT(Semaphore != gcvNULL);
6474
6475     /* Release the semaphore. */
6476     up((struct semaphore *) Semaphore);
6477
6478     /* Success. */
6479     gcmkFOOTER_NO();
6480     return gcvSTATUS_OK;
6481 }
6482
6483 /*******************************************************************************
6484 **
6485 **  gckOS_DestroySemaphore
6486 **
6487 **  Destroy a semaphore.
6488 **
6489 **  INPUT:
6490 **
6491 **      gckOS Os
6492 **          Pointer to the gckOS object.
6493 **
6494 **      gctPOINTER Semaphore
6495 **          Pointer to the semaphore thet needs to be destroyed.
6496 **
6497 **  OUTPUT:
6498 **
6499 **      Nothing.
6500 */
6501 gceSTATUS
6502 gckOS_DestroySemaphore(
6503     IN gckOS Os,
6504     IN gctPOINTER Semaphore
6505     )
6506 {
6507     gcmkHEADER_ARG("Os=0x%X Semaphore=0x%X", Os, Semaphore);
6508
6509      /* Verify the arguments. */
6510     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
6511     gcmkVERIFY_ARGUMENT(Semaphore != gcvNULL);
6512
6513     /* Free the sempahore structure. */
6514     kfree(Semaphore);
6515
6516     /* Success. */
6517     gcmkFOOTER_NO();
6518     return gcvSTATUS_OK;
6519 }
6520
6521 /*******************************************************************************
6522 **
6523 **  gckOS_GetProcessID
6524 **
6525 **  Get current process ID.
6526 **
6527 **  INPUT:
6528 **
6529 **      Nothing.
6530 **
6531 **  OUTPUT:
6532 **
6533 **      gctUINT32_PTR ProcessID
6534 **          Pointer to the variable that receives the process ID.
6535 */
6536 gceSTATUS
6537 gckOS_GetProcessID(
6538     OUT gctUINT32_PTR ProcessID
6539     )
6540 {
6541     /* Get process ID. */
6542     if (ProcessID != gcvNULL)
6543     {
6544         *ProcessID = _GetProcessID();
6545     }
6546
6547     /* Success. */
6548     return gcvSTATUS_OK;
6549 }
6550
6551 /*******************************************************************************
6552 **
6553 **  gckOS_GetThreadID
6554 **
6555 **  Get current thread ID.
6556 **
6557 **  INPUT:
6558 **
6559 **      Nothing.
6560 **
6561 **  OUTPUT:
6562 **
6563 **      gctUINT32_PTR ThreadID
6564 **          Pointer to the variable that receives the thread ID.
6565 */
6566 gceSTATUS
6567 gckOS_GetThreadID(
6568     OUT gctUINT32_PTR ThreadID
6569     )
6570 {
6571     /* Get thread ID. */
6572     if (ThreadID != gcvNULL)
6573     {
6574         *ThreadID = _GetThreadID();
6575     }
6576
6577     /* Success. */
6578     return gcvSTATUS_OK;
6579 }
6580
6581 /*******************************************************************************
6582 **
6583 **  gckOS_SetGPUPower
6584 **
6585 **  Set the power of the GPU on or off.
6586 **
6587 **  INPUT:
6588 **
6589 **      gckOS Os
6590 **          Pointer to a gckOS object.
6591 **
6592 **      gceCORE Core
6593 **          GPU whose power is set.
6594 **
6595 **      gctBOOL Clock
6596 **          gcvTRUE to turn on the clock, or gcvFALSE to turn off the clock.
6597 **
6598 **      gctBOOL Power
6599 **          gcvTRUE to turn on the power, or gcvFALSE to turn off the power.
6600 **
6601 **  OUTPUT:
6602 **
6603 **      Nothing.
6604 */
6605 gceSTATUS
6606 gckOS_SetGPUPower(
6607     IN gckOS Os,
6608     IN gceCORE Core,
6609     IN gctBOOL Clock,
6610     IN gctBOOL Power
6611     )
6612 {
6613     gcsPLATFORM * platform;
6614
6615     gctBOOL powerChange = gcvFALSE;
6616     gctBOOL clockChange = gcvFALSE;
6617
6618     gcmkHEADER_ARG("Os=0x%X Core=%d Clock=%d Power=%d", Os, Core, Clock, Power);
6619     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
6620
6621     platform = Os->device->platform;
6622
6623     powerChange = (Power != Os->powerStates[Core]);
6624
6625     clockChange = (Clock != Os->clockStates[Core]);
6626
6627     if (powerChange && (Power == gcvTRUE))
6628     {
6629         if (platform && platform->ops->setPower)
6630         {
6631             gcmkVERIFY_OK(platform->ops->setPower(platform, Core, Power));
6632         }
6633
6634         Os->powerStates[Core] = Power;
6635     }
6636
6637     if (clockChange)
6638     {
6639         mutex_lock(&Os->registerAccessLocks[Core]);
6640
6641         if (platform && platform->ops->setClock)
6642         {
6643             gcmkVERIFY_OK(platform->ops->setClock(platform, Core, Clock));
6644         }
6645
6646         Os->clockStates[Core] = Clock;
6647
6648         mutex_unlock(&Os->registerAccessLocks[Core]);
6649     }
6650
6651     if (powerChange && (Power == gcvFALSE))
6652     {
6653         if (platform && platform->ops->setPower)
6654         {
6655             gcmkVERIFY_OK(platform->ops->setPower(platform, Core, Power));
6656         }
6657
6658         Os->powerStates[Core] = Power;
6659     }
6660
6661     gcmkFOOTER_NO();
6662     return gcvSTATUS_OK;
6663 }
6664
6665 /*******************************************************************************
6666 **
6667 **  gckOS_ResetGPU
6668 **
6669 **  Reset the GPU.
6670 **
6671 **  INPUT:
6672 **
6673 **      gckOS Os
6674 **          Pointer to a gckOS object.
6675 **
6676 **      gckCORE Core
6677 **          GPU whose power is set.
6678 **
6679 **  OUTPUT:
6680 **
6681 **      Nothing.
6682 */
6683 gceSTATUS
6684 gckOS_ResetGPU(
6685     IN gckOS Os,
6686     IN gceCORE Core
6687     )
6688 {
6689     gceSTATUS status = gcvSTATUS_NOT_SUPPORTED;
6690     gcsPLATFORM * platform;
6691
6692     gcmkHEADER_ARG("Os=0x%X Core=%d", Os, Core);
6693     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
6694
6695     platform = Os->device->platform;
6696
6697     if (platform && platform->ops->reset)
6698     {
6699         status = platform->ops->reset(platform, Core);
6700     }
6701
6702     gcmkFOOTER_NO();
6703     return status;
6704 }
6705
6706 /*******************************************************************************
6707 **
6708 **  gckOS_PrepareGPUFrequency
6709 **
6710 **  Prepare to set GPU frequency and voltage.
6711 **
6712 **  INPUT:
6713 **
6714 **      gckOS Os
6715 **          Pointer to a gckOS object.
6716 **
6717 **      gckCORE Core
6718 **          GPU whose frequency and voltage will be set.
6719 **
6720 **  OUTPUT:
6721 **
6722 **      Nothing.
6723 */
6724 gceSTATUS
6725 gckOS_PrepareGPUFrequency(
6726     IN gckOS Os,
6727     IN gceCORE Core
6728     )
6729 {
6730     return gcvSTATUS_OK;
6731 }
6732
6733 /*******************************************************************************
6734 **
6735 **  gckOS_FinishGPUFrequency
6736 **
6737 **  Finish GPU frequency setting.
6738 **
6739 **  INPUT:
6740 **
6741 **      gckOS Os
6742 **          Pointer to a gckOS object.
6743 **
6744 **      gckCORE Core
6745 **          GPU whose frequency and voltage is set.
6746 **
6747 **  OUTPUT:
6748 **
6749 **      Nothing.
6750 */
6751 gceSTATUS
6752 gckOS_FinishGPUFrequency(
6753     IN gckOS Os,
6754     IN gceCORE Core
6755     )
6756 {
6757     return gcvSTATUS_OK;
6758 }
6759
6760 /*******************************************************************************
6761 **
6762 **  gckOS_QueryGPUFrequency
6763 **
6764 **  Query the current frequency of the GPU.
6765 **
6766 **  INPUT:
6767 **
6768 **      gckOS Os
6769 **          Pointer to a gckOS object.
6770 **
6771 **      gckCORE Core
6772 **          GPU whose power is set.
6773 **
6774 **      gctUINT32 * Frequency
6775 **          Pointer to a gctUINT32 to obtain current frequency, in MHz.
6776 **
6777 **      gctUINT8 * Scale
6778 **          Pointer to a gctUINT8 to obtain current scale(1 - 64).
6779 **
6780 **  OUTPUT:
6781 **
6782 **      Nothing.
6783 */
6784 gceSTATUS
6785 gckOS_QueryGPUFrequency(
6786     IN gckOS Os,
6787     IN gceCORE Core,
6788     OUT gctUINT32 * Frequency,
6789     OUT gctUINT8 * Scale
6790     )
6791 {
6792     return gcvSTATUS_OK;
6793 }
6794
6795 /*******************************************************************************
6796 **
6797 **  gckOS_SetGPUFrequency
6798 **
6799 **  Set frequency and voltage of the GPU.
6800 **
6801 **      1. DVFS manager gives the target scale of full frequency, BSP must find
6802 **         a real frequency according to this scale and board's configure.
6803 **
6804 **      2. BSP should find a suitable voltage for this frequency.
6805 **
6806 **      3. BSP must make sure setting take effect before this function returns.
6807 **
6808 **  INPUT:
6809 **
6810 **      gckOS Os
6811 **          Pointer to a gckOS object.
6812 **
6813 **      gckCORE Core
6814 **          GPU whose power is set.
6815 **
6816 **      gctUINT8 Scale
6817 **          Target scale of full frequency, range is [1, 64]. 1 means 1/64 of
6818 **          full frequency and 64 means 64/64 of full frequency.
6819 **
6820 **  OUTPUT:
6821 **
6822 **      Nothing.
6823 */
6824 gceSTATUS
6825 gckOS_SetGPUFrequency(
6826     IN gckOS Os,
6827     IN gceCORE Core,
6828     IN gctUINT8 Scale
6829     )
6830 {
6831     return gcvSTATUS_OK;
6832 }
6833
6834 /*----------------------------------------------------------------------------*/
6835 /*----- Profile --------------------------------------------------------------*/
6836
6837 gceSTATUS
6838 gckOS_GetProfileTick(
6839     OUT gctUINT64_PTR Tick
6840     )
6841 {
6842     struct timespec time;
6843
6844     ktime_get_ts(&time);
6845
6846     *Tick = time.tv_nsec + time.tv_sec * 1000000000ULL;
6847
6848     return gcvSTATUS_OK;
6849 }
6850
6851 gceSTATUS
6852 gckOS_QueryProfileTickRate(
6853     OUT gctUINT64_PTR TickRate
6854     )
6855 {
6856     struct timespec res;
6857
6858     hrtimer_get_res(CLOCK_MONOTONIC, &res);
6859
6860     *TickRate = res.tv_nsec + res.tv_sec * 1000000000ULL;
6861
6862     return gcvSTATUS_OK;
6863 }
6864
6865 gctUINT32
6866 gckOS_ProfileToMS(
6867     IN gctUINT64 Ticks
6868     )
6869 {
6870 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,23)
6871     return div_u64(Ticks, 1000000);
6872 #else
6873     gctUINT64 rem = Ticks;
6874     gctUINT64 b = 1000000;
6875     gctUINT64 res, d = 1;
6876     gctUINT32 high = rem >> 32;
6877
6878     /* Reduce the thing a bit first */
6879     res = 0;
6880     if (high >= 1000000)
6881     {
6882         high /= 1000000;
6883         res   = (gctUINT64) high << 32;
6884         rem  -= (gctUINT64) (high * 1000000) << 32;
6885     }
6886
6887     while (((gctINT64) b > 0) && (b < rem))
6888     {
6889         b <<= 1;
6890         d <<= 1;
6891     }
6892
6893     do
6894     {
6895         if (rem >= b)
6896         {
6897             rem -= b;
6898             res += d;
6899         }
6900
6901         b >>= 1;
6902         d >>= 1;
6903     }
6904     while (d);
6905
6906     return (gctUINT32) res;
6907 #endif
6908 }
6909
6910 /******************************************************************************\
6911 ******************************* Signal Management ******************************
6912 \******************************************************************************/
6913
6914 #undef _GC_OBJ_ZONE
6915 #define _GC_OBJ_ZONE    gcvZONE_SIGNAL
6916
6917 /*******************************************************************************
6918 **
6919 **  gckOS_CreateSignal
6920 **
6921 **  Create a new signal.
6922 **
6923 **  INPUT:
6924 **
6925 **      gckOS Os
6926 **          Pointer to an gckOS object.
6927 **
6928 **      gctBOOL ManualReset
6929 **          If set to gcvTRUE, gckOS_Signal with gcvFALSE must be called in
6930 **          order to set the signal to nonsignaled state.
6931 **          If set to gcvFALSE, the signal will automatically be set to
6932 **          nonsignaled state by gckOS_WaitSignal function.
6933 **
6934 **  OUTPUT:
6935 **
6936 **      gctSIGNAL * Signal
6937 **          Pointer to a variable receiving the created gctSIGNAL.
6938 */
6939 gceSTATUS
6940 gckOS_CreateSignal(
6941     IN gckOS Os,
6942     IN gctBOOL ManualReset,
6943     OUT gctSIGNAL * Signal
6944     )
6945 {
6946     gceSTATUS status;
6947     gcsSIGNAL_PTR signal;
6948
6949     gcmkHEADER_ARG("Os=0x%X ManualReset=%d", Os, ManualReset);
6950
6951     /* Verify the arguments. */
6952     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
6953     gcmkVERIFY_ARGUMENT(Signal != gcvNULL);
6954
6955     /* Create an event structure. */
6956     signal = (gcsSIGNAL_PTR) kmalloc(sizeof(gcsSIGNAL), GFP_KERNEL | gcdNOWARN);
6957
6958     if (signal == gcvNULL)
6959     {
6960         gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
6961     }
6962
6963     /* Save the process ID. */
6964     signal->process = (gctHANDLE)(gctUINTPTR_T) _GetProcessID();
6965     signal->manualReset = ManualReset;
6966     signal->hardware = gcvNULL;
6967     init_completion(&signal->obj);
6968     atomic_set(&signal->ref, 1);
6969
6970     gcmkONERROR(_AllocateIntegerId(&Os->signalDB, signal, &signal->id));
6971
6972     *Signal = (gctSIGNAL)(gctUINTPTR_T)signal->id;
6973
6974     gcmkFOOTER_ARG("*Signal=0x%X", *Signal);
6975     return gcvSTATUS_OK;
6976
6977 OnError:
6978     if (signal != gcvNULL)
6979     {
6980         kfree(signal);
6981     }
6982
6983     gcmkFOOTER_NO();
6984     return status;
6985 }
6986
6987 gceSTATUS
6988 gckOS_SignalQueryHardware(
6989     IN gckOS Os,
6990     IN gctSIGNAL Signal,
6991     OUT gckHARDWARE * Hardware
6992     )
6993 {
6994     gceSTATUS status;
6995     gcsSIGNAL_PTR signal;
6996
6997     gcmkHEADER_ARG("Os=0x%X Signal=0x%X Hardware=0x%X", Os, Signal, Hardware);
6998
6999     /* Verify the arguments. */
7000     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
7001     gcmkVERIFY_ARGUMENT(Signal != gcvNULL);
7002     gcmkVERIFY_ARGUMENT(Hardware != gcvNULL);
7003
7004     gcmkONERROR(_QueryIntegerId(&Os->signalDB, (gctUINT32)(gctUINTPTR_T)Signal, (gctPOINTER)&signal));
7005
7006     *Hardware = signal->hardware;
7007
7008     gcmkFOOTER_NO();
7009     return gcvSTATUS_OK;
7010 OnError:
7011     gcmkFOOTER();
7012     return status;
7013 }
7014
7015 gceSTATUS
7016 gckOS_SignalSetHardware(
7017     IN gckOS Os,
7018     IN gctSIGNAL Signal,
7019     IN gckHARDWARE Hardware
7020     )
7021 {
7022     gceSTATUS status;
7023     gcsSIGNAL_PTR signal;
7024
7025     gcmkHEADER_ARG("Os=0x%X Signal=0x%X Hardware=0x%X", Os, Signal, Hardware);
7026
7027     /* Verify the arguments. */
7028     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
7029     gcmkVERIFY_ARGUMENT(Signal != gcvNULL);
7030
7031     gcmkONERROR(_QueryIntegerId(&Os->signalDB, (gctUINT32)(gctUINTPTR_T)Signal, (gctPOINTER)&signal));
7032
7033     signal->hardware = Hardware;
7034
7035     gcmkFOOTER_NO();
7036     return gcvSTATUS_OK;
7037 OnError:
7038     gcmkFOOTER();
7039     return status;
7040 }
7041
7042 /*******************************************************************************
7043 **
7044 **  gckOS_DestroySignal
7045 **
7046 **  Destroy a signal.
7047 **
7048 **  INPUT:
7049 **
7050 **      gckOS Os
7051 **          Pointer to an gckOS object.
7052 **
7053 **      gctSIGNAL Signal
7054 **          Pointer to the gctSIGNAL.
7055 **
7056 **  OUTPUT:
7057 **
7058 **      Nothing.
7059 */
7060 gceSTATUS
7061 gckOS_DestroySignal(
7062     IN gckOS Os,
7063     IN gctSIGNAL Signal
7064     )
7065 {
7066     gceSTATUS status;
7067     gcsSIGNAL_PTR signal;
7068     gctBOOL acquired = gcvFALSE;
7069
7070     gcmkHEADER_ARG("Os=0x%X Signal=0x%X", Os, Signal);
7071
7072     /* Verify the arguments. */
7073     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
7074     gcmkVERIFY_ARGUMENT(Signal != gcvNULL);
7075
7076     gcmkONERROR(gckOS_AcquireMutex(Os, Os->signalMutex, gcvINFINITE));
7077     acquired = gcvTRUE;
7078
7079     gcmkONERROR(_QueryIntegerId(&Os->signalDB, (gctUINT32)(gctUINTPTR_T)Signal, (gctPOINTER)&signal));
7080
7081     gcmkASSERT(signal->id == (gctUINT32)(gctUINTPTR_T)Signal);
7082
7083     if (atomic_dec_and_test(&signal->ref))
7084     {
7085         gcmkVERIFY_OK(_DestroyIntegerId(&Os->signalDB, signal->id));
7086
7087         /* Free the sgianl. */
7088         kfree(signal);
7089     }
7090
7091     gcmkVERIFY_OK(gckOS_ReleaseMutex(Os, Os->signalMutex));
7092     acquired = gcvFALSE;
7093
7094     /* Success. */
7095     gcmkFOOTER_NO();
7096     return gcvSTATUS_OK;
7097
7098 OnError:
7099     if (acquired)
7100     {
7101         /* Release the mutex. */
7102         gcmkVERIFY_OK(gckOS_ReleaseMutex(Os, Os->signalMutex));
7103     }
7104
7105     gcmkFOOTER();
7106     return status;
7107 }
7108
7109 /*******************************************************************************
7110 **
7111 **  gckOS_Signal
7112 **
7113 **  Set a state of the specified signal.
7114 **
7115 **  INPUT:
7116 **
7117 **      gckOS Os
7118 **          Pointer to an gckOS object.
7119 **
7120 **      gctSIGNAL Signal
7121 **          Pointer to the gctSIGNAL.
7122 **
7123 **      gctBOOL State
7124 **          If gcvTRUE, the signal will be set to signaled state.
7125 **          If gcvFALSE, the signal will be set to nonsignaled state.
7126 **
7127 **  OUTPUT:
7128 **
7129 **      Nothing.
7130 */
7131 gceSTATUS
7132 gckOS_Signal(
7133     IN gckOS Os,
7134     IN gctSIGNAL Signal,
7135     IN gctBOOL State
7136     )
7137 {
7138     gceSTATUS status;
7139     gcsSIGNAL_PTR signal;
7140     gctBOOL acquired = gcvFALSE;
7141
7142     gcmkHEADER_ARG("Os=0x%X Signal=0x%X State=%d", Os, Signal, State);
7143
7144     /* Verify the arguments. */
7145     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
7146     gcmkVERIFY_ARGUMENT(Signal != gcvNULL);
7147
7148     gcmkONERROR(gckOS_AcquireMutex(Os, Os->signalMutex, gcvINFINITE));
7149     acquired = gcvTRUE;
7150
7151     gcmkONERROR(_QueryIntegerId(&Os->signalDB, (gctUINT32)(gctUINTPTR_T)Signal, (gctPOINTER)&signal));
7152
7153     gcmkASSERT(signal->id == (gctUINT32)(gctUINTPTR_T)Signal);
7154
7155     if (State)
7156     {
7157         /* unbind the signal from hardware. */
7158         signal->hardware = gcvNULL;
7159
7160         /* Set the event to a signaled state. */
7161         complete(&signal->obj);
7162     }
7163     else
7164     {
7165         /* Set the event to an unsignaled state. */
7166 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,13,0)
7167         reinit_completion(&signal->obj);
7168 #else
7169         INIT_COMPLETION(signal->obj);
7170 #endif
7171     }
7172
7173     gcmkVERIFY_OK(gckOS_ReleaseMutex(Os, Os->signalMutex));
7174     acquired = gcvFALSE;
7175
7176     /* Success. */
7177     gcmkFOOTER_NO();
7178     return gcvSTATUS_OK;
7179
7180 OnError:
7181     if (acquired)
7182     {
7183         /* Release the mutex. */
7184         gcmkVERIFY_OK(gckOS_ReleaseMutex(Os, Os->signalMutex));
7185     }
7186
7187     gcmkFOOTER();
7188     return status;
7189 }
7190
7191 #if gcdENABLE_VG
7192 gceSTATUS
7193 gckOS_SetSignalVG(
7194     IN gckOS Os,
7195     IN gctHANDLE Process,
7196     IN gctSIGNAL Signal
7197     )
7198 {
7199     gceSTATUS status;
7200     gctINT result;
7201     struct task_struct * userTask;
7202     struct siginfo info;
7203
7204     userTask = FIND_TASK_BY_PID((pid_t)(gctUINTPTR_T) Process);
7205
7206     if (userTask != gcvNULL)
7207     {
7208         info.si_signo = 48;
7209         info.si_code  = __SI_CODE(__SI_RT, SI_KERNEL);
7210         info.si_pid   = 0;
7211         info.si_uid   = 0;
7212         info.si_ptr   = (gctPOINTER) Signal;
7213
7214         /* Signals with numbers between 32 and 63 are real-time,
7215            send a real-time signal to the user process. */
7216         result = send_sig_info(48, &info, userTask);
7217
7218         printk("gckOS_SetSignalVG:0x%x\n", result);
7219         /* Error? */
7220         if (result < 0)
7221         {
7222             status = gcvSTATUS_GENERIC_IO;
7223
7224             gcmkTRACE(
7225                 gcvLEVEL_ERROR,
7226                 "%s(%d): an error has occurred.\n",
7227                 __FUNCTION__, __LINE__
7228                 );
7229         }
7230         else
7231         {
7232             status = gcvSTATUS_OK;
7233         }
7234     }
7235     else
7236     {
7237         status = gcvSTATUS_GENERIC_IO;
7238
7239         gcmkTRACE(
7240             gcvLEVEL_ERROR,
7241             "%s(%d): an error has occurred.\n",
7242             __FUNCTION__, __LINE__
7243             );
7244     }
7245
7246     /* Return status. */
7247     return status;
7248 }
7249 #endif
7250
7251 /*******************************************************************************
7252 **
7253 **  gckOS_UserSignal
7254 **
7255 **  Set the specified signal which is owned by a process to signaled state.
7256 **
7257 **  INPUT:
7258 **
7259 **      gckOS Os
7260 **          Pointer to an gckOS object.
7261 **
7262 **      gctSIGNAL Signal
7263 **          Pointer to the gctSIGNAL.
7264 **
7265 **      gctHANDLE Process
7266 **          Handle of process owning the signal.
7267 **
7268 **  OUTPUT:
7269 **
7270 **      Nothing.
7271 */
7272 gceSTATUS
7273 gckOS_UserSignal(
7274     IN gckOS Os,
7275     IN gctSIGNAL Signal,
7276     IN gctHANDLE Process
7277     )
7278 {
7279     gceSTATUS status;
7280     gctSIGNAL signal;
7281
7282     gcmkHEADER_ARG("Os=0x%X Signal=0x%X Process=%d",
7283                    Os, Signal, (gctINT32)(gctUINTPTR_T)Process);
7284
7285     /* Map the signal into kernel space. */
7286     gcmkONERROR(gckOS_MapSignal(Os, Signal, Process, &signal));
7287
7288     /* Signal. */
7289     status = gckOS_Signal(Os, signal, gcvTRUE);
7290
7291     /* Unmap the signal */
7292     gcmkVERIFY_OK(gckOS_UnmapSignal(Os, Signal));
7293
7294     gcmkFOOTER();
7295     return status;
7296
7297 OnError:
7298     /* Return the status. */
7299     gcmkFOOTER();
7300     return status;
7301 }
7302
7303 /*******************************************************************************
7304 **
7305 **  gckOS_WaitSignal
7306 **
7307 **  Wait for a signal to become signaled.
7308 **
7309 **  INPUT:
7310 **
7311 **      gckOS Os
7312 **          Pointer to an gckOS object.
7313 **
7314 **      gctSIGNAL Signal
7315 **          Pointer to the gctSIGNAL.
7316 **
7317 **      gctUINT32 Wait
7318 **          Number of milliseconds to wait.
7319 **          Pass the value of gcvINFINITE for an infinite wait.
7320 **
7321 **  OUTPUT:
7322 **
7323 **      Nothing.
7324 */
7325 gceSTATUS
7326 gckOS_WaitSignal(
7327     IN gckOS Os,
7328     IN gctSIGNAL Signal,
7329     IN gctUINT32 Wait
7330     )
7331 {
7332     gceSTATUS status = gcvSTATUS_OK;
7333     gcsSIGNAL_PTR signal;
7334
7335     gcmkHEADER_ARG("Os=0x%X Signal=0x%X Wait=0x%08X", Os, Signal, Wait);
7336
7337     /* Verify the arguments. */
7338     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
7339     gcmkVERIFY_ARGUMENT(Signal != gcvNULL);
7340
7341     gcmkONERROR(_QueryIntegerId(&Os->signalDB, (gctUINT32)(gctUINTPTR_T)Signal, (gctPOINTER)&signal));
7342
7343     gcmkASSERT(signal->id == (gctUINT32)(gctUINTPTR_T)Signal);
7344
7345     might_sleep();
7346
7347     spin_lock_irq(&signal->obj.wait.lock);
7348
7349     if (signal->obj.done)
7350     {
7351         if (!signal->manualReset)
7352         {
7353             signal->obj.done = 0;
7354         }
7355
7356         status = gcvSTATUS_OK;
7357     }
7358     else if (Wait == 0)
7359     {
7360         status = gcvSTATUS_TIMEOUT;
7361     }
7362     else
7363     {
7364         /* Convert wait to milliseconds. */
7365         long timeout = (Wait == gcvINFINITE)
7366             ? MAX_SCHEDULE_TIMEOUT
7367             : Wait * HZ / 1000;
7368
7369         DECLARE_WAITQUEUE(wait, current);
7370         wait.flags |= WQ_FLAG_EXCLUSIVE;
7371         __add_wait_queue_tail(&signal->obj.wait, &wait);
7372
7373         while (gcvTRUE)
7374         {
7375             if (signal_pending(current))
7376             {
7377                 /* Interrupt received. */
7378                 status = gcvSTATUS_INTERRUPTED;
7379                 break;
7380             }
7381
7382             __set_current_state(TASK_INTERRUPTIBLE);
7383             spin_unlock_irq(&signal->obj.wait.lock);
7384             timeout = schedule_timeout(timeout);
7385             spin_lock_irq(&signal->obj.wait.lock);
7386
7387             if (signal->obj.done)
7388             {
7389                 if (!signal->manualReset)
7390                 {
7391                     signal->obj.done = 0;
7392                 }
7393
7394                 status = gcvSTATUS_OK;
7395                 break;
7396             }
7397
7398             if (timeout == 0)
7399             {
7400
7401                 status = gcvSTATUS_TIMEOUT;
7402                 break;
7403             }
7404         }
7405
7406         __remove_wait_queue(&signal->obj.wait, &wait);
7407     }
7408
7409     spin_unlock_irq(&signal->obj.wait.lock);
7410
7411 OnError:
7412     /* Return status. */
7413     gcmkFOOTER_ARG("Signal=0x%X status=%d", Signal, status);
7414     return status;
7415 }
7416
7417 /*******************************************************************************
7418 **
7419 **  gckOS_MapSignal
7420 **
7421 **  Map a signal in to the current process space.
7422 **
7423 **  INPUT:
7424 **
7425 **      gckOS Os
7426 **          Pointer to an gckOS object.
7427 **
7428 **      gctSIGNAL Signal
7429 **          Pointer to tha gctSIGNAL to map.
7430 **
7431 **      gctHANDLE Process
7432 **          Handle of process owning the signal.
7433 **
7434 **  OUTPUT:
7435 **
7436 **      gctSIGNAL * MappedSignal
7437 **          Pointer to a variable receiving the mapped gctSIGNAL.
7438 */
7439 gceSTATUS
7440 gckOS_MapSignal(
7441     IN gckOS Os,
7442     IN gctSIGNAL Signal,
7443     IN gctHANDLE Process,
7444     OUT gctSIGNAL * MappedSignal
7445     )
7446 {
7447     gceSTATUS status;
7448     gcsSIGNAL_PTR signal;
7449     gcmkHEADER_ARG("Os=0x%X Signal=0x%X Process=0x%X", Os, Signal, Process);
7450
7451     gcmkVERIFY_ARGUMENT(Signal != gcvNULL);
7452     gcmkVERIFY_ARGUMENT(MappedSignal != gcvNULL);
7453
7454     gcmkONERROR(_QueryIntegerId(&Os->signalDB, (gctUINT32)(gctUINTPTR_T)Signal, (gctPOINTER)&signal));
7455
7456     if(atomic_inc_return(&signal->ref) <= 1)
7457     {
7458         /* The previous value is 0, it has been deleted. */
7459         gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
7460     }
7461
7462     *MappedSignal = (gctSIGNAL) Signal;
7463
7464     /* Success. */
7465     gcmkFOOTER_ARG("*MappedSignal=0x%X", *MappedSignal);
7466     return gcvSTATUS_OK;
7467
7468 OnError:
7469     gcmkFOOTER_NO();
7470     return status;
7471 }
7472
7473 /*******************************************************************************
7474 **
7475 **  gckOS_UnmapSignal
7476 **
7477 **  Unmap a signal .
7478 **
7479 **  INPUT:
7480 **
7481 **      gckOS Os
7482 **          Pointer to an gckOS object.
7483 **
7484 **      gctSIGNAL Signal
7485 **          Pointer to that gctSIGNAL mapped.
7486 */
7487 gceSTATUS
7488 gckOS_UnmapSignal(
7489     IN gckOS Os,
7490     IN gctSIGNAL Signal
7491     )
7492 {
7493     return gckOS_DestroySignal(Os, Signal);
7494 }
7495
7496 /*******************************************************************************
7497 **
7498 **  gckOS_CreateUserSignal
7499 **
7500 **  Create a new signal to be used in the user space.
7501 **
7502 **  INPUT:
7503 **
7504 **      gckOS Os
7505 **          Pointer to an gckOS object.
7506 **
7507 **      gctBOOL ManualReset
7508 **          If set to gcvTRUE, gckOS_Signal with gcvFALSE must be called in
7509 **          order to set the signal to nonsignaled state.
7510 **          If set to gcvFALSE, the signal will automatically be set to
7511 **          nonsignaled state by gckOS_WaitSignal function.
7512 **
7513 **  OUTPUT:
7514 **
7515 **      gctINT * SignalID
7516 **          Pointer to a variable receiving the created signal's ID.
7517 */
7518 gceSTATUS
7519 gckOS_CreateUserSignal(
7520     IN gckOS Os,
7521     IN gctBOOL ManualReset,
7522     OUT gctINT * SignalID
7523     )
7524 {
7525     gceSTATUS status;
7526     gctSIZE_T signal;
7527
7528     /* Create a new signal. */
7529     gcmkONERROR(gckOS_CreateSignal(Os, ManualReset, (gctSIGNAL *) &signal));
7530     *SignalID = (gctINT) signal;
7531
7532 OnError:
7533     return status;
7534 }
7535
7536 /*******************************************************************************
7537 **
7538 **  gckOS_DestroyUserSignal
7539 **
7540 **  Destroy a signal to be used in the user space.
7541 **
7542 **  INPUT:
7543 **
7544 **      gckOS Os
7545 **          Pointer to an gckOS object.
7546 **
7547 **      gctINT SignalID
7548 **          The signal's ID.
7549 **
7550 **  OUTPUT:
7551 **
7552 **      Nothing.
7553 */
7554 gceSTATUS
7555 gckOS_DestroyUserSignal(
7556     IN gckOS Os,
7557     IN gctINT SignalID
7558     )
7559 {
7560     return gckOS_DestroySignal(Os, (gctSIGNAL)(gctUINTPTR_T)SignalID);
7561 }
7562
7563 /*******************************************************************************
7564 **
7565 **  gckOS_WaitUserSignal
7566 **
7567 **  Wait for a signal used in the user mode to become signaled.
7568 **
7569 **  INPUT:
7570 **
7571 **      gckOS Os
7572 **          Pointer to an gckOS object.
7573 **
7574 **      gctINT SignalID
7575 **          Signal ID.
7576 **
7577 **      gctUINT32 Wait
7578 **          Number of milliseconds to wait.
7579 **          Pass the value of gcvINFINITE for an infinite wait.
7580 **
7581 **  OUTPUT:
7582 **
7583 **      Nothing.
7584 */
7585 gceSTATUS
7586 gckOS_WaitUserSignal(
7587     IN gckOS Os,
7588     IN gctINT SignalID,
7589     IN gctUINT32 Wait
7590     )
7591 {
7592     return gckOS_WaitSignal(Os, (gctSIGNAL)(gctUINTPTR_T)SignalID, Wait);
7593 }
7594
7595 /*******************************************************************************
7596 **
7597 **  gckOS_SignalUserSignal
7598 **
7599 **  Set a state of the specified signal to be used in the user space.
7600 **
7601 **  INPUT:
7602 **
7603 **      gckOS Os
7604 **          Pointer to an gckOS object.
7605 **
7606 **      gctINT SignalID
7607 **          SignalID.
7608 **
7609 **      gctBOOL State
7610 **          If gcvTRUE, the signal will be set to signaled state.
7611 **          If gcvFALSE, the signal will be set to nonsignaled state.
7612 **
7613 **  OUTPUT:
7614 **
7615 **      Nothing.
7616 */
7617 gceSTATUS
7618 gckOS_SignalUserSignal(
7619     IN gckOS Os,
7620     IN gctINT SignalID,
7621     IN gctBOOL State
7622     )
7623 {
7624     return gckOS_Signal(Os, (gctSIGNAL)(gctUINTPTR_T)SignalID, State);
7625 }
7626
7627 #if gcdENABLE_VG
7628 gceSTATUS
7629 gckOS_CreateSemaphoreVG(
7630     IN gckOS Os,
7631     OUT gctSEMAPHORE * Semaphore
7632     )
7633 {
7634     gceSTATUS status;
7635     struct semaphore * newSemaphore;
7636
7637     gcmkHEADER_ARG("Os=0x%X Semaphore=0x%x", Os, Semaphore);
7638     /* Verify the arguments. */
7639     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
7640     gcmkVERIFY_ARGUMENT(Semaphore != gcvNULL);
7641
7642     do
7643     {
7644         /* Allocate the semaphore structure. */
7645         newSemaphore = (struct semaphore *)kmalloc(gcmSIZEOF(struct semaphore), GFP_KERNEL | gcdNOWARN);
7646         if (newSemaphore == gcvNULL)
7647         {
7648             gcmkERR_BREAK(gcvSTATUS_OUT_OF_MEMORY);
7649         }
7650
7651         /* Initialize the semaphore. */
7652         sema_init(newSemaphore, 0);
7653
7654         /* Set the handle. */
7655         * Semaphore = (gctSEMAPHORE) newSemaphore;
7656
7657         /* Success. */
7658         status = gcvSTATUS_OK;
7659     }
7660     while (gcvFALSE);
7661
7662     gcmkFOOTER();
7663     /* Return the status. */
7664     return status;
7665 }
7666
7667
7668 gceSTATUS
7669 gckOS_IncrementSemaphore(
7670     IN gckOS Os,
7671     IN gctSEMAPHORE Semaphore
7672     )
7673 {
7674     gcmkHEADER_ARG("Os=0x%X Semaphore=0x%x", Os, Semaphore);
7675     /* Verify the arguments. */
7676     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
7677     gcmkVERIFY_ARGUMENT(Semaphore != gcvNULL);
7678
7679     /* Increment the semaphore's count. */
7680     up((struct semaphore *) Semaphore);
7681
7682     gcmkFOOTER_NO();
7683     /* Success. */
7684     return gcvSTATUS_OK;
7685 }
7686
7687 gceSTATUS
7688 gckOS_DecrementSemaphore(
7689     IN gckOS Os,
7690     IN gctSEMAPHORE Semaphore
7691     )
7692 {
7693     gceSTATUS status;
7694     gctINT result;
7695
7696     gcmkHEADER_ARG("Os=0x%X Semaphore=0x%x", Os, Semaphore);
7697     /* Verify the arguments. */
7698     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
7699     gcmkVERIFY_ARGUMENT(Semaphore != gcvNULL);
7700
7701     do
7702     {
7703         /* Decrement the semaphore's count. If the count is zero, wait
7704            until it gets incremented. */
7705         result = down_interruptible((struct semaphore *) Semaphore);
7706
7707         /* Signal received? */
7708         if (result != 0)
7709         {
7710             status = gcvSTATUS_TERMINATE;
7711             break;
7712         }
7713
7714         /* Success. */
7715         status = gcvSTATUS_OK;
7716     }
7717     while (gcvFALSE);
7718
7719     gcmkFOOTER();
7720     /* Return the status. */
7721     return status;
7722 }
7723
7724 /*******************************************************************************
7725 **
7726 **  gckOS_SetSignal
7727 **
7728 **  Set the specified signal to signaled state.
7729 **
7730 **  INPUT:
7731 **
7732 **      gckOS Os
7733 **          Pointer to the gckOS object.
7734 **
7735 **      gctHANDLE Process
7736 **          Handle of process owning the signal.
7737 **
7738 **      gctSIGNAL Signal
7739 **          Pointer to the gctSIGNAL.
7740 **
7741 **  OUTPUT:
7742 **
7743 **      Nothing.
7744 */
7745 gceSTATUS
7746 gckOS_SetSignal(
7747     IN gckOS Os,
7748     IN gctHANDLE Process,
7749     IN gctSIGNAL Signal
7750     )
7751 {
7752     gceSTATUS status;
7753     gctINT result;
7754     struct task_struct * userTask;
7755     struct siginfo info;
7756
7757     userTask = FIND_TASK_BY_PID((pid_t)(gctUINTPTR_T) Process);
7758
7759     if (userTask != gcvNULL)
7760     {
7761         info.si_signo = 48;
7762         info.si_code  = __SI_CODE(__SI_RT, SI_KERNEL);
7763         info.si_pid   = 0;
7764         info.si_uid   = 0;
7765         info.si_ptr   = (gctPOINTER) Signal;
7766
7767         /* Signals with numbers between 32 and 63 are real-time,
7768            send a real-time signal to the user process. */
7769         result = send_sig_info(48, &info, userTask);
7770
7771         /* Error? */
7772         if (result < 0)
7773         {
7774             status = gcvSTATUS_GENERIC_IO;
7775
7776             gcmkTRACE(
7777                 gcvLEVEL_ERROR,
7778                 "%s(%d): an error has occurred.\n",
7779                 __FUNCTION__, __LINE__
7780                 );
7781         }
7782         else
7783         {
7784             status = gcvSTATUS_OK;
7785         }
7786     }
7787     else
7788     {
7789         status = gcvSTATUS_GENERIC_IO;
7790
7791         gcmkTRACE(
7792             gcvLEVEL_ERROR,
7793             "%s(%d): an error has occurred.\n",
7794             __FUNCTION__, __LINE__
7795             );
7796     }
7797
7798     /* Return status. */
7799     return status;
7800 }
7801
7802 /******************************************************************************\
7803 ******************************** Thread Object *********************************
7804 \******************************************************************************/
7805
7806 gceSTATUS
7807 gckOS_StartThread(
7808     IN gckOS Os,
7809     IN gctTHREADFUNC ThreadFunction,
7810     IN gctPOINTER ThreadParameter,
7811     OUT gctTHREAD * Thread
7812     )
7813 {
7814     gceSTATUS status;
7815     struct task_struct * thread;
7816
7817     gcmkHEADER_ARG("Os=0x%X ", Os);
7818     /* Verify the arguments. */
7819     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
7820     gcmkVERIFY_ARGUMENT(ThreadFunction != gcvNULL);
7821     gcmkVERIFY_ARGUMENT(Thread != gcvNULL);
7822
7823     do
7824     {
7825         /* Create the thread. */
7826         thread = kthread_create(
7827             ThreadFunction,
7828             ThreadParameter,
7829             "Vivante Kernel Thread"
7830             );
7831
7832         /* Failed? */
7833         if (IS_ERR(thread))
7834         {
7835             status = gcvSTATUS_GENERIC_IO;
7836             break;
7837         }
7838
7839         /* Start the thread. */
7840         wake_up_process(thread);
7841
7842         /* Set the thread handle. */
7843         * Thread = (gctTHREAD) thread;
7844
7845         /* Success. */
7846         status = gcvSTATUS_OK;
7847     }
7848     while (gcvFALSE);
7849
7850     gcmkFOOTER();
7851     /* Return the status. */
7852     return status;
7853 }
7854
7855 gceSTATUS
7856 gckOS_StopThread(
7857     IN gckOS Os,
7858     IN gctTHREAD Thread
7859     )
7860 {
7861     gcmkHEADER_ARG("Os=0x%X Thread=0x%x", Os, Thread);
7862     /* Verify the arguments. */
7863     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
7864     gcmkVERIFY_ARGUMENT(Thread != gcvNULL);
7865
7866     /* Thread should have already been enabled to terminate. */
7867     kthread_stop((struct task_struct *) Thread);
7868
7869     gcmkFOOTER_NO();
7870     /* Success. */
7871     return gcvSTATUS_OK;
7872 }
7873
7874 gceSTATUS
7875 gckOS_VerifyThread(
7876     IN gckOS Os,
7877     IN gctTHREAD Thread
7878     )
7879 {
7880     gcmkHEADER_ARG("Os=0x%X Thread=0x%x", Os, Thread);
7881     /* Verify the arguments. */
7882     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
7883     gcmkVERIFY_ARGUMENT(Thread != gcvNULL);
7884
7885     gcmkFOOTER_NO();
7886     /* Success. */
7887     return gcvSTATUS_OK;
7888 }
7889 #endif
7890
7891 /******************************************************************************\
7892 ******************************** Software Timer ********************************
7893 \******************************************************************************/
7894
7895 void
7896 _TimerFunction(
7897     struct work_struct * work
7898     )
7899 {
7900     gcsOSTIMER_PTR timer = (gcsOSTIMER_PTR)work;
7901
7902     gctTIMERFUNCTION function = timer->function;
7903
7904     function(timer->data);
7905 }
7906
7907 /*******************************************************************************
7908 **
7909 **  gckOS_CreateTimer
7910 **
7911 **  Create a software timer.
7912 **
7913 **  INPUT:
7914 **
7915 **      gckOS Os
7916 **          Pointer to the gckOS object.
7917 **
7918 **      gctTIMERFUNCTION Function.
7919 **          Pointer to a call back function which will be called when timer is
7920 **          expired.
7921 **
7922 **      gctPOINTER Data.
7923 **          Private data which will be passed to call back function.
7924 **
7925 **  OUTPUT:
7926 **
7927 **      gctPOINTER * Timer
7928 **          Pointer to a variable receiving the created timer.
7929 */
7930 gceSTATUS
7931 gckOS_CreateTimer(
7932     IN gckOS Os,
7933     IN gctTIMERFUNCTION Function,
7934     IN gctPOINTER Data,
7935     OUT gctPOINTER * Timer
7936     )
7937 {
7938     gceSTATUS status;
7939     gcsOSTIMER_PTR pointer;
7940     gcmkHEADER_ARG("Os=0x%X Function=0x%X Data=0x%X", Os, Function, Data);
7941
7942     /* Verify the arguments. */
7943     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
7944     gcmkVERIFY_ARGUMENT(Timer != gcvNULL);
7945
7946     gcmkONERROR(gckOS_Allocate(Os, sizeof(gcsOSTIMER), (gctPOINTER)&pointer));
7947
7948     pointer->function = Function;
7949     pointer->data = Data;
7950
7951     INIT_DELAYED_WORK(&pointer->work, _TimerFunction);
7952
7953     *Timer = pointer;
7954
7955     gcmkFOOTER_NO();
7956     return gcvSTATUS_OK;
7957
7958 OnError:
7959     gcmkFOOTER();
7960     return status;
7961 }
7962
7963 /*******************************************************************************
7964 **
7965 **  gckOS_DestroyTimer
7966 **
7967 **  Destory a software timer.
7968 **
7969 **  INPUT:
7970 **
7971 **      gckOS Os
7972 **          Pointer to the gckOS object.
7973 **
7974 **      gctPOINTER Timer
7975 **          Pointer to the timer to be destoryed.
7976 **
7977 **  OUTPUT:
7978 **
7979 **      Nothing.
7980 */
7981 gceSTATUS
7982 gckOS_DestroyTimer(
7983     IN gckOS Os,
7984     IN gctPOINTER Timer
7985     )
7986 {
7987     gcsOSTIMER_PTR timer;
7988     gcmkHEADER_ARG("Os=0x%X Timer=0x%X", Os, Timer);
7989
7990     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
7991     gcmkVERIFY_ARGUMENT(Timer != gcvNULL);
7992
7993     timer = (gcsOSTIMER_PTR)Timer;
7994
7995 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23)
7996     cancel_delayed_work_sync(&timer->work);
7997 #else
7998     cancel_delayed_work(&timer->work);
7999     flush_workqueue(Os->workqueue);
8000 #endif
8001
8002     gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Os, Timer));
8003
8004     gcmkFOOTER_NO();
8005     return gcvSTATUS_OK;
8006 }
8007
8008 /*******************************************************************************
8009 **
8010 **  gckOS_StartTimer
8011 **
8012 **  Schedule a software timer.
8013 **
8014 **  INPUT:
8015 **
8016 **      gckOS Os
8017 **          Pointer to the gckOS object.
8018 **
8019 **      gctPOINTER Timer
8020 **          Pointer to the timer to be scheduled.
8021 **
8022 **      gctUINT32 Delay
8023 **          Delay in milliseconds.
8024 **
8025 **  OUTPUT:
8026 **
8027 **      Nothing.
8028 */
8029 gceSTATUS
8030 gckOS_StartTimer(
8031     IN gckOS Os,
8032     IN gctPOINTER Timer,
8033     IN gctUINT32 Delay
8034     )
8035 {
8036     gcsOSTIMER_PTR timer;
8037
8038     gcmkHEADER_ARG("Os=0x%X Timer=0x%X Delay=%u", Os, Timer, Delay);
8039
8040     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
8041     gcmkVERIFY_ARGUMENT(Timer != gcvNULL);
8042     gcmkVERIFY_ARGUMENT(Delay != 0);
8043
8044     timer = (gcsOSTIMER_PTR)Timer;
8045
8046 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0)
8047     mod_delayed_work(Os->workqueue, &timer->work, msecs_to_jiffies(Delay));
8048 #else
8049     if (unlikely(delayed_work_pending(&timer->work)))
8050     {
8051 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23)
8052         cancel_delayed_work_sync(&timer->work);
8053 #else
8054         cancel_delayed_work(&timer->work);
8055         flush_workqueue(Os->workqueue);
8056 #endif
8057     }
8058
8059     queue_delayed_work(Os->workqueue, &timer->work, msecs_to_jiffies(Delay));
8060 #endif
8061
8062     gcmkFOOTER_NO();
8063     return gcvSTATUS_OK;
8064 }
8065
8066 /*******************************************************************************
8067 **
8068 **  gckOS_StopTimer
8069 **
8070 **  Cancel a unscheduled timer.
8071 **
8072 **  INPUT:
8073 **
8074 **      gckOS Os
8075 **          Pointer to the gckOS object.
8076 **
8077 **      gctPOINTER Timer
8078 **          Pointer to the timer to be cancel.
8079 **
8080 **  OUTPUT:
8081 **
8082 **      Nothing.
8083 */
8084 gceSTATUS
8085 gckOS_StopTimer(
8086     IN gckOS Os,
8087     IN gctPOINTER Timer
8088     )
8089 {
8090     gcsOSTIMER_PTR timer;
8091     gcmkHEADER_ARG("Os=0x%X Timer=0x%X", Os, Timer);
8092
8093     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
8094     gcmkVERIFY_ARGUMENT(Timer != gcvNULL);
8095
8096     timer = (gcsOSTIMER_PTR)Timer;
8097
8098     cancel_delayed_work(&timer->work);
8099
8100     gcmkFOOTER_NO();
8101     return gcvSTATUS_OK;
8102 }
8103
8104 gceSTATUS
8105 gckOS_GetProcessNameByPid(
8106     IN gctINT Pid,
8107     IN gctSIZE_T Length,
8108     OUT gctUINT8_PTR String
8109     )
8110 {
8111     struct task_struct *task;
8112
8113     /* Get the task_struct of the task with pid. */
8114     rcu_read_lock();
8115
8116     task = FIND_TASK_BY_PID(Pid);
8117
8118     if (task == gcvNULL)
8119     {
8120         rcu_read_unlock();
8121         return gcvSTATUS_NOT_FOUND;
8122     }
8123
8124     /* Get name of process. */
8125     strncpy(String, task->comm, Length);
8126
8127     rcu_read_unlock();
8128
8129     return gcvSTATUS_OK;
8130 }
8131
8132 gceSTATUS
8133 gckOS_DumpCallStack(
8134     IN gckOS Os
8135     )
8136 {
8137     gcmkHEADER_ARG("Os=0x%X", Os);
8138
8139     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
8140
8141     dump_stack();
8142
8143     gcmkFOOTER_NO();
8144     return gcvSTATUS_OK;
8145 }
8146
8147 /*******************************************************************************
8148 **
8149 **  gckOS_DetectProcessByName
8150 **
8151 **      task->comm maybe part of process name, so this function
8152 **      can only be used for debugging.
8153 **
8154 **  INPUT:
8155 **
8156 **      gctCONST_POINTER Name
8157 **          Pointer to a string to hold name to be check. If the length
8158 **          of name is longer than TASK_COMM_LEN (16), use part of name
8159 **          to detect.
8160 **
8161 **  OUTPUT:
8162 **
8163 **      gcvSTATUS_TRUE if name of current process matches Name.
8164 **
8165 */
8166 gceSTATUS
8167 gckOS_DetectProcessByName(
8168     IN gctCONST_POINTER Name
8169     )
8170 {
8171     char comm[sizeof(current->comm)];
8172
8173     memset(comm, 0, sizeof(comm));
8174
8175     gcmkVERIFY_OK(
8176         gckOS_GetProcessNameByPid(_GetProcessID(), sizeof(current->comm), comm));
8177
8178     return strstr(comm, Name) ? gcvSTATUS_TRUE
8179                               : gcvSTATUS_FALSE;
8180 }
8181
8182 #if gcdANDROID_NATIVE_FENCE_SYNC
8183
8184 gceSTATUS
8185 gckOS_CreateSyncPoint(
8186     IN gckOS Os,
8187     OUT gctSYNC_POINT * SyncPoint
8188     )
8189 {
8190     gceSTATUS status;
8191     gcsSYNC_POINT_PTR syncPoint;
8192
8193     gcmkHEADER_ARG("Os=0x%X", Os);
8194
8195     /* Verify the arguments. */
8196     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
8197
8198     /* Create an sync point structure. */
8199     syncPoint = (gcsSYNC_POINT_PTR) kmalloc(
8200             sizeof(gcsSYNC_POINT), GFP_KERNEL | gcdNOWARN);
8201
8202     if (syncPoint == gcvNULL)
8203     {
8204         gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
8205     }
8206
8207     /* Initialize the sync point. */
8208     atomic_set(&syncPoint->ref, 1);
8209     atomic_set(&syncPoint->state, 0);
8210
8211     gcmkONERROR(_AllocateIntegerId(&Os->syncPointDB, syncPoint, &syncPoint->id));
8212
8213     *SyncPoint = (gctSYNC_POINT)(gctUINTPTR_T)syncPoint->id;
8214
8215     gcmkFOOTER_ARG("*SyncPonint=%d", syncPoint->id);
8216     return gcvSTATUS_OK;
8217
8218 OnError:
8219     if (syncPoint != gcvNULL)
8220     {
8221         kfree(syncPoint);
8222     }
8223
8224     gcmkFOOTER();
8225     return status;
8226 }
8227
8228 gceSTATUS
8229 gckOS_ReferenceSyncPoint(
8230     IN gckOS Os,
8231     IN gctSYNC_POINT SyncPoint
8232     )
8233 {
8234     gceSTATUS status;
8235     gcsSYNC_POINT_PTR syncPoint;
8236
8237     gcmkHEADER_ARG("Os=0x%X", Os);
8238
8239     /* Verify the arguments. */
8240     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
8241     gcmkVERIFY_ARGUMENT(SyncPoint != gcvNULL);
8242
8243     gcmkONERROR(
8244         _QueryIntegerId(&Os->syncPointDB,
8245                         (gctUINT32)(gctUINTPTR_T)SyncPoint,
8246                         (gctPOINTER)&syncPoint));
8247
8248     /* Initialize the sync point. */
8249     atomic_inc(&syncPoint->ref);
8250
8251     gcmkFOOTER_NO();
8252     return gcvSTATUS_OK;
8253
8254 OnError:
8255     gcmkFOOTER();
8256     return status;
8257 }
8258
8259 gceSTATUS
8260 gckOS_DestroySyncPoint(
8261     IN gckOS Os,
8262     IN gctSYNC_POINT SyncPoint
8263     )
8264 {
8265     gceSTATUS status;
8266     gcsSYNC_POINT_PTR syncPoint;
8267     gctBOOL acquired = gcvFALSE;
8268
8269     gcmkHEADER_ARG("Os=0x%X SyncPoint=%d", Os, (gctUINT32)(gctUINTPTR_T)SyncPoint);
8270
8271     /* Verify the arguments. */
8272     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
8273     gcmkVERIFY_ARGUMENT(SyncPoint != gcvNULL);
8274
8275     gcmkONERROR(gckOS_AcquireMutex(Os, Os->syncPointMutex, gcvINFINITE));
8276     acquired = gcvTRUE;
8277
8278     gcmkONERROR(
8279         _QueryIntegerId(&Os->syncPointDB,
8280                         (gctUINT32)(gctUINTPTR_T)SyncPoint,
8281                         (gctPOINTER)&syncPoint));
8282
8283     gcmkASSERT(syncPoint->id == (gctUINT32)(gctUINTPTR_T)SyncPoint);
8284
8285     if (atomic_dec_and_test(&syncPoint->ref))
8286     {
8287         gcmkVERIFY_OK(_DestroyIntegerId(&Os->syncPointDB, syncPoint->id));
8288
8289         /* Free the sgianl. */
8290         syncPoint->timeline = gcvNULL;
8291         kfree(syncPoint);
8292     }
8293
8294     gcmkVERIFY_OK(gckOS_ReleaseMutex(Os, Os->syncPointMutex));
8295     acquired = gcvFALSE;
8296
8297     /* Success. */
8298     gcmkFOOTER_NO();
8299     return gcvSTATUS_OK;
8300
8301 OnError:
8302     if (acquired)
8303     {
8304         /* Release the mutex. */
8305         gcmkVERIFY_OK(gckOS_ReleaseMutex(Os, Os->syncPointMutex));
8306     }
8307
8308     gcmkFOOTER();
8309     return status;
8310 }
8311
8312 gceSTATUS
8313 gckOS_SignalSyncPoint(
8314     IN gckOS Os,
8315     IN gctSYNC_POINT SyncPoint
8316     )
8317 {
8318     gceSTATUS status;
8319     gcsSYNC_POINT_PTR syncPoint;
8320     struct sync_timeline * timeline;
8321     gctBOOL acquired = gcvFALSE;
8322
8323     gcmkHEADER_ARG("Os=0x%X SyncPoint=%d", Os, (gctUINT32)(gctUINTPTR_T)SyncPoint);
8324
8325     /* Verify the arguments. */
8326     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
8327     gcmkVERIFY_ARGUMENT(SyncPoint != gcvNULL);
8328
8329     gcmkONERROR(gckOS_AcquireMutex(Os, Os->syncPointMutex, gcvINFINITE));
8330     acquired = gcvTRUE;
8331
8332     gcmkONERROR(
8333         _QueryIntegerId(&Os->syncPointDB,
8334                         (gctUINT32)(gctUINTPTR_T)SyncPoint,
8335                         (gctPOINTER)&syncPoint));
8336
8337     gcmkASSERT(syncPoint->id == (gctUINT32)(gctUINTPTR_T)SyncPoint);
8338
8339     /* Set signaled state. */
8340     atomic_set(&syncPoint->state, 1);
8341
8342     /* Get parent timeline. */
8343     timeline = syncPoint->timeline;
8344
8345     gcmkVERIFY_OK(gckOS_ReleaseMutex(Os, Os->syncPointMutex));
8346     acquired = gcvFALSE;
8347
8348     /* Signal timeline. */
8349     if (timeline)
8350     {
8351         sync_timeline_signal(timeline);
8352     }
8353
8354     /* Success. */
8355     gcmkFOOTER_NO();
8356     return gcvSTATUS_OK;
8357
8358 OnError:
8359     if (acquired)
8360     {
8361         /* Release the mutex. */
8362         gcmkVERIFY_OK(gckOS_ReleaseMutex(Os, Os->syncPointMutex));
8363     }
8364
8365     gcmkFOOTER();
8366     return status;
8367 }
8368
8369 gceSTATUS
8370 gckOS_QuerySyncPoint(
8371     IN gckOS Os,
8372     IN gctSYNC_POINT SyncPoint,
8373     OUT gctBOOL_PTR State
8374     )
8375 {
8376     gceSTATUS status;
8377     gcsSYNC_POINT_PTR syncPoint;
8378
8379     gcmkHEADER_ARG("Os=0x%X SyncPoint=%d", Os, (gctUINT32)(gctUINTPTR_T)SyncPoint);
8380
8381     /* Verify the arguments. */
8382     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
8383     gcmkVERIFY_ARGUMENT(SyncPoint != gcvNULL);
8384
8385     gcmkONERROR(
8386         _QueryIntegerId(&Os->syncPointDB,
8387                         (gctUINT32)(gctUINTPTR_T)SyncPoint,
8388                         (gctPOINTER)&syncPoint));
8389
8390     gcmkASSERT(syncPoint->id == (gctUINT32)(gctUINTPTR_T)SyncPoint);
8391
8392     /* Get state. */
8393     *State = atomic_read(&syncPoint->state);
8394
8395     /* Success. */
8396     gcmkFOOTER_ARG("*State=%d", *State);
8397     return gcvSTATUS_OK;
8398
8399 OnError:
8400     gcmkFOOTER();
8401     return status;
8402 }
8403
8404 gceSTATUS
8405 gckOS_CreateSyncTimeline(
8406     IN gckOS Os,
8407     OUT gctHANDLE * Timeline
8408     )
8409 {
8410     struct viv_sync_timeline * timeline;
8411
8412     /* Create viv sync timeline. */
8413     timeline = viv_sync_timeline_create("viv timeline", Os);
8414
8415     if (timeline == gcvNULL)
8416     {
8417         /* Out of memory. */
8418         return gcvSTATUS_OUT_OF_MEMORY;
8419     }
8420
8421     *Timeline = (gctHANDLE) timeline;
8422     return gcvSTATUS_OK;
8423 }
8424
8425 gceSTATUS
8426 gckOS_DestroySyncTimeline(
8427     IN gckOS Os,
8428     IN gctHANDLE Timeline
8429     )
8430 {
8431     struct viv_sync_timeline * timeline;
8432     gcmkASSERT(Timeline != gcvNULL);
8433
8434     /* Destroy timeline. */
8435     timeline = (struct viv_sync_timeline *) Timeline;
8436     sync_timeline_destroy(&timeline->obj);
8437
8438     return gcvSTATUS_OK;
8439 }
8440
8441 gceSTATUS
8442 gckOS_CreateNativeFence(
8443     IN gckOS Os,
8444     IN gctHANDLE Timeline,
8445     IN gctSYNC_POINT SyncPoint,
8446     OUT gctINT * FenceFD
8447     )
8448 {
8449     int fd = -1;
8450     struct viv_sync_timeline *timeline;
8451     struct sync_pt * pt = gcvNULL;
8452     struct sync_fence * fence;
8453     char name[32];
8454     gcsSYNC_POINT_PTR syncPoint;
8455     gceSTATUS status;
8456
8457     gcmkHEADER_ARG("Os=0x%X Timeline=0x%X SyncPoint=%d",
8458                    Os, Timeline, (gctUINT)(gctUINTPTR_T)SyncPoint);
8459
8460     gcmkONERROR(
8461         _QueryIntegerId(&Os->syncPointDB,
8462                         (gctUINT32)(gctUINTPTR_T)SyncPoint,
8463                         (gctPOINTER)&syncPoint));
8464
8465     /* Cast timeline. */
8466     timeline = (struct viv_sync_timeline *) Timeline;
8467
8468     fd = get_unused_fd();
8469
8470     if (fd < 0)
8471     {
8472         /* Out of resources. */
8473         gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES);
8474     }
8475
8476     /* Create viv_sync_pt. */
8477     pt = viv_sync_pt_create(timeline, SyncPoint);
8478
8479     if (pt == gcvNULL)
8480     {
8481         gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
8482     }
8483
8484     /* Reference sync_timeline. */
8485     syncPoint->timeline = &timeline->obj;
8486
8487     /* Build fence name. */
8488     snprintf(name, 32, "viv sync_fence-%u", (gctUINT)(gctUINTPTR_T)SyncPoint);
8489
8490     /* Create sync_fence. */
8491     fence = sync_fence_create(name, pt);
8492
8493     if (fence == NULL)
8494     {
8495         gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
8496     }
8497
8498     /* Install fence to fd. */
8499     sync_fence_install(fence, fd);
8500
8501     *FenceFD = fd;
8502     gcmkFOOTER_ARG("*FenceFD=%d", fd);
8503     return gcvSTATUS_OK;
8504
8505 OnError:
8506     /* Error roll back. */
8507     if (pt)
8508     {
8509         sync_pt_free(pt);
8510     }
8511
8512     if (fd > 0)
8513     {
8514         put_unused_fd(fd);
8515     }
8516
8517     gcmkFOOTER();
8518     return status;
8519 }
8520 #endif
8521
8522 #if gcdSECURITY
8523 gceSTATUS
8524 gckOS_AllocatePageArray(
8525     IN gckOS Os,
8526     IN gctPHYS_ADDR Physical,
8527     IN gctSIZE_T PageCount,
8528     OUT gctPOINTER * PageArrayLogical,
8529     OUT gctPHYS_ADDR * PageArrayPhysical
8530     )
8531 {
8532     gceSTATUS status = gcvSTATUS_OK;
8533     PLINUX_MDL  mdl;
8534     gctUINT32*  table;
8535     gctUINT32   offset;
8536     gctSIZE_T   bytes;
8537     gckALLOCATOR allocator;
8538
8539     gcmkHEADER_ARG("Os=0x%X Physical=0x%X PageCount=%u",
8540                    Os, Physical, PageCount);
8541
8542     /* Verify the arguments. */
8543     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
8544     gcmkVERIFY_ARGUMENT(Physical != gcvNULL);
8545     gcmkVERIFY_ARGUMENT(PageCount > 0);
8546
8547     bytes = PageCount * gcmSIZEOF(gctUINT32);
8548     gcmkONERROR(gckOS_AllocateNonPagedMemory(
8549         Os,
8550         gcvFALSE,
8551         &bytes,
8552         PageArrayPhysical,
8553         PageArrayLogical
8554         ));
8555
8556     table = *PageArrayLogical;
8557
8558     /* Convert pointer to MDL. */
8559     mdl = (PLINUX_MDL)Physical;
8560
8561     allocator = mdl->allocator;
8562
8563      /* Get all the physical addresses and store them in the page table. */
8564
8565     offset = 0;
8566     PageCount = PageCount / (PAGE_SIZE / 4096);
8567
8568     /* Try to get the user pages so DMA can happen. */
8569     while (PageCount-- > 0)
8570     {
8571         unsigned long phys = ~0;
8572
8573         if (mdl->pagedMem && !mdl->contiguous)
8574         {
8575             if (allocator)
8576             {
8577                 gctUINT32 phys_addr;
8578                 allocator->ops->Physical(allocator, mdl, offset, &phys_addr);
8579                 phys = (unsigned long)phys_addr;
8580             }
8581         }
8582         else
8583         {
8584             if (!mdl->pagedMem)
8585             {
8586                 gcmkTRACE_ZONE(
8587                     gcvLEVEL_INFO, gcvZONE_OS,
8588                     "%s(%d): we should not get this call for Non Paged Memory!",
8589                     __FUNCTION__, __LINE__
8590                     );
8591             }
8592
8593             phys = page_to_phys(nth_page(mdl->u.contiguousPages, offset));
8594         }
8595
8596         table[offset] = phys;
8597
8598         offset += 1;
8599     }
8600
8601 OnError:
8602
8603     /* Return the status. */
8604     gcmkFOOTER();
8605     return status;
8606 }
8607 #endif
8608
8609 gceSTATUS
8610 gckOS_CPUPhysicalToGPUPhysical(
8611     IN gckOS Os,
8612     IN gctUINT32 CPUPhysical,
8613     IN gctUINT32_PTR GPUPhysical
8614     )
8615 {
8616     gcsPLATFORM * platform;
8617     gcmkHEADER_ARG("CPUPhysical=0x%X", CPUPhysical);
8618
8619     platform = Os->device->platform;
8620
8621     if (platform && platform->ops->getGPUPhysical)
8622     {
8623         gcmkVERIFY_OK(
8624             platform->ops->getGPUPhysical(platform, CPUPhysical, GPUPhysical));
8625     }
8626     else
8627     {
8628         *GPUPhysical = CPUPhysical;
8629     }
8630
8631     gcmkFOOTER_NO();
8632     return gcvSTATUS_OK;
8633 }
8634
8635 gceSTATUS
8636 gckOS_GPUPhysicalToCPUPhysical(
8637     IN gckOS Os,
8638     IN gctUINT32 GPUPhysical,
8639     IN gctUINT32_PTR CPUPhysical
8640     )
8641 {
8642     gcmkHEADER_ARG("GPUPhysical=0x%X", GPUPhysical);
8643
8644     *CPUPhysical = GPUPhysical;
8645
8646     gcmkFOOTER_NO();
8647     return gcvSTATUS_OK;
8648 }
8649
8650 gceSTATUS
8651 gckOS_PhysicalToPhysicalAddress(
8652     IN gckOS Os,
8653     IN gctPOINTER Physical,
8654     OUT gctUINT32 * PhysicalAddress
8655     )
8656 {
8657     PLINUX_MDL mdl = (PLINUX_MDL)Physical;
8658     gckALLOCATOR allocator = mdl->allocator;
8659
8660     if (allocator)
8661     {
8662         return allocator->ops->Physical(allocator, mdl, 0, PhysicalAddress);
8663     }
8664
8665     return gcvSTATUS_NOT_SUPPORTED;
8666 }
8667
8668 gceSTATUS
8669 gckOS_QueryOption(
8670     IN gckOS Os,
8671     IN gctCONST_STRING Option,
8672     OUT gctUINT32 * Value
8673     )
8674 {
8675     gckGALDEVICE device = Os->device;
8676
8677     if (!strcmp(Option, "physBase"))
8678     {
8679         *Value = device->physBase;
8680         return gcvSTATUS_OK;
8681     }
8682     else if (!strcmp(Option, "physSize"))
8683     {
8684         *Value = device->physSize;
8685         return gcvSTATUS_OK;
8686     }
8687     else if (!strcmp(Option, "mmu"))
8688     {
8689 #if gcdSECURITY
8690         *Value = 0;
8691 #else
8692         *Value = device->mmu;
8693 #endif
8694         return gcvSTATUS_OK;
8695     }
8696
8697     return gcvSTATUS_NOT_SUPPORTED;
8698 }
8699
8700 static int
8701 fd_release(
8702     struct inode *inode,
8703     struct file *file
8704     )
8705 {
8706     gcsFDPRIVATE_PTR private = (gcsFDPRIVATE_PTR)file->private_data;
8707
8708     if (private && private->release)
8709     {
8710         return private->release(private);
8711     }
8712
8713     return 0;
8714 }
8715
8716 static const struct file_operations fd_fops = {
8717     .release = fd_release,
8718 };
8719
8720 gceSTATUS
8721 gckOS_GetFd(
8722     IN gctSTRING Name,
8723     IN gcsFDPRIVATE_PTR Private,
8724     OUT gctINT *Fd
8725     )
8726 {
8727 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
8728     *Fd = anon_inode_getfd(Name, &fd_fops, Private, O_RDWR);
8729
8730     if (*Fd < 0)
8731     {
8732         return gcvSTATUS_OUT_OF_RESOURCES;
8733     }
8734
8735     return gcvSTATUS_OK;
8736 #else
8737     return gcvSTATUS_NOT_SUPPORTED;
8738 #endif
8739 }
8740