/******************************************************************************* ** ** gckCOMMAND_Commit ** ** Commit a command buffer to the command queue. ** ** INPUT: ** ** gckCOMMAND Command ** Pointer to an gckCOMMAND object. ** ** gcoCMDBUF CommandBuffer ** Pointer to an gcoCMDBUF object. ** ** gcoCONTEXT Context ** Pointer to an gcoCONTEXT object. ** ** OUTPUT: ** ** Nothing. */ gceSTATUS gckCOMMAND_Commit( IN gckCOMMAND Command, IN gcoCMDBUF CommandBuffer, IN gcoCONTEXT Context, IN gctHANDLE Process ) { gcoCMDBUF commandBuffer; gcoCONTEXT context; gckHARDWARE hardware; gceSTATUS status; gctPOINTER initialLink, link; gctSIZE_T bytes, initialSize, lastRun; gcoCMDBUF buffer; gctPOINTER wait; gctSIZE_T waitSize; gctUINT32 offset; gctPOINTER fetchAddress; gctSIZE_T fetchSize; gctUINT8_PTR logical; gcsMAPPED_PTR stack = gcvNULL; gctINT acquired = 0; #if gcdSECURE_USER gctUINT32_PTR hint; #endif #if gcdDUMP_COMMAND gctPOINTER dataPointer; gctSIZE_T dataBytes; #endif gctPOINTER flushPointer; gctSIZE_T flushSize; gcmkHEADER_ARG("Command=0x%x CommandBuffer=0x%x Context=0x%x", Command, CommandBuffer, Context); /* Verify the arguments. */ gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND); #if gcdNULL_DRIVER == 2 /* Do nothing with infinite hardware. */ gcmkFOOTER_NO(); return gcvSTATUS_OK; #endif gcmkONERROR( _AddMap(Command->os, CommandBuffer, gcmSIZEOF(struct _gcoCMDBUF), (gctPOINTER *) &commandBuffer, &stack)); gcmkVERIFY_OBJECT(commandBuffer, gcvOBJ_COMMANDBUFFER); gcmkONERROR( _AddMap(Command->os, Context, gcmSIZEOF(struct _gcoCONTEXT), (gctPOINTER *) &context, &stack)); gcmkVERIFY_OBJECT(context, gcvOBJ_CONTEXT); /* Extract the gckHARDWARE and gckEVENT objects. */ hardware = Command->kernel->hardware; gcmkVERIFY_OBJECT(hardware, gcvOBJ_HARDWARE); /* Acquire the context switching mutex. */ gcmkONERROR( gckOS_AcquireMutex(Command->os, Command->mutexContext, gcvINFINITE)); ++acquired; /* Reserved slot in the context or command buffer. */ gcmkONERROR( gckHARDWARE_PipeSelect(hardware, gcvNULL, 0, &bytes)); /* Test if we need to switch to this context. */ if ((context->id != 0) && (context->id != Command->currentContext) ) { /* Map the context buffer.*/ gcmkONERROR( _AddMap(Command->os, context->logical, context->bufferSize, (gctPOINTER *) &logical, &stack)); #if gcdSECURE_USER /* Map the hint array.*/ gcmkONERROR( _AddMap(Command->os, context->hintArray, context->hintCount * gcmSIZEOF(gctUINT32), (gctPOINTER *) &hint, &stack)); /* Loop while we have valid hints. */ while (*hint != 0) { /* Map handle into physical address. */ gcmkONERROR( gckKERNEL_MapLogicalToPhysical( Command->kernel, Process, (gctPOINTER *) (logical + *hint))); /* Next hint. */ ++hint; } #endif /* See if we have to check pipes. */ if (context->pipe2DIndex != 0) { /* See if we are in the correct pipe. */ if (context->initialPipe == Command->pipeSelect) { gctUINT32 reserved = bytes; gctUINT8_PTR nop = logical; /* Already in the correct pipe, fill context buffer with NOP. */ while (reserved > 0) { bytes = reserved; gcmkONERROR( gckHARDWARE_Nop(hardware, nop, &bytes)); gcmkASSERT(reserved >= bytes); reserved -= bytes; nop += bytes; } } else { /* Switch to the correct pipe. */ gcmkONERROR( gckHARDWARE_PipeSelect(hardware, logical, context->initialPipe, &bytes)); } } /* Save initial link pointer. */ initialLink = logical; initialSize = context->bufferSize; #if MRVL_PRINT_CMD_BUFFER _AddCmdBuffer( Command, initialLink, initialSize, gcvTRUE, gcvFALSE ); #endif /* Save initial buffer to flush. */ flushPointer = initialLink; flushSize = initialSize; /* Save pointer to next link. */ gcmkONERROR( _AddMap(Command->os, context->link, 8, &link, &stack)); /* Start parsing CommandBuffer. */ buffer = commandBuffer; /* Mark context buffer as used. */ if (context->inUse != gcvNULL) { gctBOOL_PTR inUse; gcmkONERROR( _AddMap(Command->os, (gctPOINTER) context->inUse, gcmSIZEOF(gctBOOL), (gctPOINTER *) &inUse, &stack)); *inUse = gcvTRUE; } } else { /* Test if this is a new context. */ if (context->id == 0) { /* Generate unique ID for the context buffer. */ context->id = ++ Command->contextCounter; if (context->id == 0) { /* Context counter overflow (wow!) */ gcmkONERROR(gcvSTATUS_TOO_COMPLEX); } } /* Map the command buffer. */ gcmkONERROR( _AddMap(Command->os, commandBuffer->logical, commandBuffer->offset, (gctPOINTER *) &logical, &stack)); #if gcdSECURE_USER /* Map the hint table. */ gcmkONERROR( _AddMap(Command->os, commandBuffer->hintCommit, commandBuffer->offset - commandBuffer->startOffset, (gctPOINTER *) &hint, &stack)); /* Walk while we have valid hints. */ while (*hint != 0) { /* Map the handle to a physical address. */ gcmkONERROR( gckKERNEL_MapLogicalToPhysical( Command->kernel, Process, (gctPOINTER *) (logical + *hint))); /* Next hint. */ ++hint; } #endif if (context->entryPipe == Command->pipeSelect) { gctUINT32 reserved = Command->reservedHead; gctUINT8_PTR nop = logical + commandBuffer->startOffset; /* Already in the correct pipe, fill context buffer with NOP. */ while (reserved > 0) { bytes = reserved; gcmkONERROR( gckHARDWARE_Nop(hardware, nop, &bytes)); gcmkASSERT(reserved >= bytes); reserved -= bytes; nop += bytes; } } else { /* Switch to the correct pipe. */ gcmkONERROR( gckHARDWARE_PipeSelect(hardware, logical + commandBuffer->startOffset, context->entryPipe, &bytes)); } /* Save initial link pointer. */ initialLink = logical + commandBuffer->startOffset; initialSize = commandBuffer->offset - commandBuffer->startOffset + Command->reservedTail; #if MRVL_PRINT_CMD_BUFFER _AddCmdBuffer( Command, initialLink, initialSize, gcvFALSE, gcvFALSE ); #endif /* Save initial buffer to flush. */ flushPointer = initialLink; flushSize = initialSize; /* Save pointer to next link. */ link = logical + commandBuffer->offset; /* No more data. */ buffer = gcvNULL; } #if MRVL_PRINT_CMD_BUFFER _AddLink(Command, Command->wait, initialLink); #endif #if gcdDUMP_COMMAND dataPointer = initialLink; dataBytes = initialSize; #endif /* Loop through all remaining command buffers. */ if (buffer != gcvNULL) { /* Map the command buffer. */ gcmkONERROR( _AddMap(Command->os, buffer->logical, buffer->offset + Command->reservedTail, (gctPOINTER *) &logical, &stack)); #if MRVL_PRINT_CMD_BUFFER _AddCmdBuffer( Command, (gctUINT32_PTR)logical, buffer->offset + Command->reservedTail, gcvFALSE, gcvFALSE ); #endif #if gcdSECURE_USER /* Map the hint table. */ gcmkONERROR( _AddMap(Command->os, buffer->hintCommit, buffer->offset - buffer->startOffset, (gctPOINTER *) &hint, &stack)); /* Walk while we have valid hints. */ while (*hint != 0) { /* Map the handle to a physical address. */ gcmkONERROR( gckKERNEL_MapLogicalToPhysical( Command->kernel, Process, (gctPOINTER *) (logical + *hint))); /* Next hint. */ ++hint; } #endif /* First slot becomes a NOP. */ { gctUINT32 reserved = Command->reservedHead; gctUINT8_PTR nop = logical + buffer->startOffset; /* Already in the correct pipe, fill context buffer with NOP. */ while (reserved > 0) { bytes = reserved; gcmkONERROR( gckHARDWARE_Nop(hardware, nop, &bytes)); gcmkASSERT(reserved >= bytes); reserved -= bytes; nop += bytes; } } /* Generate the LINK to this command buffer. */ gcmkONERROR( gckHARDWARE_Link(hardware, link, logical + buffer->startOffset, buffer->offset - buffer->startOffset + Command->reservedTail, &bytes)); #if MRVL_PRINT_CMD_BUFFER _AddLink(Command, link, (gctUINT32_PTR)logical); #endif /* Flush the initial buffer. */ gcmkONERROR(gckOS_CacheFlush(Command->os, Process, flushPointer, flushSize)); /* Save new flush pointer. */ flushPointer = logical + buffer->startOffset; flushSize = buffer->offset - buffer->startOffset + Command->reservedTail; #if gcdDUMP_COMMAND _DumpCommand(Command, dataPointer, dataBytes); dataPointer = logical + buffer->startOffset; dataBytes = buffer->offset - buffer->startOffset + Command->reservedTail; #endif /* Save pointer to next link. */ link = logical + buffer->offset; } /* Compute number of bytes required for WAIT/LINK. */ gcmkONERROR( gckHARDWARE_WaitLink(hardware, gcvNULL, Command->offset, &bytes, gcvNULL, gcvNULL)); lastRun = bytes; /* Grab the command queue mutex. */ gcmkONERROR( gckOS_AcquireMutex(Command->os, Command->mutexQueue, gcvINFINITE)); ++acquired; if (Command->kernel->notifyIdle) { /* Increase the commit stamp */ Command->commitStamp++; /* Set busy if idle */ if (Command->idle) { Command->idle = gcvFALSE; gcmkVERIFY_OK(gckOS_NotifyIdle(Command->os, gcvFALSE)); } } /* Compute number of bytes left in current command queue. */ bytes = Command->pageSize - Command->offset; if (bytes < lastRun) { /* Create a new command queue. */ gcmkONERROR(_NewQueue(Command, gcvTRUE)); /* Adjust run size with any extra commands inserted. */ lastRun += Command->offset; } /* Get current offset. */ offset = Command->offset; /* Append WAIT/LINK in command queue. */ bytes = Command->pageSize - offset; gcmkONERROR( gckHARDWARE_WaitLink(hardware, (gctUINT8 *) Command->logical + offset, offset, &bytes, &wait, &waitSize)); /* Flush the cache for the wait/link. */ gcmkONERROR(gckOS_CacheFlush(Command->os, gcvNULL, (gctUINT8 *) Command->logical + offset, bytes)); #if gcdDUMP_COMMAND _DumpCommand(Command, (gctUINT8 *) Command->logical + offset, bytes); #endif /* Adjust offset. */ offset += bytes; if (Command->newQueue) { /* Compute fetch location and size for a new command queue. */ fetchAddress = Command->logical; fetchSize = offset; } else { /* Compute fetch location and size for an existing command queue. */ fetchAddress = (gctUINT8 *) Command->logical + Command->offset; fetchSize = offset - Command->offset; } bytes = 8; /* Link in WAIT/LINK. */ gcmkONERROR( gckHARDWARE_Link(hardware, link, fetchAddress, fetchSize, &bytes)); #if MRVL_PRINT_CMD_BUFFER _AddLink(Command, link, fetchAddress); #endif /* Flush the cache for the command buffer. */ gcmkONERROR(gckOS_CacheFlush(Command->os, Process, flushPointer, flushSize)); #if gcdDUMP_COMMAND _DumpCommand(Command, dataPointer, dataBytes); #endif /* Execute the entire sequence. */ gcmkONERROR( gckHARDWARE_Link(hardware, Command->wait, initialLink, initialSize, &Command->waitSize)); /* Flush the cache for the link. */ gcmkONERROR(gckOS_CacheFlush(Command->os, gcvNULL, Command->wait, Command->waitSize)); #if gcdDUMP_COMMAND _DumpCommand(Command, Command->wait, Command->waitSize); #endif /* Update command queue offset. */ Command->offset = offset; Command->newQueue = gcvFALSE; /* Update address of last WAIT. */ Command->wait = wait; Command->waitSize = waitSize; /* Update context and pipe select. */ Command->currentContext = context->id; Command->pipeSelect = context->currentPipe; /* Update queue tail pointer. */ gcmkONERROR( gckHARDWARE_UpdateQueueTail(hardware, Command->logical, Command->offset)); #if gcdDUMP_COMMAND gcmkPRINT("@[kernel.commit]"); #endif /* Release the command queue mutex. */ gcmkONERROR(gckOS_ReleaseMutex(Command->os, Command->mutexQueue)); --acquired; /* Release the context switching mutex. */ gcmkONERROR(gckOS_ReleaseMutex(Command->os, Command->mutexContext)); --acquired; /* Submit events if asked for. */ if (Command->submit) { /* Submit events. */ status = gckEVENT_Submit(Command->kernel->event, gcvFALSE, gcvFALSE); if (gcmIS_SUCCESS(status)) { /* Success. */ Command->submit = gcvFALSE; } else { gcmkTRACE_ZONE(gcvLEVEL_WARNING, gcvZONE_COMMAND, "gckEVENT_Submit returned %d", status); } } /* Success. */ status = gcvSTATUS_OK; OnError: if (acquired > 1) { /* Release the command queue mutex. */ gcmkVERIFY_OK( gckOS_ReleaseMutex(Command->os, Command->mutexQueue)); } if (acquired > 0) { /* Release the context switching mutex. */ gcmkVERIFY_OK( gckOS_ReleaseMutex(Command->os, Command->mutexContext)); } /* Unmap all mapped pointers. */ while (stack != gcvNULL) { gcsMAPPED_PTR map = stack; stack = map->next; gcmkVERIFY_OK( gckOS_UnmapUserPointer(Command->os, map->pointer, map->bytes, map->kernelPointer)); gcmkVERIFY_OK( gckOS_Free(Command->os, map)); } /* Return status. */ gcmkFOOTER(); return status; }
/******************************************************************************* ** ** gckKERNEL_Dispatch ** ** Dispatch a command received from the user HAL layer. ** ** INPUT: ** ** gckKERNEL Kernel ** Pointer to an gckKERNEL object. ** ** gctBOOL FromUser ** whether the call is from the user space. ** ** 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 gckKERNEL_Dispatch( IN gckKERNEL Kernel, IN gctBOOL FromUser, IN OUT gcsHAL_INTERFACE * Interface ) { gceSTATUS status; gctUINT32 bitsPerPixel; gctSIZE_T bytes; gcuVIDMEM_NODE_PTR node; gctBOOL locked = gcvFALSE; gctPHYS_ADDR physical; gctUINT32 address; gcmkHEADER_ARG("Kernel=0x%x FromUser=%d Interface=0x%x", Kernel, FromUser, Interface); /* Verify the arguments. */ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); gcmkVERIFY_ARGUMENT(Interface != gcvNULL); gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_KERNEL, "Dispatching command %d", Interface->command); /* Dispatch on command. */ switch (Interface->command) { case gcvHAL_GET_BASE_ADDRESS: /* Get base address. */ gcmkONERROR( gckOS_GetBaseAddress(Kernel->os, &Interface->u.GetBaseAddress.baseAddress)); break; case gcvHAL_QUERY_VIDEO_MEMORY: /* Query video memory size. */ gcmkONERROR(gckKERNEL_QueryVideoMemory(Kernel, Interface)); break; case gcvHAL_QUERY_CHIP_IDENTITY: /* Query chip identity. */ gcmkONERROR( gckHARDWARE_QueryChipIdentity( Kernel->hardware, &Interface->u.QueryChipIdentity.chipModel, &Interface->u.QueryChipIdentity.chipRevision, &Interface->u.QueryChipIdentity.chipFeatures, &Interface->u.QueryChipIdentity.chipMinorFeatures, &Interface->u.QueryChipIdentity.chipMinorFeatures1)); /* Query chip specifications. */ gcmkONERROR( gckHARDWARE_QueryChipSpecs( Kernel->hardware, &Interface->u.QueryChipIdentity.streamCount, &Interface->u.QueryChipIdentity.registerMax, &Interface->u.QueryChipIdentity.threadCount, &Interface->u.QueryChipIdentity.shaderCoreCount, &Interface->u.QueryChipIdentity.vertexCacheSize, &Interface->u.QueryChipIdentity.vertexOutputBufferSize)); break; case gcvHAL_MAP_MEMORY: physical = Interface->u.MapMemory.physical; /* Map memory. */ gcmkONERROR( gckKERNEL_MapMemory(Kernel, physical, Interface->u.MapMemory.bytes, &Interface->u.MapMemory.logical)); break; case gcvHAL_UNMAP_MEMORY: physical = Interface->u.UnmapMemory.physical; /* Unmap memory. */ gcmkONERROR( gckKERNEL_UnmapMemory(Kernel, physical, Interface->u.UnmapMemory.bytes, Interface->u.UnmapMemory.logical)); break; case gcvHAL_ALLOCATE_NON_PAGED_MEMORY: /* Allocate non-paged memory. */ #ifdef __QNXNTO__ if (FromUser) { gcmkONERROR( gckOS_AllocateNonPagedMemoryShmPool( Kernel->os, FromUser, Interface->pid, Interface->handle, &Interface->u.AllocateNonPagedMemory.bytes, &Interface->u.AllocateNonPagedMemory.physical, &Interface->u.AllocateNonPagedMemory.logical)); break; } #endif gcmkONERROR( gckOS_AllocateNonPagedMemory( Kernel->os, FromUser, &Interface->u.AllocateNonPagedMemory.bytes, &Interface->u.AllocateNonPagedMemory.physical, &Interface->u.AllocateNonPagedMemory.logical)); break; case gcvHAL_FREE_NON_PAGED_MEMORY: physical = Interface->u.FreeNonPagedMemory.physical; /* Free non-paged memory. */ gcmkONERROR( gckOS_FreeNonPagedMemory(Kernel->os, Interface->u.FreeNonPagedMemory.bytes, physical, Interface->u.FreeNonPagedMemory.logical)); break; case gcvHAL_ALLOCATE_CONTIGUOUS_MEMORY: /* Allocate contiguous memory. */ #ifdef __QNXNTO__ if (FromUser) { gcmkONERROR( gckOS_AllocateNonPagedMemoryShmPool( Kernel->os, FromUser, Interface->pid, Interface->handle, &Interface->u.AllocateNonPagedMemory.bytes, &Interface->u.AllocateNonPagedMemory.physical, &Interface->u.AllocateNonPagedMemory.logical)); break; } #endif gcmkONERROR( gckOS_AllocateContiguous( Kernel->os, FromUser, &Interface->u.AllocateContiguousMemory.bytes, &Interface->u.AllocateContiguousMemory.physical, &Interface->u.AllocateContiguousMemory.logical)); break; case gcvHAL_FREE_CONTIGUOUS_MEMORY: physical = Interface->u.FreeContiguousMemory.physical; /* Free contiguous memory. */ gcmkONERROR( gckOS_FreeContiguous(Kernel->os, physical, Interface->u.FreeContiguousMemory.logical, Interface->u.FreeContiguousMemory.bytes)); break; case gcvHAL_ALLOCATE_VIDEO_MEMORY: /* Align width and height to tiles. */ gcmkONERROR( gckHARDWARE_AlignToTile(Kernel->hardware, Interface->u.AllocateVideoMemory.type, &Interface->u.AllocateVideoMemory.width, &Interface->u.AllocateVideoMemory.height, gcvNULL)); /* Convert format into bytes per pixel and bytes per tile. */ gcmkONERROR( gckHARDWARE_ConvertFormat(Kernel->hardware, Interface->u.AllocateVideoMemory.format, &bitsPerPixel, gcvNULL)); /* Compute number of bytes for the allocation. */ bytes = Interface->u.AllocateVideoMemory.width * bitsPerPixel * Interface->u.AllocateVideoMemory.height * Interface->u.AllocateVideoMemory.depth / 8; /* Allocate memory. */ #ifdef __QNXNTO__ gcmkONERROR( _AllocateMemory(Kernel, &Interface->u.AllocateVideoMemory.pool, bytes, 64, Interface->u.AllocateVideoMemory.type, Interface->handle, &Interface->u.AllocateVideoMemory.node)); #else gcmkONERROR( _AllocateMemory(Kernel, &Interface->u.AllocateVideoMemory.pool, bytes, 64, Interface->u.AllocateVideoMemory.type, &Interface->u.AllocateVideoMemory.node)); #endif break; case gcvHAL_ALLOCATE_LINEAR_VIDEO_MEMORY: /* Allocate memory. */ #ifdef __QNXNTO__ gcmkONERROR( _AllocateMemory(Kernel, &Interface->u.AllocateLinearVideoMemory.pool, Interface->u.AllocateLinearVideoMemory.bytes, Interface->u.AllocateLinearVideoMemory.alignment, Interface->u.AllocateLinearVideoMemory.type, Interface->handle, &Interface->u.AllocateLinearVideoMemory.node)); /* Set the current user pid in the node, * which is used while locking memory. */ gcmkVERIFY_OK(gckVIDMEM_SetPID( Interface->u.AllocateLinearVideoMemory.node, Interface->pid)); #else gcmkONERROR( _AllocateMemory(Kernel, &Interface->u.AllocateLinearVideoMemory.pool, Interface->u.AllocateLinearVideoMemory.bytes, Interface->u.AllocateLinearVideoMemory.alignment, Interface->u.AllocateLinearVideoMemory.type, &Interface->u.AllocateLinearVideoMemory.node)); #endif break; case gcvHAL_FREE_VIDEO_MEMORY: #ifdef __QNXNTO__ node = Interface->u.FreeVideoMemory.node; if (node->VidMem.memory->object.type == gcvOBJ_VIDMEM && node->VidMem.logical != gcvNULL) { gcmkONERROR( gckKERNEL_UnmapVideoMemory(Kernel, node->VidMem.logical, Interface->pid, node->VidMem.bytes)); node->VidMem.logical = gcvNULL; } #endif /* Free video memory. */ gcmkONERROR( gckVIDMEM_Free(Interface->u.FreeVideoMemory.node)); break; case gcvHAL_LOCK_VIDEO_MEMORY: /* Lock video memory. */ gcmkONERROR( gckVIDMEM_Lock(Interface->u.LockVideoMemory.node, &Interface->u.LockVideoMemory.address)); locked = gcvTRUE; node = Interface->u.LockVideoMemory.node; 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, Interface->pid, node->VidMem.bytes, &node->VidMem.logical)); } Interface->u.LockVideoMemory.memory = node->VidMem.logical; #else gcmkONERROR( gckKERNEL_MapVideoMemory(Kernel, FromUser, Interface->u.LockVideoMemory.address, &Interface->u.LockVideoMemory.memory)); #endif #ifdef __QNXNTO__ /* Add more information to node, which is used while unmapping. */ gcmkVERIFY_OK(gckVIDMEM_SetPID( Interface->u.LockVideoMemory.node, Interface->pid)); #endif } else { /* Copy logical memory for virtual memory. */ Interface->u.LockVideoMemory.memory = node->Virtual.logical; /* Success. */ status = gcvSTATUS_OK; } #if gcdSECURE_USER /* Return logical address as physical address. */ Interface->u.LockVideoMemory.address = gcmPTR2INT(Interface->u.LockVideoMemory.memory); #endif break; case gcvHAL_UNLOCK_VIDEO_MEMORY: /* Unlock video memory. */ node = Interface->u.UnlockVideoMemory.node; /* Unlock video memory. */ gcmkONERROR( gckVIDMEM_Unlock(node, Interface->u.UnlockVideoMemory.type, &Interface->u.UnlockVideoMemory.asynchroneous)); break; case gcvHAL_EVENT_COMMIT: /* Commit an event queue. */ gcmkONERROR( gckEVENT_Commit(Kernel->event, Interface->u.Event.queue)); break; case gcvHAL_COMMIT: /* Commit a command and context buffer. */ gcmkONERROR( gckCOMMAND_Commit(Kernel->command, Interface->u.Commit.commandBuffer, Interface->u.Commit.contextBuffer, Interface->u.Commit.process)); break; case gcvHAL_STALL: /* Stall the command queue. */ gcmkONERROR(gckCOMMAND_Stall(Kernel->command)); break; case gcvHAL_MAP_USER_MEMORY: /* Map user memory to DMA. */ gcmkONERROR( gckOS_MapUserMemory(Kernel->os, Interface->u.MapUserMemory.memory, Interface->u.MapUserMemory.size, &Interface->u.MapUserMemory.info, &Interface->u.MapUserMemory.address)); break; case gcvHAL_UNMAP_USER_MEMORY: address = Interface->u.MapUserMemory.address; /* Unmap user memory. */ gcmkONERROR( gckOS_UnmapUserMemory(Kernel->os, Interface->u.UnmapUserMemory.memory, Interface->u.UnmapUserMemory.size, Interface->u.UnmapUserMemory.info, address)); break; #if !USE_NEW_LINUX_SIGNAL case gcvHAL_USER_SIGNAL: gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_KERNEL, "Dispatching gcvHAL_USER_SIGNAL %d", Interface->u.UserSignal.command); /* Dispatch depends on the user signal subcommands. */ switch(Interface->u.UserSignal.command) { case gcvUSER_SIGNAL_CREATE: /* Create a signal used in the user space. */ gcmkONERROR( gckOS_CreateUserSignal(Kernel->os, Interface->u.UserSignal.manualReset, Interface->u.UserSignal.signalType, &Interface->u.UserSignal.id)); break; case gcvUSER_SIGNAL_DESTROY: /* Destroy the signal. */ gcmkONERROR( gckOS_DestroyUserSignal(Kernel->os, Interface->u.UserSignal.id)); break; case gcvUSER_SIGNAL_SIGNAL: /* Signal the signal. */ gcmkONERROR( 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. */ gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT); } break; #endif case gcvHAL_SET_POWER_MANAGEMENT_STATE: /* Set the power management state. */ gcmkONERROR( gckHARDWARE_SetPowerManagementState( Kernel->hardware, Interface->u.SetPowerManagement.state)); break; case gcvHAL_QUERY_POWER_MANAGEMENT_STATE: /* Chip is not idle. */ Interface->u.QueryPowerManagement.isIdle = gcvFALSE; /* Query the power management state. */ gcmkONERROR(gckHARDWARE_QueryPowerManagementState( Kernel->hardware, &Interface->u.QueryPowerManagement.state)); /* Query the idle state. */ gcmkONERROR( gckHARDWARE_QueryIdle(Kernel->hardware, &Interface->u.QueryPowerManagement.isIdle)); break; case gcvHAL_READ_REGISTER: #if gcdREGISTER_ACCESS_FROM_USER /* Read a register. */ gcmkONERROR( gckOS_ReadRegister(Kernel->os, Interface->u.ReadRegisterData.address, &Interface->u.ReadRegisterData.data)); #else /* No access from user land to read registers. */ Interface->u.ReadRegisterData.data = 0; status = gcvSTATUS_NOT_SUPPORTED; #endif break; case gcvHAL_WRITE_REGISTER: #if gcdREGISTER_ACCESS_FROM_USER /* Write a register. */ gcmkONERROR( gckOS_WriteRegister(Kernel->os, Interface->u.WriteRegisterData.address, Interface->u.WriteRegisterData.data)); #else /* No access from user land to write registers. */ status = gcvSTATUS_NOT_SUPPORTED; #endif break; case gcvHAL_READ_ALL_PROFILE_REGISTERS: #if VIVANTE_PROFILER /* Read all 3D profile registers. */ gcmkONERROR( gckHARDWARE_QueryProfileRegisters( Kernel->hardware, &Interface->u.RegisterProfileData.counters)); #else status = gcvSTATUS_OK; #endif break; case gcvHAL_PROFILE_REGISTERS_2D: #if VIVANTE_PROFILER /* Read all 2D profile registers. */ gcmkONERROR( gckHARDWARE_ProfileEngine2D( Kernel->hardware, Interface->u.RegisterProfileData2D.hwProfile2D)); #else status = gcvSTATUS_OK; #endif break; case gcvHAL_GET_PROFILE_SETTING: #if VIVANTE_PROFILER /* Get profile setting */ Interface->u.GetProfileSetting.enable = Kernel->profileEnable; gcmkVERIFY_OK( gckOS_MemCopy(Interface->u.GetProfileSetting.fileName, Kernel->profileFileName, gcdMAX_PROFILE_FILE_NAME)); #endif status = gcvSTATUS_OK; break; case gcvHAL_SET_PROFILE_SETTING: #if VIVANTE_PROFILER /* Set profile setting */ Kernel->profileEnable = Interface->u.SetProfileSetting.enable; gcmkVERIFY_OK( gckOS_MemCopy(Kernel->profileFileName, Interface->u.SetProfileSetting.fileName, gcdMAX_PROFILE_FILE_NAME)); #endif status = gcvSTATUS_OK; break; case gcvHAL_QUERY_KERNEL_SETTINGS: /* Get kernel settings. */ gcmkONERROR( gckKERNEL_QuerySettings(Kernel, &Interface->u.QueryKernelSettings.settings)); break; case gcvHAL_RESET: /* Reset the hardware. */ gcmkONERROR( gckHARDWARE_Reset(Kernel->hardware)); break; case gcvHAL_DEBUG: /* Set debug level and zones. */ if (Interface->u.Debug.set) { gckOS_SetDebugLevel(Interface->u.Debug.level); gckOS_SetDebugZones(Interface->u.Debug.zones, Interface->u.Debug.enable); } if (Interface->u.Debug.message[0] != '\0') { /* Print a message to the debugger. */ gcmkPRINT(Interface->u.Debug.message); } status = gcvSTATUS_OK; break; case gcvHAL_CACHE: if (Interface->u.Cache.invalidate) { /* Flush and invalidate the cache. */ status = gckOS_CacheInvalidate(Kernel->os, Interface->u.Cache.process, Interface->u.Cache.logical, Interface->u.Cache.bytes); } else { /* Flush the cache. */ status = gckOS_CacheFlush(Kernel->os, Interface->u.Cache.process, Interface->u.Cache.logical, Interface->u.Cache.bytes); } break; default: /* Invalid command. */ gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT); } OnError: /* Save status. */ Interface->status = status; if (gcmIS_ERROR(status)) { if (locked) { /* Roll back the lock. */ gcmkVERIFY_OK( gckVIDMEM_Unlock(Interface->u.LockVideoMemory.node, gcvSURF_TYPE_UNKNOWN, gcvNULL)); } } /* Return the status. */ gcmkFOOTER(); return status; }
/******************************************************************************* ** ** gckCOMMAND_Execute ** ** Execute a previously reserved command queue by appending a WAIT/LINK command ** sequence after it and modifying the last WAIT into a LINK command. The ** command FIFO mutex will be released whether this function succeeds or not. ** ** INPUT: ** ** gckCOMMAND Command ** Pointer to an gckCOMMAND object. ** ** gctSIZE_T RequestedBytes ** Number of bytes previously reserved. ** ** OUTPUT: ** ** Nothing. */ gceSTATUS gckCOMMAND_Execute( IN gckCOMMAND Command, IN gctSIZE_T RequestedBytes, IN gctBOOL Locking ) { gctUINT32 offset; gctPOINTER address; gctSIZE_T bytes; gceSTATUS status; gctPOINTER wait; gctSIZE_T waitBytes; gcmkHEADER_ARG("Command=0x%x RequestedBytes=%lu Locking=%d", Command, RequestedBytes, Locking); /* Verify the arguments. */ gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND); if (Command->kernel->notifyIdle) { /* Increase the commit stamp */ Command->commitStamp++; /* Set busy if idle */ if (Command->idle) { Command->idle = gcvFALSE; gcmkVERIFY_OK(gckOS_NotifyIdle(Command->os, gcvFALSE)); } } /* Compute offset for WAIT/LINK. */ offset = Command->offset + RequestedBytes; /* Compute number of byts left in command queue. */ bytes = Command->pageSize - offset; /* Append WAIT/LINK in command queue. */ gcmkONERROR( gckHARDWARE_WaitLink(Command->kernel->hardware, (gctUINT8 *) Command->logical + offset, offset, &bytes, &wait, &waitBytes)); if (Command->newQueue) { /* For a new command queue, point to the start of the command ** queue and include both the commands inserted at the head of it ** and the WAIT/LINK. */ address = Command->logical; bytes += offset; } else { /* For an existing command queue, point to the current offset and ** include the WAIT/LINK. */ address = (gctUINT8 *) Command->logical + Command->offset; bytes += RequestedBytes; } /* Flush the cache. */ gcmkONERROR(gckOS_CacheFlush(Command->os, gcvNULL, address, bytes)); #if gcdDUMP_COMMAND _DumpCommand(Command, address, bytes); #endif /* Convert the last WAIT into a LINK. */ gcmkONERROR(gckHARDWARE_Link(Command->kernel->hardware, Command->wait, address, bytes, &Command->waitSize)); #if MRVL_PRINT_CMD_BUFFER _AddLink(Command, Command->wait, address); #endif /* Flush the cache. */ gcmkONERROR(gckOS_CacheFlush(Command->os, gcvNULL, Command->wait, Command->waitSize)); #if gcdDUMP_COMMAND _DumpCommand(Command, Command->wait, 8); #endif /* Update the pointer to the last WAIT. */ Command->wait = wait; Command->waitSize = waitBytes; /* Update the command queue. */ Command->offset += bytes; Command->newQueue = gcvFALSE; /* Update queue tail pointer. */ gcmkONERROR( gckHARDWARE_UpdateQueueTail(Command->kernel->hardware, Command->logical, Command->offset)); #if gcdDUMP_COMMAND gcmkPRINT("@[kernel.execute]"); #endif if (!Locking) { /* Release the command queue mutex. */ gcmkONERROR( gckOS_ReleaseMutex(Command->os, Command->mutexQueue)); } /* Submit events if asked for. */ if (Command->submit) { /* Submit events. */ status = gckEVENT_Submit(Command->kernel->event, gcvFALSE, gcvFALSE); if (gcmIS_SUCCESS(status)) { /* Success. */ Command->submit = gcvFALSE; } else { gcmkTRACE_ZONE(gcvLEVEL_WARNING, gcvZONE_COMMAND, "gckEVENT_Submit returned %d", status); } } /* Success. */ gcmkFOOTER_NO(); return gcvSTATUS_OK; OnError: /* Release the command queue mutex. */ gcmkVERIFY_OK( gckOS_ReleaseMutex(Command->os, Command->mutexQueue)); /* Return the status. */ gcmkFOOTER(); return status; }