/******************************************************************************* ** gckKERNEL_DeleteDatabase ** ** Remove a database from the hash list and delete its structure. ** ** INPUT: ** ** gckKERNEL Kernel ** Pointer to a gckKERNEL object. ** ** gcsDATABASE_PTR Database ** Pointer to the database structure to remove. ** ** OUTPUT: ** ** Nothing. */ static gceSTATUS gckKERNEL_DeleteDatabase( IN gckKERNEL Kernel, IN gcsDATABASE_PTR Database ) { gceSTATUS status; gctBOOL acquired = gcvFALSE; gcsDATABASE_PTR database; 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; /* Check slot value. */ gcmkVERIFY_ARGUMENT(Database->slot < gcmCOUNTOF(Kernel->db->db)); if (Database->slot < gcmCOUNTOF(Kernel->db->db)) { /* Check if database if the head of the hash list. */ if (Kernel->db->db[Database->slot] == Database) { /* Remove the database from the hash list. */ Kernel->db->db[Database->slot] = Database->next; } else { /* Walk the has list to find the database. */ for (database = Kernel->db->db[Database->slot]; database != gcvNULL; database = database->next ) { /* Check if the next list entry is this database. */ if (database->next == Database) { /* Remove the database from the hash list. */ database->next = Database->next; break; } } if (database == gcvNULL) { /* Ouch! Something got corrupted. */ gcmkONERROR(gcvSTATUS_INVALID_DATA); } } } if (Kernel->db->lastDatabase != gcvNULL) { /* Insert database to the free list. */ Kernel->db->lastDatabase->next = Kernel->db->freeDatabase; Kernel->db->freeDatabase = Kernel->db->lastDatabase; } /* Keep database as the last database. */ Kernel->db->lastDatabase = Database; /* Release the database mutex. */ gcmkONERROR(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex)); /* Success. */ gcmkFOOTER_NO(); 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_AddProcessDB ** ** Add a record to 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 add. ** ** gctPOINTER Pointer ** Data of the record to add. ** ** gctPHYS_ADDR Physical ** Physical address of the record to add. ** ** gctSIZE_T Size ** Size of the record to add. ** ** OUTPUT: ** ** Nothing. */ gceSTATUS gckKERNEL_AddProcessDB( IN gckKERNEL Kernel, IN gctUINT32 ProcessID, IN gceDATABASE_TYPE Type, IN gctPOINTER Pointer, IN gctPHYS_ADDR Physical, IN gctSIZE_T Size ) { gceSTATUS status; gcsDATABASE_PTR database; gcsDATABASE_RECORD_PTR record = gcvNULL; gcsDATABASE_COUNTERS * count; gcmkHEADER_ARG("Kernel=0x%x ProcessID=%d Type=%d Pointer=0x%x " "Physical=0x%x Size=%lu", Kernel, ProcessID, Type, Pointer, Physical, Size); /* Verify the arguments. */ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); /* Special case the idle record. */ if (Type == gcvDB_IDLE) { gctUINT64 time; /* Get the current profile time. */ gcmkONERROR(gckOS_GetProfileTick(&time)); if ((ProcessID == 0) && (Kernel->db->lastIdle != 0)) { /* Out of idle, adjust time it was idle. */ Kernel->db->idleTime += time - Kernel->db->lastIdle; Kernel->db->lastIdle = 0; } else if (ProcessID == 1) { /* Save current idle time. */ Kernel->db->lastIdle = time; } #if gcdDYNAMIC_SPEED { /* Test for first call. */ if (Kernel->db->lastSlowdown == 0) { /* Save milliseconds. */ Kernel->db->lastSlowdown = time; Kernel->db->lastSlowdownIdle = Kernel->db->idleTime; } else { /* Compute ellapsed time in milliseconds. */ gctUINT delta = gckOS_ProfileToMS(time - Kernel->db->lastSlowdown); /* Test for end of period. */ if (delta >= gcdDYNAMIC_SPEED) { /* Compute number of idle milliseconds. */ gctUINT idle = gckOS_ProfileToMS( Kernel->db->idleTime - Kernel->db->lastSlowdownIdle); /* Broadcast to slow down the GPU. */ gcmkONERROR(gckOS_BroadcastCalibrateSpeed(Kernel->os, Kernel->hardware, idle, delta)); /* Save current time. */ Kernel->db->lastSlowdown = time; Kernel->db->lastSlowdownIdle = Kernel->db->idleTime; } } } #endif /* Success. */ gcmkFOOTER_NO(); return gcvSTATUS_OK; } /* Verify the arguments. */ gcmkVERIFY_ARGUMENT(Pointer != gcvNULL); /* Find the database. */ gcmkONERROR(gckKERNEL_FindDatabase(Kernel, ProcessID, gcvFALSE, &database)); /* Create a new record in the database. */ gcmkONERROR(gckKERNEL_NewRecord(Kernel, database, _GetSlot(database, Pointer), &record)); /* Initialize the record. */ record->kernel = Kernel; record->type = Type; record->data = Pointer; record->physical = Physical; record->bytes = Size; /* Get pointer to counters. */ switch (Type) { case gcvDB_VIDEO_MEMORY: count = &database->vidMem; break; case gcvDB_NON_PAGED: count = &database->nonPaged; break; case gcvDB_CONTIGUOUS: count = &database->contiguous; break; case gcvDB_MAP_MEMORY: count = &database->mapMemory; break; case gcvDB_MAP_USER_MEMORY: count = &database->mapUserMemory; break; default: count = gcvNULL; break; } if (count != gcvNULL) { /* Adjust counters. */ count->totalBytes += Size; count->bytes += Size; if (count->bytes > count->maxBytes) { count->maxBytes = count->bytes; } } /* Success. */ gcmkFOOTER_NO(); return gcvSTATUS_OK; OnError: /* Return the status. */ gcmkFOOTER(); return status; }
/******************************************************************************* ** gckKERNEL_QueryProcessDB ** ** Query a process database for the current usage of a particular record type. ** ** INPUT: ** ** gckKERNEL Kernel ** Pointer to a gckKERNEL object. ** ** gctUINT32 ProcessID ** Process ID used to identify 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. ** ** gceDATABASE_TYPE Type ** Type of the record to query. ** ** OUTPUT: ** ** gcuDATABASE_INFO * Info ** Pointer to a variable that receives the requested information. */ gceSTATUS gckKERNEL_QueryProcessDB( IN gckKERNEL Kernel, IN gctUINT32 ProcessID, IN gctBOOL LastProcessID, IN gceDATABASE_TYPE Type, OUT gcuDATABASE_INFO * Info ) { gceSTATUS status; gcsDATABASE_PTR database; gcmkHEADER_ARG("Kernel=0x%x ProcessID=%d Type=%d Info=0x%x", Kernel, ProcessID, Type, Info); /* Verify the arguments. */ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); gcmkVERIFY_ARGUMENT(Info != gcvNULL); /* Find the database. */ gcmkONERROR( gckKERNEL_FindDatabase(Kernel, ProcessID, LastProcessID, &database)); /* Get pointer to counters. */ switch (Type) { case gcvDB_VIDEO_MEMORY: gcmkONERROR(gckOS_MemCopy(&Info->counters, &database->vidMem, gcmSIZEOF(database->vidMem))); break; case gcvDB_NON_PAGED: gcmkONERROR(gckOS_MemCopy(&Info->counters, &database->nonPaged, gcmSIZEOF(database->vidMem))); break; case gcvDB_CONTIGUOUS: gcmkONERROR(gckOS_MemCopy(&Info->counters, &database->contiguous, gcmSIZEOF(database->vidMem))); break; case gcvDB_IDLE: Info->time = Kernel->db->idleTime; Kernel->db->idleTime = 0; break; case gcvDB_MAP_MEMORY: gcmkONERROR(gckOS_MemCopy(&Info->counters, &database->mapMemory, gcmSIZEOF(database->mapMemory))); break; case gcvDB_MAP_USER_MEMORY: gcmkONERROR(gckOS_MemCopy(&Info->counters, &database->mapUserMemory, gcmSIZEOF(database->mapUserMemory))); break; default: break; } /* Success. */ gcmkFOOTER_NO(); return gcvSTATUS_OK; OnError: /* 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; }
/******************************************************************************* ** ** gckKERNEL_Dispatch ** ** Dispatch a command received from the user HAL layer. ** ** INPUT: ** ** gckKERNEL Kernel ** Pointer to an gckKERNEL object. ** ** gcsHAL_INTERFACE * Interface ** Pointer to a gcsHAL_INTERFACE structure that defines the command to ** be dispatched. ** ** OUTPUT: ** ** gcsHAL_INTERFACE * Interface ** Pointer to a gcsHAL_INTERFACE structure that receives any data to be ** returned. */ gceSTATUS gckVGKERNEL_Dispatch( IN gckKERNEL Kernel, IN gctBOOL FromUser, IN OUT gcsHAL_INTERFACE * Interface ) { gceSTATUS status; gcsHAL_INTERFACE * kernelInterface = Interface; gcuVIDMEM_NODE_PTR node; gctUINT32 processID; gckKERNEL kernel = Kernel; gctPOINTER info = gcvNULL; gctPHYS_ADDR physical = gcvNULL; gctPOINTER logical = gcvNULL; gctSIZE_T bytes = 0; gcmkHEADER_ARG("Kernel=0x%x Interface=0x%x ", Kernel, Interface); /* Verify the arguments. */ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); gcmkVERIFY_ARGUMENT(Interface != gcvNULL); gcmkONERROR(gckOS_GetProcessID(&processID)); /* Dispatch on command. */ switch (Interface->command) { case gcvHAL_QUERY_VIDEO_MEMORY: /* Query video memory size. */ gcmkERR_BREAK(gckKERNEL_QueryVideoMemory( Kernel, kernelInterface )); break; case gcvHAL_QUERY_CHIP_IDENTITY: /* Query chip identity. */ gcmkERR_BREAK(gckVGHARDWARE_QueryChipIdentity( Kernel->vg->hardware, &kernelInterface->u.QueryChipIdentity.chipModel, &kernelInterface->u.QueryChipIdentity.chipRevision, &kernelInterface->u.QueryChipIdentity.chipFeatures, &kernelInterface->u.QueryChipIdentity.chipMinorFeatures, &kernelInterface->u.QueryChipIdentity.chipMinorFeatures2 )); break; case gcvHAL_QUERY_COMMAND_BUFFER: /* Query command buffer information. */ gcmkERR_BREAK(gckKERNEL_QueryCommandBuffer( Kernel, &kernelInterface->u.QueryCommandBuffer.information )); break; case gcvHAL_ALLOCATE_NON_PAGED_MEMORY: bytes = (gctSIZE_T) kernelInterface->u.AllocateNonPagedMemory.bytes; /* Allocate non-paged memory. */ gcmkERR_BREAK(gckOS_AllocateContiguous( Kernel->os, gcvTRUE, &bytes, &physical, &logical )); kernelInterface->u.AllocateNonPagedMemory.bytes = bytes; kernelInterface->u.AllocateNonPagedMemory.logical = gcmPTR_TO_UINT64(logical); kernelInterface->u.AllocateNonPagedMemory.physical = gcmPTR_TO_NAME(physical); break; case gcvHAL_FREE_NON_PAGED_MEMORY: physical = gcmNAME_TO_PTR(kernelInterface->u.AllocateNonPagedMemory.physical); /* Unmap user logical out of physical memory first. */ gcmkERR_BREAK(gckOS_UnmapUserLogical( Kernel->os, physical, (gctSIZE_T) kernelInterface->u.AllocateNonPagedMemory.bytes, gcmUINT64_TO_PTR(kernelInterface->u.AllocateNonPagedMemory.logical) )); /* Free non-paged memory. */ gcmkERR_BREAK(gckOS_FreeNonPagedMemory( Kernel->os, (gctSIZE_T) kernelInterface->u.AllocateNonPagedMemory.bytes, physical, gcmUINT64_TO_PTR(kernelInterface->u.AllocateNonPagedMemory.logical) )); gcmRELEASE_NAME(kernelInterface->u.AllocateNonPagedMemory.physical); break; case gcvHAL_ALLOCATE_CONTIGUOUS_MEMORY: bytes = (gctSIZE_T) kernelInterface->u.AllocateNonPagedMemory.bytes; /* Allocate contiguous memory. */ gcmkERR_BREAK(gckOS_AllocateContiguous( Kernel->os, gcvTRUE, &bytes, &physical, &logical )); kernelInterface->u.AllocateNonPagedMemory.bytes = bytes; kernelInterface->u.AllocateNonPagedMemory.logical = gcmPTR_TO_UINT64(logical); kernelInterface->u.AllocateNonPagedMemory.physical = gcmPTR_TO_NAME(physical); break; case gcvHAL_FREE_CONTIGUOUS_MEMORY: physical = gcmNAME_TO_PTR(kernelInterface->u.AllocateNonPagedMemory.physical); /* Unmap user logical out of physical memory first. */ gcmkERR_BREAK(gckOS_UnmapUserLogical( Kernel->os, physical, (gctSIZE_T) kernelInterface->u.AllocateNonPagedMemory.bytes, gcmUINT64_TO_PTR(kernelInterface->u.AllocateNonPagedMemory.logical) )); /* Free contiguous memory. */ gcmkERR_BREAK(gckOS_FreeContiguous( Kernel->os, physical, gcmUINT64_TO_PTR(kernelInterface->u.AllocateNonPagedMemory.logical), (gctSIZE_T) kernelInterface->u.AllocateNonPagedMemory.bytes )); gcmRELEASE_NAME(kernelInterface->u.AllocateNonPagedMemory.physical); break; case gcvHAL_ALLOCATE_VIDEO_MEMORY: { gctSIZE_T bytes; gctUINT32 bitsPerPixel; gctUINT32 bits; /* Align width and height to tiles. */ gcmkERR_BREAK(gckVGHARDWARE_AlignToTile( Kernel->vg->hardware, kernelInterface->u.AllocateVideoMemory.type, &kernelInterface->u.AllocateVideoMemory.width, &kernelInterface->u.AllocateVideoMemory.height )); /* Convert format into bytes per pixel and bytes per tile. */ gcmkERR_BREAK(gckVGHARDWARE_ConvertFormat( Kernel->vg->hardware, kernelInterface->u.AllocateVideoMemory.format, &bitsPerPixel, gcvNULL )); /* Compute number of bits for the allocation. */ bits = kernelInterface->u.AllocateVideoMemory.width * kernelInterface->u.AllocateVideoMemory.height * kernelInterface->u.AllocateVideoMemory.depth * bitsPerPixel; /* Compute number of bytes for the allocation. */ bytes = gcmALIGN(bits, 8) / 8; /* Allocate memory. */ gcmkERR_BREAK(gckKERNEL_AllocateLinearMemory( Kernel, &kernelInterface->u.AllocateVideoMemory.pool, bytes, 64, kernelInterface->u.AllocateVideoMemory.type, &node )); kernelInterface->u.AllocateVideoMemory.node = gcmPTR_TO_UINT64(node); } break; case gcvHAL_ALLOCATE_LINEAR_VIDEO_MEMORY: /* Allocate memory. */ gcmkERR_BREAK(gckKERNEL_AllocateLinearMemory( Kernel, &kernelInterface->u.AllocateLinearVideoMemory.pool, kernelInterface->u.AllocateLinearVideoMemory.bytes, kernelInterface->u.AllocateLinearVideoMemory.alignment, kernelInterface->u.AllocateLinearVideoMemory.type, &node )); gcmkERR_BREAK(gckKERNEL_AddProcessDB(Kernel, processID, gcvDB_VIDEO_MEMORY, node, gcvNULL, kernelInterface->u.AllocateLinearVideoMemory.bytes )); kernelInterface->u.AllocateLinearVideoMemory.node = gcmPTR_TO_UINT64(node); break; case gcvHAL_FREE_VIDEO_MEMORY: node = gcmUINT64_TO_PTR(Interface->u.FreeVideoMemory.node); #ifdef __QNXNTO__ /* Unmap the video memory */ if ((node->VidMem.memory->object.type == gcvOBJ_VIDMEM) && (node->VidMem.logical != gcvNULL)) { gckKERNEL_UnmapVideoMemory(Kernel, node->VidMem.logical, processID, node->VidMem.bytes); node->VidMem.logical = gcvNULL; } #endif /* __QNXNTO__ */ /* Free video memory. */ gcmkERR_BREAK(gckVIDMEM_Free( node )); gcmkERR_BREAK(gckKERNEL_RemoveProcessDB( Kernel, processID, gcvDB_VIDEO_MEMORY, node )); break; case gcvHAL_MAP_MEMORY: /* Map memory. */ gcmkERR_BREAK(gckKERNEL_MapMemory( Kernel, gcmINT2PTR(kernelInterface->u.MapMemory.physical), (gctSIZE_T) kernelInterface->u.MapMemory.bytes, &logical )); kernelInterface->u.MapMemory.logical = gcmPTR_TO_UINT64(logical); break; case gcvHAL_UNMAP_MEMORY: /* Unmap memory. */ gcmkERR_BREAK(gckKERNEL_UnmapMemory( Kernel, gcmINT2PTR(kernelInterface->u.MapMemory.physical), (gctSIZE_T) kernelInterface->u.MapMemory.bytes, gcmUINT64_TO_PTR(kernelInterface->u.MapMemory.logical) )); break; case gcvHAL_MAP_USER_MEMORY: /* Map user memory to DMA. */ gcmkERR_BREAK(gckOS_MapUserMemory( Kernel->os, gcvCORE_VG, gcmUINT64_TO_PTR(kernelInterface->u.MapUserMemory.memory), kernelInterface->u.MapUserMemory.physical, (gctSIZE_T) kernelInterface->u.MapUserMemory.size, &info, &kernelInterface->u.MapUserMemory.address )); kernelInterface->u.MapUserMemory.info = gcmPTR_TO_NAME(info); break; case gcvHAL_UNMAP_USER_MEMORY: /* Unmap user memory. */ gcmkERR_BREAK(gckOS_UnmapUserMemory( Kernel->os, gcvCORE_VG, gcmUINT64_TO_PTR(kernelInterface->u.UnmapUserMemory.memory), (gctSIZE_T) kernelInterface->u.UnmapUserMemory.size, gcmNAME_TO_PTR(kernelInterface->u.UnmapUserMemory.info), kernelInterface->u.UnmapUserMemory.address )); gcmRELEASE_NAME(kernelInterface->u.UnmapUserMemory.info); break; case gcvHAL_LOCK_VIDEO_MEMORY: node = gcmUINT64_TO_PTR(Interface->u.LockVideoMemory.node); /* Lock video memory. */ gcmkERR_BREAK( gckVIDMEM_Lock(Kernel, node, gcvFALSE, &Interface->u.LockVideoMemory.address)); if (node->VidMem.memory->object.type == gcvOBJ_VIDMEM) { /* Map video memory address into user space. */ #ifdef __QNXNTO__ if (node->VidMem.logical == gcvNULL) { gcmkONERROR( gckKERNEL_MapVideoMemory(Kernel, FromUser, Interface->u.LockVideoMemory.address, processID, node->VidMem.bytes, &node->VidMem.logical)); } Interface->u.LockVideoMemory.memory = gcmPTR_TO_UINT64(node->VidMem.logical); #else gcmkERR_BREAK( gckKERNEL_MapVideoMemoryEx(Kernel, gcvCORE_VG, FromUser, Interface->u.LockVideoMemory.address, &logical)); Interface->u.LockVideoMemory.memory = gcmPTR_TO_UINT64(logical); #endif } else { Interface->u.LockVideoMemory.memory = gcmPTR_TO_UINT64(node->Virtual.logical); /* Success. */ status = gcvSTATUS_OK; } #if gcdSECURE_USER /* Return logical address as physical address. */ Interface->u.LockVideoMemory.address = (gctUINT32)(Interface->u.LockVideoMemory.memory); #endif gcmkERR_BREAK( gckKERNEL_AddProcessDB(Kernel, processID, gcvDB_VIDEO_MEMORY_LOCKED, node, gcvNULL, 0)); break; case gcvHAL_UNLOCK_VIDEO_MEMORY: /* Unlock video memory. */ node = gcmUINT64_TO_PTR(Interface->u.UnlockVideoMemory.node); #if gcdSECURE_USER /* Save node information before it disappears. */ if (node->VidMem.memory->object.type == gcvOBJ_VIDMEM) { logical = gcvNULL; bytes = 0; } else { logical = node->Virtual.logical; bytes = node->Virtual.bytes; } #endif /* Unlock video memory. */ gcmkERR_BREAK( gckVIDMEM_Unlock(Kernel, node, Interface->u.UnlockVideoMemory.type, &Interface->u.UnlockVideoMemory.asynchroneous)); #if gcdSECURE_USER /* Flush the translation cache for virtual surfaces. */ if (logical != gcvNULL) { gcmkVERIFY_OK(gckKERNEL_FlushTranslationCache(Kernel, cache, logical, bytes)); } #endif if (Interface->u.UnlockVideoMemory.asynchroneous == gcvFALSE) { /* There isn't a event to unlock this node, remove record now */ gcmkERR_BREAK( gckKERNEL_RemoveProcessDB(Kernel, processID, gcvDB_VIDEO_MEMORY_LOCKED, node)); } break; case gcvHAL_USER_SIGNAL: #if !USE_NEW_LINUX_SIGNAL /* Dispatch depends on the user signal subcommands. */ switch(Interface->u.UserSignal.command) { case gcvUSER_SIGNAL_CREATE: /* Create a signal used in the user space. */ gcmkERR_BREAK( gckOS_CreateUserSignal(Kernel->os, Interface->u.UserSignal.manualReset, &Interface->u.UserSignal.id)); gcmkVERIFY_OK( gckKERNEL_AddProcessDB(Kernel, processID, gcvDB_SIGNAL, gcmINT2PTR(Interface->u.UserSignal.id), gcvNULL, 0)); break; case gcvUSER_SIGNAL_DESTROY: /* Destroy the signal. */ gcmkERR_BREAK( gckOS_DestroyUserSignal(Kernel->os, Interface->u.UserSignal.id)); gcmkVERIFY_OK(gckKERNEL_RemoveProcessDB( Kernel, processID, gcvDB_SIGNAL, gcmINT2PTR(Interface->u.UserSignal.id))); break; case gcvUSER_SIGNAL_SIGNAL: /* Signal the signal. */ gcmkERR_BREAK( gckOS_SignalUserSignal(Kernel->os, Interface->u.UserSignal.id, Interface->u.UserSignal.state)); break; case gcvUSER_SIGNAL_WAIT: /* Wait on the signal. */ status = gckOS_WaitUserSignal(Kernel->os, Interface->u.UserSignal.id, Interface->u.UserSignal.wait); break; default: /* Invalid user signal command. */ gcmkERR_BREAK(gcvSTATUS_INVALID_ARGUMENT); } #endif break; case gcvHAL_COMMIT: /* Commit a command and context buffer. */ gcmkERR_BREAK(gckVGCOMMAND_Commit( Kernel->vg->command, gcmUINT64_TO_PTR(kernelInterface->u.VGCommit.context), gcmUINT64_TO_PTR(kernelInterface->u.VGCommit.queue), kernelInterface->u.VGCommit.entryCount, gcmUINT64_TO_PTR(kernelInterface->u.VGCommit.taskTable) )); break; case gcvHAL_VERSION: kernelInterface->u.Version.major = gcvVERSION_MAJOR; kernelInterface->u.Version.minor = gcvVERSION_MINOR; kernelInterface->u.Version.patch = gcvVERSION_PATCH; kernelInterface->u.Version.build = gcvVERSION_BUILD; status = gcvSTATUS_OK; break; case gcvHAL_GET_BASE_ADDRESS: /* Get base address. */ gcmkERR_BREAK( gckOS_GetBaseAddress(Kernel->os, &kernelInterface->u.GetBaseAddress.baseAddress)); break; default: /* Invalid command. */ status = gcvSTATUS_INVALID_ARGUMENT; } OnError: /* Save status. */ kernelInterface->status = status; gcmkFOOTER(); /* Return the status. */ return status; }
/******************************************************************************* ** ** gckCOMMAND_Construct ** ** Construct a new gckCOMMAND object. ** ** INPUT: ** ** gckKERNEL Kernel ** Pointer to an gckKERNEL object. ** ** OUTPUT: ** ** gckCOMMAND * Command ** Pointer to a variable that will hold the pointer to the gckCOMMAND ** object. */ gceSTATUS gckCOMMAND_Construct( IN gckKERNEL Kernel, OUT gckCOMMAND * Command ) { gckOS os; gckCOMMAND command = gcvNULL; gceSTATUS status; gctINT i; gcmkHEADER_ARG("Kernel=0x%x", Kernel); /* Verify the arguments. */ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); gcmkVERIFY_ARGUMENT(Command != gcvNULL); /* Extract the gckOS object. */ os = Kernel->os; /* Allocate the gckCOMMAND structure. */ gcmkONERROR( gckOS_Allocate(os, gcmSIZEOF(struct _gckCOMMAND), (gctPOINTER *) &command)); /* Initialize the gckCOMMAND object.*/ command->object.type = gcvOBJ_COMMAND; command->kernel = Kernel; command->os = os; command->mutexQueue = gcvNULL; command->mutexContext = gcvNULL; /* No command queues created yet. */ command->index = 0; for (i = 0; i < gcdCOMMAND_QUEUES; ++i) { command->queues[i].signal = gcvNULL; command->queues[i].logical = gcvNULL; } /* Get the command buffer requirements. */ gcmkONERROR( gckHARDWARE_QueryCommandBuffer(Kernel->hardware, &command->alignment, &command->reservedHead, &command->reservedTail)); /* No contexts available yet. */ command->contextCounter = command->currentContext = 0; /* Create the command queue mutex. */ gcmkONERROR( gckOS_CreateMutex(os, &command->mutexQueue)); /* Create the context switching mutex. */ gcmkONERROR( gckOS_CreateMutex(os, &command->mutexContext)); /* Get the page size from teh OS. */ gcmkONERROR( gckOS_GetPageSize(os, &command->pageSize)); /* Set hardware to pipe 0. */ command->pipeSelect = 0; /* Pre-allocate the command queues. */ for (i = 0; i < gcdCOMMAND_QUEUES; ++i) { gcmkONERROR( gckOS_AllocateNonPagedMemory(os, gcvFALSE, &command->pageSize, &command->queues[i].physical, &command->queues[i].logical)); gcmkONERROR( gckOS_CreateSignal(os, gcvFALSE, &command->queues[i].signal)); gcmkONERROR( gckOS_Signal(os, command->queues[i].signal, gcvTRUE)); } /* No command queue in use yet. */ command->index = -1; command->logical = gcvNULL; command->newQueue = gcvFALSE; command->submit = gcvFALSE; /* Command is not yet running. */ command->running = gcvFALSE; /* Command queue is idle. */ command->idle = gcvTRUE; /* Commit stamp is zero. */ command->commitStamp = 0; /* Return pointer to the gckCOMMAND object. */ *Command = command; /* Success. */ gcmkFOOTER_ARG("*Command=0x%x", *Command); return gcvSTATUS_OK; OnError: /* Roll back. */ if (command != gcvNULL) { if (command->mutexContext != gcvNULL) { gcmkVERIFY_OK(gckOS_DeleteMutex(os, command->mutexContext)); } if (command->mutexQueue != gcvNULL) { gcmkVERIFY_OK(gckOS_DeleteMutex(os, command->mutexQueue)); } for (i = 0; i < gcdCOMMAND_QUEUES; ++i) { if (command->queues[i].signal != gcvNULL) { gcmkVERIFY_OK( gckOS_DestroySignal(os, command->queues[i].signal)); } if (command->queues[i].logical != gcvNULL) { gcmkVERIFY_OK( gckOS_FreeNonPagedMemory(os, command->pageSize, command->queues[i].physical, command->queues[i].logical)); } } gcmkVERIFY_OK(gckOS_Free(os, command)); } /* Return the status. */ gcmkFOOTER(); return status; }
/******************************************************************************* ** gckKERNEL_RemoveProcessDB ** ** Remove 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: ** ** Nothing. */ gceSTATUS gckKERNEL_RemoveProcessDB( IN gckKERNEL Kernel, IN gctUINT32 ProcessID, IN gceDATABASE_TYPE Type, IN gctPOINTER Pointer ) { gceSTATUS status; gcsDATABASE_PTR database; gctSIZE_T bytes = 0; gcmkHEADER_ARG("Kernel=0x%x ProcessID=%d Type=%d Pointer=0x%x", Kernel, ProcessID, Type, Pointer); /* Verify the arguments. */ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); gcmkVERIFY_ARGUMENT(Pointer != gcvNULL); /* Find the database. */ gcmkONERROR(gckKERNEL_FindDatabase(Kernel, ProcessID, gcvFALSE, &database)); /* Delete the record. */ gcmkONERROR( gckKERNEL_DeleteRecord(Kernel, database, Type, Pointer, &bytes)); /* Update counters. */ switch (Type) { case gcvDB_VIDEO_MEMORY: database->vidMem.bytes -= bytes; break; case gcvDB_NON_PAGED: database->nonPaged.bytes -= bytes; break; case gcvDB_CONTIGUOUS: database->contiguous.bytes -= bytes; break; case gcvDB_MAP_MEMORY: database->mapMemory.bytes -= bytes; break; case gcvDB_MAP_USER_MEMORY: database->mapUserMemory.bytes -= bytes; break; case gcvDB_VIDEO_MEMORY_RESERVED: database->vidMemResv.bytes -= bytes; break; case gcvDB_VIDEO_MEMORY_CONTIGUOUS: database->vidMemCont.bytes -= bytes; break; case gcvDB_VIDEO_MEMORY_VIRTUAL: database->vidMemVirt.bytes -= bytes; break; default: break; } /* Success. */ gcmkFOOTER_NO(); return gcvSTATUS_OK; OnError: /* Return the status. */ gcmkFOOTER(); return status; }