static ssize_t store_register_stats (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { gctCHAR type[10]; gctUINT32 offset, clkState = 0; gctINT t = ~0; SYSFS_VERIFY_INPUT(sscanf(buf, "%s 0x%x", type, &offset), 2); SYSFS_VERIFY_INPUT_RANGE(offset, 0, 0x30001); if(strstr(type, "default")) { t = 0; } else if(strstr(type, "offset")) { t = 1; } else { gcmkPRINT("Invalid Command~"); return count; } gcmkVERIFY_OK(gckOS_QueryRegisterStats( galDevice->os, t, offset, &clkState)); if(t && clkState) { gcmkPRINT("Some Registers can't be read because of %s disabled", (clkState&0x11)?("External/Internal clk"):((clkState&0x01)?"External":"Internal")); } return count; }
gceSTATUS _ShrinkMemory( IN gckPLATFORM Platform ) { struct platform_device *pdev; gckGALDEVICE galDevice; gckKERNEL kernel; pdev = Platform->device; galDevice = platform_get_drvdata(pdev); kernel = _GetValidKernel(galDevice); if (kernel != gcvNULL) { force_contiguous_lowmem_shrink(kernel); } else { gcmkPRINT("%s(%d) can't find kernel! ", __FUNCTION__, __LINE__); } return gcvSTATUS_OK; }
static void create_gc_proc_file(void) { gc_proc_file = create_proc_entry(GC_PROC_FILE, 0644, gcvNULL); if (gc_proc_file) { gc_proc_file->proc_fops = &gc_proc_ops; } else gcmkPRINT("[galcore] proc file create failed!\n"); }
/******************************************************************************* ** ** _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; }
gceSTATUS gckKERNEL_DumpProcessDB( IN gckKERNEL Kernel ) { gcsDATABASE_PTR database; gctINT i, pid; gctUINT8 name[24]; gcmkHEADER_ARG("Kernel=0x%x", Kernel); /* Acquire the database mutex. */ gcmkVERIFY_OK( gckOS_AcquireMutex(Kernel->os, Kernel->db->dbMutex, gcvINFINITE)); gcmkPRINT("**************************\n"); gcmkPRINT("*** PROCESS DB DUMP ***\n"); gcmkPRINT("**************************\n"); gcmkPRINT_N(8, "%-8s%s\n", "PID", "NAME"); /* Walk the databases. */ for (i = 0; i < gcmCOUNTOF(Kernel->db->db); ++i) { for (database = Kernel->db->db[i]; database != gcvNULL; database = database->next) { pid = database->processID; gcmkVERIFY_OK(gckOS_ZeroMemory(name, gcmSIZEOF(name))); gcmkVERIFY_OK(gckOS_GetProcessNameByPid(pid, gcmSIZEOF(name), name)); gcmkPRINT_N(8, "%-8d%s\n", pid, name); } } /* Release the database mutex. */ gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex)); /* Success. */ gcmkFOOTER_NO(); return gcvSTATUS_OK; }
gceSTATUS gckKERNEL_AttachProcess( IN gckKERNEL Kernel, IN gctBOOL Attach ) { gceSTATUS status; gctINT32 old; gcmkHEADER_ARG("Kernel=0x%x Attach=%d", Kernel, Attach); /* Verify the arguments. */ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); if (Attach) { /* Increment the number of clients attached. */ gcmkONERROR( gckOS_AtomIncrement(Kernel->os, Kernel->atomClients, &old)); if (old == 0) { /* gcmkONERROR(gckHARDWARE_SetPowerManagementState(Kernel->hardware, gcvPOWER_ON)); */ } } else { /* Decrement the number of clients attached. */ gcmkONERROR( gckOS_AtomDecrement(Kernel->os, Kernel->atomClients, &old)); if (old == 1) { gcmkONERROR(gckHARDWARE_SetPowerManagementState(Kernel->hardware, gcvPOWER_OFF)); /* Flush the debug cache. */ gcmkPRINT("$$FLUSH$$"); } } /* Success. */ gcmkFOOTER_NO(); return gcvSTATUS_OK; OnError: /* Return the status. */ gcmkFOOTER(); return status; }
static ssize_t store_register_stats (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { gctUINT32 core, offset, value; SYSFS_VERIFY_INPUT(sscanf(buf, "%d 0x%x", &core, &offset), 2); SYSFS_VERIFY_INPUT_RANGE(core, 0, gcdMAX_GPU_COUNT - 1); SYSFS_VERIFY_INPUT_RANGE(offset, 0, 0x30001); gcmkVERIFY_OK(gckOS_ReadRegisterEx(galDevice->os, core, offset, &value)); gcmkPRINT("Core(%d) Register[0x%x] value is 0x%08x\n", core, offset, value); return count; }
static void _Policy( IN gckDVFS Dvfs, IN gctUINT32 Load, OUT gctUINT8 *Scale ) { gctUINT8 load[4], nextLoad; gctUINT8 scale; /* Last 4 history. */ load[0] = (Load & 0xFF); load[1] = (Load & 0xFF00) >> 8; load[2] = (Load & 0xFF0000) >> 16; load[3] = (Load & 0xFF000000) >> 24; /* Determine target scale. */ if (load[0] > 54) { _IncreaseScale(Dvfs, Load, &scale); } else { nextLoad = (load[0] + load[1] + load[2] + load[3])/4; scale = Dvfs->currentScale * (nextLoad) / 54; scale = gcmMAX(1, scale); scale = gcmMIN(64, scale); } Dvfs->totalConfig++; Dvfs->loads[(load[0]-1)/8]++; *Scale = scale; if (Dvfs->totalConfig % 100 == 0) { gcmkPRINT("======================================================="); gcmkPRINT("GPU Load: %-8d %-8d %-8d %-8d %-8d %-8d %-8d %-8d", 8, 16, 24, 32, 40, 48, 56, 64); gcmkPRINT(" %-8d %-8d %-8d %-8d %-8d %-8d %-8d %-8d", _GetLoadHistory(Dvfs,2, 0), _GetLoadHistory(Dvfs,2, 1), _GetLoadHistory(Dvfs,2, 2), _GetLoadHistory(Dvfs,2, 3), _GetLoadHistory(Dvfs,2, 4), _GetLoadHistory(Dvfs,2, 5), _GetLoadHistory(Dvfs,2, 6), _GetLoadHistory(Dvfs,2, 7) ); gcmkPRINT("Frequency(MHz) %-8d %-8d %-8d %-8d %-8d", 58, 120, 240, 360, 480); gcmkPRINT(" %-8d %-8d %-8d %-8d %-8d", _GetFrequencyHistory(Dvfs, 58), _GetFrequencyHistory(Dvfs,120), _GetFrequencyHistory(Dvfs,240), _GetFrequencyHistory(Dvfs,360), _GetFrequencyHistory(Dvfs,480) ); } }
long drv_ioctl( struct file* filp, unsigned int ioctlCode, unsigned long arg ) { gceSTATUS status = gcvSTATUS_OK; gcsHAL_INTERFACE iface; gctUINT32 copyLen; DRIVER_ARGS drvArgs; gckGALDEVICE device; gcsHAL_PRIVATE_DATA_PTR data = gcvNULL; gctINT32 i, count; 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, 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 < 0 || iface.hardwareType > 7) { gcmkTRACE_ZONE( gcvLEVEL_ERROR, gcvZONE_DRIVER, "%s(%d): unknown hardwareType %d\n", __FUNCTION__, __LINE__, iface.hardwareType ); gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT); } /* print commands for debugging. */ if( galDevice->printPID && iface.hardwareType && ((galDevice->printPID & iface.hardwareType)!= 0) ) { gctUINT32 procID; char procName[gcdPROC_NAME_LEN]; gcmkVERIFY_OK(gckOS_GetProcessID(&procID)); gcmkVERIFY_OK(gckOS_GetProcessName(&procName[0])); gcmkPRINT("[%4s] PROC[%5d](%16s) CMD[%d]\n", (iface.hardwareType == gcvHARDWARE_3D) ? "3D" : ((iface.hardwareType == gcvHARDWARE_2D) ? "2D " : ((iface.hardwareType == gcvHARDWARE_VG) ? "VG" : "2D3D")), procID, procName, iface.command); } #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)) { /* Special case for mapped memory. */ if ((data->mappedMemory != gcvNULL) && (iface.u.LockVideoMemory.node->VidMem.memory->object.type == gcvOBJ_VIDMEM) ) { /* Compute offset into mapped memory. */ gctUINT32 offset = (gctUINT8 *) iface.u.LockVideoMemory.memory - (gctUINT8 *) device->contiguousBase; /* Compute offset into user-mapped region. */ iface.u.LockVideoMemory.memory = (gctUINT8 *) data->mappedMemory + offset; } } /* Copy data back to the user. */ copyLen = copy_to_user( 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: if(data != gcvNULL) { kfree(data); filp->private_data = gcvNULL; } gcmkFOOTER(); return -ENOTTY; }
int drv_release( struct inode* inode, struct file* filp ) { gceSTATUS status = gcvSTATUS_OK; gcsHAL_PRIVATE_DATA_PTR data = gcvNULL; gckGALDEVICE device; gctINT i; gcmkHEADER_ARG("inode=0x%08X filp=0x%08X", inode, filp); 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 (!device->contiguousMapped) { if (data->contiguousLogical != gcvNULL) { gcmkONERROR(gckOS_UnmapMemoryEx( galDevice->os, galDevice->contiguousPhysical, galDevice->contiguousSize, data->contiguousLogical, data->pidOpen )); for (i = 0; i < gcdMAX_GPU_COUNT; i++) { if (galDevice->kernels[i] != gcvNULL) { gcmkVERIFY_OK( gckKERNEL_RemoveProcessDB(galDevice->kernels[i], data->pidOpen, gcvDB_MAP_MEMORY, data->contiguousLogical)); } } data->contiguousLogical = gcvNULL; } } /* A process gets detached. */ gcmkPRINT("Process %d released (%s)\n", data->pidOpen, _GC_VERSION_STRING_); for (i = 0; i < gcdMAX_GPU_COUNT; i++) { if (galDevice->kernels[i] != gcvNULL) { /*gcmkONERROR(gckKERNEL_ShowProcessMemUsage(galDevice->kernels[i], data->pidOpen));*/ gcmkONERROR(gckKERNEL_AttachProcessEx(galDevice->kernels[i], gcvFALSE, data->pidOpen)); } } kfree(data); filp->private_data = gcvNULL; /* Print memory information _gc_gather_infomation(buf, &len); printk("%s", buf);*/ /* Success. */ gcmkFOOTER_NO(); return 0; OnError: if(data!=gcvNULL) { kfree(data); filp->private_data = gcvNULL; } gcmkFOOTER(); return -ENOTTY; }
/******************************************************************************* ** ** gckCOMMAND_Stall ** ** The calling thread will be suspended until the command queue has been ** completed. ** ** INPUT: ** ** gckCOMMAND Command ** Pointer to an gckCOMMAND object. ** ** OUTPUT: ** ** Nothing. */ gceSTATUS gckCOMMAND_Stall( IN gckCOMMAND Command ) { gckOS os; gckHARDWARE hardware; gckEVENT event; gceSTATUS status; gctSIGNAL signal = gcvNULL; gcmkHEADER_ARG("Command=0x%x", Command); /* Verify the arguments. */ gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND); #if gcdNULL_DRIVER == 2 /* Do nothing with infinite hardware. */ gcmkFOOTER_NO(); return gcvSTATUS_OK; #endif /* Extract the gckOS object pointer. */ os = Command->os; gcmkVERIFY_OBJECT(os, gcvOBJ_OS); /* Extract the gckHARDWARE object pointer. */ hardware = Command->kernel->hardware; gcmkVERIFY_OBJECT(hardware, gcvOBJ_HARDWARE); /* Extract the gckEVENT object pointer. */ event = Command->kernel->event; gcmkVERIFY_OBJECT(event, gcvOBJ_EVENT); /* Allocate the signal. */ gcmkONERROR( gckOS_CreateSignal(os, gcvTRUE, &signal)); /* Append the EVENT command to trigger the signal. */ gcmkONERROR(gckEVENT_Signal(event, signal, gcvKERNEL_PIXEL, gcvFALSE)); /* Submit the event queue. */ gcmkONERROR(gckEVENT_Submit(event, gcvTRUE, gcvFALSE)); #if gcdDUMP_COMMAND gcmkPRINT("@[kernel.stall]"); #endif if (status == gcvSTATUS_CHIP_NOT_READY) { /* Error. */ goto OnError; } do { /* Wait for the signal. */ status = gckOS_WaitSignal(os, signal, gcvINFINITE); if (status == gcvSTATUS_TIMEOUT) { #if gcdDEBUG gctUINT32 idle; /* IDLE */ gckOS_ReadRegister(Command->os, 0x0004, &idle); gcmkTRACE(gcvLEVEL_ERROR, "%s(%d): idle=%08x", __FUNCTION__, __LINE__, idle); gckOS_Log(_GFX_LOG_WARNING_, "%s : %d : idle register = 0x%08x \n", __FUNCTION__, __LINE__, idle); #endif #if MRVL_PRINT_CMD_BUFFER { gctUINT i; gctUINT32 idle; gctUINT32 intAck; gctUINT32 prevAddr = 0; gctUINT32 currAddr; gctBOOL changeDetected; changeDetected = gcvFALSE; /* IDLE */ gckOS_ReadRegister(Command->os, 0x0004, &idle); /* INT ACK */ gckOS_ReadRegister(Command->os, 0x0010, &intAck); /* DMA POS */ for (i = 0; i < 300; i += 1) { gckOS_ReadRegister(Command->os, 0x0664, &currAddr); if ((i > 0) && (prevAddr != currAddr)) { changeDetected = gcvTRUE; } prevAddr = currAddr; } gcmTRACE(0, "\n%s(%d):\n" " idle = 0x%08X\n" " int = 0x%08X\n" " dma = 0x%08X (change=%d)\n", __FUNCTION__, __LINE__, idle, intAck, currAddr, changeDetected ); _PrintCmdBuffer(Command, currAddr); _PrintLinkChain(); } #endif #if MRVL_LOW_POWER_MODE_DEBUG { int i = 0; printk(">>>>>>>>>>>>galDevice->kernel->kernelMSG\n"); printk("galDevice->kernel->msgLen=%d\n",Command->kernel->msgLen); for(i=0;i<Command->kernel->msgLen;i+=1024) { Command->kernel->kernelMSG[i+1023] = '\0'; printk("%s\n",(char*)Command->kernel->kernelMSG + i); } } #endif #ifdef __QNXNTO__ gctUINT32 reg_cmdbuf_fetch; gctUINT32 reg_intr; gcmkVERIFY_OK( gckOS_ReadRegister(Command->kernel->hardware->os, 0x0664, ®_cmdbuf_fetch)); if (idle == 0x7FFFFFFE) { /* * GPU is idle so there should not be pending interrupts. * Just double check. * * Note that reading interrupt register clears it. * That's why we don't read it in all cases. */ gcmkVERIFY_OK( gckOS_ReadRegister(Command->kernel->hardware->os, 0x10, ®_intr)); slogf( _SLOG_SETCODE(1, 0), _SLOG_CRITICAL, "GALcore: Stall timeout (idle = 0x%X, command buffer fetch = 0x%X, interrupt = 0x%X)", idle, reg_cmdbuf_fetch, reg_intr); } else { slogf( _SLOG_SETCODE(1, 0), _SLOG_CRITICAL, "GALcore: Stall timeout (idle = 0x%X, command buffer fetch = 0x%X)", idle, reg_cmdbuf_fetch); } #endif gcmkVERIFY_OK( gckOS_MemoryBarrier(os, gcvNULL)); } } while (gcmIS_ERROR(status)); /* Delete the signal. */ gcmkVERIFY_OK(gckOS_DestroySignal(os, signal)); /* Success. */ gcmkFOOTER_NO(); return gcvSTATUS_OK; OnError: /* Free the signal. */ if (signal != gcvNULL) { gcmkVERIFY_OK(gckOS_DestroySignal(os, signal)); } /* 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; }
static ssize_t store_freq (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { int core, scale, gpu_count, i; gceSTATUS status = gcvSTATUS_OK; gckHARDWARE hardware; /* count core numbers */ for (i = 0, gpu_count = 0; i < gcdMAX_GPU_COUNT; i++) if (galDevice->kernels[i] != gcvNULL) gpu_count++; /* scan input value and verify */ SYSFS_VERIFY_INPUT(sscanf(buf, "%d,%d", &core, &scale), 2); SYSFS_VERIFY_INPUT_RANGE(core, 0, (gpu_count-1)); SYSFS_VERIFY_INPUT_RANGE(scale, 1, 64); /* internal frequency scaling */ printk("[pm_test] freq %s core 1/%d\n", (core == gcvCORE_MAJOR)?"3D":"2D", scale); hardware = galDevice->kernels[core]->hardware; switch (scale) { case 1: /* frequency change to full speed */ gcmkONERROR(gckOS_WriteRegisterEx(hardware->os, hardware->core, 0x00000, 0x300)); /* Loading the frequency scaler. */ gcmkONERROR(gckOS_WriteRegisterEx(hardware->os, hardware->core, 0x00000, 0x100)); break; case 2: /* frequency change to 1/2 speed */ gcmkONERROR(gckOS_WriteRegisterEx(hardware->os, hardware->core, 0x00000, 0x280)); /* Loading the frequency scaler. */ gcmkONERROR(gckOS_WriteRegisterEx(hardware->os, hardware->core, 0x00000, 0x080)); break; case 4: /* frequency change to 1/4 speed */ gcmkONERROR(gckOS_WriteRegisterEx(hardware->os, hardware->core, 0x00000, 0x240)); /* Loading the frequency scaler. */ gcmkONERROR(gckOS_WriteRegisterEx(hardware->os, hardware->core, 0x00000, 0x040)); break; case 8: /* frequency change to 1/8 speed */ gcmkONERROR(gckOS_WriteRegisterEx(hardware->os, hardware->core, 0x00000, 0x220)); /* Loading the frequency scaler. */ gcmkONERROR(gckOS_WriteRegisterEx(hardware->os, hardware->core, 0x00000, 0x020)); break; case 16: /* frequency change to 1/16 speed */ gcmkONERROR(gckOS_WriteRegisterEx(hardware->os, hardware->core, 0x00000, 0x210)); /* Loading the frequency scaler. */ gcmkONERROR(gckOS_WriteRegisterEx(hardware->os, hardware->core, 0x00000, 0x010)); break; case 32: /* frequency change to 1/32 speed */ gcmkONERROR(gckOS_WriteRegisterEx(hardware->os, hardware->core, 0x00000, 0x208)); /* Loading the frequency scaler. */ gcmkONERROR(gckOS_WriteRegisterEx(hardware->os, hardware->core, 0x00000, 0x008)); break; case 64: /* frequency change to 1/64 speed */ gcmkONERROR(gckOS_WriteRegisterEx(hardware->os, hardware->core, 0x00000, 0x204)); /* Loading the frequency scaler. */ gcmkONERROR(gckOS_WriteRegisterEx(hardware->os, hardware->core, 0x00000, 0x004)); break; default: gcmkPRINT("[pm_test]: freq unknown scaler\n"); break; } return count; OnError: return (ssize_t)-EINVAL; }
static ssize_t store_dutycycle (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { #if MRVL_PULSE_EATER_COUNT_NUM if(has_feat_pulse_eater_profiler()) { gctBOOL start; gctUINT core; gctUINT32 busyRatio[4], totalTime[4], timeGap = 0; gcePulseEaterDomain domain = gcvPulse_Core; gceSTATUS status = gcvSTATUS_OK; SYSFS_VERIFY_INPUT(sscanf(buf, "%d %d", &start, &core), 2); SYSFS_VERIFY_INPUT_RANGE(start, 0, 1); #if gcdENABLE_VG SYSFS_VERIFY_INPUT_RANGE(core, 0, 2); #else SYSFS_VERIFY_INPUT_RANGE(core, 0, 1); #endif for(; domain < 2; domain++) { status = gckKERNEL_QueryPulseEaterIdleProfile(galDevice->kernels[core], start, domain, busyRatio, &timeGap, totalTime); if(!start && !status) { gctINT i = 0; gcmkPRINT("\n|Domain: %6s totalTime: %8d|", domain ==0 ?"Core":"Shader" ,timeGap); gcmkPRINT("|Freq RunTime| BusyRatio| DutyCycle|\n"); for(; i < gcmCOUNTOF(busyRatio); i++) { gcmkPRINT("|%dM %6u| %8u| %8d%%|\n", i==2?416: 156*(i+1), totalTime[i], busyRatio[i], totalTime[i]==0?0: ((100*((gctINT)busyRatio[i]))/(gctINT)totalTime[i])); } } else if(status) { switch(status) { case gcvSTATUS_INVALID_ARGUMENT: printk("Invalidate argument: %d, cat /sys/../dutycycle for more info\n", status); break; case gcvSTATUS_INVALID_REQUEST: printk("Statistics has started alreay, echo 0 x > /sys/.../dutycycle to stop it\n"); break; default: printk("cat /sys/../dutycycle for more info, status: %d\n", status); } } } } else #endif { printk("Oops, %s is under working\n", __func__); } return count; }
/******************************************************************************* ** ** 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; }
static void _DumpCommand( IN gckCOMMAND Command, IN gctPOINTER Pointer, IN gctSIZE_T Bytes ) { gctUINT32_PTR data = (gctUINT32_PTR) Pointer; gctUINT32 address; #ifdef MRVL_DUMP_COMMAND struct file* pDump_Cmd = 0; mm_segment_t old_fs; pDump_Cmd = filp_open("./dump_cmd.bin",O_WRONLY | O_CREAT | O_APPEND,0644); if (pDump_Cmd == 0) { gcmkPRINT("open file dump_cmd.bin failed!\n"); return; } old_fs = get_fs(); set_fs(KERNEL_DS); pDump_Cmd->f_op->write(pDump_Cmd,Pointer,Bytes,&pDump_Cmd->f_pos); set_fs(old_fs); filp_close(pDump_Cmd,0); return; #endif gckOS_GetPhysicalAddress(Command->os, Pointer, &address); gcmkPRINT("@[kernel.command %08X %08X", address, Bytes); while (Bytes >= 8*4) { gcmkPRINT(" %08X %08X %08X %08X %08X %08X %08X %08X", data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7]); data += 8; Bytes -= 32; } switch (Bytes) { case 7*4: gcmkPRINT(" %08X %08X %08X %08X %08X %08X %08X", data[0], data[1], data[2], data[3], data[4], data[5], data[6]); break; case 6*4: gcmkPRINT(" %08X %08X %08X %08X %08X %08X", data[0], data[1], data[2], data[3], data[4], data[5]); break; case 5*4: gcmkPRINT(" %08X %08X %08X %08X %08X", data[0], data[1], data[2], data[3], data[4]); break; case 4*4: gcmkPRINT(" %08X %08X %08X %08X", data[0], data[1], data[2], data[3]); break; case 3*4: gcmkPRINT(" %08X %08X %08X", data[0], data[1], data[2]); break; case 2*4: gcmkPRINT(" %08X %08X", data[0], data[1]); break; case 1*4: gcmkPRINT(" %08X", data[0]); break; } gcmkPRINT("] -- command"); }
/******************************************************************************* ** ** 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; }
static ssize_t gc_proc_write( struct file *file, const char *buff, size_t len, loff_t *off) { char messages[256]; if(len > 256) len = 256; if(copy_from_user(messages, buff, len)) return -EFAULT; printk("\n"); if(strncmp(messages, "dutycycle", 9) == 0) { gctINT32 option; gcuDATABASE_INFO gpuIdle; static gctUINT64 startTime = 0; static gctUINT64 endTime = 0; gcmkVERIFY_OK(gckOS_ZeroMemory((gctPOINTER)&gpuIdle, gcmSIZEOF(gcuDATABASE_INFO))); sscanf(messages+9, "%d", &option); switch(option) { case 0: gcmkVERIFY_OK(gckOS_GetProfileTick(&startTime)); gcmkVERIFY_OK(gckKERNEL_QueryDutyCycleDB(galDevice->kernels[gcvCORE_MAJOR], gcvTRUE, &gpuIdle)); gpuIdle.time = 0; endTime = 0; break; case 1: gcmkVERIFY_OK(gckKERNEL_QueryDutyCycleDB(galDevice->kernels[gcvCORE_MAJOR], gcvFALSE, &gpuIdle)); gcmkVERIFY_OK(gckOS_GetProfileTick(&endTime)); break; default: printk(KERN_INFO "usage: echo dutycycle [0|1] > /proc/driver/gc\n"); } if(startTime != 0 && endTime != 0) { gctUINT64 delta = endTime - startTime; gctUINT32 per = 100 - 100 * gckOS_ProfileToMS(gpuIdle.time) / gckOS_ProfileToMS(delta); printk(KERN_INFO "\n %%GPU START END DELTA IDLE\n"); printk(KERN_INFO "%5u%% %8u %8u %8u %8u\n\n", per, gckOS_ProfileToMS(startTime), gckOS_ProfileToMS(endTime), gckOS_ProfileToMS(delta), gckOS_ProfileToMS(gpuIdle.time)); } } else if(strncmp(messages, "reg", 3) == 0) { gctINT32 option; gctUINT32 idle, address, clockControl; sscanf(messages+3, "%d", &option); switch(option) { case 1: /* Read the current FE address. */ gckOS_ReadRegisterEx(galDevice->os, galDevice->kernels[0]->hardware->core, 0x00664, &address); gcmkPRINT("address: 0x%2x\n", address); break; case 2: /* Read idle register. */ gckOS_ReadRegisterEx(galDevice->os, galDevice->kernels[0]->hardware->core, 0x00004, &idle); gcmkPRINT("idle: 0x%2x\n", idle); break; case 3: gckOS_ReadRegisterEx(galDevice->os, gcvCORE_MAJOR, 0x00000, &clockControl); gcmkPRINT("clockControl: 0x%2x\n", clockControl); break; default: printk(KERN_INFO "usage: echo reg [1|2|3] > /proc/driver/gc\n"); } } else if(strncmp(messages, "help", 4) == 0) { printk("Supported options:\n" "dutycycle measure dutycycle in a period\n" "reg enable debugging for register reading\n" "help show this help page\n" "\n"); } else { gcmkPRINT("unknown echo\n"); } printk("\n"); return len; }
gceSTATUS gckHEAP_ProfileEnd( IN gckHEAP Heap, IN gctCONST_STRING Title ) { gcmkHEADER_ARG("Heap=0x%x Title=0x%x", Heap, Title); /* Verify the arguments. */ gcmkVERIFY_OBJECT(Heap, gcvOBJ_HEAP); gcmkVERIFY_ARGUMENT(Title != gcvNULL); gcmkPRINT(""); gcmkPRINT("=====[ HEAP - %s ]=====", Title); gcmkPRINT("Number of allocations : %12u", Heap->allocCount); gcmkPRINT("Number of bytes allocated : %12llu", Heap->allocBytes); gcmkPRINT("Maximum allocation size : %12llu", Heap->allocBytesMax); gcmkPRINT("Total number of bytes allocated : %12llu", Heap->allocBytesTotal); gcmkPRINT("Number of heaps : %12u", Heap->heapCount); gcmkPRINT("Heap memory in bytes : %12llu", Heap->heapMemory); gcmkPRINT("Maximum number of heaps : %12u", Heap->heapCountMax); gcmkPRINT("Maximum heap memory in bytes : %12llu", Heap->heapMemoryMax); gcmkPRINT("=============================================="); /* Success. */ gcmkFOOTER_NO(); return gcvSTATUS_OK; }
/******************************************************************************* ** ** gckCOMMAND_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; }