long drv_ioctl( struct file* filp, unsigned int ioctlCode, unsigned long arg ) { gceSTATUS status; gcsHAL_INTERFACE iface; gctUINT32 copyLen; DRIVER_ARGS drvArgs; gckGALDEVICE device; gcsHAL_PRIVATE_DATA_PTR data; gctINT32 i, count; gckVIDMEM_NODE nodeObject; gcmkHEADER_ARG( "filp=0x%08X ioctlCode=0x%08X arg=0x%08X", filp, ioctlCode, arg ); if (filp == gcvNULL) { gcmkTRACE_ZONE( gcvLEVEL_ERROR, gcvZONE_DRIVER, "%s(%d): filp is NULL\n", __FUNCTION__, __LINE__ ); gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT); } data = filp->private_data; if (data == gcvNULL) { gcmkTRACE_ZONE( gcvLEVEL_ERROR, gcvZONE_DRIVER, "%s(%d): private_data is NULL\n", __FUNCTION__, __LINE__ ); gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT); } device = data->device; if (device == gcvNULL) { gcmkTRACE_ZONE( gcvLEVEL_ERROR, gcvZONE_DRIVER, "%s(%d): device is NULL\n", __FUNCTION__, __LINE__ ); gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT); } if ((ioctlCode != IOCTL_GCHAL_INTERFACE) && (ioctlCode != IOCTL_GCHAL_KERNEL_INTERFACE) ) { gcmkTRACE_ZONE( gcvLEVEL_ERROR, gcvZONE_DRIVER, "%s(%d): unknown command %d\n", __FUNCTION__, __LINE__, ioctlCode ); gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT); } /* Get the drvArgs. */ copyLen = copy_from_user( &drvArgs, (void *) arg, sizeof(DRIVER_ARGS) ); if (copyLen != 0) { gcmkTRACE_ZONE( gcvLEVEL_ERROR, gcvZONE_DRIVER, "%s(%d): error copying of the input arguments.\n", __FUNCTION__, __LINE__ ); gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT); } /* Now bring in the gcsHAL_INTERFACE structure. */ if ((drvArgs.InputBufferSize != sizeof(gcsHAL_INTERFACE)) || (drvArgs.OutputBufferSize != sizeof(gcsHAL_INTERFACE)) ) { gcmkTRACE_ZONE( gcvLEVEL_ERROR, gcvZONE_DRIVER, "%s(%d): input or/and output structures are invalid.\n", __FUNCTION__, __LINE__ ); gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT); } copyLen = copy_from_user( &iface, gcmUINT64_TO_PTR(drvArgs.InputBuffer), sizeof(gcsHAL_INTERFACE) ); if (copyLen != 0) { gcmkTRACE_ZONE( gcvLEVEL_ERROR, gcvZONE_DRIVER, "%s(%d): error copying of input HAL interface.\n", __FUNCTION__, __LINE__ ); gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT); } if (iface.command == gcvHAL_CHIP_INFO) { count = 0; for (i = 0; i < gcdMAX_GPU_COUNT; i++) { if (device->kernels[i] != gcvNULL) { #if gcdENABLE_VG if (i == gcvCORE_VG) { iface.u.ChipInfo.types[count] = gcvHARDWARE_VG; } else #endif { gcmkVERIFY_OK(gckHARDWARE_GetType(device->kernels[i]->hardware, &iface.u.ChipInfo.types[count])); } count++; } } iface.u.ChipInfo.count = count; iface.status = status = gcvSTATUS_OK; } else { if (iface.hardwareType > 7) { gcmkTRACE_ZONE( gcvLEVEL_ERROR, gcvZONE_DRIVER, "%s(%d): unknown hardwareType %d\n", __FUNCTION__, __LINE__, iface.hardwareType ); gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT); } #if gcdENABLE_VG if (device->coreMapping[iface.hardwareType] == gcvCORE_VG) { status = gckVGKERNEL_Dispatch(device->kernels[gcvCORE_VG], (ioctlCode == IOCTL_GCHAL_INTERFACE), &iface); } else #endif { status = gckKERNEL_Dispatch(device->kernels[device->coreMapping[iface.hardwareType]], (ioctlCode == IOCTL_GCHAL_INTERFACE), &iface); } } /* Redo system call after pending signal is handled. */ if (status == gcvSTATUS_INTERRUPTED) { gcmkFOOTER(); return -ERESTARTSYS; } if (gcmIS_SUCCESS(status) && (iface.command == gcvHAL_LOCK_VIDEO_MEMORY)) { gcuVIDMEM_NODE_PTR node; gctUINT32 processID; gckOS_GetProcessID(&processID); gcmkONERROR(gckVIDMEM_HANDLE_Lookup(device->kernels[device->coreMapping[iface.hardwareType]], processID, (gctUINT32)iface.u.LockVideoMemory.node, &nodeObject)); node = nodeObject->node; /* Special case for mapped memory. */ if ((data->mappedMemory != gcvNULL) && (node->VidMem.memory->object.type == gcvOBJ_VIDMEM) ) { /* Compute offset into mapped memory. */ gctUINT32 offset = (gctUINT8 *) gcmUINT64_TO_PTR(iface.u.LockVideoMemory.memory) - (gctUINT8 *) device->contiguousBase; /* Compute offset into user-mapped region. */ iface.u.LockVideoMemory.memory = gcmPTR_TO_UINT64((gctUINT8 *) data->mappedMemory + offset); } } /* Copy data back to the user. */ copyLen = copy_to_user( gcmUINT64_TO_PTR(drvArgs.OutputBuffer), &iface, sizeof(gcsHAL_INTERFACE) ); if (copyLen != 0) { gcmkTRACE_ZONE( gcvLEVEL_ERROR, gcvZONE_DRIVER, "%s(%d): error copying of output HAL interface.\n", __FUNCTION__, __LINE__ ); gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT); } /* Success. */ gcmkFOOTER_NO(); return 0; OnError: gcmkFOOTER(); return -ENOTTY; }
/******************************************************************************* ** ** 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 )); 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; }