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