/******************************************************************************* ** 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; }
static int __devinit gpu_probe(struct platform_device *pdev) #endif { int ret = -ENODEV; struct resource* res; gcmkHEADER(); res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "gpu_irq"); if (!res) { printk(KERN_ERR "%s: No irq line supplied.\n",__FUNCTION__); goto gpu_probe_fail; } irqLine = res->start; res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "gpu_base"); if (!res) { printk(KERN_ERR "%s: No register base supplied.\n",__FUNCTION__); goto gpu_probe_fail; } registerMemBase = res->start; registerMemSize = res->end - res->start + 1; res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "gpu_mem"); if (!res) { printk(KERN_ERR "%s: No memory base supplied.\n",__FUNCTION__); goto gpu_probe_fail; } contiguousBase = res->start; contiguousSize = res->end - res->start + 1; /*####modified for marvell-bg2*/ ret = drv_get_dts_for_gpu(); /*if there is no gpu2d, it will also return error*/ /*####end for marvell-bg2*/ ret = drv_init(); if (!ret) { platform_set_drvdata(pdev, galDevice); gcmkFOOTER_NO(); return ret; } gpu_probe_fail: gcmkFOOTER_ARG(KERN_INFO "Failed to register gpu driver: %d\n", ret); return ret; }
/******************************************************************************* ** ** _NewQueue ** ** Allocate a new command queue. ** ** INPUT: ** ** gckCOMMAND Command ** Pointer to an gckCOMMAND object. ** ** OUTPUT: ** ** gckCOMMAND Command ** gckCOMMAND object has been updated with a new command queue. */ static gceSTATUS _NewQueue( IN OUT gckCOMMAND Command, IN gctBOOL Locking ) { gceSTATUS status; gctINT currentIndex, newIndex; gcmkHEADER_ARG("Command=0x%x Locking=%d", Command, Locking); /* Switch to the next command buffer. */ currentIndex = Command->index; newIndex = (currentIndex + 1) % gcdCOMMAND_QUEUES; /* Wait for availability. */ #if gcdDUMP_COMMAND gcmkPRINT("@[kernel.waitsignal]"); #endif gcmkONERROR( gckOS_WaitSignal(Command->os, Command->queues[newIndex].signal, gcvINFINITE)); if (currentIndex >= 0) { /* Mark the command queue as available. */ gcmkONERROR(gckEVENT_Signal(Command->kernel->event, Command->queues[currentIndex].signal, gcvKERNEL_PIXEL, Locking)); } /* Update gckCOMMAND object with new command queue. */ Command->index = newIndex; Command->newQueue = gcvTRUE; Command->physical = Command->queues[newIndex].physical; Command->logical = Command->queues[newIndex].logical; Command->offset = 0; if (currentIndex >= 0) { /* Submit the event queue. */ Command->submit = gcvTRUE; } /* Success. */ gcmkFOOTER_ARG("Command->index=%d", Command->index); return gcvSTATUS_OK; OnError: /* Return the status. */ 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_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; }
/******************************************************************************* ** ** gckHEAP_Destroy ** ** Destroy a gckHEAP object. ** ** INPUT: ** ** gckHEAP Heap ** Pointer to a gckHEAP object to destroy. ** ** OUTPUT: ** ** Nothing. */ gceSTATUS gckHEAP_Destroy( IN gckHEAP Heap ) { gcskHEAP_PTR heap; #if gcmIS_DEBUG(gcdDEBUG_CODE) gctSIZE_T leaked = 0; #endif gcmkHEADER_ARG("Heap=0x%x", Heap); for (heap = Heap->heap; heap != gcvNULL; heap = Heap->heap) { /* Unlink heap from linked list. */ Heap->heap = heap->next; #if gcmIS_DEBUG(gcdDEBUG_CODE) /* Check for leaked memory. */ leaked += _DumpHeap(heap); #endif /* Free the heap. */ gcmkVERIFY_OK(gckOS_FreeMemory(Heap->os, heap)); } /* Free the mutex. */ gcmkVERIFY_OK(gckOS_DeleteMutex(Heap->os, Heap->mutex)); /* Free the heap structure. */ gcmkVERIFY_OK(gckOS_FreeMemory(Heap->os, Heap)); /* Success. */ #if gcmIS_DEBUG(gcdDEBUG_CODE) gcmkFOOTER_ARG("leaked=%lu", leaked); #else gcmkFOOTER_NO(); #endif 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; }
static gceSTATUS _AllocateMemory( IN gckGALDEVICE Device, IN gctSIZE_T Bytes, OUT gctPOINTER *Logical, OUT gctPHYS_ADDR *Physical, OUT gctUINT32 *PhysAddr ) { gceSTATUS status; gcmkHEADER_ARG("Device=0x%x Bytes=%lu", Device, Bytes); gcmkVERIFY_ARGUMENT(Device != NULL); gcmkVERIFY_ARGUMENT(Logical != NULL); gcmkVERIFY_ARGUMENT(Physical != NULL); gcmkVERIFY_ARGUMENT(PhysAddr != NULL); gcmkONERROR(gckOS_AllocateContiguous( Device->os, gcvFALSE, &Bytes, Physical, Logical )); *PhysAddr = ((PLINUX_MDL)*Physical)->dmaHandle - Device->baseAddress; /* Success. */ gcmkFOOTER_ARG( "*Logical=0x%x *Physical=0x%x *PhysAddr=0x%08x", *Logical, *Physical, *PhysAddr ); return gcvSTATUS_OK; OnError: gcmkFOOTER(); return status; }
/******************************************************************************* ** ** gckVIDMEM_ConstructVirtual ** ** Construct a new gcuVIDMEM_NODE union for virtual memory. ** ** INPUT: ** ** gckKERNEL Kernel ** Pointer to an gckKERNEL object. ** ** gctSIZE_T Bytes ** Number of byte to allocate. ** ** OUTPUT: ** ** gcuVIDMEM_NODE_PTR * Node ** Pointer to a variable that receives the gcuVIDMEM_NODE union pointer. */ gceSTATUS gckVIDMEM_ConstructVirtual( IN gckKERNEL Kernel, IN gctBOOL Contiguous, IN gctSIZE_T Bytes, #ifdef __QNXNTO__ IN gctHANDLE Handle, #endif OUT gcuVIDMEM_NODE_PTR * Node ) { gckOS os; gceSTATUS status; gcuVIDMEM_NODE_PTR node = gcvNULL; gcmkHEADER_ARG("Kernel=0x%x Bytes=%lu", Kernel, Bytes); /* Verify the arguments. */ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); gcmkVERIFY_ARGUMENT(Bytes > 0); gcmkVERIFY_ARGUMENT(Node != gcvNULL); #ifdef __QNXNTO__ gcmkVERIFY_ARGUMENT(Handle != gcvNULL); #endif /* Extract the gckOS object pointer. */ os = Kernel->os; gcmkVERIFY_OBJECT(os, gcvOBJ_OS); /* Allocate an gcuVIDMEM_NODE union. */ gcmkONERROR( gckOS_Allocate(os, gcmSIZEOF(gcuVIDMEM_NODE), (gctPOINTER *) &node)); /* Initialize gcuVIDMEM_NODE union for virtual memory. */ node->Virtual.kernel = Kernel; node->Virtual.contiguous = Contiguous; node->Virtual.locked = 0; node->Virtual.logical = gcvNULL; node->Virtual.pageTable = gcvNULL; node->Virtual.mutex = gcvNULL; #ifdef __QNXNTO__ node->Virtual.next = gcvNULL; node->Virtual.unlockPending = gcvFALSE; node->Virtual.freePending = gcvFALSE; node->Virtual.handle = Handle; #else node->Virtual.pending = gcvFALSE; #endif /* Create the mutex. */ gcmkONERROR( gckOS_CreateMutex(os, &node->Virtual.mutex)); /* Allocate the virtual memory. */ gcmkONERROR( gckOS_AllocatePagedMemoryEx(os, node->Virtual.contiguous, node->Virtual.bytes = Bytes, &node->Virtual.physical)); #ifdef __QNXNTO__ /* Register. */ gckMMU_InsertNode(Kernel->mmu, node); #endif /* Return pointer to the gcuVIDMEM_NODE union. */ *Node = node; gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM, "Created virtual node 0x%x for %u bytes @ 0x%x", node, Bytes, node->Virtual.physical); /* Success. */ gcmkFOOTER_ARG("*Node=0x%x", *Node); return gcvSTATUS_OK; OnError: /* Roll back. */ if (node != gcvNULL) { if (node->Virtual.mutex != gcvNULL) { /* Destroy the mutex. */ gcmkVERIFY_OK(gckOS_DeleteMutex(os, node->Virtual.mutex)); } /* Free the structure. */ gcmkVERIFY_OK(gckOS_Free(os, node)); } /* Return the status. */ gcmkFOOTER(); return status; }
/******************************************************************************* ** ** gckVIDMEM_Lock ** ** Lock a video memory node and return it's hardware specific address. ** ** INPUT: ** ** gcuVIDMEM_NODE_PTR Node ** Pointer to a gcuVIDMEM_NODE union. ** ** OUTPUT: ** ** gctUINT32 * Address ** Pointer to a variable that will hold the hardware specific address. */ gceSTATUS gckVIDMEM_Lock( IN gcuVIDMEM_NODE_PTR Node, OUT gctUINT32 * Address ) { gceSTATUS status; gctBOOL acquired = gcvFALSE; gctBOOL locked = gcvFALSE; gckOS os = gcvNULL; gcmkHEADER_ARG("Node=0x%x", Node); /* Verify the arguments. */ gcmkVERIFY_ARGUMENT(Address != gcvNULL); if ((Node == gcvNULL) || (Node->VidMem.memory == gcvNULL) ) { /* Invalid object. */ gcmkONERROR(gcvSTATUS_INVALID_OBJECT); } /**************************** Video Memory ********************************/ if (Node->VidMem.memory->object.type == gcvOBJ_VIDMEM) { /* Increment the lock count. */ Node->VidMem.locked ++; /* Return the address of the node. */ *Address = Node->VidMem.memory->baseAddress + Node->VidMem.offset + Node->VidMem.alignment; gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM, "Locked node 0x%x (%d) @ 0x%08X", Node, Node->VidMem.locked, *Address); } /*************************** Virtual Memory *******************************/ else { /* Verify the gckKERNEL object pointer. */ gcmkVERIFY_OBJECT(Node->Virtual.kernel, gcvOBJ_KERNEL); /* Extract the gckOS object pointer. */ os = Node->Virtual.kernel->os; gcmkVERIFY_OBJECT(os, gcvOBJ_OS); /* Grab the mutex. */ gcmkONERROR(gckOS_AcquireMutex(os, Node->Virtual.mutex, gcvINFINITE)); acquired = gcvTRUE; /* Increment the lock count. */ if (Node->Virtual.locked ++ == 0) { /* Is this node pending for a final unlock? */ #ifdef __QNXNTO__ if (!Node->Virtual.contiguous && Node->Virtual.unlockPending) #else if (!Node->Virtual.contiguous && Node->Virtual.pending) #endif { /* Make sure we have a page table. */ gcmkASSERT(Node->Virtual.pageTable != gcvNULL); /* Remove pending unlock. */ #ifdef __QNXNTO__ Node->Virtual.unlockPending = gcvFALSE; #else Node->Virtual.pending = gcvFALSE; #endif } /* First lock - create a page table. */ gcmkASSERT(Node->Virtual.pageTable == gcvNULL); /* Make sure we mark our node as not flushed. */ #ifdef __QNXNTO__ Node->Virtual.unlockPending = gcvFALSE; #else Node->Virtual.pending = gcvFALSE; #endif /* Lock the allocated pages. */ #ifdef __QNXNTO__ gcmkONERROR( gckOS_LockPages(os, Node->Virtual.physical, Node->Virtual.bytes, Node->Virtual.userPID, &Node->Virtual.logical, &Node->Virtual.pageCount)); #else gcmkONERROR( gckOS_LockPages(os, Node->Virtual.physical, Node->Virtual.bytes, &Node->Virtual.logical, &Node->Virtual.pageCount)); #endif locked = gcvTRUE; if (Node->Virtual.contiguous) { /* Get physical address directly */ gcmkONERROR(gckOS_GetPhysicalAddress(os, Node->Virtual.logical, &Node->Virtual.address)); } else { /* Allocate pages inside the MMU. */ gcmkONERROR( gckMMU_AllocatePages(Node->Virtual.kernel->mmu, Node->Virtual.pageCount, &Node->Virtual.pageTable, &Node->Virtual.address)); /* Map the pages. */ #ifdef __QNXNTO__ gcmkONERROR( gckOS_MapPages(os, Node->Virtual.physical, Node->Virtual.logical, Node->Virtual.pageCount, Node->Virtual.pageTable)); #else gcmkONERROR( gckOS_MapPages(os, Node->Virtual.physical, Node->Virtual.pageCount, Node->Virtual.pageTable)); #endif gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM, "Mapped virtual node 0x%x to 0x%08X", Node, Node->Virtual.address); } } /* Return hardware address. */ *Address = Node->Virtual.address; /* Release the mutex. */ gcmkVERIFY_OK(gckOS_ReleaseMutex(os, Node->Virtual.mutex)); } /* Success. */ gcmkFOOTER_ARG("*Address=%08x", *Address); return gcvSTATUS_OK; OnError: if (locked) { if (Node->Virtual.pageTable != gcvNULL) { /* Free the pages from the MMU. */ gcmkVERIFY_OK( gckMMU_FreePages(Node->Virtual.kernel->mmu, Node->Virtual.pageTable, Node->Virtual.pageCount)); Node->Virtual.pageTable = gcvNULL; } /* Unlock the pages. */ #ifdef __QNXNTO__ gcmkVERIFY_OK( gckOS_UnlockPages(os, Node->Virtual.physical, Node->Virtual.userPID, Node->Virtual.bytes, Node->Virtual.logical)); #else gcmkVERIFY_OK( gckOS_UnlockPages(os, Node->Virtual.physical, Node->Virtual.bytes, Node->Virtual.logical)); #endif } if (acquired) { /* Release the mutex. */ gcmkVERIFY_OK(gckOS_ReleaseMutex(os, Node->Virtual.mutex)); } /* Return the status. */ gcmkFOOTER(); return status; }
/******************************************************************************* ** ** gckVIDMEM_Unlock ** ** Unlock a video memory node. ** ** INPUT: ** ** gcuVIDMEM_NODE_PTR Node ** Pointer to a locked gcuVIDMEM_NODE union. ** ** gceSURF_TYPE Type ** Type of surface to unlock. ** ** gctSIZE_T * CommandSize ** Pointer to a variable specifying the number of bytes in the command ** buffer specified by 'Commands'. If gcvNULL, there is no command ** buffer and the video memory shoud be unlocked synchronously. ** ** gctBOOL * Asynchroneous ** Pointer to a variable specifying whether the surface should be ** unlocked asynchroneously or not. ** ** OUTPUT: ** ** gctBOOL * Asynchroneous ** Pointer to a variable receiving the number of bytes used in the ** command buffer specified by 'Commands'. If gcvNULL, there is no ** command buffer. */ gceSTATUS gckVIDMEM_Unlock( IN gcuVIDMEM_NODE_PTR Node, IN gceSURF_TYPE Type, IN OUT gctBOOL * Asynchroneous ) { gceSTATUS status; gckKERNEL kernel; gckHARDWARE hardware; gctPOINTER buffer; gctSIZE_T requested, bufferSize; gckCOMMAND command = gcvNULL; gceKERNEL_FLUSH flush; gckOS os = gcvNULL; gctBOOL acquired = gcvFALSE; gctBOOL needRelease = gcvFALSE; gctBOOL pendingUnlock = gcvFALSE; gcmkHEADER_ARG("Node=0x%x Type=%d *Asynchroneous=%d", Node, Type, gcmOPT_VALUE(Asynchroneous)); /* Verify the arguments. */ if ((Node == gcvNULL) || (Node->VidMem.memory == gcvNULL) ) { /* Invalid object. */ gcmkONERROR(gcvSTATUS_INVALID_OBJECT); } /**************************** Video Memory ********************************/ if (Node->VidMem.memory->object.type == gcvOBJ_VIDMEM) { if (Node->VidMem.locked <= 0) { /* The surface was not locked. */ gcmkONERROR(gcvSTATUS_MEMORY_UNLOCKED); } /* Decrement the lock count. */ Node->VidMem.locked --; if (Asynchroneous != gcvNULL) { /* No need for any events. */ *Asynchroneous = gcvFALSE; } } /*************************** Virtual Memory *******************************/ else { /* Verify the gckKERNEL object pointer. */ kernel = Node->Virtual.kernel; gcmkVERIFY_OBJECT(kernel, gcvOBJ_KERNEL); /* Verify the gckHARDWARE object pointer. */ hardware = Node->Virtual.kernel->hardware; gcmkVERIFY_OBJECT(hardware, gcvOBJ_HARDWARE); /* Verify the gckCOMMAND object pointer. */ command = Node->Virtual.kernel->command; gcmkVERIFY_OBJECT(command, gcvOBJ_COMMAND); if (Asynchroneous == gcvNULL) { gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM, "gckVIDMEM_Unlock: Unlocking virtual node 0x%x (%d)", Node, Node->Virtual.locked); /* Get the gckOS object pointer. */ os = kernel->os; gcmkVERIFY_OBJECT(os, gcvOBJ_OS); /* Grab the mutex. */ gcmkONERROR( gckOS_AcquireMutex(os, Node->Virtual.mutex, gcvINFINITE)); /* If we need to unlock a node from virtual memory we have to be ** very carefull. If the node is still inside the caches we ** might get a bus error later if the cache line needs to be ** replaced. So - we have to flush the caches before we do ** anything. We also need to stall to make sure the flush has ** happened. However - when we get to this point we are inside ** the interrupt handler and we cannot just gckCOMMAND_Wait ** because it will wait forever. So - what we do here is we ** verify the type of the surface, flush the appropriate cache, ** mark the node as flushed, and issue another unlock to unmap ** the MMU. */ if (!Node->Virtual.contiguous && (Node->Virtual.locked == 1) #ifdef __QNXTO__ && !Node->Virtual.unlockPending #else && !Node->Virtual.pending #endif ) { if (Type == gcvSURF_BITMAP) { /* Flush 2D cache. */ flush = gcvFLUSH_2D; } else if (Type == gcvSURF_RENDER_TARGET) { /* Flush color cache. */ flush = gcvFLUSH_COLOR; } else if (Type == gcvSURF_DEPTH) { /* Flush depth cache. */ flush = gcvFLUSH_DEPTH; } else { /* No flush required. */ flush = (gceKERNEL_FLUSH) 0; } gcmkONERROR( gckHARDWARE_Flush(hardware, flush, gcvNULL, &requested)); if (requested != 0) { gcmkONERROR( gckCOMMAND_Reserve(command, requested, &buffer, &bufferSize)); needRelease = gcvTRUE; gcmkONERROR(gckHARDWARE_Flush(hardware, flush, buffer, &bufferSize)); gcmkONERROR( gckEVENT_Unlock(Node->Virtual.kernel->event, gcvKERNEL_PIXEL, Node, Type)); /* Mark node as pending. */ #ifdef __QNXNTO__ Node->Virtual.unlockPending = gcvTRUE; #else Node->Virtual.pending = gcvTRUE; #endif needRelease = gcvFALSE; gcmkONERROR(gckCOMMAND_Execute(command, requested)); pendingUnlock = gcvTRUE; } } if (!pendingUnlock) { if (Node->Virtual.locked == 0) { status = gcvSTATUS_MEMORY_UNLOCKED; goto OnError; } /* Decrement lock count. */ -- Node->Virtual.locked; /* See if we can unlock the resources. */ if (Node->Virtual.locked == 0) { /* Unlock the pages. */ #ifdef __QNXNTO__ gcmkONERROR( gckOS_UnlockPages(os, Node->Virtual.physical, Node->Virtual.userPID, Node->Virtual.bytes, Node->Virtual.logical)); #else gcmkONERROR( gckOS_UnlockPages(os, Node->Virtual.physical, Node->Virtual.bytes, Node->Virtual.logical)); #endif /* Free the page table. */ if (Node->Virtual.pageTable != gcvNULL) { gcmkONERROR( gckMMU_FreePages(Node->Virtual.kernel->mmu, Node->Virtual.pageTable, Node->Virtual.pageCount)); /* Mark page table as freed. */ Node->Virtual.pageTable = gcvNULL; } /* Mark node as unlocked. */ #ifdef __QNXTO Node->Virtual.unlockPending = gcvFALSE; #else Node->Virtual.pending = gcvFALSE; #endif } gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM, "Unmapped virtual node 0x%x from 0x%08X", Node, Node->Virtual.address); } /* Release the mutex. */ gcmkVERIFY_OK(gckOS_ReleaseMutex(os, Node->Virtual.mutex)); } else { gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM, "Scheduled unlock for virtual node 0x%x", Node); /* Schedule the surface to be unlocked. */ *Asynchroneous = gcvTRUE; } } /* Success. */ gcmkFOOTER_ARG("*Asynchroneous=%d", gcmOPT_VALUE(Asynchroneous)); return gcvSTATUS_OK; OnError: if (needRelease) { gcmkVERIFY_OK(gckCOMMAND_Release(command)); } if (acquired) { /* Release the mutex. */ gcmkVERIFY_OK(gckOS_ReleaseMutex(os, Node->Virtual.mutex)); } /* Return the status. */ gcmkFOOTER(); return status; }
/******************************************************************************* ** gckKERNEL_NewRecord ** ** Create a new database record structure and insert it to the head of the ** database. ** ** INPUT: ** ** gckKERNEL Kernel ** Pointer to a gckKERNEL object. ** ** gcsDATABASE_PTR Database ** Pointer to a database structure. ** ** OUTPUT: ** ** gcsDATABASE_RECORD_PTR * Record ** Pointer to a variable receiving the database record structure ** pointer on success. */ static gceSTATUS gckKERNEL_NewRecord( IN gckKERNEL Kernel, IN gcsDATABASE_PTR Database, IN gctUINT32 Slot, OUT gcsDATABASE_RECORD_PTR * Record ) { gceSTATUS status; gctBOOL acquired = gcvFALSE; gcsDATABASE_RECORD_PTR record = gcvNULL; gcmkHEADER_ARG("Kernel=0x%x Database=0x%x", Kernel, Database); /* Acquire the database mutex. */ gcmkONERROR( gckOS_AcquireMutex(Kernel->os, Kernel->db->dbMutex, gcvINFINITE)); acquired = gcvTRUE; if (Kernel->db->freeRecord != gcvNULL) { /* Allocate the record from the free list. */ record = Kernel->db->freeRecord; Kernel->db->freeRecord = record->next; } else { gctPOINTER pointer = gcvNULL; /* Allocate the record from the heap. */ gcmkONERROR(gckOS_Allocate(Kernel->os, gcmSIZEOF(gcsDATABASE_RECORD), &pointer)); record = pointer; } /* Insert the record in the database. */ record->next = Database->list[Slot]; Database->list[Slot] = record; /* Release the database mutex. */ gcmkONERROR(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex)); /* Return the record. */ *Record = record; /* Success. */ gcmkFOOTER_ARG("*Record=0x%x", *Record); return gcvSTATUS_OK; OnError: if (acquired) { /* Release the database mutex. */ gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex)); } if (record != gcvNULL) { gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Kernel->os, record)); } /* Return the status. */ gcmkFOOTER(); return status; }
/******************************************************************************* ** ** gckKERNEL_Construct ** ** Construct a new gckKERNEL object. ** ** INPUT: ** ** gckOS Os ** Pointer to an gckOS object. ** ** IN gctPOINTER Context ** Pointer to a driver defined context. ** ** OUTPUT: ** ** gckKERNEL * Kernel ** Pointer to a variable that will hold the pointer to the gckKERNEL ** object. */ gceSTATUS gckVGKERNEL_Construct( IN gckOS Os, IN gctPOINTER Context, IN gckKERNEL inKernel, OUT gckVGKERNEL * Kernel ) { gceSTATUS status; gckVGKERNEL kernel = gcvNULL; gcmkHEADER_ARG("Os=0x%x Context=0x%x", Os, Context); /* Verify the arguments. */ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); gcmkVERIFY_ARGUMENT(Kernel != gcvNULL); do { /* Allocate the gckKERNEL object. */ gcmkERR_BREAK(gckOS_Allocate( Os, sizeof(struct _gckVGKERNEL), (gctPOINTER *) &kernel )); /* Initialize the gckKERNEL object. */ kernel->object.type = gcvOBJ_KERNEL; kernel->os = Os; kernel->context = Context; kernel->hardware = gcvNULL; kernel->interrupt = gcvNULL; kernel->command = gcvNULL; kernel->mmu = gcvNULL; kernel->kernel = inKernel; /* Construct the gckVGHARDWARE object. */ gcmkERR_BREAK(gckVGHARDWARE_Construct( Os, &kernel->hardware )); /* Set pointer to gckKERNEL object in gckVGHARDWARE object. */ kernel->hardware->kernel = kernel; /* Construct the gckVGINTERRUPT object. */ gcmkERR_BREAK(gckVGINTERRUPT_Construct( kernel, &kernel->interrupt )); /* Construct the gckVGCOMMAND object. */ gcmkERR_BREAK(gckVGCOMMAND_Construct( kernel, gcmKB2BYTES(8), gcmKB2BYTES(2), &kernel->command )); /* Construct the gckVGMMU object. */ gcmkERR_BREAK(gckVGMMU_Construct( kernel, gcmKB2BYTES(32), &kernel->mmu )); /* Return pointer to the gckKERNEL object. */ *Kernel = kernel; gcmkFOOTER_ARG("*Kernel=0x%x", *Kernel); /* Success. */ return gcvSTATUS_OK; } while (gcvFALSE); /* Roll back. */ if (kernel != gcvNULL) { if (kernel->mmu != gcvNULL) { gcmkVERIFY_OK(gckVGMMU_Destroy(kernel->mmu)); } if (kernel->command != gcvNULL) { gcmkVERIFY_OK(gckVGCOMMAND_Destroy(kernel->command)); } if (kernel->interrupt != gcvNULL) { gcmkVERIFY_OK(gckVGINTERRUPT_Destroy(kernel->interrupt)); } if (kernel->hardware != gcvNULL) { gcmkVERIFY_OK(gckVGHARDWARE_Destroy(kernel->hardware)); } gcmkVERIFY_OK(gckOS_Free(Os, kernel)); } gcmkFOOTER(); /* Return status. */ return status; }
/******************************************************************************* ** ** gckVIDMEM_AllocateLinear ** ** Allocate linear memory from the gckVIDMEM object. ** ** INPUT: ** ** gckVIDMEM Memory ** Pointer to an gckVIDMEM object. ** ** gctSIZE_T Bytes ** Number of bytes to allocate. ** ** 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_AllocateLinear( IN gckVIDMEM Memory, IN gctSIZE_T Bytes, IN gctUINT32 Alignment, IN gceSURF_TYPE Type, #ifdef __QNXNTO__ IN gctHANDLE Handle, #endif OUT gcuVIDMEM_NODE_PTR * Node ) { gceSTATUS status; gcuVIDMEM_NODE_PTR node; gctUINT32 alignment; gctINT bank, i; gctBOOL acquired = gcvFALSE; gcmkHEADER_ARG("Memory=0x%x Bytes=%lu Alignment=%u Type=%d", Memory, Bytes, Alignment, Type); /* Verify the arguments. */ gcmkVERIFY_OBJECT(Memory, gcvOBJ_VIDMEM); gcmkVERIFY_ARGUMENT(Bytes > 0); gcmkVERIFY_ARGUMENT(Node != gcvNULL); #ifdef __QNXNTO__ gcmkVERIFY_ARGUMENT(Handle != gcvNULL); #endif /* Acquire the mutex. */ gcmkONERROR( gckOS_AcquireMutex(Memory->os, Memory->mutex, gcvINFINITE)); acquired = gcvTRUE; if (Bytes > Memory->freeBytes) { /* Not enough memory. */ gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY); } /* Find the default bank for this surface type. */ gcmkASSERT((gctINT) Type < gcmCOUNTOF(Memory->mapping)); bank = Memory->mapping[Type]; alignment = Alignment; /* Find a free node in the default bank. */ node = _FindNode(Memory, bank, Bytes, &alignment); /* Out of memory? */ if (node == gcvNULL) { /* Walk all lower banks. */ for (i = bank - 1; i >= 0; --i) { /* Find a free node inside the current bank. */ node = _FindNode(Memory, i, Bytes, &alignment); if (node != gcvNULL) { break; } } } if (node == gcvNULL) { /* Walk all upper banks. */ for (i = bank + 1; i < gcmCOUNTOF(Memory->sentinel); ++i) { if (Memory->sentinel[i].VidMem.nextFree == gcvNULL) { /* Abort when we reach unused banks. */ break; } /* Find a free node inside the current bank. */ node = _FindNode(Memory, i, Bytes, &alignment); if (node != gcvNULL) { break; } } } if (node == gcvNULL) { /* Out of memory. */ gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY); } /* Do we have an alignment? */ if (alignment > 0) { /* Split the node so it is aligned. */ if (_Split(Memory->os, node, alignment)) { /* Successful split, move to aligned node. */ node = node->VidMem.next; /* Remove alignment. */ alignment = 0; } } /* Do we have enough memory after the allocation to split it? */ if (node->VidMem.bytes - Bytes > Memory->threshold) { /* Adjust the node size. */ _Split(Memory->os, node, Bytes); } /* Remove the node from the free list. */ node->VidMem.prevFree->VidMem.nextFree = node->VidMem.nextFree; node->VidMem.nextFree->VidMem.prevFree = node->VidMem.prevFree; node->VidMem.nextFree = node->VidMem.prevFree = gcvNULL; /* Fill in the information. */ node->VidMem.alignment = alignment; node->VidMem.memory = Memory; #ifdef __QNXNTO__ node->VidMem.logical = gcvNULL; node->VidMem.handle = Handle; #endif /* Adjust the number of free bytes. */ Memory->freeBytes -= node->VidMem.bytes; /* Release the mutex. */ gcmkVERIFY_OK(gckOS_ReleaseMutex(Memory->os, Memory->mutex)); /* Return the pointer to the node. */ *Node = node; gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM, "Allocated %u bytes @ 0x%x [0x%08X]", node->VidMem.bytes, node, node->VidMem.offset); /* Success. */ gcmkFOOTER_ARG("*Node=0x%x", *Node); return gcvSTATUS_OK; OnError: if (acquired) { /* Release the mutex. */ gcmkVERIFY_OK(gckOS_ReleaseMutex(Memory->os, Memory->mutex)); } /* Return the status. */ gcmkFOOTER(); return status; }
static int __devinit gpu_probe(struct platform_device *pdev) { int ret = -ENODEV; struct resource* res; gcmkHEADER(); res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "gpu_irq"); if (!res) { printk(KERN_ERR "%s: No irq line supplied.\n",__FUNCTION__); goto gpu_probe_fail; } irqLine = res->start; res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "gpu_base"); if (!res) { printk(KERN_ERR "%s: No register base supplied.\n",__FUNCTION__); goto gpu_probe_fail; } registerMemBase = res->start; registerMemSize = res->end - res->start + 1; #if MRVL_USE_GPU_RESERVE_MEM gcmkPRINT(KERN_INFO "[galcore] info: GC use memblock to reserve video memory.\n"); res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "gpu_mem"); if (!res) { printk(KERN_ERR "%s: No gpu reserved memory supplied. res = %p\n",__FUNCTION__, res); goto gpu_probe_fail; } contiguousBase = res->start; contiguousSize = res->end - res->start + 1; #endif printk("\n[galcore] GC Version: %s\n", _GC_VERSION_STRING_); printk("\ncontiguousBase:%08x, contiguousSize:%08x\n", (gctUINT32)contiguousBase, (gctUINT32)contiguousSize); pdevice = &pdev->dev; ret = drv_init(); if (!ret) { platform_set_drvdata(pdev, galDevice); #if MRVL_CONFIG_PROC create_gc_proc_file(); #endif create_gc_sysfs_file(pdev); #if MRVL_CONFIG_ENABLE_GPUFREQ __enable_gpufreq(galDevice); #endif #if MRVL_CONFIG_ENABLE_EARLYSUSPEND register_early_suspend(&gpu_early_suspend_handler); #endif #if (MRVL_VIDEO_MEMORY_USE_TYPE == gcdMEM_TYPE_ION) #if (gcdMEM_TYPE_IONAF_3_4_39 == 1) gc_ion_client = ion_client_create(pxa_ion_dev, "gc ion"); #else gc_ion_client = ion_client_create(pxa_ion_dev, ION_HEAP_CARVEOUT_MASK, "gc ion"); #endif #endif #if MRVL_CONFIG_USE_PM_RUNTIME pm_runtime_enable(&pdev->dev); pm_runtime_forbid(&pdev->dev); #endif /* save device pointer to GALDEVICE */ galDevice->dev = &pdev->dev; gcmkFOOTER_NO(); return ret; } gpu_probe_fail: gcmkFOOTER_ARG(KERN_INFO "Failed to register gpu driver: %d\n", ret); return ret; }
/******************************************************************************* ** gckKERNEL_NewDatabase ** ** Create a new database structure and insert it to the head of the hash list. ** ** INPUT: ** ** gckKERNEL Kernel ** Pointer to a gckKERNEL object. ** ** u32 ProcessID ** ProcessID that identifies the database. ** ** OUTPUT: ** ** gcsDATABASE_PTR * Database ** Pointer to a variable receiving the database structure pointer on ** success. */ static gceSTATUS gckKERNEL_NewDatabase( IN gckKERNEL Kernel, IN u32 ProcessID, OUT gcsDATABASE_PTR * Database ) { gceSTATUS status; gcsDATABASE_PTR database; int acquired = gcvFALSE; size_t slot; gcmkHEADER_ARG("Kernel=0x%x ProcessID=%d", Kernel, ProcessID); /* Acquire the database mutex. */ gcmkONERROR(gckOS_AcquireMutex(Kernel->os, Kernel->db->dbMutex, gcvINFINITE)); acquired = gcvTRUE; if (Kernel->db->freeDatabase != NULL) { /* Allocate a database from the free list. */ database = Kernel->db->freeDatabase; Kernel->db->freeDatabase = database->next; } else { void *pointer = NULL; /* Allocate a new database from the heap. */ gcmkONERROR(gckOS_Allocate(Kernel->os, sizeof(gcsDATABASE), &pointer)); database = pointer; } /* Compute the hash for the database. */ slot = ProcessID % ARRAY_SIZE(Kernel->db->db); /* Insert the database into the hash. */ database->next = Kernel->db->db[slot]; Kernel->db->db[slot] = database; /* Save the hash slot. */ database->slot = slot; /* Release the database mutex. */ gcmkONERROR(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex)); /* Return the database. */ *Database = database; /* Success. */ gcmkFOOTER_ARG("*Database=0x%x", *Database); return gcvSTATUS_OK; OnError: if (acquired) { /* Release the database mutex. */ gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex)); } /* Return the status. */ gcmkFOOTER(); return status; }
static int __devinit gpu_probe(struct platform_device *pdev) #endif { int ret = -ENODEV; gcsMODULE_PARAMETERS moduleParam = { #if gcdMULTI_GPU || gcdMULTI_GPU_AFFINITY #else .irqLine = irqLine, .registerMemBase = registerMemBase, .registerMemSize = registerMemSize, #endif .irqLine2D = irqLine2D, .registerMemBase2D = registerMemBase2D, .registerMemSize2D = registerMemSize2D, .irqLineVG = irqLineVG, .registerMemBaseVG = registerMemBaseVG, .registerMemSizeVG = registerMemSizeVG, .contiguousSize = contiguousSize, .contiguousBase = contiguousBase, .bankSize = bankSize, .fastClear = fastClear, .compression = compression, .powerManagement = powerManagement, .gpuProfiler = gpuProfiler, .signal = signal, .baseAddress = baseAddress, .physSize = physSize, .logFileSize = logFileSize, .recovery = recovery, .stuckDump = stuckDump, .showArgs = showArgs, .gpu3DMinClock = gpu3DMinClock, }; gcmkHEADER(); platform.device = pdev; if (platform.ops->getPower) { if (gcmIS_ERROR(platform.ops->getPower(&platform))) { gcmkFOOTER_NO(); return ret; } } if (platform.ops->adjustParam) { /* Override default module param. */ platform.ops->adjustParam(&platform, &moduleParam); /* Update module param because drv_init() uses them directly. */ _UpdateModuleParam(&moduleParam); } ret = drv_init(); if (!ret) { platform_set_drvdata(pdev, galDevice); gcmkFOOTER_NO(); return ret; } gcmkFOOTER_ARG(KERN_INFO "Failed to register gpu driver: %d\n", ret); return ret; }
static int __devinit gpu_probe(struct platform_device *pdev) #endif { int ret = -ENODEV; struct resource* res; #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0) struct contiguous_mem_pool *pool; struct reset_control *rstc; #elif LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0) struct device_node *dn =pdev->dev.of_node; const u32 *prop; #else struct viv_gpu_platform_data *pdata; #endif gcmkHEADER(); res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phys_baseaddr"); if (res) baseAddress = res->start; res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "irq_3d"); if (res) irqLine = res->start; res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "iobase_3d"); if (res) { registerMemBase = res->start; registerMemSize = res->end - res->start + 1; } res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "irq_2d"); if (res) irqLine2D = res->start; res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "iobase_2d"); if (res) { registerMemBase2D = res->start; registerMemSize2D = res->end - res->start + 1; } res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "irq_vg"); if (res) irqLineVG = res->start; res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "iobase_vg"); if (res) { registerMemBaseVG = res->start; registerMemSizeVG = res->end - res->start + 1; } #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0) pool = devm_kzalloc(&pdev->dev, sizeof(*pool), GFP_KERNEL); if (!pool) return -ENOMEM; pool->size = contiguousSize; init_dma_attrs(&pool->attrs); dma_set_attr(DMA_ATTR_WRITE_COMBINE, &pool->attrs); pool->virt = dma_alloc_attrs(&pdev->dev, pool->size, &pool->phys, GFP_KERNEL, &pool->attrs); if (!pool->virt) { dev_err(&pdev->dev, "Failed to allocate contiguous memory\n"); return -ENOMEM; } contiguousBase = pool->phys; dev_set_drvdata(&pdev->dev, pool); #elif LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0) prop = of_get_property(dn, "contiguousbase", NULL); if(prop) contiguousBase = *prop; of_property_read_u32(dn,"contiguoussize", (u32 *)&contiguousSize); #else pdata = pdev->dev.platform_data; if (pdata) { contiguousBase = pdata->reserved_mem_base; contiguousSize = pdata->reserved_mem_size; } #endif if (contiguousSize == 0) gckOS_Print("Warning: No contiguous memory is reserverd for gpu.!\n "); ret = drv_init(&pdev->dev); if (!ret) { #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0) rstc = devm_reset_control_get(&pdev->dev, "gpu3d"); galDevice->rstc[gcvCORE_MAJOR] = IS_ERR(rstc) ? NULL : rstc; rstc = devm_reset_control_get(&pdev->dev, "gpu2d"); galDevice->rstc[gcvCORE_2D] = IS_ERR(rstc) ? NULL : rstc; rstc = devm_reset_control_get(&pdev->dev, "gpuvg"); galDevice->rstc[gcvCORE_VG] = IS_ERR(rstc) ? NULL : rstc; #endif platform_set_drvdata(pdev, galDevice); #if gcdENABLE_FSCALE_VAL_ADJUST if (galDevice->kernels[gcvCORE_MAJOR]) REG_THERMAL_NOTIFIER(&thermal_hot_pm_notifier); #endif gcmkFOOTER_NO(); return ret; } #if gcdENABLE_FSCALE_VAL_ADJUST UNREG_THERMAL_NOTIFIER(&thermal_hot_pm_notifier); #endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0) dma_free_attrs(&pdev->dev, pool->size, pool->virt, pool->phys, &pool->attrs); #endif gcmkFOOTER_ARG(KERN_INFO "Failed to register gpu driver: %d\n", ret); return ret; }
/******************************************************************************* ** ** 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 ) { GCHAL * gchal; gckVIDMEM videoMemory; gceSTATUS status; gcmkHEADER_ARG("Kernel=%p Pool=%d", Kernel, Pool); gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_KERNEL, "[ENTER] gckHARDWARE_GetVideoMemoryPool"); /* Verify the arguments. */ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); gcmkVERIFY_ARGUMENT(VideoMemory != gcvNULL); /* Extract the pointer to the GCHAL class. */ gchal = (GCHAL *) Kernel->context; /* Dispatch on pool. */ switch (Pool) { case gcvPOOL_LOCAL_INTERNAL: /* Internal memory. */ videoMemory = gchal->GetInternalHeap(); break; case gcvPOOL_LOCAL_EXTERNAL: /* External memory. */ videoMemory = gchal->GetExternalHeap(); break; case gcvPOOL_SYSTEM: /* System memory. */ videoMemory = gchal->GetContiguousHeap(); break; default: /* Unknown pool. */ videoMemory = gcvNULL; gcmkFATAL("Unknown memory pool: %u", Pool); } /* Return pointer to the gckVIDMEM object. */ *VideoMemory = videoMemory; /* Determine the status. */ status = (videoMemory == gcvNULL) ? gcvSTATUS_OUT_OF_MEMORY : gcvSTATUS_OK; if (gcmIS_SUCCESS(status)) { gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_KERNEL, "gckHARDWARE_GetVideoMemoryPool: Pool %u starts at %p", Pool, videoMemory); } gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_KERNEL, "[LEAVE] gckHARDWARE_GetVideoMemoryPool(%u)", status); /* Return the status. */ gcmkFOOTER_ARG("status=%d, *VideoMemory=%p", status, gcmOPT_VALUE(VideoMemory)); return status; }
/******************************************************************************* ** gckKERNEL_FindRecord ** ** Find a database record from the database. ** ** INPUT: ** ** gckKERNEL Kernel ** Pointer to a gckKERNEL object. ** ** gcsDATABASE_PTR Database ** Pointer to a database structure. ** ** gceDATABASE_TYPE Type ** Type of the record to remove. ** ** gctPOINTER Data ** Data of the record to remove. ** ** OUTPUT: ** ** gctSIZE_T_PTR Bytes ** Pointer to a variable that receives the size of the record deleted. ** Can be gcvNULL if the size is not required. */ static gceSTATUS gckKERNEL_FindRecord( IN gckKERNEL Kernel, IN gcsDATABASE_PTR Database, IN gceDATABASE_TYPE Type, IN gctPOINTER Data, OUT gcsDATABASE_RECORD_PTR Record ) { gceSTATUS status; gctBOOL acquired = gcvFALSE; gcsDATABASE_RECORD_PTR record; gctUINT32 slot = _GetSlot(Database, Data); gcmkHEADER_ARG("Kernel=0x%x Database=0x%x Type=%d Data=0x%x", Kernel, Database, Type, Data); /* Acquire the database mutex. */ gcmkONERROR( gckOS_AcquireMutex(Kernel->os, Kernel->db->dbMutex, gcvINFINITE)); acquired = gcvTRUE; /* Scan the database for this record. */ for (record = Database->list[slot]; record != gcvNULL; record = record->next ) { if ((record->type == Type) && (record->data == Data) ) { /* Found it! */ break; } } if (record == gcvNULL) { /* Ouch! This record is not found? */ gcmkONERROR(gcvSTATUS_INVALID_DATA); } if (Record != gcvNULL) { /* Return information of record. */ gcmkONERROR( gckOS_MemCopy(Record, record, sizeof(gcsDATABASE_RECORD))); } /* Release the database mutex. */ gcmkONERROR(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex)); /* Success. */ gcmkFOOTER_ARG("Record=0x%x", Record); return gcvSTATUS_OK; OnError: if (acquired) { /* Release the database mutex. */ gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex)); } /* Return the status. */ gcmkFOOTER(); return status; }
/******************************************************************************* ** gckKERNEL_NewDatabase ** ** Create a new database structure and insert it to the head of the hash list. ** ** INPUT: ** ** gckKERNEL Kernel ** Pointer to a gckKERNEL object. ** ** gctUINT32 ProcessID ** ProcessID that identifies the database. ** ** OUTPUT: ** ** gcsDATABASE_PTR * Database ** Pointer to a variable receiving the database structure pointer on ** success. */ static gceSTATUS gckKERNEL_NewDatabase( IN gckKERNEL Kernel, IN gctUINT32 ProcessID, OUT gcsDATABASE_PTR * Database ) { gceSTATUS status; gcsDATABASE_PTR database; gctBOOL acquired = gcvFALSE; gctSIZE_T slot; gcsDATABASE_PTR existingDatabase; gcmkHEADER_ARG("Kernel=0x%x ProcessID=%d", Kernel, ProcessID); /* Acquire the database mutex. */ gcmkONERROR(gckOS_AcquireMutex(Kernel->os, Kernel->db->dbMutex, gcvINFINITE)); acquired = gcvTRUE; /* Compute the hash for the database. */ slot = ProcessID % gcmCOUNTOF(Kernel->db->db); /* Walk the hash list. */ for (existingDatabase = Kernel->db->db[slot]; existingDatabase != gcvNULL; existingDatabase = existingDatabase->next) { if (existingDatabase->processID == ProcessID) { /* One process can't be added twice. */ gcmkONERROR(gcvSTATUS_NOT_SUPPORTED); } } if (Kernel->db->freeDatabase != gcvNULL) { /* Allocate a database from the free list. */ database = Kernel->db->freeDatabase; Kernel->db->freeDatabase = database->next; } else { gctPOINTER pointer = gcvNULL; /* Allocate a new database from the heap. */ gcmkONERROR(gckOS_Allocate(Kernel->os, gcmSIZEOF(gcsDATABASE), &pointer)); database = pointer; } /* Insert the database into the hash. */ database->next = Kernel->db->db[slot]; Kernel->db->db[slot] = database; /* Save the hash slot. */ database->slot = slot; /* Release the database mutex. */ gcmkONERROR(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex)); /* Return the database. */ *Database = database; /* Success. */ gcmkFOOTER_ARG("*Database=0x%x", *Database); return gcvSTATUS_OK; OnError: if (acquired) { /* Release the database mutex. */ gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex)); } /* Return the status. */ gcmkFOOTER(); return status; }
/******************************************************************************* ** gckKERNEL_DeleteRecord ** ** Remove a database record from the database and delete its structure. ** ** INPUT: ** ** gckKERNEL Kernel ** Pointer to a gckKERNEL object. ** ** gcsDATABASE_PTR Database ** Pointer to a database structure. ** ** gceDATABASE_TYPE Type ** Type of the record to remove. ** ** gctPOINTER Data ** Data of the record to remove. ** ** OUTPUT: ** ** gctSIZE_T_PTR Bytes ** Pointer to a variable that receives the size of the record deleted. ** Can be gcvNULL if the size is not required. */ static gceSTATUS gckKERNEL_DeleteRecord( IN gckKERNEL Kernel, IN gcsDATABASE_PTR Database, IN gceDATABASE_TYPE Type, IN gctPOINTER Data, OUT gctSIZE_T_PTR Bytes OPTIONAL ) { gceSTATUS status; gctBOOL acquired = gcvFALSE; gcsDATABASE_RECORD_PTR record, previous; gctUINT32 slot = _GetSlot(Database, Data); gcmkHEADER_ARG("Kernel=0x%x Database=0x%x Type=%d Data=0x%x", Kernel, Database, Type, Data); /* Acquire the database mutex. */ gcmkONERROR( gckOS_AcquireMutex(Kernel->os, Kernel->db->dbMutex, gcvINFINITE)); acquired = gcvTRUE; /* Scan the database for this record. */ for (record = Database->list[slot], previous = gcvNULL; record != gcvNULL; record = record->next ) { if ((record->type == Type) && (record->data == Data) ) { /* Found it! */ break; } previous = record; } if (record == gcvNULL) { /* Ouch! This record is not found? */ gcmkONERROR(gcvSTATUS_INVALID_DATA); } if (Bytes != gcvNULL) { /* Return size of record. */ *Bytes = record->bytes; } /* Remove record from database. */ if (previous == gcvNULL) { Database->list[slot] = record->next; } else { previous->next = record->next; } /* Insert record in free list. */ record->next = Kernel->db->freeRecord; Kernel->db->freeRecord = record; /* Release the database mutex. */ gcmkONERROR(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex)); /* Success. */ gcmkFOOTER_ARG("*Bytes=%lu", gcmOPT_VALUE(Bytes)); return gcvSTATUS_OK; OnError: if (acquired) { /* Release the database mutex. */ gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex)); } /* Return the status. */ gcmkFOOTER(); return status; }
/******************************************************************************* ** ** gckVIDMEM_Construct ** ** Construct a new gckVIDMEM object. ** ** INPUT: ** ** gckOS Os ** Pointer to an gckOS object. ** ** gctUINT32 BaseAddress ** Base address for the video memory heap. ** ** gctSIZE_T Bytes ** Number of bytes in the video memory heap. ** ** gctSIZE_T Threshold ** Minimum number of bytes beyond am allocation before the node is ** split. Can be used as a minimum alignment requirement. ** ** gctSIZE_T BankSize ** Number of bytes per physical memory bank. Used by bank ** optimization. ** ** OUTPUT: ** ** gckVIDMEM * Memory ** Pointer to a variable that will hold the pointer to the gckVIDMEM ** object. */ gceSTATUS gckVIDMEM_Construct( IN gckOS Os, IN gctUINT32 BaseAddress, IN gctSIZE_T Bytes, IN gctSIZE_T Threshold, IN gctSIZE_T BankSize, OUT gckVIDMEM * Memory ) { gckVIDMEM memory = gcvNULL; gceSTATUS status; gcuVIDMEM_NODE_PTR node; gctINT i, banks = 0; gcmkHEADER_ARG("Os=0x%x BaseAddress=%08x Bytes=%lu Threshold=%lu " "BankSize=%lu", Os, BaseAddress, Bytes, Threshold, BankSize); /* Verify the arguments. */ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); gcmkVERIFY_ARGUMENT(Bytes > 0); gcmkVERIFY_ARGUMENT(Memory != gcvNULL); /* Allocate the gckVIDMEM object. */ gcmkONERROR( gckOS_Allocate(Os, gcmSIZEOF(struct _gckVIDMEM), (gctPOINTER *) &memory)); /* Initialize the gckVIDMEM object. */ memory->object.type = gcvOBJ_VIDMEM; memory->os = Os; /* Set video memory heap information. */ memory->baseAddress = BaseAddress; memory->bytes = Bytes; memory->freeBytes = Bytes; memory->threshold = Threshold; memory->mutex = gcvNULL; BaseAddress = 0; /* Walk all possible banks. */ for (i = 0; i < gcmCOUNTOF(memory->sentinel); ++i) { gctSIZE_T bytes; if (BankSize == 0) { /* Use all bytes for the first bank. */ bytes = Bytes; } else { /* Compute number of bytes for this bank. */ bytes = gcmALIGN(BaseAddress + 1, BankSize) - BaseAddress; if (bytes > Bytes) { /* Make sure we don't exceed the total number of bytes. */ bytes = Bytes; } } if (bytes == 0) { /* Mark heap is not used. */ memory->sentinel[i].VidMem.next = memory->sentinel[i].VidMem.prev = memory->sentinel[i].VidMem.nextFree = memory->sentinel[i].VidMem.prevFree = gcvNULL; continue; } /* Allocate one gcuVIDMEM_NODE union. */ gcmkONERROR( gckOS_Allocate(Os, gcmSIZEOF(gcuVIDMEM_NODE), (gctPOINTER *) &node)); /* Initialize gcuVIDMEM_NODE union. */ node->VidMem.memory = memory; node->VidMem.next = node->VidMem.prev = node->VidMem.nextFree = node->VidMem.prevFree = &memory->sentinel[i]; node->VidMem.offset = BaseAddress; node->VidMem.bytes = bytes; node->VidMem.alignment = 0; node->VidMem.physical = 0; node->VidMem.pool = gcvPOOL_UNKNOWN; node->VidMem.locked = 0; #ifdef __QNXNTO__ node->VidMem.logical = gcvNULL; node->VidMem.handle = 0; #endif /* Initialize the linked list of nodes. */ memory->sentinel[i].VidMem.next = memory->sentinel[i].VidMem.prev = memory->sentinel[i].VidMem.nextFree = memory->sentinel[i].VidMem.prevFree = node; /* Mark sentinel. */ memory->sentinel[i].VidMem.bytes = 0; /* Adjust address for next bank. */ BaseAddress += bytes; Bytes -= bytes; banks ++; } /* Assign all the bank mappings. */ memory->mapping[gcvSURF_RENDER_TARGET] = banks - 1; memory->mapping[gcvSURF_BITMAP] = banks - 1; if (banks > 1) --banks; memory->mapping[gcvSURF_DEPTH] = banks - 1; memory->mapping[gcvSURF_HIERARCHICAL_DEPTH] = banks - 1; if (banks > 1) --banks; memory->mapping[gcvSURF_TEXTURE] = banks - 1; if (banks > 1) --banks; memory->mapping[gcvSURF_VERTEX] = banks - 1; if (banks > 1) --banks; memory->mapping[gcvSURF_INDEX] = banks - 1; if (banks > 1) --banks; memory->mapping[gcvSURF_TILE_STATUS] = banks - 1; if (banks > 1) --banks; memory->mapping[gcvSURF_TYPE_UNKNOWN] = 0; gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM, "[GALCORE] INDEX: bank %d", memory->mapping[gcvSURF_INDEX]); gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM, "[GALCORE] VERTEX: bank %d", memory->mapping[gcvSURF_VERTEX]); gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM, "[GALCORE] TEXTURE: bank %d", memory->mapping[gcvSURF_TEXTURE]); gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM, "[GALCORE] RENDER_TARGET: bank %d", memory->mapping[gcvSURF_RENDER_TARGET]); gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM, "[GALCORE] DEPTH: bank %d", memory->mapping[gcvSURF_DEPTH]); gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM, "[GALCORE] TILE_STATUS: bank %d", memory->mapping[gcvSURF_TILE_STATUS]); /* Allocate the mutex. */ gcmkONERROR(gckOS_CreateMutex(Os, &memory->mutex)); /* Return pointer to the gckVIDMEM object. */ *Memory = memory; /* Success. */ gcmkFOOTER_ARG("*Memory=0x%x", *Memory); return gcvSTATUS_OK; OnError: /* Roll back. */ if (memory != gcvNULL) { if (memory->mutex != gcvNULL) { /* Delete the mutex. */ gcmkVERIFY_OK(gckOS_DeleteMutex(Os, memory->mutex)); } for (i = 0; i < banks; ++i) { /* Free the heap. */ gcmkASSERT(memory->sentinel[i].VidMem.next != gcvNULL); gcmkVERIFY_OK(gckOS_Free(Os, memory->sentinel[i].VidMem.next)); } /* Free the object. */ gcmkVERIFY_OK(gckOS_Free(Os, memory)); } /* Return the status. */ gcmkFOOTER(); return status; }
gceSTATUS gckKERNEL_MapLogicalToPhysical( IN gckKERNEL Kernel, IN gctHANDLE Process, IN OUT gctPOINTER * Data ) { gctUINT i, oldest; gceSTATUS status; gctUINT32 baseAddress; gcmkHEADER_ARG("Kernel=0x%x Process=0x%x *Data=0x%x", Kernel, Process, gcmOPT_POINTER(Data)); /* Verify the arguments. */ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); gcmkVERIFY_ARGUMENT(Data != gcvNULL); /* Get base address. */ gcmkONERROR(gckHARDWARE_GetBaseAddress(Kernel->hardware, &baseAddress)); /* Walk all used cache slots. */ for (i = oldest = 0; i < Kernel->cacheSlots; ++i) { if ((Kernel->cache[i].logical == *Data) && (Kernel->cache[i].process == Process) ) { /* Bail out. */ break; } if (i == 0) { /* First slot. */ oldest = i; } /* Test if this cache slot is older. */ else if (Kernel->cache[i].stamp < Kernel->cache[oldest].stamp) { oldest = i; } } /* See if we had a match. */ if (i == Kernel->cacheSlots) { /* See if there is room in the cache. */ if (i < gcmCOUNTOF(Kernel->cache)) { /* Just append to the cache. */ i = Kernel->cacheSlots++; } else { /* Evict the oldest cache line. */ i = oldest; } /* Initialize the cache line. */ Kernel->cache[i].logical = *Data; Kernel->cache[i].process = Process; /* Map the logical address to a DMA address. */ gcmkONERROR(gckOS_GetPhysicalAddress(Kernel->os, *Data, &Kernel->cache[i].dma)); if (baseAddress != 0) { gctBOOL needBase; /* Does this state load need a base address? */ gcmkONERROR(gckHARDWARE_NeedBaseAddress(Kernel->hardware, ((gctUINT32_PTR) Data)[-1], &needBase)); if (needBase) { /* Add the base address. */ Kernel->cache[i].dma += baseAddress; } } } /* Increment time stamp of the cache slot. */ Kernel->cache[i].stamp = Kernel->cacheTimeStamp++; /* Return DMA address. */ *Data = gcmINT2PTR(Kernel->cache[i].dma); /* Success. */ gcmkFOOTER_ARG("*Data=0x%08x", *Data); return gcvSTATUS_OK; OnError: gcmkLOG_ERROR_STATUS(); /* Return the status. */ gcmkFOOTER(); return status; }
/******************************************************************************* ** ** gckGALDEVICE_Construct ** ** Constructor. ** ** INPUT: ** ** OUTPUT: ** ** gckGALDEVICE * Device ** Pointer to a variable receiving the gckGALDEVICE object pointer on ** success. */ gceSTATUS gckGALDEVICE_Construct( IN gctINT IrqLine, IN gctUINT32 RegisterMemBase, IN gctSIZE_T RegisterMemSize, IN gctINT IrqLine2D, IN gctUINT32 RegisterMemBase2D, IN gctSIZE_T RegisterMemSize2D, IN gctINT IrqLineVG, IN gctUINT32 RegisterMemBaseVG, IN gctSIZE_T RegisterMemSizeVG, IN gctUINT32 ContiguousBase, IN gctSIZE_T ContiguousSize, IN gctSIZE_T BankSize, IN gctINT FastClear, IN gctINT Compression, IN gctUINT32 PhysBaseAddr, IN gctUINT32 PhysSize, IN gctINT Signal, IN gctUINT LogFileSize, OUT gckGALDEVICE *Device ) { gctUINT32 internalBaseAddress = 0, internalAlignment = 0; gctUINT32 externalBaseAddress = 0, externalAlignment = 0; gctUINT32 horizontalTileSize, verticalTileSize; struct resource* mem_region; gctUINT32 physAddr; gctUINT32 physical; gckGALDEVICE device; gceSTATUS status; gctINT32 i; gceHARDWARE_TYPE type; gckDB sharedDB = gcvNULL; gckKERNEL kernel = gcvNULL; gcmkHEADER_ARG("IrqLine=%d RegisterMemBase=0x%08x RegisterMemSize=%u " "IrqLine2D=%d RegisterMemBase2D=0x%08x RegisterMemSize2D=%u " "IrqLineVG=%d RegisterMemBaseVG=0x%08x RegisterMemSizeVG=%u " "ContiguousBase=0x%08x ContiguousSize=%lu BankSize=%lu " "FastClear=%d Compression=%d PhysBaseAddr=0x%x PhysSize=%d Signal=%d", IrqLine, RegisterMemBase, RegisterMemSize, IrqLine2D, RegisterMemBase2D, RegisterMemSize2D, IrqLineVG, RegisterMemBaseVG, RegisterMemSizeVG, ContiguousBase, ContiguousSize, BankSize, FastClear, Compression, PhysBaseAddr, PhysSize, Signal); /* Allocate device structure. */ device = kmalloc(sizeof(struct _gckGALDEVICE), GFP_KERNEL | __GFP_NOWARN); if (!device) { gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY); } memset(device, 0, sizeof(struct _gckGALDEVICE)); device->dbgnode = gcvNULL; if(LogFileSize != 0) { if(gckDebugFileSystemCreateNode(LogFileSize,PARENT_FILE,DEBUG_FILE,&(device->dbgnode)) != 0) { gcmkTRACE_ZONE( gcvLEVEL_ERROR, gcvZONE_DRIVER, "%s(%d): Failed to create the debug file system %s/%s \n", __FUNCTION__, __LINE__, PARENT_FILE, DEBUG_FILE ); } else { /*Everything is OK*/ gckDebugFileSystemSetCurrentNode(device->dbgnode); } } if (IrqLine != -1) { device->requestedRegisterMemBases[gcvCORE_MAJOR] = RegisterMemBase; device->requestedRegisterMemSizes[gcvCORE_MAJOR] = RegisterMemSize; } if (IrqLine2D != -1) { device->requestedRegisterMemBases[gcvCORE_2D] = RegisterMemBase2D; device->requestedRegisterMemSizes[gcvCORE_2D] = RegisterMemSize2D; } if (IrqLineVG != -1) { device->requestedRegisterMemBases[gcvCORE_VG] = RegisterMemBaseVG; device->requestedRegisterMemSizes[gcvCORE_VG] = RegisterMemSizeVG; } device->requestedContiguousBase = 0; device->requestedContiguousSize = 0; for (i = 0; i < gcdMAX_GPU_COUNT; i++) { physical = device->requestedRegisterMemBases[i]; /* Set up register memory region. */ if (physical != 0) { mem_region = request_mem_region( physical, device->requestedRegisterMemSizes[i], "galcore register region" ); if (mem_region == gcvNULL) { gcmkTRACE_ZONE( gcvLEVEL_ERROR, gcvZONE_DRIVER, "%s(%d): Failed to claim %lu bytes @ 0x%08X\n", __FUNCTION__, __LINE__, physical, device->requestedRegisterMemSizes[i] ); gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES); } device->registerBases[i] = (gctPOINTER) ioremap_nocache( physical, device->requestedRegisterMemSizes[i]); if (device->registerBases[i] == gcvNULL) { gcmkTRACE_ZONE( gcvLEVEL_ERROR, gcvZONE_DRIVER, "%s(%d): Unable to map %ld bytes @ 0x%08X\n", __FUNCTION__, __LINE__, physical, device->requestedRegisterMemSizes[i] ); gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES); } physical += device->requestedRegisterMemSizes[i]; } else { device->registerBases[i] = gcvNULL; } } /* Set the base address */ device->baseAddress = PhysBaseAddr; /* Construct the gckOS object. */ gcmkONERROR(gckOS_Construct(device, &device->os)); if (IrqLine != -1) { /* Construct the gckKERNEL object. */ gcmkONERROR(gckKERNEL_Construct( device->os, gcvCORE_MAJOR, device, gcvNULL, &device->kernels[gcvCORE_MAJOR])); sharedDB = device->kernels[gcvCORE_MAJOR]->db; /* Initialize core mapping */ for (i = 0; i < 8; i++) { device->coreMapping[i] = gcvCORE_MAJOR; } /* Setup the ISR manager. */ gcmkONERROR(gckHARDWARE_SetIsrManager( device->kernels[gcvCORE_MAJOR]->hardware, (gctISRMANAGERFUNC) gckGALDEVICE_Setup_ISR, (gctISRMANAGERFUNC) gckGALDEVICE_Release_ISR, device )); gcmkONERROR(gckHARDWARE_SetFastClear( device->kernels[gcvCORE_MAJOR]->hardware, FastClear, Compression )); #if COMMAND_PROCESSOR_VERSION == 1 /* Start the command queue. */ gcmkONERROR(gckCOMMAND_Start(device->kernels[gcvCORE_MAJOR]->command)); #endif } else { device->kernels[gcvCORE_MAJOR] = gcvNULL; } if (IrqLine2D != -1) { gcmkONERROR(gckKERNEL_Construct( device->os, gcvCORE_2D, device, sharedDB, &device->kernels[gcvCORE_2D])); if (sharedDB == gcvNULL) sharedDB = device->kernels[gcvCORE_2D]->db; /* Verify the hardware type */ gcmkONERROR(gckHARDWARE_GetType(device->kernels[gcvCORE_2D]->hardware, &type)); if (type != gcvHARDWARE_2D) { gcmkTRACE_ZONE( gcvLEVEL_ERROR, gcvZONE_DRIVER, "%s(%d): Unexpected hardware type: %d\n", __FUNCTION__, __LINE__, type ); gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT); } /* Initialize core mapping */ if (device->kernels[gcvCORE_MAJOR] == gcvNULL) { for (i = 0; i < 8; i++) { device->coreMapping[i] = gcvCORE_2D; } } else { device->coreMapping[gcvHARDWARE_2D] = gcvCORE_2D; } /* Setup the ISR manager. */ gcmkONERROR(gckHARDWARE_SetIsrManager( device->kernels[gcvCORE_2D]->hardware, (gctISRMANAGERFUNC) gckGALDEVICE_Setup_ISR_2D, (gctISRMANAGERFUNC) gckGALDEVICE_Release_ISR_2D, device )); #if COMMAND_PROCESSOR_VERSION == 1 /* Start the command queue. */ gcmkONERROR(gckCOMMAND_Start(device->kernels[gcvCORE_2D]->command)); #endif } else { device->kernels[gcvCORE_2D] = gcvNULL; } if (IrqLineVG != -1) { } else { device->kernels[gcvCORE_VG] = gcvNULL; } /* Initialize the ISR. */ device->irqLines[gcvCORE_MAJOR] = IrqLine; device->irqLines[gcvCORE_2D] = IrqLine2D; device->irqLines[gcvCORE_VG] = IrqLineVG; /* Initialize the kernel thread semaphores. */ for (i = 0; i < gcdMAX_GPU_COUNT; i++) { if (device->irqLines[i] != -1) sema_init(&device->semas[i], 0); } device->signal = Signal; for (i = 0; i < gcdMAX_GPU_COUNT; i++) { if (device->kernels[i] != gcvNULL) break; } if (i == gcdMAX_GPU_COUNT) { gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT); } { /* Query the ceiling of the system memory. */ gcmkONERROR(gckHARDWARE_QuerySystemMemory( device->kernels[i]->hardware, &device->systemMemorySize, &device->systemMemoryBaseAddress )); /* query the amount of video memory */ gcmkONERROR(gckHARDWARE_QueryMemory( device->kernels[i]->hardware, &device->internalSize, &internalBaseAddress, &internalAlignment, &device->externalSize, &externalBaseAddress, &externalAlignment, &horizontalTileSize, &verticalTileSize )); } /* Grab the first availiable kernel */ for (i = 0; i < gcdMAX_GPU_COUNT; i++) { if (device->irqLines[i] != -1) { kernel = device->kernels[i]; break; } } /* Set up the internal memory region. */ if (device->internalSize > 0) { status = gckVIDMEM_Construct( device->os, internalBaseAddress, device->internalSize, internalAlignment, 0, &device->internalVidMem ); if (gcmIS_ERROR(status)) { /* Error, disable internal heap. */ device->internalSize = 0; } else { /* Map internal memory. */ device->internalLogical = (gctPOINTER) ioremap_nocache(physical, device->internalSize); if (device->internalLogical == gcvNULL) { gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES); } device->internalPhysical = (gctPHYS_ADDR)(gctUINTPTR_T) physical; device->internalPhysicalName = gcmPTR_TO_NAME(device->internalPhysical); physical += device->internalSize; } } if (device->externalSize > 0) { /* create the external memory heap */ status = gckVIDMEM_Construct( device->os, externalBaseAddress, device->externalSize, externalAlignment, 0, &device->externalVidMem ); if (gcmIS_ERROR(status)) { /* Error, disable internal heap. */ device->externalSize = 0; } else { /* Map external memory. */ device->externalLogical = (gctPOINTER) ioremap_nocache(physical, device->externalSize); if (device->externalLogical == gcvNULL) { gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES); } device->externalPhysical = (gctPHYS_ADDR)(gctUINTPTR_T) physical; device->externalPhysicalName = gcmPTR_TO_NAME(device->externalPhysical); physical += device->externalSize; } } /* set up the contiguous memory */ device->contiguousSize = ContiguousSize; if (ContiguousSize > 0) { if (ContiguousBase == 0) { while (device->contiguousSize > 0) { /* Allocate contiguous memory. */ status = _AllocateMemory( device, device->contiguousSize, &device->contiguousBase, &device->contiguousPhysical, &physAddr ); if (gcmIS_SUCCESS(status)) { device->contiguousPhysicalName = gcmPTR_TO_NAME(device->contiguousPhysical); status = gckVIDMEM_Construct( device->os, physAddr | device->systemMemoryBaseAddress, device->contiguousSize, 64, BankSize, &device->contiguousVidMem ); if (gcmIS_SUCCESS(status)) { break; } gcmkONERROR(_FreeMemory( device, device->contiguousBase, device->contiguousPhysical )); gcmRELEASE_NAME(device->contiguousPhysicalName); device->contiguousBase = gcvNULL; device->contiguousPhysical = gcvNULL; } if (device->contiguousSize <= (4 << 20)) { device->contiguousSize = 0; } else { device->contiguousSize -= (4 << 20); } } } else { /* Create the contiguous memory heap. */ status = gckVIDMEM_Construct( device->os, ContiguousBase | device->systemMemoryBaseAddress, ContiguousSize, 64, BankSize, &device->contiguousVidMem ); if (gcmIS_ERROR(status)) { /* Error, disable contiguous memory pool. */ device->contiguousVidMem = gcvNULL; device->contiguousSize = 0; } else { mem_region = request_mem_region( ContiguousBase, ContiguousSize, "galcore managed memory" ); if (mem_region == gcvNULL) { gcmkTRACE_ZONE( gcvLEVEL_ERROR, gcvZONE_DRIVER, "%s(%d): Failed to claim %ld bytes @ 0x%08X\n", __FUNCTION__, __LINE__, ContiguousSize, ContiguousBase ); gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES); } device->requestedContiguousBase = ContiguousBase; device->requestedContiguousSize = ContiguousSize; device->contiguousPhysical = gcvNULL; device->contiguousPhysicalName = 0; device->contiguousSize = ContiguousSize; device->contiguousMapped = gcvTRUE; } } } /* Return pointer to the device. */ * Device = device; gcmkFOOTER_ARG("*Device=0x%x", * Device); return gcvSTATUS_OK; OnError: /* Roll back. */ gcmkVERIFY_OK(gckGALDEVICE_Destroy(device)); gcmkFOOTER(); return status; }
gceSTATUS gckKERNEL_Construct( IN gckOS Os, IN gctPOINTER Context, OUT gckKERNEL * Kernel ) { gckKERNEL kernel = gcvNULL; gceSTATUS status; gcmkHEADER_ARG("Os=0x%x Context=0x%x", Os, Context); /* Verify the arguments. */ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); gcmkVERIFY_ARGUMENT(Kernel != gcvNULL); /* Allocate the gckKERNEL object. */ gcmkONERROR( gckOS_Allocate(Os, gcmSIZEOF(struct _gckKERNEL), (gctPOINTER *) &kernel)); #if MRVL_LOW_POWER_MODE_DEBUG gcmERR_RETURN( gckOS_Allocate(Os, 0x1000000, (gctPOINTER *) &kernel->kernelMSG)); kernel->msgLen = 0; #endif /* Zero the object pointers. */ kernel->hardware = gcvNULL; kernel->command = gcvNULL; kernel->event = gcvNULL; kernel->mmu = gcvNULL; /* Initialize the gckKERNEL object. */ kernel->object.type = gcvOBJ_KERNEL; kernel->os = Os; /* Save context. */ kernel->context = Context; /* Construct atom holding number of clients. */ kernel->atomClients = gcvNULL; gcmkONERROR(gckOS_AtomConstruct(Os, &kernel->atomClients)); #if gcdSECURE_USER kernel->cacheSlots = 0; kernel->cacheTimeStamp = 0; #endif /* Construct the gckHARDWARE object. */ gcmkONERROR( gckHARDWARE_Construct(Os, &kernel->hardware)); /* Set pointer to gckKERNEL object in gckHARDWARE object. */ kernel->hardware->kernel = kernel; /* Initialize the hardware. */ gcmkONERROR( gckHARDWARE_InitializeHardware(kernel->hardware)); /* Construct the gckCOMMAND object. */ gcmkONERROR( gckCOMMAND_Construct(kernel, &kernel->command)); /* Construct the gckEVENT object. */ gcmkONERROR( gckEVENT_Construct(kernel, &kernel->event)); /* Construct the gckMMU object. */ gcmkONERROR( gckMMU_Construct(kernel, gcdMMU_SIZE, &kernel->mmu)); kernel->notifyIdle = gcvTRUE; /* gcvFALSE; */ #if VIVANTE_PROFILER /* Initialize profile setting */ #if defined ANDROID kernel->profileEnable = gcvFALSE; #else kernel->profileEnable = gcvTRUE; #endif gcmkVERIFY_OK( gckOS_MemCopy(kernel->profileFileName, DEFAULT_PROFILE_FILE_NAME, gcmSIZEOF(DEFAULT_PROFILE_FILE_NAME) + 1)); #endif /* Return pointer to the gckKERNEL object. */ *Kernel = kernel; /* Success. */ gcmkFOOTER_ARG("*Kernel=0x%x", *Kernel); return gcvSTATUS_OK; OnError: if (kernel != gcvNULL) { if (kernel->event != gcvNULL) { gcmkVERIFY_OK(gckEVENT_Destroy(kernel->event)); } if (kernel->command != gcvNULL) { gcmkVERIFY_OK(gckCOMMAND_Destroy(kernel->command)); } if (kernel->hardware != gcvNULL) { gcmkVERIFY_OK(gckHARDWARE_Destroy(kernel->hardware)); } if (kernel->atomClients != gcvNULL) { gcmkVERIFY_OK(gckOS_AtomDestroy(Os, kernel->atomClients)); } kernel->version = _GC_VERSION_STRING_; #if MRVL_LOW_POWER_MODE_DEBUG gcmkVERIFY_OK( gckOS_Free(Os, kernel->kernelMSG)); #endif gcmkVERIFY_OK(gckOS_Free(Os, kernel)); } /* Return the error. */ 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; }
int __devinit gpu_probe(struct platform_device *pdev) { int ret = -ENODEV; struct resource* res; gcmkHEADER(); #ifdef CONFIG_G2D #ifdef CONFIG_G2D_K3 g2d_core_clk = clk_get(NULL, "clk_g2d"); if (IS_ERR(g2d_core_clk)) { printk(KERN_ERR "Could not get clk_g2d!\n"); return ret; } ret = clk_set_rate(g2d_core_clk, 480000000); if (ret) { printk(KERN_ERR "G2D, %s: failed to set G2D clk rete, G2D clk = %p \n", __func__, g2d_core_clk); return ret; } #else g2d_core_clk = clk_get(NULL, CLK_5G2D_CORE_CLK); if (IS_ERR(g2d_core_clk)) { printk(KERN_ERR "Could not get g2d_core_clk!\n"); goto gpu_probe_fail; } g2d_axi_clkhb = clk_get(NULL, CLK_4G2D_AXI_CLKHB); if (IS_ERR(g2d_axi_clkhb)) { printk(KERN_ERR "Could not get g2d_axi_clkhb!\n"); goto gpu_probe_fail; } g2d_cfg_clk = clk_get(NULL, CLK_3G2D_CFG_CLK); if (IS_ERR(g2d_cfg_clk)) { printk(KERN_ERR "Could not get g2d_cfg_clk!\n"); goto gpu_probe_fail; } if (clk_set_rate(g2d_core_clk, G2D_CLK_RATE)) { printk(KERN_ERR "G2D, %s: failed to set G2D clk rete, G2D clk = %p \n", __func__, g2d_core_clk); goto gpu_probe_fail; } #endif res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "g2d_irq"); if (!res) { printk(KERN_ERR "%s: No irq line supplied.\n",__FUNCTION__); goto gpu_probe_fail; } irqLine = res->start; res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "g2d_base"); if (!res) { printk(KERN_ERR "%s: No register base supplied.\n",__FUNCTION__); goto gpu_probe_fail; } registerMemBase = res->start; registerMemSize = res->end - res->start + 1; #endif /* res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "gpu_mem"); if (!res) { printk(KERN_ERR "%s: No memory base supplied.\n",__FUNCTION__); goto gpu_probe_fail; } contiguousBase = res->start; contiguousSize = res->end - res->start + 1; */ ret = drv_init(); if (!ret) { platform_set_drvdata(pdev, galDevice); gcmkFOOTER_NO(); return ret; } gpu_probe_fail: gcmkFOOTER_ARG(KERN_INFO "Failed to register gpu driver: %d\n", ret); return ret; }
/******************************************************************************* ** ** 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; }
/******************************************************************************* ** gckKERNEL_FindDatabase ** ** Find a database identified by a process ID and move it to the head of the ** hash list. ** ** INPUT: ** ** gckKERNEL Kernel ** Pointer to a gckKERNEL object. ** ** gctUINT32 ProcessID ** ProcessID that identifies the database. ** ** gctBOOL LastProcessID ** gcvTRUE if searching for the last known process ID. gcvFALSE if ** we need to search for the process ID specified by the ProcessID ** argument. ** ** OUTPUT: ** ** gcsDATABASE_PTR * Database ** Pointer to a variable receiving the database structure pointer on ** success. */ static gceSTATUS gckKERNEL_FindDatabase( IN gckKERNEL Kernel, IN gctUINT32 ProcessID, IN gctBOOL LastProcessID, OUT gcsDATABASE_PTR * Database ) { gceSTATUS status; gcsDATABASE_PTR database, previous; gctSIZE_T slot; gctBOOL acquired = gcvFALSE; gcmkHEADER_ARG("Kernel=0x%x ProcessID=%d LastProcessID=%d", Kernel, ProcessID, LastProcessID); /* Compute the hash for the database. */ slot = ProcessID % gcmCOUNTOF(Kernel->db->db); /* Acquire the database mutex. */ gcmkONERROR( gckOS_AcquireMutex(Kernel->os, Kernel->db->dbMutex, gcvINFINITE)); acquired = gcvTRUE; /* Check whether we are getting the last known database. */ if (LastProcessID) { /* Use last database. */ database = Kernel->db->lastDatabase; if (database == gcvNULL) { /* Database not found. */ gcmkONERROR(gcvSTATUS_INVALID_DATA); } } else { /* Walk the hash list. */ for (previous = gcvNULL, database = Kernel->db->db[slot]; database != gcvNULL; database = database->next) { if (database->processID == ProcessID) { /* Found it! */ break; } previous = database; } if (database == gcvNULL) { /* Database not found. */ gcmkONERROR(gcvSTATUS_INVALID_DATA); } if (previous != gcvNULL) { /* Move database to the head of the hash list. */ previous->next = database->next; database->next = Kernel->db->db[slot]; Kernel->db->db[slot] = database; } } /* Release the database mutex. */ gcmkONERROR(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex)); /* Return the database. */ *Database = database; /* Success. */ gcmkFOOTER_ARG("*Database=0x%x", *Database); return gcvSTATUS_OK; OnError: if (acquired) { /* Release the database mutex. */ gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex)); } /* Return the status. */ gcmkFOOTER(); return status; }