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