ENGR00156850 gpu-viv: add gpu-viv driver source
[wandboard.git] / drivers / mxc / gpu-viv / hal / os / linux / kernel / gc_hal_kernel_os.c
blob979493830c7c5d9583ea6b201a4d5f6338513087
1 /****************************************************************************
3 * Copyright (C) 2005 - 2011 by Vivante Corp.
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.
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.
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.
19 *****************************************************************************/
24 #include "gc_hal_kernel_linux.h"
26 #include <linux/pagemap.h>
27 #include <linux/seq_file.h>
28 #include <linux/mm.h>
29 #include <linux/mman.h>
30 #include <linux/sched.h>
31 #include <asm/atomic.h>
32 #include <linux/dma-mapping.h>
33 #include <linux/slab.h>
34 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,23)
35 #include <linux/math64.h>
36 #endif
38 #define _GC_OBJ_ZONE gcvZONE_OS
40 /*******************************************************************************
41 ***** Version Signature *******************************************************/
43 #ifdef ANDROID
44 const char * _PLATFORM = "\n\0$PLATFORM$Android$\n";
45 #else
46 const char * _PLATFORM = "\n\0$PLATFORM$Linux$\n";
47 #endif
49 #define USER_SIGNAL_TABLE_LEN_INIT 64
51 #define MEMORY_LOCK(os) \
52 gcmkVERIFY_OK(gckOS_AcquireMutex( \
53 (os), \
54 (os)->memoryLock, \
55 gcvINFINITE))
57 #define MEMORY_UNLOCK(os) \
58 gcmkVERIFY_OK(gckOS_ReleaseMutex((os), (os)->memoryLock))
60 #define MEMORY_MAP_LOCK(os) \
61 gcmkVERIFY_OK(gckOS_AcquireMutex( \
62 (os), \
63 (os)->memoryMapLock, \
64 gcvINFINITE))
66 #define MEMORY_MAP_UNLOCK(os) \
67 gcmkVERIFY_OK(gckOS_ReleaseMutex((os), (os)->memoryMapLock))
69 #define gcdINFINITE_TIMEOUT (60 * 1000)
70 #define gcdDETECT_TIMEOUT 0
71 #define gcdDETECT_DMA_ADDRESS 1
72 #define gcdDETECT_DMA_STATE 1
74 /******************************************************************************\
75 ********************************** Structures **********************************
76 \******************************************************************************/
78 typedef struct _gcsUSER_MAPPING * gcsUSER_MAPPING_PTR;
79 typedef struct _gcsUSER_MAPPING
81 /* Pointer to next mapping structure. */
82 gcsUSER_MAPPING_PTR next;
84 /* Physical address of this mapping. */
85 gctUINT32 physical;
87 /* Logical address of this mapping. */
88 gctPOINTER logical;
90 /* Number of bytes of this mapping. */
91 gctSIZE_T bytes;
93 /* Starting address of this mapping. */
94 gctINT8_PTR start;
96 /* Ending address of this mapping. */
97 gctINT8_PTR end;
99 gcsUSER_MAPPING;
101 struct _gckOS
103 /* Object. */
104 gcsOBJECT object;
106 /* Heap. */
107 gckHEAP heap;
109 /* Pointer to device */
110 gckGALDEVICE device;
112 /* Memory management */
113 gctPOINTER memoryLock;
114 gctPOINTER memoryMapLock;
116 struct _LINUX_MDL *mdlHead;
117 struct _LINUX_MDL *mdlTail;
119 /* Kernel process ID. */
120 gctUINT32 kernelProcessID;
122 /* Signal management. */
123 struct _signal
125 /* Unused signal ID number. */
126 gctINT unused;
128 /* The pointer to the table. */
129 gctPOINTER * table;
131 /* Signal table length. */
132 gctINT tableLen;
134 /* The current unused signal ID. */
135 gctINT currentID;
137 /* Lock. */
138 gctPOINTER lock;
140 signal;
142 gcsUSER_MAPPING_PTR userMap;
143 gctPOINTER debugLock;
146 typedef struct _gcsSIGNAL * gcsSIGNAL_PTR;
147 typedef struct _gcsSIGNAL
149 /* Kernel sync primitive. */
150 struct completion obj;
152 /* Manual reset flag. */
153 gctBOOL manualReset;
155 /* The reference counter. */
156 atomic_t ref;
158 /* The owner of the signal. */
159 gctHANDLE process;
161 gcsSIGNAL;
163 typedef struct _gcsPageInfo * gcsPageInfo_PTR;
164 typedef struct _gcsPageInfo
166 struct page **pages;
167 gctUINT32_PTR pageTable;
169 gcsPageInfo;
171 typedef struct _gcsiDEBUG_REGISTERS * gcsiDEBUG_REGISTERS_PTR;
172 typedef struct _gcsiDEBUG_REGISTERS
174 gctSTRING module;
175 gctUINT index;
176 gctUINT shift;
177 gctUINT data;
178 gctUINT count;
179 gctUINT32 signature;
181 gcsiDEBUG_REGISTERS;
184 /******************************************************************************\
185 ******************************* Private Functions ******************************
186 \******************************************************************************/
188 static gceSTATUS
189 _VerifyDMA(
190 IN gckOS Os,
191 IN gceCORE Core,
192 gctUINT32_PTR Address1,
193 gctUINT32_PTR Address2,
194 gctUINT32_PTR State1,
195 gctUINT32_PTR State2
198 gceSTATUS status;
199 gctUINT32 i;
201 gcmkONERROR(gckOS_ReadRegisterEx(Os, Core, 0x660, State1));
202 gcmkONERROR(gckOS_ReadRegisterEx(Os, Core, 0x664, Address1));
204 for (i = 0; i < 500; i += 1)
206 gcmkONERROR(gckOS_ReadRegisterEx(Os, Core, 0x660, State2));
207 gcmkONERROR(gckOS_ReadRegisterEx(Os, Core, 0x664, Address2));
209 if (*Address1 != *Address2)
211 break;
214 #if gcdDETECT_DMA_STATE
215 if (*State1 != *State2)
217 break;
219 #endif
222 OnError:
223 return status;
226 static gceSTATUS
227 _DumpDebugRegisters(
228 IN gckOS Os,
229 IN gcsiDEBUG_REGISTERS_PTR Descriptor
232 gceSTATUS status;
233 gctUINT32 select;
234 gctUINT32 data;
235 gctUINT i;
237 gcmkHEADER_ARG("Os=0x%X Descriptor=0x%X", Os, Descriptor);
239 gcmkPRINT_N(4, " %s debug registers:\n", Descriptor->module);
241 select = 0xF << Descriptor->shift;
243 for (i = 0; i < 500; i += 1)
245 gcmkONERROR(gckOS_WriteRegister(Os, Descriptor->index, select));
246 gcmkONERROR(gckOS_Delay(Os, 1000));
247 gcmkONERROR(gckOS_ReadRegister(Os, Descriptor->data, &data));
249 if (data == Descriptor->signature)
251 break;
255 if (i == 500)
257 gcmkPRINT_N(4, " failed to obtain the signature (read 0x%08X).\n", data);
259 else
261 gcmkPRINT_N(8, " signature = 0x%08X (%d read attempt(s))\n", data, i + 1);
264 for (i = 0; i < Descriptor->count; i += 1)
266 select = i << Descriptor->shift;
268 gcmkONERROR(gckOS_WriteRegister(Os, Descriptor->index, select));
269 gcmkONERROR(gckOS_Delay(Os, 1000));
270 gcmkONERROR(gckOS_ReadRegister(Os, Descriptor->data, &data));
272 gcmkPRINT_N(12, " [0x%02X] 0x%08X\n", i, data);
275 OnError:
276 /* Return the error. */
277 gcmkFOOTER();
278 return status;
281 static gceSTATUS
282 _DumpGPUState(
283 IN gckOS Os
286 static gctCONST_STRING _cmdState[] =
288 "PAR_IDLE_ST", "PAR_DEC_ST", "PAR_ADR0_ST", "PAR_LOAD0_ST",
289 "PAR_ADR1_ST", "PAR_LOAD1_ST", "PAR_3DADR_ST", "PAR_3DCMD_ST",
290 "PAR_3DCNTL_ST", "PAR_3DIDXCNTL_ST", "PAR_INITREQDMA_ST",
291 "PAR_DRAWIDX_ST", "PAR_DRAW_ST", "PAR_2DRECT0_ST", "PAR_2DRECT1_ST",
292 "PAR_2DDATA0_ST", "PAR_2DDATA1_ST", "PAR_WAITFIFO_ST", "PAR_WAIT_ST",
293 "PAR_LINK_ST", "PAR_END_ST", "PAR_STALL_ST"
296 static gctCONST_STRING _cmdDmaState[] =
298 "CMD_IDLE_ST", "CMD_START_ST", "CMD_REQ_ST", "CMD_END_ST"
301 static gctCONST_STRING _cmdFetState[] =
303 "FET_IDLE_ST", "FET_RAMVALID_ST", "FET_VALID_ST"
306 static gctCONST_STRING _reqDmaState[] =
308 "REQ_IDLE_ST", "REQ_WAITIDX_ST", "REQ_CAL_ST"
311 static gctCONST_STRING _calState[] =
313 "CAL_IDLE_ST", "CAL_LDADR_ST", "CAL_IDXCALC_ST"
316 static gctCONST_STRING _veReqState[] =
318 "VER_IDLE_ST", "VER_CKCACHE_ST", "VER_MISS_ST"
321 static gcsiDEBUG_REGISTERS _dbgRegs[] =
323 { "RA", 0x474, 16, 0x448, 4, 0x12344321 },
324 { "TX", 0x474, 24, 0x44C, 4, 0x12211221 },
325 { "FE", 0x470, 0, 0x450, 4, 0xBABEF00D },
326 { "PE", 0x470, 16, 0x454, 4, 0xBABEF00D },
327 { "DE", 0x470, 8, 0x458, 4, 0xBABEF00D },
328 { "SH", 0x470, 24, 0x45C, 15, 0xDEADBEEF },
329 { "PA", 0x474, 0, 0x460, 4, 0x0000AAAA },
330 { "SE", 0x474, 8, 0x464, 4, 0x5E5E5E5E },
331 { "MC", 0x478, 0, 0x468, 4, 0x12345678 },
332 { "HI", 0x478, 8, 0x46C, 4, 0xAAAAAAAA }
335 gceSTATUS status;
336 gctBOOL acquired = gcvFALSE;
337 gckGALDEVICE device;
338 gckKERNEL kernel;
339 gctUINT32 idle, axi;
340 gctUINT32 dmaAddress1, dmaAddress2;
341 gctUINT32 dmaState1, dmaState2;
342 gctUINT32 dmaLow, dmaHigh;
343 gctUINT32 cmdState, cmdDmaState, cmdFetState;
344 gctUINT32 dmaReqState, calState, veReqState;
345 gctUINT i;
347 gcmkHEADER_ARG("Os=0x%X", Os);
349 gcmkONERROR(gckOS_AcquireMutex(Os, Os->debugLock, gcvINFINITE));
350 acquired = gcvTRUE;
352 /* Extract the pointer to the gckGALDEVICE class. */
353 device = (gckGALDEVICE) Os->device;
355 /* TODO: Kernel shortcut. */
356 kernel = device->kernels[gcvCORE_MAJOR];
358 if (kernel == gcvNULL) return gcvSTATUS_OK;
360 /* Reset register values. */
361 idle = axi =
362 dmaState1 = dmaState2 =
363 dmaAddress1 = dmaAddress2 =
364 dmaLow = dmaHigh = 0;
366 /* Verify whether DMA is running. */
367 gcmkONERROR(_VerifyDMA(
368 Os, kernel->core, &dmaAddress1, &dmaAddress2, &dmaState1, &dmaState2
371 cmdState = dmaState2 & 0x1F;
372 cmdDmaState = (dmaState2 >> 8) & 0x03;
373 cmdFetState = (dmaState2 >> 10) & 0x03;
374 dmaReqState = (dmaState2 >> 12) & 0x03;
375 calState = (dmaState2 >> 14) & 0x03;
376 veReqState = (dmaState2 >> 16) & 0x03;
378 gcmkONERROR(gckOS_ReadRegisterEx(Os, kernel->core, 0x004, &idle));
379 gcmkONERROR(gckOS_ReadRegisterEx(Os, kernel->core, 0x00C, &axi));
380 gcmkONERROR(gckOS_ReadRegisterEx(Os, kernel->core, 0x668, &dmaLow));
381 gcmkONERROR(gckOS_ReadRegisterEx(Os, kernel->core, 0x66C, &dmaHigh));
383 gcmkPRINT_N(0, "**************************\n");
384 gcmkPRINT_N(0, "*** GPU STATE DUMP ***\n");
385 gcmkPRINT_N(0, "**************************\n");
387 gcmkPRINT_N(4, " axi = 0x%08X\n", axi);
389 gcmkPRINT_N(4, " idle = 0x%08X\n", idle);
390 if ((idle & 0x00000001) == 0) gcmkPRINT_N(0, " FE not idle\n");
391 if ((idle & 0x00000002) == 0) gcmkPRINT_N(0, " DE not idle\n");
392 if ((idle & 0x00000004) == 0) gcmkPRINT_N(0, " PE not idle\n");
393 if ((idle & 0x00000008) == 0) gcmkPRINT_N(0, " SH not idle\n");
394 if ((idle & 0x00000010) == 0) gcmkPRINT_N(0, " PA not idle\n");
395 if ((idle & 0x00000020) == 0) gcmkPRINT_N(0, " SE not idle\n");
396 if ((idle & 0x00000040) == 0) gcmkPRINT_N(0, " RA not idle\n");
397 if ((idle & 0x00000080) == 0) gcmkPRINT_N(0, " TX not idle\n");
398 if ((idle & 0x00000100) == 0) gcmkPRINT_N(0, " VG not idle\n");
399 if ((idle & 0x00000200) == 0) gcmkPRINT_N(0, " IM not idle\n");
400 if ((idle & 0x00000400) == 0) gcmkPRINT_N(0, " FP not idle\n");
401 if ((idle & 0x00000800) == 0) gcmkPRINT_N(0, " TS not idle\n");
402 if ((idle & 0x80000000) != 0) gcmkPRINT_N(0, " AXI low power mode\n");
404 if (
405 (dmaAddress1 == dmaAddress2)
407 #if gcdDETECT_DMA_STATE
408 && (dmaState1 == dmaState2)
409 #endif
412 gcmkPRINT_N(0, " DMA appears to be stuck at this address:\n");
413 gcmkPRINT_N(4, " 0x%08X\n", dmaAddress1);
415 else
417 if (dmaAddress1 == dmaAddress2)
419 gcmkPRINT_N(0, " DMA address is constant, but state is changing:\n");
420 gcmkPRINT_N(4, " 0x%08X\n", dmaState1);
421 gcmkPRINT_N(4, " 0x%08X\n", dmaState2);
423 else
425 gcmkPRINT_N(0, " DMA is running; known addresses are:\n");
426 gcmkPRINT_N(4, " 0x%08X\n", dmaAddress1);
427 gcmkPRINT_N(4, " 0x%08X\n", dmaAddress2);
431 gcmkPRINT_N(4, " dmaLow = 0x%08X\n", dmaLow);
432 gcmkPRINT_N(4, " dmaHigh = 0x%08X\n", dmaHigh);
433 gcmkPRINT_N(4, " dmaState = 0x%08X\n", dmaState2);
434 gcmkPRINT_N(8, " command state = %d (%s)\n", cmdState, _cmdState [cmdState]);
435 gcmkPRINT_N(8, " command DMA state = %d (%s)\n", cmdDmaState, _cmdDmaState[cmdDmaState]);
436 gcmkPRINT_N(8, " command fetch state = %d (%s)\n", cmdFetState, _cmdFetState[cmdFetState]);
437 gcmkPRINT_N(8, " DMA request state = %d (%s)\n", dmaReqState, _reqDmaState[dmaReqState]);
438 gcmkPRINT_N(8, " cal state = %d (%s)\n", calState, _calState [calState]);
439 gcmkPRINT_N(8, " VE request state = %d (%s)\n", veReqState, _veReqState [veReqState]);
441 for (i = 0; i < gcmCOUNTOF(_dbgRegs); i += 1)
443 gcmkONERROR(_DumpDebugRegisters(Os, &_dbgRegs[i]));
446 if (kernel->hardware->chipFeatures & (1 << 4))
448 gctUINT32 read0, read1, write;
450 read0 = read1 = write = 0;
452 gcmkONERROR(gckOS_ReadRegisterEx(Os, kernel->core, 0x43C, &read0));
453 gcmkONERROR(gckOS_ReadRegisterEx(Os, kernel->core, 0x440, &read1));
454 gcmkONERROR(gckOS_ReadRegisterEx(Os, kernel->core, 0x444, &write));
456 gcmkPRINT_N(4, " read0 = 0x%08X\n", read0);
457 gcmkPRINT_N(4, " read1 = 0x%08X\n", read1);
458 gcmkPRINT_N(4, " write = 0x%08X\n", write);
461 OnError:
462 if (acquired)
464 /* Release the mutex. */
465 gcmkVERIFY_OK(gckOS_ReleaseMutex(Os, Os->debugLock));
468 /* Return the error. */
469 gcmkFOOTER();
470 return status;
473 static gctINT
474 _GetProcessID(
475 void
478 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
479 return task_tgid_vnr(current);
480 #else
481 return current->tgid;
482 #endif
485 static gctINT
486 _GetThreadID(
487 void
490 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
491 return task_pid_vnr(current);
492 #else
493 return current->pid;
494 #endif
497 static PLINUX_MDL
498 _CreateMdl(
499 IN gctINT ProcessID
502 PLINUX_MDL mdl;
504 gcmkHEADER_ARG("ProcessID=%d", ProcessID);
506 mdl = (PLINUX_MDL)kmalloc(sizeof(struct _LINUX_MDL), GFP_KERNEL);
507 if (mdl == gcvNULL)
509 gcmkFOOTER_NO();
510 return gcvNULL;
513 mdl->pid = ProcessID;
514 mdl->maps = gcvNULL;
515 mdl->prev = gcvNULL;
516 mdl->next = gcvNULL;
518 gcmkFOOTER_ARG("0x%X", mdl);
519 return mdl;
522 static gceSTATUS
523 _DestroyMdlMap(
524 IN PLINUX_MDL Mdl,
525 IN PLINUX_MDL_MAP MdlMap
528 static gceSTATUS
529 _DestroyMdl(
530 IN PLINUX_MDL Mdl
533 PLINUX_MDL_MAP mdlMap, next;
535 gcmkHEADER_ARG("Mdl=0x%X", Mdl);
537 /* Verify the arguments. */
538 gcmkVERIFY_ARGUMENT(Mdl != gcvNULL);
540 mdlMap = Mdl->maps;
542 while (mdlMap != gcvNULL)
544 next = mdlMap->next;
546 gcmkVERIFY_OK(_DestroyMdlMap(Mdl, mdlMap));
548 mdlMap = next;
551 kfree(Mdl);
553 gcmkFOOTER_NO();
554 return gcvSTATUS_OK;
557 static PLINUX_MDL_MAP
558 _CreateMdlMap(
559 IN PLINUX_MDL Mdl,
560 IN gctINT ProcessID
563 PLINUX_MDL_MAP mdlMap;
565 gcmkHEADER_ARG("Mdl=0x%X ProcessID=%d", Mdl, ProcessID);
567 mdlMap = (PLINUX_MDL_MAP)kmalloc(sizeof(struct _LINUX_MDL_MAP), GFP_KERNEL);
568 if (mdlMap == gcvNULL)
570 gcmkFOOTER_NO();
571 return gcvNULL;
574 mdlMap->pid = ProcessID;
575 mdlMap->vmaAddr = gcvNULL;
576 mdlMap->vma = gcvNULL;
578 mdlMap->next = Mdl->maps;
579 Mdl->maps = mdlMap;
581 gcmkFOOTER_ARG("0x%X", mdlMap);
582 return mdlMap;
585 static gceSTATUS
586 _DestroyMdlMap(
587 IN PLINUX_MDL Mdl,
588 IN PLINUX_MDL_MAP MdlMap
591 PLINUX_MDL_MAP prevMdlMap;
593 gcmkHEADER_ARG("Mdl=0x%X MdlMap=0x%X", Mdl, MdlMap);
595 /* Verify the arguments. */
596 gcmkVERIFY_ARGUMENT(MdlMap != gcvNULL);
597 gcmkASSERT(Mdl->maps != gcvNULL);
599 if (Mdl->maps == MdlMap)
601 Mdl->maps = MdlMap->next;
603 else
605 prevMdlMap = Mdl->maps;
607 while (prevMdlMap->next != MdlMap)
609 prevMdlMap = prevMdlMap->next;
611 gcmkASSERT(prevMdlMap != gcvNULL);
614 prevMdlMap->next = MdlMap->next;
617 kfree(MdlMap);
619 gcmkFOOTER_NO();
620 return gcvSTATUS_OK;
623 extern PLINUX_MDL_MAP
624 FindMdlMap(
625 IN PLINUX_MDL Mdl,
626 IN gctINT ProcessID
629 PLINUX_MDL_MAP mdlMap;
631 gcmkHEADER_ARG("Mdl=0x%X ProcessID=%d", Mdl, ProcessID);
632 if(Mdl == gcvNULL)
634 return gcvNULL;
636 mdlMap = Mdl->maps;
638 while (mdlMap != gcvNULL)
640 if (mdlMap->pid == ProcessID)
642 gcmkFOOTER_ARG("0x%X", mdlMap);
643 return mdlMap;
646 mdlMap = mdlMap->next;
649 gcmkFOOTER_NO();
650 return gcvNULL;
653 void
654 OnProcessExit(
655 IN gckOS Os,
656 IN gckKERNEL Kernel
661 /*******************************************************************************
663 ** gckOS_Construct
665 ** Construct a new gckOS object.
667 ** INPUT:
669 ** gctPOINTER Context
670 ** Pointer to the gckGALDEVICE class.
672 ** OUTPUT:
674 ** gckOS * Os
675 ** Pointer to a variable that will hold the pointer to the gckOS object.
677 gceSTATUS
678 gckOS_Construct(
679 IN gctPOINTER Context,
680 OUT gckOS * Os
683 gckOS os;
684 gceSTATUS status;
686 gcmkHEADER_ARG("Context=0x%X", Context);
688 /* Verify the arguments. */
689 gcmkVERIFY_ARGUMENT(Os != gcvNULL);
691 /* Allocate the gckOS object. */
692 os = (gckOS) kmalloc(gcmSIZEOF(struct _gckOS), GFP_KERNEL);
694 if (os == gcvNULL)
696 /* Out of memory. */
697 gcmkFOOTER_ARG("status=%d", gcvSTATUS_OUT_OF_MEMORY);
698 return gcvSTATUS_OUT_OF_MEMORY;
701 /* Zero the memory. */
702 gckOS_ZeroMemory(os, gcmSIZEOF(struct _gckOS));
704 /* Initialize the gckOS object. */
705 os->object.type = gcvOBJ_OS;
707 /* Set device device. */
708 os->device = Context;
710 /* IMPORTANT! No heap yet. */
711 os->heap = gcvNULL;
713 /* Initialize the memory lock. */
714 gcmkONERROR(gckOS_CreateMutex(os, &os->memoryLock));
715 gcmkONERROR(gckOS_CreateMutex(os, &os->memoryMapLock));
717 /* Create debug lock mutex. */
718 gcmkONERROR(gckOS_CreateMutex(os, &os->debugLock));
720 /* Create the gckHEAP object. */
721 gcmkONERROR(gckHEAP_Construct(os, gcdHEAP_SIZE, &os->heap));
723 os->mdlHead = os->mdlTail = gcvNULL;
725 /* Get the kernel process ID. */
726 gcmkONERROR(gckOS_GetProcessID(&os->kernelProcessID));
729 * Initialize the signal manager.
730 * It creates the signals to be used in
731 * the user space.
734 /* Initialize mutex. */
735 gcmkONERROR(
736 gckOS_CreateMutex(os, &os->signal.lock));
738 /* Initialize the signal table. */
739 os->signal.table =
740 kmalloc(gcmSIZEOF(gctPOINTER) * USER_SIGNAL_TABLE_LEN_INIT, GFP_KERNEL);
742 if (os->signal.table == gcvNULL)
744 /* Out of memory. */
745 gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
748 gckOS_ZeroMemory(os->signal.table,
749 gcmSIZEOF(gctPOINTER) * USER_SIGNAL_TABLE_LEN_INIT);
751 /* Set the signal table length. */
752 os->signal.tableLen = USER_SIGNAL_TABLE_LEN_INIT;
754 /* The table is empty. */
755 os->signal.unused = os->signal.tableLen;
757 /* Initial signal ID. */
758 os->signal.currentID = 0;
760 /* Return pointer to the gckOS object. */
761 *Os = os;
763 /* Success. */
764 gcmkFOOTER_ARG("*Os=0x%X", *Os);
765 return gcvSTATUS_OK;
767 OnError:
768 /* Roll back any allocation. */
769 if (os->signal.table != gcvNULL)
771 kfree(os->signal.table);
774 if (os->signal.lock != gcvNULL)
776 gcmkVERIFY_OK(
777 gckOS_DeleteMutex(os, os->signal.lock));
780 if (os->heap != gcvNULL)
782 gcmkVERIFY_OK(
783 gckHEAP_Destroy(os->heap));
786 if (os->memoryMapLock != gcvNULL)
788 gcmkVERIFY_OK(
789 gckOS_DeleteMutex(os, os->memoryMapLock));
792 if (os->memoryLock != gcvNULL)
794 gcmkVERIFY_OK(
795 gckOS_DeleteMutex(os, os->memoryLock));
798 if (os->debugLock != gcvNULL)
800 gcmkVERIFY_OK(
801 gckOS_DeleteMutex(os, os->debugLock));
804 kfree(os);
806 /* Return the error. */
807 gcmkFOOTER();
808 return status;
811 /*******************************************************************************
813 ** gckOS_Destroy
815 ** Destroy an gckOS object.
817 ** INPUT:
819 ** gckOS Os
820 ** Pointer to an gckOS object that needs to be destroyed.
822 ** OUTPUT:
824 ** Nothing.
826 gceSTATUS
827 gckOS_Destroy(
828 IN gckOS Os
831 gckHEAP heap;
833 gcmkHEADER_ARG("Os=0x%X", Os);
835 /* Verify the arguments. */
836 gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
839 * Destroy the signal manager.
842 /* Destroy the mutex. */
843 gcmkVERIFY_OK(gckOS_DeleteMutex(Os, Os->signal.lock));
845 /* Free the signal table. */
846 kfree(Os->signal.table);
848 if (Os->heap != gcvNULL)
850 /* Mark gckHEAP as gone. */
851 heap = Os->heap;
852 Os->heap = gcvNULL;
854 /* Destroy the gckHEAP object. */
855 gcmkVERIFY_OK(gckHEAP_Destroy(heap));
858 /* Destroy the memory lock. */
859 gcmkVERIFY_OK(gckOS_DeleteMutex(Os, Os->memoryMapLock));
860 gcmkVERIFY_OK(gckOS_DeleteMutex(Os, Os->memoryLock));
862 /* Destroy debug lock mutex. */
863 gcmkVERIFY_OK(gckOS_DeleteMutex(Os, Os->debugLock));
865 /* Flush the debug cache. */
866 gcmkDEBUGFLUSH(~0U);
868 /* Mark the gckOS object as unknown. */
869 Os->object.type = gcvOBJ_UNKNOWN;
871 /* Free the gckOS object. */
872 kfree(Os);
874 /* Success. */
875 gcmkFOOTER_NO();
876 return gcvSTATUS_OK;
879 /*******************************************************************************
881 ** gckOS_Allocate
883 ** Allocate memory.
885 ** INPUT:
887 ** gckOS Os
888 ** Pointer to an gckOS object.
890 ** gctSIZE_T Bytes
891 ** Number of bytes to allocate.
893 ** OUTPUT:
895 ** gctPOINTER * Memory
896 ** Pointer to a variable that will hold the allocated memory location.
898 gceSTATUS
899 gckOS_Allocate(
900 IN gckOS Os,
901 IN gctSIZE_T Bytes,
902 OUT gctPOINTER * Memory
905 gceSTATUS status;
907 gcmkHEADER_ARG("Os=0x%X Bytes=%lu", Os, Bytes);
909 /* Verify the arguments. */
910 gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
911 gcmkVERIFY_ARGUMENT(Bytes > 0);
912 gcmkVERIFY_ARGUMENT(Memory != gcvNULL);
914 /* Do we have a heap? */
915 if (Os->heap != gcvNULL)
917 /* Allocate from the heap. */
918 gcmkONERROR(gckHEAP_Allocate(Os->heap, Bytes, Memory));
920 else
922 gcmkONERROR(gckOS_AllocateMemory(Os, Bytes, Memory));
925 /* Success. */
926 gcmkFOOTER_ARG("*Memory=0x%X", *Memory);
927 return gcvSTATUS_OK;
929 OnError:
930 /* Return the status. */
931 gcmkFOOTER();
932 return status;
935 /*******************************************************************************
937 ** gckOS_Free
939 ** Free allocated memory.
941 ** INPUT:
943 ** gckOS Os
944 ** Pointer to an gckOS object.
946 ** gctPOINTER Memory
947 ** Pointer to memory allocation to free.
949 ** OUTPUT:
951 ** Nothing.
953 gceSTATUS
954 gckOS_Free(
955 IN gckOS Os,
956 IN gctPOINTER Memory
959 gceSTATUS status;
961 gcmkHEADER_ARG("Os=0x%X Memory=0x%X", Os, Memory);
963 /* Verify the arguments. */
964 gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
965 gcmkVERIFY_ARGUMENT(Memory != gcvNULL);
967 /* Do we have a heap? */
968 if (Os->heap != gcvNULL)
970 /* Free from the heap. */
971 gcmkONERROR(gckHEAP_Free(Os->heap, Memory));
973 else
975 gcmkONERROR(gckOS_FreeMemory(Os, Memory));
978 /* Success. */
979 gcmkFOOTER_NO();
980 return gcvSTATUS_OK;
982 OnError:
983 /* Return the status. */
984 gcmkFOOTER();
985 return status;
988 /*******************************************************************************
990 ** gckOS_AllocateMemory
992 ** Allocate memory wrapper.
994 ** INPUT:
996 ** gctSIZE_T Bytes
997 ** Number of bytes to allocate.
999 ** OUTPUT:
1001 ** gctPOINTER * Memory
1002 ** Pointer to a variable that will hold the allocated memory location.
1004 gceSTATUS
1005 gckOS_AllocateMemory(
1006 IN gckOS Os,
1007 IN gctSIZE_T Bytes,
1008 OUT gctPOINTER * Memory
1011 gctPOINTER memory;
1012 gceSTATUS status;
1014 gcmkHEADER_ARG("Os=0x%X Bytes=%lu", Os, Bytes);
1016 /* Verify the arguments. */
1017 gcmkVERIFY_ARGUMENT(Bytes > 0);
1018 gcmkVERIFY_ARGUMENT(Memory != gcvNULL);
1020 memory = (gctPOINTER) kmalloc(Bytes, GFP_KERNEL);
1022 if (memory == gcvNULL)
1024 /* Out of memory. */
1025 gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
1028 /* Return pointer to the memory allocation. */
1029 *Memory = memory;
1031 /* Success. */
1032 gcmkFOOTER_ARG("*Memory=0x%X", *Memory);
1033 return gcvSTATUS_OK;
1035 OnError:
1036 /* Return the status. */
1037 gcmkFOOTER();
1038 return status;
1041 /*******************************************************************************
1043 ** gckOS_FreeMemory
1045 ** Free allocated memory wrapper.
1047 ** INPUT:
1049 ** gctPOINTER Memory
1050 ** Pointer to memory allocation to free.
1052 ** OUTPUT:
1054 ** Nothing.
1056 gceSTATUS
1057 gckOS_FreeMemory(
1058 IN gckOS Os,
1059 IN gctPOINTER Memory
1062 gcmkHEADER_ARG("Memory=0x%X", Memory);
1064 /* Verify the arguments. */
1065 gcmkVERIFY_ARGUMENT(Memory != gcvNULL);
1067 /* Free the memory from the OS pool. */
1068 kfree(Memory);
1070 /* Success. */
1071 gcmkFOOTER_NO();
1072 return gcvSTATUS_OK;
1075 /*******************************************************************************
1077 ** gckOS_MapMemory
1079 ** Map physical memory into the current process.
1081 ** INPUT:
1083 ** gckOS Os
1084 ** Pointer to an gckOS object.
1086 ** gctPHYS_ADDR Physical
1087 ** Start of physical address memory.
1089 ** gctSIZE_T Bytes
1090 ** Number of bytes to map.
1092 ** OUTPUT:
1094 ** gctPOINTER * Memory
1095 ** Pointer to a variable that will hold the logical address of the
1096 ** mapped memory.
1098 gceSTATUS
1099 gckOS_MapMemory(
1100 IN gckOS Os,
1101 IN gctPHYS_ADDR Physical,
1102 IN gctSIZE_T Bytes,
1103 OUT gctPOINTER * Logical
1106 PLINUX_MDL_MAP mdlMap;
1107 PLINUX_MDL mdl = (PLINUX_MDL)Physical;
1109 gcmkHEADER_ARG("Os=0x%X Physical=0x%X Bytes=%lu", Os, Physical, Bytes);
1111 /* Verify the arguments. */
1112 gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
1113 gcmkVERIFY_ARGUMENT(Physical != 0);
1114 gcmkVERIFY_ARGUMENT(Bytes > 0);
1115 gcmkVERIFY_ARGUMENT(Logical != gcvNULL);
1117 MEMORY_LOCK(Os);
1119 mdlMap = FindMdlMap(mdl, _GetProcessID());
1121 if (mdlMap == gcvNULL)
1123 mdlMap = _CreateMdlMap(mdl, _GetProcessID());
1125 if (mdlMap == gcvNULL)
1127 MEMORY_UNLOCK(Os);
1129 gcmkFOOTER_ARG("status=%d", gcvSTATUS_OUT_OF_MEMORY);
1130 return gcvSTATUS_OUT_OF_MEMORY;
1134 if (mdlMap->vmaAddr == gcvNULL)
1136 down_write(&current->mm->mmap_sem);
1138 mdlMap->vmaAddr = (char *)do_mmap_pgoff(gcvNULL,
1140 mdl->numPages * PAGE_SIZE,
1141 PROT_READ | PROT_WRITE,
1142 MAP_SHARED,
1145 if (IS_ERR(mdlMap->vmaAddr))
1147 gcmkTRACE(
1148 gcvLEVEL_ERROR,
1149 "%s(%d): do_mmap_pgoff error",
1150 __FUNCTION__, __LINE__
1153 gcmkTRACE(
1154 gcvLEVEL_ERROR,
1155 "%s(%d): mdl->numPages: %d mdl->vmaAddr: 0x%X",
1156 __FUNCTION__, __LINE__,
1157 mdl->numPages,
1158 mdlMap->vmaAddr
1161 mdlMap->vmaAddr = gcvNULL;
1163 up_write(&current->mm->mmap_sem);
1165 MEMORY_UNLOCK(Os);
1167 gcmkFOOTER_ARG("status=%d", gcvSTATUS_OUT_OF_MEMORY);
1168 return gcvSTATUS_OUT_OF_MEMORY;
1171 mdlMap->vma = find_vma(current->mm, (unsigned long)mdlMap->vmaAddr);
1173 if (!mdlMap->vma)
1175 gcmkTRACE(
1176 gcvLEVEL_ERROR,
1177 "%s(%d): find_vma error.",
1178 __FUNCTION__, __LINE__
1181 mdlMap->vmaAddr = gcvNULL;
1183 up_write(&current->mm->mmap_sem);
1185 MEMORY_UNLOCK(Os);
1187 gcmkFOOTER_ARG("status=%d", gcvSTATUS_OUT_OF_RESOURCES);
1188 return gcvSTATUS_OUT_OF_RESOURCES;
1191 #ifndef NO_DMA_COHERENT
1192 if (dma_mmap_coherent(gcvNULL,
1193 mdlMap->vma,
1194 mdl->addr,
1195 mdl->dmaHandle,
1196 mdl->numPages * PAGE_SIZE) < 0)
1198 up_write(&current->mm->mmap_sem);
1200 gcmkTRACE(
1201 gcvLEVEL_ERROR,
1202 "%s(%d): dma_mmap_coherent error.",
1203 __FUNCTION__, __LINE__
1206 mdlMap->vmaAddr = gcvNULL;
1208 MEMORY_UNLOCK(Os);
1210 gcmkFOOTER_ARG("status=%d", gcvSTATUS_OUT_OF_RESOURCES);
1211 return gcvSTATUS_OUT_OF_RESOURCES;
1213 #else
1214 #if !gcdPAGED_MEMORY_CACHEABLE
1215 mdlMap->vma->vm_page_prot = pgprot_noncached(mdlMap->vma->vm_page_prot);
1216 mdlMap->vma->vm_flags |= VM_IO | VM_DONTCOPY | VM_DONTEXPAND | VM_RESERVED;
1217 # endif
1218 mdlMap->vma->vm_pgoff = 0;
1220 if (remap_pfn_range(mdlMap->vma,
1221 mdlMap->vma->vm_start,
1222 mdl->dmaHandle >> PAGE_SHIFT,
1223 mdl->numPages*PAGE_SIZE,
1224 mdlMap->vma->vm_page_prot) < 0)
1226 up_write(&current->mm->mmap_sem);
1228 gcmkTRACE(
1229 gcvLEVEL_ERROR,
1230 "%s(%d): remap_pfn_range error.",
1231 __FUNCTION__, __LINE__
1234 mdlMap->vmaAddr = gcvNULL;
1236 MEMORY_UNLOCK(Os);
1238 gcmkFOOTER_ARG("status=%d", gcvSTATUS_OUT_OF_RESOURCES);
1239 return gcvSTATUS_OUT_OF_RESOURCES;
1241 #endif
1243 up_write(&current->mm->mmap_sem);
1246 MEMORY_UNLOCK(Os);
1248 *Logical = mdlMap->vmaAddr;
1250 gcmkFOOTER_ARG("*Logical=0x%X", *Logical);
1251 return gcvSTATUS_OK;
1254 /*******************************************************************************
1256 ** gckOS_UnmapMemory
1258 ** Unmap physical memory out of the current process.
1260 ** INPUT:
1262 ** gckOS Os
1263 ** Pointer to an gckOS object.
1265 ** gctPHYS_ADDR Physical
1266 ** Start of physical address memory.
1268 ** gctSIZE_T Bytes
1269 ** Number of bytes to unmap.
1271 ** gctPOINTER Memory
1272 ** Pointer to a previously mapped memory region.
1274 ** OUTPUT:
1276 ** Nothing.
1278 gceSTATUS
1279 gckOS_UnmapMemory(
1280 IN gckOS Os,
1281 IN gctPHYS_ADDR Physical,
1282 IN gctSIZE_T Bytes,
1283 IN gctPOINTER Logical
1286 gcmkHEADER_ARG("Os=0x%X Physical=0x%X Bytes=%lu Logical=0x%X",
1287 Os, Physical, Bytes, Logical);
1289 /* Verify the arguments. */
1290 gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
1291 gcmkVERIFY_ARGUMENT(Physical != 0);
1292 gcmkVERIFY_ARGUMENT(Bytes > 0);
1293 gcmkVERIFY_ARGUMENT(Logical != gcvNULL);
1295 gckOS_UnmapMemoryEx(Os, Physical, Bytes, Logical, _GetProcessID());
1297 /* Success. */
1298 gcmkFOOTER_NO();
1299 return gcvSTATUS_OK;
1303 /*******************************************************************************
1305 ** gckOS_UnmapMemoryEx
1307 ** Unmap physical memory in the specified process.
1309 ** INPUT:
1311 ** gckOS Os
1312 ** Pointer to an gckOS object.
1314 ** gctPHYS_ADDR Physical
1315 ** Start of physical address memory.
1317 ** gctSIZE_T Bytes
1318 ** Number of bytes to unmap.
1320 ** gctPOINTER Memory
1321 ** Pointer to a previously mapped memory region.
1323 ** gctUINT32 PID
1324 ** Pid of the process that opened the device and mapped this memory.
1326 ** OUTPUT:
1328 ** Nothing.
1330 gceSTATUS
1331 gckOS_UnmapMemoryEx(
1332 IN gckOS Os,
1333 IN gctPHYS_ADDR Physical,
1334 IN gctSIZE_T Bytes,
1335 IN gctPOINTER Logical,
1336 IN gctUINT32 PID
1339 PLINUX_MDL_MAP mdlMap;
1340 PLINUX_MDL mdl = (PLINUX_MDL)Physical;
1341 struct task_struct * task;
1343 gcmkHEADER_ARG("Os=0x%X Physical=0x%X Bytes=%lu Logical=0x%X PID=%d",
1344 Os, Physical, Bytes, Logical, PID);
1346 /* Verify the arguments. */
1347 gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
1348 gcmkVERIFY_ARGUMENT(Physical != 0);
1349 gcmkVERIFY_ARGUMENT(Bytes > 0);
1350 gcmkVERIFY_ARGUMENT(Logical != gcvNULL);
1351 gcmkVERIFY_ARGUMENT(PID != 0);
1353 MEMORY_LOCK(Os);
1355 if (Logical)
1357 mdlMap = FindMdlMap(mdl, PID);
1359 if (mdlMap == gcvNULL || mdlMap->vmaAddr == gcvNULL)
1361 MEMORY_UNLOCK(Os);
1363 gcmkFOOTER_ARG("status=%d", gcvSTATUS_INVALID_ARGUMENT);
1364 return gcvSTATUS_INVALID_ARGUMENT;
1367 /* Get the current pointer for the task with stored pid. */
1368 task = FIND_TASK_BY_PID(mdlMap->pid);
1370 if (task != gcvNULL && task->mm != gcvNULL)
1372 down_write(&task->mm->mmap_sem);
1373 do_munmap(task->mm, (unsigned long)Logical, mdl->numPages*PAGE_SIZE);
1374 up_write(&task->mm->mmap_sem);
1376 else
1378 gcmkTRACE_ZONE(
1379 gcvLEVEL_INFO, gcvZONE_OS,
1380 "%s(%d): can't find the task with pid->%d. No unmapping",
1381 __FUNCTION__, __LINE__,
1382 mdlMap->pid
1386 gcmkVERIFY_OK(_DestroyMdlMap(mdl, mdlMap));
1389 MEMORY_UNLOCK(Os);
1391 /* Success. */
1392 gcmkFOOTER_NO();
1393 return gcvSTATUS_OK;
1396 /*******************************************************************************
1398 ** gckOS_AllocateNonPagedMemory
1400 ** Allocate a number of pages from non-paged memory.
1402 ** INPUT:
1404 ** gckOS Os
1405 ** Pointer to an gckOS object.
1407 ** gctBOOL InUserSpace
1408 ** gcvTRUE if the pages need to be mapped into user space.
1410 ** gctSIZE_T * Bytes
1411 ** Pointer to a variable that holds the number of bytes to allocate.
1413 ** OUTPUT:
1415 ** gctSIZE_T * Bytes
1416 ** Pointer to a variable that hold the number of bytes allocated.
1418 ** gctPHYS_ADDR * Physical
1419 ** Pointer to a variable that will hold the physical address of the
1420 ** allocation.
1422 ** gctPOINTER * Logical
1423 ** Pointer to a variable that will hold the logical address of the
1424 ** allocation.
1426 gceSTATUS
1427 gckOS_AllocateNonPagedMemory(
1428 IN gckOS Os,
1429 IN gctBOOL InUserSpace,
1430 IN OUT gctSIZE_T * Bytes,
1431 OUT gctPHYS_ADDR * Physical,
1432 OUT gctPOINTER * Logical
1435 gctSIZE_T bytes;
1436 gctINT numPages;
1437 PLINUX_MDL mdl = gcvNULL;
1438 PLINUX_MDL_MAP mdlMap = gcvNULL;
1439 gctSTRING addr;
1440 #ifdef NO_DMA_COHERENT
1441 struct page * page;
1442 long size, order;
1443 gctPOINTER vaddr;
1444 #endif
1445 gctBOOL locked = gcvFALSE;
1446 gceSTATUS status;
1448 gcmkHEADER_ARG("Os=0x%X InUserSpace=%d *Bytes=%lu",
1449 Os, InUserSpace, gcmOPT_VALUE(Bytes));
1451 /* Verify the arguments. */
1452 gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
1453 gcmkVERIFY_ARGUMENT(Bytes != gcvNULL);
1454 gcmkVERIFY_ARGUMENT(*Bytes > 0);
1455 gcmkVERIFY_ARGUMENT(Physical != gcvNULL);
1456 gcmkVERIFY_ARGUMENT(Logical != gcvNULL);
1458 /* Align number of bytes to page size. */
1459 bytes = gcmALIGN(*Bytes, PAGE_SIZE);
1461 /* Get total number of pages.. */
1462 numPages = GetPageCount(bytes, 0);
1464 /* Allocate mdl+vector structure */
1465 mdl = _CreateMdl(_GetProcessID());
1466 if (mdl == gcvNULL)
1468 gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
1471 mdl->pagedMem = 0;
1472 mdl->numPages = numPages;
1474 MEMORY_LOCK(Os);
1475 locked = gcvTRUE;
1477 #ifndef NO_DMA_COHERENT
1478 addr = dma_alloc_coherent(gcvNULL,
1479 mdl->numPages * PAGE_SIZE,
1480 &mdl->dmaHandle,
1481 GFP_KERNEL);
1482 #else
1483 size = mdl->numPages * PAGE_SIZE;
1484 order = get_order(size);
1485 page = alloc_pages(GFP_KERNEL, order);
1487 if (page == gcvNULL)
1489 gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
1492 vaddr = (gctPOINTER)page_address(page);
1494 #if gcdNONPAGED_MEMORY_CACHEABLE
1495 addr = vaddr;
1496 # elif gcdNONPAGED_MEMORY_BUFFERABLE
1497 addr = ioremap_wc(virt_to_phys(vaddr), size);
1498 # else
1499 addr = ioremap_nocache(virt_to_phys(vaddr), size);
1500 # endif
1502 mdl->dmaHandle = virt_to_phys(vaddr);
1503 mdl->kaddr = vaddr;
1505 /* Cache invalidate. */
1506 dma_sync_single_for_device(
1507 gcvNULL,
1508 page_to_phys(page),
1509 bytes,
1510 DMA_FROM_DEVICE);
1512 while (size > 0)
1514 SetPageReserved(virt_to_page(vaddr));
1516 vaddr += PAGE_SIZE;
1517 size -= PAGE_SIZE;
1519 #endif
1521 if (addr == gcvNULL)
1523 gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
1526 if ((Os->device->baseAddress & 0x80000000) != (mdl->dmaHandle & 0x80000000))
1528 mdl->dmaHandle = (mdl->dmaHandle & ~0x80000000)
1529 | (Os->device->baseAddress & 0x80000000);
1532 mdl->addr = addr;
1535 * We will not do any mapping from here.
1536 * Mapping will happen from mmap method.
1537 * mdl structure will be used.
1540 /* Return allocated memory. */
1541 *Bytes = bytes;
1542 *Physical = (gctPHYS_ADDR) mdl;
1544 if (InUserSpace)
1546 mdlMap = _CreateMdlMap(mdl, _GetProcessID());
1548 if (mdlMap == gcvNULL)
1550 gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
1553 /* Only after mmap this will be valid. */
1555 /* We need to map this to user space. */
1556 down_write(&current->mm->mmap_sem);
1558 mdlMap->vmaAddr = (gctSTRING) do_mmap_pgoff(gcvNULL,
1560 mdl->numPages * PAGE_SIZE,
1561 PROT_READ | PROT_WRITE,
1562 MAP_SHARED,
1565 if (IS_ERR(mdlMap->vmaAddr))
1567 gcmkTRACE_ZONE(
1568 gcvLEVEL_WARNING, gcvZONE_OS,
1569 "%s(%d): do_mmap_pgoff error",
1570 __FUNCTION__, __LINE__
1573 mdlMap->vmaAddr = gcvNULL;
1575 up_write(&current->mm->mmap_sem);
1577 gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
1580 mdlMap->vma = find_vma(current->mm, (unsigned long)mdlMap->vmaAddr);
1582 if (mdlMap->vma == gcvNULL)
1584 gcmkTRACE_ZONE(
1585 gcvLEVEL_WARNING, gcvZONE_OS,
1586 "%s(%d): find_vma error",
1587 __FUNCTION__, __LINE__
1590 up_write(&current->mm->mmap_sem);
1592 gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES);
1595 #ifndef NO_DMA_COHERENT
1596 if (dma_mmap_coherent(gcvNULL,
1597 mdlMap->vma,
1598 mdl->addr,
1599 mdl->dmaHandle,
1600 mdl->numPages * PAGE_SIZE) < 0)
1602 gcmkTRACE_ZONE(
1603 gcvLEVEL_WARNING, gcvZONE_OS,
1604 "%s(%d): dma_mmap_coherent error",
1605 __FUNCTION__, __LINE__
1608 up_write(&current->mm->mmap_sem);
1610 gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES);
1612 #else
1613 mdlMap->vma->vm_page_prot = pgprot_noncached(mdlMap->vma->vm_page_prot);
1614 mdlMap->vma->vm_flags |= VM_IO | VM_DONTCOPY | VM_DONTEXPAND | VM_RESERVED;
1615 mdlMap->vma->vm_pgoff = 0;
1617 if (remap_pfn_range(mdlMap->vma,
1618 mdlMap->vma->vm_start,
1619 mdl->dmaHandle >> PAGE_SHIFT,
1620 mdl->numPages * PAGE_SIZE,
1621 mdlMap->vma->vm_page_prot))
1623 gcmkTRACE_ZONE(
1624 gcvLEVEL_WARNING, gcvZONE_OS,
1625 "%s(%d): remap_pfn_range error",
1626 __FUNCTION__, __LINE__
1629 up_write(&current->mm->mmap_sem);
1631 gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES);
1633 #endif /* NO_DMA_COHERENT */
1635 up_write(&current->mm->mmap_sem);
1637 *Logical = mdlMap->vmaAddr;
1639 else
1641 *Logical = (gctPOINTER)mdl->addr;
1645 * Add this to a global list.
1646 * Will be used by get physical address
1647 * and mapuser pointer functions.
1650 if (!Os->mdlHead)
1652 /* Initialize the queue. */
1653 Os->mdlHead = Os->mdlTail = mdl;
1655 else
1657 /* Add to the tail. */
1658 mdl->prev = Os->mdlTail;
1659 Os->mdlTail->next = mdl;
1660 Os->mdlTail = mdl;
1663 MEMORY_UNLOCK(Os);
1665 /* Success. */
1666 gcmkFOOTER_ARG("*Bytes=%lu *Physical=0x%X *Logical=0x%X",
1667 *Bytes, *Physical, *Logical);
1668 return gcvSTATUS_OK;
1670 OnError:
1671 if (mdlMap != gcvNULL)
1673 /* Free LINUX_MDL_MAP. */
1674 gcmkVERIFY_OK(_DestroyMdlMap(mdl, mdlMap));
1677 if (mdl != gcvNULL)
1679 /* Free LINUX_MDL. */
1680 gcmkVERIFY_OK(_DestroyMdl(mdl));
1683 if (locked)
1685 /* Unlock memory. */
1686 MEMORY_UNLOCK(Os);
1689 /* Return the status. */
1690 gcmkFOOTER();
1691 return status;
1694 /*******************************************************************************
1696 ** gckOS_FreeNonPagedMemory
1698 ** Free previously allocated and mapped pages from non-paged memory.
1700 ** INPUT:
1702 ** gckOS Os
1703 ** Pointer to an gckOS object.
1705 ** gctSIZE_T Bytes
1706 ** Number of bytes allocated.
1708 ** gctPHYS_ADDR Physical
1709 ** Physical address of the allocated memory.
1711 ** gctPOINTER Logical
1712 ** Logical address of the allocated memory.
1714 ** OUTPUT:
1716 ** Nothing.
1718 gceSTATUS gckOS_FreeNonPagedMemory(
1719 IN gckOS Os,
1720 IN gctSIZE_T Bytes,
1721 IN gctPHYS_ADDR Physical,
1722 IN gctPOINTER Logical
1725 PLINUX_MDL mdl;
1726 PLINUX_MDL_MAP mdlMap;
1727 struct task_struct * task;
1728 #ifdef NO_DMA_COHERENT
1729 unsigned size;
1730 gctPOINTER vaddr;
1731 #endif /* NO_DMA_COHERENT */
1733 gcmkHEADER_ARG("Os=0x%X Bytes=%lu Physical=0x%X Logical=0x%X",
1734 Os, Bytes, Physical, Logical);
1736 /* Verify the arguments. */
1737 gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
1738 gcmkVERIFY_ARGUMENT(Bytes > 0);
1739 gcmkVERIFY_ARGUMENT(Physical != 0);
1740 gcmkVERIFY_ARGUMENT(Logical != gcvNULL);
1742 /* Convert physical address into a pointer to a MDL. */
1743 mdl = (PLINUX_MDL) Physical;
1745 MEMORY_LOCK(Os);
1747 #ifndef NO_DMA_COHERENT
1748 dma_free_coherent(gcvNULL,
1749 mdl->numPages * PAGE_SIZE,
1750 mdl->addr,
1751 mdl->dmaHandle);
1752 #else
1753 size = mdl->numPages * PAGE_SIZE;
1754 vaddr = mdl->kaddr;
1756 while (size > 0)
1758 ClearPageReserved(virt_to_page(vaddr));
1760 vaddr += PAGE_SIZE;
1761 size -= PAGE_SIZE;
1764 free_pages((unsigned long)mdl->kaddr, get_order(mdl->numPages * PAGE_SIZE));
1766 #if !gcdNONPAGED_MEMORY_CACHEABLE
1767 iounmap(mdl->addr);
1768 #endif
1770 #endif /* NO_DMA_COHERENT */
1772 mdlMap = mdl->maps;
1774 while (mdlMap != gcvNULL)
1776 if (mdlMap->vmaAddr != gcvNULL)
1778 /* Get the current pointer for the task with stored pid. */
1779 task = FIND_TASK_BY_PID(mdlMap->pid);
1781 if (task != gcvNULL && task->mm != gcvNULL)
1783 down_write(&task->mm->mmap_sem);
1785 if (do_munmap(task->mm,
1786 (unsigned long)mdlMap->vmaAddr,
1787 mdl->numPages * PAGE_SIZE) < 0)
1789 gcmkTRACE_ZONE(
1790 gcvLEVEL_WARNING, gcvZONE_OS,
1791 "%s(%d): do_munmap failed",
1792 __FUNCTION__, __LINE__
1796 up_write(&task->mm->mmap_sem);
1799 mdlMap->vmaAddr = gcvNULL;
1802 mdlMap = mdlMap->next;
1805 /* Remove the node from global list.. */
1806 if (mdl == Os->mdlHead)
1808 if ((Os->mdlHead = mdl->next) == gcvNULL)
1810 Os->mdlTail = gcvNULL;
1813 else
1815 mdl->prev->next = mdl->next;
1816 if (mdl == Os->mdlTail)
1818 Os->mdlTail = mdl->prev;
1820 else
1822 mdl->next->prev = mdl->prev;
1826 MEMORY_UNLOCK(Os);
1828 gcmkVERIFY_OK(_DestroyMdl(mdl));
1830 /* Success. */
1831 gcmkFOOTER_NO();
1832 return gcvSTATUS_OK;
1835 /*******************************************************************************
1837 ** gckOS_ReadRegister
1839 ** Read data from a register.
1841 ** INPUT:
1843 ** gckOS Os
1844 ** Pointer to an gckOS object.
1846 ** gctUINT32 Address
1847 ** Address of register.
1849 ** OUTPUT:
1851 ** gctUINT32 * Data
1852 ** Pointer to a variable that receives the data read from the register.
1854 gceSTATUS
1855 gckOS_ReadRegister(
1856 IN gckOS Os,
1857 IN gctUINT32 Address,
1858 OUT gctUINT32 * Data
1861 return gckOS_ReadRegisterEx(Os, gcvCORE_MAJOR, Address, Data);
1864 gceSTATUS
1865 gckOS_ReadRegisterEx(
1866 IN gckOS Os,
1867 IN gceCORE Core,
1868 IN gctUINT32 Address,
1869 OUT gctUINT32 * Data
1872 gcmkHEADER_ARG("Os=0x%X Core=%d Address=0x%X", Os, Core, Address);
1874 /* Verify the arguments. */
1875 gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
1876 gcmkVERIFY_ARGUMENT(Data != gcvNULL);
1878 *Data = readl((gctUINT8 *)Os->device->registerBases[Core] + Address);
1880 /* Success. */
1881 gcmkFOOTER_ARG("*Data=0x%08x", *Data);
1882 return gcvSTATUS_OK;
1885 /*******************************************************************************
1887 ** gckOS_WriteRegister
1889 ** Write data to a register.
1891 ** INPUT:
1893 ** gckOS Os
1894 ** Pointer to an gckOS object.
1896 ** gctUINT32 Address
1897 ** Address of register.
1899 ** gctUINT32 Data
1900 ** Data for register.
1902 ** OUTPUT:
1904 ** Nothing.
1906 gceSTATUS
1907 gckOS_WriteRegister(
1908 IN gckOS Os,
1909 IN gctUINT32 Address,
1910 IN gctUINT32 Data
1913 return gckOS_WriteRegisterEx(Os, gcvCORE_MAJOR, Address, Data);
1916 gceSTATUS
1917 gckOS_WriteRegisterEx(
1918 IN gckOS Os,
1919 IN gceCORE Core,
1920 IN gctUINT32 Address,
1921 IN gctUINT32 Data
1924 gcmkHEADER_ARG("Os=0x%X Core=%d Address=0x%X Data=0x%08x", Os, Core, Address, Data);
1926 writel(Data, (gctUINT8 *)Os->device->registerBases[Core] + Address);
1928 /* Success. */
1929 gcmkFOOTER_NO();
1930 return gcvSTATUS_OK;
1933 /*******************************************************************************
1935 ** gckOS_GetPageSize
1937 ** Get the system's page size.
1939 ** INPUT:
1941 ** gckOS Os
1942 ** Pointer to an gckOS object.
1944 ** OUTPUT:
1946 ** gctSIZE_T * PageSize
1947 ** Pointer to a variable that will receive the system's page size.
1949 gceSTATUS gckOS_GetPageSize(
1950 IN gckOS Os,
1951 OUT gctSIZE_T * PageSize
1954 gcmkHEADER_ARG("Os=0x%X", Os);
1956 /* Verify the arguments. */
1957 gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
1958 gcmkVERIFY_ARGUMENT(PageSize != gcvNULL);
1960 /* Return the page size. */
1961 *PageSize = (gctSIZE_T) PAGE_SIZE;
1963 /* Success. */
1964 gcmkFOOTER_ARG("*PageSize", *PageSize);
1965 return gcvSTATUS_OK;
1968 /*******************************************************************************
1970 ** gckOS_GetPhysicalAddress
1972 ** Get the physical system address of a corresponding virtual address.
1974 ** INPUT:
1976 ** gckOS Os
1977 ** Pointer to an gckOS object.
1979 ** gctPOINTER Logical
1980 ** Logical address.
1982 ** OUTPUT:
1984 ** gctUINT32 * Address
1985 ** Poinetr to a variable that receives the 32-bit physical adress.
1987 gceSTATUS
1988 gckOS_GetPhysicalAddress(
1989 IN gckOS Os,
1990 IN gctPOINTER Logical,
1991 OUT gctUINT32 * Address
1994 gceSTATUS status;
1995 gctUINT32 processID;
1997 gcmkHEADER_ARG("Os=0x%X Logical=0x%X", Os, Logical);
1999 /* Verify the arguments. */
2000 gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
2001 gcmkVERIFY_ARGUMENT(Address != gcvNULL);
2003 /* Get current process ID. */
2004 processID = _GetProcessID();
2006 /* Route through other function. */
2007 gcmkONERROR(
2008 gckOS_GetPhysicalAddressProcess(Os, Logical, processID, Address));
2010 /* Success. */
2011 gcmkFOOTER_ARG("*Address=0x%08x", *Address);
2012 return gcvSTATUS_OK;
2014 OnError:
2015 /* Return the status. */
2016 gcmkFOOTER();
2017 return status;
2020 #if gcdSECURE_USER
2021 static gceSTATUS
2022 gckOS_AddMapping(
2023 IN gckOS Os,
2024 IN gctUINT32 Physical,
2025 IN gctPOINTER Logical,
2026 IN gctSIZE_T Bytes
2029 gceSTATUS status;
2030 gcsUSER_MAPPING_PTR map;
2032 gcmkHEADER_ARG("Os=0x%X Physical=0x%X Logical=0x%X Bytes=%lu",
2033 Os, Physical, Logical, Bytes);
2035 gcmkONERROR(gckOS_Allocate(Os,
2036 gcmSIZEOF(gcsUSER_MAPPING),
2037 (gctPOINTER *) &map));
2039 map->next = Os->userMap;
2040 map->physical = Physical - Os->device->baseAddress;
2041 map->logical = Logical;
2042 map->bytes = Bytes;
2043 map->start = (gctINT8_PTR) Logical;
2044 map->end = map->start + Bytes;
2046 Os->userMap = map;
2048 gcmkFOOTER_NO();
2049 return gcvSTATUS_OK;
2051 OnError:
2052 gcmkFOOTER();
2053 return status;
2056 static gceSTATUS
2057 gckOS_RemoveMapping(
2058 IN gckOS Os,
2059 IN gctPOINTER Logical,
2060 IN gctSIZE_T Bytes
2063 gceSTATUS status;
2064 gcsUSER_MAPPING_PTR map, prev;
2066 gcmkHEADER_ARG("Os=0x%X Logical=0x%X Bytes=%lu", Os, Logical, Bytes);
2068 for (map = Os->userMap, prev = gcvNULL; map != gcvNULL; map = map->next)
2070 if ((map->logical == Logical)
2071 && (map->bytes == Bytes)
2074 break;
2077 prev = map;
2080 if (map == gcvNULL)
2082 gcmkONERROR(gcvSTATUS_INVALID_ADDRESS);
2085 if (prev == gcvNULL)
2087 Os->userMap = map->next;
2089 else
2091 prev->next = map->next;
2094 gcmkONERROR(gcmkOS_SAFE_FREE(Os, map));
2096 gcmkFOOTER_NO();
2097 return gcvSTATUS_OK;
2099 OnError:
2100 gcmkFOOTER();
2101 return status;
2103 #endif
2105 static gceSTATUS
2106 _ConvertLogical2Physical(
2107 IN gckOS Os,
2108 IN gctPOINTER Logical,
2109 IN gctUINT32 ProcessID,
2110 IN PLINUX_MDL Mdl,
2111 OUT gctUINT32_PTR Physical
2114 gctINT8_PTR base, vBase;
2115 gctUINT32 offset;
2116 PLINUX_MDL_MAP map;
2117 gcsUSER_MAPPING_PTR userMap;
2119 base = (Mdl == gcvNULL) ? gcvNULL : (gctINT8_PTR) Mdl->addr;
2121 /* Check for the logical address match. */
2122 if ((base != gcvNULL)
2123 && ((gctINT8_PTR) Logical >= base)
2124 && ((gctINT8_PTR) Logical < base + Mdl->numPages * PAGE_SIZE)
2127 offset = (gctINT8_PTR) Logical - base;
2129 if (Mdl->dmaHandle != 0)
2131 /* The memory was from coherent area. */
2132 *Physical = (gctUINT32) Mdl->dmaHandle + offset;
2134 else if (Mdl->pagedMem && !Mdl->contiguous)
2136 *Physical = page_to_phys(vmalloc_to_page(base + offset));
2138 else
2140 *Physical = gcmPTR2INT(virt_to_phys(base)) + offset;
2143 return gcvSTATUS_OK;
2146 /* Walk user maps. */
2147 for (userMap = Os->userMap; userMap != gcvNULL; userMap = userMap->next)
2149 if (((gctINT8_PTR) Logical >= userMap->start)
2150 && ((gctINT8_PTR) Logical < userMap->end)
2153 *Physical = userMap->physical
2154 + (gctUINT32) ((gctINT8_PTR) Logical - userMap->start);
2156 return gcvSTATUS_OK;
2160 if (ProcessID != Os->kernelProcessID)
2162 map = FindMdlMap(Mdl, (gctINT) ProcessID);
2163 vBase = (map == gcvNULL) ? gcvNULL : (gctINT8_PTR) map->vmaAddr;
2165 /* Is the given address within that range. */
2166 if ((vBase != gcvNULL)
2167 && ((gctINT8_PTR) Logical >= vBase)
2168 && ((gctINT8_PTR) Logical < vBase + Mdl->numPages * PAGE_SIZE)
2171 offset = (gctINT8_PTR) Logical - vBase;
2173 if (Mdl->dmaHandle != 0)
2175 /* The memory was from coherent area. */
2176 *Physical = (gctUINT32) Mdl->dmaHandle + offset;
2178 else if (Mdl->pagedMem && !Mdl->contiguous)
2180 *Physical = page_to_phys(vmalloc_to_page(base + offset));
2182 else
2184 /* Return the kernel virtual pointer based on this. */
2185 *Physical = gcmPTR2INT(virt_to_phys(base)) + offset;
2188 return gcvSTATUS_OK;
2192 /* Address not yet found. */
2193 return gcvSTATUS_INVALID_ADDRESS;
2196 /*******************************************************************************
2198 ** gckOS_GetPhysicalAddressProcess
2200 ** Get the physical system address of a corresponding virtual address for a
2201 ** given process.
2203 ** INPUT:
2205 ** gckOS Os
2206 ** Pointer to gckOS object.
2208 ** gctPOINTER Logical
2209 ** Logical address.
2211 ** gctUINT32 ProcessID
2212 ** Process ID.
2214 ** OUTPUT:
2216 ** gctUINT32 * Address
2217 ** Poinetr to a variable that receives the 32-bit physical adress.
2219 gceSTATUS
2220 gckOS_GetPhysicalAddressProcess(
2221 IN gckOS Os,
2222 IN gctPOINTER Logical,
2223 IN gctUINT32 ProcessID,
2224 OUT gctUINT32 * Address
2227 PLINUX_MDL mdl;
2228 gctINT8_PTR base;
2229 gceSTATUS status = gcvSTATUS_INVALID_ADDRESS;
2231 gcmkHEADER_ARG("Os=0x%X Logical=0x%X ProcessID=%d", Os, Logical, ProcessID);
2233 /* Verify the arguments. */
2234 gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
2235 gcmkVERIFY_ARGUMENT(Address != gcvNULL);
2237 MEMORY_LOCK(Os);
2239 /* First try the contiguous memory pool. */
2240 if (Os->device->contiguousMapped)
2242 base = (gctINT8_PTR) Os->device->contiguousBase;
2244 if (((gctINT8_PTR) Logical >= base)
2245 && ((gctINT8_PTR) Logical < base + Os->device->contiguousSize)
2248 /* Convert logical address into physical. */
2249 *Address = Os->device->contiguousVidMem->baseAddress
2250 + (gctINT8_PTR) Logical - base;
2251 status = gcvSTATUS_OK;
2254 else
2256 /* Try the contiguous memory pool. */
2257 mdl = (PLINUX_MDL) Os->device->contiguousPhysical;
2258 status = _ConvertLogical2Physical(Os,
2259 Logical,
2260 ProcessID,
2261 mdl,
2262 Address);
2265 if (gcmIS_ERROR(status))
2267 /* Walk all MDLs. */
2268 for (mdl = Os->mdlHead; mdl != gcvNULL; mdl = mdl->next)
2270 /* Try this MDL. */
2271 status = _ConvertLogical2Physical(Os,
2272 Logical,
2273 ProcessID,
2274 mdl,
2275 Address);
2276 if (gcmIS_SUCCESS(status))
2278 break;
2283 MEMORY_UNLOCK(Os);
2285 gcmkONERROR(status);
2287 if (Os->device->baseAddress != 0)
2289 /* Subtract base address to get a GPU physical address. */
2290 gcmkASSERT(*Address >= Os->device->baseAddress);
2291 *Address -= Os->device->baseAddress;
2294 /* Success. */
2295 gcmkFOOTER_ARG("*Address=0x%08x", *Address);
2296 return gcvSTATUS_OK;
2298 OnError:
2299 /* Return the status. */
2300 gcmkFOOTER();
2301 return status;
2304 /*******************************************************************************
2306 ** gckOS_MapPhysical
2308 ** Map a physical address into kernel space.
2310 ** INPUT:
2312 ** gckOS Os
2313 ** Pointer to an gckOS object.
2315 ** gctUINT32 Physical
2316 ** Physical address of the memory to map.
2318 ** gctSIZE_T Bytes
2319 ** Number of bytes to map.
2321 ** OUTPUT:
2323 ** gctPOINTER * Logical
2324 ** Pointer to a variable that receives the base address of the mapped
2325 ** memory.
2327 gceSTATUS
2328 gckOS_MapPhysical(
2329 IN gckOS Os,
2330 IN gctUINT32 Physical,
2331 IN gctSIZE_T Bytes,
2332 OUT gctPOINTER * Logical
2335 gctPOINTER logical;
2336 PLINUX_MDL mdl;
2337 gctUINT32 physical;
2339 gcmkHEADER_ARG("Os=0x%X Physical=0x%X Bytes=%lu", Os, Physical, Bytes);
2341 /* Verify the arguments. */
2342 gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
2343 gcmkVERIFY_ARGUMENT(Bytes > 0);
2344 gcmkVERIFY_ARGUMENT(Logical != gcvNULL);
2346 MEMORY_LOCK(Os);
2348 /* Compute true physical address (before subtraction of the baseAddress). */
2349 physical = Physical + Os->device->baseAddress;
2351 /* Go through our mapping to see if we know this physical address already. */
2352 mdl = Os->mdlHead;
2354 while (mdl != gcvNULL)
2356 if (mdl->dmaHandle != 0)
2358 if ((physical >= mdl->dmaHandle)
2359 && (physical < mdl->dmaHandle + mdl->numPages * PAGE_SIZE)
2362 *Logical = mdl->addr + (physical - mdl->dmaHandle);
2363 break;
2367 mdl = mdl->next;
2370 if (mdl == gcvNULL)
2372 /* Map memory as cached memory. */
2373 request_mem_region(physical, Bytes, "MapRegion");
2374 logical = (gctPOINTER) ioremap_nocache(physical, Bytes);
2376 if (logical == gcvNULL)
2378 gcmkTRACE_ZONE(
2379 gcvLEVEL_INFO, gcvZONE_OS,
2380 "%s(%d): Failed to ioremap",
2381 __FUNCTION__, __LINE__
2384 MEMORY_UNLOCK(Os);
2386 /* Out of resources. */
2387 gcmkFOOTER_ARG("status=%d", gcvSTATUS_OUT_OF_RESOURCES);
2388 return gcvSTATUS_OUT_OF_RESOURCES;
2391 /* Return pointer to mapped memory. */
2392 *Logical = logical;
2395 MEMORY_UNLOCK(Os);
2397 /* Success. */
2398 gcmkFOOTER_ARG("*Logical=0x%X", *Logical);
2399 return gcvSTATUS_OK;
2402 /*******************************************************************************
2404 ** gckOS_UnmapPhysical
2406 ** Unmap a previously mapped memory region from kernel memory.
2408 ** INPUT:
2410 ** gckOS Os
2411 ** Pointer to an gckOS object.
2413 ** gctPOINTER Logical
2414 ** Pointer to the base address of the memory to unmap.
2416 ** gctSIZE_T Bytes
2417 ** Number of bytes to unmap.
2419 ** OUTPUT:
2421 ** Nothing.
2423 gceSTATUS
2424 gckOS_UnmapPhysical(
2425 IN gckOS Os,
2426 IN gctPOINTER Logical,
2427 IN gctSIZE_T Bytes
2430 PLINUX_MDL mdl;
2432 gcmkHEADER_ARG("Os=0x%X Logical=0x%X Bytes=%lu", Os, Logical, Bytes);
2434 /* Verify the arguments. */
2435 gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
2436 gcmkVERIFY_ARGUMENT(Logical != gcvNULL);
2437 gcmkVERIFY_ARGUMENT(Bytes > 0);
2439 MEMORY_LOCK(Os);
2441 mdl = Os->mdlHead;
2443 while (mdl != gcvNULL)
2445 if (mdl->addr != gcvNULL)
2447 if (Logical >= (gctPOINTER)mdl->addr
2448 && Logical < (gctPOINTER)((gctSTRING)mdl->addr + mdl->numPages * PAGE_SIZE))
2450 break;
2454 mdl = mdl->next;
2457 if (mdl == gcvNULL)
2459 /* Unmap the memory. */
2460 iounmap(Logical);
2463 MEMORY_UNLOCK(Os);
2465 /* Success. */
2466 gcmkFOOTER_NO();
2467 return gcvSTATUS_OK;
2470 /*******************************************************************************
2472 ** gckOS_CreateMutex
2474 ** Create a new mutex.
2476 ** INPUT:
2478 ** gckOS Os
2479 ** Pointer to an gckOS object.
2481 ** OUTPUT:
2483 ** gctPOINTER * Mutex
2484 ** Pointer to a variable that will hold a pointer to the mutex.
2486 gceSTATUS
2487 gckOS_CreateMutex(
2488 IN gckOS Os,
2489 OUT gctPOINTER * Mutex
2492 gcmkHEADER_ARG("Os=0x%X", Os);
2494 /* Validate the arguments. */
2495 gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
2496 gcmkVERIFY_ARGUMENT(Mutex != gcvNULL);
2498 /* Allocate a FAST_MUTEX structure. */
2499 *Mutex = (gctPOINTER)kmalloc(sizeof(struct semaphore), GFP_KERNEL);
2501 if (*Mutex == gcvNULL)
2503 gcmkFOOTER_ARG("status=%d", gcvSTATUS_OUT_OF_MEMORY);
2504 return gcvSTATUS_OUT_OF_MEMORY;
2507 /* Initialize the semaphore.. Come up in unlocked state. */
2508 sema_init(*Mutex, 1);
2510 /* Return status. */
2511 gcmkFOOTER_ARG("*Mutex=0x%X", *Mutex);
2512 return gcvSTATUS_OK;
2515 /*******************************************************************************
2517 ** gckOS_DeleteMutex
2519 ** Delete a mutex.
2521 ** INPUT:
2523 ** gckOS Os
2524 ** Pointer to an gckOS object.
2526 ** gctPOINTER Mutex
2527 ** Pointer to the mute to be deleted.
2529 ** OUTPUT:
2531 ** Nothing.
2533 gceSTATUS
2534 gckOS_DeleteMutex(
2535 IN gckOS Os,
2536 IN gctPOINTER Mutex
2539 gcmkHEADER_ARG("Os=0x%X Mutex=0x%X", Os, Mutex);
2541 /* Validate the arguments. */
2542 gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
2543 gcmkVERIFY_ARGUMENT(Mutex != gcvNULL);
2545 /* Delete the fast mutex. */
2546 kfree(Mutex);
2548 gcmkFOOTER_NO();
2549 return gcvSTATUS_OK;
2552 /*******************************************************************************
2554 ** gckOS_AcquireMutex
2556 ** Acquire a mutex.
2558 ** INPUT:
2560 ** gckOS Os
2561 ** Pointer to an gckOS object.
2563 ** gctPOINTER Mutex
2564 ** Pointer to the mutex to be acquired.
2566 ** gctUINT32 Timeout
2567 ** Timeout value specified in milliseconds.
2568 ** Specify the value of gcvINFINITE to keep the thread suspended
2569 ** until the mutex has been acquired.
2571 ** OUTPUT:
2573 ** Nothing.
2575 gceSTATUS
2576 gckOS_AcquireMutex(
2577 IN gckOS Os,
2578 IN gctPOINTER Mutex,
2579 IN gctUINT32 Timeout
2582 #if gcdDETECT_TIMEOUT
2583 gctUINT32 timeout;
2584 #endif
2586 gcmkHEADER_ARG("Os=0x%X Mutex=0x%0x Timeout=%u", Os, Mutex, Timeout);
2588 /* Validate the arguments. */
2589 gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
2590 gcmkVERIFY_ARGUMENT(Mutex != gcvNULL);
2592 #if gcdDETECT_TIMEOUT
2593 timeout = 0;
2595 for (;;)
2597 /* Try to acquire the mutex. */
2598 if (!down_trylock((struct semaphore *) Mutex))
2600 /* Success. */
2601 gcmkFOOTER_NO();
2602 return gcvSTATUS_OK;
2605 /* Advance the timeout. */
2606 timeout += 1;
2608 if (Timeout == gcvINFINITE)
2610 if (timeout == gcdINFINITE_TIMEOUT)
2612 gctUINT32 dmaAddress1, dmaAddress2;
2613 gctUINT32 dmaState1, dmaState2;
2615 dmaState1 = dmaState2 =
2616 dmaAddress1 = dmaAddress2 = 0;
2618 /* Verify whether DMA is running. */
2619 gcmkVERIFY_OK(_VerifyDMA(
2620 Os, &dmaAddress1, &dmaAddress2, &dmaState1, &dmaState2
2623 #if gcdDETECT_DMA_ADDRESS
2624 /* Dump only if DMA appears stuck. */
2625 if (
2626 (dmaAddress1 == dmaAddress2)
2627 #if gcdDETECT_DMA_STATE
2628 && (dmaState1 == dmaState2)
2629 # endif
2631 # endif
2633 gcmkVERIFY_OK(_DumpGPUState(Os));
2635 gcmkPRINT(
2636 "%s(%d): mutex 0x%X; forced message flush.",
2637 __FUNCTION__, __LINE__, Mutex
2640 /* Flush the debug cache. */
2641 gcmkDEBUGFLUSH(dmaAddress2);
2644 timeout = 0;
2647 else
2649 /* Timedout? */
2650 if (timeout >= Timeout)
2652 break;
2656 /* Wait for 1 millisecond. */
2657 gcmkVERIFY_OK(gckOS_Delay(Os, 1));
2659 #else
2660 if (Timeout == gcvINFINITE)
2662 down((struct semaphore *) Mutex);
2664 /* Success. */
2665 gcmkFOOTER_NO();
2666 return gcvSTATUS_OK;
2669 for (;;)
2671 /* Try to acquire the mutex. */
2672 if (!down_trylock((struct semaphore *) Mutex))
2674 /* Success. */
2675 gcmkFOOTER_NO();
2676 return gcvSTATUS_OK;
2679 if (Timeout-- == 0)
2681 break;
2684 /* Wait for 1 millisecond. */
2685 gcmkVERIFY_OK(gckOS_Delay(Os, 1));
2687 #endif
2689 /* Timeout. */
2690 gcmkFOOTER_ARG("status=%d", gcvSTATUS_TIMEOUT);
2691 return gcvSTATUS_TIMEOUT;
2694 /*******************************************************************************
2696 ** gckOS_ReleaseMutex
2698 ** Release an acquired mutex.
2700 ** INPUT:
2702 ** gckOS Os
2703 ** Pointer to an gckOS object.
2705 ** gctPOINTER Mutex
2706 ** Pointer to the mutex to be released.
2708 ** OUTPUT:
2710 ** Nothing.
2712 gceSTATUS
2713 gckOS_ReleaseMutex(
2714 IN gckOS Os,
2715 IN gctPOINTER Mutex
2718 gcmkHEADER_ARG("Os=0x%X Mutex=0x%0x", Os, Mutex);
2720 /* Validate the arguments. */
2721 gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
2722 gcmkVERIFY_ARGUMENT(Mutex != gcvNULL);
2724 /* Release the fast mutex. */
2725 up((struct semaphore *) Mutex);
2727 /* Success. */
2728 gcmkFOOTER_NO();
2729 return gcvSTATUS_OK;
2732 /*******************************************************************************
2734 ** gckOS_AtomicExchange
2736 ** Atomically exchange a pair of 32-bit values.
2738 ** INPUT:
2740 ** gckOS Os
2741 ** Pointer to an gckOS object.
2743 ** IN OUT gctINT32_PTR Target
2744 ** Pointer to the 32-bit value to exchange.
2746 ** IN gctINT32 NewValue
2747 ** Specifies a new value for the 32-bit value pointed to by Target.
2749 ** OUT gctINT32_PTR OldValue
2750 ** The old value of the 32-bit value pointed to by Target.
2752 ** OUTPUT:
2754 ** Nothing.
2756 gceSTATUS
2757 gckOS_AtomicExchange(
2758 IN gckOS Os,
2759 IN OUT gctUINT32_PTR Target,
2760 IN gctUINT32 NewValue,
2761 OUT gctUINT32_PTR OldValue
2764 gcmkHEADER_ARG("Os=0x%X Target=0x%X NewValue=%u", Os, Target, NewValue);
2766 /* Verify the arguments. */
2767 gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
2769 /* Exchange the pair of 32-bit values. */
2770 *OldValue = (gctUINT32) atomic_xchg((atomic_t *) Target, (int) NewValue);
2772 /* Success. */
2773 gcmkFOOTER_ARG("*OldValue=%u", *OldValue);
2774 return gcvSTATUS_OK;
2777 /*******************************************************************************
2779 ** gckOS_AtomicExchangePtr
2781 ** Atomically exchange a pair of pointers.
2783 ** INPUT:
2785 ** gckOS Os
2786 ** Pointer to an gckOS object.
2788 ** IN OUT gctPOINTER * Target
2789 ** Pointer to the 32-bit value to exchange.
2791 ** IN gctPOINTER NewValue
2792 ** Specifies a new value for the pointer pointed to by Target.
2794 ** OUT gctPOINTER * OldValue
2795 ** The old value of the pointer pointed to by Target.
2797 ** OUTPUT:
2799 ** Nothing.
2801 gceSTATUS
2802 gckOS_AtomicExchangePtr(
2803 IN gckOS Os,
2804 IN OUT gctPOINTER * Target,
2805 IN gctPOINTER NewValue,
2806 OUT gctPOINTER * OldValue
2809 gcmkHEADER_ARG("Os=0x%X Target=0x%X NewValue=0x%X", Os, Target, NewValue);
2811 /* Verify the arguments. */
2812 gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
2814 /* Exchange the pair of pointers. */
2815 *OldValue = (gctPOINTER) atomic_xchg((atomic_t *) Target, (int) NewValue);
2817 /* Success. */
2818 gcmkFOOTER_ARG("*OldValue=0x%X", *OldValue);
2819 return gcvSTATUS_OK;
2822 /*******************************************************************************
2824 ** gckOS_AtomConstruct
2826 ** Create an atom.
2828 ** INPUT:
2830 ** gckOS Os
2831 ** Pointer to a gckOS object.
2833 ** OUTPUT:
2835 ** gctPOINTER * Atom
2836 ** Pointer to a variable receiving the constructed atom.
2838 gceSTATUS
2839 gckOS_AtomConstruct(
2840 IN gckOS Os,
2841 OUT gctPOINTER * Atom
2844 gceSTATUS status;
2846 gcmkHEADER_ARG("Os=0x%X", Os);
2848 /* Verify the arguments. */
2849 gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
2850 gcmkVERIFY_ARGUMENT(Atom != gcvNULL);
2852 /* Allocate the atom. */
2853 gcmkONERROR(gckOS_Allocate(Os, gcmSIZEOF(atomic_t), Atom));
2855 /* Initialize the atom. */
2856 atomic_set((atomic_t *) *Atom, 0);
2858 /* Success. */
2859 gcmkFOOTER_ARG("*Atom=0x%X", *Atom);
2860 return gcvSTATUS_OK;
2862 OnError:
2863 /* Return the status. */
2864 gcmkFOOTER();
2865 return status;
2868 /*******************************************************************************
2870 ** gckOS_AtomDestroy
2872 ** Destroy an atom.
2874 ** INPUT:
2876 ** gckOS Os
2877 ** Pointer to a gckOS object.
2879 ** gctPOINTER Atom
2880 ** Pointer to the atom to destroy.
2882 ** OUTPUT:
2884 ** Nothing.
2886 gceSTATUS
2887 gckOS_AtomDestroy(
2888 IN gckOS Os,
2889 OUT gctPOINTER Atom
2892 gceSTATUS status;
2894 gcmkHEADER_ARG("Os=0x%X Atom=0x%0x", Os, Atom);
2896 /* Verify the arguments. */
2897 gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
2898 gcmkVERIFY_ARGUMENT(Atom != gcvNULL);
2900 /* Free the atom. */
2901 gcmkONERROR(gcmkOS_SAFE_FREE(Os, Atom));
2903 /* Success. */
2904 gcmkFOOTER_NO();
2905 return gcvSTATUS_OK;
2907 OnError:
2908 /* Return the status. */
2909 gcmkFOOTER();
2910 return status;
2913 /*******************************************************************************
2915 ** gckOS_AtomGet
2917 ** Get the 32-bit value protected by an atom.
2919 ** INPUT:
2921 ** gckOS Os
2922 ** Pointer to a gckOS object.
2924 ** gctPOINTER Atom
2925 ** Pointer to the atom.
2927 ** OUTPUT:
2929 ** gctINT32_PTR Value
2930 ** Pointer to a variable the receives the value of the atom.
2932 gceSTATUS
2933 gckOS_AtomGet(
2934 IN gckOS Os,
2935 IN gctPOINTER Atom,
2936 OUT gctINT32_PTR Value
2939 gcmkHEADER_ARG("Os=0x%X Atom=0x%0x", Os, Atom);
2941 /* Verify the arguments. */
2942 gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
2943 gcmkVERIFY_ARGUMENT(Atom != gcvNULL);
2945 /* Return the current value of atom. */
2946 *Value = atomic_read((atomic_t *) Atom);
2948 /* Success. */
2949 gcmkFOOTER_ARG("*Value=%d", *Value);
2950 return gcvSTATUS_OK;
2953 /*******************************************************************************
2955 ** gckOS_AtomSet
2957 ** Set the 32-bit value protected by an atom.
2959 ** INPUT:
2961 ** gckOS Os
2962 ** Pointer to a gckOS object.
2964 ** gctPOINTER Atom
2965 ** Pointer to the atom.
2967 ** gctINT32 Value
2968 ** The value of the atom.
2970 ** OUTPUT:
2972 ** Nothing.
2974 gceSTATUS
2975 gckOS_AtomSet(
2976 IN gckOS Os,
2977 IN gctPOINTER Atom,
2978 IN gctINT32 Value
2981 gcmkHEADER_ARG("Os=0x%X Atom=0x%0x Value=%d", Os, Atom);
2983 /* Verify the arguments. */
2984 gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
2985 gcmkVERIFY_ARGUMENT(Atom != gcvNULL);
2987 /* Set the current value of atom. */
2988 atomic_set((atomic_t *) Atom, Value);
2990 /* Success. */
2991 gcmkFOOTER_NO();
2992 return gcvSTATUS_OK;
2995 /*******************************************************************************
2997 ** gckOS_AtomIncrement
2999 ** Atomically increment the 32-bit integer value inside an atom.
3001 ** INPUT:
3003 ** gckOS Os
3004 ** Pointer to a gckOS object.
3006 ** gctPOINTER Atom
3007 ** Pointer to the atom.
3009 ** OUTPUT:
3011 ** gctINT32_PTR Value
3012 ** Pointer to a variable that receives the original value of the atom.
3014 gceSTATUS
3015 gckOS_AtomIncrement(
3016 IN gckOS Os,
3017 IN gctPOINTER Atom,
3018 OUT gctINT32_PTR Value
3021 gcmkHEADER_ARG("Os=0x%X Atom=0x%0x", Os, Atom);
3023 /* Verify the arguments. */
3024 gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
3025 gcmkVERIFY_ARGUMENT(Atom != gcvNULL);
3027 /* Increment the atom. */
3028 *Value = atomic_inc_return((atomic_t *) Atom) - 1;
3030 /* Success. */
3031 gcmkFOOTER_ARG("*Value=%d", *Value);
3032 return gcvSTATUS_OK;
3035 /*******************************************************************************
3037 ** gckOS_AtomDecrement
3039 ** Atomically decrement the 32-bit integer value inside an atom.
3041 ** INPUT:
3043 ** gckOS Os
3044 ** Pointer to a gckOS object.
3046 ** gctPOINTER Atom
3047 ** Pointer to the atom.
3049 ** OUTPUT:
3051 ** gctINT32_PTR Value
3052 ** Pointer to a variable that receives the original value of the atom.
3054 gceSTATUS
3055 gckOS_AtomDecrement(
3056 IN gckOS Os,
3057 IN gctPOINTER Atom,
3058 OUT gctINT32_PTR Value
3061 gcmkHEADER_ARG("Os=0x%X Atom=0x%0x", Os, Atom);
3063 /* Verify the arguments. */
3064 gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
3065 gcmkVERIFY_ARGUMENT(Atom != gcvNULL);
3067 /* Decrement the atom. */
3068 *Value = atomic_dec_return((atomic_t *) Atom) + 1;
3070 /* Success. */
3071 gcmkFOOTER_ARG("*Value=%d", *Value);
3072 return gcvSTATUS_OK;
3075 /*******************************************************************************
3077 ** gckOS_Delay
3079 ** Delay execution of the current thread for a number of milliseconds.
3081 ** INPUT:
3083 ** gckOS Os
3084 ** Pointer to an gckOS object.
3086 ** gctUINT32 Delay
3087 ** Delay to sleep, specified in milliseconds.
3089 ** OUTPUT:
3091 ** Nothing.
3093 gceSTATUS
3094 gckOS_Delay(
3095 IN gckOS Os,
3096 IN gctUINT32 Delay
3099 struct timeval now;
3100 unsigned long jiffies;
3102 gcmkHEADER_ARG("Os=0x%X Delay=%u", Os, Delay);
3104 if (Delay > 0)
3106 /* Convert milliseconds into seconds and microseconds. */
3107 now.tv_sec = Delay / 1000;
3108 now.tv_usec = (Delay % 1000) * 1000;
3110 /* Convert timeval to jiffies. */
3111 jiffies = timeval_to_jiffies(&now);
3113 /* Schedule timeout. */
3114 schedule_timeout_interruptible(jiffies);
3117 /* Success. */
3118 gcmkFOOTER_NO();
3119 return gcvSTATUS_OK;
3122 /*******************************************************************************
3124 ** gckOS_GetTicks
3126 ** Get the number of milliseconds since the system started.
3128 ** INPUT:
3130 ** OUTPUT:
3132 ** gctUINT32_PTR Time
3133 ** Pointer to a variable to get time.
3136 gceSTATUS
3137 gckOS_GetTicks(
3138 OUT gctUINT32_PTR Time
3141 gcmkHEADER();
3143 *Time = jiffies * 1000 / HZ;
3145 gcmkFOOTER_NO();
3146 return gcvSTATUS_OK;
3149 /*******************************************************************************
3151 ** gckOS_TicksAfter
3153 ** Compare time values got from gckOS_GetTicks.
3155 ** INPUT:
3156 ** gctUINT32 Time1
3157 ** First time value to be compared.
3159 ** gctUINT32 Time2
3160 ** Second time value to be compared.
3162 ** OUTPUT:
3164 ** gctBOOL_PTR IsAfter
3165 ** Pointer to a variable to result.
3168 gceSTATUS
3169 gckOS_TicksAfter(
3170 IN gctUINT32 Time1,
3171 IN gctUINT32 Time2,
3172 OUT gctBOOL_PTR IsAfter
3175 gcmkHEADER();
3177 *IsAfter = time_after((unsigned long)Time1, (unsigned long)Time2);
3179 gcmkFOOTER_NO();
3180 return gcvSTATUS_OK;
3183 /*******************************************************************************
3185 ** gckOS_GetTime
3187 ** Get the number of microseconds since the system started.
3189 ** INPUT:
3191 ** OUTPUT:
3193 ** gctUINT64_PTR Time
3194 ** Pointer to a variable to get time.
3197 gceSTATUS
3198 gckOS_GetTime(
3199 OUT gctUINT64_PTR Time
3202 gcmkHEADER();
3204 *Time = 0;
3206 gcmkFOOTER_NO();
3207 return gcvSTATUS_OK;
3210 /*******************************************************************************
3212 ** gckOS_MemoryBarrier
3214 ** Make sure the CPU has executed everything up to this point and the data got
3215 ** written to the specified pointer.
3217 ** INPUT:
3219 ** gckOS Os
3220 ** Pointer to an gckOS object.
3222 ** gctPOINTER Address
3223 ** Address of memory that needs to be barriered.
3225 ** OUTPUT:
3227 ** Nothing.
3229 gceSTATUS
3230 gckOS_MemoryBarrier(
3231 IN gckOS Os,
3232 IN gctPOINTER Address
3235 gcmkHEADER_ARG("Os=0x%X Address=0x%X", Os, Address);
3237 /* Verify the arguments. */
3238 gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
3240 #if gcdNONPAGED_MEMORY_BUFFERABLE \
3241 && defined (CONFIG_ARM) \
3242 && (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,34))
3243 /* drain write buffer */
3244 dsb();
3246 /* drain outer cache's write buffer? */
3247 #else
3248 mb();
3249 #endif
3251 /* Success. */
3252 gcmkFOOTER_NO();
3253 return gcvSTATUS_OK;
3256 /*******************************************************************************
3258 ** gckOS_AllocatePagedMemory
3260 ** Allocate memory from the paged pool.
3262 ** INPUT:
3264 ** gckOS Os
3265 ** Pointer to an gckOS object.
3267 ** gctSIZE_T Bytes
3268 ** Number of bytes to allocate.
3270 ** OUTPUT:
3272 ** gctPHYS_ADDR * Physical
3273 ** Pointer to a variable that receives the physical address of the
3274 ** memory allocation.
3276 gceSTATUS
3277 gckOS_AllocatePagedMemory(
3278 IN gckOS Os,
3279 IN gctSIZE_T Bytes,
3280 OUT gctPHYS_ADDR * Physical
3283 gceSTATUS status;
3285 gcmkHEADER_ARG("Os=0x%X Bytes=%lu", Os, Bytes);
3287 /* Verify the arguments. */
3288 gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
3289 gcmkVERIFY_ARGUMENT(Bytes > 0);
3290 gcmkVERIFY_ARGUMENT(Physical != gcvNULL);
3292 /* Allocate the memory. */
3293 gcmkONERROR(gckOS_AllocatePagedMemoryEx(Os, gcvFALSE, Bytes, Physical));
3295 /* Success. */
3296 gcmkFOOTER_ARG("*Physical=0x%X", *Physical);
3297 return gcvSTATUS_OK;
3299 OnError:
3300 /* Return the status. */
3301 gcmkFOOTER();
3302 return status;
3305 /*******************************************************************************
3307 ** gckOS_AllocatePagedMemoryEx
3309 ** Allocate memory from the paged pool.
3311 ** INPUT:
3313 ** gckOS Os
3314 ** Pointer to an gckOS object.
3316 ** gctBOOL Contiguous
3317 ** Need contiguous memory or not.
3319 ** gctSIZE_T Bytes
3320 ** Number of bytes to allocate.
3322 ** OUTPUT:
3324 ** gctPHYS_ADDR * Physical
3325 ** Pointer to a variable that receives the physical address of the
3326 ** memory allocation.
3328 gceSTATUS
3329 gckOS_AllocatePagedMemoryEx(
3330 IN gckOS Os,
3331 IN gctBOOL Contiguous,
3332 IN gctSIZE_T Bytes,
3333 OUT gctPHYS_ADDR * Physical
3336 gctINT numPages;
3337 gctINT i;
3338 PLINUX_MDL mdl = gcvNULL;
3339 gctSTRING addr;
3340 gctSIZE_T bytes;
3341 gctBOOL locked = gcvFALSE;
3342 gceSTATUS status;
3344 gcmkHEADER_ARG("Os=0x%X Contiguous=%d Bytes=%lu", Os, Contiguous, Bytes);
3346 /* Verify the arguments. */
3347 gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
3348 gcmkVERIFY_ARGUMENT(Bytes > 0);
3349 gcmkVERIFY_ARGUMENT(Physical != gcvNULL);
3351 bytes = gcmALIGN(Bytes, PAGE_SIZE);
3353 numPages = GetPageCount(bytes, 0);
3355 MEMORY_LOCK(Os);
3356 locked = gcvTRUE;
3358 mdl = _CreateMdl(_GetProcessID());
3359 if (mdl == gcvNULL)
3361 gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
3364 if (Contiguous)
3366 /* Get free pages, and suppress warning (stack dump) from kernel when
3367 we run out of memory. */
3368 addr = (char *)__get_free_pages(GFP_KERNEL | __GFP_NOWARN, GetOrder(numPages));
3370 else
3372 addr = vmalloc(bytes);
3375 if (addr == gcvNULL)
3377 gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
3380 mdl->dmaHandle = 0;
3381 mdl->addr = addr;
3382 mdl->numPages = numPages;
3383 mdl->pagedMem = 1;
3384 mdl->contiguous = Contiguous;
3386 for (i = 0; i < mdl->numPages; i++)
3388 struct page *page;
3390 if (mdl->contiguous)
3392 page = virt_to_page(addr + i * PAGE_SIZE);
3394 else
3396 page = vmalloc_to_page(addr + i * PAGE_SIZE);
3399 SetPageReserved(page);
3400 flush_dcache_page(page);
3403 /* Return physical address. */
3404 *Physical = (gctPHYS_ADDR) mdl;
3407 * Add this to a global list.
3408 * Will be used by get physical address
3409 * and mapuser pointer functions.
3411 if (!Os->mdlHead)
3413 /* Initialize the queue. */
3414 Os->mdlHead = Os->mdlTail = mdl;
3416 else
3418 /* Add to tail. */
3419 mdl->prev = Os->mdlTail;
3420 Os->mdlTail->next = mdl;
3421 Os->mdlTail = mdl;
3424 MEMORY_UNLOCK(Os);
3426 /* Success. */
3427 gcmkFOOTER_ARG("*Physical=0x%X", *Physical);
3428 return gcvSTATUS_OK;
3430 OnError:
3431 if (mdl != gcvNULL)
3433 /* Free the memory. */
3434 _DestroyMdl(mdl);
3437 if (locked)
3439 /* Unlock the memory. */
3440 MEMORY_UNLOCK(Os);
3443 /* Return the status. */
3444 gcmkFOOTER();
3445 return status;
3448 /*******************************************************************************
3450 ** gckOS_FreePagedMemory
3452 ** Free memory allocated from the paged pool.
3454 ** INPUT:
3456 ** gckOS Os
3457 ** Pointer to an gckOS object.
3459 ** gctPHYS_ADDR Physical
3460 ** Physical address of the allocation.
3462 ** gctSIZE_T Bytes
3463 ** Number of bytes of the allocation.
3465 ** OUTPUT:
3467 ** Nothing.
3469 gceSTATUS
3470 gckOS_FreePagedMemory(
3471 IN gckOS Os,
3472 IN gctPHYS_ADDR Physical,
3473 IN gctSIZE_T Bytes
3476 PLINUX_MDL mdl = (PLINUX_MDL) Physical;
3477 gctSTRING addr;
3478 gctINT i;
3480 gcmkHEADER_ARG("Os=0x%X Physical=0x%X Bytes=%lu", Os, Physical, Bytes);
3482 /* Verify the arguments. */
3483 gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
3484 gcmkVERIFY_ARGUMENT(Physical != gcvNULL);
3485 gcmkVERIFY_ARGUMENT(Bytes > 0);
3487 addr = mdl->addr;
3489 MEMORY_LOCK(Os);
3491 for (i = 0; i < mdl->numPages; i++)
3493 if (mdl->contiguous)
3495 ClearPageReserved(virt_to_page((gctPOINTER)(((unsigned long)addr) + i * PAGE_SIZE)));
3497 else
3499 ClearPageReserved(vmalloc_to_page((gctPOINTER)(((unsigned long)addr) + i * PAGE_SIZE)));
3503 if (mdl->contiguous)
3505 free_pages((unsigned long)mdl->addr, GetOrder(mdl->numPages));
3507 else
3509 vfree(mdl->addr);
3512 /* Remove the node from global list. */
3513 if (mdl == Os->mdlHead)
3515 if ((Os->mdlHead = mdl->next) == gcvNULL)
3517 Os->mdlTail = gcvNULL;
3520 else
3522 mdl->prev->next = mdl->next;
3524 if (mdl == Os->mdlTail)
3526 Os->mdlTail = mdl->prev;
3528 else
3530 mdl->next->prev = mdl->prev;
3534 MEMORY_UNLOCK(Os);
3536 /* Free the structure... */
3537 gcmkVERIFY_OK(_DestroyMdl(mdl));
3539 /* Success. */
3540 gcmkFOOTER_NO();
3541 return gcvSTATUS_OK;
3544 /*******************************************************************************
3546 ** gckOS_LockPages
3548 ** Lock memory allocated from the paged pool.
3550 ** INPUT:
3552 ** gckOS Os
3553 ** Pointer to an gckOS object.
3555 ** gctPHYS_ADDR Physical
3556 ** Physical address of the allocation.
3558 ** gctSIZE_T Bytes
3559 ** Number of bytes of the allocation.
3561 ** gctBOOL Cacheable
3562 ** Cache mode of mapping.
3564 ** OUTPUT:
3566 ** gctPOINTER * Logical
3567 ** Pointer to a variable that receives the address of the mapped
3568 ** memory.
3570 ** gctSIZE_T * PageCount
3571 ** Pointer to a variable that receives the number of pages required for
3572 ** the page table according to the GPU page size.
3574 gceSTATUS
3575 gckOS_LockPages(
3576 IN gckOS Os,
3577 IN gctPHYS_ADDR Physical,
3578 IN gctSIZE_T Bytes,
3579 IN gctBOOL Cacheable,
3580 OUT gctPOINTER * Logical,
3581 OUT gctSIZE_T * PageCount
3584 PLINUX_MDL mdl;
3585 PLINUX_MDL_MAP mdlMap;
3586 gctSTRING addr;
3587 unsigned long start;
3588 unsigned long pfn;
3589 gctINT i;
3591 gcmkHEADER_ARG("Os=0x%X Physical=0x%X Bytes=%lu", Os, Physical, Logical);
3593 /* Verify the arguments. */
3594 gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
3595 gcmkVERIFY_ARGUMENT(Physical != gcvNULL);
3596 gcmkVERIFY_ARGUMENT(Logical != gcvNULL);
3597 gcmkVERIFY_ARGUMENT(PageCount != gcvNULL);
3599 mdl = (PLINUX_MDL) Physical;
3601 MEMORY_LOCK(Os);
3603 mdlMap = FindMdlMap(mdl, _GetProcessID());
3605 if (mdlMap == gcvNULL)
3607 mdlMap = _CreateMdlMap(mdl, _GetProcessID());
3609 if (mdlMap == gcvNULL)
3611 MEMORY_UNLOCK(Os);
3613 gcmkFOOTER_ARG("*status=%d", gcvSTATUS_OUT_OF_MEMORY);
3614 return gcvSTATUS_OUT_OF_MEMORY;
3618 if (mdlMap->vmaAddr == gcvNULL)
3620 down_write(&current->mm->mmap_sem);
3622 mdlMap->vmaAddr = (gctSTRING)do_mmap_pgoff(gcvNULL,
3624 mdl->numPages * PAGE_SIZE,
3625 PROT_READ | PROT_WRITE,
3626 MAP_SHARED,
3629 gcmkTRACE_ZONE(
3630 gcvLEVEL_INFO, gcvZONE_OS,
3631 "%s(%d): vmaAddr->0x%X for phys_addr->0x%X",
3632 __FUNCTION__, __LINE__,
3633 (gctUINT32) mdlMap->vmaAddr,
3634 (gctUINT32) mdl
3637 if (IS_ERR(mdlMap->vmaAddr))
3639 up_write(&current->mm->mmap_sem);
3641 gcmkTRACE_ZONE(
3642 gcvLEVEL_INFO, gcvZONE_OS,
3643 "%s(%d): do_mmap_pgoff error",
3644 __FUNCTION__, __LINE__
3647 mdlMap->vmaAddr = gcvNULL;
3649 MEMORY_UNLOCK(Os);
3651 gcmkFOOTER_ARG("*status=%d", gcvSTATUS_OUT_OF_MEMORY);
3652 return gcvSTATUS_OUT_OF_MEMORY;
3655 mdlMap->vma = find_vma(current->mm, (unsigned long)mdlMap->vmaAddr);
3657 if (mdlMap->vma == gcvNULL)
3659 up_write(&current->mm->mmap_sem);
3661 gcmkTRACE_ZONE(
3662 gcvLEVEL_INFO, gcvZONE_OS,
3663 "%s(%d): find_vma error",
3664 __FUNCTION__, __LINE__
3667 mdlMap->vmaAddr = gcvNULL;
3669 MEMORY_UNLOCK(Os);
3671 gcmkFOOTER_ARG("*status=%d", gcvSTATUS_OUT_OF_RESOURCES);
3672 return gcvSTATUS_OUT_OF_RESOURCES;
3675 mdlMap->vma->vm_flags |= VM_RESERVED;
3676 #if !gcdPAGED_MEMORY_CACHEABLE
3677 if (Cacheable == gcvFALSE)
3679 /* Make this mapping non-cached. */
3680 mdlMap->vma->vm_page_prot = pgprot_noncached(mdlMap->vma->vm_page_prot);
3682 #endif
3683 addr = mdl->addr;
3685 /* Now map all the vmalloc pages to this user address. */
3686 if (mdl->contiguous)
3688 /* map kernel memory to user space.. */
3689 if (remap_pfn_range(mdlMap->vma,
3690 mdlMap->vma->vm_start,
3691 virt_to_phys((gctPOINTER)mdl->addr) >> PAGE_SHIFT,
3692 mdlMap->vma->vm_end - mdlMap->vma->vm_start,
3693 mdlMap->vma->vm_page_prot) < 0)
3695 up_write(&current->mm->mmap_sem);
3697 gcmkTRACE_ZONE(
3698 gcvLEVEL_INFO, gcvZONE_OS,
3699 "%s(%d): unable to mmap ret",
3700 __FUNCTION__, __LINE__
3703 mdlMap->vmaAddr = gcvNULL;
3705 MEMORY_UNLOCK(Os);
3707 gcmkFOOTER_ARG("*status=%d", gcvSTATUS_OUT_OF_MEMORY);
3708 return gcvSTATUS_OUT_OF_MEMORY;
3711 else
3713 start = mdlMap->vma->vm_start;
3715 for (i = 0; i < mdl->numPages; i++)
3717 pfn = vmalloc_to_pfn(addr);
3719 if (remap_pfn_range(mdlMap->vma,
3720 start,
3721 pfn,
3722 PAGE_SIZE,
3723 mdlMap->vma->vm_page_prot) < 0)
3725 up_write(&current->mm->mmap_sem);
3727 gcmkTRACE_ZONE(
3728 gcvLEVEL_INFO, gcvZONE_OS,
3729 "%s(%d): gctPHYS_ADDR->0x%X Logical->0x%X Unable to map addr->0x%X to start->0x%X",
3730 __FUNCTION__, __LINE__,
3731 (gctUINT32) Physical,
3732 (gctUINT32) *Logical,
3733 (gctUINT32) addr,
3734 (gctUINT32) start
3737 mdlMap->vmaAddr = gcvNULL;
3739 MEMORY_UNLOCK(Os);
3741 gcmkFOOTER_ARG("*status=%d", gcvSTATUS_OUT_OF_MEMORY);
3742 return gcvSTATUS_OUT_OF_MEMORY;
3745 start += PAGE_SIZE;
3746 addr += PAGE_SIZE;
3750 up_write(&current->mm->mmap_sem);
3752 else
3754 /* mdlMap->vmaAddr != gcvNULL means current process has already locked this node. */
3755 MEMORY_UNLOCK(Os);
3757 gcmkFOOTER_ARG("*status=%d, mdlMap->vmaAddr=%x", gcvSTATUS_MEMORY_LOCKED, mdlMap->vmaAddr);
3758 return gcvSTATUS_MEMORY_LOCKED;
3761 /* Convert pointer to MDL. */
3762 *Logical = mdlMap->vmaAddr;
3764 /* Return the page number according to the GPU page size. */
3765 gcmkASSERT((PAGE_SIZE % 4096) == 0);
3766 gcmkASSERT((PAGE_SIZE / 4096) >= 1);
3768 *PageCount = mdl->numPages * (PAGE_SIZE / 4096);
3770 MEMORY_UNLOCK(Os);
3772 /* Success. */
3773 gcmkFOOTER_ARG("*Logical=0x%X *PageCount=%lu", *Logical, *PageCount);
3774 return gcvSTATUS_OK;
3777 /*******************************************************************************
3779 ** gckOS_MapPages
3781 ** Map paged memory into a page table.
3783 ** INPUT:
3785 ** gckOS Os
3786 ** Pointer to an gckOS object.
3788 ** gctPHYS_ADDR Physical
3789 ** Physical address of the allocation.
3791 ** gctSIZE_T PageCount
3792 ** Number of pages required for the physical address.
3794 ** gctPOINTER PageTable
3795 ** Pointer to the page table to fill in.
3797 ** OUTPUT:
3799 ** Nothing.
3801 gceSTATUS
3802 gckOS_MapPages(
3803 IN gckOS Os,
3804 IN gctPHYS_ADDR Physical,
3805 IN gctSIZE_T PageCount,
3806 IN gctPOINTER PageTable
3809 return gckOS_MapPagesEx(Os,
3810 gcvCORE_MAJOR,
3811 Physical,
3812 PageCount,
3813 PageTable);
3816 gceSTATUS
3817 gckOS_MapPagesEx(
3818 IN gckOS Os,
3819 IN gceCORE Core,
3820 IN gctPHYS_ADDR Physical,
3821 IN gctSIZE_T PageCount,
3822 IN gctPOINTER PageTable
3825 gceSTATUS status = gcvSTATUS_OK;
3826 PLINUX_MDL mdl;
3827 gctUINT32* table;
3828 gctSTRING addr;
3829 gctUINT32 bytes;
3830 gckMMU mmu;
3831 PLINUX_MDL mmuMdl;
3832 gctPHYS_ADDR pageTablePhysical;
3834 gcmkHEADER_ARG("Os=0x%X Core=%d Physical=0x%X PageCount=%u PageTable=0x%X",
3835 Os, Core, Physical, PageCount, PageTable);
3837 /* Verify the arguments. */
3838 gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
3839 gcmkVERIFY_ARGUMENT(Physical != gcvNULL);
3840 gcmkVERIFY_ARGUMENT(PageCount > 0);
3841 gcmkVERIFY_ARGUMENT(PageTable != gcvNULL);
3843 /* Convert pointer to MDL. */
3844 mdl = (PLINUX_MDL)Physical;
3846 gcmkTRACE_ZONE(
3847 gcvLEVEL_INFO, gcvZONE_OS,
3848 "%s(%d): Physical->0x%X PageCount->0x%X PagedMemory->?%d",
3849 __FUNCTION__, __LINE__,
3850 (gctUINT32) Physical,
3851 (gctUINT32) PageCount,
3852 mdl->pagedMem
3855 MEMORY_LOCK(Os);
3857 table = (gctUINT32 *)PageTable;
3858 bytes = PageCount * sizeof(*table);
3859 mmu = Os->device->kernels[Core]->mmu;
3860 mmuMdl = (PLINUX_MDL)mmu->pageTablePhysical;
3862 /* Get all the physical addresses and store them in the page table. */
3864 addr = mdl->addr;
3866 if (mdl->pagedMem)
3868 /* Try to get the user pages so DMA can happen. */
3869 while (PageCount-- > 0)
3871 #if gcdENABLE_VG
3872 if (Core == gcvCORE_VG)
3874 if (mdl->contiguous)
3876 gcmkONERROR(
3877 gckVGMMU_SetPage(Os->device->kernels[Core]->vg->mmu,
3878 virt_to_phys(addr),
3879 table));
3881 else
3883 gcmkONERROR(
3884 gckVGMMU_SetPage(Os->device->kernels[Core]->vg->mmu,
3885 page_to_phys(vmalloc_to_page(addr)),
3886 table));
3889 else
3890 #endif
3892 if (mdl->contiguous)
3894 gcmkONERROR(
3895 gckMMU_SetPage(Os->device->kernels[Core]->mmu,
3896 virt_to_phys(addr),
3897 table));
3899 else
3901 gcmkONERROR(
3902 gckMMU_SetPage(Os->device->kernels[Core]->mmu,
3903 page_to_phys(vmalloc_to_page(addr)),
3904 table));
3908 table++;
3909 addr += 4096;
3912 else
3914 gcmkTRACE_ZONE(
3915 gcvLEVEL_INFO, gcvZONE_OS,
3916 "%s(%d): we should not get this call for Non Paged Memory!",
3917 __FUNCTION__, __LINE__
3920 while (PageCount-- > 0)
3922 #if gcdENABLE_VG
3923 if (Core == gcvCORE_VG)
3925 gcmkONERROR(
3926 gckVGMMU_SetPage(Os->device->kernels[Core]->vg->mmu,
3927 (gctUINT32)virt_to_phys(addr),
3928 table));
3930 else
3931 #endif
3933 gcmkONERROR(
3934 gckMMU_SetPage(Os->device->kernels[Core]->mmu,
3935 (gctUINT32)virt_to_phys(addr),
3936 table));
3938 table++;
3939 addr += 4096;
3943 /* Get physical address of pageTable */
3944 pageTablePhysical = (gctPHYS_ADDR)(mmuMdl->dmaHandle +
3945 ((gctUINT32 *)PageTable - mmu->pageTableLogical));
3947 #if gcdNONPAGED_MEMORY_CACHEABLE
3948 /* Flush the mmu page table cache. */
3949 gcmkONERROR(gckOS_CacheClean(
3951 _GetProcessID(),
3952 gcvNULL,
3953 pageTablePhysical,
3954 PageTable,
3955 bytes
3957 #endif
3959 OnError:
3961 MEMORY_UNLOCK(Os);
3963 /* Return the status. */
3964 gcmkFOOTER();
3965 return status;
3968 /*******************************************************************************
3970 ** gckOS_UnlockPages
3972 ** Unlock memory allocated from the paged pool.
3974 ** INPUT:
3976 ** gckOS Os
3977 ** Pointer to an gckOS object.
3979 ** gctPHYS_ADDR Physical
3980 ** Physical address of the allocation.
3982 ** gctSIZE_T Bytes
3983 ** Number of bytes of the allocation.
3985 ** gctPOINTER Logical
3986 ** Address of the mapped memory.
3988 ** OUTPUT:
3990 ** Nothing.
3992 gceSTATUS
3993 gckOS_UnlockPages(
3994 IN gckOS Os,
3995 IN gctPHYS_ADDR Physical,
3996 IN gctSIZE_T Bytes,
3997 IN gctPOINTER Logical
4000 PLINUX_MDL_MAP mdlMap;
4001 PLINUX_MDL mdl = (PLINUX_MDL)Physical;
4002 struct task_struct * task;
4004 gcmkHEADER_ARG("Os=0x%X Physical=0x%X Bytes=%u Logical=0x%X",
4005 Os, Physical, Bytes, Logical);
4007 /* Verify the arguments. */
4008 gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
4009 gcmkVERIFY_ARGUMENT(Physical != gcvNULL);
4010 gcmkVERIFY_ARGUMENT(Logical != gcvNULL);
4012 /* Make sure there is already a mapping...*/
4013 gcmkVERIFY_ARGUMENT(mdl->addr != gcvNULL);
4015 MEMORY_LOCK(Os);
4017 mdlMap = mdl->maps;
4019 while (mdlMap != gcvNULL)
4021 if ((mdlMap->vmaAddr != gcvNULL) && (_GetProcessID() == mdlMap->pid))
4023 /* Get the current pointer for the task with stored pid. */
4024 task = FIND_TASK_BY_PID(mdlMap->pid);
4026 if (task != gcvNULL && task->mm != gcvNULL)
4028 down_write(&task->mm->mmap_sem);
4029 do_munmap(task->mm, (unsigned long)mdlMap->vmaAddr, mdl->numPages * PAGE_SIZE);
4030 up_write(&task->mm->mmap_sem);
4033 mdlMap->vmaAddr = gcvNULL;
4036 mdlMap = mdlMap->next;
4039 MEMORY_UNLOCK(Os);
4041 /* Success. */
4042 gcmkFOOTER_NO();
4043 return gcvSTATUS_OK;
4047 /*******************************************************************************
4049 ** gckOS_AllocateContiguous
4051 ** Allocate memory from the contiguous pool.
4053 ** INPUT:
4055 ** gckOS Os
4056 ** Pointer to an gckOS object.
4058 ** gctBOOL InUserSpace
4059 ** gcvTRUE if the pages need to be mapped into user space.
4061 ** gctSIZE_T * Bytes
4062 ** Pointer to the number of bytes to allocate.
4064 ** OUTPUT:
4066 ** gctSIZE_T * Bytes
4067 ** Pointer to a variable that receives the number of bytes allocated.
4069 ** gctPHYS_ADDR * Physical
4070 ** Pointer to a variable that receives the physical address of the
4071 ** memory allocation.
4073 ** gctPOINTER * Logical
4074 ** Pointer to a variable that receives the logical address of the
4075 ** memory allocation.
4077 gceSTATUS
4078 gckOS_AllocateContiguous(
4079 IN gckOS Os,
4080 IN gctBOOL InUserSpace,
4081 IN OUT gctSIZE_T * Bytes,
4082 OUT gctPHYS_ADDR * Physical,
4083 OUT gctPOINTER * Logical
4086 gceSTATUS status;
4088 gcmkHEADER_ARG("Os=0x%X InUserSpace=%d *Bytes=%lu",
4089 Os, InUserSpace, gcmOPT_VALUE(Bytes));
4091 /* Verify the arguments. */
4092 gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
4093 gcmkVERIFY_ARGUMENT(Bytes != gcvNULL);
4094 gcmkVERIFY_ARGUMENT(*Bytes > 0);
4095 gcmkVERIFY_ARGUMENT(Physical != gcvNULL);
4096 gcmkVERIFY_ARGUMENT(Logical != gcvNULL);
4098 /* Same as non-paged memory for now. */
4099 gcmkONERROR(gckOS_AllocateNonPagedMemory(Os,
4100 InUserSpace,
4101 Bytes,
4102 Physical,
4103 Logical));
4105 /* Success. */
4106 gcmkFOOTER_ARG("*Bytes=%lu *Physical=0x%X *Logical=0x%X",
4107 *Bytes, *Physical, *Logical);
4108 return gcvSTATUS_OK;
4110 OnError:
4111 /* Return the status. */
4112 gcmkFOOTER();
4113 return status;
4116 /*******************************************************************************
4118 ** gckOS_FreeContiguous
4120 ** Free memory allocated from the contiguous pool.
4122 ** INPUT:
4124 ** gckOS Os
4125 ** Pointer to an gckOS object.
4127 ** gctPHYS_ADDR Physical
4128 ** Physical address of the allocation.
4130 ** gctPOINTER Logical
4131 ** Logicval address of the allocation.
4133 ** gctSIZE_T Bytes
4134 ** Number of bytes of the allocation.
4136 ** OUTPUT:
4138 ** Nothing.
4140 gceSTATUS
4141 gckOS_FreeContiguous(
4142 IN gckOS Os,
4143 IN gctPHYS_ADDR Physical,
4144 IN gctPOINTER Logical,
4145 IN gctSIZE_T Bytes
4148 gceSTATUS status;
4150 gcmkHEADER_ARG("Os=0x%X Physical=0x%X Logical=0x%X Bytes=%lu",
4151 Os, Physical, Logical, Bytes);
4153 /* Verify the arguments. */
4154 gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
4155 gcmkVERIFY_ARGUMENT(Physical != gcvNULL);
4156 gcmkVERIFY_ARGUMENT(Logical != gcvNULL);
4157 gcmkVERIFY_ARGUMENT(Bytes > 0);
4159 /* Same of non-paged memory for now. */
4160 gcmkONERROR(gckOS_FreeNonPagedMemory(Os, Bytes, Physical, Logical));
4162 /* Success. */
4163 gcmkFOOTER_NO();
4164 return gcvSTATUS_OK;
4166 OnError:
4167 /* Return the status. */
4168 gcmkFOOTER();
4169 return status;
4172 #if gcdENABLE_VG
4173 /******************************************************************************
4175 ** gckOS_GetKernelLogical
4177 ** Return the kernel logical pointer that corresponods to the specified
4178 ** hardware address.
4180 ** INPUT:
4182 ** gckOS Os
4183 ** Pointer to an gckOS object.
4185 ** gctUINT32 Address
4186 ** Hardware physical address.
4188 ** OUTPUT:
4190 ** gctPOINTER * KernelPointer
4191 ** Pointer to a variable receiving the pointer in kernel address space.
4193 gceSTATUS
4194 gckOS_GetKernelLogical(
4195 IN gckOS Os,
4196 IN gctUINT32 Address,
4197 OUT gctPOINTER * KernelPointer
4200 return gckOS_GetKernelLogicalEx(Os, gcvCORE_MAJOR, Address, KernelPointer);
4203 gceSTATUS
4204 gckOS_GetKernelLogicalEx(
4205 IN gckOS Os,
4206 IN gceCORE Core,
4207 IN gctUINT32 Address,
4208 OUT gctPOINTER * KernelPointer
4211 gceSTATUS status;
4213 gcmkHEADER_ARG("Os=0x%X Core=%d Address=0x%08x", Os, Core, Address);
4217 gckGALDEVICE device;
4218 gckKERNEL kernel;
4219 gcePOOL pool;
4220 gctUINT32 offset;
4221 gctPOINTER logical;
4223 /* Extract the pointer to the gckGALDEVICE class. */
4224 device = (gckGALDEVICE) Os->device;
4226 /* Kernel shortcut. */
4227 kernel = device->kernels[Core];
4228 #if gcdENABLE_VG
4229 if (Core == gcvCORE_VG)
4231 gcmkERR_BREAK(gckVGHARDWARE_SplitMemory(
4232 kernel->vg->hardware, Address, &pool, &offset
4235 else
4236 #endif
4238 /* Split the memory address into a pool type and offset. */
4239 gcmkERR_BREAK(gckHARDWARE_SplitMemory(
4240 kernel->hardware, Address, &pool, &offset
4244 /* Dispatch on pool. */
4245 switch (pool)
4247 case gcvPOOL_LOCAL_INTERNAL:
4248 /* Internal memory. */
4249 logical = device->internalLogical;
4250 break;
4252 case gcvPOOL_LOCAL_EXTERNAL:
4253 /* External memory. */
4254 logical = device->externalLogical;
4255 break;
4257 case gcvPOOL_SYSTEM:
4258 /* System memory. */
4259 logical = device->contiguousBase;
4260 break;
4262 default:
4263 /* Invalid memory pool. */
4264 return gcvSTATUS_INVALID_ARGUMENT;
4267 /* Build logical address of specified address. */
4268 * KernelPointer = ((gctUINT8_PTR) logical) + offset;
4270 /* Success. */
4271 gcmkFOOTER_ARG("*KernelPointer=0x%X", *KernelPointer);
4272 return gcvSTATUS_OK;
4274 while (gcvFALSE);
4276 /* Return status. */
4277 gcmkFOOTER();
4278 return status;
4280 #endif
4282 /*******************************************************************************
4284 ** gckOS_MapUserPointer
4286 ** Map a pointer from the user process into the kernel address space.
4288 ** INPUT:
4290 ** gckOS Os
4291 ** Pointer to an gckOS object.
4293 ** gctPOINTER Pointer
4294 ** Pointer in user process space that needs to be mapped.
4296 ** gctSIZE_T Size
4297 ** Number of bytes that need to be mapped.
4299 ** OUTPUT:
4301 ** gctPOINTER * KernelPointer
4302 ** Pointer to a variable receiving the mapped pointer in kernel address
4303 ** space.
4305 gceSTATUS
4306 gckOS_MapUserPointer(
4307 IN gckOS Os,
4308 IN gctPOINTER Pointer,
4309 IN gctSIZE_T Size,
4310 OUT gctPOINTER * KernelPointer
4313 gcmkHEADER_ARG("Os=0x%X Pointer=0x%X Size=%lu", Os, Pointer, Size);
4315 #if NO_USER_DIRECT_ACCESS_FROM_KERNEL
4317 gctPOINTER buf = gcvNULL;
4318 gctUINT32 len;
4320 /* Verify the arguments. */
4321 gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
4322 gcmkVERIFY_ARGUMENT(Pointer != gcvNULL);
4323 gcmkVERIFY_ARGUMENT(Size > 0);
4324 gcmkVERIFY_ARGUMENT(KernelPointer != gcvNULL);
4326 buf = kmalloc(Size, GFP_KERNEL);
4327 if (buf == gcvNULL)
4329 gcmkTRACE(
4330 gcvLEVEL_ERROR,
4331 "%s(%d): Failed to allocate memory.",
4332 __FUNCTION__, __LINE__
4335 gcmkFOOTER_ARG("*status=%d", gcvSTATUS_OUT_OF_MEMORY);
4336 return gcvSTATUS_OUT_OF_MEMORY;
4339 len = copy_from_user(buf, Pointer, Size);
4340 if (len != 0)
4342 gcmkTRACE(
4343 gcvLEVEL_ERROR,
4344 "%s(%d): Failed to copy data from user.",
4345 __FUNCTION__, __LINE__
4348 if (buf != gcvNULL)
4350 kfree(buf);
4353 gcmkFOOTER_ARG("*status=%d", gcvSTATUS_GENERIC_IO);
4354 return gcvSTATUS_GENERIC_IO;
4357 *KernelPointer = buf;
4359 #else
4360 *KernelPointer = Pointer;
4361 #endif /* NO_USER_DIRECT_ACCESS_FROM_KERNEL */
4363 gcmkFOOTER_ARG("*KernelPointer=0x%X", *KernelPointer);
4364 return gcvSTATUS_OK;
4367 /*******************************************************************************
4369 ** gckOS_UnmapUserPointer
4371 ** Unmap a user process pointer from the kernel address space.
4373 ** INPUT:
4375 ** gckOS Os
4376 ** Pointer to an gckOS object.
4378 ** gctPOINTER Pointer
4379 ** Pointer in user process space that needs to be unmapped.
4381 ** gctSIZE_T Size
4382 ** Number of bytes that need to be unmapped.
4384 ** gctPOINTER KernelPointer
4385 ** Pointer in kernel address space that needs to be unmapped.
4387 ** OUTPUT:
4389 ** Nothing.
4391 gceSTATUS
4392 gckOS_UnmapUserPointer(
4393 IN gckOS Os,
4394 IN gctPOINTER Pointer,
4395 IN gctSIZE_T Size,
4396 IN gctPOINTER KernelPointer
4399 gcmkHEADER_ARG("Os=0x%X Pointer=0x%X Size=%lu KernelPointer=0x%X",
4400 Os, Pointer, Size, KernelPointer);
4402 #if NO_USER_DIRECT_ACCESS_FROM_KERNEL
4404 gctUINT32 len;
4406 /* Verify the arguments. */
4407 gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
4408 gcmkVERIFY_ARGUMENT(Pointer != gcvNULL);
4409 gcmkVERIFY_ARGUMENT(Size > 0);
4410 gcmkVERIFY_ARGUMENT(KernelPointer != gcvNULL);
4412 len = copy_to_user(Pointer, KernelPointer, Size);
4414 kfree(KernelPointer);
4416 if (len != 0)
4418 gcmkTRACE(
4419 gcvLEVEL_ERROR,
4420 "%s(%d): Failed to copy data to user.",
4421 __FUNCTION__, __LINE__
4424 gcmkFOOTER_ARG("status=%d", gcvSTATUS_GENERIC_IO);
4425 return gcvSTATUS_GENERIC_IO;
4428 #endif /* NO_USER_DIRECT_ACCESS_FROM_KERNEL */
4430 gcmkFOOTER_NO();
4431 return gcvSTATUS_OK;
4434 /*******************************************************************************
4436 ** gckOS_QueryNeedCopy
4438 ** Query whether the memory can be accessed or mapped directly or it has to be
4439 ** copied.
4441 ** INPUT:
4443 ** gckOS Os
4444 ** Pointer to an gckOS object.
4446 ** gctUINT32 ProcessID
4447 ** Process ID of the current process.
4449 ** OUTPUT:
4451 ** gctBOOL_PTR NeedCopy
4452 ** Pointer to a boolean receiving gcvTRUE if the memory needs a copy or
4453 ** gcvFALSE if the memory can be accessed or mapped dircetly.
4455 gceSTATUS
4456 gckOS_QueryNeedCopy(
4457 IN gckOS Os,
4458 IN gctUINT32 ProcessID,
4459 OUT gctBOOL_PTR NeedCopy
4462 gcmkHEADER_ARG("Os=0x%X ProcessID=%d", Os, ProcessID);
4464 /* Verify the arguments. */
4465 gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
4466 gcmkVERIFY_ARGUMENT(NeedCopy != gcvNULL);
4468 #if NO_USER_DIRECT_ACCESS_FROM_KERNEL
4469 /* We need to copy data. */
4470 *NeedCopy = gcvTRUE;
4471 #else
4472 /* No need to copy data. */
4473 *NeedCopy = gcvFALSE;
4474 #endif
4476 /* Success. */
4477 gcmkFOOTER_ARG("*NeedCopy=%d", *NeedCopy);
4478 return gcvSTATUS_OK;
4481 /*******************************************************************************
4483 ** gckOS_CopyFromUserData
4485 ** Copy data from user to kernel memory.
4487 ** INPUT:
4489 ** gckOS Os
4490 ** Pointer to an gckOS object.
4492 ** gctPOINTER KernelPointer
4493 ** Pointer to kernel memory.
4495 ** gctPOINTER Pointer
4496 ** Pointer to user memory.
4498 ** gctSIZE_T Size
4499 ** Number of bytes to copy.
4501 ** OUTPUT:
4503 ** Nothing.
4505 gceSTATUS
4506 gckOS_CopyFromUserData(
4507 IN gckOS Os,
4508 IN gctPOINTER KernelPointer,
4509 IN gctPOINTER Pointer,
4510 IN gctSIZE_T Size
4513 gceSTATUS status;
4515 gcmkHEADER_ARG("Os=0x%X KernelPointer=0x%X Pointer=0x%X Size=%lu",
4516 Os, KernelPointer, Pointer, Size);
4518 /* Verify the arguments. */
4519 gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
4520 gcmkVERIFY_ARGUMENT(KernelPointer != gcvNULL);
4521 gcmkVERIFY_ARGUMENT(Pointer != gcvNULL);
4522 gcmkVERIFY_ARGUMENT(Size > 0);
4524 /* Copy data from user. */
4525 if (copy_from_user(KernelPointer, Pointer, Size) != 0)
4527 /* Could not copy all the bytes. */
4528 gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES);
4531 /* Success. */
4532 gcmkFOOTER_NO();
4533 return gcvSTATUS_OK;
4535 OnError:
4536 /* Return the status. */
4537 gcmkFOOTER();
4538 return status;
4541 /*******************************************************************************
4543 ** gckOS_CopyToUserData
4545 ** Copy data from kernel to user memory.
4547 ** INPUT:
4549 ** gckOS Os
4550 ** Pointer to an gckOS object.
4552 ** gctPOINTER KernelPointer
4553 ** Pointer to kernel memory.
4555 ** gctPOINTER Pointer
4556 ** Pointer to user memory.
4558 ** gctSIZE_T Size
4559 ** Number of bytes to copy.
4561 ** OUTPUT:
4563 ** Nothing.
4565 gceSTATUS
4566 gckOS_CopyToUserData(
4567 IN gckOS Os,
4568 IN gctPOINTER KernelPointer,
4569 IN gctPOINTER Pointer,
4570 IN gctSIZE_T Size
4573 gceSTATUS status;
4575 gcmkHEADER_ARG("Os=0x%X KernelPointer=0x%X Pointer=0x%X Size=%lu",
4576 Os, KernelPointer, Pointer, Size);
4578 /* Verify the arguments. */
4579 gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
4580 gcmkVERIFY_ARGUMENT(KernelPointer != gcvNULL);
4581 gcmkVERIFY_ARGUMENT(Pointer != gcvNULL);
4582 gcmkVERIFY_ARGUMENT(Size > 0);
4584 /* Copy data to user. */
4585 if (copy_to_user(Pointer, KernelPointer, Size) != 0)
4587 /* Could not copy all the bytes. */
4588 gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES);
4591 /* Success. */
4592 gcmkFOOTER_NO();
4593 return gcvSTATUS_OK;
4595 OnError:
4596 /* Return the status. */
4597 gcmkFOOTER();
4598 return status;
4601 /*******************************************************************************
4603 ** gckOS_WriteMemory
4605 ** Write data to a memory.
4607 ** INPUT:
4609 ** gckOS Os
4610 ** Pointer to an gckOS object.
4612 ** gctPOINTER Address
4613 ** Address of the memory to write to.
4615 ** gctUINT32 Data
4616 ** Data for register.
4618 ** OUTPUT:
4620 ** Nothing.
4622 gceSTATUS
4623 gckOS_WriteMemory(
4624 IN gckOS Os,
4625 IN gctPOINTER Address,
4626 IN gctUINT32 Data
4629 gcmkHEADER_ARG("Os=0x%X Address=0x%X Data=%u", Os, Address, Data);
4631 /* Verify the arguments. */
4632 gcmkVERIFY_ARGUMENT(Address != gcvNULL);
4634 /* Write memory. */
4635 writel(Data, (gctUINT8 *)Address);
4637 /* Success. */
4638 gcmkFOOTER_NO();
4639 return gcvSTATUS_OK;
4642 /*******************************************************************************
4644 ** gckOS_MapUserMemory
4646 ** Lock down a user buffer and return an DMA'able address to be used by the
4647 ** hardware to access it.
4649 ** INPUT:
4651 ** gctPOINTER Memory
4652 ** Pointer to memory to lock down.
4654 ** gctSIZE_T Size
4655 ** Size in bytes of the memory to lock down.
4657 ** OUTPUT:
4659 ** gctPOINTER * Info
4660 ** Pointer to variable receiving the information record required by
4661 ** gckOS_UnmapUserMemory.
4663 ** gctUINT32_PTR Address
4664 ** Pointer to a variable that will receive the address DMA'able by the
4665 ** hardware.
4667 gceSTATUS
4668 gckOS_MapUserMemory(
4669 IN gckOS Os,
4670 IN gctPOINTER Memory,
4671 IN gctSIZE_T Size,
4672 OUT gctPOINTER * Info,
4673 OUT gctUINT32_PTR Address
4676 return gckOS_MapUserMemoryEx(Os, gcvCORE_MAJOR, Memory, Size, Info, Address);
4679 gceSTATUS
4680 gckOS_MapUserMemoryEx(
4681 IN gckOS Os,
4682 IN gceCORE Core,
4683 IN gctPOINTER Memory,
4684 IN gctSIZE_T Size,
4685 OUT gctPOINTER * Info,
4686 OUT gctUINT32_PTR Address
4689 gceSTATUS status;
4691 gcmkHEADER_ARG("Os=0x%x Core=%d Memory=0x%x Size=%lu", Os, Core, Memory, Size);
4693 #if gcdSECURE_USER
4694 gcmkONERROR(gckOS_AddMapping(Os, *Address, Memory, Size));
4696 gcmkFOOTER_NO();
4697 return gcvSTATUS_OK;
4699 OnError:
4700 gcmkFOOTER();
4701 return status;
4702 #else
4704 gctSIZE_T pageCount, i, j;
4705 gctUINT32_PTR pageTable;
4706 gctUINT32 address;
4707 gctUINT32 start, end, memory;
4708 gctINT result = 0;
4710 gcsPageInfo_PTR info = gcvNULL;
4711 struct page **pages = gcvNULL;
4713 /* Verify the arguments. */
4714 gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
4715 gcmkVERIFY_ARGUMENT(Memory != gcvNULL);
4716 gcmkVERIFY_ARGUMENT(Size > 0);
4717 gcmkVERIFY_ARGUMENT(Info != gcvNULL);
4718 gcmkVERIFY_ARGUMENT(Address != gcvNULL);
4722 memory = (gctUINT32) Memory;
4724 /* Get the number of required pages. */
4725 end = (memory + Size + PAGE_SIZE - 1) >> PAGE_SHIFT;
4726 start = memory >> PAGE_SHIFT;
4727 pageCount = end - start;
4729 gcmkTRACE_ZONE(
4730 gcvLEVEL_INFO, gcvZONE_OS,
4731 "%s(%d): pageCount: %d.",
4732 __FUNCTION__, __LINE__,
4733 pageCount
4736 /* Invalid argument. */
4737 if (pageCount == 0)
4739 gcmkFOOTER_ARG("status=%d", gcvSTATUS_INVALID_ARGUMENT);
4740 return gcvSTATUS_INVALID_ARGUMENT;
4743 /* Overflow. */
4744 if ((memory + Size) < memory)
4746 gcmkFOOTER_ARG("status=%d", gcvSTATUS_INVALID_ARGUMENT);
4747 return gcvSTATUS_INVALID_ARGUMENT;
4750 MEMORY_MAP_LOCK(Os);
4752 /* Allocate the Info struct. */
4753 info = (gcsPageInfo_PTR)kmalloc(sizeof(gcsPageInfo), GFP_KERNEL);
4755 if (info == gcvNULL)
4757 status = gcvSTATUS_OUT_OF_MEMORY;
4758 break;
4761 /* Allocate the array of page addresses. */
4762 pages = (struct page **)kmalloc(pageCount * sizeof(struct page *), GFP_KERNEL);
4764 if (pages == gcvNULL)
4766 status = gcvSTATUS_OUT_OF_MEMORY;
4767 break;
4770 /* Get the user pages. */
4771 down_read(&current->mm->mmap_sem);
4772 result = get_user_pages(current,
4773 current->mm,
4774 memory & PAGE_MASK,
4775 pageCount,
4778 pages,
4779 gcvNULL
4781 up_read(&current->mm->mmap_sem);
4783 if (result <=0 || result < pageCount)
4785 struct vm_area_struct *vma;
4787 vma = find_vma(current->mm, memory);
4789 if (vma && (vma->vm_flags & VM_PFNMAP) )
4793 pte_t * pte;
4794 spinlock_t * ptl;
4795 unsigned long pfn;
4797 pgd_t * pgd = pgd_offset(current->mm, memory);
4798 pud_t * pud = pud_offset(pgd, memory);
4799 if (pud)
4801 pmd_t * pmd = pmd_offset(pud, memory);
4802 pte = pte_offset_map_lock(current->mm, pmd, memory, &ptl);
4803 if (!pte)
4805 break;
4808 else
4810 break;
4813 pfn = pte_pfn(*pte);
4814 *Address = ((pfn << PAGE_SHIFT) | (((unsigned long)Memory) & ~PAGE_MASK))
4815 - Os->device->baseAddress;
4816 *Info = gcvNULL;
4818 pte_unmap_unlock(pte, ptl);
4820 /* Release page info struct. */
4821 if (info != gcvNULL)
4823 /* Free the page info struct. */
4824 kfree(info);
4827 /* Free the page table. */
4828 if (pages != gcvNULL)
4830 /* Release the pages if any. */
4831 if (result > 0)
4833 for (i = 0; i < result; i++)
4835 if (pages[i] == gcvNULL)
4837 break;
4840 page_cache_release(pages[i]);
4844 kfree(pages);
4847 MEMORY_MAP_UNLOCK(Os);
4849 gcmkFOOTER_ARG("*Info=0x%X *Address=0x%08x",
4850 *Info, *Address);
4851 return gcvSTATUS_OK;
4853 while (gcvFALSE);
4855 *Address = ~0;
4856 *Info = gcvNULL;
4858 status = gcvSTATUS_OUT_OF_RESOURCES;
4859 break;
4861 else
4863 status = gcvSTATUS_OUT_OF_RESOURCES;
4864 break;
4868 for (i = 0; i < pageCount; i++)
4870 /* Flush(clean) the data cache. */
4871 #if !defined(ANDROID)
4872 dma_sync_single_for_device(
4873 gcvNULL,
4874 page_to_phys(pages[i]),
4875 PAGE_SIZE,
4876 DMA_TO_DEVICE);
4877 #else
4878 flush_dcache_page(pages[i]);
4879 #endif
4882 #if gcdENABLE_VG
4883 if (Core == gcvCORE_VG)
4885 /* Allocate pages inside the page table. */
4886 gcmkERR_BREAK(gckVGMMU_AllocatePages(Os->device->kernels[Core]->vg->mmu,
4887 pageCount * (PAGE_SIZE/4096),
4888 (gctPOINTER *) &pageTable,
4889 &address));
4891 else
4892 #endif
4894 /* Allocate pages inside the page table. */
4895 gcmkERR_BREAK(gckMMU_AllocatePages(Os->device->kernels[Core]->mmu,
4896 pageCount * (PAGE_SIZE/4096),
4897 (gctPOINTER *) &pageTable,
4898 &address));
4900 /* Fill the page table. */
4901 for (i = 0; i < pageCount; i++)
4903 #if gcdENABLE_VG
4904 if (Core == gcvCORE_VG)
4906 /* Get the physical address from page struct. */
4907 gcmkONERROR(
4908 gckVGMMU_SetPage(Os->device->kernels[Core]->vg->mmu,
4909 page_to_phys(pages[i]),
4910 pageTable + i * (PAGE_SIZE/4096)));
4912 else
4913 #endif
4915 /* Get the physical address from page struct. */
4916 gcmkONERROR(
4917 gckMMU_SetPage(Os->device->kernels[Core]->mmu,
4918 page_to_phys(pages[i]),
4919 pageTable + i * (PAGE_SIZE/4096)));
4922 for (j = 1; j < (PAGE_SIZE/4096); j++)
4924 pageTable[i * (PAGE_SIZE/4096) + j] = pageTable[i * (PAGE_SIZE/4096)] + 4096 * j;
4927 gcmkTRACE_ZONE(
4928 gcvLEVEL_INFO, gcvZONE_OS,
4929 "%s(%d): pages[%d]: 0x%X, pageTable[%d]: 0x%X.",
4930 __FUNCTION__, __LINE__,
4931 i, pages[i],
4932 i, pageTable[i]);
4935 /* Save pointer to page table. */
4936 info->pageTable = pageTable;
4937 info->pages = pages;
4939 *Info = (gctPOINTER) info;
4941 gcmkTRACE_ZONE(
4942 gcvLEVEL_INFO, gcvZONE_OS,
4943 "%s(%d): info->pages: 0x%X, info->pageTable: 0x%X, info: 0x%X.",
4944 __FUNCTION__, __LINE__,
4945 info->pages,
4946 info->pageTable,
4947 info
4950 /* Return address. */
4951 *Address = address + (memory & ~PAGE_MASK);
4953 gcmkTRACE_ZONE(
4954 gcvLEVEL_INFO, gcvZONE_OS,
4955 "%s(%d): Address: 0x%X.",
4956 __FUNCTION__, __LINE__,
4957 *Address
4960 /* Success. */
4961 status = gcvSTATUS_OK;
4963 while (gcvFALSE);
4965 OnError:
4967 if (gcmIS_ERROR(status))
4969 gcmkTRACE(
4970 gcvLEVEL_ERROR,
4971 "%s(%d): error occured: %d.",
4972 __FUNCTION__, __LINE__,
4973 status
4976 /* Release page array. */
4977 if (result > 0 && pages != gcvNULL)
4979 gcmkTRACE(
4980 gcvLEVEL_ERROR,
4981 "%s(%d): error: page table is freed.",
4982 __FUNCTION__, __LINE__
4985 for (i = 0; i < result; i++)
4987 if (pages[i] == gcvNULL)
4989 break;
4991 page_cache_release(pages[i]);
4995 if (info!= gcvNULL && pages != gcvNULL)
4997 gcmkTRACE(
4998 gcvLEVEL_ERROR,
4999 "%s(%d): error: pages is freed.",
5000 __FUNCTION__, __LINE__
5003 /* Free the page table. */
5004 kfree(pages);
5005 info->pages = gcvNULL;
5008 /* Release page info struct. */
5009 if (info != gcvNULL)
5011 gcmkTRACE(
5012 gcvLEVEL_ERROR,
5013 "%s(%d): error: info is freed.",
5014 __FUNCTION__, __LINE__
5017 /* Free the page info struct. */
5018 kfree(info);
5019 *Info = gcvNULL;
5023 MEMORY_MAP_UNLOCK(Os);
5025 /* Return the status. */
5026 if (gcmIS_SUCCESS(status))
5028 gcmkFOOTER_ARG("*Info=0x%X *Address=0x%08x", *Info, *Address);
5030 else
5032 gcmkFOOTER();
5034 return status;
5036 #endif
5039 /*******************************************************************************
5041 ** gckOS_UnmapUserMemory
5043 ** Unlock a user buffer and that was previously locked down by
5044 ** gckOS_MapUserMemory.
5046 ** INPUT:
5048 ** gctPOINTER Memory
5049 ** Pointer to memory to unlock.
5051 ** gctSIZE_T Size
5052 ** Size in bytes of the memory to unlock.
5054 ** gctPOINTER Info
5055 ** Information record returned by gckOS_MapUserMemory.
5057 ** gctUINT32_PTR Address
5058 ** The address returned by gckOS_MapUserMemory.
5060 ** OUTPUT:
5062 ** Nothing.
5064 gceSTATUS
5065 gckOS_UnmapUserMemory(
5066 IN gckOS Os,
5067 IN gctPOINTER Memory,
5068 IN gctSIZE_T Size,
5069 IN gctPOINTER Info,
5070 IN gctUINT32 Address
5073 return gckOS_UnmapUserMemoryEx(Os, gcvCORE_MAJOR, Memory, Size, Info, Address);
5076 gceSTATUS
5077 gckOS_UnmapUserMemoryEx(
5078 IN gckOS Os,
5079 IN gceCORE Core,
5080 IN gctPOINTER Memory,
5081 IN gctSIZE_T Size,
5082 IN gctPOINTER Info,
5083 IN gctUINT32 Address
5086 gceSTATUS status;
5088 gcmkHEADER_ARG("Os=0x%X Core=%d Memory=0x%X Size=%lu Info=0x%X Address0x%08x",
5089 Os, Core, Memory, Size, Info, Address);
5091 #if gcdSECURE_USER
5092 gcmkONERROR(gckOS_RemoveMapping(Os, Memory, Size));
5094 gcmkFOOTER_NO();
5095 return gcvSTATUS_OK;
5097 OnError:
5098 gcmkFOOTER();
5099 return status;
5100 #else
5102 gctUINT32 memory, start, end;
5103 gcsPageInfo_PTR info;
5104 gctSIZE_T pageCount, i;
5105 struct page **pages;
5107 /* Verify the arguments. */
5108 gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
5109 gcmkVERIFY_ARGUMENT(Memory != gcvNULL);
5110 gcmkVERIFY_ARGUMENT(Size > 0);
5111 gcmkVERIFY_ARGUMENT(Info != gcvNULL);
5115 info = (gcsPageInfo_PTR) Info;
5117 pages = info->pages;
5119 gcmkTRACE_ZONE(
5120 gcvLEVEL_INFO, gcvZONE_OS,
5121 "%s(%d): info=0x%X, pages=0x%X.",
5122 __FUNCTION__, __LINE__,
5123 info, pages
5126 /* Invalid page array. */
5127 if (pages == gcvNULL)
5129 return gcvSTATUS_INVALID_ARGUMENT;
5132 memory = (gctUINT32) Memory;
5133 end = (memory + Size + PAGE_SIZE - 1) >> PAGE_SHIFT;
5134 start = memory >> PAGE_SHIFT;
5135 pageCount = end - start;
5137 /* Overflow. */
5138 if ((memory + Size) < memory)
5140 return gcvSTATUS_INVALID_ARGUMENT;
5143 /* Invalid argument. */
5144 if (pageCount == 0)
5146 return gcvSTATUS_INVALID_ARGUMENT;
5149 gcmkTRACE_ZONE(
5150 gcvLEVEL_INFO, gcvZONE_OS,
5151 "%s(%d): memory: 0x%X, pageCount: %d, pageTable: 0x%X.",
5152 __FUNCTION__, __LINE__,
5153 memory, pageCount, info->pageTable
5156 MEMORY_MAP_LOCK(Os);
5158 #if gcdENABLE_VG
5159 if (Core == gcvCORE_VG)
5161 /* Free the pages from the MMU. */
5162 gcmkERR_BREAK(gckVGMMU_FreePages(Os->device->kernels[Core]->vg->mmu,
5163 info->pageTable,
5164 pageCount * (PAGE_SIZE/4096)
5167 else
5168 #endif
5170 /* Free the pages from the MMU. */
5171 gcmkERR_BREAK(gckMMU_FreePages(Os->device->kernels[Core]->mmu,
5172 info->pageTable,
5173 pageCount * (PAGE_SIZE/4096)
5177 /* Release the page cache. */
5178 for (i = 0; i < pageCount; i++)
5180 gcmkTRACE_ZONE(
5181 gcvLEVEL_INFO, gcvZONE_OS,
5182 "%s(%d): pages[%d]: 0x%X.",
5183 __FUNCTION__, __LINE__,
5184 i, pages[i]
5187 if (!PageReserved(pages[i]))
5189 SetPageDirty(pages[i]);
5192 #if !defined(ANDROID)
5193 /* Invalidate the data cache. */
5194 dma_sync_single_for_device(
5195 gcvNULL,
5196 page_to_phys(pages[i]),
5197 PAGE_SIZE,
5198 DMA_FROM_DEVICE);
5199 #endif
5200 page_cache_release(pages[i]);
5203 /* Success. */
5204 status = gcvSTATUS_OK;
5206 while (gcvFALSE);
5208 if (info != gcvNULL)
5210 /* Free the page array. */
5211 if (info->pages != gcvNULL)
5213 kfree(info->pages);
5216 kfree(info);
5219 MEMORY_MAP_UNLOCK(Os);
5221 /* Return the status. */
5222 gcmkFOOTER();
5223 return status;
5225 #endif
5228 /*******************************************************************************
5230 ** gckOS_GetBaseAddress
5232 ** Get the base address for the physical memory.
5234 ** INPUT:
5236 ** gckOS Os
5237 ** Pointer to the gckOS object.
5239 ** OUTPUT:
5241 ** gctUINT32_PTR BaseAddress
5242 ** Pointer to a variable that will receive the base address.
5244 gceSTATUS
5245 gckOS_GetBaseAddress(
5246 IN gckOS Os,
5247 OUT gctUINT32_PTR BaseAddress
5250 gcmkHEADER_ARG("Os=0x%X", Os);
5252 /* Verify the arguments. */
5253 gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
5254 gcmkVERIFY_ARGUMENT(BaseAddress != gcvNULL);
5256 /* Return base address. */
5257 *BaseAddress = Os->device->baseAddress;
5259 /* Success. */
5260 gcmkFOOTER_ARG("*BaseAddress=0x%08x", *BaseAddress);
5261 return gcvSTATUS_OK;
5264 gceSTATUS
5265 gckOS_SuspendInterrupt(
5266 IN gckOS Os
5269 return gckOS_SuspendInterruptEx(Os, gcvCORE_MAJOR);
5272 gceSTATUS
5273 gckOS_SuspendInterruptEx(
5274 IN gckOS Os,
5275 IN gceCORE Core
5278 gcmkHEADER_ARG("Os=0x%X Core=%d", Os, Core);
5280 /* Verify the arguments. */
5281 gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
5283 disable_irq(Os->device->irqLines[Core]);
5285 gcmkFOOTER_NO();
5286 return gcvSTATUS_OK;
5289 gceSTATUS
5290 gckOS_ResumeInterrupt(
5291 IN gckOS Os
5294 return gckOS_ResumeInterruptEx(Os, gcvCORE_MAJOR);
5297 gceSTATUS
5298 gckOS_ResumeInterruptEx(
5299 IN gckOS Os,
5300 IN gceCORE Core
5303 gcmkHEADER_ARG("Os=0x%X Core=%d", Os, Core);
5305 /* Verify the arguments. */
5306 gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
5308 enable_irq(Os->device->irqLines[Core]);
5310 gcmkFOOTER_NO();
5311 return gcvSTATUS_OK;
5314 gceSTATUS
5315 gckOS_MemCopy(
5316 IN gctPOINTER Destination,
5317 IN gctCONST_POINTER Source,
5318 IN gctSIZE_T Bytes
5321 gcmkHEADER_ARG("Destination=0x%X Source=0x%X Bytes=%lu",
5322 Destination, Source, Bytes);
5324 gcmkVERIFY_ARGUMENT(Destination != gcvNULL);
5325 gcmkVERIFY_ARGUMENT(Source != gcvNULL);
5326 gcmkVERIFY_ARGUMENT(Bytes > 0);
5328 memcpy(Destination, Source, Bytes);
5330 gcmkFOOTER_NO();
5331 return gcvSTATUS_OK;
5334 gceSTATUS
5335 gckOS_ZeroMemory(
5336 IN gctPOINTER Memory,
5337 IN gctSIZE_T Bytes
5340 gcmkHEADER_ARG("Memory=0x%X Bytes=%lu", Memory, Bytes);
5342 gcmkVERIFY_ARGUMENT(Memory != gcvNULL);
5343 gcmkVERIFY_ARGUMENT(Bytes > 0);
5345 memset(Memory, 0, Bytes);
5347 gcmkFOOTER_NO();
5348 return gcvSTATUS_OK;
5351 /*******************************************************************************
5352 ********************************* Cache Control ********************************
5353 *******************************************************************************/
5355 /*******************************************************************************
5356 ** _HandleOuterCache
5358 ** Handle the outer cache for the specified addresses.
5360 ** ARGUMENTS:
5362 ** gckOS Os
5363 ** Pointer to gckOS object.
5365 ** gctUINT32 ProcessID
5366 ** Process ID Logical belongs.
5368 ** gctPHYS_ADDR Handle
5369 ** Physical address handle. If gcvNULL it is video memory.
5371 ** gctPOINTER Physical
5372 ** Physical address to flush.
5374 ** gctPOINTER Logical
5375 ** Logical address to flush.
5377 ** gctSIZE_T Bytes
5378 ** Size of the address range in bytes to flush.
5380 ** gceOUTERCACHE_OPERATION Type
5381 ** Operation need to be execute.
5383 #if !gcdCACHE_FUNCTION_UNIMPLEMENTED && defined(CONFIG_OUTER_CACHE)
5384 static inline gceSTATUS
5385 outer_func(
5386 gceCACHEOPERATION Type,
5387 unsigned long Start,
5388 unsigned long End
5391 switch (Type)
5393 case gcvCACHE_CLEAN:
5394 outer_clean_range(Start, End);
5395 break;
5396 case gcvCACHE_INVALIDATE:
5397 outer_inv_range(Start, End);
5398 break;
5399 case gcvCACHE_FLUSH:
5400 outer_flush_range(Start, End);
5401 break;
5402 default:
5403 return gcvSTATUS_INVALID_ARGUMENT;
5404 break;
5406 return gcvSTATUS_OK;
5409 static gceSTATUS
5410 _HandleOuterCache(
5411 IN gckOS Os,
5412 IN gctUINT32 ProcessID,
5413 IN gctPHYS_ADDR Handle,
5414 IN gctPOINTER Physical,
5415 IN gctPOINTER Logical,
5416 IN gctSIZE_T Bytes,
5417 IN gceCACHEOPERATION Type
5420 gceSTATUS status;
5421 gctUINT32 i, pageNum;
5422 unsigned long paddr;
5423 gctPOINTER vaddr;
5425 gcmkHEADER_ARG("Os=0x%X ProcessID=%d Handle=0x%X Logical=0x%X Bytes=%lu",
5426 Os, ProcessID, Handle, Logical, Bytes);
5428 if (Physical != gcvNULL)
5430 /* Non paged memory or gcvPOOL_USER surface */
5431 paddr = (unsigned long) Physical;
5432 gcmkONERROR(outer_func(Type, paddr, paddr + Bytes));
5434 else if ((Handle == gcvNULL)
5435 || (Handle != gcvNULL && ((PLINUX_MDL)Handle)->contiguous)
5438 /* Video Memory or contiguous virtual memory */
5439 gcmkONERROR(gckOS_GetPhysicalAddress(Os, Logical, (gctUINT32*)&paddr));
5440 gcmkONERROR(outer_func(Type, paddr, paddr + Bytes));
5442 else
5444 /* Non contiguous virtual memory */
5445 vaddr = (gctPOINTER)gcmALIGN_BASE((gctUINT32)Logical, PAGE_SIZE);
5446 pageNum = GetPageCount(Bytes, 0);
5448 for (i = 0; i < pageNum; i += 1)
5450 gcmkONERROR(_ConvertLogical2Physical(
5452 vaddr + PAGE_SIZE * i,
5453 ProcessID,
5454 (PLINUX_MDL)Handle,
5455 (gctUINT32*)&paddr
5458 gcmkONERROR(outer_func(Type, paddr, paddr + PAGE_SIZE));
5462 mb();
5464 /* Success. */
5465 gcmkFOOTER_NO();
5466 return gcvSTATUS_OK;
5468 OnError:
5469 /* Return the status. */
5470 gcmkFOOTER();
5471 return status;
5473 #endif
5475 /*******************************************************************************
5476 ** gckOS_CacheClean
5478 ** Clean the cache for the specified addresses. The GPU is going to need the
5479 ** data. If the system is allocating memory as non-cachable, this function can
5480 ** be ignored.
5482 ** ARGUMENTS:
5484 ** gckOS Os
5485 ** Pointer to gckOS object.
5487 ** gctUINT32 ProcessID
5488 ** Process ID Logical belongs.
5490 ** gctPHYS_ADDR Handle
5491 ** Physical address handle. If gcvNULL it is video memory.
5493 ** gctPOINTER Physical
5494 ** Physical address to flush.
5496 ** gctPOINTER Logical
5497 ** Logical address to flush.
5499 ** gctSIZE_T Bytes
5500 ** Size of the address range in bytes to flush.
5502 gceSTATUS
5503 gckOS_CacheClean(
5504 IN gckOS Os,
5505 IN gctUINT32 ProcessID,
5506 IN gctPHYS_ADDR Handle,
5507 IN gctPOINTER Physical,
5508 IN gctPOINTER Logical,
5509 IN gctSIZE_T Bytes
5512 gcmkHEADER_ARG("Os=0x%X ProcessID=%d Handle=0x%X Logical=0x%X Bytes=%lu",
5513 Os, ProcessID, Handle, Logical, Bytes);
5515 /* Verify the arguments. */
5516 gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
5517 gcmkVERIFY_ARGUMENT(Logical != gcvNULL);
5518 gcmkVERIFY_ARGUMENT(Bytes > 0);
5520 #if !gcdCACHE_FUNCTION_UNIMPLEMENTED
5521 #ifdef CONFIG_ARM
5523 /* Inner cache. */
5524 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35)
5525 dmac_map_area(Logical, Bytes, DMA_TO_DEVICE);
5526 # else
5527 dmac_clean_range(Logical, Logical + Bytes);
5528 # endif
5530 #if defined(CONFIG_OUTER_CACHE)
5531 /* Outer cache. */
5532 _HandleOuterCache(Os, ProcessID, Handle, Physical, Logical, Bytes, gcvCACHE_CLEAN);
5533 #endif
5535 #elif defined(CONFIG_MIPS)
5537 dma_cache_wback((unsigned long) Logical, Bytes);
5539 #else
5540 dma_sync_single_for_device(
5541 gcvNULL,
5542 Physical,
5543 Bytes,
5544 DMA_TO_DEVICE);
5545 #endif
5546 #endif
5548 /* Success. */
5549 gcmkFOOTER_NO();
5550 return gcvSTATUS_OK;
5553 /*******************************************************************************
5554 ** gckOS_CacheInvalidate
5556 ** Invalidate the cache for the specified addresses. The GPU is going to need
5557 ** data. If the system is allocating memory as non-cachable, this function can
5558 ** be ignored.
5560 ** ARGUMENTS:
5562 ** gckOS Os
5563 ** Pointer to gckOS object.
5565 ** gctUINT32 ProcessID
5566 ** Process ID Logical belongs.
5568 ** gctPHYS_ADDR Handle
5569 ** Physical address handle. If gcvNULL it is video memory.
5571 ** gctPOINTER Logical
5572 ** Logical address to flush.
5574 ** gctSIZE_T Bytes
5575 ** Size of the address range in bytes to flush.
5577 gceSTATUS
5578 gckOS_CacheInvalidate(
5579 IN gckOS Os,
5580 IN gctUINT32 ProcessID,
5581 IN gctPHYS_ADDR Handle,
5582 IN gctPOINTER Physical,
5583 IN gctPOINTER Logical,
5584 IN gctSIZE_T Bytes
5587 gcmkHEADER_ARG("Os=0x%X ProcessID=%d Handle=0x%X Logical=0x%X Bytes=%lu",
5588 Os, ProcessID, Handle, Logical, Bytes);
5590 /* Verify the arguments. */
5591 gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
5592 gcmkVERIFY_ARGUMENT(Logical != gcvNULL);
5593 gcmkVERIFY_ARGUMENT(Bytes > 0);
5595 #if !gcdCACHE_FUNCTION_UNIMPLEMENTED
5596 #ifdef CONFIG_ARM
5598 /* Inner cache. */
5599 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35)
5600 dmac_map_area(Logical, Bytes, DMA_FROM_DEVICE);
5601 # else
5602 dmac_inv_range(Logical, Logical + Bytes);
5603 # endif
5605 #if defined(CONFIG_OUTER_CACHE)
5606 /* Outer cache. */
5607 _HandleOuterCache(Os, ProcessID, Handle, Physical, Logical, Bytes, gcvCACHE_INVALIDATE);
5608 #endif
5610 #elif defined(CONFIG_MIPS)
5611 dma_cache_inv((unsigned long) Logical, Bytes);
5612 #else
5613 dma_sync_single_for_device(
5614 gcvNULL,
5615 Physical,
5616 Bytes,
5617 DMA_FROM_DEVICE);
5618 #endif
5619 #endif
5621 /* Success. */
5622 gcmkFOOTER_NO();
5623 return gcvSTATUS_OK;
5626 /*******************************************************************************
5627 ** gckOS_CacheFlush
5629 ** Clean the cache for the specified addresses and invalidate the lines as
5630 ** well. The GPU is going to need and modify the data. If the system is
5631 ** allocating memory as non-cachable, this function can be ignored.
5633 ** ARGUMENTS:
5635 ** gckOS Os
5636 ** Pointer to gckOS object.
5638 ** gctUINT32 ProcessID
5639 ** Process ID Logical belongs.
5641 ** gctPHYS_ADDR Handle
5642 ** Physical address handle. If gcvNULL it is video memory.
5644 ** gctPOINTER Logical
5645 ** Logical address to flush.
5647 ** gctSIZE_T Bytes
5648 ** Size of the address range in bytes to flush.
5650 gceSTATUS
5651 gckOS_CacheFlush(
5652 IN gckOS Os,
5653 IN gctUINT32 ProcessID,
5654 IN gctPHYS_ADDR Handle,
5655 IN gctPOINTER Physical,
5656 IN gctPOINTER Logical,
5657 IN gctSIZE_T Bytes
5660 gcmkHEADER_ARG("Os=0x%X ProcessID=%d Handle=0x%X Logical=0x%X Bytes=%lu",
5661 Os, ProcessID, Handle, Logical, Bytes);
5663 /* Verify the arguments. */
5664 gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
5665 gcmkVERIFY_ARGUMENT(Logical != gcvNULL);
5666 gcmkVERIFY_ARGUMENT(Bytes > 0);
5668 #if !gcdCACHE_FUNCTION_UNIMPLEMENTED
5669 #ifdef CONFIG_ARM
5670 /* Inner cache. */
5671 dmac_flush_range(Logical, Logical + Bytes);
5673 #if defined(CONFIG_OUTER_CACHE)
5674 /* Outer cache. */
5675 _HandleOuterCache(Os, ProcessID, Handle, Physical, Logical, Bytes, gcvCACHE_FLUSH);
5676 #endif
5678 #elif defined(CONFIG_MIPS)
5679 dma_cache_wback_inv((unsigned long) Logical, Bytes);
5680 #else
5681 dma_sync_single_for_device(
5682 gcvNULL,
5683 Physical,
5684 Bytes,
5685 DMA_BIDIRECTIONAL);
5686 #endif
5687 #endif
5689 /* Success. */
5690 gcmkFOOTER_NO();
5691 return gcvSTATUS_OK;
5694 /*******************************************************************************
5695 ********************************* Broadcasting *********************************
5696 *******************************************************************************/
5698 /*******************************************************************************
5700 ** gckOS_Broadcast
5702 ** System hook for broadcast events from the kernel driver.
5704 ** INPUT:
5706 ** gckOS Os
5707 ** Pointer to the gckOS object.
5709 ** gckHARDWARE Hardware
5710 ** Pointer to the gckHARDWARE object.
5712 ** gceBROADCAST Reason
5713 ** Reason for the broadcast. Can be one of the following values:
5715 ** gcvBROADCAST_GPU_IDLE
5716 ** Broadcasted when the kernel driver thinks the GPU might be
5717 ** idle. This can be used to handle power management.
5719 ** gcvBROADCAST_GPU_COMMIT
5720 ** Broadcasted when any client process commits a command
5721 ** buffer. This can be used to handle power management.
5723 ** gcvBROADCAST_GPU_STUCK
5724 ** Broadcasted when the kernel driver hits the timeout waiting
5725 ** for the GPU.
5727 ** gcvBROADCAST_FIRST_PROCESS
5728 ** First process is trying to connect to the kernel.
5730 ** gcvBROADCAST_LAST_PROCESS
5731 ** Last process has detached from the kernel.
5733 ** OUTPUT:
5735 ** Nothing.
5737 gceSTATUS
5738 gckOS_Broadcast(
5739 IN gckOS Os,
5740 IN gckHARDWARE Hardware,
5741 IN gceBROADCAST Reason
5744 gceSTATUS status;
5746 gcmkHEADER_ARG("Os=0x%X Hardware=0x%X Reason=%d", Os, Hardware, Reason);
5748 /* Verify the arguments. */
5749 gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
5750 gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
5752 switch (Reason)
5754 case gcvBROADCAST_FIRST_PROCESS:
5755 gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_OS, "First process has attached");
5756 break;
5758 case gcvBROADCAST_LAST_PROCESS:
5759 gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_OS, "Last process has detached");
5761 /* Put GPU OFF. */
5762 gcmkONERROR(
5763 gckHARDWARE_SetPowerManagementState(Hardware,
5764 gcvPOWER_OFF_BROADCAST));
5765 break;
5767 case gcvBROADCAST_GPU_IDLE:
5768 gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_OS, "GPU idle.");
5770 /* Put GPU IDLE. */
5771 gcmkONERROR(
5772 gckHARDWARE_SetPowerManagementState(Hardware,
5773 gcvPOWER_IDLE_BROADCAST));
5775 /* Add idle process DB. */
5776 gcmkONERROR(gckKERNEL_AddProcessDB(Hardware->kernel,
5778 gcvDB_IDLE,
5779 gcvNULL, gcvNULL, 0));
5780 break;
5782 case gcvBROADCAST_GPU_COMMIT:
5783 gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_OS, "COMMIT has arrived.");
5785 /* Add busy process DB. */
5786 gcmkONERROR(gckKERNEL_AddProcessDB(Hardware->kernel,
5788 gcvDB_IDLE,
5789 gcvNULL, gcvNULL, 0));
5791 /* Put GPU ON. */
5792 gcmkONERROR(
5793 gckHARDWARE_SetPowerManagementState(Hardware, gcvPOWER_ON_AUTO));
5794 break;
5796 case gcvBROADCAST_GPU_STUCK:
5797 gcmkTRACE_N(gcvLEVEL_ERROR, 0, "gcvBROADCAST_GPU_STUCK\n");
5798 gcmkONERROR(_DumpGPUState(Os));
5799 gcmkONERROR(gckKERNEL_Recovery(Hardware->kernel));
5800 break;
5802 case gcvBROADCAST_AXI_BUS_ERROR:
5803 gcmkTRACE_N(gcvLEVEL_ERROR, 0, "gcvBROADCAST_AXI_BUS_ERROR\n");
5804 gcmkONERROR(_DumpGPUState(Os));
5805 /*gcmkONERROR(gckKERNEL_Recovery(Hardware->kernel));*/
5806 break;
5809 /* Success. */
5810 gcmkFOOTER_NO();
5811 return gcvSTATUS_OK;
5813 OnError:
5814 /* Return the status. */
5815 gcmkFOOTER();
5816 return status;
5819 /*******************************************************************************
5821 ** gckOS_BroadcastHurry
5823 ** The GPU is running too slow.
5825 ** INPUT:
5827 ** gckOS Os
5828 ** Pointer to the gckOS object.
5830 ** gckHARDWARE Hardware
5831 ** Pointer to the gckHARDWARE object.
5833 ** gctUINT Urgency
5834 ** The higher the number, the higher the urgency to speed up the GPU.
5835 ** The maximum value is defined by the gcdDYNAMIC_EVENT_THRESHOLD.
5837 ** OUTPUT:
5839 ** Nothing.
5841 gceSTATUS
5842 gckOS_BroadcastHurry(
5843 IN gckOS Os,
5844 IN gckHARDWARE Hardware,
5845 IN gctUINT Urgency
5848 gcmkHEADER_ARG("Os=0x%x Hardware=0x%x Urgency=%u", Os, Hardware, Urgency);
5850 /* Do whatever you need to do to speed up the GPU now. */
5852 /* Success. */
5853 gcmkFOOTER_NO();
5854 return gcvSTATUS_OK;
5857 /*******************************************************************************
5859 ** gckOS_BroadcastCalibrateSpeed
5861 ** Calibrate the speed of the GPU.
5863 ** INPUT:
5865 ** gckOS Os
5866 ** Pointer to the gckOS object.
5868 ** gckHARDWARE Hardware
5869 ** Pointer to the gckHARDWARE object.
5871 ** gctUINT Idle, Time
5872 ** Idle/Time will give the percentage the GPU is idle, so you can use
5873 ** this to calibrate the working point of the GPU.
5875 ** OUTPUT:
5877 ** Nothing.
5879 gceSTATUS
5880 gckOS_BroadcastCalibrateSpeed(
5881 IN gckOS Os,
5882 IN gckHARDWARE Hardware,
5883 IN gctUINT Idle,
5884 IN gctUINT Time
5887 gcmkHEADER_ARG("Os=0x%x Hardware=0x%x Idle=%u Time=%u",
5888 Os, Hardware, Idle, Time);
5890 /* Do whatever you need to do to callibrate the GPU speed. */
5892 /* Success. */
5893 gcmkFOOTER_NO();
5894 return gcvSTATUS_OK;
5897 /*******************************************************************************
5898 ********************************** Semaphores **********************************
5899 *******************************************************************************/
5901 /*******************************************************************************
5903 ** gckOS_CreateSemaphore
5905 ** Create a semaphore.
5907 ** INPUT:
5909 ** gckOS Os
5910 ** Pointer to the gckOS object.
5912 ** OUTPUT:
5914 ** gctPOINTER * Semaphore
5915 ** Pointer to the variable that will receive the created semaphore.
5917 gceSTATUS
5918 gckOS_CreateSemaphore(
5919 IN gckOS Os,
5920 OUT gctPOINTER * Semaphore
5923 gceSTATUS status;
5924 struct semaphore *sem = gcvNULL;
5926 gcmkHEADER_ARG("Os=0x%X", Os);
5928 /* Verify the arguments. */
5929 gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
5930 gcmkVERIFY_ARGUMENT(Semaphore != gcvNULL);
5932 /* Allocate the semaphore structure. */
5933 sem = (struct semaphore *)kmalloc(gcmSIZEOF(struct semaphore), GFP_KERNEL);
5934 if (sem == gcvNULL)
5936 gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
5939 /* Initialize the semaphore. */
5940 sema_init(sem, 1);
5942 /* Return to caller. */
5943 *Semaphore = (gctPOINTER) sem;
5945 /* Success. */
5946 gcmkFOOTER_NO();
5947 return gcvSTATUS_OK;
5949 OnError:
5950 /* Return the status. */
5951 gcmkFOOTER();
5952 return status;
5955 /*******************************************************************************
5957 ** gckOS_AcquireSemaphore
5959 ** Acquire a semaphore.
5961 ** INPUT:
5963 ** gckOS Os
5964 ** Pointer to the gckOS object.
5966 ** gctPOINTER Semaphore
5967 ** Pointer to the semaphore thet needs to be acquired.
5969 ** OUTPUT:
5971 ** Nothing.
5973 gceSTATUS
5974 gckOS_AcquireSemaphore(
5975 IN gckOS Os,
5976 IN gctPOINTER Semaphore
5979 gceSTATUS status;
5981 gcmkHEADER_ARG("Os=0x%08X Semaphore=0x%08X", Os, Semaphore);
5983 /* Verify the arguments. */
5984 gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
5985 gcmkVERIFY_ARGUMENT(Semaphore != gcvNULL);
5987 /* Acquire the semaphore. */
5988 if (down_interruptible((struct semaphore *) Semaphore))
5990 gcmkONERROR(gcvSTATUS_TIMEOUT);
5993 /* Success. */
5994 gcmkFOOTER_NO();
5995 return gcvSTATUS_OK;
5997 OnError:
5998 /* Return the status. */
5999 gcmkFOOTER();
6000 return status;
6003 /*******************************************************************************
6005 ** gckOS_TryAcquireSemaphore
6007 ** Try to acquire a semaphore.
6009 ** INPUT:
6011 ** gckOS Os
6012 ** Pointer to the gckOS object.
6014 ** gctPOINTER Semaphore
6015 ** Pointer to the semaphore thet needs to be acquired.
6017 ** OUTPUT:
6019 ** Nothing.
6021 gceSTATUS
6022 gckOS_TryAcquireSemaphore(
6023 IN gckOS Os,
6024 IN gctPOINTER Semaphore
6027 gceSTATUS status;
6029 gcmkHEADER_ARG("Os=0x%x", Os);
6031 /* Verify the arguments. */
6032 gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
6033 gcmkVERIFY_ARGUMENT(Semaphore != gcvNULL);
6035 /* Acquire the semaphore. */
6036 if (down_trylock((struct semaphore *) Semaphore))
6038 /* Timeout. */
6039 status = gcvSTATUS_TIMEOUT;
6040 gcmkFOOTER();
6041 return status;
6044 /* Success. */
6045 gcmkFOOTER_NO();
6046 return gcvSTATUS_OK;
6049 /*******************************************************************************
6051 ** gckOS_ReleaseSemaphore
6053 ** Release a previously acquired semaphore.
6055 ** INPUT:
6057 ** gckOS Os
6058 ** Pointer to the gckOS object.
6060 ** gctPOINTER Semaphore
6061 ** Pointer to the semaphore thet needs to be released.
6063 ** OUTPUT:
6065 ** Nothing.
6067 gceSTATUS
6068 gckOS_ReleaseSemaphore(
6069 IN gckOS Os,
6070 IN gctPOINTER Semaphore
6073 gcmkHEADER_ARG("Os=0x%X Semaphore=0x%X", Os, Semaphore);
6075 /* Verify the arguments. */
6076 gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
6077 gcmkVERIFY_ARGUMENT(Semaphore != gcvNULL);
6079 /* Release the semaphore. */
6080 up((struct semaphore *) Semaphore);
6082 /* Success. */
6083 gcmkFOOTER_NO();
6084 return gcvSTATUS_OK;
6087 /*******************************************************************************
6089 ** gckOS_DestroySemaphore
6091 ** Destroy a semaphore.
6093 ** INPUT:
6095 ** gckOS Os
6096 ** Pointer to the gckOS object.
6098 ** gctPOINTER Semaphore
6099 ** Pointer to the semaphore thet needs to be destroyed.
6101 ** OUTPUT:
6103 ** Nothing.
6105 gceSTATUS
6106 gckOS_DestroySemaphore(
6107 IN gckOS Os,
6108 IN gctPOINTER Semaphore
6111 gcmkHEADER_ARG("Os=0x%X Semaphore=0x%X", Os, Semaphore);
6113 /* Verify the arguments. */
6114 gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
6115 gcmkVERIFY_ARGUMENT(Semaphore != gcvNULL);
6117 /* Free the sempahore structure. */
6118 kfree(Semaphore);
6120 /* Success. */
6121 gcmkFOOTER_NO();
6122 return gcvSTATUS_OK;
6125 /*******************************************************************************
6127 ** gckOS_GetProcessID
6129 ** Get current process ID.
6131 ** INPUT:
6133 ** Nothing.
6135 ** OUTPUT:
6137 ** gctUINT32_PTR ProcessID
6138 ** Pointer to the variable that receives the process ID.
6140 gceSTATUS
6141 gckOS_GetProcessID(
6142 OUT gctUINT32_PTR ProcessID
6145 /* Get process ID. */
6146 if (ProcessID != gcvNULL)
6148 *ProcessID = _GetProcessID();
6151 /* Success. */
6152 return gcvSTATUS_OK;
6155 /*******************************************************************************
6157 ** gckOS_GetThreadID
6159 ** Get current thread ID.
6161 ** INPUT:
6163 ** Nothing.
6165 ** OUTPUT:
6167 ** gctUINT32_PTR ThreadID
6168 ** Pointer to the variable that receives the thread ID.
6170 gceSTATUS
6171 gckOS_GetThreadID(
6172 OUT gctUINT32_PTR ThreadID
6175 /* Get thread ID. */
6176 if (ThreadID != gcvNULL)
6178 *ThreadID = _GetThreadID();
6181 /* Success. */
6182 return gcvSTATUS_OK;
6185 /*******************************************************************************
6187 ** gckOS_SetGPUPower
6189 ** Set the power of the GPU on or off.
6191 ** INPUT:
6193 ** gckOS Os
6194 ** Pointer to a gckOS object.
6196 ** gctBOOL Clock
6197 ** gcvTRUE to turn on the clock, or gcvFALSE to turn off the clock.
6199 ** gctBOOL Power
6200 ** gcvTRUE to turn on the power, or gcvFALSE to turn off the power.
6202 ** OUTPUT:
6204 ** Nothing.
6206 gceSTATUS
6207 gckOS_SetGPUPower(
6208 IN gckOS Os,
6209 IN gctBOOL Clock,
6210 IN gctBOOL Power
6213 gcmkHEADER_ARG("Os=0x%X Clock=%d Power=%d", Os, Clock, Power);
6215 /* TODO: Put your code here. */
6217 gcmkFOOTER_NO();
6218 return gcvSTATUS_OK;
6221 /*----------------------------------------------------------------------------*/
6222 /*----- Profile --------------------------------------------------------------*/
6224 gceSTATUS
6225 gckOS_GetProfileTick(
6226 OUT gctUINT64_PTR Tick
6229 struct timespec time;
6231 ktime_get_ts(&time);
6233 *Tick = time.tv_nsec + time.tv_sec * 1000000000ULL;
6235 return gcvSTATUS_OK;
6238 gceSTATUS
6239 gckOS_QueryProfileTickRate(
6240 OUT gctUINT64_PTR TickRate
6243 struct timespec res;
6245 hrtimer_get_res(CLOCK_MONOTONIC, &res);
6247 *TickRate = res.tv_nsec + res.tv_sec * 1000000000ULL;
6249 return gcvSTATUS_OK;
6252 gctUINT32
6253 gckOS_ProfileToMS(
6254 IN gctUINT64 Ticks
6257 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,23)
6258 return div_u64(Ticks, 1000000);
6259 #else
6260 gctUINT64 rem = Ticks;
6261 gctUINT64 b = 1000000;
6262 gctUINT64 res, d = 1;
6263 gctUINT32 high = rem >> 32;
6265 /* Reduce the thing a bit first */
6266 res = 0;
6267 if (high >= 1000000)
6269 high /= 1000000;
6270 res = (gctUINT64) high << 32;
6271 rem -= (gctUINT64) (high * 1000000) << 32;
6274 while (((gctINT64) b > 0) && (b < rem))
6276 b <<= 1;
6277 d <<= 1;
6282 if (rem >= b)
6284 rem -= b;
6285 res += d;
6288 b >>= 1;
6289 d >>= 1;
6291 while (d);
6293 return (gctUINT32) res;
6294 #endif
6297 #if gcdENABLE_BANK_ALIGNMENT
6298 /*******************************************************************************
6299 ** gckOS_GetSurfaceBankAlignment
6301 ** Return the required offset alignment required to the make BaseAddress
6302 ** aligned properly.
6304 ** INPUT:
6306 ** gckOS Os
6307 ** Pointer to gcoOS object.
6309 ** gceSURF_TYPE Type
6310 ** Type of allocation.
6312 ** gctUINT32 BaseAddress
6313 ** Base address of current video memory node.
6315 ** OUTPUT:
6317 ** gctUINT32_PTR Alignment
6318 ** Pointer to a variable thah twil hold the number of bytes to skip in
6319 ** the current video memory node in order to make the alignment bank
6320 ** aligned.
6322 gceSTATUS
6323 gckOS_GetSurfaceBankAlignment(
6324 IN gckOS Os,
6325 IN gceSURF_TYPE Type,
6326 IN gctUINT32 BaseAddress,
6327 OUT gctUINT32_PTR Alignment
6330 gctUINT32 alignedBaseAddress;
6332 gcmkHEADER_ARG("Os=0x%x Type=%d BaseAddress=0x%x ", Os, Type, BaseAddress);
6334 /* Verify the arguments. */
6335 gcmkVERIFY_ARGUMENT(Alignment != gcvNULL);
6337 switch (Type)
6339 case gcvSURF_RENDER_TARGET:
6340 /* Align to first 4kB bank. */
6341 alignedBaseAddress = (((BaseAddress >> 15) << 3) + (0x8 + 0x0)) << 12;
6342 break;
6344 case gcvSURF_DEPTH:
6345 /* Align to third 4kB bank. */
6346 alignedBaseAddress = (((BaseAddress >> 15) << 3) + (0x8 + 0x2)) << 12;
6348 /* Add 64-byte offset to change channel bit 6. */
6349 alignedBaseAddress += 64;
6350 break;
6352 default:
6353 /* no alignment needed. */
6354 alignedBaseAddress = BaseAddress;
6357 /* Return alignment. */
6358 *Alignment = alignedBaseAddress - BaseAddress;
6360 /* Return the status. */
6361 gcmkFOOTER_ARG("*Alignment=%u", *Alignment);
6362 return gcvSTATUS_OK;
6364 #endif
6366 /******************************************************************************\
6367 ******************************* Signal Management ******************************
6368 \******************************************************************************/
6370 #undef _GC_OBJ_ZONE
6371 #define _GC_OBJ_ZONE gcvZONE_SIGNAL
6373 /*******************************************************************************
6375 ** gckOS_CreateSignal
6377 ** Create a new signal.
6379 ** INPUT:
6381 ** gckOS Os
6382 ** Pointer to an gckOS object.
6384 ** gctBOOL ManualReset
6385 ** If set to gcvTRUE, gckOS_Signal with gcvFALSE must be called in
6386 ** order to set the signal to nonsignaled state.
6387 ** If set to gcvFALSE, the signal will automatically be set to
6388 ** nonsignaled state by gckOS_WaitSignal function.
6390 ** OUTPUT:
6392 ** gctSIGNAL * Signal
6393 ** Pointer to a variable receiving the created gctSIGNAL.
6395 gceSTATUS
6396 gckOS_CreateSignal(
6397 IN gckOS Os,
6398 IN gctBOOL ManualReset,
6399 OUT gctSIGNAL * Signal
6402 gcsSIGNAL_PTR signal;
6404 gcmkHEADER_ARG("Os=0x%X ManualReset=%d", Os, ManualReset);
6406 /* Verify the arguments. */
6407 gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
6408 gcmkVERIFY_ARGUMENT(Signal != gcvNULL);
6410 /* Create an event structure. */
6411 signal = (gcsSIGNAL_PTR) kmalloc(sizeof(gcsSIGNAL), GFP_KERNEL);
6413 if (signal == gcvNULL)
6415 gcmkFOOTER_ARG("status=%d", gcvSTATUS_OUT_OF_MEMORY);
6416 return gcvSTATUS_OUT_OF_MEMORY;
6419 signal->manualReset = ManualReset;
6420 init_completion(&signal->obj);
6421 atomic_set(&signal->ref, 1);
6423 *Signal = (gctSIGNAL) signal;
6425 gcmkFOOTER_ARG("*Signal=0x%X", *Signal);
6426 return gcvSTATUS_OK;
6429 /*******************************************************************************
6431 ** gckOS_DestroySignal
6433 ** Destroy a signal.
6435 ** INPUT:
6437 ** gckOS Os
6438 ** Pointer to an gckOS object.
6440 ** gctSIGNAL Signal
6441 ** Pointer to the gctSIGNAL.
6443 ** OUTPUT:
6445 ** Nothing.
6447 gceSTATUS
6448 gckOS_DestroySignal(
6449 IN gckOS Os,
6450 IN gctSIGNAL Signal
6453 gcsSIGNAL_PTR signal;
6455 gcmkHEADER_ARG("Os=0x%X Signal=0x%X", Os, Signal);
6457 /* Verify the arguments. */
6458 gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
6459 gcmkVERIFY_ARGUMENT(Signal != gcvNULL);
6461 signal = (gcsSIGNAL_PTR) Signal;
6463 if (atomic_dec_and_test(&signal->ref))
6465 /* Free the sgianl. */
6466 kfree(Signal);
6469 /* Success. */
6470 gcmkFOOTER_NO();
6471 return gcvSTATUS_OK;
6474 /*******************************************************************************
6476 ** gckOS_Signal
6478 ** Set a state of the specified signal.
6480 ** INPUT:
6482 ** gckOS Os
6483 ** Pointer to an gckOS object.
6485 ** gctSIGNAL Signal
6486 ** Pointer to the gctSIGNAL.
6488 ** gctBOOL State
6489 ** If gcvTRUE, the signal will be set to signaled state.
6490 ** If gcvFALSE, the signal will be set to nonsignaled state.
6492 ** OUTPUT:
6494 ** Nothing.
6496 gceSTATUS
6497 gckOS_Signal(
6498 IN gckOS Os,
6499 IN gctSIGNAL Signal,
6500 IN gctBOOL State
6503 gcsSIGNAL_PTR signal;
6505 gcmkHEADER_ARG("Os=0x%X Signal=0x%X State=%d", Os, Signal, State);
6507 /* Verify the arguments. */
6508 gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
6509 gcmkVERIFY_ARGUMENT(Signal != gcvNULL);
6511 signal = (gcsSIGNAL_PTR) Signal;
6513 if (State)
6515 /* Set the event to a signaled state. */
6516 complete(&signal->obj);
6518 else
6520 /* Set the event to an unsignaled state. */
6521 INIT_COMPLETION(signal->obj);
6524 /* Success. */
6525 gcmkFOOTER_NO();
6526 return gcvSTATUS_OK;
6529 #if gcdENABLE_VG
6530 gceSTATUS
6531 gckOS_SetSignalVG(
6532 IN gckOS Os,
6533 IN gctHANDLE Process,
6534 IN gctSIGNAL Signal
6537 gceSTATUS status;
6538 gctINT result;
6539 struct task_struct * userTask;
6540 struct siginfo info;
6542 userTask = FIND_TASK_BY_PID((pid_t) Process);
6544 if (userTask != gcvNULL)
6546 info.si_signo = 48;
6547 info.si_code = __SI_CODE(__SI_RT, SI_KERNEL);
6548 info.si_pid = 0;
6549 info.si_uid = 0;
6550 info.si_ptr = (gctPOINTER) Signal;
6552 /* Signals with numbers between 32 and 63 are real-time,
6553 send a real-time signal to the user process. */
6554 result = send_sig_info(48, &info, userTask);
6556 printk("gckOS_SetSignalVG:0x%x\n", result);
6557 /* Error? */
6558 if (result < 0)
6560 status = gcvSTATUS_GENERIC_IO;
6562 gcmkTRACE(
6563 gcvLEVEL_ERROR,
6564 "%s(%d): an error has occurred.\n",
6565 __FUNCTION__, __LINE__
6568 else
6570 status = gcvSTATUS_OK;
6573 else
6575 status = gcvSTATUS_GENERIC_IO;
6577 gcmkTRACE(
6578 gcvLEVEL_ERROR,
6579 "%s(%d): an error has occurred.\n",
6580 __FUNCTION__, __LINE__
6584 /* Return status. */
6585 return status;
6587 #endif
6589 /*******************************************************************************
6591 ** gckOS_UserSignal
6593 ** Set the specified signal which is owned by a process to signaled state.
6595 ** INPUT:
6597 ** gckOS Os
6598 ** Pointer to an gckOS object.
6600 ** gctSIGNAL Signal
6601 ** Pointer to the gctSIGNAL.
6603 ** gctHANDLE Process
6604 ** Handle of process owning the signal.
6606 ** OUTPUT:
6608 ** Nothing.
6610 gceSTATUS
6611 gckOS_UserSignal(
6612 IN gckOS Os,
6613 IN gctSIGNAL Signal,
6614 IN gctHANDLE Process
6617 gceSTATUS status;
6618 gctSIGNAL signal;
6620 gcmkHEADER_ARG("Os=0x%X Signal=0x%X Process=%d",
6621 Os, Signal, (gctINT32) Process);
6623 /* Map the signal into kernel space. */
6624 gcmkONERROR(gckOS_MapSignal(Os, Signal, Process, &signal));
6626 /* Signal. */
6627 status = gckOS_Signal(Os, signal, gcvTRUE);
6629 /* Unmap the signal */
6630 gcmkVERIFY_OK(gckOS_UnmapSignal(Os, Signal));
6632 gcmkFOOTER();
6633 return status;
6635 OnError:
6636 /* Return the status. */
6637 gcmkFOOTER();
6638 return status;
6641 /*******************************************************************************
6643 ** gckOS_WaitSignal
6645 ** Wait for a signal to become signaled.
6647 ** INPUT:
6649 ** gckOS Os
6650 ** Pointer to an gckOS object.
6652 ** gctSIGNAL Signal
6653 ** Pointer to the gctSIGNAL.
6655 ** gctUINT32 Wait
6656 ** Number of milliseconds to wait.
6657 ** Pass the value of gcvINFINITE for an infinite wait.
6659 ** OUTPUT:
6661 ** Nothing.
6663 gceSTATUS
6664 gckOS_WaitSignal(
6665 IN gckOS Os,
6666 IN gctSIGNAL Signal,
6667 IN gctUINT32 Wait
6670 gceSTATUS status = gcvSTATUS_OK;
6671 gcsSIGNAL_PTR signal;
6673 gcmkHEADER_ARG("Os=0x%X Signal=0x%X Wait=0x%08X", Os, Signal, Wait);
6675 /* Verify the arguments. */
6676 gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
6677 gcmkVERIFY_ARGUMENT(Signal != gcvNULL);
6679 signal = (gcsSIGNAL_PTR) Signal;
6681 might_sleep();
6683 spin_lock_irq(&signal->obj.wait.lock);
6685 if (signal->obj.done)
6687 if (!signal->manualReset)
6689 signal->obj.done = 0;
6692 status = gcvSTATUS_OK;
6694 else if (Wait == 0)
6696 status = gcvSTATUS_TIMEOUT;
6698 else
6700 /* Convert wait to milliseconds. */
6701 #if gcdDETECT_TIMEOUT
6702 gctINT timeout = (Wait == gcvINFINITE)
6703 ? gcdINFINITE_TIMEOUT * HZ / 1000
6704 : Wait * HZ / 1000;
6706 gctUINT complained = 0;
6707 #else
6708 gctINT timeout = (Wait == gcvINFINITE)
6709 ? MAX_SCHEDULE_TIMEOUT
6710 : Wait * HZ / 1000;
6711 #endif
6713 DECLARE_WAITQUEUE(wait, current);
6714 wait.flags |= WQ_FLAG_EXCLUSIVE;
6715 __add_wait_queue_tail(&signal->obj.wait, &wait);
6717 while (gcvTRUE)
6719 if (signal_pending(current))
6721 /* Interrupt received. */
6722 status = gcvSTATUS_INTERRUPTED;
6723 break;
6726 __set_current_state(TASK_INTERRUPTIBLE);
6727 spin_unlock_irq(&signal->obj.wait.lock);
6728 timeout = schedule_timeout(timeout);
6729 spin_lock_irq(&signal->obj.wait.lock);
6731 if (signal->obj.done)
6733 if (!signal->manualReset)
6735 signal->obj.done = 0;
6738 status = gcvSTATUS_OK;
6739 break;
6742 #if gcdDETECT_TIMEOUT
6743 if ((Wait == gcvINFINITE) && (timeout == 0))
6745 gctUINT32 dmaAddress1, dmaAddress2;
6746 gctUINT32 dmaState1, dmaState2;
6748 dmaState1 = dmaState2 =
6749 dmaAddress1 = dmaAddress2 = 0;
6751 /* Verify whether DMA is running. */
6752 gcmkVERIFY_OK(_VerifyDMA(
6753 Os, &dmaAddress1, &dmaAddress2, &dmaState1, &dmaState2
6756 #if gcdDETECT_DMA_ADDRESS
6757 /* Dump only if DMA appears stuck. */
6758 if (
6759 (dmaAddress1 == dmaAddress2)
6760 #if gcdDETECT_DMA_STATE
6761 && (dmaState1 == dmaState2)
6762 #endif
6764 #endif
6766 /* Increment complain count. */
6767 complained += 1;
6769 gcmkVERIFY_OK(_DumpGPUState(Os));
6771 gcmkPRINT(
6772 "%s(%d): signal 0x%X; forced message flush (%d).",
6773 __FUNCTION__, __LINE__, Signal, complained
6776 /* Flush the debug cache. */
6777 gcmkDEBUGFLUSH(dmaAddress2);
6780 /* Reset timeout. */
6781 timeout = gcdINFINITE_TIMEOUT * HZ / 1000;
6783 #endif
6785 if (timeout == 0)
6788 status = gcvSTATUS_TIMEOUT;
6789 break;
6793 __remove_wait_queue(&signal->obj.wait, &wait);
6795 #if gcdDETECT_TIMEOUT
6796 if (complained)
6798 gcmkPRINT(
6799 "%s(%d): signal=0x%X; waiting done; status=%d",
6800 __FUNCTION__, __LINE__, Signal, status
6803 #endif
6806 spin_unlock_irq(&signal->obj.wait.lock);
6808 /* Return status. */
6809 gcmkFOOTER_ARG("Signal=0x%X status=%d", Signal, status);
6810 return status;
6813 /*******************************************************************************
6815 ** gckOS_MapSignal
6817 ** Map a signal in to the current process space.
6819 ** INPUT:
6821 ** gckOS Os
6822 ** Pointer to an gckOS object.
6824 ** gctSIGNAL Signal
6825 ** Pointer to tha gctSIGNAL to map.
6827 ** gctHANDLE Process
6828 ** Handle of process owning the signal.
6830 ** OUTPUT:
6832 ** gctSIGNAL * MappedSignal
6833 ** Pointer to a variable receiving the mapped gctSIGNAL.
6835 gceSTATUS
6836 gckOS_MapSignal(
6837 IN gckOS Os,
6838 IN gctSIGNAL Signal,
6839 IN gctHANDLE Process,
6840 OUT gctSIGNAL * MappedSignal
6843 gctINT signalID;
6844 gcsSIGNAL_PTR signal;
6845 gceSTATUS status;
6846 gctBOOL acquired = gcvFALSE;
6848 gcmkHEADER_ARG("Os=0x%X Signal=0x%X Process=0x%X", Os, Signal, Process);
6850 gcmkVERIFY_ARGUMENT(Signal != gcvNULL);
6851 gcmkVERIFY_ARGUMENT(MappedSignal != gcvNULL);
6853 signalID = (gctINT) Signal - 1;
6855 gcmkONERROR(gckOS_AcquireMutex(Os, Os->signal.lock, gcvINFINITE));
6856 acquired = gcvTRUE;
6858 if (signalID >= 0 && signalID < Os->signal.tableLen)
6860 /* It is a user space signal. */
6861 signal = Os->signal.table[signalID];
6863 if (signal == gcvNULL)
6865 gcmkONERROR(gcvSTATUS_NOT_FOUND);
6868 else
6870 /* It is a kernel space signal structure. */
6871 signal = (gcsSIGNAL_PTR) Signal;
6874 if (atomic_inc_return(&signal->ref) <= 1)
6876 /* The previous value is 0, it has been deleted. */
6877 gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
6880 /* Release the mutex. */
6881 gcmkONERROR(gckOS_ReleaseMutex(Os, Os->signal.lock));
6883 *MappedSignal = (gctSIGNAL) signal;
6885 /* Success. */
6886 gcmkFOOTER_ARG("*MappedSignal=0x%X", *MappedSignal);
6887 return gcvSTATUS_OK;
6889 OnError:
6890 if (acquired)
6892 /* Release the mutex. */
6893 gcmkVERIFY_OK(gckOS_ReleaseMutex(Os, Os->signal.lock));
6896 /* Return the staus. */
6897 gcmkFOOTER();
6898 return status;
6901 /*******************************************************************************
6903 ** gckOS_UnmapSignal
6905 ** Unmap a signal .
6907 ** INPUT:
6909 ** gckOS Os
6910 ** Pointer to an gckOS object.
6912 ** gctSIGNAL Signal
6913 ** Pointer to that gctSIGNAL mapped.
6915 gceSTATUS
6916 gckOS_UnmapSignal(
6917 IN gckOS Os,
6918 IN gctSIGNAL Signal
6921 gctINT signalID;
6922 gcsSIGNAL_PTR signal;
6923 gceSTATUS status;
6924 gctBOOL acquired = gcvFALSE;
6926 gcmkHEADER_ARG("Os=0x%X Signal=0x%X ", Os, Signal);
6928 gcmkVERIFY_ARGUMENT(Signal != gcvNULL);
6930 signalID = (gctINT) Signal - 1;
6932 gcmkONERROR(gckOS_AcquireMutex(Os, Os->signal.lock, gcvINFINITE));
6933 acquired = gcvTRUE;
6935 if (signalID >= 0 && signalID < Os->signal.tableLen)
6937 /* It is a user space signal. */
6938 signal = Os->signal.table[signalID];
6940 if (signal == gcvNULL)
6942 gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
6945 if (atomic_read(&signal->ref) == 1)
6947 /* Update the table. */
6948 Os->signal.table[signalID] = gcvNULL;
6950 if (Os->signal.unused++ == 0)
6952 Os->signal.currentID = signalID;
6956 gcmkONERROR(gckOS_DestroySignal(Os, signal));
6958 else
6960 /* It is a kernel space signal structure. */
6961 signal = (gcsSIGNAL_PTR) Signal;
6963 gcmkONERROR(gckOS_DestroySignal(Os, signal));
6966 /* Release the mutex. */
6967 gcmkONERROR(gckOS_ReleaseMutex(Os, Os->signal.lock));
6969 /* Success. */
6970 gcmkFOOTER();
6971 return gcvSTATUS_OK;
6973 OnError:
6974 if (acquired)
6976 /* Release the mutex. */
6977 gcmkVERIFY_OK(gckOS_ReleaseMutex(Os, Os->signal.lock));
6980 /* Return the staus. */
6981 gcmkFOOTER();
6982 return status;
6985 /*******************************************************************************
6987 ** gckOS_CreateUserSignal
6989 ** Create a new signal to be used in the user space.
6991 ** INPUT:
6993 ** gckOS Os
6994 ** Pointer to an gckOS object.
6996 ** gctBOOL ManualReset
6997 ** If set to gcvTRUE, gckOS_Signal with gcvFALSE must be called in
6998 ** order to set the signal to nonsignaled state.
6999 ** If set to gcvFALSE, the signal will automatically be set to
7000 ** nonsignaled state by gckOS_WaitSignal function.
7002 ** OUTPUT:
7004 ** gctINT * SignalID
7005 ** Pointer to a variable receiving the created signal's ID.
7007 gceSTATUS
7008 gckOS_CreateUserSignal(
7009 IN gckOS Os,
7010 IN gctBOOL ManualReset,
7011 OUT gctINT * SignalID
7014 gcsSIGNAL_PTR signal = gcvNULL;
7015 gctINT unused, currentID, tableLen;
7016 gctPOINTER * table;
7017 gctINT i;
7018 gceSTATUS status;
7019 gctBOOL acquired = gcvFALSE;
7021 gcmkHEADER_ARG("Os=0x%0x ManualReset=%d", Os, ManualReset);
7023 /* Verify the arguments. */
7024 gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
7025 gcmkVERIFY_ARGUMENT(SignalID != gcvNULL);
7027 /* Lock the table. */
7028 gcmkONERROR(gckOS_AcquireMutex(Os, Os->signal.lock, gcvINFINITE));
7030 acquired = gcvTRUE;
7032 if (Os->signal.unused < 1)
7034 /* Enlarge the table. */
7035 table = (gctPOINTER *) kmalloc(
7036 sizeof(gctPOINTER) * (Os->signal.tableLen + USER_SIGNAL_TABLE_LEN_INIT),
7037 GFP_KERNEL);
7039 if (table == gcvNULL)
7041 /* Out of memory. */
7042 gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
7045 memset(table + Os->signal.tableLen, 0, sizeof(gctPOINTER) * USER_SIGNAL_TABLE_LEN_INIT);
7046 memcpy(table, Os->signal.table, sizeof(gctPOINTER) * Os->signal.tableLen);
7048 /* Release the old table. */
7049 kfree(Os->signal.table);
7051 /* Update the table. */
7052 Os->signal.table = table;
7053 Os->signal.currentID = Os->signal.tableLen;
7054 Os->signal.tableLen += USER_SIGNAL_TABLE_LEN_INIT;
7055 Os->signal.unused += USER_SIGNAL_TABLE_LEN_INIT;
7058 table = Os->signal.table;
7059 currentID = Os->signal.currentID;
7060 tableLen = Os->signal.tableLen;
7061 unused = Os->signal.unused;
7063 /* Create a new signal. */
7064 gcmkONERROR(
7065 gckOS_CreateSignal(Os, ManualReset, (gctSIGNAL *) &signal));
7067 /* Save the process ID. */
7068 signal->process = (gctHANDLE) _GetProcessID();
7070 table[currentID] = signal;
7072 /* Plus 1 to avoid gcvNULL claims. */
7073 *SignalID = currentID + 1;
7075 /* Update the currentID. */
7076 if (--unused > 0)
7078 for (i = 0; i < tableLen; i++)
7080 if (++currentID >= tableLen)
7082 /* Wrap to the begin. */
7083 currentID = 0;
7086 if (table[currentID] == gcvNULL)
7088 break;
7093 Os->signal.table = table;
7094 Os->signal.currentID = currentID;
7095 Os->signal.tableLen = tableLen;
7096 Os->signal.unused = unused;
7098 gcmkONERROR(
7099 gckOS_ReleaseMutex(Os, Os->signal.lock));
7101 gcmkFOOTER_ARG("*SignalID=%d", gcmOPT_VALUE(SignalID));
7102 return gcvSTATUS_OK;
7104 OnError:
7105 if (acquired)
7107 /* Release the mutex. */
7108 gcmkONERROR(
7109 gckOS_ReleaseMutex(Os, Os->signal.lock));
7112 /* Return the staus. */
7113 gcmkFOOTER();
7114 return status;
7117 /*******************************************************************************
7119 ** gckOS_DestroyUserSignal
7121 ** Destroy a signal to be used in the user space.
7123 ** INPUT:
7125 ** gckOS Os
7126 ** Pointer to an gckOS object.
7128 ** gctINT SignalID
7129 ** The signal's ID.
7131 ** OUTPUT:
7133 ** Nothing.
7135 gceSTATUS
7136 gckOS_DestroyUserSignal(
7137 IN gckOS Os,
7138 IN gctINT SignalID
7141 gceSTATUS status;
7142 gcsSIGNAL_PTR signal;
7143 gctBOOL acquired = gcvFALSE;
7145 gcmkHEADER_ARG("Os=0x%X SignalID=%d", Os, SignalID);
7147 /* Verify the arguments. */
7148 gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
7150 gcmkONERROR(
7151 gckOS_AcquireMutex(Os, Os->signal.lock, gcvINFINITE));
7153 acquired = gcvTRUE;
7155 if (SignalID < 1 || SignalID > Os->signal.tableLen)
7157 gcmkTRACE(
7158 gcvLEVEL_ERROR,
7159 "%s(%d): invalid signal->%d.",
7160 __FUNCTION__, __LINE__,
7161 (gctINT) SignalID
7164 gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
7167 SignalID -= 1;
7169 signal = Os->signal.table[SignalID];
7171 if (signal == gcvNULL)
7173 gcmkTRACE(
7174 gcvLEVEL_ERROR,
7175 "%s(%d): signal is gcvNULL.",
7176 __FUNCTION__, __LINE__
7179 gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
7183 if (atomic_read(&signal->ref) == 1)
7185 /* Update the table. */
7186 Os->signal.table[SignalID] = gcvNULL;
7188 if (Os->signal.unused++ == 0)
7190 Os->signal.currentID = SignalID;
7194 gcmkONERROR(
7195 gckOS_DestroySignal(Os, signal));
7197 gcmkVERIFY_OK(
7198 gckOS_ReleaseMutex(Os, Os->signal.lock));
7200 /* Success. */
7201 gcmkFOOTER_NO();
7202 return gcvSTATUS_OK;
7204 OnError:
7205 if (acquired)
7207 /* Release the mutex. */
7208 gcmkVERIFY_OK(
7209 gckOS_ReleaseMutex(Os, Os->signal.lock));
7212 /* Return the status. */
7213 gcmkFOOTER();
7214 return status;
7217 /*******************************************************************************
7219 ** gckOS_WaitUserSignal
7221 ** Wait for a signal used in the user mode to become signaled.
7223 ** INPUT:
7225 ** gckOS Os
7226 ** Pointer to an gckOS object.
7228 ** gctINT SignalID
7229 ** Signal ID.
7231 ** gctUINT32 Wait
7232 ** Number of milliseconds to wait.
7233 ** Pass the value of gcvINFINITE for an infinite wait.
7235 ** OUTPUT:
7237 ** Nothing.
7239 gceSTATUS
7240 gckOS_WaitUserSignal(
7241 IN gckOS Os,
7242 IN gctINT SignalID,
7243 IN gctUINT32 Wait
7246 gceSTATUS status;
7247 gcsSIGNAL_PTR signal;
7248 gctBOOL acquired = gcvFALSE;
7250 gcmkHEADER_ARG("Os=0x%X SignalID=%d Wait=%u", Os, SignalID, Wait);
7252 /* Verify the arguments. */
7253 gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
7255 gcmkONERROR(gckOS_AcquireMutex(Os, Os->signal.lock, gcvINFINITE));
7256 acquired = gcvTRUE;
7258 if (SignalID < 1 || SignalID > Os->signal.tableLen)
7260 gcmkTRACE(
7261 gcvLEVEL_ERROR,
7262 "%s(%d): invalid signal %d",
7263 __FUNCTION__, __LINE__,
7264 SignalID
7267 gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
7270 SignalID -= 1;
7272 signal = Os->signal.table[SignalID];
7274 gcmkONERROR(gckOS_ReleaseMutex(Os, Os->signal.lock));
7275 acquired = gcvFALSE;
7277 if (signal == gcvNULL)
7279 gcmkTRACE(
7280 gcvLEVEL_ERROR,
7281 "%s(%d): signal is gcvNULL.",
7282 __FUNCTION__, __LINE__
7285 gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
7289 status = gckOS_WaitSignal(Os, signal, Wait);
7291 /* Return the status. */
7292 gcmkFOOTER();
7293 return status;
7295 OnError:
7296 if (acquired)
7298 /* Release the mutex. */
7299 gcmkVERIFY_OK(gckOS_ReleaseMutex(Os, Os->signal.lock));
7302 /* Return the staus. */
7303 gcmkFOOTER();
7304 return status;
7307 /*******************************************************************************
7309 ** gckOS_SignalUserSignal
7311 ** Set a state of the specified signal to be used in the user space.
7313 ** INPUT:
7315 ** gckOS Os
7316 ** Pointer to an gckOS object.
7318 ** gctINT SignalID
7319 ** SignalID.
7321 ** gctBOOL State
7322 ** If gcvTRUE, the signal will be set to signaled state.
7323 ** If gcvFALSE, the signal will be set to nonsignaled state.
7325 ** OUTPUT:
7327 ** Nothing.
7329 gceSTATUS
7330 gckOS_SignalUserSignal(
7331 IN gckOS Os,
7332 IN gctINT SignalID,
7333 IN gctBOOL State
7336 gceSTATUS status;
7337 gcsSIGNAL_PTR signal;
7338 gctBOOL acquired = gcvFALSE;
7340 gcmkHEADER_ARG("Os=0x%X SignalID=%d State=%d", Os, SignalID, State);
7342 /* Verify the arguments. */
7343 gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
7345 gcmkONERROR(gckOS_AcquireMutex(Os, Os->signal.lock, gcvINFINITE));
7346 acquired = gcvTRUE;
7348 if ((SignalID < 1)
7349 || (SignalID > Os->signal.tableLen)
7352 gcmkTRACE(
7353 gcvLEVEL_ERROR,
7354 "%s(%d): invalid signal->%d.",
7355 __FUNCTION__, __LINE__,
7356 SignalID
7359 gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
7362 SignalID -= 1;
7364 signal = Os->signal.table[SignalID];
7366 gcmkONERROR(gckOS_ReleaseMutex(Os, Os->signal.lock));
7367 acquired = gcvFALSE;
7369 if (signal == gcvNULL)
7371 gcmkTRACE(
7372 gcvLEVEL_ERROR,
7373 "%s(%d): signal is gcvNULL.",
7374 __FUNCTION__, __LINE__
7377 gcmkONERROR(gcvSTATUS_INVALID_REQUEST);
7381 status = gckOS_Signal(Os, signal, State);
7383 /* Success. */
7384 gcmkFOOTER();
7385 return status;
7387 OnError:
7388 if (acquired)
7390 /* Release the mutex. */
7391 gcmkVERIFY_OK(
7392 gckOS_ReleaseMutex(Os, Os->signal.lock));
7395 /* Return the staus. */
7396 gcmkFOOTER();
7397 return status;
7400 gceSTATUS
7401 gckOS_CleanProcessSignal(
7402 gckOS Os,
7403 gctHANDLE Process
7406 gctINT signal;
7408 gcmkHEADER_ARG("Os=0x%X Process=%d", Os, Process);
7410 gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
7412 gcmkVERIFY_OK(gckOS_AcquireMutex(Os,
7413 Os->signal.lock,
7414 gcvINFINITE
7417 if (Os->signal.unused == Os->signal.tableLen)
7419 gcmkVERIFY_OK(gckOS_ReleaseMutex(Os,
7420 Os->signal.lock
7423 gcmkFOOTER_NO();
7424 return gcvSTATUS_OK;
7427 for (signal = 0; signal < Os->signal.tableLen; signal++)
7429 if (Os->signal.table[signal] != gcvNULL &&
7430 ((gcsSIGNAL_PTR)Os->signal.table[signal])->process == Process)
7432 gckOS_DestroySignal(Os, Os->signal.table[signal]);
7434 /* Update the signal table. */
7435 Os->signal.table[signal] = gcvNULL;
7436 if (Os->signal.unused++ == 0)
7438 Os->signal.currentID = signal;
7443 gcmkVERIFY_OK(gckOS_ReleaseMutex(Os,
7444 Os->signal.lock
7447 gcmkFOOTER_NO();
7448 return gcvSTATUS_OK;
7451 #if gcdENABLE_VG
7452 gceSTATUS
7453 gckOS_CreateSemaphoreVG(
7454 IN gckOS Os,
7455 OUT gctSEMAPHORE * Semaphore
7458 gceSTATUS status;
7459 struct semaphore * newSemaphore;
7461 gcmkHEADER_ARG("Os=0x%X Semaphore=0x%x", Os, Semaphore);
7462 /* Verify the arguments. */
7463 gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
7464 gcmkVERIFY_ARGUMENT(Semaphore != gcvNULL);
7468 /* Allocate the semaphore structure. */
7469 newSemaphore = (struct semaphore *)kmalloc(gcmSIZEOF(struct semaphore), GFP_KERNEL);
7470 if (newSemaphore == gcvNULL)
7472 gcmkERR_BREAK(gcvSTATUS_OUT_OF_MEMORY);
7475 /* Initialize the semaphore. */
7476 sema_init(newSemaphore, 0);
7478 /* Set the handle. */
7479 * Semaphore = (gctSEMAPHORE) newSemaphore;
7481 /* Success. */
7482 status = gcvSTATUS_OK;
7484 while (gcvFALSE);
7486 gcmkFOOTER();
7487 /* Return the status. */
7488 return status;
7492 gceSTATUS
7493 gckOS_IncrementSemaphore(
7494 IN gckOS Os,
7495 IN gctSEMAPHORE Semaphore
7498 gcmkHEADER_ARG("Os=0x%X Semaphore=0x%x", Os, Semaphore);
7499 /* Verify the arguments. */
7500 gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
7501 gcmkVERIFY_ARGUMENT(Semaphore != gcvNULL);
7503 /* Increment the semaphore's count. */
7504 up((struct semaphore *) Semaphore);
7506 gcmkFOOTER_NO();
7507 /* Success. */
7508 return gcvSTATUS_OK;
7511 gceSTATUS
7512 gckOS_DecrementSemaphore(
7513 IN gckOS Os,
7514 IN gctSEMAPHORE Semaphore
7517 gceSTATUS status;
7518 gctINT result;
7520 gcmkHEADER_ARG("Os=0x%X Semaphore=0x%x", Os, Semaphore);
7521 /* Verify the arguments. */
7522 gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
7523 gcmkVERIFY_ARGUMENT(Semaphore != gcvNULL);
7527 /* Decrement the semaphore's count. If the count is zero, wait
7528 until it gets incremented. */
7529 result = down_interruptible((struct semaphore *) Semaphore);
7531 /* Signal received? */
7532 if (result != 0)
7534 status = gcvSTATUS_TERMINATE;
7535 break;
7538 /* Success. */
7539 status = gcvSTATUS_OK;
7541 while (gcvFALSE);
7543 gcmkFOOTER();
7544 /* Return the status. */
7545 return status;
7548 /*******************************************************************************
7550 ** gckOS_SetSignal
7552 ** Set the specified signal to signaled state.
7554 ** INPUT:
7556 ** gckOS Os
7557 ** Pointer to the gckOS object.
7559 ** gctHANDLE Process
7560 ** Handle of process owning the signal.
7562 ** gctSIGNAL Signal
7563 ** Pointer to the gctSIGNAL.
7565 ** OUTPUT:
7567 ** Nothing.
7569 gceSTATUS
7570 gckOS_SetSignal(
7571 IN gckOS Os,
7572 IN gctHANDLE Process,
7573 IN gctSIGNAL Signal
7576 gceSTATUS status;
7577 gctINT result;
7578 struct task_struct * userTask;
7579 struct siginfo info;
7581 userTask = FIND_TASK_BY_PID((pid_t) Process);
7583 if (userTask != gcvNULL)
7585 info.si_signo = 48;
7586 info.si_code = __SI_CODE(__SI_RT, SI_KERNEL);
7587 info.si_pid = 0;
7588 info.si_uid = 0;
7589 info.si_ptr = (gctPOINTER) Signal;
7591 /* Signals with numbers between 32 and 63 are real-time,
7592 send a real-time signal to the user process. */
7593 result = send_sig_info(48, &info, userTask);
7595 /* Error? */
7596 if (result < 0)
7598 status = gcvSTATUS_GENERIC_IO;
7600 gcmkTRACE(
7601 gcvLEVEL_ERROR,
7602 "%s(%d): an error has occurred.\n",
7603 __FUNCTION__, __LINE__
7606 else
7608 status = gcvSTATUS_OK;
7611 else
7613 status = gcvSTATUS_GENERIC_IO;
7615 gcmkTRACE(
7616 gcvLEVEL_ERROR,
7617 "%s(%d): an error has occurred.\n",
7618 __FUNCTION__, __LINE__
7622 /* Return status. */
7623 return status;
7626 /******************************************************************************\
7627 ******************************** Thread Object *********************************
7628 \******************************************************************************/
7630 gceSTATUS
7631 gckOS_StartThread(
7632 IN gckOS Os,
7633 IN gctTHREADFUNC ThreadFunction,
7634 IN gctPOINTER ThreadParameter,
7635 OUT gctTHREAD * Thread
7638 gceSTATUS status;
7639 struct task_struct * thread;
7641 gcmkHEADER_ARG("Os=0x%X ", Os);
7642 /* Verify the arguments. */
7643 gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
7644 gcmkVERIFY_ARGUMENT(ThreadFunction != gcvNULL);
7645 gcmkVERIFY_ARGUMENT(Thread != gcvNULL);
7649 /* Create the thread. */
7650 thread = kthread_create(
7651 ThreadFunction,
7652 ThreadParameter,
7653 "Vivante Kernel Thread"
7656 /* Failed? */
7657 if (IS_ERR(thread))
7659 status = gcvSTATUS_GENERIC_IO;
7660 break;
7663 /* Start the thread. */
7664 wake_up_process(thread);
7666 /* Set the thread handle. */
7667 * Thread = (gctTHREAD) thread;
7669 /* Success. */
7670 status = gcvSTATUS_OK;
7672 while (gcvFALSE);
7674 gcmkFOOTER();
7675 /* Return the status. */
7676 return status;
7679 gceSTATUS
7680 gckOS_StopThread(
7681 IN gckOS Os,
7682 IN gctTHREAD Thread
7685 gcmkHEADER_ARG("Os=0x%X Thread=0x%x", Os, Thread);
7686 /* Verify the arguments. */
7687 gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
7688 gcmkVERIFY_ARGUMENT(Thread != gcvNULL);
7690 /* Thread should have already been enabled to terminate. */
7691 kthread_stop((struct task_struct *) Thread);
7693 gcmkFOOTER_NO();
7694 /* Success. */
7695 return gcvSTATUS_OK;
7698 gceSTATUS
7699 gckOS_VerifyThread(
7700 IN gckOS Os,
7701 IN gctTHREAD Thread
7704 gcmkHEADER_ARG("Os=0x%X Thread=0x%x", Os, Thread);
7705 /* Verify the arguments. */
7706 gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
7707 gcmkVERIFY_ARGUMENT(Thread != gcvNULL);
7709 gcmkFOOTER_NO();
7710 /* Success. */
7711 return gcvSTATUS_OK;
7713 #endif