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