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