]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_os.c
5366c08ef47a0f55de172ebce5d106088c2f408a
[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
6858     gctBOOL oldClockState = gcvFALSE;
6859     gctBOOL oldPowerState = gcvFALSE;
6860
6861     gcmkHEADER_ARG("Os=0x%X Core=%d Clock=%d Power=%d", Os, Core, Clock, Power);
6862
6863     if (Os->device->kernels[Core] != NULL)
6864     {
6865 #if gcdENABLE_VG
6866         if (Core == gcvCORE_VG)
6867         {
6868             oldClockState = Os->device->kernels[Core]->vg->hardware->clockState;
6869             oldPowerState = Os->device->kernels[Core]->vg->hardware->powerState;
6870         }
6871         else
6872         {
6873 #endif
6874             oldClockState = Os->device->kernels[Core]->hardware->clockState;
6875             oldPowerState = Os->device->kernels[Core]->hardware->powerState;
6876 #if gcdENABLE_VG
6877         }
6878 #endif
6879     }
6880         if((Power == gcvTRUE) && (oldPowerState == gcvFALSE))
6881         {
6882 #if LINUX_VERSION_CODE < KERNEL_VERSION(3,5,0)
6883         if(!IS_ERR(Os->device->gpu_regulator))
6884             regulator_enable(Os->device->gpu_regulator);
6885 #else
6886         imx_gpc_power_up_pu(true);
6887 #endif
6888
6889 #ifdef CONFIG_PM
6890                 pm_runtime_get_sync(Os->device->pmdev);
6891 #endif
6892         }
6893
6894 #if LINUX_VERSION_CODE < KERNEL_VERSION(3,5,0)
6895     if (Clock == gcvTRUE) {
6896         if (oldClockState == gcvFALSE) {
6897             switch (Core) {
6898             case gcvCORE_MAJOR:
6899                 clk_enable(clk_3dcore);
6900                 if (cpu_is_mx6q())
6901                     clk_enable(clk_3dshader);
6902                 break;
6903             case gcvCORE_2D:
6904                 clk_enable(clk_2dcore);
6905                 clk_enable(clk_2d_axi);
6906                 break;
6907             case gcvCORE_VG:
6908                 clk_enable(clk_2dcore);
6909                 clk_enable(clk_vg_axi);
6910                 break;
6911             default:
6912                 break;
6913             }
6914         }
6915     } else {
6916         if (oldClockState == gcvTRUE) {
6917             switch (Core) {
6918             case gcvCORE_MAJOR:
6919                 if (cpu_is_mx6q())
6920                     clk_disable(clk_3dshader);
6921                 clk_disable(clk_3dcore);
6922                 break;
6923            case gcvCORE_2D:
6924                 clk_disable(clk_2dcore);
6925                 clk_disable(clk_2d_axi);
6926                 break;
6927             case gcvCORE_VG:
6928                 clk_disable(clk_2dcore);
6929                 clk_disable(clk_vg_axi);
6930                 break;
6931             default:
6932                 break;
6933             }
6934         }
6935     }
6936 #else
6937     if (Clock == gcvTRUE) {
6938         if (oldClockState == gcvFALSE) {
6939             switch (Core) {
6940             case gcvCORE_MAJOR:
6941                 clk_prepare(clk_3dcore);
6942                 clk_enable(clk_3dcore);
6943                 clk_prepare(clk_3dshader);
6944                 clk_enable(clk_3dshader);
6945                 clk_prepare(clk_3d_axi);
6946                 clk_enable(clk_3d_axi);
6947                 break;
6948             case gcvCORE_2D:
6949                 clk_prepare(clk_2dcore);
6950                 clk_enable(clk_2dcore);
6951                 clk_prepare(clk_2d_axi);
6952                 clk_enable(clk_2d_axi);
6953                 break;
6954             case gcvCORE_VG:
6955                 clk_prepare(clk_2dcore);
6956                 clk_enable(clk_2dcore);
6957                 clk_prepare(clk_vg_axi);
6958                 clk_enable(clk_vg_axi);
6959                 break;
6960             default:
6961                 break;
6962             }
6963         }
6964     } else {
6965         if (oldClockState == gcvTRUE) {
6966             switch (Core) {
6967             case gcvCORE_MAJOR:
6968                 clk_disable(clk_3dshader);
6969                 clk_unprepare(clk_3dshader);
6970                 clk_disable(clk_3dcore);
6971                 clk_unprepare(clk_3dcore);
6972                 clk_disable(clk_3d_axi);
6973                 clk_unprepare(clk_3d_axi);
6974                 break;
6975            case gcvCORE_2D:
6976                 clk_disable(clk_2dcore);
6977                 clk_unprepare(clk_2dcore);
6978                 clk_disable(clk_2d_axi);
6979                 clk_unprepare(clk_2d_axi);
6980                 break;
6981             case gcvCORE_VG:
6982                 clk_disable(clk_2dcore);
6983                 clk_unprepare(clk_2dcore);
6984                 clk_disable(clk_vg_axi);
6985                 clk_unprepare(clk_vg_axi);
6986                 break;
6987             default:
6988                 break;
6989             }
6990         }
6991     }
6992 #endif
6993         if((Power == gcvFALSE) && (oldPowerState == gcvTRUE))
6994         {
6995 #ifdef CONFIG_PM
6996                 pm_runtime_put_sync(Os->device->pmdev);
6997 #endif
6998
6999 #if LINUX_VERSION_CODE < KERNEL_VERSION(3,5,0)
7000         if(!IS_ERR(Os->device->gpu_regulator))
7001             regulator_disable(Os->device->gpu_regulator);
7002 #else
7003         imx_gpc_power_up_pu(false);
7004 #endif
7005
7006         }
7007     /* TODO: Put your code here. */
7008     gcmkFOOTER_NO();
7009     return gcvSTATUS_OK;
7010 }
7011
7012 /*******************************************************************************
7013 **
7014 **  gckOS_ResetGPU
7015 **
7016 **  Reset the GPU.
7017 **
7018 **  INPUT:
7019 **
7020 **      gckOS Os
7021 **          Pointer to a gckOS object.
7022 **
7023 **      gckCORE Core
7024 **          GPU whose power is set.
7025 **
7026 **  OUTPUT:
7027 **
7028 **      Nothing.
7029 */
7030 gceSTATUS
7031 gckOS_ResetGPU(
7032     IN gckOS Os,
7033     IN gceCORE Core
7034     )
7035 {
7036 #if LINUX_VERSION_CODE < KERNEL_VERSION(3,5,0)
7037 #define SRC_SCR_OFFSET 0
7038 #define BP_SRC_SCR_GPU3D_RST 1
7039 #define BP_SRC_SCR_GPU2D_RST 4
7040     void __iomem *src_base = IO_ADDRESS(SRC_BASE_ADDR);
7041     gctUINT32 bit_offset,val;
7042
7043     gcmkHEADER_ARG("Os=0x%X Core=%d", Os, Core);
7044
7045     if(Core == gcvCORE_MAJOR) {
7046         bit_offset = BP_SRC_SCR_GPU3D_RST;
7047     } else if((Core == gcvCORE_VG)
7048             ||(Core == gcvCORE_2D)) {
7049         bit_offset = BP_SRC_SCR_GPU2D_RST;
7050     } else {
7051         return gcvSTATUS_INVALID_CONFIG;
7052     }
7053     val = __raw_readl(src_base + SRC_SCR_OFFSET);
7054     val &= ~(1 << (bit_offset));
7055     val |= (1 << (bit_offset));
7056     __raw_writel(val, src_base + SRC_SCR_OFFSET);
7057
7058     while ((__raw_readl(src_base + SRC_SCR_OFFSET) &
7059                 (1 << (bit_offset))) != 0) {
7060     }
7061
7062     gcmkFOOTER_NO();
7063 #elif LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
7064         struct reset_control *rstc = Os->device->rstc[Core];
7065         if (rstc)
7066                 reset_control_reset(rstc);
7067 #else
7068     imx_src_reset_gpu((int)Core);
7069 #endif
7070     return gcvSTATUS_OK;
7071 }
7072
7073 /*******************************************************************************
7074 **
7075 **  gckOS_PrepareGPUFrequency
7076 **
7077 **  Prepare to set GPU frequency and voltage.
7078 **
7079 **  INPUT:
7080 **
7081 **      gckOS Os
7082 **          Pointer to a gckOS object.
7083 **
7084 **      gckCORE Core
7085 **          GPU whose frequency and voltage will be set.
7086 **
7087 **  OUTPUT:
7088 **
7089 **      Nothing.
7090 */
7091 gceSTATUS
7092 gckOS_PrepareGPUFrequency(
7093     IN gckOS Os,
7094     IN gceCORE Core
7095     )
7096 {
7097     return gcvSTATUS_OK;
7098 }
7099
7100 /*******************************************************************************
7101 **
7102 **  gckOS_FinishGPUFrequency
7103 **
7104 **  Finish GPU frequency setting.
7105 **
7106 **  INPUT:
7107 **
7108 **      gckOS Os
7109 **          Pointer to a gckOS object.
7110 **
7111 **      gckCORE Core
7112 **          GPU whose frequency and voltage is set.
7113 **
7114 **  OUTPUT:
7115 **
7116 **      Nothing.
7117 */
7118 gceSTATUS
7119 gckOS_FinishGPUFrequency(
7120     IN gckOS Os,
7121     IN gceCORE Core
7122     )
7123 {
7124     return gcvSTATUS_OK;
7125 }
7126
7127 /*******************************************************************************
7128 **
7129 **  gckOS_QueryGPUFrequency
7130 **
7131 **  Query the current frequency of the GPU.
7132 **
7133 **  INPUT:
7134 **
7135 **      gckOS Os
7136 **          Pointer to a gckOS object.
7137 **
7138 **      gckCORE Core
7139 **          GPU whose power is set.
7140 **
7141 **      gctUINT32 * Frequency
7142 **          Pointer to a gctUINT32 to obtain current frequency, in MHz.
7143 **
7144 **      gctUINT8 * Scale
7145 **          Pointer to a gctUINT8 to obtain current scale(1 - 64).
7146 **
7147 **  OUTPUT:
7148 **
7149 **      Nothing.
7150 */
7151 gceSTATUS
7152 gckOS_QueryGPUFrequency(
7153     IN gckOS Os,
7154     IN gceCORE Core,
7155     OUT gctUINT32 * Frequency,
7156     OUT gctUINT8 * Scale
7157     )
7158 {
7159     return gcvSTATUS_OK;
7160 }
7161
7162 /*******************************************************************************
7163 **
7164 **  gckOS_SetGPUFrequency
7165 **
7166 **  Set frequency and voltage of the GPU.
7167 **
7168 **      1. DVFS manager gives the target scale of full frequency, BSP must find
7169 **         a real frequency according to this scale and board's configure.
7170 **
7171 **      2. BSP should find a suitable voltage for this frequency.
7172 **
7173 **      3. BSP must make sure setting take effect before this function returns.
7174 **
7175 **  INPUT:
7176 **
7177 **      gckOS Os
7178 **          Pointer to a gckOS object.
7179 **
7180 **      gckCORE Core
7181 **          GPU whose power is set.
7182 **
7183 **      gctUINT8 Scale
7184 **          Target scale of full frequency, range is [1, 64]. 1 means 1/64 of
7185 **          full frequency and 64 means 64/64 of full frequency.
7186 **
7187 **  OUTPUT:
7188 **
7189 **      Nothing.
7190 */
7191 gceSTATUS
7192 gckOS_SetGPUFrequency(
7193     IN gckOS Os,
7194     IN gceCORE Core,
7195     IN gctUINT8 Scale
7196     )
7197 {
7198     return gcvSTATUS_OK;
7199 }
7200
7201 /*----------------------------------------------------------------------------*/
7202 /*----- Profile --------------------------------------------------------------*/
7203
7204 gceSTATUS
7205 gckOS_GetProfileTick(
7206     OUT gctUINT64_PTR Tick
7207     )
7208 {
7209     struct timespec time;
7210
7211     ktime_get_ts(&time);
7212
7213     *Tick = time.tv_nsec + time.tv_sec * 1000000000ULL;
7214
7215     return gcvSTATUS_OK;
7216 }
7217
7218 gceSTATUS
7219 gckOS_QueryProfileTickRate(
7220     OUT gctUINT64_PTR TickRate
7221     )
7222 {
7223     struct timespec res;
7224
7225     hrtimer_get_res(CLOCK_MONOTONIC, &res);
7226
7227     *TickRate = res.tv_nsec + res.tv_sec * 1000000000ULL;
7228
7229     return gcvSTATUS_OK;
7230 }
7231
7232 gctUINT32
7233 gckOS_ProfileToMS(
7234     IN gctUINT64 Ticks
7235     )
7236 {
7237 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,23)
7238     return div_u64(Ticks, 1000000);
7239 #else
7240     gctUINT64 rem = Ticks;
7241     gctUINT64 b = 1000000;
7242     gctUINT64 res, d = 1;
7243     gctUINT32 high = rem >> 32;
7244
7245     /* Reduce the thing a bit first */
7246     res = 0;
7247     if (high >= 1000000)
7248     {
7249         high /= 1000000;
7250         res   = (gctUINT64) high << 32;
7251         rem  -= (gctUINT64) (high * 1000000) << 32;
7252     }
7253
7254     while (((gctINT64) b > 0) && (b < rem))
7255     {
7256         b <<= 1;
7257         d <<= 1;
7258     }
7259
7260     do
7261     {
7262         if (rem >= b)
7263         {
7264             rem -= b;
7265             res += d;
7266         }
7267
7268         b >>= 1;
7269         d >>= 1;
7270     }
7271     while (d);
7272
7273     return (gctUINT32) res;
7274 #endif
7275 }
7276
7277 /******************************************************************************\
7278 ******************************* Signal Management ******************************
7279 \******************************************************************************/
7280
7281 #undef _GC_OBJ_ZONE
7282 #define _GC_OBJ_ZONE    gcvZONE_SIGNAL
7283
7284 /*******************************************************************************
7285 **
7286 **  gckOS_CreateSignal
7287 **
7288 **  Create a new signal.
7289 **
7290 **  INPUT:
7291 **
7292 **      gckOS Os
7293 **          Pointer to an gckOS object.
7294 **
7295 **      gctBOOL ManualReset
7296 **          If set to gcvTRUE, gckOS_Signal with gcvFALSE must be called in
7297 **          order to set the signal to nonsignaled state.
7298 **          If set to gcvFALSE, the signal will automatically be set to
7299 **          nonsignaled state by gckOS_WaitSignal function.
7300 **
7301 **  OUTPUT:
7302 **
7303 **      gctSIGNAL * Signal
7304 **          Pointer to a variable receiving the created gctSIGNAL.
7305 */
7306 gceSTATUS
7307 gckOS_CreateSignal(
7308     IN gckOS Os,
7309     IN gctBOOL ManualReset,
7310     OUT gctSIGNAL * Signal
7311     )
7312 {
7313     gceSTATUS status;
7314     gcsSIGNAL_PTR signal;
7315
7316     gcmkHEADER_ARG("Os=0x%X ManualReset=%d", Os, ManualReset);
7317
7318     /* Verify the arguments. */
7319     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
7320     gcmkVERIFY_ARGUMENT(Signal != gcvNULL);
7321
7322     /* Create an event structure. */
7323     signal = (gcsSIGNAL_PTR) kmalloc(sizeof(gcsSIGNAL), GFP_KERNEL | gcdNOWARN);
7324
7325     if (signal == gcvNULL)
7326     {
7327         gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
7328     }
7329
7330     /* Save the process ID. */
7331     signal->process = (gctHANDLE)(gctUINTPTR_T) _GetProcessID();
7332     signal->manualReset = ManualReset;
7333     signal->hardware = gcvNULL;
7334     init_completion(&signal->obj);
7335     atomic_set(&signal->ref, 1);
7336
7337     gcmkONERROR(_AllocateIntegerId(&Os->signalDB, signal, &signal->id));
7338
7339     *Signal = (gctSIGNAL)(gctUINTPTR_T)signal->id;
7340
7341     gcmkFOOTER_ARG("*Signal=0x%X", *Signal);
7342     return gcvSTATUS_OK;
7343
7344 OnError:
7345     if (signal != gcvNULL)
7346     {
7347         kfree(signal);
7348     }
7349
7350     gcmkFOOTER_NO();
7351     return status;
7352 }
7353
7354 gceSTATUS
7355 gckOS_SignalQueryHardware(
7356     IN gckOS Os,
7357     IN gctSIGNAL Signal,
7358     OUT gckHARDWARE * Hardware
7359     )
7360 {
7361     gceSTATUS status;
7362     gcsSIGNAL_PTR signal;
7363
7364     gcmkHEADER_ARG("Os=0x%X Signal=0x%X Hardware=0x%X", Os, Signal, Hardware);
7365
7366     /* Verify the arguments. */
7367     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
7368     gcmkVERIFY_ARGUMENT(Signal != gcvNULL);
7369     gcmkVERIFY_ARGUMENT(Hardware != gcvNULL);
7370
7371     gcmkONERROR(_QueryIntegerId(&Os->signalDB, (gctUINT32)(gctUINTPTR_T)Signal, (gctPOINTER)&signal));
7372
7373     *Hardware = signal->hardware;
7374
7375     gcmkFOOTER_NO();
7376     return gcvSTATUS_OK;
7377 OnError:
7378     gcmkFOOTER();
7379     return status;
7380 }
7381
7382 gceSTATUS
7383 gckOS_SignalSetHardware(
7384     IN gckOS Os,
7385     IN gctSIGNAL Signal,
7386     IN gckHARDWARE Hardware
7387     )
7388 {
7389     gceSTATUS status;
7390     gcsSIGNAL_PTR signal;
7391
7392     gcmkHEADER_ARG("Os=0x%X Signal=0x%X Hardware=0x%X", Os, Signal, Hardware);
7393
7394     /* Verify the arguments. */
7395     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
7396     gcmkVERIFY_ARGUMENT(Signal != gcvNULL);
7397
7398     gcmkONERROR(_QueryIntegerId(&Os->signalDB, (gctUINT32)(gctUINTPTR_T)Signal, (gctPOINTER)&signal));
7399
7400     signal->hardware = Hardware;
7401
7402     gcmkFOOTER_NO();
7403     return gcvSTATUS_OK;
7404 OnError:
7405     gcmkFOOTER();
7406     return status;
7407 }
7408
7409 /*******************************************************************************
7410 **
7411 **  gckOS_DestroySignal
7412 **
7413 **  Destroy a signal.
7414 **
7415 **  INPUT:
7416 **
7417 **      gckOS Os
7418 **          Pointer to an gckOS object.
7419 **
7420 **      gctSIGNAL Signal
7421 **          Pointer to the gctSIGNAL.
7422 **
7423 **  OUTPUT:
7424 **
7425 **      Nothing.
7426 */
7427 gceSTATUS
7428 gckOS_DestroySignal(
7429     IN gckOS Os,
7430     IN gctSIGNAL Signal
7431     )
7432 {
7433     gceSTATUS status;
7434     gcsSIGNAL_PTR signal;
7435     gctBOOL acquired = gcvFALSE;
7436
7437     gcmkHEADER_ARG("Os=0x%X Signal=0x%X", Os, Signal);
7438
7439     /* Verify the arguments. */
7440     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
7441     gcmkVERIFY_ARGUMENT(Signal != gcvNULL);
7442
7443     gcmkONERROR(gckOS_AcquireMutex(Os, Os->signalMutex, gcvINFINITE));
7444     acquired = gcvTRUE;
7445
7446     gcmkONERROR(_QueryIntegerId(&Os->signalDB, (gctUINT32)(gctUINTPTR_T)Signal, (gctPOINTER)&signal));
7447
7448     gcmkASSERT(signal->id == (gctUINT32)(gctUINTPTR_T)Signal);
7449
7450     if (atomic_dec_and_test(&signal->ref))
7451     {
7452         gcmkVERIFY_OK(_DestroyIntegerId(&Os->signalDB, signal->id));
7453
7454         /* Free the sgianl. */
7455         kfree(signal);
7456     }
7457
7458     gcmkVERIFY_OK(gckOS_ReleaseMutex(Os, Os->signalMutex));
7459     acquired = gcvFALSE;
7460
7461     /* Success. */
7462     gcmkFOOTER_NO();
7463     return gcvSTATUS_OK;
7464
7465 OnError:
7466     if (acquired)
7467     {
7468         /* Release the mutex. */
7469         gcmkVERIFY_OK(gckOS_ReleaseMutex(Os, Os->signalMutex));
7470     }
7471
7472     gcmkFOOTER();
7473     return status;
7474 }
7475
7476 /*******************************************************************************
7477 **
7478 **  gckOS_Signal
7479 **
7480 **  Set a state of the specified signal.
7481 **
7482 **  INPUT:
7483 **
7484 **      gckOS Os
7485 **          Pointer to an gckOS object.
7486 **
7487 **      gctSIGNAL Signal
7488 **          Pointer to the gctSIGNAL.
7489 **
7490 **      gctBOOL State
7491 **          If gcvTRUE, the signal will be set to signaled state.
7492 **          If gcvFALSE, the signal will be set to nonsignaled state.
7493 **
7494 **  OUTPUT:
7495 **
7496 **      Nothing.
7497 */
7498 gceSTATUS
7499 gckOS_Signal(
7500     IN gckOS Os,
7501     IN gctSIGNAL Signal,
7502     IN gctBOOL State
7503     )
7504 {
7505     gceSTATUS status;
7506     gcsSIGNAL_PTR signal;
7507     gctBOOL acquired = gcvFALSE;
7508
7509     gcmkHEADER_ARG("Os=0x%X Signal=0x%X State=%d", Os, Signal, State);
7510
7511     /* Verify the arguments. */
7512     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
7513     gcmkVERIFY_ARGUMENT(Signal != gcvNULL);
7514
7515     gcmkONERROR(gckOS_AcquireMutex(Os, Os->signalMutex, gcvINFINITE));
7516     acquired = gcvTRUE;
7517
7518     gcmkONERROR(_QueryIntegerId(&Os->signalDB, (gctUINT32)(gctUINTPTR_T)Signal, (gctPOINTER)&signal));
7519
7520     gcmkASSERT(signal->id == (gctUINT32)(gctUINTPTR_T)Signal);
7521
7522     if (State)
7523     {
7524         /* unbind the signal from hardware. */
7525         signal->hardware = gcvNULL;
7526
7527         /* Set the event to a signaled state. */
7528         complete(&signal->obj);
7529     }
7530     else
7531     {
7532         /* Set the event to an unsignaled state. */
7533         INIT_COMPLETION(signal->obj);
7534     }
7535
7536     gcmkVERIFY_OK(gckOS_ReleaseMutex(Os, Os->signalMutex));
7537     acquired = gcvFALSE;
7538
7539     /* Success. */
7540     gcmkFOOTER_NO();
7541     return gcvSTATUS_OK;
7542
7543 OnError:
7544     if (acquired)
7545     {
7546         /* Release the mutex. */
7547         gcmkVERIFY_OK(gckOS_ReleaseMutex(Os, Os->signalMutex));
7548     }
7549
7550     gcmkFOOTER();
7551     return status;
7552 }
7553
7554 #if gcdENABLE_VG
7555 gceSTATUS
7556 gckOS_SetSignalVG(
7557     IN gckOS Os,
7558     IN gctHANDLE Process,
7559     IN gctSIGNAL Signal
7560     )
7561 {
7562     gceSTATUS status;
7563     gctINT result;
7564     struct task_struct * userTask;
7565     struct siginfo info;
7566
7567     userTask = FIND_TASK_BY_PID((pid_t)(gctUINTPTR_T) Process);
7568
7569     if (userTask != gcvNULL)
7570     {
7571         info.si_signo = 48;
7572         info.si_code  = __SI_CODE(__SI_RT, SI_KERNEL);
7573         info.si_pid   = 0;
7574         info.si_uid   = 0;
7575         info.si_ptr   = (gctPOINTER) Signal;
7576
7577         /* Signals with numbers between 32 and 63 are real-time,
7578            send a real-time signal to the user process. */
7579         result = send_sig_info(48, &info, userTask);
7580
7581         printk("gckOS_SetSignalVG:0x%x\n", result);
7582         /* Error? */
7583         if (result < 0)
7584         {
7585             status = gcvSTATUS_GENERIC_IO;
7586
7587             gcmkTRACE(
7588                 gcvLEVEL_ERROR,
7589                 "%s(%d): an error has occurred.\n",
7590                 __FUNCTION__, __LINE__
7591                 );
7592         }
7593         else
7594         {
7595             status = gcvSTATUS_OK;
7596         }
7597     }
7598     else
7599     {
7600         status = gcvSTATUS_GENERIC_IO;
7601
7602         gcmkTRACE(
7603             gcvLEVEL_ERROR,
7604             "%s(%d): an error has occurred.\n",
7605             __FUNCTION__, __LINE__
7606             );
7607     }
7608
7609     /* Return status. */
7610     return status;
7611 }
7612 #endif
7613
7614 /*******************************************************************************
7615 **
7616 **  gckOS_UserSignal
7617 **
7618 **  Set the specified signal which is owned by a process to signaled state.
7619 **
7620 **  INPUT:
7621 **
7622 **      gckOS Os
7623 **          Pointer to an gckOS object.
7624 **
7625 **      gctSIGNAL Signal
7626 **          Pointer to the gctSIGNAL.
7627 **
7628 **      gctHANDLE Process
7629 **          Handle of process owning the signal.
7630 **
7631 **  OUTPUT:
7632 **
7633 **      Nothing.
7634 */
7635 gceSTATUS
7636 gckOS_UserSignal(
7637     IN gckOS Os,
7638     IN gctSIGNAL Signal,
7639     IN gctHANDLE Process
7640     )
7641 {
7642     gceSTATUS status;
7643     gctSIGNAL signal;
7644
7645     gcmkHEADER_ARG("Os=0x%X Signal=0x%X Process=%d",
7646                    Os, Signal, (gctINT32)(gctUINTPTR_T)Process);
7647
7648     /* Map the signal into kernel space. */
7649     gcmkONERROR(gckOS_MapSignal(Os, Signal, Process, &signal));
7650
7651     /* Signal. */
7652     status = gckOS_Signal(Os, signal, gcvTRUE);
7653
7654     /* Unmap the signal */
7655     gcmkVERIFY_OK(gckOS_UnmapSignal(Os, Signal));
7656
7657     gcmkFOOTER();
7658     return status;
7659
7660 OnError:
7661     /* Return the status. */
7662     gcmkFOOTER();
7663     return status;
7664 }
7665
7666 /*******************************************************************************
7667 **
7668 **  gckOS_WaitSignal
7669 **
7670 **  Wait for a signal to become signaled.
7671 **
7672 **  INPUT:
7673 **
7674 **      gckOS Os
7675 **          Pointer to an gckOS object.
7676 **
7677 **      gctSIGNAL Signal
7678 **          Pointer to the gctSIGNAL.
7679 **
7680 **      gctUINT32 Wait
7681 **          Number of milliseconds to wait.
7682 **          Pass the value of gcvINFINITE for an infinite wait.
7683 **
7684 **  OUTPUT:
7685 **
7686 **      Nothing.
7687 */
7688 gceSTATUS
7689 gckOS_WaitSignal(
7690     IN gckOS Os,
7691     IN gctSIGNAL Signal,
7692     IN gctUINT32 Wait
7693     )
7694 {
7695     gceSTATUS status = gcvSTATUS_OK;
7696     gcsSIGNAL_PTR signal;
7697
7698     gcmkHEADER_ARG("Os=0x%X Signal=0x%X Wait=0x%08X", Os, Signal, Wait);
7699
7700     /* Verify the arguments. */
7701     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
7702     gcmkVERIFY_ARGUMENT(Signal != gcvNULL);
7703
7704     gcmkONERROR(_QueryIntegerId(&Os->signalDB, (gctUINT32)(gctUINTPTR_T)Signal, (gctPOINTER)&signal));
7705
7706     gcmkASSERT(signal->id == (gctUINT32)(gctUINTPTR_T)Signal);
7707
7708     might_sleep();
7709
7710     spin_lock_irq(&signal->obj.wait.lock);
7711
7712     if (signal->obj.done)
7713     {
7714         if (!signal->manualReset)
7715         {
7716             signal->obj.done = 0;
7717         }
7718
7719         status = gcvSTATUS_OK;
7720     }
7721     else if (Wait == 0)
7722     {
7723         status = gcvSTATUS_TIMEOUT;
7724     }
7725     else
7726     {
7727         /* Convert wait to milliseconds. */
7728 #if gcdDETECT_TIMEOUT
7729         gctINT timeout = (Wait == gcvINFINITE)
7730             ? gcdINFINITE_TIMEOUT * HZ / 1000
7731             : Wait * HZ / 1000;
7732
7733         gctUINT complained = 0;
7734 #else
7735         gctINT timeout = (Wait == gcvINFINITE)
7736             ? MAX_SCHEDULE_TIMEOUT
7737             : Wait * HZ / 1000;
7738 #endif
7739
7740         DECLARE_WAITQUEUE(wait, current);
7741         wait.flags |= WQ_FLAG_EXCLUSIVE;
7742         __add_wait_queue_tail(&signal->obj.wait, &wait);
7743
7744         while (gcvTRUE)
7745         {
7746             if (signal_pending(current))
7747             {
7748                 /* Interrupt received. */
7749                 status = gcvSTATUS_INTERRUPTED;
7750                 break;
7751             }
7752
7753             __set_current_state(TASK_INTERRUPTIBLE);
7754             spin_unlock_irq(&signal->obj.wait.lock);
7755             timeout = schedule_timeout(timeout);
7756             spin_lock_irq(&signal->obj.wait.lock);
7757
7758             if (signal->obj.done)
7759             {
7760                 if (!signal->manualReset)
7761                 {
7762                     signal->obj.done = 0;
7763                 }
7764
7765                 status = gcvSTATUS_OK;
7766                 break;
7767             }
7768
7769 #if gcdDETECT_TIMEOUT
7770             if ((Wait == gcvINFINITE) && (timeout == 0))
7771             {
7772                 gctUINT32 dmaAddress1, dmaAddress2;
7773                 gctUINT32 dmaState1, dmaState2;
7774
7775                 dmaState1   = dmaState2   =
7776                 dmaAddress1 = dmaAddress2 = 0;
7777
7778                 /* Verify whether DMA is running. */
7779                 gcmkVERIFY_OK(_VerifyDMA(
7780                     Os, &dmaAddress1, &dmaAddress2, &dmaState1, &dmaState2
7781                     ));
7782
7783 #if gcdDETECT_DMA_ADDRESS
7784                 /* Dump only if DMA appears stuck. */
7785                 if (
7786                     (dmaAddress1 == dmaAddress2)
7787 #if gcdDETECT_DMA_STATE
7788                  && (dmaState1   == dmaState2)
7789 #endif
7790                 )
7791 #endif
7792                 {
7793                     /* Increment complain count. */
7794                     complained += 1;
7795
7796                     gcmkVERIFY_OK(_DumpGPUState(Os, gcvCORE_MAJOR));
7797
7798                     gcmkPRINT(
7799                         "%s(%d): signal 0x%X; forced message flush (%d).",
7800                         __FUNCTION__, __LINE__, Signal, complained
7801                         );
7802
7803                     /* Flush the debug cache. */
7804                     gcmkDEBUGFLUSH(dmaAddress2);
7805                 }
7806
7807                 /* Reset timeout. */
7808                 timeout = gcdINFINITE_TIMEOUT * HZ / 1000;
7809             }
7810 #endif
7811
7812             if (timeout == 0)
7813             {
7814
7815                 status = gcvSTATUS_TIMEOUT;
7816                 break;
7817             }
7818         }
7819
7820         __remove_wait_queue(&signal->obj.wait, &wait);
7821
7822 #if gcdDETECT_TIMEOUT
7823         if (complained)
7824         {
7825             gcmkPRINT(
7826                 "%s(%d): signal=0x%X; waiting done; status=%d",
7827                 __FUNCTION__, __LINE__, Signal, status
7828                 );
7829         }
7830 #endif
7831     }
7832
7833     spin_unlock_irq(&signal->obj.wait.lock);
7834
7835 OnError:
7836     /* Return status. */
7837     gcmkFOOTER_ARG("Signal=0x%X status=%d", Signal, status);
7838     return status;
7839 }
7840
7841 /*******************************************************************************
7842 **
7843 **  gckOS_MapSignal
7844 **
7845 **  Map a signal in to the current process space.
7846 **
7847 **  INPUT:
7848 **
7849 **      gckOS Os
7850 **          Pointer to an gckOS object.
7851 **
7852 **      gctSIGNAL Signal
7853 **          Pointer to tha gctSIGNAL to map.
7854 **
7855 **      gctHANDLE Process
7856 **          Handle of process owning the signal.
7857 **
7858 **  OUTPUT:
7859 **
7860 **      gctSIGNAL * MappedSignal
7861 **          Pointer to a variable receiving the mapped gctSIGNAL.
7862 */
7863 gceSTATUS
7864 gckOS_MapSignal(
7865     IN gckOS Os,
7866     IN gctSIGNAL Signal,
7867     IN gctHANDLE Process,
7868     OUT gctSIGNAL * MappedSignal
7869     )
7870 {
7871     gceSTATUS status;
7872     gcsSIGNAL_PTR signal;
7873     gcmkHEADER_ARG("Os=0x%X Signal=0x%X Process=0x%X", Os, Signal, Process);
7874
7875     gcmkVERIFY_ARGUMENT(Signal != gcvNULL);
7876     gcmkVERIFY_ARGUMENT(MappedSignal != gcvNULL);
7877
7878     gcmkONERROR(_QueryIntegerId(&Os->signalDB, (gctUINT32)(gctUINTPTR_T)Signal, (gctPOINTER)&signal));
7879
7880     if(atomic_inc_return(&signal->ref) <= 1)
7881     {
7882         /* The previous value is 0, it has been deleted. */
7883         gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
7884     }
7885
7886     *MappedSignal = (gctSIGNAL) Signal;
7887
7888     /* Success. */
7889     gcmkFOOTER_ARG("*MappedSignal=0x%X", *MappedSignal);
7890     return gcvSTATUS_OK;
7891
7892 OnError:
7893     gcmkFOOTER_NO();
7894     return status;
7895 }
7896
7897 /*******************************************************************************
7898 **
7899 **      gckOS_UnmapSignal
7900 **
7901 **      Unmap a signal .
7902 **
7903 **      INPUT:
7904 **
7905 **              gckOS Os
7906 **                      Pointer to an gckOS object.
7907 **
7908 **              gctSIGNAL Signal
7909 **                      Pointer to that gctSIGNAL mapped.
7910 */
7911 gceSTATUS
7912 gckOS_UnmapSignal(
7913     IN gckOS Os,
7914     IN gctSIGNAL Signal
7915     )
7916 {
7917     return gckOS_DestroySignal(Os, Signal);
7918 }
7919
7920 /*******************************************************************************
7921 **
7922 **  gckOS_CreateUserSignal
7923 **
7924 **  Create a new signal to be used in the user space.
7925 **
7926 **  INPUT:
7927 **
7928 **      gckOS Os
7929 **          Pointer to an gckOS object.
7930 **
7931 **      gctBOOL ManualReset
7932 **          If set to gcvTRUE, gckOS_Signal with gcvFALSE must be called in
7933 **          order to set the signal to nonsignaled state.
7934 **          If set to gcvFALSE, the signal will automatically be set to
7935 **          nonsignaled state by gckOS_WaitSignal function.
7936 **
7937 **  OUTPUT:
7938 **
7939 **      gctINT * SignalID
7940 **          Pointer to a variable receiving the created signal's ID.
7941 */
7942 gceSTATUS
7943 gckOS_CreateUserSignal(
7944     IN gckOS Os,
7945     IN gctBOOL ManualReset,
7946     OUT gctINT * SignalID
7947     )
7948 {
7949     gceSTATUS status;
7950     gctSIZE_T signal;
7951
7952     /* Create a new signal. */
7953     status = gckOS_CreateSignal(Os, ManualReset, (gctSIGNAL *) &signal);
7954     *SignalID = (gctINT) signal;
7955
7956     return status;
7957 }
7958
7959 /*******************************************************************************
7960 **
7961 **  gckOS_DestroyUserSignal
7962 **
7963 **  Destroy a signal to be used in the user space.
7964 **
7965 **  INPUT:
7966 **
7967 **      gckOS Os
7968 **          Pointer to an gckOS object.
7969 **
7970 **      gctINT SignalID
7971 **          The signal's ID.
7972 **
7973 **  OUTPUT:
7974 **
7975 **      Nothing.
7976 */
7977 gceSTATUS
7978 gckOS_DestroyUserSignal(
7979     IN gckOS Os,
7980     IN gctINT SignalID
7981     )
7982 {
7983     return gckOS_DestroySignal(Os, (gctSIGNAL)(gctUINTPTR_T)SignalID);
7984 }
7985
7986 /*******************************************************************************
7987 **
7988 **  gckOS_WaitUserSignal
7989 **
7990 **  Wait for a signal used in the user mode to become signaled.
7991 **
7992 **  INPUT:
7993 **
7994 **      gckOS Os
7995 **          Pointer to an gckOS object.
7996 **
7997 **      gctINT SignalID
7998 **          Signal ID.
7999 **
8000 **      gctUINT32 Wait
8001 **          Number of milliseconds to wait.
8002 **          Pass the value of gcvINFINITE for an infinite wait.
8003 **
8004 **  OUTPUT:
8005 **
8006 **      Nothing.
8007 */
8008 gceSTATUS
8009 gckOS_WaitUserSignal(
8010     IN gckOS Os,
8011     IN gctINT SignalID,
8012     IN gctUINT32 Wait
8013     )
8014 {
8015     return gckOS_WaitSignal(Os, (gctSIGNAL)(gctUINTPTR_T)SignalID, Wait);
8016 }
8017
8018 /*******************************************************************************
8019 **
8020 **  gckOS_SignalUserSignal
8021 **
8022 **  Set a state of the specified signal to be used in the user space.
8023 **
8024 **  INPUT:
8025 **
8026 **      gckOS Os
8027 **          Pointer to an gckOS object.
8028 **
8029 **      gctINT SignalID
8030 **          SignalID.
8031 **
8032 **      gctBOOL State
8033 **          If gcvTRUE, the signal will be set to signaled state.
8034 **          If gcvFALSE, the signal will be set to nonsignaled state.
8035 **
8036 **  OUTPUT:
8037 **
8038 **      Nothing.
8039 */
8040 gceSTATUS
8041 gckOS_SignalUserSignal(
8042     IN gckOS Os,
8043     IN gctINT SignalID,
8044     IN gctBOOL State
8045     )
8046 {
8047     return gckOS_Signal(Os, (gctSIGNAL)(gctUINTPTR_T)SignalID, State);
8048 }
8049
8050 #if gcdENABLE_VG
8051 gceSTATUS
8052 gckOS_CreateSemaphoreVG(
8053     IN gckOS Os,
8054     OUT gctSEMAPHORE * Semaphore
8055     )
8056 {
8057     gceSTATUS status;
8058     struct semaphore * newSemaphore;
8059
8060     gcmkHEADER_ARG("Os=0x%X Semaphore=0x%x", Os, Semaphore);
8061     /* Verify the arguments. */
8062     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
8063     gcmkVERIFY_ARGUMENT(Semaphore != gcvNULL);
8064
8065     do
8066     {
8067         /* Allocate the semaphore structure. */
8068         newSemaphore = (struct semaphore *)kmalloc(gcmSIZEOF(struct semaphore), GFP_KERNEL | gcdNOWARN);
8069         if (newSemaphore == gcvNULL)
8070         {
8071                 gcmkERR_BREAK(gcvSTATUS_OUT_OF_MEMORY);
8072         }
8073
8074         /* Initialize the semaphore. */
8075         sema_init(newSemaphore, 0);
8076
8077         /* Set the handle. */
8078         * Semaphore = (gctSEMAPHORE) newSemaphore;
8079
8080         /* Success. */
8081         status = gcvSTATUS_OK;
8082     }
8083     while (gcvFALSE);
8084
8085     gcmkFOOTER();
8086     /* Return the status. */
8087     return status;
8088 }
8089
8090
8091 gceSTATUS
8092 gckOS_IncrementSemaphore(
8093     IN gckOS Os,
8094     IN gctSEMAPHORE Semaphore
8095     )
8096 {
8097     gcmkHEADER_ARG("Os=0x%X Semaphore=0x%x", Os, Semaphore);
8098     /* Verify the arguments. */
8099     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
8100     gcmkVERIFY_ARGUMENT(Semaphore != gcvNULL);
8101
8102     /* Increment the semaphore's count. */
8103     up((struct semaphore *) Semaphore);
8104
8105     gcmkFOOTER_NO();
8106     /* Success. */
8107     return gcvSTATUS_OK;
8108 }
8109
8110 gceSTATUS
8111 gckOS_DecrementSemaphore(
8112     IN gckOS Os,
8113     IN gctSEMAPHORE Semaphore
8114     )
8115 {
8116     gceSTATUS status;
8117     gctINT result;
8118
8119     gcmkHEADER_ARG("Os=0x%X Semaphore=0x%x", Os, Semaphore);
8120     /* Verify the arguments. */
8121     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
8122     gcmkVERIFY_ARGUMENT(Semaphore != gcvNULL);
8123
8124     do
8125     {
8126         /* Decrement the semaphore's count. If the count is zero, wait
8127            until it gets incremented. */
8128         result = down_interruptible((struct semaphore *) Semaphore);
8129
8130         /* Signal received? */
8131         if (result != 0)
8132         {
8133             status = gcvSTATUS_TERMINATE;
8134             break;
8135         }
8136
8137         /* Success. */
8138         status = gcvSTATUS_OK;
8139     }
8140     while (gcvFALSE);
8141
8142     gcmkFOOTER();
8143     /* Return the status. */
8144     return status;
8145 }
8146
8147 /*******************************************************************************
8148 **
8149 **  gckOS_SetSignal
8150 **
8151 **  Set the specified signal to signaled state.
8152 **
8153 **  INPUT:
8154 **
8155 **      gckOS Os
8156 **          Pointer to the gckOS object.
8157 **
8158 **      gctHANDLE Process
8159 **          Handle of process owning the signal.
8160 **
8161 **      gctSIGNAL Signal
8162 **          Pointer to the gctSIGNAL.
8163 **
8164 **  OUTPUT:
8165 **
8166 **      Nothing.
8167 */
8168 gceSTATUS
8169 gckOS_SetSignal(
8170     IN gckOS Os,
8171     IN gctHANDLE Process,
8172     IN gctSIGNAL Signal
8173     )
8174 {
8175     gceSTATUS status;
8176     gctINT result;
8177     struct task_struct * userTask;
8178     struct siginfo info;
8179
8180     userTask = FIND_TASK_BY_PID((pid_t)(gctUINTPTR_T) Process);
8181
8182     if (userTask != gcvNULL)
8183     {
8184         info.si_signo = 48;
8185         info.si_code  = __SI_CODE(__SI_RT, SI_KERNEL);
8186         info.si_pid   = 0;
8187         info.si_uid   = 0;
8188         info.si_ptr   = (gctPOINTER) Signal;
8189
8190         /* Signals with numbers between 32 and 63 are real-time,
8191            send a real-time signal to the user process. */
8192         result = send_sig_info(48, &info, userTask);
8193
8194         /* Error? */
8195         if (result < 0)
8196         {
8197             status = gcvSTATUS_GENERIC_IO;
8198
8199             gcmkTRACE(
8200                 gcvLEVEL_ERROR,
8201                 "%s(%d): an error has occurred.\n",
8202                 __FUNCTION__, __LINE__
8203                 );
8204         }
8205         else
8206         {
8207             status = gcvSTATUS_OK;
8208         }
8209     }
8210     else
8211     {
8212         status = gcvSTATUS_GENERIC_IO;
8213
8214         gcmkTRACE(
8215             gcvLEVEL_ERROR,
8216             "%s(%d): an error has occurred.\n",
8217             __FUNCTION__, __LINE__
8218             );
8219     }
8220
8221     /* Return status. */
8222     return status;
8223 }
8224
8225 /******************************************************************************\
8226 ******************************** Thread Object *********************************
8227 \******************************************************************************/
8228
8229 gceSTATUS
8230 gckOS_StartThread(
8231     IN gckOS Os,
8232     IN gctTHREADFUNC ThreadFunction,
8233     IN gctPOINTER ThreadParameter,
8234     OUT gctTHREAD * Thread
8235     )
8236 {
8237     gceSTATUS status;
8238     struct task_struct * thread;
8239
8240     gcmkHEADER_ARG("Os=0x%X ", Os);
8241     /* Verify the arguments. */
8242     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
8243     gcmkVERIFY_ARGUMENT(ThreadFunction != gcvNULL);
8244     gcmkVERIFY_ARGUMENT(Thread != gcvNULL);
8245
8246     do
8247     {
8248         /* Create the thread. */
8249         thread = kthread_create(
8250             ThreadFunction,
8251             ThreadParameter,
8252             "Vivante Kernel Thread"
8253             );
8254
8255         /* Failed? */
8256         if (IS_ERR(thread))
8257         {
8258             status = gcvSTATUS_GENERIC_IO;
8259             break;
8260         }
8261
8262         /* Start the thread. */
8263         wake_up_process(thread);
8264
8265         /* Set the thread handle. */
8266         * Thread = (gctTHREAD) thread;
8267
8268         /* Success. */
8269         status = gcvSTATUS_OK;
8270     }
8271     while (gcvFALSE);
8272
8273     gcmkFOOTER();
8274     /* Return the status. */
8275     return status;
8276 }
8277
8278 gceSTATUS
8279 gckOS_StopThread(
8280     IN gckOS Os,
8281     IN gctTHREAD Thread
8282     )
8283 {
8284     gcmkHEADER_ARG("Os=0x%X Thread=0x%x", Os, Thread);
8285     /* Verify the arguments. */
8286     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
8287     gcmkVERIFY_ARGUMENT(Thread != gcvNULL);
8288
8289     /* Thread should have already been enabled to terminate. */
8290     kthread_stop((struct task_struct *) Thread);
8291
8292     gcmkFOOTER_NO();
8293     /* Success. */
8294     return gcvSTATUS_OK;
8295 }
8296
8297 gceSTATUS
8298 gckOS_VerifyThread(
8299     IN gckOS Os,
8300     IN gctTHREAD Thread
8301     )
8302 {
8303     gcmkHEADER_ARG("Os=0x%X Thread=0x%x", Os, Thread);
8304     /* Verify the arguments. */
8305     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
8306     gcmkVERIFY_ARGUMENT(Thread != gcvNULL);
8307
8308     gcmkFOOTER_NO();
8309     /* Success. */
8310     return gcvSTATUS_OK;
8311 }
8312 #endif
8313
8314 /******************************************************************************\
8315 ******************************** Software Timer ********************************
8316 \******************************************************************************/
8317
8318 void
8319 _TimerFunction(
8320     struct work_struct * work
8321     )
8322 {
8323     gcsOSTIMER_PTR timer = (gcsOSTIMER_PTR)work;
8324
8325     gctTIMERFUNCTION function = timer->function;
8326
8327     function(timer->data);
8328 }
8329
8330 /*******************************************************************************
8331 **
8332 **  gckOS_CreateTimer
8333 **
8334 **  Create a software timer.
8335 **
8336 **  INPUT:
8337 **
8338 **      gckOS Os
8339 **          Pointer to the gckOS object.
8340 **
8341 **      gctTIMERFUNCTION Function.
8342 **          Pointer to a call back function which will be called when timer is
8343 **          expired.
8344 **
8345 **      gctPOINTER Data.
8346 **          Private data which will be passed to call back function.
8347 **
8348 **  OUTPUT:
8349 **
8350 **      gctPOINTER * Timer
8351 **          Pointer to a variable receiving the created timer.
8352 */
8353 gceSTATUS
8354 gckOS_CreateTimer(
8355     IN gckOS Os,
8356     IN gctTIMERFUNCTION Function,
8357     IN gctPOINTER Data,
8358     OUT gctPOINTER * Timer
8359     )
8360 {
8361     gceSTATUS status;
8362     gcsOSTIMER_PTR pointer;
8363     gcmkHEADER_ARG("Os=0x%X Function=0x%X Data=0x%X", Os, Function, Data);
8364
8365     /* Verify the arguments. */
8366     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
8367     gcmkVERIFY_ARGUMENT(Timer != gcvNULL);
8368
8369     gcmkONERROR(gckOS_Allocate(Os, sizeof(gcsOSTIMER), (gctPOINTER)&pointer));
8370
8371     pointer->function = Function;
8372     pointer->data = Data;
8373
8374     INIT_DELAYED_WORK(&pointer->work, _TimerFunction);
8375
8376     *Timer = pointer;
8377
8378     gcmkFOOTER_NO();
8379     return gcvSTATUS_OK;
8380
8381 OnError:
8382     gcmkFOOTER();
8383     return status;
8384 }
8385
8386 /*******************************************************************************
8387 **
8388 **  gckOS_DestroyTimer
8389 **
8390 **  Destory a software timer.
8391 **
8392 **  INPUT:
8393 **
8394 **      gckOS Os
8395 **          Pointer to the gckOS object.
8396 **
8397 **      gctPOINTER Timer
8398 **          Pointer to the timer to be destoryed.
8399 **
8400 **  OUTPUT:
8401 **
8402 **      Nothing.
8403 */
8404 gceSTATUS
8405 gckOS_DestroyTimer(
8406     IN gckOS Os,
8407     IN gctPOINTER Timer
8408     )
8409 {
8410     gcsOSTIMER_PTR timer;
8411     gcmkHEADER_ARG("Os=0x%X Timer=0x%X", Os, Timer);
8412
8413     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
8414     gcmkVERIFY_ARGUMENT(Timer != gcvNULL);
8415
8416     timer = (gcsOSTIMER_PTR)Timer;
8417
8418 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23)
8419     cancel_delayed_work_sync(&timer->work);
8420 #else
8421     cancel_delayed_work(&timer->work);
8422     flush_workqueue(Os->workqueue);
8423 #endif
8424
8425     gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Os, Timer));
8426
8427     gcmkFOOTER_NO();
8428     return gcvSTATUS_OK;
8429 }
8430
8431 /*******************************************************************************
8432 **
8433 **  gckOS_StartTimer
8434 **
8435 **  Schedule a software timer.
8436 **
8437 **  INPUT:
8438 **
8439 **      gckOS Os
8440 **          Pointer to the gckOS object.
8441 **
8442 **      gctPOINTER Timer
8443 **          Pointer to the timer to be scheduled.
8444 **
8445 **      gctUINT32 Delay
8446 **          Delay in milliseconds.
8447 **
8448 **  OUTPUT:
8449 **
8450 **      Nothing.
8451 */
8452 gceSTATUS
8453 gckOS_StartTimer(
8454     IN gckOS Os,
8455     IN gctPOINTER Timer,
8456     IN gctUINT32 Delay
8457     )
8458 {
8459     gcsOSTIMER_PTR timer;
8460
8461     gcmkHEADER_ARG("Os=0x%X Timer=0x%X Delay=%u", Os, Timer, Delay);
8462
8463     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
8464     gcmkVERIFY_ARGUMENT(Timer != gcvNULL);
8465     gcmkVERIFY_ARGUMENT(Delay != 0);
8466
8467     timer = (gcsOSTIMER_PTR)Timer;
8468
8469     if (unlikely(delayed_work_pending(&timer->work)))
8470     {
8471         cancel_delayed_work(&timer->work);
8472     }
8473
8474     queue_delayed_work(Os->workqueue, &timer->work, msecs_to_jiffies(Delay));
8475
8476     gcmkFOOTER_NO();
8477     return gcvSTATUS_OK;
8478 }
8479
8480 /*******************************************************************************
8481 **
8482 **  gckOS_StopTimer
8483 **
8484 **  Cancel a unscheduled timer.
8485 **
8486 **  INPUT:
8487 **
8488 **      gckOS Os
8489 **          Pointer to the gckOS object.
8490 **
8491 **      gctPOINTER Timer
8492 **          Pointer to the timer to be cancel.
8493 **
8494 **  OUTPUT:
8495 **
8496 **      Nothing.
8497 */
8498 gceSTATUS
8499 gckOS_StopTimer(
8500     IN gckOS Os,
8501     IN gctPOINTER Timer
8502     )
8503 {
8504     gcsOSTIMER_PTR timer;
8505     gcmkHEADER_ARG("Os=0x%X Timer=0x%X", Os, Timer);
8506
8507     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
8508     gcmkVERIFY_ARGUMENT(Timer != gcvNULL);
8509
8510     timer = (gcsOSTIMER_PTR)Timer;
8511
8512     cancel_delayed_work(&timer->work);
8513
8514     gcmkFOOTER_NO();
8515     return gcvSTATUS_OK;
8516 }
8517
8518
8519 gceSTATUS
8520 gckOS_DumpCallStack(
8521     IN gckOS Os
8522     )
8523 {
8524     gcmkHEADER_ARG("Os=0x%X", Os);
8525
8526     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
8527
8528     dump_stack();
8529
8530     gcmkFOOTER_NO();
8531     return gcvSTATUS_OK;
8532 }
8533
8534
8535 gceSTATUS
8536 gckOS_GetProcessNameByPid(
8537     IN gctINT Pid,
8538     IN gctSIZE_T Length,
8539     OUT gctUINT8_PTR String
8540     )
8541 {
8542     struct task_struct *task;
8543
8544     /* Get the task_struct of the task with pid. */
8545     rcu_read_lock();
8546
8547     task = FIND_TASK_BY_PID(Pid);
8548
8549     if (task == gcvNULL)
8550     {
8551         rcu_read_unlock();
8552         return gcvSTATUS_NOT_FOUND;
8553     }
8554
8555     /* Get name of process. */
8556     strncpy(String, task->comm, Length);
8557
8558     rcu_read_unlock();
8559
8560     return gcvSTATUS_OK;
8561 }
8562