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