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