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