]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_os.c
ENGR00274478 fix gpu memory multi-lock failure
[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->reference = 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 #if 0
4437     else
4438     {
4439         /* mdlMap->vmaAddr != gcvNULL means current process has already locked this node. */
4440         MEMORY_UNLOCK(Os);
4441
4442         gcmkFOOTER_ARG("*status=%d, mdlMap->vmaAddr=%x", gcvSTATUS_MEMORY_LOCKED, mdlMap->vmaAddr);
4443         return gcvSTATUS_MEMORY_LOCKED;
4444     }
4445 #endif
4446
4447     /* Convert pointer to MDL. */
4448     *Logical = mdlMap->vmaAddr;
4449
4450     /* Return the page number according to the GPU page size. */
4451     gcmkASSERT((PAGE_SIZE % 4096) == 0);
4452     gcmkASSERT((PAGE_SIZE / 4096) >= 1);
4453
4454     *PageCount = mdl->numPages * (PAGE_SIZE / 4096);
4455
4456     /* Increase reference count. */
4457     mdlMap->reference++;
4458
4459     MEMORY_UNLOCK(Os);
4460
4461     gcmkVERIFY_OK(gckOS_CacheFlush(
4462         Os,
4463         _GetProcessID(),
4464         Physical,
4465         gcvNULL,
4466         (gctPOINTER)mdlMap->vmaAddr,
4467         mdl->numPages * PAGE_SIZE
4468         ));
4469
4470     /* Success. */
4471     gcmkFOOTER_ARG("*Logical=0x%X *PageCount=%lu", *Logical, *PageCount);
4472     return gcvSTATUS_OK;
4473 }
4474
4475 /*******************************************************************************
4476 **
4477 **  gckOS_MapPages
4478 **
4479 **  Map paged memory into a page table.
4480 **
4481 **  INPUT:
4482 **
4483 **      gckOS Os
4484 **          Pointer to an gckOS object.
4485 **
4486 **      gctPHYS_ADDR Physical
4487 **          Physical address of the allocation.
4488 **
4489 **      gctSIZE_T PageCount
4490 **          Number of pages required for the physical address.
4491 **
4492 **      gctPOINTER PageTable
4493 **          Pointer to the page table to fill in.
4494 **
4495 **  OUTPUT:
4496 **
4497 **      Nothing.
4498 */
4499 gceSTATUS
4500 gckOS_MapPages(
4501     IN gckOS Os,
4502     IN gctPHYS_ADDR Physical,
4503     IN gctSIZE_T PageCount,
4504     IN gctPOINTER PageTable
4505     )
4506 {
4507     return gckOS_MapPagesEx(Os,
4508                             gcvCORE_MAJOR,
4509                             Physical,
4510                             PageCount,
4511                             PageTable);
4512 }
4513
4514 gceSTATUS
4515 gckOS_MapPagesEx(
4516     IN gckOS Os,
4517     IN gceCORE Core,
4518     IN gctPHYS_ADDR Physical,
4519     IN gctSIZE_T PageCount,
4520     IN gctPOINTER PageTable
4521     )
4522 {
4523     gceSTATUS status = gcvSTATUS_OK;
4524     PLINUX_MDL  mdl;
4525     gctUINT32*  table;
4526     gctUINT32   offset;
4527 #if gcdNONPAGED_MEMORY_CACHEABLE
4528     gckMMU      mmu;
4529     PLINUX_MDL  mmuMdl;
4530     gctUINT32   bytes;
4531     gctPHYS_ADDR pageTablePhysical;
4532 #endif
4533
4534     gcmkHEADER_ARG("Os=0x%X Core=%d Physical=0x%X PageCount=%u PageTable=0x%X",
4535                    Os, Core, Physical, PageCount, PageTable);
4536
4537     /* Verify the arguments. */
4538     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
4539     gcmkVERIFY_ARGUMENT(Physical != gcvNULL);
4540     gcmkVERIFY_ARGUMENT(PageCount > 0);
4541     gcmkVERIFY_ARGUMENT(PageTable != gcvNULL);
4542
4543     /* Convert pointer to MDL. */
4544     mdl = (PLINUX_MDL)Physical;
4545
4546     gcmkTRACE_ZONE(
4547         gcvLEVEL_INFO, gcvZONE_OS,
4548         "%s(%d): Physical->0x%X PageCount->0x%X PagedMemory->?%d",
4549         __FUNCTION__, __LINE__,
4550         (gctUINT32)(gctUINTPTR_T)Physical,
4551         (gctUINT32)(gctUINTPTR_T)PageCount,
4552         mdl->pagedMem
4553         );
4554
4555     MEMORY_LOCK(Os);
4556
4557     table = (gctUINT32 *)PageTable;
4558 #if gcdNONPAGED_MEMORY_CACHEABLE
4559     mmu = Os->device->kernels[Core]->mmu;
4560     bytes = PageCount * sizeof(*table);
4561     mmuMdl = (PLINUX_MDL)mmu->pageTablePhysical;
4562 #endif
4563
4564      /* Get all the physical addresses and store them in the page table. */
4565
4566     offset = 0;
4567
4568     if (mdl->pagedMem)
4569     {
4570         /* Try to get the user pages so DMA can happen. */
4571         while (PageCount-- > 0)
4572         {
4573 #if gcdENABLE_VG
4574             if (Core == gcvCORE_VG)
4575             {
4576                 if (mdl->contiguous)
4577                 {
4578                     gcmkONERROR(
4579                         gckVGMMU_SetPage(Os->device->kernels[Core]->vg->mmu,
4580                              page_to_phys(nth_page(mdl->u.contiguousPages, offset)),
4581                              table));
4582                 }
4583                 else
4584                 {
4585                     gcmkONERROR(
4586                         gckVGMMU_SetPage(Os->device->kernels[Core]->vg->mmu,
4587                              _NonContiguousToPhys(mdl->u.nonContiguousPages, offset),
4588                              table));
4589                 }
4590             }
4591             else
4592 #endif
4593             {
4594                 if (mdl->contiguous)
4595                 {
4596                     gcmkONERROR(
4597                         gckMMU_SetPage(Os->device->kernels[Core]->mmu,
4598                              page_to_phys(nth_page(mdl->u.contiguousPages, offset)),
4599                              table));
4600                 }
4601                 else
4602                 {
4603                     gcmkONERROR(
4604                         gckMMU_SetPage(Os->device->kernels[Core]->mmu,
4605                              _NonContiguousToPhys(mdl->u.nonContiguousPages, offset),
4606                              table));
4607                 }
4608             }
4609
4610             table++;
4611             offset += 1;
4612         }
4613     }
4614     else
4615     {
4616         gcmkTRACE_ZONE(
4617             gcvLEVEL_INFO, gcvZONE_OS,
4618             "%s(%d): we should not get this call for Non Paged Memory!",
4619             __FUNCTION__, __LINE__
4620             );
4621
4622         while (PageCount-- > 0)
4623         {
4624 #if gcdENABLE_VG
4625             if (Core == gcvCORE_VG)
4626             {
4627                 gcmkONERROR(
4628                         gckVGMMU_SetPage(Os->device->kernels[Core]->vg->mmu,
4629                                          page_to_phys(nth_page(mdl->u.contiguousPages, offset)),
4630                                          table));
4631             }
4632             else
4633 #endif
4634             {
4635                 gcmkONERROR(
4636                         gckMMU_SetPage(Os->device->kernels[Core]->mmu,
4637                                          page_to_phys(nth_page(mdl->u.contiguousPages, offset)),
4638                                          table));
4639             }
4640             table++;
4641             offset += 1;
4642         }
4643     }
4644
4645 #if gcdNONPAGED_MEMORY_CACHEABLE
4646     /* Get physical address of pageTable */
4647     pageTablePhysical = (gctPHYS_ADDR)(mmuMdl->dmaHandle +
4648                         ((gctUINT32 *)PageTable - mmu->pageTableLogical));
4649
4650     /* Flush the mmu page table cache. */
4651     gcmkONERROR(gckOS_CacheClean(
4652         Os,
4653         _GetProcessID(),
4654         gcvNULL,
4655         pageTablePhysical,
4656         PageTable,
4657         bytes
4658         ));
4659 #endif
4660
4661 OnError:
4662
4663     MEMORY_UNLOCK(Os);
4664
4665     /* Return the status. */
4666     gcmkFOOTER();
4667     return status;
4668 }
4669
4670 /*******************************************************************************
4671 **
4672 **  gckOS_UnlockPages
4673 **
4674 **  Unlock memory allocated from the paged pool.
4675 **
4676 **  INPUT:
4677 **
4678 **      gckOS Os
4679 **          Pointer to an gckOS object.
4680 **
4681 **      gctPHYS_ADDR Physical
4682 **          Physical address of the allocation.
4683 **
4684 **      gctSIZE_T Bytes
4685 **          Number of bytes of the allocation.
4686 **
4687 **      gctPOINTER Logical
4688 **          Address of the mapped memory.
4689 **
4690 **  OUTPUT:
4691 **
4692 **      Nothing.
4693 */
4694 gceSTATUS
4695 gckOS_UnlockPages(
4696     IN gckOS Os,
4697     IN gctPHYS_ADDR Physical,
4698     IN gctSIZE_T Bytes,
4699     IN gctPOINTER Logical
4700     )
4701 {
4702     PLINUX_MDL_MAP          mdlMap;
4703     PLINUX_MDL              mdl = (PLINUX_MDL)Physical;
4704
4705     gcmkHEADER_ARG("Os=0x%X Physical=0x%X Bytes=%u Logical=0x%X",
4706                    Os, Physical, Bytes, Logical);
4707
4708     /* Verify the arguments. */
4709     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
4710     gcmkVERIFY_ARGUMENT(Physical != gcvNULL);
4711     gcmkVERIFY_ARGUMENT(Logical != gcvNULL);
4712
4713     /* Make sure there is already a mapping...*/
4714     gcmkVERIFY_ARGUMENT(mdl->u.nonContiguousPages != gcvNULL
4715                        || mdl->u.contiguousPages != gcvNULL);
4716
4717     MEMORY_LOCK(Os);
4718
4719     mdlMap = mdl->maps;
4720
4721     while (mdlMap != gcvNULL)
4722     {
4723         if ((mdlMap->vmaAddr != gcvNULL) && (_GetProcessID() == mdlMap->pid))
4724         {
4725             if (--mdlMap->reference > 0)
4726             {
4727                 continue;
4728             }
4729
4730             _UnmapUserLogical(mdlMap->pid, mdlMap->vmaAddr, mdl->numPages * PAGE_SIZE);
4731             mdlMap->vmaAddr = gcvNULL;
4732         }
4733
4734         mdlMap = mdlMap->next;
4735     }
4736
4737     MEMORY_UNLOCK(Os);
4738
4739     /* Success. */
4740     gcmkFOOTER_NO();
4741     return gcvSTATUS_OK;
4742 }
4743
4744
4745 /*******************************************************************************
4746 **
4747 **  gckOS_AllocateContiguous
4748 **
4749 **  Allocate memory from the contiguous pool.
4750 **
4751 **  INPUT:
4752 **
4753 **      gckOS Os
4754 **          Pointer to an gckOS object.
4755 **
4756 **      gctBOOL InUserSpace
4757 **          gcvTRUE if the pages need to be mapped into user space.
4758 **
4759 **      gctSIZE_T * Bytes
4760 **          Pointer to the number of bytes to allocate.
4761 **
4762 **  OUTPUT:
4763 **
4764 **      gctSIZE_T * Bytes
4765 **          Pointer to a variable that receives the number of bytes allocated.
4766 **
4767 **      gctPHYS_ADDR * Physical
4768 **          Pointer to a variable that receives the physical address of the
4769 **          memory allocation.
4770 **
4771 **      gctPOINTER * Logical
4772 **          Pointer to a variable that receives the logical address of the
4773 **          memory allocation.
4774 */
4775 gceSTATUS
4776 gckOS_AllocateContiguous(
4777     IN gckOS Os,
4778     IN gctBOOL InUserSpace,
4779     IN OUT gctSIZE_T * Bytes,
4780     OUT gctPHYS_ADDR * Physical,
4781     OUT gctPOINTER * Logical
4782     )
4783 {
4784     gceSTATUS status;
4785
4786     gcmkHEADER_ARG("Os=0x%X InUserSpace=%d *Bytes=%lu",
4787                    Os, InUserSpace, gcmOPT_VALUE(Bytes));
4788
4789     /* Verify the arguments. */
4790     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
4791     gcmkVERIFY_ARGUMENT(Bytes != gcvNULL);
4792     gcmkVERIFY_ARGUMENT(*Bytes > 0);
4793     gcmkVERIFY_ARGUMENT(Physical != gcvNULL);
4794     gcmkVERIFY_ARGUMENT(Logical != gcvNULL);
4795
4796     /* Same as non-paged memory for now. */
4797     gcmkONERROR(gckOS_AllocateNonPagedMemory(Os,
4798                                              InUserSpace,
4799                                              Bytes,
4800                                              Physical,
4801                                              Logical));
4802
4803     /* Success. */
4804     gcmkFOOTER_ARG("*Bytes=%lu *Physical=0x%X *Logical=0x%X",
4805                    *Bytes, *Physical, *Logical);
4806     return gcvSTATUS_OK;
4807
4808 OnError:
4809     /* Return the status. */
4810     gcmkFOOTER();
4811     return status;
4812 }
4813
4814 /*******************************************************************************
4815 **
4816 **  gckOS_FreeContiguous
4817 **
4818 **  Free memory allocated from the contiguous pool.
4819 **
4820 **  INPUT:
4821 **
4822 **      gckOS Os
4823 **          Pointer to an gckOS object.
4824 **
4825 **      gctPHYS_ADDR Physical
4826 **          Physical address of the allocation.
4827 **
4828 **      gctPOINTER Logical
4829 **          Logicval address of the allocation.
4830 **
4831 **      gctSIZE_T Bytes
4832 **          Number of bytes of the allocation.
4833 **
4834 **  OUTPUT:
4835 **
4836 **      Nothing.
4837 */
4838 gceSTATUS
4839 gckOS_FreeContiguous(
4840     IN gckOS Os,
4841     IN gctPHYS_ADDR Physical,
4842     IN gctPOINTER Logical,
4843     IN gctSIZE_T Bytes
4844     )
4845 {
4846     gceSTATUS status;
4847
4848     gcmkHEADER_ARG("Os=0x%X Physical=0x%X Logical=0x%X Bytes=%lu",
4849                    Os, Physical, Logical, Bytes);
4850
4851     /* Verify the arguments. */
4852     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
4853     gcmkVERIFY_ARGUMENT(Physical != gcvNULL);
4854     gcmkVERIFY_ARGUMENT(Logical != gcvNULL);
4855     gcmkVERIFY_ARGUMENT(Bytes > 0);
4856
4857     /* Same of non-paged memory for now. */
4858     gcmkONERROR(gckOS_FreeNonPagedMemory(Os, Bytes, Physical, Logical));
4859
4860     /* Success. */
4861     gcmkFOOTER_NO();
4862     return gcvSTATUS_OK;
4863
4864 OnError:
4865     /* Return the status. */
4866     gcmkFOOTER();
4867     return status;
4868 }
4869
4870 #if gcdENABLE_VG
4871 /******************************************************************************
4872 **
4873 **  gckOS_GetKernelLogical
4874 **
4875 **  Return the kernel logical pointer that corresponods to the specified
4876 **  hardware address.
4877 **
4878 **  INPUT:
4879 **
4880 **      gckOS Os
4881 **          Pointer to an gckOS object.
4882 **
4883 **      gctUINT32 Address
4884 **          Hardware physical address.
4885 **
4886 **  OUTPUT:
4887 **
4888 **      gctPOINTER * KernelPointer
4889 **          Pointer to a variable receiving the pointer in kernel address space.
4890 */
4891 gceSTATUS
4892 gckOS_GetKernelLogical(
4893     IN gckOS Os,
4894     IN gctUINT32 Address,
4895     OUT gctPOINTER * KernelPointer
4896     )
4897 {
4898     return gckOS_GetKernelLogicalEx(Os, gcvCORE_MAJOR, Address, KernelPointer);
4899 }
4900
4901 gceSTATUS
4902 gckOS_GetKernelLogicalEx(
4903     IN gckOS Os,
4904     IN gceCORE Core,
4905     IN gctUINT32 Address,
4906     OUT gctPOINTER * KernelPointer
4907     )
4908 {
4909     gceSTATUS status;
4910
4911     gcmkHEADER_ARG("Os=0x%X Core=%d Address=0x%08x", Os, Core, Address);
4912
4913     do
4914     {
4915         gckGALDEVICE device;
4916         gckKERNEL kernel;
4917         gcePOOL pool;
4918         gctUINT32 offset;
4919         gctPOINTER logical;
4920
4921         /* Extract the pointer to the gckGALDEVICE class. */
4922         device = (gckGALDEVICE) Os->device;
4923
4924         /* Kernel shortcut. */
4925         kernel = device->kernels[Core];
4926 #if gcdENABLE_VG
4927        if (Core == gcvCORE_VG)
4928        {
4929            gcmkERR_BREAK(gckVGHARDWARE_SplitMemory(
4930                 kernel->vg->hardware, Address, &pool, &offset
4931                 ));
4932        }
4933        else
4934 #endif
4935        {
4936         /* Split the memory address into a pool type and offset. */
4937             gcmkERR_BREAK(gckHARDWARE_SplitMemory(
4938                 kernel->hardware, Address, &pool, &offset
4939                 ));
4940        }
4941
4942         /* Dispatch on pool. */
4943         switch (pool)
4944         {
4945         case gcvPOOL_LOCAL_INTERNAL:
4946             /* Internal memory. */
4947             logical = device->internalLogical;
4948             break;
4949
4950         case gcvPOOL_LOCAL_EXTERNAL:
4951             /* External memory. */
4952             logical = device->externalLogical;
4953             break;
4954
4955         case gcvPOOL_SYSTEM:
4956             /* System memory. */
4957             logical = device->contiguousBase;
4958             break;
4959
4960         default:
4961             /* Invalid memory pool. */
4962             gcmkFOOTER();
4963             return gcvSTATUS_INVALID_ARGUMENT;
4964         }
4965
4966         /* Build logical address of specified address. */
4967         * KernelPointer = ((gctUINT8_PTR) logical) + offset;
4968
4969         /* Success. */
4970         gcmkFOOTER_ARG("*KernelPointer=0x%X", *KernelPointer);
4971         return gcvSTATUS_OK;
4972     }
4973     while (gcvFALSE);
4974
4975     /* Return status. */
4976     gcmkFOOTER();
4977     return status;
4978 }
4979 #endif
4980
4981 /*******************************************************************************
4982 **
4983 **  gckOS_MapUserPointer
4984 **
4985 **  Map a pointer from the user process into the kernel address space.
4986 **
4987 **  INPUT:
4988 **
4989 **      gckOS Os
4990 **          Pointer to an gckOS object.
4991 **
4992 **      gctPOINTER Pointer
4993 **          Pointer in user process space that needs to be mapped.
4994 **
4995 **      gctSIZE_T Size
4996 **          Number of bytes that need to be mapped.
4997 **
4998 **  OUTPUT:
4999 **
5000 **      gctPOINTER * KernelPointer
5001 **          Pointer to a variable receiving the mapped pointer in kernel address
5002 **          space.
5003 */
5004 gceSTATUS
5005 gckOS_MapUserPointer(
5006     IN gckOS Os,
5007     IN gctPOINTER Pointer,
5008     IN gctSIZE_T Size,
5009     OUT gctPOINTER * KernelPointer
5010     )
5011 {
5012     gctPOINTER buf = gcvNULL;
5013     gctUINT32 len;
5014
5015     gcmkHEADER_ARG("Os=0x%X Pointer=0x%X Size=%lu", Os, Pointer, Size);
5016
5017     /* Verify the arguments. */
5018     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
5019     gcmkVERIFY_ARGUMENT(Pointer != gcvNULL);
5020     gcmkVERIFY_ARGUMENT(Size > 0);
5021     gcmkVERIFY_ARGUMENT(KernelPointer != gcvNULL);
5022
5023     buf = kmalloc(Size, GFP_KERNEL | gcdNOWARN);
5024     if (buf == gcvNULL)
5025     {
5026         gcmkTRACE(
5027             gcvLEVEL_ERROR,
5028             "%s(%d): Failed to allocate memory.",
5029             __FUNCTION__, __LINE__
5030             );
5031
5032         gcmkFOOTER_ARG("*status=%d", gcvSTATUS_OUT_OF_MEMORY);
5033         return gcvSTATUS_OUT_OF_MEMORY;
5034     }
5035
5036     len = copy_from_user(buf, Pointer, Size);
5037     if (len != 0)
5038     {
5039         gcmkTRACE(
5040             gcvLEVEL_ERROR,
5041             "%s(%d): Failed to copy data from user.",
5042             __FUNCTION__, __LINE__
5043             );
5044
5045         if (buf != gcvNULL)
5046         {
5047             kfree(buf);
5048         }
5049
5050         gcmkFOOTER_ARG("*status=%d", gcvSTATUS_GENERIC_IO);
5051         return gcvSTATUS_GENERIC_IO;
5052     }
5053
5054     *KernelPointer = buf;
5055
5056     gcmkFOOTER_ARG("*KernelPointer=0x%X", *KernelPointer);
5057     return gcvSTATUS_OK;
5058 }
5059
5060 /*******************************************************************************
5061 **
5062 **  gckOS_UnmapUserPointer
5063 **
5064 **  Unmap a user process pointer from the kernel address space.
5065 **
5066 **  INPUT:
5067 **
5068 **      gckOS Os
5069 **          Pointer to an gckOS object.
5070 **
5071 **      gctPOINTER Pointer
5072 **          Pointer in user process space that needs to be unmapped.
5073 **
5074 **      gctSIZE_T Size
5075 **          Number of bytes that need to be unmapped.
5076 **
5077 **      gctPOINTER KernelPointer
5078 **          Pointer in kernel address space that needs to be unmapped.
5079 **
5080 **  OUTPUT:
5081 **
5082 **      Nothing.
5083 */
5084 gceSTATUS
5085 gckOS_UnmapUserPointer(
5086     IN gckOS Os,
5087     IN gctPOINTER Pointer,
5088     IN gctSIZE_T Size,
5089     IN gctPOINTER KernelPointer
5090     )
5091 {
5092     gctUINT32 len;
5093
5094     gcmkHEADER_ARG("Os=0x%X Pointer=0x%X Size=%lu KernelPointer=0x%X",
5095                    Os, Pointer, Size, KernelPointer);
5096
5097
5098     /* Verify the arguments. */
5099     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
5100     gcmkVERIFY_ARGUMENT(Pointer != gcvNULL);
5101     gcmkVERIFY_ARGUMENT(Size > 0);
5102     gcmkVERIFY_ARGUMENT(KernelPointer != gcvNULL);
5103
5104     len = copy_to_user(Pointer, KernelPointer, Size);
5105
5106     kfree(KernelPointer);
5107
5108     if (len != 0)
5109     {
5110         gcmkTRACE(
5111             gcvLEVEL_ERROR,
5112             "%s(%d): Failed to copy data to user.",
5113             __FUNCTION__, __LINE__
5114             );
5115
5116         gcmkFOOTER_ARG("status=%d", gcvSTATUS_GENERIC_IO);
5117         return gcvSTATUS_GENERIC_IO;
5118     }
5119
5120     gcmkFOOTER_NO();
5121     return gcvSTATUS_OK;
5122 }
5123
5124 /*******************************************************************************
5125 **
5126 **  gckOS_QueryNeedCopy
5127 **
5128 **  Query whether the memory can be accessed or mapped directly or it has to be
5129 **  copied.
5130 **
5131 **  INPUT:
5132 **
5133 **      gckOS Os
5134 **          Pointer to an gckOS object.
5135 **
5136 **      gctUINT32 ProcessID
5137 **          Process ID of the current process.
5138 **
5139 **  OUTPUT:
5140 **
5141 **      gctBOOL_PTR NeedCopy
5142 **          Pointer to a boolean receiving gcvTRUE if the memory needs a copy or
5143 **          gcvFALSE if the memory can be accessed or mapped dircetly.
5144 */
5145 gceSTATUS
5146 gckOS_QueryNeedCopy(
5147     IN gckOS Os,
5148     IN gctUINT32 ProcessID,
5149     OUT gctBOOL_PTR NeedCopy
5150     )
5151 {
5152     gcmkHEADER_ARG("Os=0x%X ProcessID=%d", Os, ProcessID);
5153
5154     /* Verify the arguments. */
5155     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
5156     gcmkVERIFY_ARGUMENT(NeedCopy != gcvNULL);
5157
5158     /* We need to copy data. */
5159     *NeedCopy = gcvTRUE;
5160
5161     /* Success. */
5162     gcmkFOOTER_ARG("*NeedCopy=%d", *NeedCopy);
5163     return gcvSTATUS_OK;
5164 }
5165
5166 /*******************************************************************************
5167 **
5168 **  gckOS_CopyFromUserData
5169 **
5170 **  Copy data from user to kernel memory.
5171 **
5172 **  INPUT:
5173 **
5174 **      gckOS Os
5175 **          Pointer to an gckOS object.
5176 **
5177 **      gctPOINTER KernelPointer
5178 **          Pointer to kernel memory.
5179 **
5180 **      gctPOINTER Pointer
5181 **          Pointer to user memory.
5182 **
5183 **      gctSIZE_T Size
5184 **          Number of bytes to copy.
5185 **
5186 **  OUTPUT:
5187 **
5188 **      Nothing.
5189 */
5190 gceSTATUS
5191 gckOS_CopyFromUserData(
5192     IN gckOS Os,
5193     IN gctPOINTER KernelPointer,
5194     IN gctPOINTER Pointer,
5195     IN gctSIZE_T Size
5196     )
5197 {
5198     gceSTATUS status;
5199
5200     gcmkHEADER_ARG("Os=0x%X KernelPointer=0x%X Pointer=0x%X Size=%lu",
5201                    Os, KernelPointer, Pointer, Size);
5202
5203     /* Verify the arguments. */
5204     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
5205     gcmkVERIFY_ARGUMENT(KernelPointer != gcvNULL);
5206     gcmkVERIFY_ARGUMENT(Pointer != gcvNULL);
5207     gcmkVERIFY_ARGUMENT(Size > 0);
5208
5209     /* Copy data from user. */
5210     if (copy_from_user(KernelPointer, Pointer, Size) != 0)
5211     {
5212         /* Could not copy all the bytes. */
5213         gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES);
5214     }
5215
5216     /* Success. */
5217     gcmkFOOTER_NO();
5218     return gcvSTATUS_OK;
5219
5220 OnError:
5221     /* Return the status. */
5222     gcmkFOOTER();
5223     return status;
5224 }
5225
5226 /*******************************************************************************
5227 **
5228 **  gckOS_CopyToUserData
5229 **
5230 **  Copy data from kernel to user memory.
5231 **
5232 **  INPUT:
5233 **
5234 **      gckOS Os
5235 **          Pointer to an gckOS object.
5236 **
5237 **      gctPOINTER KernelPointer
5238 **          Pointer to kernel memory.
5239 **
5240 **      gctPOINTER Pointer
5241 **          Pointer to user memory.
5242 **
5243 **      gctSIZE_T Size
5244 **          Number of bytes to copy.
5245 **
5246 **  OUTPUT:
5247 **
5248 **      Nothing.
5249 */
5250 gceSTATUS
5251 gckOS_CopyToUserData(
5252     IN gckOS Os,
5253     IN gctPOINTER KernelPointer,
5254     IN gctPOINTER Pointer,
5255     IN gctSIZE_T Size
5256     )
5257 {
5258     gceSTATUS status;
5259
5260     gcmkHEADER_ARG("Os=0x%X KernelPointer=0x%X Pointer=0x%X Size=%lu",
5261                    Os, KernelPointer, Pointer, Size);
5262
5263     /* Verify the arguments. */
5264     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
5265     gcmkVERIFY_ARGUMENT(KernelPointer != gcvNULL);
5266     gcmkVERIFY_ARGUMENT(Pointer != gcvNULL);
5267     gcmkVERIFY_ARGUMENT(Size > 0);
5268
5269     /* Copy data to user. */
5270     if (copy_to_user(Pointer, KernelPointer, Size) != 0)
5271     {
5272         /* Could not copy all the bytes. */
5273         gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES);
5274     }
5275
5276     /* Success. */
5277     gcmkFOOTER_NO();
5278     return gcvSTATUS_OK;
5279
5280 OnError:
5281     /* Return the status. */
5282     gcmkFOOTER();
5283     return status;
5284 }
5285
5286 /*******************************************************************************
5287 **
5288 **  gckOS_WriteMemory
5289 **
5290 **  Write data to a memory.
5291 **
5292 **  INPUT:
5293 **
5294 **      gckOS Os
5295 **          Pointer to an gckOS object.
5296 **
5297 **      gctPOINTER Address
5298 **          Address of the memory to write to.
5299 **
5300 **      gctUINT32 Data
5301 **          Data for register.
5302 **
5303 **  OUTPUT:
5304 **
5305 **      Nothing.
5306 */
5307 gceSTATUS
5308 gckOS_WriteMemory(
5309     IN gckOS Os,
5310     IN gctPOINTER Address,
5311     IN gctUINT32 Data
5312     )
5313 {
5314     gceSTATUS status;
5315     gcmkHEADER_ARG("Os=0x%X Address=0x%X Data=%u", Os, Address, Data);
5316
5317     /* Verify the arguments. */
5318     gcmkVERIFY_ARGUMENT(Address != gcvNULL);
5319
5320     /* Write memory. */
5321     if (access_ok(VERIFY_WRITE, Address, 4))
5322     {
5323         /* User address. */
5324         if(put_user(Data, (gctUINT32*)Address))
5325         {
5326             gcmkONERROR(gcvSTATUS_INVALID_ADDRESS);
5327         }
5328     }
5329     else
5330     {
5331         /* Kernel address. */
5332         *(gctUINT32 *)Address = Data;
5333     }
5334
5335     /* Success. */
5336     gcmkFOOTER_NO();
5337     return gcvSTATUS_OK;
5338
5339 OnError:
5340     gcmkFOOTER();
5341     return status;
5342 }
5343
5344 /*******************************************************************************
5345 **
5346 **  gckOS_MapUserMemory
5347 **
5348 **  Lock down a user buffer and return an DMA'able address to be used by the
5349 **  hardware to access it.
5350 **
5351 **  INPUT:
5352 **
5353 **      gctPOINTER Memory
5354 **          Pointer to memory to lock down.
5355 **
5356 **      gctSIZE_T Size
5357 **          Size in bytes of the memory to lock down.
5358 **
5359 **  OUTPUT:
5360 **
5361 **      gctPOINTER * Info
5362 **          Pointer to variable receiving the information record required by
5363 **          gckOS_UnmapUserMemory.
5364 **
5365 **      gctUINT32_PTR Address
5366 **          Pointer to a variable that will receive the address DMA'able by the
5367 **          hardware.
5368 */
5369 gceSTATUS
5370 gckOS_MapUserMemory(
5371     IN gckOS Os,
5372     IN gceCORE Core,
5373     IN gctPOINTER Memory,
5374     IN gctUINT32 Physical,
5375     IN gctSIZE_T Size,
5376     OUT gctPOINTER * Info,
5377     OUT gctUINT32_PTR Address
5378     )
5379 {
5380     gceSTATUS status;
5381
5382     gcmkHEADER_ARG("Os=0x%x Core=%d Memory=0x%x Size=%lu", Os, Core, Memory, Size);
5383
5384 #if gcdSECURE_USER
5385     gcmkONERROR(gckOS_AddMapping(Os, *Address, Memory, Size));
5386
5387     gcmkFOOTER_NO();
5388     return gcvSTATUS_OK;
5389
5390 OnError:
5391     gcmkFOOTER();
5392     return status;
5393 #else
5394 {
5395     gctSIZE_T pageCount, i, j;
5396     gctUINT32_PTR pageTable;
5397     gctUINT32 address = 0, physical = ~0U;
5398     gctUINTPTR_T start, end, memory;
5399     gctUINT32 offset;
5400     gctINT result = 0;
5401
5402     gcsPageInfo_PTR info = gcvNULL;
5403     struct page **pages = gcvNULL;
5404
5405     /* Verify the arguments. */
5406     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
5407     gcmkVERIFY_ARGUMENT(Memory != gcvNULL || Physical != ~0U);
5408     gcmkVERIFY_ARGUMENT(Size > 0);
5409     gcmkVERIFY_ARGUMENT(Info != gcvNULL);
5410     gcmkVERIFY_ARGUMENT(Address != gcvNULL);
5411
5412     do
5413     {
5414         memory = (gctUINTPTR_T) Memory;
5415
5416         /* Get the number of required pages. */
5417         end = (memory + Size + PAGE_SIZE - 1) >> PAGE_SHIFT;
5418         start = memory >> PAGE_SHIFT;
5419         pageCount = end - start;
5420
5421         gcmkTRACE_ZONE(
5422             gcvLEVEL_INFO, gcvZONE_OS,
5423             "%s(%d): pageCount: %d.",
5424             __FUNCTION__, __LINE__,
5425             pageCount
5426             );
5427
5428         /* Overflow. */
5429         if ((memory + Size) < memory)
5430         {
5431             gcmkFOOTER_ARG("status=%d", gcvSTATUS_INVALID_ARGUMENT);
5432             return gcvSTATUS_INVALID_ARGUMENT;
5433         }
5434
5435         MEMORY_MAP_LOCK(Os);
5436
5437         /* Allocate the Info struct. */
5438         info = (gcsPageInfo_PTR)kmalloc(sizeof(gcsPageInfo), GFP_KERNEL | gcdNOWARN);
5439
5440         if (info == gcvNULL)
5441         {
5442             status = gcvSTATUS_OUT_OF_MEMORY;
5443             break;
5444         }
5445
5446         /* Allocate the array of page addresses. */
5447         pages = (struct page **)kmalloc(pageCount * sizeof(struct page *), GFP_KERNEL | gcdNOWARN);
5448
5449         if (pages == gcvNULL)
5450         {
5451             status = gcvSTATUS_OUT_OF_MEMORY;
5452             break;
5453         }
5454
5455         if (Physical != ~0U)
5456         {
5457             for (i = 0; i < pageCount; i++)
5458             {
5459                 pages[i] = pfn_to_page((Physical >> PAGE_SHIFT) + i);
5460                 get_page(pages[i]);
5461             }
5462         }
5463         else
5464         {
5465             /* Get the user pages. */
5466             down_read(&current->mm->mmap_sem);
5467
5468             result = get_user_pages(current,
5469                     current->mm,
5470                     memory & PAGE_MASK,
5471                     pageCount,
5472                     1,
5473                     0,
5474                     pages,
5475                     gcvNULL
5476                     );
5477
5478             up_read(&current->mm->mmap_sem);
5479
5480             if (result <=0 || result < pageCount)
5481             {
5482                 struct vm_area_struct *vma;
5483
5484                 /* Release the pages if any. */
5485                 if (result > 0)
5486                 {
5487                     for (i = 0; i < result; i++)
5488                     {
5489                         if (pages[i] == gcvNULL)
5490                         {
5491                             break;
5492                         }
5493
5494                         page_cache_release(pages[i]);
5495                         pages[i] = gcvNULL;
5496                     }
5497
5498                     result = 0;
5499                 }
5500
5501                 vma = find_vma(current->mm, memory);
5502
5503                 if (vma && (vma->vm_flags & VM_PFNMAP))
5504                 {
5505                     pte_t       * pte;
5506                     spinlock_t  * ptl;
5507                     gctUINTPTR_T logical = memory;
5508
5509                     for (i = 0; i < pageCount; i++)
5510                     {
5511                         pgd_t * pgd = pgd_offset(current->mm, logical);
5512                         pud_t * pud = pud_offset(pgd, logical);
5513
5514                         if (pud)
5515                         {
5516                             pmd_t * pmd = pmd_offset(pud, logical);
5517                             pte = pte_offset_map_lock(current->mm, pmd, logical, &ptl);
5518                             if (!pte)
5519                             {
5520                                 gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES);
5521                             }
5522                         }
5523                         else
5524                         {
5525                             gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES);
5526                         }
5527
5528                         pages[i] = pte_page(*pte);
5529                         pte_unmap_unlock(pte, ptl);
5530
5531                         /* Advance to next. */
5532                         logical += PAGE_SIZE;
5533                     }
5534                 }
5535                 else
5536                 {
5537                     gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES);
5538                 }
5539
5540                 /* Check if this memory is contiguous for old mmu. */
5541                 if (Os->device->kernels[Core]->hardware->mmuVersion == 0)
5542                 {
5543                     for (i = 1; i < pageCount; i++)
5544                     {
5545                         if (pages[i] != nth_page(pages[0], i))
5546                         {
5547                             /* Non-contiguous. */
5548                             break;
5549                         }
5550                     }
5551
5552                     if (i == pageCount)
5553                     {
5554                         /* Contiguous memory. */
5555                         physical = page_to_phys(pages[0]) | (memory & ~PAGE_MASK);
5556
5557                         if (!((physical - Os->device->baseAddress) & 0x80000000))
5558                         {
5559                             kfree(pages);
5560                             pages = gcvNULL;
5561
5562                             info->pages = gcvNULL;
5563                             info->pageTable = gcvNULL;
5564
5565                             MEMORY_MAP_UNLOCK(Os);
5566
5567                             *Address = physical - Os->device->baseAddress;
5568                             *Info    = info;
5569
5570                             gcmkFOOTER_ARG("*Info=0x%X *Address=0x%08x",
5571                                            *Info, *Address);
5572
5573                             return gcvSTATUS_OK;
5574                         }
5575                     }
5576                 }
5577
5578                 /* Reference pages. */
5579                 for (i = 0; i < pageCount; i++)
5580                 {
5581                     get_page(pages[i]);
5582                 }
5583             }
5584         }
5585
5586         for (i = 0; i < pageCount; i++)
5587         {
5588 #ifdef CONFIG_ARM
5589             gctUINT32 data;
5590             get_user(data, (gctUINT32*)((memory & PAGE_MASK) + i * PAGE_SIZE));
5591 #endif
5592
5593             /* Flush(clean) the data cache. */
5594             gcmkONERROR(gckOS_CacheFlush(Os, _GetProcessID(), gcvNULL,
5595                              (gctPOINTER)(gctUINTPTR_T)page_to_phys(pages[i]),
5596                              (gctPOINTER)(memory & PAGE_MASK) + i*PAGE_SIZE,
5597                              PAGE_SIZE));
5598         }
5599
5600 #if gcdENABLE_VG
5601         if (Core == gcvCORE_VG)
5602         {
5603             /* Allocate pages inside the page table. */
5604             gcmkERR_BREAK(gckVGMMU_AllocatePages(Os->device->kernels[Core]->vg->mmu,
5605                                               pageCount * (PAGE_SIZE/4096),
5606                                               (gctPOINTER *) &pageTable,
5607                                               &address));
5608         }
5609         else
5610 #endif
5611         {
5612             /* Allocate pages inside the page table. */
5613             gcmkERR_BREAK(gckMMU_AllocatePages(Os->device->kernels[Core]->mmu,
5614                                               pageCount * (PAGE_SIZE/4096),
5615                                               (gctPOINTER *) &pageTable,
5616                                               &address));
5617         }
5618
5619         /* Fill the page table. */
5620         for (i = 0; i < pageCount; i++)
5621         {
5622             gctUINT32 phys;
5623             gctUINT32_PTR tab = pageTable + i * (PAGE_SIZE/4096);
5624
5625             phys = page_to_phys(pages[i]);
5626
5627 #if gcdENABLE_VG
5628             if (Core == gcvCORE_VG)
5629             {
5630                 /* Get the physical address from page struct. */
5631                 gcmkONERROR(
5632                     gckVGMMU_SetPage(Os->device->kernels[Core]->vg->mmu,
5633                                    phys,
5634                                    tab));
5635             }
5636             else
5637 #endif
5638             {
5639                 /* Get the physical address from page struct. */
5640                 gcmkONERROR(
5641                     gckMMU_SetPage(Os->device->kernels[Core]->mmu,
5642                                    phys,
5643                                    tab));
5644             }
5645
5646             for (j = 1; j < (PAGE_SIZE/4096); j++)
5647             {
5648                 pageTable[i * (PAGE_SIZE/4096) + j] = pageTable[i * (PAGE_SIZE/4096)] + 4096 * j;
5649             }
5650
5651             gcmkTRACE_ZONE(
5652                 gcvLEVEL_INFO, gcvZONE_OS,
5653                 "%s(%d): pageTable[%d]: 0x%X 0x%X.",
5654                 __FUNCTION__, __LINE__,
5655                 i, phys, pageTable[i]);
5656         }
5657
5658 #if gcdENABLE_VG
5659         if (Core == gcvCORE_VG)
5660         {
5661             gcmkONERROR(gckVGMMU_Flush(Os->device->kernels[Core]->vg->mmu));
5662         }
5663         else
5664 #endif
5665         {
5666             gcmkONERROR(gckMMU_Flush(Os->device->kernels[Core]->mmu));
5667         }
5668
5669         /* Save pointer to page table. */
5670         info->pageTable = pageTable;
5671         info->pages = pages;
5672
5673         *Info = (gctPOINTER) info;
5674
5675         gcmkTRACE_ZONE(
5676             gcvLEVEL_INFO, gcvZONE_OS,
5677             "%s(%d): info->pages: 0x%X, info->pageTable: 0x%X, info: 0x%X.",
5678             __FUNCTION__, __LINE__,
5679             info->pages,
5680             info->pageTable,
5681             info
5682             );
5683
5684         offset = (Physical != ~0U)
5685                ? (Physical & ~PAGE_MASK)
5686                : (memory & ~PAGE_MASK);
5687
5688         /* Return address. */
5689         *Address = address + offset;
5690
5691         gcmkTRACE_ZONE(
5692             gcvLEVEL_INFO, gcvZONE_OS,
5693             "%s(%d): Address: 0x%X.",
5694             __FUNCTION__, __LINE__,
5695             *Address
5696             );
5697
5698         /* Success. */
5699         status = gcvSTATUS_OK;
5700     }
5701     while (gcvFALSE);
5702
5703 OnError:
5704
5705     if (gcmIS_ERROR(status))
5706     {
5707         gcmkTRACE(
5708             gcvLEVEL_ERROR,
5709             "%s(%d): error occured: %d.",
5710             __FUNCTION__, __LINE__,
5711             status
5712             );
5713
5714         /* Release page array. */
5715         if (result > 0 && pages != gcvNULL)
5716         {
5717             gcmkTRACE(
5718                 gcvLEVEL_ERROR,
5719                 "%s(%d): error: page table is freed.",
5720                 __FUNCTION__, __LINE__
5721                 );
5722
5723             for (i = 0; i < result; i++)
5724             {
5725                 if (pages[i] == gcvNULL)
5726                 {
5727                     break;
5728                 }
5729                 page_cache_release(pages[i]);
5730             }
5731         }
5732
5733         if (info!= gcvNULL && pages != gcvNULL)
5734         {
5735             gcmkTRACE(
5736                 gcvLEVEL_ERROR,
5737                 "%s(%d): error: pages is freed.",
5738                 __FUNCTION__, __LINE__
5739                 );
5740
5741             /* Free the page table. */
5742             kfree(pages);
5743             info->pages = gcvNULL;
5744         }
5745
5746         /* Release page info struct. */
5747         if (info != gcvNULL)
5748         {
5749             gcmkTRACE(
5750                 gcvLEVEL_ERROR,
5751                 "%s(%d): error: info is freed.",
5752                 __FUNCTION__, __LINE__
5753                 );
5754
5755             /* Free the page info struct. */
5756             kfree(info);
5757             *Info = gcvNULL;
5758         }
5759     }
5760
5761     MEMORY_MAP_UNLOCK(Os);
5762
5763     /* Return the status. */
5764     if (gcmIS_SUCCESS(status))
5765     {
5766         gcmkFOOTER_ARG("*Info=0x%X *Address=0x%08x", *Info, *Address);
5767     }
5768     else
5769     {
5770         gcmkFOOTER();
5771     }
5772
5773     return status;
5774 }
5775 #endif
5776 }
5777
5778 /*******************************************************************************
5779 **
5780 **  gckOS_UnmapUserMemory
5781 **
5782 **  Unlock a user buffer and that was previously locked down by
5783 **  gckOS_MapUserMemory.
5784 **
5785 **  INPUT:
5786 **
5787 **      gctPOINTER Memory
5788 **          Pointer to memory to unlock.
5789 **
5790 **      gctSIZE_T Size
5791 **          Size in bytes of the memory to unlock.
5792 **
5793 **      gctPOINTER Info
5794 **          Information record returned by gckOS_MapUserMemory.
5795 **
5796 **      gctUINT32_PTR Address
5797 **          The address returned by gckOS_MapUserMemory.
5798 **
5799 **  OUTPUT:
5800 **
5801 **      Nothing.
5802 */
5803 gceSTATUS
5804 gckOS_UnmapUserMemory(
5805     IN gckOS Os,
5806     IN gceCORE Core,
5807     IN gctPOINTER Memory,
5808     IN gctSIZE_T Size,
5809     IN gctPOINTER Info,
5810     IN gctUINT32 Address
5811     )
5812 {
5813     gceSTATUS status;
5814
5815     gcmkHEADER_ARG("Os=0x%X Core=%d Memory=0x%X Size=%lu Info=0x%X Address0x%08x",
5816                    Os, Core, Memory, Size, Info, Address);
5817
5818 #if gcdSECURE_USER
5819     gcmkONERROR(gckOS_RemoveMapping(Os, Memory, Size));
5820
5821     gcmkFOOTER_NO();
5822     return gcvSTATUS_OK;
5823
5824 OnError:
5825     gcmkFOOTER();
5826     return status;
5827 #else
5828 {
5829     gctUINTPTR_T memory, start, end;
5830     gcsPageInfo_PTR info;
5831     gctSIZE_T pageCount, i;
5832     struct page **pages;
5833
5834     /* Verify the arguments. */
5835     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
5836     gcmkVERIFY_ARGUMENT(Memory != gcvNULL);
5837     gcmkVERIFY_ARGUMENT(Size > 0);
5838     gcmkVERIFY_ARGUMENT(Info != gcvNULL);
5839
5840     do
5841     {
5842         info = (gcsPageInfo_PTR) Info;
5843
5844         pages = info->pages;
5845
5846         gcmkTRACE_ZONE(
5847             gcvLEVEL_INFO, gcvZONE_OS,
5848             "%s(%d): info=0x%X, pages=0x%X.",
5849             __FUNCTION__, __LINE__,
5850             info, pages
5851             );
5852
5853         /* Invalid page array. */
5854         if (pages == gcvNULL && info->pageTable == gcvNULL)
5855         {
5856             kfree(info);
5857
5858             gcmkFOOTER_NO();
5859             return gcvSTATUS_OK;
5860         }
5861
5862         memory = (gctUINTPTR_T)Memory;
5863         end = (memory + Size + PAGE_SIZE - 1) >> PAGE_SHIFT;
5864         start = memory >> PAGE_SHIFT;
5865         pageCount = end - start;
5866
5867         /* Overflow. */
5868         if ((memory + Size) < memory)
5869         {
5870             gcmkFOOTER_ARG("status=%d", gcvSTATUS_INVALID_ARGUMENT);
5871             return gcvSTATUS_INVALID_ARGUMENT;
5872         }
5873
5874         gcmkTRACE_ZONE(
5875             gcvLEVEL_INFO, gcvZONE_OS,
5876             "%s(%d): memory: 0x%X, pageCount: %d, pageTable: 0x%X.",
5877             __FUNCTION__, __LINE__,
5878             memory, pageCount, info->pageTable
5879             );
5880
5881         MEMORY_MAP_LOCK(Os);
5882
5883         gcmkASSERT(info->pageTable != gcvNULL);
5884
5885 #if gcdENABLE_VG
5886         if (Core == gcvCORE_VG)
5887         {
5888             /* Free the pages from the MMU. */
5889             gcmkERR_BREAK(gckVGMMU_FreePages(Os->device->kernels[Core]->vg->mmu,
5890                                           info->pageTable,
5891                                           pageCount * (PAGE_SIZE/4096)
5892                                           ));
5893         }
5894         else
5895 #endif
5896         {
5897             /* Free the pages from the MMU. */
5898             gcmkERR_BREAK(gckMMU_FreePages(Os->device->kernels[Core]->mmu,
5899                                           info->pageTable,
5900                                           pageCount * (PAGE_SIZE/4096)
5901                                           ));
5902         }
5903
5904         /* Release the page cache. */
5905         if (pages)
5906         {
5907             for (i = 0; i < pageCount; i++)
5908             {
5909                 gcmkTRACE_ZONE(
5910                     gcvLEVEL_INFO, gcvZONE_OS,
5911                     "%s(%d): pages[%d]: 0x%X.",
5912                     __FUNCTION__, __LINE__,
5913                     i, pages[i]
5914                     );
5915
5916                 if (!PageReserved(pages[i]))
5917                 {
5918                      SetPageDirty(pages[i]);
5919                 }
5920
5921                 page_cache_release(pages[i]);
5922             }
5923         }
5924
5925         /* Success. */
5926         status = gcvSTATUS_OK;
5927     }
5928     while (gcvFALSE);
5929
5930     if (info != gcvNULL)
5931     {
5932         /* Free the page array. */
5933         if (info->pages != gcvNULL)
5934         {
5935             kfree(info->pages);
5936         }
5937
5938         kfree(info);
5939     }
5940
5941     MEMORY_MAP_UNLOCK(Os);
5942
5943     /* Return the status. */
5944     gcmkFOOTER();
5945     return status;
5946 }
5947 #endif
5948 }
5949
5950 /*******************************************************************************
5951 **
5952 **  gckOS_GetBaseAddress
5953 **
5954 **  Get the base address for the physical memory.
5955 **
5956 **  INPUT:
5957 **
5958 **      gckOS Os
5959 **          Pointer to the gckOS object.
5960 **
5961 **  OUTPUT:
5962 **
5963 **      gctUINT32_PTR BaseAddress
5964 **          Pointer to a variable that will receive the base address.
5965 */
5966 gceSTATUS
5967 gckOS_GetBaseAddress(
5968     IN gckOS Os,
5969     OUT gctUINT32_PTR BaseAddress
5970     )
5971 {
5972     gcmkHEADER_ARG("Os=0x%X", Os);
5973
5974     /* Verify the arguments. */
5975     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
5976     gcmkVERIFY_ARGUMENT(BaseAddress != gcvNULL);
5977
5978     /* Return base address. */
5979     *BaseAddress = Os->device->baseAddress;
5980
5981     /* Success. */
5982     gcmkFOOTER_ARG("*BaseAddress=0x%08x", *BaseAddress);
5983     return gcvSTATUS_OK;
5984 }
5985
5986 gceSTATUS
5987 gckOS_SuspendInterrupt(
5988     IN gckOS Os
5989     )
5990 {
5991     return gckOS_SuspendInterruptEx(Os, gcvCORE_MAJOR);
5992 }
5993
5994 gceSTATUS
5995 gckOS_SuspendInterruptEx(
5996     IN gckOS Os,
5997     IN gceCORE Core
5998     )
5999 {
6000     gcmkHEADER_ARG("Os=0x%X Core=%d", Os, Core);
6001
6002     /* Verify the arguments. */
6003     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
6004
6005     disable_irq(Os->device->irqLines[Core]);
6006
6007     gcmkFOOTER_NO();
6008     return gcvSTATUS_OK;
6009 }
6010
6011 gceSTATUS
6012 gckOS_ResumeInterrupt(
6013     IN gckOS Os
6014     )
6015 {
6016     return gckOS_ResumeInterruptEx(Os, gcvCORE_MAJOR);
6017 }
6018
6019 gceSTATUS
6020 gckOS_ResumeInterruptEx(
6021     IN gckOS Os,
6022     IN gceCORE Core
6023     )
6024 {
6025     gcmkHEADER_ARG("Os=0x%X Core=%d", Os, Core);
6026
6027     /* Verify the arguments. */
6028     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
6029
6030     enable_irq(Os->device->irqLines[Core]);
6031
6032     gcmkFOOTER_NO();
6033     return gcvSTATUS_OK;
6034 }
6035
6036 gceSTATUS
6037 gckOS_MemCopy(
6038     IN gctPOINTER Destination,
6039     IN gctCONST_POINTER Source,
6040     IN gctSIZE_T Bytes
6041     )
6042 {
6043     gcmkHEADER_ARG("Destination=0x%X Source=0x%X Bytes=%lu",
6044                    Destination, Source, Bytes);
6045
6046     gcmkVERIFY_ARGUMENT(Destination != gcvNULL);
6047     gcmkVERIFY_ARGUMENT(Source != gcvNULL);
6048     gcmkVERIFY_ARGUMENT(Bytes > 0);
6049
6050     memcpy(Destination, Source, Bytes);
6051
6052     gcmkFOOTER_NO();
6053     return gcvSTATUS_OK;
6054 }
6055
6056 gceSTATUS
6057 gckOS_ZeroMemory(
6058     IN gctPOINTER Memory,
6059     IN gctSIZE_T Bytes
6060     )
6061 {
6062     gcmkHEADER_ARG("Memory=0x%X Bytes=%lu", Memory, Bytes);
6063
6064     gcmkVERIFY_ARGUMENT(Memory != gcvNULL);
6065     gcmkVERIFY_ARGUMENT(Bytes > 0);
6066
6067     memset(Memory, 0, Bytes);
6068
6069     gcmkFOOTER_NO();
6070     return gcvSTATUS_OK;
6071 }
6072
6073 /*******************************************************************************
6074 ********************************* Cache Control ********************************
6075 *******************************************************************************/
6076
6077 #if !gcdCACHE_FUNCTION_UNIMPLEMENTED && defined(CONFIG_OUTER_CACHE)
6078 static inline gceSTATUS
6079 outer_func(
6080     gceCACHEOPERATION Type,
6081     unsigned long Start,
6082     unsigned long End
6083     )
6084 {
6085     switch (Type)
6086     {
6087         case gcvCACHE_CLEAN:
6088             outer_clean_range(Start, End);
6089             break;
6090         case gcvCACHE_INVALIDATE:
6091             outer_inv_range(Start, End);
6092             break;
6093         case gcvCACHE_FLUSH:
6094             outer_flush_range(Start, End);
6095             break;
6096         default:
6097             return gcvSTATUS_INVALID_ARGUMENT;
6098             break;
6099     }
6100     return gcvSTATUS_OK;
6101 }
6102
6103 #if gcdENABLE_OUTER_CACHE_PATCH
6104 /*******************************************************************************
6105 **  _HandleOuterCache
6106 **
6107 **  Handle the outer cache for the specified addresses.
6108 **
6109 **  ARGUMENTS:
6110 **
6111 **      gckOS Os
6112 **          Pointer to gckOS object.
6113 **
6114 **      gctUINT32 ProcessID
6115 **          Process ID Logical belongs.
6116 **
6117 **      gctPHYS_ADDR Handle
6118 **          Physical address handle.  If gcvNULL it is video memory.
6119 **
6120 **      gctPOINTER Physical
6121 **          Physical address to flush.
6122 **
6123 **      gctPOINTER Logical
6124 **          Logical address to flush.
6125 **
6126 **      gctSIZE_T Bytes
6127 **          Size of the address range in bytes to flush.
6128 **
6129 **      gceOUTERCACHE_OPERATION Type
6130 **          Operation need to be execute.
6131 */
6132 static gceSTATUS
6133 _HandleOuterCache(
6134     IN gckOS Os,
6135     IN gctUINT32 ProcessID,
6136     IN gctPHYS_ADDR Handle,
6137     IN gctPOINTER Physical,
6138     IN gctPOINTER Logical,
6139     IN gctSIZE_T Bytes,
6140     IN gceCACHEOPERATION Type
6141     )
6142 {
6143     gceSTATUS status;
6144     gctUINT32 i, pageNum;
6145     unsigned long paddr;
6146     gctPOINTER vaddr;
6147
6148     gcmkHEADER_ARG("Os=0x%X ProcessID=%d Handle=0x%X Logical=0x%X Bytes=%lu",
6149                    Os, ProcessID, Handle, Logical, Bytes);
6150
6151     if (Physical != gcvNULL)
6152     {
6153         /* Non paged memory or gcvPOOL_USER surface */
6154         paddr = (unsigned long) Physical;
6155         gcmkONERROR(outer_func(Type, paddr, paddr + Bytes));
6156     }
6157     else if ((Handle == gcvNULL)
6158     || (Handle != gcvNULL && ((PLINUX_MDL)Handle)->contiguous)
6159     )
6160     {
6161         /* Video Memory or contiguous virtual memory */
6162         gcmkONERROR(gckOS_GetPhysicalAddress(Os, Logical, (gctUINT32*)&paddr));
6163         gcmkONERROR(outer_func(Type, paddr, paddr + Bytes));
6164     }
6165     else
6166     {
6167         /* Non contiguous virtual memory */
6168         vaddr = (gctPOINTER)gcmALIGN_BASE((gctUINTPTR_T)Logical, PAGE_SIZE);
6169         pageNum = GetPageCount(Bytes, 0);
6170
6171         for (i = 0; i < pageNum; i += 1)
6172         {
6173             gcmkONERROR(_ConvertLogical2Physical(
6174                 Os,
6175                 vaddr + PAGE_SIZE * i,
6176                 ProcessID,
6177                 (PLINUX_MDL)Handle,
6178                 (gctUINT32*)&paddr
6179                 ));
6180
6181             gcmkONERROR(outer_func(Type, paddr, paddr + PAGE_SIZE));
6182         }
6183     }
6184
6185     mb();
6186
6187     /* Success. */
6188     gcmkFOOTER_NO();
6189     return gcvSTATUS_OK;
6190
6191 OnError:
6192     /* Return the status. */
6193     gcmkFOOTER();
6194     return status;
6195 }
6196 #endif
6197 #endif
6198
6199 /*******************************************************************************
6200 **  gckOS_CacheClean
6201 **
6202 **  Clean the cache for the specified addresses.  The GPU is going to need the
6203 **  data.  If the system is allocating memory as non-cachable, this function can
6204 **  be ignored.
6205 **
6206 **  ARGUMENTS:
6207 **
6208 **      gckOS Os
6209 **          Pointer to gckOS object.
6210 **
6211 **      gctUINT32 ProcessID
6212 **          Process ID Logical belongs.
6213 **
6214 **      gctPHYS_ADDR Handle
6215 **          Physical address handle.  If gcvNULL it is video memory.
6216 **
6217 **      gctPOINTER Physical
6218 **          Physical address to flush.
6219 **
6220 **      gctPOINTER Logical
6221 **          Logical address to flush.
6222 **
6223 **      gctSIZE_T Bytes
6224 **          Size of the address range in bytes to flush.
6225 */
6226 gceSTATUS
6227 gckOS_CacheClean(
6228     IN gckOS Os,
6229     IN gctUINT32 ProcessID,
6230     IN gctPHYS_ADDR Handle,
6231     IN gctPOINTER Physical,
6232     IN gctPOINTER Logical,
6233     IN gctSIZE_T Bytes
6234     )
6235 {
6236     gcmkHEADER_ARG("Os=0x%X ProcessID=%d Handle=0x%X Logical=0x%X Bytes=%lu",
6237                    Os, ProcessID, Handle, Logical, Bytes);
6238
6239     /* Verify the arguments. */
6240     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
6241     gcmkVERIFY_ARGUMENT(Logical != gcvNULL);
6242     gcmkVERIFY_ARGUMENT(Bytes > 0);
6243
6244 #if !gcdCACHE_FUNCTION_UNIMPLEMENTED
6245 #ifdef CONFIG_ARM
6246
6247     /* Inner cache. */
6248 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35)
6249     dmac_map_area(Logical, Bytes, DMA_TO_DEVICE);
6250 #      else
6251     dmac_clean_range(Logical, Logical + Bytes);
6252 #      endif
6253
6254 #if defined(CONFIG_OUTER_CACHE)
6255     /* Outer cache. */
6256 #if gcdENABLE_OUTER_CACHE_PATCH
6257     _HandleOuterCache(Os, ProcessID, Handle, Physical, Logical, Bytes, gcvCACHE_CLEAN);
6258 #else
6259     outer_clean_range((unsigned long) Handle, (unsigned long) Handle + Bytes);
6260 #endif
6261 #endif
6262
6263 #elif defined(CONFIG_MIPS)
6264
6265     dma_cache_wback((unsigned long) Logical, Bytes);
6266
6267 #elif defined(CONFIG_PPC)
6268
6269     /* TODO */
6270
6271 #else
6272     dma_sync_single_for_device(
6273               gcvNULL,
6274               (dma_addr_t)Physical,
6275               Bytes,
6276               DMA_TO_DEVICE);
6277 #endif
6278 #endif
6279
6280     /* Success. */
6281     gcmkFOOTER_NO();
6282     return gcvSTATUS_OK;
6283 }
6284
6285 /*******************************************************************************
6286 **  gckOS_CacheInvalidate
6287 **
6288 **  Invalidate the cache for the specified addresses. The GPU is going to need
6289 **  data.  If the system is allocating memory as non-cachable, this function can
6290 **  be ignored.
6291 **
6292 **  ARGUMENTS:
6293 **
6294 **      gckOS Os
6295 **          Pointer to gckOS object.
6296 **
6297 **      gctUINT32 ProcessID
6298 **          Process ID Logical belongs.
6299 **
6300 **      gctPHYS_ADDR Handle
6301 **          Physical address handle.  If gcvNULL it is video memory.
6302 **
6303 **      gctPOINTER Logical
6304 **          Logical address to flush.
6305 **
6306 **      gctSIZE_T Bytes
6307 **          Size of the address range in bytes to flush.
6308 */
6309 gceSTATUS
6310 gckOS_CacheInvalidate(
6311     IN gckOS Os,
6312     IN gctUINT32 ProcessID,
6313     IN gctPHYS_ADDR Handle,
6314     IN gctPOINTER Physical,
6315     IN gctPOINTER Logical,
6316     IN gctSIZE_T Bytes
6317     )
6318 {
6319     gcmkHEADER_ARG("Os=0x%X ProcessID=%d Handle=0x%X Logical=0x%X Bytes=%lu",
6320                    Os, ProcessID, Handle, Logical, Bytes);
6321
6322     /* Verify the arguments. */
6323     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
6324     gcmkVERIFY_ARGUMENT(Logical != gcvNULL);
6325     gcmkVERIFY_ARGUMENT(Bytes > 0);
6326
6327 #if !gcdCACHE_FUNCTION_UNIMPLEMENTED
6328 #ifdef CONFIG_ARM
6329
6330     /* Inner cache. */
6331 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35)
6332     dmac_map_area(Logical, Bytes, DMA_FROM_DEVICE);
6333 #      else
6334     dmac_inv_range(Logical, Logical + Bytes);
6335 #      endif
6336
6337 #if defined(CONFIG_OUTER_CACHE)
6338     /* Outer cache. */
6339 #if gcdENABLE_OUTER_CACHE_PATCH
6340     _HandleOuterCache(Os, ProcessID, Handle, Physical, Logical, Bytes, gcvCACHE_INVALIDATE);
6341 #else
6342     outer_inv_range((unsigned long) Handle, (unsigned long) Handle + Bytes);
6343 #endif
6344 #endif
6345
6346 #elif defined(CONFIG_MIPS)
6347     dma_cache_inv((unsigned long) Logical, Bytes);
6348 #elif defined(CONFIG_PPC)
6349     /* TODO */
6350 #else
6351     dma_sync_single_for_device(
6352               gcvNULL,
6353               (dma_addr_t)Physical,
6354               Bytes,
6355               DMA_FROM_DEVICE);
6356 #endif
6357 #endif
6358
6359     /* Success. */
6360     gcmkFOOTER_NO();
6361     return gcvSTATUS_OK;
6362 }
6363
6364 /*******************************************************************************
6365 **  gckOS_CacheFlush
6366 **
6367 **  Clean the cache for the specified addresses and invalidate the lines as
6368 **  well.  The GPU is going to need and modify the data.  If the system is
6369 **  allocating memory as non-cachable, this function can be ignored.
6370 **
6371 **  ARGUMENTS:
6372 **
6373 **      gckOS Os
6374 **          Pointer to gckOS object.
6375 **
6376 **      gctUINT32 ProcessID
6377 **          Process ID Logical belongs.
6378 **
6379 **      gctPHYS_ADDR Handle
6380 **          Physical address handle.  If gcvNULL it is video memory.
6381 **
6382 **      gctPOINTER Logical
6383 **          Logical address to flush.
6384 **
6385 **      gctSIZE_T Bytes
6386 **          Size of the address range in bytes to flush.
6387 */
6388 gceSTATUS
6389 gckOS_CacheFlush(
6390     IN gckOS Os,
6391     IN gctUINT32 ProcessID,
6392     IN gctPHYS_ADDR Handle,
6393     IN gctPOINTER Physical,
6394     IN gctPOINTER Logical,
6395     IN gctSIZE_T Bytes
6396     )
6397 {
6398     gcmkHEADER_ARG("Os=0x%X ProcessID=%d Handle=0x%X Logical=0x%X Bytes=%lu",
6399                    Os, ProcessID, Handle, Logical, Bytes);
6400
6401     /* Verify the arguments. */
6402     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
6403     gcmkVERIFY_ARGUMENT(Logical != gcvNULL);
6404     gcmkVERIFY_ARGUMENT(Bytes > 0);
6405
6406 #if !gcdCACHE_FUNCTION_UNIMPLEMENTED
6407 #ifdef CONFIG_ARM
6408     /* Inner cache. */
6409     dmac_flush_range(Logical, Logical + Bytes);
6410
6411 #if defined(CONFIG_OUTER_CACHE)
6412     /* Outer cache. */
6413 #if gcdENABLE_OUTER_CACHE_PATCH
6414     _HandleOuterCache(Os, ProcessID, Handle, Physical, Logical, Bytes, gcvCACHE_FLUSH);
6415 #else
6416     outer_flush_range((unsigned long) Handle, (unsigned long) Handle + Bytes);
6417 #endif
6418 #endif
6419
6420 #elif defined(CONFIG_MIPS)
6421     dma_cache_wback_inv((unsigned long) Logical, Bytes);
6422 #elif defined(CONFIG_PPC)
6423     /* TODO */
6424 #else
6425     dma_sync_single_for_device(
6426               gcvNULL,
6427               (dma_addr_t)Physical,
6428               Bytes,
6429               DMA_BIDIRECTIONAL);
6430 #endif
6431 #endif
6432
6433     /* Success. */
6434     gcmkFOOTER_NO();
6435     return gcvSTATUS_OK;
6436 }
6437
6438 /*******************************************************************************
6439 ********************************* Broadcasting *********************************
6440 *******************************************************************************/
6441
6442 /*******************************************************************************
6443 **
6444 **  gckOS_Broadcast
6445 **
6446 **  System hook for broadcast events from the kernel driver.
6447 **
6448 **  INPUT:
6449 **
6450 **      gckOS Os
6451 **          Pointer to the gckOS object.
6452 **
6453 **      gckHARDWARE Hardware
6454 **          Pointer to the gckHARDWARE object.
6455 **
6456 **      gceBROADCAST Reason
6457 **          Reason for the broadcast.  Can be one of the following values:
6458 **
6459 **              gcvBROADCAST_GPU_IDLE
6460 **                  Broadcasted when the kernel driver thinks the GPU might be
6461 **                  idle.  This can be used to handle power management.
6462 **
6463 **              gcvBROADCAST_GPU_COMMIT
6464 **                  Broadcasted when any client process commits a command
6465 **                  buffer.  This can be used to handle power management.
6466 **
6467 **              gcvBROADCAST_GPU_STUCK
6468 **                  Broadcasted when the kernel driver hits the timeout waiting
6469 **                  for the GPU.
6470 **
6471 **              gcvBROADCAST_FIRST_PROCESS
6472 **                  First process is trying to connect to the kernel.
6473 **
6474 **              gcvBROADCAST_LAST_PROCESS
6475 **                  Last process has detached from the kernel.
6476 **
6477 **  OUTPUT:
6478 **
6479 **      Nothing.
6480 */
6481 gceSTATUS
6482 gckOS_Broadcast(
6483     IN gckOS Os,
6484     IN gckHARDWARE Hardware,
6485     IN gceBROADCAST Reason
6486     )
6487 {
6488     gceSTATUS status;
6489
6490     gcmkHEADER_ARG("Os=0x%X Hardware=0x%X Reason=%d", Os, Hardware, Reason);
6491
6492     /* Verify the arguments. */
6493     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
6494     gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
6495
6496     switch (Reason)
6497     {
6498     case gcvBROADCAST_FIRST_PROCESS:
6499         gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_OS, "First process has attached");
6500         break;
6501
6502     case gcvBROADCAST_LAST_PROCESS:
6503         gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_OS, "Last process has detached");
6504
6505         /* Put GPU OFF. */
6506         gcmkONERROR(
6507             gckHARDWARE_SetPowerManagementState(Hardware,
6508                                                 gcvPOWER_OFF_BROADCAST));
6509         break;
6510
6511     case gcvBROADCAST_GPU_IDLE:
6512         gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_OS, "GPU idle.");
6513
6514         /* Put GPU IDLE. */
6515         gcmkONERROR(
6516             gckHARDWARE_SetPowerManagementState(Hardware,
6517 #if gcdPOWER_SUSNPEND_WHEN_IDLE
6518                                                 gcvPOWER_SUSPEND_BROADCAST));
6519 #else
6520                                                 gcvPOWER_IDLE_BROADCAST));
6521 #endif
6522
6523         /* Add idle process DB. */
6524         gcmkONERROR(gckKERNEL_AddProcessDB(Hardware->kernel,
6525                                            1,
6526                                            gcvDB_IDLE,
6527                                            gcvNULL, gcvNULL, 0));
6528         break;
6529
6530     case gcvBROADCAST_GPU_COMMIT:
6531         gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_OS, "COMMIT has arrived.");
6532
6533         /* Add busy process DB. */
6534         gcmkONERROR(gckKERNEL_AddProcessDB(Hardware->kernel,
6535                                            0,
6536                                            gcvDB_IDLE,
6537                                            gcvNULL, gcvNULL, 0));
6538
6539         /* Put GPU ON. */
6540         gcmkONERROR(
6541             gckHARDWARE_SetPowerManagementState(Hardware, gcvPOWER_ON_AUTO));
6542         break;
6543
6544     case gcvBROADCAST_GPU_STUCK:
6545         gcmkTRACE_N(gcvLEVEL_ERROR, 0, "gcvBROADCAST_GPU_STUCK\n");
6546 #if !gcdENABLE_RECOVERY
6547         gcmkONERROR(gckHARDWARE_DumpGPUState(Hardware));
6548 #endif
6549         gcmkONERROR(gckKERNEL_Recovery(Hardware->kernel));
6550         break;
6551
6552     case gcvBROADCAST_AXI_BUS_ERROR:
6553         gcmkTRACE_N(gcvLEVEL_ERROR, 0, "gcvBROADCAST_AXI_BUS_ERROR\n");
6554         gcmkONERROR(gckHARDWARE_DumpGPUState(Hardware));
6555         gcmkONERROR(gckKERNEL_Recovery(Hardware->kernel));
6556         break;
6557     }
6558
6559     /* Success. */
6560     gcmkFOOTER_NO();
6561     return gcvSTATUS_OK;
6562
6563 OnError:
6564     /* Return the status. */
6565     gcmkFOOTER();
6566     return status;
6567 }
6568
6569 /*******************************************************************************
6570 **
6571 **  gckOS_BroadcastHurry
6572 **
6573 **  The GPU is running too slow.
6574 **
6575 **  INPUT:
6576 **
6577 **      gckOS Os
6578 **          Pointer to the gckOS object.
6579 **
6580 **      gckHARDWARE Hardware
6581 **          Pointer to the gckHARDWARE object.
6582 **
6583 **      gctUINT Urgency
6584 **          The higher the number, the higher the urgency to speed up the GPU.
6585 **          The maximum value is defined by the gcdDYNAMIC_EVENT_THRESHOLD.
6586 **
6587 **  OUTPUT:
6588 **
6589 **      Nothing.
6590 */
6591 gceSTATUS
6592 gckOS_BroadcastHurry(
6593     IN gckOS Os,
6594     IN gckHARDWARE Hardware,
6595     IN gctUINT Urgency
6596     )
6597 {
6598     gcmkHEADER_ARG("Os=0x%x Hardware=0x%x Urgency=%u", Os, Hardware, Urgency);
6599
6600     /* Do whatever you need to do to speed up the GPU now. */
6601
6602     /* Success. */
6603     gcmkFOOTER_NO();
6604     return gcvSTATUS_OK;
6605 }
6606
6607 /*******************************************************************************
6608 **
6609 **  gckOS_BroadcastCalibrateSpeed
6610 **
6611 **  Calibrate the speed of the GPU.
6612 **
6613 **  INPUT:
6614 **
6615 **      gckOS Os
6616 **          Pointer to the gckOS object.
6617 **
6618 **      gckHARDWARE Hardware
6619 **          Pointer to the gckHARDWARE object.
6620 **
6621 **      gctUINT Idle, Time
6622 **          Idle/Time will give the percentage the GPU is idle, so you can use
6623 **          this to calibrate the working point of the GPU.
6624 **
6625 **  OUTPUT:
6626 **
6627 **      Nothing.
6628 */
6629 gceSTATUS
6630 gckOS_BroadcastCalibrateSpeed(
6631     IN gckOS Os,
6632     IN gckHARDWARE Hardware,
6633     IN gctUINT Idle,
6634     IN gctUINT Time
6635     )
6636 {
6637     gcmkHEADER_ARG("Os=0x%x Hardware=0x%x Idle=%u Time=%u",
6638                    Os, Hardware, Idle, Time);
6639
6640     /* Do whatever you need to do to callibrate the GPU speed. */
6641
6642     /* Success. */
6643     gcmkFOOTER_NO();
6644     return gcvSTATUS_OK;
6645 }
6646
6647 /*******************************************************************************
6648 ********************************** Semaphores **********************************
6649 *******************************************************************************/
6650
6651 /*******************************************************************************
6652 **
6653 **  gckOS_CreateSemaphore
6654 **
6655 **  Create a semaphore.
6656 **
6657 **  INPUT:
6658 **
6659 **      gckOS Os
6660 **          Pointer to the gckOS object.
6661 **
6662 **  OUTPUT:
6663 **
6664 **      gctPOINTER * Semaphore
6665 **          Pointer to the variable that will receive the created semaphore.
6666 */
6667 gceSTATUS
6668 gckOS_CreateSemaphore(
6669     IN gckOS Os,
6670     OUT gctPOINTER * Semaphore
6671     )
6672 {
6673     gceSTATUS status;
6674     struct semaphore *sem = gcvNULL;
6675
6676     gcmkHEADER_ARG("Os=0x%X", Os);
6677
6678     /* Verify the arguments. */
6679     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
6680     gcmkVERIFY_ARGUMENT(Semaphore != gcvNULL);
6681
6682     /* Allocate the semaphore structure. */
6683     sem = (struct semaphore *)kmalloc(gcmSIZEOF(struct semaphore), GFP_KERNEL | gcdNOWARN);
6684     if (sem == gcvNULL)
6685     {
6686         gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
6687     }
6688
6689     /* Initialize the semaphore. */
6690     sema_init(sem, 1);
6691
6692     /* Return to caller. */
6693     *Semaphore = (gctPOINTER) sem;
6694
6695     /* Success. */
6696     gcmkFOOTER_NO();
6697     return gcvSTATUS_OK;
6698
6699 OnError:
6700     /* Return the status. */
6701     gcmkFOOTER();
6702     return status;
6703 }
6704
6705 /*******************************************************************************
6706 **
6707 **  gckOS_AcquireSemaphore
6708 **
6709 **  Acquire a semaphore.
6710 **
6711 **  INPUT:
6712 **
6713 **      gckOS Os
6714 **          Pointer to the gckOS object.
6715 **
6716 **      gctPOINTER Semaphore
6717 **          Pointer to the semaphore thet needs to be acquired.
6718 **
6719 **  OUTPUT:
6720 **
6721 **      Nothing.
6722 */
6723 gceSTATUS
6724 gckOS_AcquireSemaphore(
6725     IN gckOS Os,
6726     IN gctPOINTER Semaphore
6727     )
6728 {
6729     gceSTATUS status;
6730
6731     gcmkHEADER_ARG("Os=0x%08X Semaphore=0x%08X", Os, Semaphore);
6732
6733     /* Verify the arguments. */
6734     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
6735     gcmkVERIFY_ARGUMENT(Semaphore != gcvNULL);
6736
6737     /* Acquire the semaphore. */
6738     if (down_interruptible((struct semaphore *) Semaphore))
6739     {
6740         gcmkONERROR(gcvSTATUS_INTERRUPTED);
6741     }
6742
6743     /* Success. */
6744     gcmkFOOTER_NO();
6745     return gcvSTATUS_OK;
6746
6747 OnError:
6748     /* Return the status. */
6749     gcmkFOOTER();
6750     return status;
6751 }
6752
6753 /*******************************************************************************
6754 **
6755 **  gckOS_TryAcquireSemaphore
6756 **
6757 **  Try to acquire a semaphore.
6758 **
6759 **  INPUT:
6760 **
6761 **      gckOS Os
6762 **          Pointer to the gckOS object.
6763 **
6764 **      gctPOINTER Semaphore
6765 **          Pointer to the semaphore thet needs to be acquired.
6766 **
6767 **  OUTPUT:
6768 **
6769 **      Nothing.
6770 */
6771 gceSTATUS
6772 gckOS_TryAcquireSemaphore(
6773     IN gckOS Os,
6774     IN gctPOINTER Semaphore
6775     )
6776 {
6777     gceSTATUS status;
6778
6779     gcmkHEADER_ARG("Os=0x%x", Os);
6780
6781     /* Verify the arguments. */
6782     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
6783     gcmkVERIFY_ARGUMENT(Semaphore != gcvNULL);
6784
6785     /* Acquire the semaphore. */
6786     if (down_trylock((struct semaphore *) Semaphore))
6787     {
6788         /* Timeout. */
6789         status = gcvSTATUS_TIMEOUT;
6790         gcmkFOOTER();
6791         return status;
6792     }
6793
6794     /* Success. */
6795     gcmkFOOTER_NO();
6796     return gcvSTATUS_OK;
6797 }
6798
6799 /*******************************************************************************
6800 **
6801 **  gckOS_ReleaseSemaphore
6802 **
6803 **  Release a previously acquired semaphore.
6804 **
6805 **  INPUT:
6806 **
6807 **      gckOS Os
6808 **          Pointer to the gckOS object.
6809 **
6810 **      gctPOINTER Semaphore
6811 **          Pointer to the semaphore thet needs to be released.
6812 **
6813 **  OUTPUT:
6814 **
6815 **      Nothing.
6816 */
6817 gceSTATUS
6818 gckOS_ReleaseSemaphore(
6819     IN gckOS Os,
6820     IN gctPOINTER Semaphore
6821     )
6822 {
6823     gcmkHEADER_ARG("Os=0x%X Semaphore=0x%X", Os, Semaphore);
6824
6825     /* Verify the arguments. */
6826     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
6827     gcmkVERIFY_ARGUMENT(Semaphore != gcvNULL);
6828
6829     /* Release the semaphore. */
6830     up((struct semaphore *) Semaphore);
6831
6832     /* Success. */
6833     gcmkFOOTER_NO();
6834     return gcvSTATUS_OK;
6835 }
6836
6837 /*******************************************************************************
6838 **
6839 **  gckOS_DestroySemaphore
6840 **
6841 **  Destroy a semaphore.
6842 **
6843 **  INPUT:
6844 **
6845 **      gckOS Os
6846 **          Pointer to the gckOS object.
6847 **
6848 **      gctPOINTER Semaphore
6849 **          Pointer to the semaphore thet needs to be destroyed.
6850 **
6851 **  OUTPUT:
6852 **
6853 **      Nothing.
6854 */
6855 gceSTATUS
6856 gckOS_DestroySemaphore(
6857     IN gckOS Os,
6858     IN gctPOINTER Semaphore
6859     )
6860 {
6861     gcmkHEADER_ARG("Os=0x%X Semaphore=0x%X", Os, Semaphore);
6862
6863      /* Verify the arguments. */
6864     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
6865     gcmkVERIFY_ARGUMENT(Semaphore != gcvNULL);
6866
6867     /* Free the sempahore structure. */
6868     kfree(Semaphore);
6869
6870     /* Success. */
6871     gcmkFOOTER_NO();
6872     return gcvSTATUS_OK;
6873 }
6874
6875 /*******************************************************************************
6876 **
6877 **  gckOS_GetProcessID
6878 **
6879 **  Get current process ID.
6880 **
6881 **  INPUT:
6882 **
6883 **      Nothing.
6884 **
6885 **  OUTPUT:
6886 **
6887 **      gctUINT32_PTR ProcessID
6888 **          Pointer to the variable that receives the process ID.
6889 */
6890 gceSTATUS
6891 gckOS_GetProcessID(
6892     OUT gctUINT32_PTR ProcessID
6893     )
6894 {
6895     /* Get process ID. */
6896     if (ProcessID != gcvNULL)
6897     {
6898         *ProcessID = _GetProcessID();
6899     }
6900
6901     /* Success. */
6902     return gcvSTATUS_OK;
6903 }
6904
6905 /*******************************************************************************
6906 **
6907 **  gckOS_GetThreadID
6908 **
6909 **  Get current thread ID.
6910 **
6911 **  INPUT:
6912 **
6913 **      Nothing.
6914 **
6915 **  OUTPUT:
6916 **
6917 **      gctUINT32_PTR ThreadID
6918 **          Pointer to the variable that receives the thread ID.
6919 */
6920 gceSTATUS
6921 gckOS_GetThreadID(
6922     OUT gctUINT32_PTR ThreadID
6923     )
6924 {
6925     /* Get thread ID. */
6926     if (ThreadID != gcvNULL)
6927     {
6928         *ThreadID = _GetThreadID();
6929     }
6930
6931     /* Success. */
6932     return gcvSTATUS_OK;
6933 }
6934
6935 /*******************************************************************************
6936 **
6937 **  gckOS_SetGPUPower
6938 **
6939 **  Set the power of the GPU on or off.
6940 **
6941 **  INPUT:
6942 **
6943 **      gckOS Os
6944 **          Pointer to a gckOS object.
6945 **
6946 **      gckCORE Core
6947 **          GPU whose power is set.
6948 **
6949 **      gctBOOL Clock
6950 **          gcvTRUE to turn on the clock, or gcvFALSE to turn off the clock.
6951 **
6952 **      gctBOOL Power
6953 **          gcvTRUE to turn on the power, or gcvFALSE to turn off the power.
6954 **
6955 **  OUTPUT:
6956 **
6957 **      Nothing.
6958 */
6959 gceSTATUS
6960 gckOS_SetGPUPower(
6961     IN gckOS Os,
6962     IN gceCORE Core,
6963     IN gctBOOL Clock,
6964     IN gctBOOL Power
6965     )
6966 {
6967     struct clk *clk_3dcore = Os->device->clk_3d_core;
6968     struct clk *clk_3dshader = Os->device->clk_3d_shader;
6969 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0)
6970     struct clk *clk_3d_axi = Os->device->clk_3d_axi;
6971 #endif
6972     struct clk *clk_2dcore = Os->device->clk_2d_core;
6973     struct clk *clk_2d_axi = Os->device->clk_2d_axi;
6974     struct clk *clk_vg_axi = Os->device->clk_vg_axi;
6975 #if LINUX_VERSION_CODE < KERNEL_VERSION(3,5,0) || LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
6976     int ret;
6977 #endif
6978
6979     gctBOOL oldClockState = gcvFALSE;
6980     gctBOOL oldPowerState = gcvFALSE;
6981
6982     gcmkHEADER_ARG("Os=0x%X Core=%d Clock=%d Power=%d", Os, Core, Clock, Power);
6983
6984     if (Os->device->kernels[Core] != NULL)
6985     {
6986 #if gcdENABLE_VG
6987         if (Core == gcvCORE_VG)
6988         {
6989             oldClockState = Os->device->kernels[Core]->vg->hardware->clockState;
6990             oldPowerState = Os->device->kernels[Core]->vg->hardware->powerState;
6991         }
6992         else
6993         {
6994 #endif
6995             oldClockState = Os->device->kernels[Core]->hardware->clockState;
6996             oldPowerState = Os->device->kernels[Core]->hardware->powerState;
6997 #if gcdENABLE_VG
6998         }
6999 #endif
7000     }
7001         if((Power == gcvTRUE) && (oldPowerState == gcvFALSE))
7002         {
7003 #if LINUX_VERSION_CODE < KERNEL_VERSION(3,5,0) || LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
7004         if(!IS_ERR(Os->device->gpu_regulator)) {
7005             ret = regulator_enable(Os->device->gpu_regulator);
7006             if (ret != 0)
7007                 gckOS_Print("%s(%d): fail to enable pu regulator %d!\n",
7008                     __FUNCTION__, __LINE__, ret);
7009         }
7010 #else
7011         imx_gpc_power_up_pu(true);
7012 #endif
7013
7014 #ifdef CONFIG_PM
7015                 pm_runtime_get_sync(Os->device->pmdev);
7016 #endif
7017         }
7018
7019 #if LINUX_VERSION_CODE < KERNEL_VERSION(3,5,0)
7020     if (Clock == gcvTRUE) {
7021         if (oldClockState == gcvFALSE) {
7022             switch (Core) {
7023             case gcvCORE_MAJOR:
7024                 clk_enable(clk_3dcore);
7025                 if (cpu_is_mx6q())
7026                     clk_enable(clk_3dshader);
7027                 break;
7028             case gcvCORE_2D:
7029                 clk_enable(clk_2dcore);
7030                 clk_enable(clk_2d_axi);
7031                 break;
7032             case gcvCORE_VG:
7033                 clk_enable(clk_2dcore);
7034                 clk_enable(clk_vg_axi);
7035                 break;
7036             default:
7037                 break;
7038             }
7039         }
7040     } else {
7041         if (oldClockState == gcvTRUE) {
7042             switch (Core) {
7043             case gcvCORE_MAJOR:
7044                 if (cpu_is_mx6q())
7045                     clk_disable(clk_3dshader);
7046                 clk_disable(clk_3dcore);
7047                 break;
7048            case gcvCORE_2D:
7049                 clk_disable(clk_2dcore);
7050                 clk_disable(clk_2d_axi);
7051                 break;
7052             case gcvCORE_VG:
7053                 clk_disable(clk_2dcore);
7054                 clk_disable(clk_vg_axi);
7055                 break;
7056             default:
7057                 break;
7058             }
7059         }
7060     }
7061 #else
7062     if (Clock == gcvTRUE) {
7063         if (oldClockState == gcvFALSE) {
7064             switch (Core) {
7065             case gcvCORE_MAJOR:
7066                 clk_prepare(clk_3dcore);
7067                 clk_enable(clk_3dcore);
7068                 clk_prepare(clk_3dshader);
7069                 clk_enable(clk_3dshader);
7070                 clk_prepare(clk_3d_axi);
7071                 clk_enable(clk_3d_axi);
7072                 break;
7073             case gcvCORE_2D:
7074                 clk_prepare(clk_2dcore);
7075                 clk_enable(clk_2dcore);
7076                 clk_prepare(clk_2d_axi);
7077                 clk_enable(clk_2d_axi);
7078                 break;
7079             case gcvCORE_VG:
7080                 clk_prepare(clk_2dcore);
7081                 clk_enable(clk_2dcore);
7082                 clk_prepare(clk_vg_axi);
7083                 clk_enable(clk_vg_axi);
7084                 break;
7085             default:
7086                 break;
7087             }
7088         }
7089     } else {
7090         if (oldClockState == gcvTRUE) {
7091             switch (Core) {
7092             case gcvCORE_MAJOR:
7093                 clk_disable(clk_3dshader);
7094                 clk_unprepare(clk_3dshader);
7095                 clk_disable(clk_3dcore);
7096                 clk_unprepare(clk_3dcore);
7097                 clk_disable(clk_3d_axi);
7098                 clk_unprepare(clk_3d_axi);
7099                 break;
7100            case gcvCORE_2D:
7101                 clk_disable(clk_2dcore);
7102                 clk_unprepare(clk_2dcore);
7103                 clk_disable(clk_2d_axi);
7104                 clk_unprepare(clk_2d_axi);
7105                 break;
7106             case gcvCORE_VG:
7107                 clk_disable(clk_2dcore);
7108                 clk_unprepare(clk_2dcore);
7109                 clk_disable(clk_vg_axi);
7110                 clk_unprepare(clk_vg_axi);
7111                 break;
7112             default:
7113                 break;
7114             }
7115         }
7116     }
7117 #endif
7118         if((Power == gcvFALSE) && (oldPowerState == gcvTRUE))
7119         {
7120 #ifdef CONFIG_PM
7121                 pm_runtime_put_sync(Os->device->pmdev);
7122 #endif
7123
7124 #if LINUX_VERSION_CODE < KERNEL_VERSION(3,5,0) || LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
7125         if(!IS_ERR(Os->device->gpu_regulator))
7126             regulator_disable(Os->device->gpu_regulator);
7127 #else
7128         imx_gpc_power_up_pu(false);
7129 #endif
7130
7131         }
7132     /* TODO: Put your code here. */
7133     gcmkFOOTER_NO();
7134     return gcvSTATUS_OK;
7135 }
7136
7137 /*******************************************************************************
7138 **
7139 **  gckOS_ResetGPU
7140 **
7141 **  Reset the GPU.
7142 **
7143 **  INPUT:
7144 **
7145 **      gckOS Os
7146 **          Pointer to a gckOS object.
7147 **
7148 **      gckCORE Core
7149 **          GPU whose power is set.
7150 **
7151 **  OUTPUT:
7152 **
7153 **      Nothing.
7154 */
7155 gceSTATUS
7156 gckOS_ResetGPU(
7157     IN gckOS Os,
7158     IN gceCORE Core
7159     )
7160 {
7161 #if LINUX_VERSION_CODE < KERNEL_VERSION(3,5,0)
7162 #define SRC_SCR_OFFSET 0
7163 #define BP_SRC_SCR_GPU3D_RST 1
7164 #define BP_SRC_SCR_GPU2D_RST 4
7165     void __iomem *src_base = IO_ADDRESS(SRC_BASE_ADDR);
7166     gctUINT32 bit_offset,val;
7167
7168     gcmkHEADER_ARG("Os=0x%X Core=%d", Os, Core);
7169
7170     if(Core == gcvCORE_MAJOR) {
7171         bit_offset = BP_SRC_SCR_GPU3D_RST;
7172     } else if((Core == gcvCORE_VG)
7173             ||(Core == gcvCORE_2D)) {
7174         bit_offset = BP_SRC_SCR_GPU2D_RST;
7175     } else {
7176         return gcvSTATUS_INVALID_CONFIG;
7177     }
7178     val = __raw_readl(src_base + SRC_SCR_OFFSET);
7179     val &= ~(1 << (bit_offset));
7180     val |= (1 << (bit_offset));
7181     __raw_writel(val, src_base + SRC_SCR_OFFSET);
7182
7183     while ((__raw_readl(src_base + SRC_SCR_OFFSET) &
7184                 (1 << (bit_offset))) != 0) {
7185     }
7186
7187     gcmkFOOTER_NO();
7188 #elif LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
7189         struct reset_control *rstc = Os->device->rstc[Core];
7190         if (rstc)
7191                 reset_control_reset(rstc);
7192 #else
7193     imx_src_reset_gpu((int)Core);
7194 #endif
7195     return gcvSTATUS_OK;
7196 }
7197
7198 /*******************************************************************************
7199 **
7200 **  gckOS_PrepareGPUFrequency
7201 **
7202 **  Prepare to set GPU frequency and voltage.
7203 **
7204 **  INPUT:
7205 **
7206 **      gckOS Os
7207 **          Pointer to a gckOS object.
7208 **
7209 **      gckCORE Core
7210 **          GPU whose frequency and voltage will be set.
7211 **
7212 **  OUTPUT:
7213 **
7214 **      Nothing.
7215 */
7216 gceSTATUS
7217 gckOS_PrepareGPUFrequency(
7218     IN gckOS Os,
7219     IN gceCORE Core
7220     )
7221 {
7222     return gcvSTATUS_OK;
7223 }
7224
7225 /*******************************************************************************
7226 **
7227 **  gckOS_FinishGPUFrequency
7228 **
7229 **  Finish GPU frequency setting.
7230 **
7231 **  INPUT:
7232 **
7233 **      gckOS Os
7234 **          Pointer to a gckOS object.
7235 **
7236 **      gckCORE Core
7237 **          GPU whose frequency and voltage is set.
7238 **
7239 **  OUTPUT:
7240 **
7241 **      Nothing.
7242 */
7243 gceSTATUS
7244 gckOS_FinishGPUFrequency(
7245     IN gckOS Os,
7246     IN gceCORE Core
7247     )
7248 {
7249     return gcvSTATUS_OK;
7250 }
7251
7252 /*******************************************************************************
7253 **
7254 **  gckOS_QueryGPUFrequency
7255 **
7256 **  Query the current frequency of the GPU.
7257 **
7258 **  INPUT:
7259 **
7260 **      gckOS Os
7261 **          Pointer to a gckOS object.
7262 **
7263 **      gckCORE Core
7264 **          GPU whose power is set.
7265 **
7266 **      gctUINT32 * Frequency
7267 **          Pointer to a gctUINT32 to obtain current frequency, in MHz.
7268 **
7269 **      gctUINT8 * Scale
7270 **          Pointer to a gctUINT8 to obtain current scale(1 - 64).
7271 **
7272 **  OUTPUT:
7273 **
7274 **      Nothing.
7275 */
7276 gceSTATUS
7277 gckOS_QueryGPUFrequency(
7278     IN gckOS Os,
7279     IN gceCORE Core,
7280     OUT gctUINT32 * Frequency,
7281     OUT gctUINT8 * Scale
7282     )
7283 {
7284     return gcvSTATUS_OK;
7285 }
7286
7287 /*******************************************************************************
7288 **
7289 **  gckOS_SetGPUFrequency
7290 **
7291 **  Set frequency and voltage of the GPU.
7292 **
7293 **      1. DVFS manager gives the target scale of full frequency, BSP must find
7294 **         a real frequency according to this scale and board's configure.
7295 **
7296 **      2. BSP should find a suitable voltage for this frequency.
7297 **
7298 **      3. BSP must make sure setting take effect before this function returns.
7299 **
7300 **  INPUT:
7301 **
7302 **      gckOS Os
7303 **          Pointer to a gckOS object.
7304 **
7305 **      gckCORE Core
7306 **          GPU whose power is set.
7307 **
7308 **      gctUINT8 Scale
7309 **          Target scale of full frequency, range is [1, 64]. 1 means 1/64 of
7310 **          full frequency and 64 means 64/64 of full frequency.
7311 **
7312 **  OUTPUT:
7313 **
7314 **      Nothing.
7315 */
7316 gceSTATUS
7317 gckOS_SetGPUFrequency(
7318     IN gckOS Os,
7319     IN gceCORE Core,
7320     IN gctUINT8 Scale
7321     )
7322 {
7323     return gcvSTATUS_OK;
7324 }
7325
7326 /*----------------------------------------------------------------------------*/
7327 /*----- Profile --------------------------------------------------------------*/
7328
7329 gceSTATUS
7330 gckOS_GetProfileTick(
7331     OUT gctUINT64_PTR Tick
7332     )
7333 {
7334     struct timespec time;
7335
7336     ktime_get_ts(&time);
7337
7338     *Tick = time.tv_nsec + time.tv_sec * 1000000000ULL;
7339
7340     return gcvSTATUS_OK;
7341 }
7342
7343 gceSTATUS
7344 gckOS_QueryProfileTickRate(
7345     OUT gctUINT64_PTR TickRate
7346     )
7347 {
7348     struct timespec res;
7349
7350     hrtimer_get_res(CLOCK_MONOTONIC, &res);
7351
7352     *TickRate = res.tv_nsec + res.tv_sec * 1000000000ULL;
7353
7354     return gcvSTATUS_OK;
7355 }
7356
7357 gctUINT32
7358 gckOS_ProfileToMS(
7359     IN gctUINT64 Ticks
7360     )
7361 {
7362 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,23)
7363     return div_u64(Ticks, 1000000);
7364 #else
7365     gctUINT64 rem = Ticks;
7366     gctUINT64 b = 1000000;
7367     gctUINT64 res, d = 1;
7368     gctUINT32 high = rem >> 32;
7369
7370     /* Reduce the thing a bit first */
7371     res = 0;
7372     if (high >= 1000000)
7373     {
7374         high /= 1000000;
7375         res   = (gctUINT64) high << 32;
7376         rem  -= (gctUINT64) (high * 1000000) << 32;
7377     }
7378
7379     while (((gctINT64) b > 0) && (b < rem))
7380     {
7381         b <<= 1;
7382         d <<= 1;
7383     }
7384
7385     do
7386     {
7387         if (rem >= b)
7388         {
7389             rem -= b;
7390             res += d;
7391         }
7392
7393         b >>= 1;
7394         d >>= 1;
7395     }
7396     while (d);
7397
7398     return (gctUINT32) res;
7399 #endif
7400 }
7401
7402 /******************************************************************************\
7403 ******************************* Signal Management ******************************
7404 \******************************************************************************/
7405
7406 #undef _GC_OBJ_ZONE
7407 #define _GC_OBJ_ZONE    gcvZONE_SIGNAL
7408
7409 /*******************************************************************************
7410 **
7411 **  gckOS_CreateSignal
7412 **
7413 **  Create a new signal.
7414 **
7415 **  INPUT:
7416 **
7417 **      gckOS Os
7418 **          Pointer to an gckOS object.
7419 **
7420 **      gctBOOL ManualReset
7421 **          If set to gcvTRUE, gckOS_Signal with gcvFALSE must be called in
7422 **          order to set the signal to nonsignaled state.
7423 **          If set to gcvFALSE, the signal will automatically be set to
7424 **          nonsignaled state by gckOS_WaitSignal function.
7425 **
7426 **  OUTPUT:
7427 **
7428 **      gctSIGNAL * Signal
7429 **          Pointer to a variable receiving the created gctSIGNAL.
7430 */
7431 gceSTATUS
7432 gckOS_CreateSignal(
7433     IN gckOS Os,
7434     IN gctBOOL ManualReset,
7435     OUT gctSIGNAL * Signal
7436     )
7437 {
7438     gceSTATUS status;
7439     gcsSIGNAL_PTR signal;
7440
7441     gcmkHEADER_ARG("Os=0x%X ManualReset=%d", Os, ManualReset);
7442
7443     /* Verify the arguments. */
7444     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
7445     gcmkVERIFY_ARGUMENT(Signal != gcvNULL);
7446
7447     /* Create an event structure. */
7448     signal = (gcsSIGNAL_PTR) kmalloc(sizeof(gcsSIGNAL), GFP_KERNEL | gcdNOWARN);
7449
7450     if (signal == gcvNULL)
7451     {
7452         gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
7453     }
7454
7455     /* Save the process ID. */
7456     signal->process = (gctHANDLE)(gctUINTPTR_T) _GetProcessID();
7457     signal->manualReset = ManualReset;
7458     signal->hardware = gcvNULL;
7459     init_completion(&signal->obj);
7460     atomic_set(&signal->ref, 1);
7461
7462     gcmkONERROR(_AllocateIntegerId(&Os->signalDB, signal, &signal->id));
7463
7464     *Signal = (gctSIGNAL)(gctUINTPTR_T)signal->id;
7465
7466     gcmkFOOTER_ARG("*Signal=0x%X", *Signal);
7467     return gcvSTATUS_OK;
7468
7469 OnError:
7470     if (signal != gcvNULL)
7471     {
7472         kfree(signal);
7473     }
7474
7475     gcmkFOOTER_NO();
7476     return status;
7477 }
7478
7479 gceSTATUS
7480 gckOS_SignalQueryHardware(
7481     IN gckOS Os,
7482     IN gctSIGNAL Signal,
7483     OUT gckHARDWARE * Hardware
7484     )
7485 {
7486     gceSTATUS status;
7487     gcsSIGNAL_PTR signal;
7488
7489     gcmkHEADER_ARG("Os=0x%X Signal=0x%X Hardware=0x%X", Os, Signal, Hardware);
7490
7491     /* Verify the arguments. */
7492     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
7493     gcmkVERIFY_ARGUMENT(Signal != gcvNULL);
7494     gcmkVERIFY_ARGUMENT(Hardware != gcvNULL);
7495
7496     gcmkONERROR(_QueryIntegerId(&Os->signalDB, (gctUINT32)(gctUINTPTR_T)Signal, (gctPOINTER)&signal));
7497
7498     *Hardware = signal->hardware;
7499
7500     gcmkFOOTER_NO();
7501     return gcvSTATUS_OK;
7502 OnError:
7503     gcmkFOOTER();
7504     return status;
7505 }
7506
7507 gceSTATUS
7508 gckOS_SignalSetHardware(
7509     IN gckOS Os,
7510     IN gctSIGNAL Signal,
7511     IN gckHARDWARE Hardware
7512     )
7513 {
7514     gceSTATUS status;
7515     gcsSIGNAL_PTR signal;
7516
7517     gcmkHEADER_ARG("Os=0x%X Signal=0x%X Hardware=0x%X", Os, Signal, Hardware);
7518
7519     /* Verify the arguments. */
7520     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
7521     gcmkVERIFY_ARGUMENT(Signal != gcvNULL);
7522
7523     gcmkONERROR(_QueryIntegerId(&Os->signalDB, (gctUINT32)(gctUINTPTR_T)Signal, (gctPOINTER)&signal));
7524
7525     signal->hardware = Hardware;
7526
7527     gcmkFOOTER_NO();
7528     return gcvSTATUS_OK;
7529 OnError:
7530     gcmkFOOTER();
7531     return status;
7532 }
7533
7534 /*******************************************************************************
7535 **
7536 **  gckOS_DestroySignal
7537 **
7538 **  Destroy a signal.
7539 **
7540 **  INPUT:
7541 **
7542 **      gckOS Os
7543 **          Pointer to an gckOS object.
7544 **
7545 **      gctSIGNAL Signal
7546 **          Pointer to the gctSIGNAL.
7547 **
7548 **  OUTPUT:
7549 **
7550 **      Nothing.
7551 */
7552 gceSTATUS
7553 gckOS_DestroySignal(
7554     IN gckOS Os,
7555     IN gctSIGNAL Signal
7556     )
7557 {
7558     gceSTATUS status;
7559     gcsSIGNAL_PTR signal;
7560     gctBOOL acquired = gcvFALSE;
7561
7562     gcmkHEADER_ARG("Os=0x%X Signal=0x%X", Os, Signal);
7563
7564     /* Verify the arguments. */
7565     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
7566     gcmkVERIFY_ARGUMENT(Signal != gcvNULL);
7567
7568     gcmkONERROR(gckOS_AcquireMutex(Os, Os->signalMutex, gcvINFINITE));
7569     acquired = gcvTRUE;
7570
7571     gcmkONERROR(_QueryIntegerId(&Os->signalDB, (gctUINT32)(gctUINTPTR_T)Signal, (gctPOINTER)&signal));
7572
7573     gcmkASSERT(signal->id == (gctUINT32)(gctUINTPTR_T)Signal);
7574
7575     if (atomic_dec_and_test(&signal->ref))
7576     {
7577         gcmkVERIFY_OK(_DestroyIntegerId(&Os->signalDB, signal->id));
7578
7579         /* Free the sgianl. */
7580         kfree(signal);
7581     }
7582
7583     gcmkVERIFY_OK(gckOS_ReleaseMutex(Os, Os->signalMutex));
7584     acquired = gcvFALSE;
7585
7586     /* Success. */
7587     gcmkFOOTER_NO();
7588     return gcvSTATUS_OK;
7589
7590 OnError:
7591     if (acquired)
7592     {
7593         /* Release the mutex. */
7594         gcmkVERIFY_OK(gckOS_ReleaseMutex(Os, Os->signalMutex));
7595     }
7596
7597     gcmkFOOTER();
7598     return status;
7599 }
7600
7601 /*******************************************************************************
7602 **
7603 **  gckOS_Signal
7604 **
7605 **  Set a state of the specified signal.
7606 **
7607 **  INPUT:
7608 **
7609 **      gckOS Os
7610 **          Pointer to an gckOS object.
7611 **
7612 **      gctSIGNAL Signal
7613 **          Pointer to the gctSIGNAL.
7614 **
7615 **      gctBOOL State
7616 **          If gcvTRUE, the signal will be set to signaled state.
7617 **          If gcvFALSE, the signal will be set to nonsignaled state.
7618 **
7619 **  OUTPUT:
7620 **
7621 **      Nothing.
7622 */
7623 gceSTATUS
7624 gckOS_Signal(
7625     IN gckOS Os,
7626     IN gctSIGNAL Signal,
7627     IN gctBOOL State
7628     )
7629 {
7630     gceSTATUS status;
7631     gcsSIGNAL_PTR signal;
7632     gctBOOL acquired = gcvFALSE;
7633
7634     gcmkHEADER_ARG("Os=0x%X Signal=0x%X State=%d", Os, Signal, State);
7635
7636     /* Verify the arguments. */
7637     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
7638     gcmkVERIFY_ARGUMENT(Signal != gcvNULL);
7639
7640     gcmkONERROR(gckOS_AcquireMutex(Os, Os->signalMutex, gcvINFINITE));
7641     acquired = gcvTRUE;
7642
7643     gcmkONERROR(_QueryIntegerId(&Os->signalDB, (gctUINT32)(gctUINTPTR_T)Signal, (gctPOINTER)&signal));
7644
7645     gcmkASSERT(signal->id == (gctUINT32)(gctUINTPTR_T)Signal);
7646
7647     if (State)
7648     {
7649         /* unbind the signal from hardware. */
7650         signal->hardware = gcvNULL;
7651
7652         /* Set the event to a signaled state. */
7653         complete(&signal->obj);
7654     }
7655     else
7656     {
7657         /* Set the event to an unsignaled state. */
7658         INIT_COMPLETION(signal->obj);
7659     }
7660
7661     gcmkVERIFY_OK(gckOS_ReleaseMutex(Os, Os->signalMutex));
7662     acquired = gcvFALSE;
7663
7664     /* Success. */
7665     gcmkFOOTER_NO();
7666     return gcvSTATUS_OK;
7667
7668 OnError:
7669     if (acquired)
7670     {
7671         /* Release the mutex. */
7672         gcmkVERIFY_OK(gckOS_ReleaseMutex(Os, Os->signalMutex));
7673     }
7674
7675     gcmkFOOTER();
7676     return status;
7677 }
7678
7679 #if gcdENABLE_VG
7680 gceSTATUS
7681 gckOS_SetSignalVG(
7682     IN gckOS Os,
7683     IN gctHANDLE Process,
7684     IN gctSIGNAL Signal
7685     )
7686 {
7687     gceSTATUS status;
7688     gctINT result;
7689     struct task_struct * userTask;
7690     struct siginfo info;
7691
7692     userTask = FIND_TASK_BY_PID((pid_t)(gctUINTPTR_T) Process);
7693
7694     if (userTask != gcvNULL)
7695     {
7696         info.si_signo = 48;
7697         info.si_code  = __SI_CODE(__SI_RT, SI_KERNEL);
7698         info.si_pid   = 0;
7699         info.si_uid   = 0;
7700         info.si_ptr   = (gctPOINTER) Signal;
7701
7702         /* Signals with numbers between 32 and 63 are real-time,
7703            send a real-time signal to the user process. */
7704         result = send_sig_info(48, &info, userTask);
7705
7706         printk("gckOS_SetSignalVG:0x%x\n", result);
7707         /* Error? */
7708         if (result < 0)
7709         {
7710             status = gcvSTATUS_GENERIC_IO;
7711
7712             gcmkTRACE(
7713                 gcvLEVEL_ERROR,
7714                 "%s(%d): an error has occurred.\n",
7715                 __FUNCTION__, __LINE__
7716                 );
7717         }
7718         else
7719         {
7720             status = gcvSTATUS_OK;
7721         }
7722     }
7723     else
7724     {
7725         status = gcvSTATUS_GENERIC_IO;
7726
7727         gcmkTRACE(
7728             gcvLEVEL_ERROR,
7729             "%s(%d): an error has occurred.\n",
7730             __FUNCTION__, __LINE__
7731             );
7732     }
7733
7734     /* Return status. */
7735     return status;
7736 }
7737 #endif
7738
7739 /*******************************************************************************
7740 **
7741 **  gckOS_UserSignal
7742 **
7743 **  Set the specified signal which is owned by a process to signaled state.
7744 **
7745 **  INPUT:
7746 **
7747 **      gckOS Os
7748 **          Pointer to an gckOS object.
7749 **
7750 **      gctSIGNAL Signal
7751 **          Pointer to the gctSIGNAL.
7752 **
7753 **      gctHANDLE Process
7754 **          Handle of process owning the signal.
7755 **
7756 **  OUTPUT:
7757 **
7758 **      Nothing.
7759 */
7760 gceSTATUS
7761 gckOS_UserSignal(
7762     IN gckOS Os,
7763     IN gctSIGNAL Signal,
7764     IN gctHANDLE Process
7765     )
7766 {
7767     gceSTATUS status;
7768     gctSIGNAL signal;
7769
7770     gcmkHEADER_ARG("Os=0x%X Signal=0x%X Process=%d",
7771                    Os, Signal, (gctINT32)(gctUINTPTR_T)Process);
7772
7773     /* Map the signal into kernel space. */
7774     gcmkONERROR(gckOS_MapSignal(Os, Signal, Process, &signal));
7775
7776     /* Signal. */
7777     status = gckOS_Signal(Os, signal, gcvTRUE);
7778
7779     /* Unmap the signal */
7780     gcmkVERIFY_OK(gckOS_UnmapSignal(Os, Signal));
7781
7782     gcmkFOOTER();
7783     return status;
7784
7785 OnError:
7786     /* Return the status. */
7787     gcmkFOOTER();
7788     return status;
7789 }
7790
7791 /*******************************************************************************
7792 **
7793 **  gckOS_WaitSignal
7794 **
7795 **  Wait for a signal to become signaled.
7796 **
7797 **  INPUT:
7798 **
7799 **      gckOS Os
7800 **          Pointer to an gckOS object.
7801 **
7802 **      gctSIGNAL Signal
7803 **          Pointer to the gctSIGNAL.
7804 **
7805 **      gctUINT32 Wait
7806 **          Number of milliseconds to wait.
7807 **          Pass the value of gcvINFINITE for an infinite wait.
7808 **
7809 **  OUTPUT:
7810 **
7811 **      Nothing.
7812 */
7813 gceSTATUS
7814 gckOS_WaitSignal(
7815     IN gckOS Os,
7816     IN gctSIGNAL Signal,
7817     IN gctUINT32 Wait
7818     )
7819 {
7820     gceSTATUS status = gcvSTATUS_OK;
7821     gcsSIGNAL_PTR signal;
7822
7823     gcmkHEADER_ARG("Os=0x%X Signal=0x%X Wait=0x%08X", Os, Signal, Wait);
7824
7825     /* Verify the arguments. */
7826     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
7827     gcmkVERIFY_ARGUMENT(Signal != gcvNULL);
7828
7829     gcmkONERROR(_QueryIntegerId(&Os->signalDB, (gctUINT32)(gctUINTPTR_T)Signal, (gctPOINTER)&signal));
7830
7831     gcmkASSERT(signal->id == (gctUINT32)(gctUINTPTR_T)Signal);
7832
7833     might_sleep();
7834
7835     spin_lock_irq(&signal->obj.wait.lock);
7836
7837     if (signal->obj.done)
7838     {
7839         if (!signal->manualReset)
7840         {
7841             signal->obj.done = 0;
7842         }
7843
7844         status = gcvSTATUS_OK;
7845     }
7846     else if (Wait == 0)
7847     {
7848         status = gcvSTATUS_TIMEOUT;
7849     }
7850     else
7851     {
7852         /* Convert wait to milliseconds. */
7853 #if gcdDETECT_TIMEOUT
7854         gctINT timeout = (Wait == gcvINFINITE)
7855             ? gcdINFINITE_TIMEOUT * HZ / 1000
7856             : Wait * HZ / 1000;
7857
7858         gctUINT complained = 0;
7859 #else
7860         gctINT timeout = (Wait == gcvINFINITE)
7861             ? MAX_SCHEDULE_TIMEOUT
7862             : Wait * HZ / 1000;
7863 #endif
7864
7865         DECLARE_WAITQUEUE(wait, current);
7866         wait.flags |= WQ_FLAG_EXCLUSIVE;
7867         __add_wait_queue_tail(&signal->obj.wait, &wait);
7868
7869         while (gcvTRUE)
7870         {
7871             if (signal_pending(current))
7872             {
7873                 /* Interrupt received. */
7874                 status = gcvSTATUS_INTERRUPTED;
7875                 break;
7876             }
7877
7878             __set_current_state(TASK_INTERRUPTIBLE);
7879             spin_unlock_irq(&signal->obj.wait.lock);
7880             timeout = schedule_timeout(timeout);
7881             spin_lock_irq(&signal->obj.wait.lock);
7882
7883             if (signal->obj.done)
7884             {
7885                 if (!signal->manualReset)
7886                 {
7887                     signal->obj.done = 0;
7888                 }
7889
7890                 status = gcvSTATUS_OK;
7891                 break;
7892             }
7893
7894 #if gcdDETECT_TIMEOUT
7895             if ((Wait == gcvINFINITE) && (timeout == 0))
7896             {
7897                 gctUINT32 dmaAddress1, dmaAddress2;
7898                 gctUINT32 dmaState1, dmaState2;
7899
7900                 dmaState1   = dmaState2   =
7901                 dmaAddress1 = dmaAddress2 = 0;
7902
7903                 /* Verify whether DMA is running. */
7904                 gcmkVERIFY_OK(_VerifyDMA(
7905                     Os, &dmaAddress1, &dmaAddress2, &dmaState1, &dmaState2
7906                     ));
7907
7908 #if gcdDETECT_DMA_ADDRESS
7909                 /* Dump only if DMA appears stuck. */
7910                 if (
7911                     (dmaAddress1 == dmaAddress2)
7912 #if gcdDETECT_DMA_STATE
7913                  && (dmaState1   == dmaState2)
7914 #endif
7915                 )
7916 #endif
7917                 {
7918                     /* Increment complain count. */
7919                     complained += 1;
7920
7921                     gcmkVERIFY_OK(_DumpGPUState(Os, gcvCORE_MAJOR));
7922
7923                     gcmkPRINT(
7924                         "%s(%d): signal 0x%X; forced message flush (%d).",
7925                         __FUNCTION__, __LINE__, Signal, complained
7926                         );
7927
7928                     /* Flush the debug cache. */
7929                     gcmkDEBUGFLUSH(dmaAddress2);
7930                 }
7931
7932                 /* Reset timeout. */
7933                 timeout = gcdINFINITE_TIMEOUT * HZ / 1000;
7934             }
7935 #endif
7936
7937             if (timeout == 0)
7938             {
7939
7940                 status = gcvSTATUS_TIMEOUT;
7941                 break;
7942             }
7943         }
7944
7945         __remove_wait_queue(&signal->obj.wait, &wait);
7946
7947 #if gcdDETECT_TIMEOUT
7948         if (complained)
7949         {
7950             gcmkPRINT(
7951                 "%s(%d): signal=0x%X; waiting done; status=%d",
7952                 __FUNCTION__, __LINE__, Signal, status
7953                 );
7954         }
7955 #endif
7956     }
7957
7958     spin_unlock_irq(&signal->obj.wait.lock);
7959
7960 OnError:
7961     /* Return status. */
7962     gcmkFOOTER_ARG("Signal=0x%X status=%d", Signal, status);
7963     return status;
7964 }
7965
7966 /*******************************************************************************
7967 **
7968 **  gckOS_MapSignal
7969 **
7970 **  Map a signal in to the current process space.
7971 **
7972 **  INPUT:
7973 **
7974 **      gckOS Os
7975 **          Pointer to an gckOS object.
7976 **
7977 **      gctSIGNAL Signal
7978 **          Pointer to tha gctSIGNAL to map.
7979 **
7980 **      gctHANDLE Process
7981 **          Handle of process owning the signal.
7982 **
7983 **  OUTPUT:
7984 **
7985 **      gctSIGNAL * MappedSignal
7986 **          Pointer to a variable receiving the mapped gctSIGNAL.
7987 */
7988 gceSTATUS
7989 gckOS_MapSignal(
7990     IN gckOS Os,
7991     IN gctSIGNAL Signal,
7992     IN gctHANDLE Process,
7993     OUT gctSIGNAL * MappedSignal
7994     )
7995 {
7996     gceSTATUS status;
7997     gcsSIGNAL_PTR signal;
7998     gcmkHEADER_ARG("Os=0x%X Signal=0x%X Process=0x%X", Os, Signal, Process);
7999
8000     gcmkVERIFY_ARGUMENT(Signal != gcvNULL);
8001     gcmkVERIFY_ARGUMENT(MappedSignal != gcvNULL);
8002
8003     gcmkONERROR(_QueryIntegerId(&Os->signalDB, (gctUINT32)(gctUINTPTR_T)Signal, (gctPOINTER)&signal));
8004
8005     if(atomic_inc_return(&signal->ref) <= 1)
8006     {
8007         /* The previous value is 0, it has been deleted. */
8008         gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
8009     }
8010
8011     *MappedSignal = (gctSIGNAL) Signal;
8012
8013     /* Success. */
8014     gcmkFOOTER_ARG("*MappedSignal=0x%X", *MappedSignal);
8015     return gcvSTATUS_OK;
8016
8017 OnError:
8018     gcmkFOOTER_NO();
8019     return status;
8020 }
8021
8022 /*******************************************************************************
8023 **
8024 **      gckOS_UnmapSignal
8025 **
8026 **      Unmap a signal .
8027 **
8028 **      INPUT:
8029 **
8030 **              gckOS Os
8031 **                      Pointer to an gckOS object.
8032 **
8033 **              gctSIGNAL Signal
8034 **                      Pointer to that gctSIGNAL mapped.
8035 */
8036 gceSTATUS
8037 gckOS_UnmapSignal(
8038     IN gckOS Os,
8039     IN gctSIGNAL Signal
8040     )
8041 {
8042     return gckOS_DestroySignal(Os, Signal);
8043 }
8044
8045 /*******************************************************************************
8046 **
8047 **  gckOS_CreateUserSignal
8048 **
8049 **  Create a new signal to be used in the user space.
8050 **
8051 **  INPUT:
8052 **
8053 **      gckOS Os
8054 **          Pointer to an gckOS object.
8055 **
8056 **      gctBOOL ManualReset
8057 **          If set to gcvTRUE, gckOS_Signal with gcvFALSE must be called in
8058 **          order to set the signal to nonsignaled state.
8059 **          If set to gcvFALSE, the signal will automatically be set to
8060 **          nonsignaled state by gckOS_WaitSignal function.
8061 **
8062 **  OUTPUT:
8063 **
8064 **      gctINT * SignalID
8065 **          Pointer to a variable receiving the created signal's ID.
8066 */
8067 gceSTATUS
8068 gckOS_CreateUserSignal(
8069     IN gckOS Os,
8070     IN gctBOOL ManualReset,
8071     OUT gctINT * SignalID
8072     )
8073 {
8074     gceSTATUS status;
8075     gctSIZE_T signal;
8076
8077     /* Create a new signal. */
8078     status = gckOS_CreateSignal(Os, ManualReset, (gctSIGNAL *) &signal);
8079     *SignalID = (gctINT) signal;
8080
8081     return status;
8082 }
8083
8084 /*******************************************************************************
8085 **
8086 **  gckOS_DestroyUserSignal
8087 **
8088 **  Destroy a signal to be used in the user space.
8089 **
8090 **  INPUT:
8091 **
8092 **      gckOS Os
8093 **          Pointer to an gckOS object.
8094 **
8095 **      gctINT SignalID
8096 **          The signal's ID.
8097 **
8098 **  OUTPUT:
8099 **
8100 **      Nothing.
8101 */
8102 gceSTATUS
8103 gckOS_DestroyUserSignal(
8104     IN gckOS Os,
8105     IN gctINT SignalID
8106     )
8107 {
8108     return gckOS_DestroySignal(Os, (gctSIGNAL)(gctUINTPTR_T)SignalID);
8109 }
8110
8111 /*******************************************************************************
8112 **
8113 **  gckOS_WaitUserSignal
8114 **
8115 **  Wait for a signal used in the user mode to become signaled.
8116 **
8117 **  INPUT:
8118 **
8119 **      gckOS Os
8120 **          Pointer to an gckOS object.
8121 **
8122 **      gctINT SignalID
8123 **          Signal ID.
8124 **
8125 **      gctUINT32 Wait
8126 **          Number of milliseconds to wait.
8127 **          Pass the value of gcvINFINITE for an infinite wait.
8128 **
8129 **  OUTPUT:
8130 **
8131 **      Nothing.
8132 */
8133 gceSTATUS
8134 gckOS_WaitUserSignal(
8135     IN gckOS Os,
8136     IN gctINT SignalID,
8137     IN gctUINT32 Wait
8138     )
8139 {
8140     return gckOS_WaitSignal(Os, (gctSIGNAL)(gctUINTPTR_T)SignalID, Wait);
8141 }
8142
8143 /*******************************************************************************
8144 **
8145 **  gckOS_SignalUserSignal
8146 **
8147 **  Set a state of the specified signal to be used in the user space.
8148 **
8149 **  INPUT:
8150 **
8151 **      gckOS Os
8152 **          Pointer to an gckOS object.
8153 **
8154 **      gctINT SignalID
8155 **          SignalID.
8156 **
8157 **      gctBOOL State
8158 **          If gcvTRUE, the signal will be set to signaled state.
8159 **          If gcvFALSE, the signal will be set to nonsignaled state.
8160 **
8161 **  OUTPUT:
8162 **
8163 **      Nothing.
8164 */
8165 gceSTATUS
8166 gckOS_SignalUserSignal(
8167     IN gckOS Os,
8168     IN gctINT SignalID,
8169     IN gctBOOL State
8170     )
8171 {
8172     return gckOS_Signal(Os, (gctSIGNAL)(gctUINTPTR_T)SignalID, State);
8173 }
8174
8175 #if gcdENABLE_VG
8176 gceSTATUS
8177 gckOS_CreateSemaphoreVG(
8178     IN gckOS Os,
8179     OUT gctSEMAPHORE * Semaphore
8180     )
8181 {
8182     gceSTATUS status;
8183     struct semaphore * newSemaphore;
8184
8185     gcmkHEADER_ARG("Os=0x%X Semaphore=0x%x", Os, Semaphore);
8186     /* Verify the arguments. */
8187     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
8188     gcmkVERIFY_ARGUMENT(Semaphore != gcvNULL);
8189
8190     do
8191     {
8192         /* Allocate the semaphore structure. */
8193         newSemaphore = (struct semaphore *)kmalloc(gcmSIZEOF(struct semaphore), GFP_KERNEL | gcdNOWARN);
8194         if (newSemaphore == gcvNULL)
8195         {
8196                 gcmkERR_BREAK(gcvSTATUS_OUT_OF_MEMORY);
8197         }
8198
8199         /* Initialize the semaphore. */
8200         sema_init(newSemaphore, 0);
8201
8202         /* Set the handle. */
8203         * Semaphore = (gctSEMAPHORE) newSemaphore;
8204
8205         /* Success. */
8206         status = gcvSTATUS_OK;
8207     }
8208     while (gcvFALSE);
8209
8210     gcmkFOOTER();
8211     /* Return the status. */
8212     return status;
8213 }
8214
8215
8216 gceSTATUS
8217 gckOS_IncrementSemaphore(
8218     IN gckOS Os,
8219     IN gctSEMAPHORE Semaphore
8220     )
8221 {
8222     gcmkHEADER_ARG("Os=0x%X Semaphore=0x%x", Os, Semaphore);
8223     /* Verify the arguments. */
8224     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
8225     gcmkVERIFY_ARGUMENT(Semaphore != gcvNULL);
8226
8227     /* Increment the semaphore's count. */
8228     up((struct semaphore *) Semaphore);
8229
8230     gcmkFOOTER_NO();
8231     /* Success. */
8232     return gcvSTATUS_OK;
8233 }
8234
8235 gceSTATUS
8236 gckOS_DecrementSemaphore(
8237     IN gckOS Os,
8238     IN gctSEMAPHORE Semaphore
8239     )
8240 {
8241     gceSTATUS status;
8242     gctINT result;
8243
8244     gcmkHEADER_ARG("Os=0x%X Semaphore=0x%x", Os, Semaphore);
8245     /* Verify the arguments. */
8246     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
8247     gcmkVERIFY_ARGUMENT(Semaphore != gcvNULL);
8248
8249     do
8250     {
8251         /* Decrement the semaphore's count. If the count is zero, wait
8252            until it gets incremented. */
8253         result = down_interruptible((struct semaphore *) Semaphore);
8254
8255         /* Signal received? */
8256         if (result != 0)
8257         {
8258             status = gcvSTATUS_TERMINATE;
8259             break;
8260         }
8261
8262         /* Success. */
8263         status = gcvSTATUS_OK;
8264     }
8265     while (gcvFALSE);
8266
8267     gcmkFOOTER();
8268     /* Return the status. */
8269     return status;
8270 }
8271
8272 /*******************************************************************************
8273 **
8274 **  gckOS_SetSignal
8275 **
8276 **  Set the specified signal to signaled state.
8277 **
8278 **  INPUT:
8279 **
8280 **      gckOS Os
8281 **          Pointer to the gckOS object.
8282 **
8283 **      gctHANDLE Process
8284 **          Handle of process owning the signal.
8285 **
8286 **      gctSIGNAL Signal
8287 **          Pointer to the gctSIGNAL.
8288 **
8289 **  OUTPUT:
8290 **
8291 **      Nothing.
8292 */
8293 gceSTATUS
8294 gckOS_SetSignal(
8295     IN gckOS Os,
8296     IN gctHANDLE Process,
8297     IN gctSIGNAL Signal
8298     )
8299 {
8300     gceSTATUS status;
8301     gctINT result;
8302     struct task_struct * userTask;
8303     struct siginfo info;
8304
8305     userTask = FIND_TASK_BY_PID((pid_t)(gctUINTPTR_T) Process);
8306
8307     if (userTask != gcvNULL)
8308     {
8309         info.si_signo = 48;
8310         info.si_code  = __SI_CODE(__SI_RT, SI_KERNEL);
8311         info.si_pid   = 0;
8312         info.si_uid   = 0;
8313         info.si_ptr   = (gctPOINTER) Signal;
8314
8315         /* Signals with numbers between 32 and 63 are real-time,
8316            send a real-time signal to the user process. */
8317         result = send_sig_info(48, &info, userTask);
8318
8319         /* Error? */
8320         if (result < 0)
8321         {
8322             status = gcvSTATUS_GENERIC_IO;
8323
8324             gcmkTRACE(
8325                 gcvLEVEL_ERROR,
8326                 "%s(%d): an error has occurred.\n",
8327                 __FUNCTION__, __LINE__
8328                 );
8329         }
8330         else
8331         {
8332             status = gcvSTATUS_OK;
8333         }
8334     }
8335     else
8336     {
8337         status = gcvSTATUS_GENERIC_IO;
8338
8339         gcmkTRACE(
8340             gcvLEVEL_ERROR,
8341             "%s(%d): an error has occurred.\n",
8342             __FUNCTION__, __LINE__
8343             );
8344     }
8345
8346     /* Return status. */
8347     return status;
8348 }
8349
8350 /******************************************************************************\
8351 ******************************** Thread Object *********************************
8352 \******************************************************************************/
8353
8354 gceSTATUS
8355 gckOS_StartThread(
8356     IN gckOS Os,
8357     IN gctTHREADFUNC ThreadFunction,
8358     IN gctPOINTER ThreadParameter,
8359     OUT gctTHREAD * Thread
8360     )
8361 {
8362     gceSTATUS status;
8363     struct task_struct * thread;
8364
8365     gcmkHEADER_ARG("Os=0x%X ", Os);
8366     /* Verify the arguments. */
8367     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
8368     gcmkVERIFY_ARGUMENT(ThreadFunction != gcvNULL);
8369     gcmkVERIFY_ARGUMENT(Thread != gcvNULL);
8370
8371     do
8372     {
8373         /* Create the thread. */
8374         thread = kthread_create(
8375             ThreadFunction,
8376             ThreadParameter,
8377             "Vivante Kernel Thread"
8378             );
8379
8380         /* Failed? */
8381         if (IS_ERR(thread))
8382         {
8383             status = gcvSTATUS_GENERIC_IO;
8384             break;
8385         }
8386
8387         /* Start the thread. */
8388         wake_up_process(thread);
8389
8390         /* Set the thread handle. */
8391         * Thread = (gctTHREAD) thread;
8392
8393         /* Success. */
8394         status = gcvSTATUS_OK;
8395     }
8396     while (gcvFALSE);
8397
8398     gcmkFOOTER();
8399     /* Return the status. */
8400     return status;
8401 }
8402
8403 gceSTATUS
8404 gckOS_StopThread(
8405     IN gckOS Os,
8406     IN gctTHREAD Thread
8407     )
8408 {
8409     gcmkHEADER_ARG("Os=0x%X Thread=0x%x", Os, Thread);
8410     /* Verify the arguments. */
8411     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
8412     gcmkVERIFY_ARGUMENT(Thread != gcvNULL);
8413
8414     /* Thread should have already been enabled to terminate. */
8415     kthread_stop((struct task_struct *) Thread);
8416
8417     gcmkFOOTER_NO();
8418     /* Success. */
8419     return gcvSTATUS_OK;
8420 }
8421
8422 gceSTATUS
8423 gckOS_VerifyThread(
8424     IN gckOS Os,
8425     IN gctTHREAD Thread
8426     )
8427 {
8428     gcmkHEADER_ARG("Os=0x%X Thread=0x%x", Os, Thread);
8429     /* Verify the arguments. */
8430     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
8431     gcmkVERIFY_ARGUMENT(Thread != gcvNULL);
8432
8433     gcmkFOOTER_NO();
8434     /* Success. */
8435     return gcvSTATUS_OK;
8436 }
8437 #endif
8438
8439 /******************************************************************************\
8440 ******************************** Software Timer ********************************
8441 \******************************************************************************/
8442
8443 void
8444 _TimerFunction(
8445     struct work_struct * work
8446     )
8447 {
8448     gcsOSTIMER_PTR timer = (gcsOSTIMER_PTR)work;
8449
8450     gctTIMERFUNCTION function = timer->function;
8451
8452     function(timer->data);
8453 }
8454
8455 /*******************************************************************************
8456 **
8457 **  gckOS_CreateTimer
8458 **
8459 **  Create a software timer.
8460 **
8461 **  INPUT:
8462 **
8463 **      gckOS Os
8464 **          Pointer to the gckOS object.
8465 **
8466 **      gctTIMERFUNCTION Function.
8467 **          Pointer to a call back function which will be called when timer is
8468 **          expired.
8469 **
8470 **      gctPOINTER Data.
8471 **          Private data which will be passed to call back function.
8472 **
8473 **  OUTPUT:
8474 **
8475 **      gctPOINTER * Timer
8476 **          Pointer to a variable receiving the created timer.
8477 */
8478 gceSTATUS
8479 gckOS_CreateTimer(
8480     IN gckOS Os,
8481     IN gctTIMERFUNCTION Function,
8482     IN gctPOINTER Data,
8483     OUT gctPOINTER * Timer
8484     )
8485 {
8486     gceSTATUS status;
8487     gcsOSTIMER_PTR pointer;
8488     gcmkHEADER_ARG("Os=0x%X Function=0x%X Data=0x%X", Os, Function, Data);
8489
8490     /* Verify the arguments. */
8491     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
8492     gcmkVERIFY_ARGUMENT(Timer != gcvNULL);
8493
8494     gcmkONERROR(gckOS_Allocate(Os, sizeof(gcsOSTIMER), (gctPOINTER)&pointer));
8495
8496     pointer->function = Function;
8497     pointer->data = Data;
8498
8499     INIT_DELAYED_WORK(&pointer->work, _TimerFunction);
8500
8501     *Timer = pointer;
8502
8503     gcmkFOOTER_NO();
8504     return gcvSTATUS_OK;
8505
8506 OnError:
8507     gcmkFOOTER();
8508     return status;
8509 }
8510
8511 /*******************************************************************************
8512 **
8513 **  gckOS_DestroyTimer
8514 **
8515 **  Destory a software timer.
8516 **
8517 **  INPUT:
8518 **
8519 **      gckOS Os
8520 **          Pointer to the gckOS object.
8521 **
8522 **      gctPOINTER Timer
8523 **          Pointer to the timer to be destoryed.
8524 **
8525 **  OUTPUT:
8526 **
8527 **      Nothing.
8528 */
8529 gceSTATUS
8530 gckOS_DestroyTimer(
8531     IN gckOS Os,
8532     IN gctPOINTER Timer
8533     )
8534 {
8535     gcsOSTIMER_PTR timer;
8536     gcmkHEADER_ARG("Os=0x%X Timer=0x%X", Os, Timer);
8537
8538     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
8539     gcmkVERIFY_ARGUMENT(Timer != gcvNULL);
8540
8541     timer = (gcsOSTIMER_PTR)Timer;
8542
8543 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23)
8544     cancel_delayed_work_sync(&timer->work);
8545 #else
8546     cancel_delayed_work(&timer->work);
8547     flush_workqueue(Os->workqueue);
8548 #endif
8549
8550     gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Os, Timer));
8551
8552     gcmkFOOTER_NO();
8553     return gcvSTATUS_OK;
8554 }
8555
8556 /*******************************************************************************
8557 **
8558 **  gckOS_StartTimer
8559 **
8560 **  Schedule a software timer.
8561 **
8562 **  INPUT:
8563 **
8564 **      gckOS Os
8565 **          Pointer to the gckOS object.
8566 **
8567 **      gctPOINTER Timer
8568 **          Pointer to the timer to be scheduled.
8569 **
8570 **      gctUINT32 Delay
8571 **          Delay in milliseconds.
8572 **
8573 **  OUTPUT:
8574 **
8575 **      Nothing.
8576 */
8577 gceSTATUS
8578 gckOS_StartTimer(
8579     IN gckOS Os,
8580     IN gctPOINTER Timer,
8581     IN gctUINT32 Delay
8582     )
8583 {
8584     gcsOSTIMER_PTR timer;
8585
8586     gcmkHEADER_ARG("Os=0x%X Timer=0x%X Delay=%u", Os, Timer, Delay);
8587
8588     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
8589     gcmkVERIFY_ARGUMENT(Timer != gcvNULL);
8590     gcmkVERIFY_ARGUMENT(Delay != 0);
8591
8592     timer = (gcsOSTIMER_PTR)Timer;
8593
8594     if (unlikely(delayed_work_pending(&timer->work)))
8595     {
8596         cancel_delayed_work(&timer->work);
8597     }
8598
8599     queue_delayed_work(Os->workqueue, &timer->work, msecs_to_jiffies(Delay));
8600
8601     gcmkFOOTER_NO();
8602     return gcvSTATUS_OK;
8603 }
8604
8605 /*******************************************************************************
8606 **
8607 **  gckOS_StopTimer
8608 **
8609 **  Cancel a unscheduled timer.
8610 **
8611 **  INPUT:
8612 **
8613 **      gckOS Os
8614 **          Pointer to the gckOS object.
8615 **
8616 **      gctPOINTER Timer
8617 **          Pointer to the timer to be cancel.
8618 **
8619 **  OUTPUT:
8620 **
8621 **      Nothing.
8622 */
8623 gceSTATUS
8624 gckOS_StopTimer(
8625     IN gckOS Os,
8626     IN gctPOINTER Timer
8627     )
8628 {
8629     gcsOSTIMER_PTR timer;
8630     gcmkHEADER_ARG("Os=0x%X Timer=0x%X", Os, Timer);
8631
8632     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
8633     gcmkVERIFY_ARGUMENT(Timer != gcvNULL);
8634
8635     timer = (gcsOSTIMER_PTR)Timer;
8636
8637     cancel_delayed_work(&timer->work);
8638
8639     gcmkFOOTER_NO();
8640     return gcvSTATUS_OK;
8641 }
8642
8643
8644 gceSTATUS
8645 gckOS_DumpCallStack(
8646     IN gckOS Os
8647     )
8648 {
8649     gcmkHEADER_ARG("Os=0x%X", Os);
8650
8651     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
8652
8653     dump_stack();
8654
8655     gcmkFOOTER_NO();
8656     return gcvSTATUS_OK;
8657 }
8658
8659
8660 gceSTATUS
8661 gckOS_GetProcessNameByPid(
8662     IN gctINT Pid,
8663     IN gctSIZE_T Length,
8664     OUT gctUINT8_PTR String
8665     )
8666 {
8667     struct task_struct *task;
8668
8669     /* Get the task_struct of the task with pid. */
8670     rcu_read_lock();
8671
8672     task = FIND_TASK_BY_PID(Pid);
8673
8674     if (task == gcvNULL)
8675     {
8676         rcu_read_unlock();
8677         return gcvSTATUS_NOT_FOUND;
8678     }
8679
8680     /* Get name of process. */
8681     strncpy(String, task->comm, Length);
8682
8683     rcu_read_unlock();
8684
8685     return gcvSTATUS_OK;
8686 }
8687
8688 #if gcdANDROID_NATIVE_FENCE_SYNC
8689
8690 gceSTATUS
8691 gckOS_CreateSyncPoint(
8692     IN gckOS Os,
8693     OUT gctSYNC_POINT * SyncPoint
8694     )
8695 {
8696     gceSTATUS status;
8697     gcsSYNC_POINT_PTR syncPoint;
8698
8699     gcmkHEADER_ARG("Os=0x%X", Os);
8700
8701     /* Verify the arguments. */
8702     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
8703
8704     /* Create an sync point structure. */
8705     syncPoint = (gcsSYNC_POINT_PTR) kmalloc(
8706             sizeof(gcsSYNC_POINT), GFP_KERNEL | gcdNOWARN);
8707
8708     if (syncPoint == gcvNULL)
8709     {
8710         gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
8711     }
8712
8713     /* Initialize the sync point. */
8714     atomic_set(&syncPoint->ref, 1);
8715     atomic_set(&syncPoint->state, 0);
8716
8717     gcmkONERROR(_AllocateIntegerId(&Os->syncPointDB, syncPoint, &syncPoint->id));
8718
8719     *SyncPoint = (gctSYNC_POINT)(gctUINTPTR_T)syncPoint->id;
8720
8721     gcmkFOOTER_ARG("*SyncPonint=%d", syncPoint->id);
8722     return gcvSTATUS_OK;
8723
8724 OnError:
8725     if (syncPoint != gcvNULL)
8726     {
8727         kfree(syncPoint);
8728     }
8729
8730     gcmkFOOTER();
8731     return status;
8732 }
8733
8734 gceSTATUS
8735 gckOS_ReferenceSyncPoint(
8736     IN gckOS Os,
8737     IN gctSYNC_POINT SyncPoint
8738     )
8739 {
8740     gceSTATUS status;
8741     gcsSYNC_POINT_PTR syncPoint;
8742
8743     gcmkHEADER_ARG("Os=0x%X", Os);
8744
8745     /* Verify the arguments. */
8746     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
8747     gcmkVERIFY_ARGUMENT(SyncPoint != gcvNULL);
8748
8749     gcmkONERROR(
8750         _QueryIntegerId(&Os->syncPointDB,
8751                         (gctUINT32)(gctUINTPTR_T)SyncPoint,
8752                         (gctPOINTER)&syncPoint));
8753
8754     /* Initialize the sync point. */
8755     atomic_inc(&syncPoint->ref);
8756
8757     gcmkFOOTER_NO();
8758     return gcvSTATUS_OK;
8759
8760 OnError:
8761     gcmkFOOTER();
8762     return status;
8763 }
8764
8765 gceSTATUS
8766 gckOS_DestroySyncPoint(
8767     IN gckOS Os,
8768     IN gctSYNC_POINT SyncPoint
8769     )
8770 {
8771     gceSTATUS status;
8772     gcsSYNC_POINT_PTR syncPoint;
8773     gctBOOL acquired = gcvFALSE;
8774
8775     gcmkHEADER_ARG("Os=0x%X SyncPoint=%d", Os, (gctUINT32)(gctUINTPTR_T)SyncPoint);
8776
8777     /* Verify the arguments. */
8778     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
8779     gcmkVERIFY_ARGUMENT(SyncPoint != gcvNULL);
8780
8781     gcmkONERROR(gckOS_AcquireMutex(Os, Os->syncPointMutex, gcvINFINITE));
8782     acquired = gcvTRUE;
8783
8784     gcmkONERROR(
8785         _QueryIntegerId(&Os->syncPointDB,
8786                         (gctUINT32)(gctUINTPTR_T)SyncPoint,
8787                         (gctPOINTER)&syncPoint));
8788
8789     gcmkASSERT(syncPoint->id == (gctUINT32)(gctUINTPTR_T)SyncPoint);
8790
8791     if (atomic_dec_and_test(&syncPoint->ref))
8792     {
8793         gcmkVERIFY_OK(_DestroyIntegerId(&Os->syncPointDB, syncPoint->id));
8794
8795         /* Free the sgianl. */
8796         syncPoint->timeline = gcvNULL;
8797         kfree(syncPoint);
8798     }
8799
8800     gcmkVERIFY_OK(gckOS_ReleaseMutex(Os, Os->syncPointMutex));
8801     acquired = gcvFALSE;
8802
8803     /* Success. */
8804     gcmkFOOTER_NO();
8805     return gcvSTATUS_OK;
8806
8807 OnError:
8808     if (acquired)
8809     {
8810         /* Release the mutex. */
8811         gcmkVERIFY_OK(gckOS_ReleaseMutex(Os, Os->syncPointMutex));
8812     }
8813
8814     gcmkFOOTER();
8815     return status;
8816 }
8817
8818 gceSTATUS
8819 gckOS_SignalSyncPoint(
8820     IN gckOS Os,
8821     IN gctSYNC_POINT SyncPoint
8822     )
8823 {
8824     gceSTATUS status;
8825     gcsSYNC_POINT_PTR syncPoint;
8826     gctBOOL acquired = gcvFALSE;
8827
8828     gcmkHEADER_ARG("Os=0x%X SyncPoint=%d", Os, (gctUINT32)(gctUINTPTR_T)SyncPoint);
8829
8830     /* Verify the arguments. */
8831     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
8832     gcmkVERIFY_ARGUMENT(SyncPoint != gcvNULL);
8833
8834     gcmkONERROR(gckOS_AcquireMutex(Os, Os->syncPointMutex, gcvINFINITE));
8835     acquired = gcvTRUE;
8836
8837     gcmkONERROR(
8838         _QueryIntegerId(&Os->syncPointDB,
8839                         (gctUINT32)(gctUINTPTR_T)SyncPoint,
8840                         (gctPOINTER)&syncPoint));
8841
8842     gcmkASSERT(syncPoint->id == (gctUINT32)(gctUINTPTR_T)SyncPoint);
8843
8844     /* Get state. */
8845     atomic_set(&syncPoint->state, gcvTRUE);
8846
8847     /* Signal timeline. */
8848     if (syncPoint->timeline)
8849     {
8850         sync_timeline_signal(syncPoint->timeline);
8851     }
8852
8853     gcmkVERIFY_OK(gckOS_ReleaseMutex(Os, Os->syncPointMutex));
8854     acquired = gcvFALSE;
8855
8856     /* Success. */
8857     gcmkFOOTER_NO();
8858     return gcvSTATUS_OK;
8859
8860 OnError:
8861     if (acquired)
8862     {
8863         /* Release the mutex. */
8864         gcmkVERIFY_OK(gckOS_ReleaseMutex(Os, Os->syncPointMutex));
8865     }
8866
8867     gcmkFOOTER();
8868     return status;
8869 }
8870
8871 gceSTATUS
8872 gckOS_QuerySyncPoint(
8873     IN gckOS Os,
8874     IN gctSYNC_POINT SyncPoint,
8875     OUT gctBOOL_PTR State
8876     )
8877 {
8878     gceSTATUS status;
8879     gcsSYNC_POINT_PTR syncPoint;
8880
8881     gcmkHEADER_ARG("Os=0x%X SyncPoint=%d", Os, (gctUINT32)(gctUINTPTR_T)SyncPoint);
8882
8883     /* Verify the arguments. */
8884     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
8885     gcmkVERIFY_ARGUMENT(SyncPoint != gcvNULL);
8886
8887     gcmkONERROR(
8888         _QueryIntegerId(&Os->syncPointDB,
8889                         (gctUINT32)(gctUINTPTR_T)SyncPoint,
8890                         (gctPOINTER)&syncPoint));
8891
8892     gcmkASSERT(syncPoint->id == (gctUINT32)(gctUINTPTR_T)SyncPoint);
8893
8894     /* Get state. */
8895     *State = atomic_read(&syncPoint->state);
8896
8897     /* Success. */
8898     gcmkFOOTER_ARG("*State=%d", *State);
8899     return gcvSTATUS_OK;
8900
8901 OnError:
8902     gcmkFOOTER();
8903     return status;
8904 }
8905
8906 gceSTATUS
8907 gckOS_CreateSyncTimeline(
8908     IN gckOS Os,
8909     OUT gctHANDLE * Timeline
8910     )
8911 {
8912     struct viv_sync_timeline * timeline;
8913
8914     /* Create viv sync timeline. */
8915     timeline = viv_sync_timeline_create("viv timeline", Os);
8916
8917     if (timeline == gcvNULL)
8918     {
8919         /* Out of memory. */
8920         return gcvSTATUS_OUT_OF_MEMORY;
8921     }
8922
8923     *Timeline = (gctHANDLE) timeline;
8924     return gcvSTATUS_OK;
8925 }
8926
8927 gceSTATUS
8928 gckOS_DestroySyncTimeline(
8929     IN gckOS Os,
8930     IN gctHANDLE Timeline
8931     )
8932 {
8933     struct viv_sync_timeline * timeline;
8934     gcmkASSERT(Timeline != gcvNULL);
8935
8936     /* Destroy timeline. */
8937     timeline = (struct viv_sync_timeline *) Timeline;
8938     sync_timeline_destroy(&timeline->obj);
8939
8940     return gcvSTATUS_OK;
8941 }
8942
8943 gceSTATUS
8944 gckOS_CreateNativeFence(
8945     IN gckOS Os,
8946     IN gctHANDLE Timeline,
8947     IN gctSYNC_POINT SyncPoint,
8948     OUT gctINT * FenceFD
8949     )
8950 {
8951     int fd = -1;
8952     struct viv_sync_timeline *timeline;
8953     struct sync_pt * pt = gcvNULL;
8954     struct sync_fence * fence;
8955     char name[32];
8956     gcsSYNC_POINT_PTR syncPoint;
8957     gceSTATUS status;
8958
8959     gcmkHEADER_ARG("Os=0x%X Timeline=0x%X SyncPoint=%d",
8960                    Os, Timeline, (gctUINT)(gctUINTPTR_T)SyncPoint);
8961
8962     gcmkONERROR(
8963         _QueryIntegerId(&Os->syncPointDB,
8964                         (gctUINT32)(gctUINTPTR_T)SyncPoint,
8965                         (gctPOINTER)&syncPoint));
8966
8967     /* Cast timeline. */
8968     timeline = (struct viv_sync_timeline *) Timeline;
8969
8970     fd = get_unused_fd();
8971
8972     if (fd < 0)
8973     {
8974         /* Out of resources. */
8975         gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES);
8976     }
8977
8978     /* Create viv_sync_pt. */
8979     pt = viv_sync_pt_create(timeline, SyncPoint);
8980
8981     if (pt == gcvNULL)
8982     {
8983         gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
8984     }
8985
8986     /* Reference sync_timeline. */
8987     syncPoint->timeline = &timeline->obj;
8988
8989     /* Build fence name. */
8990     snprintf(name, 32, "viv sync_fence-%u", (gctUINT)(gctUINTPTR_T)SyncPoint);
8991
8992     /* Create sync_fence. */
8993     fence = sync_fence_create(name, pt);
8994
8995     if (fence == NULL)
8996     {
8997         gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
8998     }
8999
9000     /* Install fence to fd. */
9001     sync_fence_install(fence, fd);
9002
9003     *FenceFD = fd;
9004     gcmkFOOTER_ARG("*FenceFD=%d", fd);
9005     return gcvSTATUS_OK;
9006
9007 OnError:
9008     /* Error roll back. */
9009     if (pt)
9010     {
9011         sync_pt_free(pt);
9012     }
9013
9014     if (fd > 0)
9015     {
9016         put_unused_fd(fd);
9017     }
9018
9019     gcmkFOOTER();
9020     return status;
9021 }
9022 #endif