/******************************************************************************* ** ** gckVGMMU_Destroy ** ** Destroy a nAQMMU object. ** ** INPUT: ** ** gckVGMMU Mmu ** Pointer to an gckVGMMU object. ** ** OUTPUT: ** ** Nothing. */ gceSTATUS gckVGMMU_Destroy( IN gckVGMMU Mmu ) { gcmkHEADER_ARG("Mmu=0x%x", Mmu); /* Verify the arguments. */ gcmkVERIFY_OBJECT(Mmu, gcvOBJ_MMU); /* Free the page table. */ gcmkVERIFY_OK(gckOS_FreeContiguous(Mmu->os, Mmu->pageTablePhysical, Mmu->pageTableLogical, Mmu->pageTableSize)); /* Roll back. */ gcmkVERIFY_OK(gckOS_DeleteMutex(Mmu->os, Mmu->mutex)); /* Mark the gckVGMMU object as unknown. */ Mmu->object.type = gcvOBJ_UNKNOWN; /* Free the gckVGMMU object. */ gcmkVERIFY_OK(gckOS_Free(Mmu->os, Mmu)); gcmkFOOTER_NO(); /* Success. */ return gcvSTATUS_OK; }
/******************************************************************************* ** ** gckKERNEL_QueryVideoMemory ** ** Query the amount of video memory. ** ** INPUT: ** ** gckKERNEL Kernel ** Pointer to an gckKERNEL object. ** ** OUTPUT: ** ** gcsHAL_INTERFACE * Interface ** Pointer to an gcsHAL_INTERFACE structure that will be filled in with ** the memory information. */ gceSTATUS gckKERNEL_QueryVideoMemory( IN gckKERNEL Kernel, OUT gcsHAL_INTERFACE * Interface ) { gckGALDEVICE device; gcmkHEADER_ARG("Kernel=%p", Kernel); /* Verify the arguments. */ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); gcmkVERIFY_ARGUMENT(Interface != NULL); /* Extract the pointer to the gckGALDEVICE class. */ device = (gckGALDEVICE) Kernel->context; /* Get internal memory size and physical address. */ Interface->u.QueryVideoMemory.internalSize = device->internalSize; Interface->u.QueryVideoMemory.internalPhysical = device->internalPhysicalName; /* Get external memory size and physical address. */ Interface->u.QueryVideoMemory.externalSize = device->externalSize; Interface->u.QueryVideoMemory.externalPhysical = device->externalPhysicalName; /* Get contiguous memory size and physical address. */ Interface->u.QueryVideoMemory.contiguousSize = device->contiguousSize; Interface->u.QueryVideoMemory.contiguousPhysical = device->contiguousPhysicalName; /* Success. */ gcmkFOOTER_NO(); return gcvSTATUS_OK; }
/******************************************************************************* ** gckKERNEL_GetProcessDBCache ** ** Get teh secure cache from a process database. ** ** INPUT: ** ** gckKERNEL Kernel ** Pointer to a gckKERNEL object. ** ** gctUINT32 ProcessID ** Process ID used to identify the database. ** ** OUTPUT: ** ** gcskSECURE_CACHE_PTR * Cache ** Pointer to a variable that receives the secure cache pointer. */ gceSTATUS gckKERNEL_GetProcessDBCache( IN gckKERNEL Kernel, IN gctUINT32 ProcessID, OUT gcskSECURE_CACHE_PTR * Cache ) { gceSTATUS status; gcsDATABASE_PTR database; gcmkHEADER_ARG("Kernel=0x%x ProcessID=%d", Kernel, ProcessID); /* Verify the arguments. */ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); gcmkVERIFY_ARGUMENT(Cache != gcvNULL); /* Find the database. */ gcmkONERROR(gckKERNEL_FindDatabase(Kernel, ProcessID, gcvFALSE, &database)); /* Return the pointer to the cache. */ *Cache = &database->cache; /* Success. */ gcmkFOOTER_ARG("*Cache=0x%x", *Cache); return gcvSTATUS_OK; OnError: /* Return the status. */ gcmkFOOTER(); return status; }
gceSTATUS gckHEAP_ProfileEnd( IN gckHEAP Heap, IN gctCONST_STRING Title ) { gcmkHEADER_ARG("Heap=0x%x Title=0x%x", Heap, Title); /* Verify the arguments. */ gcmkVERIFY_OBJECT(Heap, gcvOBJ_HEAP); gcmkVERIFY_ARGUMENT(Title != gcvNULL); gcmkPRINT(""); gcmkPRINT("=====[ HEAP - %s ]=====", Title); gcmkPRINT("Number of allocations : %12u", Heap->allocCount); gcmkPRINT("Number of bytes allocated : %12llu", Heap->allocBytes); gcmkPRINT("Maximum allocation size : %12llu", Heap->allocBytesMax); gcmkPRINT("Total number of bytes allocated : %12llu", Heap->allocBytesTotal); gcmkPRINT("Number of heaps : %12u", Heap->heapCount); gcmkPRINT("Heap memory in bytes : %12llu", Heap->heapMemory); gcmkPRINT("Maximum number of heaps : %12u", Heap->heapCountMax); gcmkPRINT("Maximum heap memory in bytes : %12llu", Heap->heapMemoryMax); gcmkPRINT("=============================================="); /* Success. */ gcmkFOOTER_NO(); return gcvSTATUS_OK; }
/******************************************************************************* ** ** gckCOMMAND_Stop ** ** Stop the command queue. ** ** INPUT: ** ** gckCOMMAND Command ** Pointer to an gckCOMMAND object to stop. ** ** OUTPUT: ** ** Nothing. */ gceSTATUS gckCOMMAND_Stop( IN gckCOMMAND Command ) { gckHARDWARE hardware; gceSTATUS status; gctUINT32 idle; gcmkHEADER_ARG("Command=0x%x", Command); /* Verify the arguments. */ gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND); if (!Command->running) { /* Command queue is not running. */ gcmkFOOTER_NO(); return gcvSTATUS_OK; } /* Extract the gckHARDWARE object. */ hardware = Command->kernel->hardware; gcmkVERIFY_OBJECT(hardware, gcvOBJ_HARDWARE); /* Replace last WAIT with END. */ gcmkONERROR( gckHARDWARE_End(hardware, Command->wait, &Command->waitSize)); /* Wait for idle. */ gcmkONERROR( gckHARDWARE_GetIdle(hardware, gcvTRUE, &idle)); /* Command queue is no longer running. */ Command->running = gcvFALSE; /* Success. */ gcmkFOOTER_NO(); return gcvSTATUS_OK; OnError: /* Return the status. */ gcmkFOOTER(); return status; }
/******************************************************************************* ** ** gckVIDMEM_DestroyVirtual ** ** Destroy an gcuVIDMEM_NODE union for virtual memory. ** ** INPUT: ** ** gcuVIDMEM_NODE_PTR Node ** Pointer to a gcuVIDMEM_NODE union. ** ** OUTPUT: ** ** Nothing. */ gceSTATUS gckVIDMEM_DestroyVirtual( IN gcuVIDMEM_NODE_PTR Node ) { gckOS os; gcmkHEADER_ARG("Node=0x%x", Node); /* Verify the arguments. */ gcmkVERIFY_OBJECT(Node->Virtual.kernel, gcvOBJ_KERNEL); /* Extact the gckOS object pointer. */ os = Node->Virtual.kernel->os; gcmkVERIFY_OBJECT(os, gcvOBJ_OS); #ifdef __QNXNTO__ /* Unregister. */ gcmkVERIFY_OK( gckMMU_RemoveNode(Node->Virtual.kernel->mmu, Node)); /* Free virtual memory. */ gcmkVERIFY_OK( gckOS_FreePagedMemory(os, Node->Virtual.physical, Node->Virtual.bytes)); #endif /* Delete the mutex. */ gcmkVERIFY_OK(gckOS_DeleteMutex(os, Node->Virtual.mutex)); if (Node->Virtual.pageTable != gcvNULL) { /* Free the pages. */ gcmkVERIFY_OK(gckMMU_FreePages(Node->Virtual.kernel->mmu, Node->Virtual.pageTable, Node->Virtual.pageCount)); } /* Delete the gcuVIDMEM_NODE union. */ gcmkVERIFY_OK(gckOS_Free(os, Node)); /* Success. */ gcmkFOOTER_NO(); return gcvSTATUS_OK; }
gceSTATUS gckDVFS_Construct( IN gckHARDWARE Hardware, OUT gckDVFS * Dvfs ) { gceSTATUS status = gcvSTATUS_OK; gctPOINTER pointer; gckDVFS dvfs = gcvNULL; gckOS os = Hardware->os; gcmkHEADER_ARG("Hardware=0x%X", Hardware); gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); gcmkVERIFY_ARGUMENT(Dvfs != gcvNULL); /* Allocate a gckDVFS manager. */ gcmkONERROR(gckOS_Allocate(os, gcmSIZEOF(struct _gckDVFS), &pointer)); gckOS_ZeroMemory(pointer, gcmSIZEOF(struct _gckDVFS)); dvfs = pointer; /* Initialization. */ dvfs->hardware = Hardware; dvfs->pollingTime = gcdDVFS_POLLING_TIME; dvfs->os = Hardware->os; dvfs->currentScale = 64; /* Create a polling timer. */ gcmkONERROR(gckOS_CreateTimer(os, _TimerFunction, pointer, &dvfs->timer)); /* Initialize frequency and voltage adjustment helper. */ gcmkONERROR(gckOS_PrepareGPUFrequency(os, Hardware->core)); /* Return result. */ *Dvfs = dvfs; gcmkFOOTER_NO(); return gcvSTATUS_OK; OnError: /* Roll back. */ if (dvfs) { if (dvfs->timer) { gcmkVERIFY_OK(gckOS_DestroyTimer(os, dvfs->timer)); } gcmkOS_SAFE_FREE(os, dvfs); } gcmkFOOTER(); return status; }
/******************************************************************************* ** ** gckVIDMEM_Allocate ** ** Allocate rectangular memory from the gckVIDMEM object. ** ** INPUT: ** ** gckVIDMEM Memory ** Pointer to an gckVIDMEM object. ** ** gctUINT Width ** Width of rectangle to allocate. Make sure the width is properly ** aligned. ** ** gctUINT Height ** Height of rectangle to allocate. Make sure the height is properly ** aligned. ** ** gctUINT Depth ** Depth of rectangle to allocate. This equals to the number of ** rectangles to allocate contiguously (i.e., for cubic maps and volume ** textures). ** ** gctUINT BytesPerPixel ** Number of bytes per pixel. ** ** gctUINT32 Alignment ** Byte alignment for allocation. ** ** gceSURF_TYPE Type ** Type of surface to allocate (use by bank optimization). ** ** OUTPUT: ** ** gcuVIDMEM_NODE_PTR * Node ** Pointer to a variable that will hold the allocated memory node. */ gceSTATUS gckVIDMEM_Allocate( IN gckVIDMEM Memory, IN gctUINT Width, IN gctUINT Height, IN gctUINT Depth, IN gctUINT BytesPerPixel, IN gctUINT32 Alignment, IN gceSURF_TYPE Type, #ifdef __QNXNTO__ IN gctHANDLE Handle, #endif OUT gcuVIDMEM_NODE_PTR * Node ) { gctSIZE_T bytes; gceSTATUS status; gcmkHEADER_ARG("Memory=0x%x Width=%u Height=%u Depth=%u BytesPerPixel=%u " "Alignment=%u Type=%d", Memory, Width, Height, Depth, BytesPerPixel, Alignment, Type); /* Verify the arguments. */ gcmkVERIFY_OBJECT(Memory, gcvOBJ_VIDMEM); gcmkVERIFY_ARGUMENT(Width > 0); gcmkVERIFY_ARGUMENT(Height > 0); gcmkVERIFY_ARGUMENT(Depth > 0); gcmkVERIFY_ARGUMENT(BytesPerPixel > 0); gcmkVERIFY_ARGUMENT(Node != gcvNULL); #ifdef __QNXNTO__ gcmkVERIFY_ARGUMENT(Handle != gcvNULL); #endif /* Compute linear size. */ bytes = Width * Height * Depth * BytesPerPixel; /* Allocate through linear function. */ #ifdef __QNXNTO__ gcmkONERROR( gckVIDMEM_AllocateLinear(Memory, bytes, Alignment, Type, Handle, Node)); #else gcmkONERROR( gckVIDMEM_AllocateLinear(Memory, bytes, Alignment, Type, Node)); #endif /* Success. */ gcmkFOOTER_ARG("*Node=0x%x", *Node); return gcvSTATUS_OK; OnError: /* Return the status. */ gcmkFOOTER(); return status; }
/******************************************************************************* ** ** gckKERNEL_Destroy ** ** Destroy an gckKERNEL object. ** ** INPUT: ** ** gckKERNEL Kernel ** Pointer to an gckKERNEL object to destroy. ** ** OUTPUT: ** ** Nothing. */ gceSTATUS gckVGKERNEL_Destroy( IN gckVGKERNEL Kernel ) { gceSTATUS status; gcmkHEADER_ARG("Kernel=0x%x", Kernel); /* Verify the arguments. */ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); do { /* Destroy the gckVGMMU object. */ if (Kernel->mmu != gcvNULL) { gcmkERR_BREAK(gckVGMMU_Destroy(Kernel->mmu)); Kernel->mmu = gcvNULL; } /* Destroy the gckVGCOMMAND object. */ if (Kernel->command != gcvNULL) { gcmkERR_BREAK(gckVGCOMMAND_Destroy(Kernel->command)); Kernel->command = gcvNULL; } /* Destroy the gckVGINTERRUPT object. */ if (Kernel->interrupt != gcvNULL) { gcmkERR_BREAK(gckVGINTERRUPT_Destroy(Kernel->interrupt)); Kernel->interrupt = gcvNULL; } /* Destroy the gckVGHARDWARE object. */ if (Kernel->hardware != gcvNULL) { gcmkERR_BREAK(gckVGHARDWARE_Destroy(Kernel->hardware)); Kernel->hardware = gcvNULL; } /* Mark the gckKERNEL object as unknown. */ Kernel->object.type = gcvOBJ_UNKNOWN; /* Free the gckKERNEL object. */ gcmkERR_BREAK(gckOS_Free(Kernel->os, Kernel)); } while (gcvFALSE); gcmkFOOTER(); /* Return status. */ return status; }
gceSTATUS gckKERNEL_AttachProcess( IN gckKERNEL Kernel, IN gctBOOL Attach ) { gceSTATUS status; gctINT32 old; gcmkHEADER_ARG("Kernel=0x%x Attach=%d", Kernel, Attach); /* Verify the arguments. */ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); if (Attach) { /* Increment the number of clients attached. */ gcmkONERROR( gckOS_AtomIncrement(Kernel->os, Kernel->atomClients, &old)); if (old == 0) { /* gcmkONERROR(gckHARDWARE_SetPowerManagementState(Kernel->hardware, gcvPOWER_ON)); */ } } else { /* Decrement the number of clients attached. */ gcmkONERROR( gckOS_AtomDecrement(Kernel->os, Kernel->atomClients, &old)); if (old == 1) { gcmkONERROR(gckHARDWARE_SetPowerManagementState(Kernel->hardware, gcvPOWER_OFF)); /* Flush the debug cache. */ gcmkPRINT("$$FLUSH$$"); } } /* Success. */ gcmkFOOTER_NO(); return gcvSTATUS_OK; OnError: /* Return the status. */ gcmkFOOTER(); return status; }
/******************************************************************************* ** ** gckKERNEL_GetVideoMemoryPool ** ** Get the gckVIDMEM object belonging to the specified pool. ** ** INPUT: ** ** gckKERNEL Kernel ** Pointer to an gckKERNEL object. ** ** gcePOOL Pool ** Pool to query gckVIDMEM object for. ** ** OUTPUT: ** ** gckVIDMEM * VideoMemory ** Pointer to a variable that will hold the pointer to the gckVIDMEM ** object belonging to the requested pool. */ gceSTATUS gckKERNEL_GetVideoMemoryPool( IN gckKERNEL Kernel, IN gcePOOL Pool, OUT gckVIDMEM * VideoMemory ) { gckGALDEVICE device; gckVIDMEM videoMemory; gcmkHEADER_ARG("Kernel=%p Pool=%d", Kernel, Pool); /* Verify the arguments. */ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); gcmkVERIFY_ARGUMENT(VideoMemory != NULL); /* Extract the pointer to the gckGALDEVICE class. */ device = (gckGALDEVICE) Kernel->context; /* Dispatch on pool. */ switch (Pool) { case gcvPOOL_LOCAL_INTERNAL: /* Internal memory. */ videoMemory = device->internalVidMem; break; case gcvPOOL_LOCAL_EXTERNAL: /* External memory. */ videoMemory = device->externalVidMem; break; case gcvPOOL_SYSTEM: /* System memory. */ videoMemory = device->contiguousVidMem; break; default: /* Unknown pool. */ videoMemory = NULL; } /* Return pointer to the gckVIDMEM object. */ *VideoMemory = videoMemory; /* Return status. */ gcmkFOOTER_ARG("*VideoMemory=%p", *VideoMemory); return (videoMemory == NULL) ? gcvSTATUS_OUT_OF_MEMORY : gcvSTATUS_OK; }
/******************************************************************************* ** ** gckVIDMEM_Destroy ** ** Destroy an gckVIDMEM object. ** ** INPUT: ** ** gckVIDMEM Memory ** Pointer to an gckVIDMEM object to destroy. ** ** OUTPUT: ** ** Nothing. */ gceSTATUS gckVIDMEM_Destroy( IN gckVIDMEM Memory ) { gcuVIDMEM_NODE_PTR node, next; gctINT i; gcmkHEADER_ARG("Memory=0x%x", Memory); /* Verify the arguments. */ gcmkVERIFY_OBJECT(Memory, gcvOBJ_VIDMEM); /* Walk all sentinels. */ for (i = 0; i < gcmCOUNTOF(Memory->sentinel); ++i) { /* Bail out of the heap is not used. */ if (Memory->sentinel[i].VidMem.next == gcvNULL) { break; } /* Walk all the nodes until we reach the sentinel. */ for (node = Memory->sentinel[i].VidMem.next; node->VidMem.bytes != 0; node = next) { /* Save pointer to the next node. */ next = node->VidMem.next; /* Free the node. */ gcmkVERIFY_OK(gckOS_Free(Memory->os, node)); } } /* Free the mutex. */ gcmkVERIFY_OK(gckOS_DeleteMutex(Memory->os, Memory->mutex)); /* Mark the object as unknown. */ Memory->object.type = gcvOBJ_UNKNOWN; /* Free the gckVIDMEM object. */ gcmkVERIFY_OK(gckOS_Free(Memory->os, Memory)); /* Success. */ gcmkFOOTER_NO(); return gcvSTATUS_OK; }
gceSTATUS gckKERNEL_QuerySettings( IN gckKERNEL Kernel, OUT gcsKERNEL_SETTINGS * Settings ) { gcmkHEADER_ARG("Kernel=%p", Kernel); /* Verify the arguments. */ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); gcmkVERIFY_ARGUMENT(Settings != gcvNULL); /* Success. */ gcmkFOOTER_NO(); return gcvSTATUS_OK; }
/******************************************************************************* ** ** gckCOMMAND_Destroy ** ** Destroy an gckCOMMAND object. ** ** INPUT: ** ** gckCOMMAND Command ** Pointer to an gckCOMMAND object to destroy. ** ** OUTPUT: ** ** Nothing. */ gceSTATUS gckCOMMAND_Destroy( IN gckCOMMAND Command ) { gctINT i; gcmkHEADER_ARG("Command=0x%x", Command); /* Verify the arguments. */ gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND); /* Stop the command queue. */ gcmkVERIFY_OK(gckCOMMAND_Stop(Command)); for (i = 0; i < gcdCOMMAND_QUEUES; ++i) { gcmkASSERT(Command->queues[i].signal != gcvNULL); gcmkVERIFY_OK( gckOS_DestroySignal(Command->os, Command->queues[i].signal)); gcmkASSERT(Command->queues[i].logical != gcvNULL); gcmkVERIFY_OK( gckOS_FreeNonPagedMemory(Command->os, Command->pageSize, Command->queues[i].physical, Command->queues[i].logical)); } /* Delete the context switching mutex. */ gcmkVERIFY_OK(gckOS_DeleteMutex(Command->os, Command->mutexContext)); /* Delete the command queue mutex. */ gcmkVERIFY_OK(gckOS_DeleteMutex(Command->os, Command->mutexQueue)); /* Mark object as unknown. */ Command->object.type = gcvOBJ_UNKNOWN; /* Free the gckCOMMAND object. */ gcmkVERIFY_OK(gckOS_Free(Command->os, Command)); /* Success. */ gcmkFOOTER_NO(); return gcvSTATUS_OK; }
/******************************************************************************* ** ** gckKERNEL_QueryVideoMemory ** ** Query the amount of video memory. ** ** INPUT: ** ** gckKERNEL Kernel ** Pointer to an gckKERNEL object. ** ** OUTPUT: ** ** gcsHAL_INTERFACE * Interface ** Pointer to an gcsHAL_INTERFACE structure that will be filled in with ** the memory information. */ gceSTATUS gckKERNEL_QueryVideoMemory( IN gckKERNEL Kernel, OUT gcsHAL_INTERFACE * Interface ) { GCHAL * gchal; gcmkHEADER_ARG("Kernel=%p", Kernel); gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_KERNEL, "[ENTER] gckKERNEL_QueryVideoMemory"); /* Verify the arguments. */ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); gcmkVERIFY_ARGUMENT(Interface != gcvNULL); /* Extract the pointer to the CExtension class. */ gchal = (GCHAL *) Kernel->context; /* Get internal memory size and physical address. */ Interface->u.QueryVideoMemory.internalSize = gchal->GetInternalSize(); Interface->u.QueryVideoMemory.internalPhysical = gchal->GetInternalPhysical(); /* Get external memory size and physical address. */ Interface->u.QueryVideoMemory.externalSize = gchal->GetExternalSize(); Interface->u.QueryVideoMemory.externalPhysical = gchal->GetExternalPhysical(); /* Get contiguous memory size and physical address. */ Interface->u.QueryVideoMemory.contiguousSize = gchal->GetContiguousSize(); Interface->u.QueryVideoMemory.contiguousPhysical = gchal->GetContiguousPhysical(); gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_KERNEL, "[LEAVE] gckKERNEL_QueryVideoMemory(%u)", gcvSTATUS_OK); /* Success. */ gcmkFOOTER_NO(); return gcvSTATUS_OK; }
/******************************************************************************* ** ** gckHEAP_Free ** ** Free allocated memory from the heap. ** ** INPUT: ** ** gckHEAP Heap ** Pointer to a gckHEAP object. ** ** IN gctPOINTER Memory ** Pointer to memory to free. ** ** OUTPUT: ** ** NOTHING. */ gceSTATUS gckHEAP_Free( IN gckHEAP Heap, IN gctPOINTER Memory ) { gcskNODE_PTR node; gceSTATUS status; gcmkHEADER_ARG("Heap=0x%x Memory=0x%x", Heap, Memory); /* Verify the arguments. */ gcmkVERIFY_OBJECT(Heap, gcvOBJ_HEAP); gcmkVERIFY_ARGUMENT(Memory != gcvNULL); /* Acquire the mutex. */ gcmkONERROR( gckOS_AcquireMutex(Heap->os, Heap->mutex, gcvINFINITE)); /* Pointer to structure. */ node = (gcskNODE_PTR) Memory - 1; /* Mark the node as freed. */ node->next = gcvNULL; #if VIVANTE_PROFILER || gcmIS_DEBUG(gcdDEBUG_CODE) /* Update profile counters. */ Heap->allocBytes -= node->bytes; #endif /* Release the mutex. */ gcmkVERIFY_OK( gckOS_ReleaseMutex(Heap->os, Heap->mutex)); /* Success. */ gcmkFOOTER_NO(); return gcvSTATUS_OK; OnError: /* Return the status. */ gcmkFOOTER(); return status; }
/******************************************************************************* ** ** gckCOMMAND_Release ** ** Release a previously reserved command queue. The command FIFO mutex will be ** released. ** ** INPUT: ** ** gckCOMMAND Command ** Pointer to an gckCOMMAND object. ** ** OUTPUT: ** ** Nothing. */ gceSTATUS gckCOMMAND_Release( IN gckCOMMAND Command ) { gceSTATUS status; gcmkHEADER_ARG("Command=0x%x", Command); /* Verify the arguments. */ gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND); /* Release the command queue mutex. */ status = gckOS_ReleaseMutex(Command->os, Command->mutexQueue); /* Return the status. */ gcmkFOOTER(); return status; }
/******************************************************************************* ** ** gckKERNEL_QueryCommandBuffer ** ** Query command buffer attributes. ** ** INPUT: ** ** gckKERNEL Kernel ** Pointer to an gckVGHARDWARE object. ** ** OUTPUT: ** ** gcsCOMMAND_BUFFER_INFO_PTR Information ** Pointer to the information structure to receive buffer attributes. */ gceSTATUS gckKERNEL_QueryCommandBuffer( IN gckKERNEL Kernel, OUT gcsCOMMAND_BUFFER_INFO_PTR Information ) { gceSTATUS status; gcmkHEADER_ARG("Kernel=0x%x *Pool=0x%x", Kernel, Information); /* Verify the arguments. */ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); /* Get the information. */ status = gckVGCOMMAND_QueryCommandBuffer(Kernel->vg->command, Information); gcmkFOOTER(); /* Return status. */ return status; }
gceSTATUS gckVGMMU_SetPage( IN gckVGMMU Mmu, IN gctUINT32 PageAddress, IN gctUINT32 *PageEntry ) { gcmkHEADER_ARG("Mmu=0x%x", Mmu); /* Verify the arguments. */ gcmkVERIFY_OBJECT(Mmu, gcvOBJ_MMU); gcmkVERIFY_ARGUMENT(PageEntry != gcvNULL); gcmkVERIFY_ARGUMENT(!(PageAddress & 0xFFF)); *PageEntry = PageAddress; /* Success. */ gcmkFOOTER_NO(); return gcvSTATUS_OK; }
/******************************************************************************* ** ** gckKERNEL_Destroy ** ** Destroy an gckKERNEL object. ** ** INPUT: ** ** gckKERNEL Kernel ** Pointer to an gckKERNEL object to destroy. ** ** OUTPUT: ** ** Nothing. */ gceSTATUS gckKERNEL_Destroy( IN gckKERNEL Kernel ) { gcmkHEADER_ARG("Kernel=0x%x", Kernel); /* Verify the arguments. */ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); /* Destroy the gckMMU object. */ gcmkVERIFY_OK(gckMMU_Destroy(Kernel->mmu)); /* Destroy the gckEVENT object. */ gcmkVERIFY_OK(gckEVENT_Destroy(Kernel->event)); /* Destroy the gckCOMMNAND object. */ gcmkVERIFY_OK(gckCOMMAND_Destroy(Kernel->command)); /* Destroy the gckHARDWARE object. */ gcmkVERIFY_OK(gckHARDWARE_Destroy(Kernel->hardware)); /* Detsroy the client atom. */ gcmkVERIFY_OK(gckOS_AtomDestroy(Kernel->os, Kernel->atomClients)); /* Mark the gckKERNEL object as unknown. */ Kernel->object.type = gcvOBJ_UNKNOWN; #if MRVL_LOW_POWER_MODE_DEBUG gcmkVERIFY_OK( gckOS_Free(Kernel->os, Kernel->kernelMSG)); #endif /* Free the gckKERNEL object. */ gcmkVERIFY_OK(gckOS_Free(Kernel->os, Kernel)); /* Success. */ gcmkFOOTER_NO(); return gcvSTATUS_OK; }
/******************************************************************************* ** ** gckKERNEL_Notify ** ** This function iscalled by clients to notify the gckKERNEL object of an event. ** ** INPUT: ** ** gckKERNEL Kernel ** Pointer to an gckKERNEL object. ** ** gceNOTIFY Notification ** Notification event. ** ** gctBOOL Data ** Optional data for notification. ** ** OUTPUT: ** ** Nothing. */ gceSTATUS gckKERNEL_Notify( IN gckKERNEL Kernel, IN gceNOTIFY Notification, IN gctBOOL Data ) { gceSTATUS status; gcmkHEADER_ARG("Kernel=%p Notification=%d Data=%d", Kernel, Notification, Data); /* Verify the arguments. */ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); /* Dispatch on notifcation. */ switch (Notification) { case gcvNOTIFY_INTERRUPT: /* Process interrupt. */ status = gckHARDWARE_Interrupt(Kernel->hardware, Data); break; #ifdef EMULATOR case gcvNOTIFY_COMMAND_QUEUE: // Unfreeze C-Model. ((GCHAL*) Kernel->context)->UnFreeze(); status = gcvSTATUS_OK; break; #endif default: /* Success. */ status = gcvSTATUS_OK; break; } /* Return the status. */ gcmkFOOTER(); return status; }
/******************************************************************************* ** ** gckVGMMU_FreePages ** ** Free pages inside the page table. ** ** INPUT: ** ** gckVGMMU Mmu ** Pointer to an gckVGMMU object. ** ** gctPOINTER PageTable ** Base address of the page table to free. ** ** gctSIZE_T PageCount ** Number of pages to free. ** ** OUTPUT: ** ** Nothing. */ gceSTATUS gckVGMMU_FreePages( IN gckVGMMU Mmu, IN gctPOINTER PageTable, IN gctSIZE_T PageCount ) { gctUINT32 * table; gcmkHEADER_ARG("Mmu=0x%x PageTable=0x%x PageCount=0x%x", Mmu, PageTable, PageCount); /* Verify the arguments. */ gcmkVERIFY_OBJECT(Mmu, gcvOBJ_MMU); gcmkVERIFY_ARGUMENT(PageTable != gcvNULL); gcmkVERIFY_ARGUMENT(PageCount > 0); gcmkTRACE_ZONE( gcvLEVEL_INFO, gcvZONE_MMU, "%s(%d): freeing %u pages at index %u @ %p.\n", __FUNCTION__, __LINE__, PageCount, ((gctUINT32 *) PageTable - (gctUINT32 *) Mmu->pageTableLogical), PageTable ); /* Convert pointer. */ table = (gctUINT32 *) PageTable; /* Mark the page table entries as available. */ while (PageCount-- > 0) { *table++ = (gctUINT32)~0; } gcmkFOOTER_NO(); /* Success. */ return gcvSTATUS_OK; }
gceSTATUS gckKERNEL_QuerySettings( IN gckKERNEL Kernel, OUT gcsKERNEL_SETTINGS * Settings ) { gckGALDEVICE device; gcmkHEADER_ARG("Kernel=%p", Kernel); /* Verify the arguments. */ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); gcmkVERIFY_ARGUMENT(Settings != gcvNULL); /* Extract the pointer to the gckGALDEVICE class. */ device = (gckGALDEVICE) Kernel->context; /* Fill in signal. */ Settings->signal = device->signal; /* Success. */ gcmkFOOTER_ARG("Settings->signal=%d", Settings->signal); return gcvSTATUS_OK; }
/******************************************************************************* ** ** gckKERNEL_Notify ** ** This function iscalled by clients to notify the gckKERNRL object of an event. ** ** INPUT: ** ** gckKERNEL Kernel ** Pointer to an gckKERNEL object. ** ** gceNOTIFY Notification ** Notification event. ** ** OUTPUT: ** ** Nothing. */ gceSTATUS gckKERNEL_Notify( IN gckKERNEL Kernel, IN gceNOTIFY Notification, IN gctBOOL Data ) { gceSTATUS status; gcmkHEADER_ARG("Kernel=%p Notification=%d Data=%d", Kernel, Notification, Data); /* Verify the arguments. */ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); /* Dispatch on notifcation. */ switch (Notification) { case gcvNOTIFY_INTERRUPT: /* Process the interrupt. */ #if COMMAND_PROCESSOR_VERSION > 1 status = gckINTERRUPT_Notify(Kernel->interrupt, Data); #else status = gckHARDWARE_Interrupt(Kernel->hardware, Data); #endif break; default: status = gcvSTATUS_OK; break; } /* Success. */ gcmkFOOTER(); return status; }
/******************************************************************************* ** gckKERNEL_FindProcessDB ** ** Find a record from a process database. ** ** INPUT: ** ** gckKERNEL Kernel ** Pointer to a gckKERNEL object. ** ** gctUINT32 ProcessID ** Process ID used to identify the database. ** ** gceDATABASE_TYPE TYPE ** Type of the record to remove. ** ** gctPOINTER Pointer ** Data of the record to remove. ** ** OUTPUT: ** ** gcsDATABASE_RECORD_PTR Record ** Copy of record. */ gceSTATUS gckKERNEL_FindProcessDB( IN gckKERNEL Kernel, IN gctUINT32 ProcessID, IN gctUINT32 ThreadID, IN gceDATABASE_TYPE Type, IN gctPOINTER Pointer, OUT gcsDATABASE_RECORD_PTR Record ) { gceSTATUS status; gcsDATABASE_PTR database; gcmkHEADER_ARG("Kernel=0x%x ProcessID=%d Type=%d Pointer=0x%x", Kernel, ProcessID, ThreadID, Type, Pointer); /* Verify the arguments. */ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); gcmkVERIFY_ARGUMENT(Pointer != gcvNULL); /* Find the database. */ gcmkONERROR(gckKERNEL_FindDatabase(Kernel, ProcessID, gcvFALSE, &database)); /* Find the record. */ gcmkONERROR( gckKERNEL_FindRecord(Kernel, database, Type, Pointer, Record)); /* Success. */ gcmkFOOTER_NO(); return gcvSTATUS_OK; OnError: /* Return the status. */ gcmkFOOTER(); return status; }
gceSTATUS gckHEAP_ProfileStart( IN gckHEAP Heap ) { gcmkHEADER_ARG("Heap=0x%x", Heap); /* Verify the arguments. */ gcmkVERIFY_OBJECT(Heap, gcvOBJ_HEAP); /* Zero the counters. */ Heap->allocCount = 0; Heap->allocBytes = 0; Heap->allocBytesMax = 0; Heap->allocBytesTotal = 0; Heap->heapCount = 0; Heap->heapCountMax = 0; Heap->heapMemory = 0; Heap->heapMemoryMax = 0; /* Success. */ gcmkFOOTER_NO(); return gcvSTATUS_OK; }
/******************************************************************************* ** ** gckVGMMU_AllocatePages ** ** Allocate pages inside the page table. ** ** INPUT: ** ** gckVGMMU Mmu ** Pointer to an gckVGMMU object. ** ** gctSIZE_T PageCount ** Number of pages to allocate. ** ** OUTPUT: ** ** gctPOINTER * PageTable ** Pointer to a variable that receives the base address of the page ** table. ** ** gctUINT32 * Address ** Pointer to a variable that receives the hardware specific address. */ gceSTATUS gckVGMMU_AllocatePages( IN gckVGMMU Mmu, IN gctSIZE_T PageCount, OUT gctPOINTER * PageTable, OUT gctUINT32 * Address ) { gceSTATUS status; gctUINT32 tail, index, i; gctUINT32 * table; gctBOOL allocated = gcvFALSE; gcmkHEADER_ARG("Mmu=0x%x PageCount=0x%x PageTable=0x%x Address=0x%x", Mmu, PageCount, PageTable, Address); /* Verify the arguments. */ gcmkVERIFY_OBJECT(Mmu, gcvOBJ_MMU); gcmkVERIFY_ARGUMENT(PageCount > 0); gcmkVERIFY_ARGUMENT(PageTable != gcvNULL); gcmkVERIFY_ARGUMENT(Address != gcvNULL); gcmkTRACE_ZONE( gcvLEVEL_INFO, gcvZONE_MMU, "%s(%d): %u pages.\n", __FUNCTION__, __LINE__, PageCount ); if (PageCount > Mmu->entryCount) { gcmkTRACE_ZONE( gcvLEVEL_ERROR, gcvZONE_MMU, "%s(%d): page table too small for %u pages.\n", __FUNCTION__, __LINE__, PageCount ); gcmkFOOTER_NO(); /* Not enough pages avaiable. */ return gcvSTATUS_OUT_OF_RESOURCES; } /* Grab the mutex. */ status = gckOS_AcquireMutex(Mmu->os, Mmu->mutex, gcvINFINITE); if (status < 0) { gcmkTRACE_ZONE( gcvLEVEL_ERROR, gcvZONE_MMU, "%s(%d): could not acquire mutex.\n" ,__FUNCTION__, __LINE__ ); gcmkFOOTER(); /* Error. */ return status; } /* Compute the tail for this allocation. */ tail = Mmu->entryCount - PageCount; /* Walk all entries until we find enough slots. */ for (index = Mmu->entry; index <= tail;) { /* Access page table. */ table = (gctUINT32 *) Mmu->pageTableLogical + index; /* See if all slots are available. */ for (i = 0; i < PageCount; i++, table++) { if (*table != ~0) { /* Start from next slot. */ index += i + 1; break; } } if (i == PageCount) { /* Bail out if we have enough page entries. */ allocated = gcvTRUE; break; } } if (!allocated) { if (status >= 0) { /* Walk all entries until we find enough slots. */ for (index = 0; index <= tail;) { /* Access page table. */ table = (gctUINT32 *) Mmu->pageTableLogical + index; /* See if all slots are available. */ for (i = 0; i < PageCount; i++, table++) { if (*table != ~0) { /* Start from next slot. */ index += i + 1; break; } } if (i == PageCount) { /* Bail out if we have enough page entries. */ allocated = gcvTRUE; break; } } } } if (!allocated && (status >= 0)) { gcmkTRACE_ZONE( gcvLEVEL_ERROR, gcvZONE_MMU, "%s(%d): not enough free pages for %u pages.\n", __FUNCTION__, __LINE__, PageCount ); /* Not enough empty slots available. */ status = gcvSTATUS_OUT_OF_RESOURCES; } if (status >= 0) { /* Build virtual address. */ status = gckVGHARDWARE_BuildVirtualAddress(Mmu->hardware, index, 0, Address); if (status >= 0) { /* Update current entry into page table. */ Mmu->entry = index + PageCount; /* Return pointer to page table. */ *PageTable = (gctUINT32 *) Mmu->pageTableLogical + index; gcmkTRACE_ZONE( gcvLEVEL_INFO, gcvZONE_MMU, "%s(%d): allocated %u pages at index %u (0x%08X) @ %p.\n", __FUNCTION__, __LINE__, PageCount, index, *Address, *PageTable ); } } /* Release the mutex. */ gcmkVERIFY_OK(gckOS_ReleaseMutex(Mmu->os, Mmu->mutex)); gcmkFOOTER(); /* Return status. */ return status; }
/******************************************************************************* ** ** gckHEAP_Allocate ** ** Allocate data from the heap. ** ** INPUT: ** ** gckHEAP Heap ** Pointer to a gckHEAP object. ** ** IN gctSIZE_T Bytes ** Number of byte to allocate. ** ** OUTPUT: ** ** gctPOINTER * Memory ** Pointer to a variable that will hold the address of the allocated ** memory. */ gceSTATUS gckHEAP_Allocate( IN gckHEAP Heap, IN gctSIZE_T Bytes, OUT gctPOINTER * Memory ) { gctBOOL acquired = gcvFALSE; gcskHEAP_PTR heap; gceSTATUS status; gctSIZE_T bytes; gcskNODE_PTR node, used, prevFree = gcvNULL; gctPOINTER memory = gcvNULL; gcmkHEADER_ARG("Heap=0x%x Bytes=%lu", Heap, Bytes); /* Verify the arguments. */ gcmkVERIFY_OBJECT(Heap, gcvOBJ_HEAP); gcmkVERIFY_ARGUMENT(Bytes > 0); gcmkVERIFY_ARGUMENT(Memory != gcvNULL); /* Determine number of bytes required for a node. */ bytes = gcmALIGN(Bytes + gcmSIZEOF(gcskNODE), 8); /* Acquire the mutex. */ gcmkONERROR( gckOS_AcquireMutex(Heap->os, Heap->mutex, gcvINFINITE)); acquired = gcvTRUE; /* Check if this allocation is bigger than the default allocation size. */ if (bytes > Heap->allocationSize - gcmSIZEOF(gcskHEAP) - gcmSIZEOF(gcskNODE)) { /* Adjust allocation size. */ Heap->allocationSize = bytes * 2; } else if (Heap->heap != gcvNULL) { gctINT i; /* 2 retries, since we might need to compact. */ for (i = 0; i < 2; ++i) { /* Walk all the heaps. */ for (heap = Heap->heap; heap != gcvNULL; heap = heap->next) { /* Check if this heap has enough bytes to hold the request. */ if (bytes <= heap->size - gcmSIZEOF(gcskNODE)) { prevFree = gcvNULL; /* Walk the chain of free nodes. */ for (node = heap->freeList; node != gcvNULL; node = node->next ) { gcmkASSERT(node->next != gcdIN_USE); /* Check if this free node has enough bytes. */ if (node->bytes >= bytes) { /* Use the node. */ goto UseNode; } /* Save current free node for linked list management. */ prevFree = node; } } } if (i == 0) { /* Compact the heap. */ gcmkVERIFY_OK(_CompactKernelHeap(Heap)); #if gcmIS_DEBUG(gcdDEBUG_CODE) gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_HEAP, "===== KERNEL HEAP ====="); gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_HEAP, "Number of allocations : %12u", Heap->allocCount); gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_HEAP, "Number of bytes allocated : %12llu", Heap->allocBytes); gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_HEAP, "Maximum allocation size : %12llu", Heap->allocBytesMax); gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_HEAP, "Total number of bytes allocated : %12llu", Heap->allocBytesTotal); gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_HEAP, "Number of heaps : %12u", Heap->heapCount); gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_HEAP, "Heap memory in bytes : %12llu", Heap->heapMemory); gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_HEAP, "Maximum number of heaps : %12u", Heap->heapCountMax); gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_HEAP, "Maximum heap memory in bytes : %12llu", Heap->heapMemoryMax); #endif } } } /* Release the mutex. */ gcmkONERROR( gckOS_ReleaseMutex(Heap->os, Heap->mutex)); acquired = gcvFALSE; /* Allocate a new heap. */ gcmkONERROR( gckOS_AllocateMemory(Heap->os, Heap->allocationSize, &memory)); gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HEAP, "Allocated heap 0x%x (%lu bytes)", memory, Heap->allocationSize); /* Acquire the mutex. */ gcmkONERROR( gckOS_AcquireMutex(Heap->os, Heap->mutex, gcvINFINITE)); acquired = gcvTRUE; /* Use the allocated memory as the heap. */ heap = (gcskHEAP_PTR) memory; /* Insert this heap to the head of the chain. */ heap->next = Heap->heap; heap->prev = gcvNULL; heap->size = Heap->allocationSize - gcmSIZEOF(gcskHEAP); if (heap->next != gcvNULL) { heap->next->prev = heap; } Heap->heap = heap; /* Mark the end of the heap. */ node = (gcskNODE_PTR) ( (gctUINT8_PTR) heap + Heap->allocationSize - gcmSIZEOF(gcskNODE) ); node->bytes = 0; node->next = gcvNULL; /* Create a free list. */ node = (gcskNODE_PTR) (heap + 1); heap->freeList = node; /* Initialize the free list. */ node->bytes = heap->size - gcmSIZEOF(gcskNODE); node->next = gcvNULL; /* No previous free. */ prevFree = gcvNULL; #if VIVANTE_PROFILER || gcmIS_DEBUG(gcdDEBUG_CODE) /* Update profiling. */ Heap->heapCount += 1; Heap->heapMemory += Heap->allocationSize; if (Heap->heapCount > Heap->heapCountMax) { Heap->heapCountMax = Heap->heapCount; } if (Heap->heapMemory > Heap->heapMemoryMax) { Heap->heapMemoryMax = Heap->heapMemory; } #endif UseNode: /* Verify some stuff. */ gcmkASSERT(heap != gcvNULL); gcmkASSERT(node != gcvNULL); gcmkASSERT(node->bytes >= bytes); if (heap->prev != gcvNULL) { /* Unlink the heap from the linked list. */ heap->prev->next = heap->next; if (heap->next != gcvNULL) { heap->next->prev = heap->prev; } /* Move the heap to the front of the list. */ heap->next = Heap->heap; heap->prev = gcvNULL; Heap->heap = heap; heap->next->prev = heap; } /* Check if there is enough free space left after usage for another free ** node. */ if (node->bytes - bytes >= gcmSIZEOF(gcskNODE)) { /* Allocated used space from the back of the free list. */ used = (gcskNODE_PTR) ((gctUINT8_PTR) node + node->bytes - bytes); /* Adjust the number of free bytes. */ node->bytes -= bytes; gcmkASSERT(node->bytes >= gcmSIZEOF(gcskNODE)); } else { /* Remove this free list from the chain. */ if (prevFree == gcvNULL) { heap->freeList = node->next; } else { prevFree->next = node->next; } /* Consume the entire free node. */ used = (gcskNODE_PTR) node; bytes = node->bytes; } /* Mark node as used. */ used->bytes = bytes; used->next = gcdIN_USE; #if gcmIS_DEBUG(gcdDEBUG_CODE) used->timeStamp = ++Heap->timeStamp; #endif #if VIVANTE_PROFILER || gcmIS_DEBUG(gcdDEBUG_CODE) /* Update profile counters. */ Heap->allocCount += 1; Heap->allocBytes += bytes; Heap->allocBytesMax = gcmMAX(Heap->allocBytes, Heap->allocBytesMax); Heap->allocBytesTotal += bytes; #endif /* Release the mutex. */ gcmkVERIFY_OK( gckOS_ReleaseMutex(Heap->os, Heap->mutex)); /* Return pointer to memory. */ *Memory = used + 1; /* Success. */ gcmkFOOTER_ARG("*Memory=0x%x", *Memory); return gcvSTATUS_OK; OnError: if (acquired) { /* Release the mutex. */ gcmkVERIFY_OK( gckOS_ReleaseMutex(Heap->os, Heap->mutex)); } if (memory != gcvNULL) { /* Free the heap memory. */ gckOS_FreeMemory(Heap->os, memory); } /* Return the status. */ gcmkFOOTER(); return status; }
/******************************************************************************* ** ** gckHEAP_Construct ** ** Construct a new gckHEAP object. ** ** INPUT: ** ** gckOS Os ** Pointer to a gckOS object. ** ** gctSIZE_T AllocationSize ** Minimum size per arena. ** ** OUTPUT: ** ** gckHEAP * Heap ** Pointer to a variable that will hold the pointer to the gckHEAP ** object. */ gceSTATUS gckHEAP_Construct( IN gckOS Os, IN gctSIZE_T AllocationSize, OUT gckHEAP * Heap ) { gceSTATUS status; gckHEAP heap = gcvNULL; gctPOINTER pointer = gcvNULL; gcmkHEADER_ARG("Os=0x%x AllocationSize=%lu", Os, AllocationSize); /* Verify the arguments. */ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); gcmkVERIFY_ARGUMENT(Heap != gcvNULL); /* Allocate the gckHEAP object. */ gcmkONERROR(gckOS_AllocateMemory(Os, gcmSIZEOF(struct _gckHEAP), &pointer)); heap = pointer; /* Initialize the gckHEAP object. */ heap->object.type = gcvOBJ_HEAP; heap->os = Os; heap->allocationSize = AllocationSize; heap->heap = gcvNULL; #if gcmIS_DEBUG(gcdDEBUG_CODE) heap->timeStamp = 0; #endif #if VIVANTE_PROFILER || gcmIS_DEBUG(gcdDEBUG_CODE) /* Zero the counters. */ heap->allocCount = 0; heap->allocBytes = 0; heap->allocBytesMax = 0; heap->allocBytesTotal = 0; heap->heapCount = 0; heap->heapCountMax = 0; heap->heapMemory = 0; heap->heapMemoryMax = 0; #endif /* Create the mutex. */ gcmkONERROR(gckOS_CreateMutex(Os, &heap->mutex)); /* Return the pointer to the gckHEAP object. */ *Heap = heap; /* Success. */ gcmkFOOTER_ARG("*Heap=0x%x", *Heap); return gcvSTATUS_OK; OnError: /* Roll back. */ if (heap != gcvNULL) { /* Free the heap structure. */ gcmkVERIFY_OK(gckOS_FreeMemory(Os, heap)); } /* Return the status. */ gcmkFOOTER(); return status; }
/******************************************************************************* ** ** gckVGMMU_Construct ** ** Construct a new gckVGMMU object. ** ** INPUT: ** ** gckVGKERNEL Kernel ** Pointer to an gckVGKERNEL object. ** ** gctSIZE_T MmuSize ** Number of bytes for the page table. ** ** OUTPUT: ** ** gckVGMMU * Mmu ** Pointer to a variable that receives the gckVGMMU object pointer. */ gceSTATUS gckVGMMU_Construct( IN gckVGKERNEL Kernel, IN gctSIZE_T MmuSize, OUT gckVGMMU * Mmu ) { gckOS os; gckVGHARDWARE hardware; gceSTATUS status; gckVGMMU mmu; gctUINT32 * pageTable; gctUINT32 i; gcmkHEADER_ARG("Kernel=0x%x MmuSize=0x%x Mmu=0x%x", Kernel, MmuSize, Mmu); /* Verify the arguments. */ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); gcmkVERIFY_ARGUMENT(MmuSize > 0); gcmkVERIFY_ARGUMENT(Mmu != gcvNULL); /* Extract the gckOS object pointer. */ os = Kernel->os; gcmkVERIFY_OBJECT(os, gcvOBJ_OS); /* Extract the gckVGHARDWARE object pointer. */ hardware = Kernel->hardware; gcmkVERIFY_OBJECT(hardware, gcvOBJ_HARDWARE); /* Allocate memory for the gckVGMMU object. */ status = gckOS_Allocate(os, sizeof(struct _gckVGMMU), (gctPOINTER *) &mmu); if (status < 0) { /* Error. */ gcmkFATAL( "%s(%d): could not allocate gckVGMMU object.", __FUNCTION__, __LINE__ ); gcmkFOOTER(); return status; } /* Initialize the gckVGMMU object. */ mmu->object.type = gcvOBJ_MMU; mmu->os = os; mmu->hardware = hardware; /* Create the mutex. */ status = gckOS_CreateMutex(os, &mmu->mutex); if (status < 0) { /* Roll back. */ mmu->object.type = gcvOBJ_UNKNOWN; gcmkVERIFY_OK(gckOS_Free(os, mmu)); gcmkFOOTER(); /* Error. */ return status; } /* Allocate the page table. */ mmu->pageTableSize = MmuSize; status = gckOS_AllocateContiguous(os, gcvFALSE, &mmu->pageTableSize, &mmu->pageTablePhysical, &mmu->pageTableLogical); if (status < 0) { /* Roll back. */ gcmkVERIFY_OK(gckOS_DeleteMutex(os, mmu->mutex)); mmu->object.type = gcvOBJ_UNKNOWN; gcmkVERIFY_OK(gckOS_Free(os, mmu)); /* Error. */ gcmkFATAL( "%s(%d): could not allocate page table.", __FUNCTION__, __LINE__ ); gcmkFOOTER(); return status; } /* Compute number of entries in page table. */ mmu->entryCount = mmu->pageTableSize / sizeof(gctUINT32); mmu->entry = 0; /* Mark the entire page table as available. */ pageTable = (gctUINT32 *) mmu->pageTableLogical; for (i = 0; i < mmu->entryCount; i++) { pageTable[i] = (gctUINT32)~0; } /* Set page table address. */ status = gckVGHARDWARE_SetMMU(hardware, mmu->pageTableLogical); if (status < 0) { /* Free the page table. */ gcmkVERIFY_OK(gckOS_FreeContiguous(mmu->os, mmu->pageTablePhysical, mmu->pageTableLogical, mmu->pageTableSize)); /* Roll back. */ gcmkVERIFY_OK(gckOS_DeleteMutex(os, mmu->mutex)); mmu->object.type = gcvOBJ_UNKNOWN; gcmkVERIFY_OK(gckOS_Free(os, mmu)); /* Error. */ gcmkFATAL( "%s(%d): could not program page table.", __FUNCTION__, __LINE__ ); gcmkFOOTER(); return status; } /* Return the gckVGMMU object pointer. */ *Mmu = mmu; gcmkTRACE_ZONE( gcvLEVEL_INFO, gcvZONE_MMU, "%s(%d): %u entries at %p.(0x%08X)\n", __FUNCTION__, __LINE__, mmu->entryCount, mmu->pageTableLogical, mmu->pageTablePhysical ); gcmkFOOTER_NO(); /* Success. */ return gcvSTATUS_OK; }